Update: 最新功能更新 - Main/RadioManager/GUIManager/LoginManager等模块优化
This commit is contained in:
+7
-1
@@ -36,4 +36,10 @@ build/
|
|||||||
.vscode/
|
.vscode/
|
||||||
|
|
||||||
### Mac OS ###
|
### Mac OS ###
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
|
# 开发辅助文件(本地保留,不推送到仓库)
|
||||||
|
txt/
|
||||||
|
*.xlsx
|
||||||
|
*.patch
|
||||||
|
新建*.txt
|
||||||
@@ -62,5 +62,4 @@
|
|||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -25,7 +25,10 @@ public class ConfigManager {
|
|||||||
public long smtpVerifyExpire = 0;
|
public long smtpVerifyExpire = 0;
|
||||||
public long smtpLastSendTime = 0;
|
public long smtpLastSendTime = 0;
|
||||||
public String smtpConfiguringPlayer = "";
|
public String smtpConfiguringPlayer = "";
|
||||||
public String updatePlatform = "gh";
|
public String broadcastServerUrl = "";
|
||||||
|
public int httpPort = 8080;
|
||||||
|
public String garbageTag= "admin";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public ConfigManager(File dataFolder) {
|
public ConfigManager(File dataFolder) {
|
||||||
@@ -321,11 +324,8 @@ public class ConfigManager {
|
|||||||
garbageMaxRounds = parseInt(
|
garbageMaxRounds = parseInt(
|
||||||
m.getOrDefault("垃圾站_保留轮数",
|
m.getOrDefault("垃圾站_保留轮数",
|
||||||
"1"), 1);
|
"1"), 1);
|
||||||
|
// loadSettings() 末尾添加:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void saveSettings() {
|
public void saveSettings() {
|
||||||
File file = new File(dataFolder, "插件设置.txt");
|
File file = new File(dataFolder, "插件设置.txt");
|
||||||
List<String> L = new ArrayList<>();
|
List<String> L = new ArrayList<>();
|
||||||
@@ -344,8 +344,7 @@ public class ConfigManager {
|
|||||||
L.add("垃圾站_清理间隔秒=" + garbageInterval);
|
L.add("垃圾站_清理间隔秒=" + garbageInterval);
|
||||||
L.add("垃圾站_保留轮数=" + garbageMaxRounds);
|
L.add("垃圾站_保留轮数=" + garbageMaxRounds);
|
||||||
|
|
||||||
|
writeLines(file, L);
|
||||||
writeLines(file, L);
|
|
||||||
}
|
}
|
||||||
public double providerPointsPerScore = 2.0;
|
public double providerPointsPerScore = 2.0;
|
||||||
public int baseEconomyReward = 100;
|
public int baseEconomyReward = 100;
|
||||||
@@ -375,6 +374,9 @@ public class ConfigManager {
|
|||||||
L.add("垃圾站_启用=true");
|
L.add("垃圾站_启用=true");
|
||||||
L.add("垃圾站_清理间隔秒=300");
|
L.add("垃圾站_清理间隔秒=300");
|
||||||
L.add("垃圾站_保留轮数=1");
|
L.add("垃圾站_保留轮数=1");
|
||||||
|
L.add("# ---- 资源包(HTTP) ----");
|
||||||
|
L.add("resource-pack-url=");
|
||||||
|
L.add("http-port=8080");
|
||||||
|
|
||||||
|
|
||||||
writeLines(f, L);
|
writeLines(f, L);
|
||||||
|
|||||||
@@ -213,18 +213,6 @@ public class DatabaseManager {
|
|||||||
+ ")");
|
+ ")");
|
||||||
safeAdd(st, "menu_snowball",
|
safeAdd(st, "menu_snowball",
|
||||||
"INTEGER DEFAULT 1");
|
"INTEGER DEFAULT 1");
|
||||||
// ===== 独立任务进度表 =====
|
|
||||||
st.executeUpdate(
|
|
||||||
"CREATE TABLE IF NOT EXISTS "
|
|
||||||
+ "quest_progress ("
|
|
||||||
+ "player_name TEXT NOT NULL, "
|
|
||||||
+ "condition_key TEXT NOT NULL, "
|
|
||||||
+ "progress_value INTEGER DEFAULT 0, "
|
|
||||||
+ "completed INTEGER DEFAULT 0, "
|
|
||||||
+ "PRIMARY KEY (player_name, "
|
|
||||||
+ "condition_key)"
|
|
||||||
+ ")");
|
|
||||||
|
|
||||||
st.close();
|
st.close();
|
||||||
logger.info("[Sdf1_login] 数据库初始化完成");
|
logger.info("[Sdf1_login] 数据库初始化完成");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -873,8 +861,9 @@ public class DatabaseManager {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
获取指定ID的备份数据
|
/**
|
||||||
|
* 获取指定ID的备份数据
|
||||||
*/
|
*/
|
||||||
public String[] getInventoryBackupById(
|
public String[] getInventoryBackupById(
|
||||||
int backupId) {
|
int backupId) {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import org.bukkit.Material;
|
|||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.inventory.*;
|
import org.bukkit.inventory.*;
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@@ -41,7 +42,7 @@ public class GUIManager {
|
|||||||
g.setItem(14, mkItem(Material.EMERALD,
|
g.setItem(14, mkItem(Material.EMERALD,
|
||||||
"§d§l积分商城"));
|
"§d§l积分商城"));
|
||||||
g.setItem(16, mkItem(Material.CHEST,
|
g.setItem(16, mkItem(Material.CHEST,
|
||||||
"§e§l任务中心"));
|
"§e§l新人礼包"));
|
||||||
g.setItem(18, mkItem(Material.BOOK,
|
g.setItem(18, mkItem(Material.BOOK,
|
||||||
"§6工单系统",
|
"§6工单系统",
|
||||||
"§7提交bug、求助、举报"));
|
"§7提交bug、求助、举报"));
|
||||||
@@ -105,6 +106,32 @@ public class GUIManager {
|
|||||||
p.openInventory(g);
|
p.openInventory(g);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 在 openGiftStages 方法之前添加:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取任务列表(带真实完成状态)
|
||||||
|
* 使用 QuestTracker 解析 .md 文件
|
||||||
|
*/
|
||||||
|
public List<Map<String, Object>> getQuestList(
|
||||||
|
String category) {
|
||||||
|
QuestTracker qt = plugin.getQuestTracker();
|
||||||
|
if (qt == null) return new ArrayList<>();
|
||||||
|
List<QuestTracker.QuestFile> quests =
|
||||||
|
qt.getQuests(category);
|
||||||
|
List<Map<String, Object>> list =
|
||||||
|
new ArrayList<>();
|
||||||
|
for (QuestTracker.QuestFile qf : quests) {
|
||||||
|
Map<String, Object> map =
|
||||||
|
new LinkedHashMap<>();
|
||||||
|
map.put("name", qf.displayName);
|
||||||
|
map.put("conditions", qf.conditions);
|
||||||
|
map.put("rewards", qf.rewards);
|
||||||
|
map.put("questFile", qf);
|
||||||
|
list.add(map);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 打开账号删除选择面板
|
* 打开账号删除选择面板
|
||||||
* 展示该玩家IP下所有账号,供选择删除
|
* 展示该玩家IP下所有账号,供选择删除
|
||||||
@@ -370,7 +397,6 @@ public class GUIManager {
|
|||||||
"§7双击管理"));
|
"§7双击管理"));
|
||||||
slot++;
|
slot++;
|
||||||
}
|
}
|
||||||
|
|
||||||
g.setItem(53, mkItem(Material.ARROW, "§7返回"));
|
g.setItem(53, mkItem(Material.ARROW, "§7返回"));
|
||||||
p.openInventory(g);
|
p.openInventory(g);
|
||||||
}
|
}
|
||||||
@@ -379,279 +405,154 @@ public class GUIManager {
|
|||||||
Inventory g = Bukkit.createInventory(
|
Inventory g = Bukkit.createInventory(
|
||||||
null, 27, T_TASK_CENTER);
|
null, 27, T_TASK_CENTER);
|
||||||
fillBg(g);
|
fillBg(g);
|
||||||
|
|
||||||
QuestTracker qt =
|
|
||||||
plugin.getQuestTracker();
|
|
||||||
String player = p.getName();
|
|
||||||
|
|
||||||
// 新人任务进度
|
|
||||||
List<QuestTracker.QuestFile> newQuests =
|
|
||||||
qt.getQuests("新人任务");
|
|
||||||
int newTotal = newQuests.size();
|
|
||||||
int newDone =
|
|
||||||
qt.getCompletedStageCount(
|
|
||||||
player, newQuests);
|
|
||||||
QuestTracker.QuestFile newCurrent =
|
|
||||||
qt.getCurrentStage(
|
|
||||||
player, newQuests);
|
|
||||||
|
|
||||||
String newInfo = newDone + "/" + newTotal;
|
|
||||||
List<String> newLore = new ArrayList<>();
|
|
||||||
newLore.add("§7进度: §e" + newInfo);
|
|
||||||
if (newCurrent != null) {
|
|
||||||
newLore.add("§7当前: §f"
|
|
||||||
+ newCurrent.displayName);
|
|
||||||
if (newCurrent.hasConditions()) {
|
|
||||||
List<String> unmet =
|
|
||||||
qt.getUnmetConditions(
|
|
||||||
player,
|
|
||||||
newCurrent.conditions);
|
|
||||||
if (!unmet.isEmpty()) {
|
|
||||||
for (String c : unmet) {
|
|
||||||
newLore.add("§7 "
|
|
||||||
+ qt.getProgress(
|
|
||||||
player, c));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
newLore.add("§a✓ 条件已满足");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
newLore.add("§a§l全部完成!");
|
|
||||||
}
|
|
||||||
|
|
||||||
g.setItem(10, mkItem(Material.BOOK,
|
g.setItem(10, mkItem(Material.BOOK,
|
||||||
"§e§l新人任务 §7["
|
"§e§l新人任务",
|
||||||
+ newInfo + "]",
|
"§7完成新手阶段获取奖励"));
|
||||||
newLore.toArray(new String[0])));
|
|
||||||
|
|
||||||
// 主线任务
|
|
||||||
List<QuestTracker.QuestFile> mainQuests =
|
|
||||||
qt.getQuests("主线任务");
|
|
||||||
g.setItem(12, mkItem(Material.COMPASS,
|
g.setItem(12, mkItem(Material.COMPASS,
|
||||||
"§b§l主线任务 §7["
|
"§b§l主线任务",
|
||||||
+ qt.getCompletedStageCount(
|
|
||||||
player, mainQuests)
|
|
||||||
+ "/" + mainQuests.size()
|
|
||||||
+ "]",
|
|
||||||
"§7查看主线任务列表"));
|
"§7查看主线任务列表"));
|
||||||
|
|
||||||
// 支线任务
|
|
||||||
List<QuestTracker.QuestFile> sideQuests =
|
|
||||||
qt.getQuests("支线任务");
|
|
||||||
g.setItem(14, mkItem(Material.PAPER,
|
g.setItem(14, mkItem(Material.PAPER,
|
||||||
"§a§l支线任务 §7["
|
"§a§l支线任务",
|
||||||
+ qt.getCompletedStageCount(
|
|
||||||
player, sideQuests)
|
|
||||||
+ "/" + sideQuests.size()
|
|
||||||
+ "]",
|
|
||||||
"§7查看支线任务列表"));
|
"§7查看支线任务列表"));
|
||||||
|
|
||||||
g.setItem(16, mkItem(Material.EMERALD,
|
g.setItem(16, mkItem(Material.EMERALD,
|
||||||
"§d§l每日签到",
|
"§d§l每日签到",
|
||||||
"§7签到获取积分"));
|
"§7签到获取积分"));
|
||||||
|
g.setItem(22, mkItem(Material.ARROW, "§7返回"));
|
||||||
// 打卡上报按钮(slot 21)
|
|
||||||
g.setItem(21, mkItem(
|
|
||||||
Material.EMERALD,
|
|
||||||
"§a§l打卡上报",
|
|
||||||
"§7验证当前阶段任务完成情况",
|
|
||||||
"§7满足条件将自动标记完成"));
|
|
||||||
|
|
||||||
// 返回按钮(slot 26)
|
|
||||||
g.setItem(26, mkItem(
|
|
||||||
Material.ARROW, "§7返回"));
|
|
||||||
p.openInventory(g);
|
p.openInventory(g);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void openGiftStages(Player p) {
|
public void openGiftStages(Player p) {
|
||||||
Inventory g = Bukkit.createInventory(
|
Inventory g = Bukkit.createInventory(
|
||||||
null, 54, T_GIFT_STAGES);
|
null, 27, T_GIFT_STAGES);
|
||||||
fillBg(g);
|
fillBg(g);
|
||||||
|
|
||||||
QuestTracker qt =
|
QuestTracker qt = plugin.getQuestTracker();
|
||||||
plugin.getQuestTracker();
|
if (qt == null) {
|
||||||
|
g.setItem(22, mkItem(Material.BARRIER,
|
||||||
|
"§7任务系统未加载"));
|
||||||
|
p.openInventory(g);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
List<QuestTracker.QuestFile> quests =
|
List<QuestTracker.QuestFile> quests =
|
||||||
qt.getQuests("新人任务");
|
qt.getQuests("新人任务");
|
||||||
int total = quests.size();
|
String playerName = p.getName();
|
||||||
int completed =
|
|
||||||
qt.getCompletedStageCount(
|
|
||||||
p.getName(), quests);
|
|
||||||
QuestTracker.QuestFile current =
|
|
||||||
qt.getCurrentStage(
|
|
||||||
p.getName(), quests);
|
|
||||||
|
|
||||||
g.setItem(4, mkItem(Material.BOOK,
|
int max = quests.size();
|
||||||
"§e§l新人任务进度",
|
for (int i = 0; i < max && i < 9; i++) {
|
||||||
"§7已完成: §e" + completed
|
QuestTracker.QuestFile qf = quests.get(i);
|
||||||
+ "/" + total,
|
boolean completed =
|
||||||
current != null
|
qt.isStageCompleted(playerName, qf);
|
||||||
? "§7当前: §f"
|
boolean claimed =
|
||||||
+ current.displayName
|
qt.hasClaimed(playerName, qf);
|
||||||
: "§a§l全部完成!"));
|
|
||||||
|
|
||||||
for (int i = 0;
|
|
||||||
i < quests.size() && i < 44; i++) {
|
|
||||||
QuestTracker.QuestFile qf =
|
|
||||||
quests.get(i);
|
|
||||||
boolean done =
|
|
||||||
qt.isStageCompleted(
|
|
||||||
p.getName(), qf);
|
|
||||||
boolean isCurrent =
|
|
||||||
(current != null
|
|
||||||
&& current == qf);
|
|
||||||
|
|
||||||
Material mat;
|
Material mat;
|
||||||
List<String> lore = new ArrayList<>();
|
String status;
|
||||||
|
if (completed && claimed) {
|
||||||
if (done) {
|
|
||||||
mat = Material.LIME_WOOL;
|
mat = Material.LIME_WOOL;
|
||||||
} else if (isCurrent) {
|
status = "§a已领取";
|
||||||
|
} else if (completed) {
|
||||||
mat = Material.YELLOW_WOOL;
|
mat = Material.YELLOW_WOOL;
|
||||||
|
status = "§e可领取";
|
||||||
} else {
|
} else {
|
||||||
mat = Material.RED_WOOL;
|
mat = Material.RED_WOOL;
|
||||||
|
status = "§c未达标";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!qf.details.isEmpty()) {
|
// 显示进度
|
||||||
lore.add("§7---- 任务详情 ----");
|
List<String> lore = new ArrayList<>();
|
||||||
for (String d : qf.details) {
|
lore.add("§7" + status);
|
||||||
lore.add("§f" + d);
|
for (String cond : qf.conditions) {
|
||||||
}
|
String progress =
|
||||||
}
|
qt.getProgress(playerName, cond);
|
||||||
|
lore.add("§7" + progress);
|
||||||
if (qf.hasConditions()
|
|
||||||
&& (done || isCurrent)) {
|
|
||||||
lore.add("");
|
|
||||||
for (String c : qf.conditions) {
|
|
||||||
if (qt.isOptional(c))
|
|
||||||
continue;
|
|
||||||
if (qt.isConditionMet(
|
|
||||||
p.getName(), c)) {
|
|
||||||
lore.add("§7 §a✓ "
|
|
||||||
+ qt.getProgress(
|
|
||||||
p.getName(), c));
|
|
||||||
} else {
|
|
||||||
lore.add("§7 §c✗ "
|
|
||||||
+ qt.getProgress(
|
|
||||||
p.getName(), c));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!qf.rewards.isEmpty()) {
|
|
||||||
lore.add("");
|
|
||||||
lore.add("§7---- 奖励 ----");
|
|
||||||
for (String r : qf.rewards) {
|
|
||||||
lore.add("§a" + r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (done
|
|
||||||
&& !qf.rewards.isEmpty()
|
|
||||||
&& !qt.hasClaimed(
|
|
||||||
p.getName(), qf)) {
|
|
||||||
lore.add("");
|
|
||||||
lore.add("§e§l点击领取奖励");
|
|
||||||
}
|
|
||||||
if (done && qt.hasClaimed(
|
|
||||||
p.getName(), qf)) {
|
|
||||||
lore.add("");
|
|
||||||
lore.add("§7已领取奖励");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g.setItem(10 + i, mkItem(mat,
|
g.setItem(10 + i, mkItem(mat,
|
||||||
"§e" + qf.displayName,
|
"§e" + qf.displayName,
|
||||||
lore.toArray(new String[0])));
|
lore.toArray(new String[0])));
|
||||||
}
|
}
|
||||||
// 返回按钮
|
g.setItem(26, mkItem(Material.ARROW, "§7返回"));
|
||||||
g.setItem(53, mkItem(
|
|
||||||
Material.ARROW, "§7返回"));
|
|
||||||
p.openInventory(g);
|
p.openInventory(g);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void openTaskList(Player p, String folderName) {
|
||||||
|
Inventory g = Bukkit.createInventory(null, 54,
|
||||||
public void openTaskList(Player p,
|
|
||||||
String folderName) {
|
|
||||||
QuestTracker qt =
|
|
||||||
plugin.getQuestTracker();
|
|
||||||
List<QuestTracker.QuestFile> tasks =
|
|
||||||
qt.getQuests(folderName);
|
|
||||||
|
|
||||||
int size = Math.min(54,
|
|
||||||
Math.max(54,
|
|
||||||
((tasks.size() / 9) + 1) * 9));
|
|
||||||
Inventory g = Bukkit.createInventory(
|
|
||||||
null, size,
|
|
||||||
"§d§l" + folderName);
|
"§d§l" + folderName);
|
||||||
fillBg(g);
|
fillBg(g);
|
||||||
|
|
||||||
for (int i = 0;
|
// [FIX] 使用 QuestTracker 获取真实任务数据
|
||||||
i < tasks.size()
|
QuestTracker qt = plugin.getQuestTracker();
|
||||||
&& i < 45; i++) {
|
if (qt == null) {
|
||||||
QuestTracker.QuestFile qf =
|
g.setItem(22, mkItem(Material.BARRIER,
|
||||||
tasks.get(i);
|
"§7任务系统未加载"));
|
||||||
boolean done =
|
p.openInventory(g);
|
||||||
qt.isStageCompleted(
|
return;
|
||||||
p.getName(), qf);
|
}
|
||||||
Material mat = done
|
|
||||||
? Material.LIME_WOOL
|
List<QuestTracker.QuestFile> quests =
|
||||||
: Material.BOOK;
|
qt.getQuests(folderName);
|
||||||
|
String playerName = p.getName();
|
||||||
|
|
||||||
|
if (quests.isEmpty()) {
|
||||||
|
g.setItem(22, mkItem(Material.BARRIER,
|
||||||
|
"§7暂无任务"));
|
||||||
|
p.openInventory(g);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int slot = 0;
|
||||||
|
for (QuestTracker.QuestFile qf : quests) {
|
||||||
|
if (slot >= 45) break;
|
||||||
|
|
||||||
|
boolean completed =
|
||||||
|
qt.isStageCompleted(playerName, qf);
|
||||||
|
boolean claimed =
|
||||||
|
qt.hasClaimed(playerName, qf);
|
||||||
|
|
||||||
|
Material mat;
|
||||||
|
String status;
|
||||||
|
if (completed && claimed) {
|
||||||
|
mat = Material.LIME_WOOL;
|
||||||
|
status = "§a✓ 已完成并领取";
|
||||||
|
} else if (completed) {
|
||||||
|
mat = Material.YELLOW_WOOL;
|
||||||
|
status = "§e✓ 已完成 - 可领取奖励";
|
||||||
|
} else {
|
||||||
|
mat = Material.RED_WOOL;
|
||||||
|
status = "§c未完成";
|
||||||
|
}
|
||||||
|
|
||||||
List<String> lore = new ArrayList<>();
|
List<String> lore = new ArrayList<>();
|
||||||
|
lore.add(status);
|
||||||
|
lore.add("§7───── 条件 ─────");
|
||||||
|
|
||||||
// 解锁条件
|
// 显示每个条件及完成状态
|
||||||
if (qf.hasConditions()) {
|
for (String cond : qf.conditions) {
|
||||||
lore.add("§7──── 解锁条件 ────");
|
String progress =
|
||||||
for (String c : qf.conditions) {
|
qt.getProgress(playerName, cond);
|
||||||
if (qt.isOptional(c))
|
if (qt.isOptional(cond)) {
|
||||||
continue;
|
lore.add("§7[可选] " + progress);
|
||||||
if (qt.isConditionMet(
|
} else {
|
||||||
p.getName(), c)) {
|
lore.add("§e" + progress);
|
||||||
lore.add("§a ✓ "
|
|
||||||
+ qt.getProgress(
|
|
||||||
p.getName(), c));
|
|
||||||
} else {
|
|
||||||
lore.add("§c ✗ "
|
|
||||||
+ qt.getProgress(
|
|
||||||
p.getName(), c));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 任务详情
|
|
||||||
if (!qf.details.isEmpty()) {
|
|
||||||
lore.add("");
|
|
||||||
lore.add("§7──── 任务详情 ────");
|
|
||||||
for (String d : qf.details) {
|
|
||||||
lore.add("§f" + d);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 任务奖励
|
|
||||||
if (!qf.rewards.isEmpty()) {
|
if (!qf.rewards.isEmpty()) {
|
||||||
lore.add("");
|
lore.add("");
|
||||||
lore.add("§7──── 任务奖励 ────");
|
lore.add("§7───── 奖励 ─────");
|
||||||
for (String r : qf.rewards) {
|
for (String r : qf.rewards) {
|
||||||
lore.add("§a" + r);
|
lore.add("§a" + r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
g.setItem(i, mkItem(mat,
|
g.setItem(slot, mkItem(mat,
|
||||||
(done ? "§a✓ " : "§e")
|
"§e" + qf.displayName,
|
||||||
+ qf.displayName,
|
|
||||||
lore.toArray(new String[0])));
|
lore.toArray(new String[0])));
|
||||||
|
slot++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tasks.isEmpty()) {
|
g.setItem(53, mkItem(Material.ARROW, "§7返回"));
|
||||||
g.setItem(22, mkItem(
|
|
||||||
Material.BARRIER,
|
|
||||||
"§7暂无任务"));
|
|
||||||
}
|
|
||||||
g.setItem(size - 1, mkItem(
|
|
||||||
Material.ARROW, "§7返回"));
|
|
||||||
p.openInventory(g);
|
p.openInventory(g);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -683,81 +584,11 @@ public class GUIManager {
|
|||||||
Material.SNOWBALL,
|
Material.SNOWBALL,
|
||||||
"§e§l雪球菜单",
|
"§e§l雪球菜单",
|
||||||
"§7点击为该玩家发放菜单雪球"));
|
"§7点击为该玩家发放菜单雪球"));
|
||||||
g.setItem(16, mkItem(
|
|
||||||
Material.ENDER_EYE,
|
|
||||||
"§b§l打卡记录",
|
|
||||||
"§7查看该玩家的群系打卡记录"));
|
|
||||||
|
|
||||||
g.setItem(22, mkItem(Material.ARROW, "§7返回"));
|
g.setItem(22, mkItem(Material.ARROW, "§7返回"));
|
||||||
p.openInventory(g);
|
p.openInventory(g);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void openCheckInRecords(
|
|
||||||
Player p, String target) {
|
|
||||||
Inventory g = Bukkit.createInventory(
|
|
||||||
null, 54,
|
|
||||||
"§b§l打卡记录: " + target);
|
|
||||||
fillBg(g);
|
|
||||||
|
|
||||||
QuestTracker qt =
|
|
||||||
plugin.getQuestTracker();
|
|
||||||
List<String> records =
|
|
||||||
qt.getPlayerRecords(target);
|
|
||||||
|
|
||||||
java.text.SimpleDateFormat sdf =
|
|
||||||
new java.text.SimpleDateFormat(
|
|
||||||
"yyyy-MM-dd HH:mm:ss");
|
|
||||||
|
|
||||||
int slot = 0;
|
|
||||||
for (int i = records.size() - 1;
|
|
||||||
i >= 0 && slot < 45; i--) {
|
|
||||||
String r = records.get(i);
|
|
||||||
String[] parts = r.split("\\|");
|
|
||||||
if (parts.length < 7) continue;
|
|
||||||
|
|
||||||
String world = parts[1];
|
|
||||||
String biome = parts[2];
|
|
||||||
String category = parts[3];
|
|
||||||
String x = parts[4];
|
|
||||||
String y = parts[5];
|
|
||||||
String z = parts[6];
|
|
||||||
String timeStr = "";
|
|
||||||
if (parts.length >= 8) {
|
|
||||||
try {
|
|
||||||
long ts = Long.parseLong(
|
|
||||||
parts[7]);
|
|
||||||
timeStr = sdf.format(
|
|
||||||
new java.util.Date(
|
|
||||||
ts));
|
|
||||||
} catch (Exception e) {
|
|
||||||
timeStr = parts[7];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
g.setItem(slot, mkItem(
|
|
||||||
Material.PAPER,
|
|
||||||
"§e" + category + " - "
|
|
||||||
+ biome,
|
|
||||||
"§7时间: " + timeStr,
|
|
||||||
"§7世界: " + world,
|
|
||||||
"§7坐标: " + x
|
|
||||||
+ ", " + y
|
|
||||||
+ ", " + z));
|
|
||||||
slot++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (slot == 0) {
|
|
||||||
g.setItem(22, mkItem(
|
|
||||||
Material.BARRIER,
|
|
||||||
"§7暂无打卡记录"));
|
|
||||||
}
|
|
||||||
|
|
||||||
g.setItem(53, mkItem(
|
|
||||||
Material.ARROW, "§7返回"));
|
|
||||||
p.openInventory(g);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 打开账号请求面板
|
* 打开账号请求面板
|
||||||
* 玩家通过 /oa 命令触发
|
* 玩家通过 /oa 命令触发
|
||||||
|
|||||||
@@ -1,89 +1,96 @@
|
|||||||
package Sdf1_login;
|
package Sdf1_login;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class InviteManager {
|
public class InviteManager {
|
||||||
|
|
||||||
private final Main plugin;
|
private final Main plugin;
|
||||||
|
|
||||||
public InviteManager(Main plugin) {
|
public InviteManager(Main plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String generateCode(Player p) {
|
public String generateCode(Player p) {
|
||||||
String code = PasswordUtils.generateInviteCode();
|
String code = PasswordUtils.generateInviteCode();
|
||||||
plugin.getDb().setField(
|
plugin.getDb().setField(
|
||||||
p.getName(), "invite_code", code);
|
p.getName(), "invite_code", code);
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onInviteeCheckIn(String inviteeName) {
|
public void onInviteeCheckIn(String inviteeName) {
|
||||||
String invitedBy = (String) plugin.getDb()
|
String invitedBy = (String) plugin.getDb()
|
||||||
.getField(inviteeName, "invited_by");
|
.getField(inviteeName, "invited_by");
|
||||||
if (invitedBy == null || invitedBy.isEmpty())
|
if (invitedBy == null || invitedBy.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
String month = new SimpleDateFormat("yyyy-MM")
|
String month = new SimpleDateFormat("yyyy-MM")
|
||||||
.format(new Date());
|
.format(new Date());
|
||||||
String lastMonth = (String) plugin.getDb()
|
String lastMonth = (String) plugin.getDb()
|
||||||
.getField(invitedBy, "invite_month");
|
.getField(invitedBy, "invite_month");
|
||||||
|
|
||||||
if (!month.equals(lastMonth)) {
|
if (!month.equals(lastMonth)) {
|
||||||
plugin.getDb().setField(
|
plugin.getDb().setField(
|
||||||
invitedBy, "invite_month", month);
|
invitedBy, "invite_month", month);
|
||||||
plugin.getDb().setField(
|
plugin.getDb().setField(
|
||||||
invitedBy, "monthly_invite_count", 0);
|
invitedBy, "monthly_invite_count", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int count = ((Number) plugin.getDb()
|
int count = ((Number) plugin.getDb()
|
||||||
.getField(invitedBy,
|
.getField(invitedBy,
|
||||||
"monthly_invite_count"))
|
"monthly_invite_count"))
|
||||||
.intValue();
|
.intValue();
|
||||||
plugin.getDb().setField(
|
plugin.getDb().setField(
|
||||||
invitedBy, "monthly_invite_count",
|
invitedBy, "monthly_invite_count",
|
||||||
count + 1);
|
count + 1);
|
||||||
|
|
||||||
double rate = plugin.getCommission()
|
double rate = 0.10;
|
||||||
.getCommissionRate(invitedBy);
|
if (count + 1 > 15) {
|
||||||
int bonus = (int) (1 * rate);
|
rate = 0.60;
|
||||||
if (bonus > 0) {
|
} else if (count + 1 > 10) {
|
||||||
plugin.getDb().addPoints(invitedBy, bonus);
|
rate = 0.35;
|
||||||
Player inviterPlayer = Bukkit
|
} else if (count + 1 > 5) {
|
||||||
.getPlayerExact(invitedBy);
|
rate = 0.15;
|
||||||
if (inviterPlayer != null
|
}
|
||||||
&& inviterPlayer.isOnline()) {
|
|
||||||
inviterPlayer.sendMessage(
|
int bonus = (int) (1 * rate);
|
||||||
plugin.getConfig2()
|
if (bonus > 0) {
|
||||||
.msg("invite_referral_bonus")
|
plugin.getDb().addPoints(invitedBy, bonus);
|
||||||
.replace("{points}",
|
Player inviterPlayer = Bukkit
|
||||||
String.valueOf(bonus)));
|
.getPlayerExact(invitedBy);
|
||||||
}
|
if (inviterPlayer != null
|
||||||
}
|
&& inviterPlayer.isOnline()) {
|
||||||
}
|
inviterPlayer.sendMessage(
|
||||||
|
plugin.getConfig2()
|
||||||
public List<Map<String, Object>> getAllInviteData() {
|
.msg("invite_referral_bonus")
|
||||||
List<Map<String, Object>> result =
|
.replace("{points}",
|
||||||
new ArrayList<>();
|
String.valueOf(bonus)));
|
||||||
for (Map<String, Object> user
|
}
|
||||||
: plugin.getDb().getAllUsers()) {
|
}
|
||||||
String code = (String) user.getOrDefault(
|
}
|
||||||
"invite_code", "");
|
|
||||||
if (!code.isEmpty()) {
|
public List<Map<String, Object>> getAllInviteData() {
|
||||||
Map<String, Object> row =
|
List<Map<String, Object>> result =
|
||||||
new LinkedHashMap<>();
|
new ArrayList<>();
|
||||||
row.put("player",
|
for (Map<String, Object> user
|
||||||
user.get("player_name"));
|
: plugin.getDb().getAllUsers()) {
|
||||||
row.put("code", code);
|
String code = (String) user.getOrDefault(
|
||||||
row.put("monthly",
|
"invite_code", "");
|
||||||
user.getOrDefault(
|
if (!code.isEmpty()) {
|
||||||
"monthly_invite_count", 0));
|
Map<String, Object> row =
|
||||||
result.add(row);
|
new LinkedHashMap<>();
|
||||||
}
|
row.put("player",
|
||||||
}
|
user.get("player_name"));
|
||||||
return result;
|
row.put("code", code);
|
||||||
}
|
row.put("monthly",
|
||||||
}
|
user.getOrDefault(
|
||||||
|
"monthly_invite_count", 0));
|
||||||
|
result.add(row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,302 +1,308 @@
|
|||||||
package Sdf1_login;
|
package Sdf1_login;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Sound;
|
import org.bukkit.Sound;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
public class LoginManager {
|
public class LoginManager {
|
||||||
|
|
||||||
private final Main plugin;
|
private final Main plugin;
|
||||||
|
|
||||||
public LoginManager(Main plugin) {
|
public LoginManager(Main plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean handleRegister(Player p,
|
public boolean handleRegister(Player p,
|
||||||
String[] args) {
|
String[] args) {
|
||||||
String name = p.getName();
|
String name = p.getName();
|
||||||
|
|
||||||
// 已注册玩家不能再注册
|
// 已注册玩家不能再注册
|
||||||
if (plugin.getDb().userExists(name)) {
|
if (plugin.getDb().userExists(name)) {
|
||||||
p.sendMessage(plugin.getConfig2()
|
p.sendMessage(plugin.getConfig2()
|
||||||
.msg("already_registered"));
|
.msg("already_registered"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// IP注册限制检查
|
// IP注册限制检查
|
||||||
String ip = plugin.getPlayerIP(p);
|
String ip = plugin.getPlayerIP(p);
|
||||||
if (ip != null && plugin.getConfig2()
|
if (ip != null && plugin.getConfig2()
|
||||||
.maxAccountsPerIP > 0) {
|
.maxAccountsPerIP > 0) {
|
||||||
if (!plugin.getIPGroup()
|
if (!plugin.getIPGroup()
|
||||||
.canRegister(ip)) {
|
.canRegister(ip)) {
|
||||||
int count = plugin.getIPGroup()
|
int count = plugin.getIPGroup()
|
||||||
.getAccountCount(ip);
|
.getAccountCount(ip);
|
||||||
int max = plugin.getConfig2()
|
int max = plugin.getConfig2()
|
||||||
.maxAccountsPerIP;
|
.maxAccountsPerIP;
|
||||||
p.sendMessage("§c该IP注册已达上限("
|
p.sendMessage("§c该IP注册已达上限("
|
||||||
+ count + "/" + max + ")");
|
+ count + "/" + max + ")");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.length < 1) {
|
if (args.length < 1) {
|
||||||
p.sendMessage("§c用法: /reg <密码>");
|
p.sendMessage("§c用法: /reg <密码>");
|
||||||
p.sendMessage("§7密码要求: 6位以上,"
|
p.sendMessage("§7密码要求: 6位以上,"
|
||||||
+ "包含大小写字母和数字");
|
+ "包含大小写字母和数字");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
String pwd = args[0];
|
String pwd = args[0];
|
||||||
if (pwd.length() < 6) {
|
if (pwd.length() < 6) {
|
||||||
p.sendMessage("§c密码长度不足6位");
|
p.sendMessage("§c密码长度不足6位");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!pwd.matches(".*[a-z].*")
|
if (!pwd.matches(".*[a-z].*")
|
||||||
|| !pwd.matches(".*[A-Z].*")
|
|| !pwd.matches(".*[A-Z].*")
|
||||||
|| !pwd.matches(".*[0-9].*")) {
|
|| !pwd.matches(".*[0-9].*")) {
|
||||||
p.sendMessage("§c密码必须包含大写字母、"
|
p.sendMessage("§c密码必须包含大写字母、"
|
||||||
+ "小写字母和数字");
|
+ "小写字母和数字");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
String salt =
|
String salt =
|
||||||
PasswordUtils.generateSalt();
|
PasswordUtils.generateSalt();
|
||||||
String hash =
|
String hash =
|
||||||
PasswordUtils.hash(pwd, salt);
|
PasswordUtils.hash(pwd, salt);
|
||||||
plugin.getDb().createUser(
|
plugin.getDb().createUser(
|
||||||
name, hash, salt);
|
name, hash, salt);
|
||||||
plugin.getLoggedIn().add(name);
|
plugin.getLoggedIn().add(name);
|
||||||
plugin.getDb().setLoggedIn(name, true);
|
p.setAllowFlight(false);
|
||||||
plugin.getDb().setField(name,
|
p.setFlying(false);
|
||||||
"last_login_time",
|
plugin.getDb().setLoggedIn(name, true);
|
||||||
System.currentTimeMillis());
|
plugin.getDb().setField(name,
|
||||||
plugin.getDb().setField(name,
|
"last_login_time",
|
||||||
"last_online_check",
|
System.currentTimeMillis());
|
||||||
System.currentTimeMillis());
|
plugin.getDb().setField(name,
|
||||||
plugin.getDb().recordIP(name, ip);
|
"last_online_check",
|
||||||
plugin.getDb().setField(name,
|
System.currentTimeMillis());
|
||||||
"register_time",
|
plugin.getDb().recordIP(name, ip);
|
||||||
System.currentTimeMillis());
|
plugin.getDb().setField(name,
|
||||||
plugin.restoreInventory(p);
|
"register_time",
|
||||||
plugin.recordIPLogin(p);
|
System.currentTimeMillis());
|
||||||
plugin.giveMenuSnowball(p);
|
plugin.restoreInventory(p);
|
||||||
|
plugin.recordIPLogin(p);
|
||||||
p.sendMessage(plugin.getConfig2()
|
plugin.giveMenuSnowball(p);
|
||||||
.msg("reg_success"));
|
|
||||||
playRegisterSound(p);
|
p.sendMessage(plugin.getConfig2()
|
||||||
|
.msg("reg_success"));
|
||||||
try {
|
playRegisterSound(p);
|
||||||
org.bukkit.plugin.Plugin cy =
|
|
||||||
Bukkit.getPluginManager()
|
try {
|
||||||
.getPlugin("CY_beibao");
|
org.bukkit.plugin.Plugin cy =
|
||||||
if (cy != null && cy.isEnabled()) {
|
Bukkit.getPluginManager()
|
||||||
cy.getClass().getMethod(
|
.getPlugin("CY_beibao");
|
||||||
"onSdf1Activation",
|
if (cy != null && cy.isEnabled()) {
|
||||||
String.class,
|
cy.getClass().getMethod(
|
||||||
int.class, int.class)
|
"onSdf1Activation",
|
||||||
.invoke(cy, name, 9, 0);
|
String.class,
|
||||||
}
|
int.class, int.class)
|
||||||
} catch (Exception ignored) {
|
.invoke(cy, name, 9, 0);
|
||||||
}
|
}
|
||||||
return true;
|
} catch (Exception ignored) {
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
private void playRegisterSound(Player p) {
|
}
|
||||||
p.playSound(p.getLocation(),
|
|
||||||
Sound.BLOCK_NOTE_BLOCK_CHIME,
|
private void playRegisterSound(Player p) {
|
||||||
1.0f, 0.79f);
|
p.playSound(p.getLocation(),
|
||||||
p.playSound(p.getLocation(),
|
Sound.BLOCK_NOTE_BLOCK_CHIME,
|
||||||
Sound.BLOCK_NOTE_BLOCK_BASS,
|
1.0f, 0.79f);
|
||||||
1.0f, 0.79f);
|
p.playSound(p.getLocation(),
|
||||||
p.playSound(p.getLocation(),
|
Sound.BLOCK_NOTE_BLOCK_BASS,
|
||||||
Sound.BLOCK_NOTE_BLOCK_PLING,
|
1.0f, 0.79f);
|
||||||
1.0f, 0.79f);
|
p.playSound(p.getLocation(),
|
||||||
}
|
Sound.BLOCK_NOTE_BLOCK_PLING,
|
||||||
|
1.0f, 0.79f);
|
||||||
|
}
|
||||||
public boolean handleLogin(Player p,
|
|
||||||
String[] args) {
|
|
||||||
String name = p.getName();
|
public boolean handleLogin(Player p,
|
||||||
try {
|
String[] args) {
|
||||||
if (plugin.getLoggedIn().contains(name)) {
|
String name = p.getName();
|
||||||
p.sendMessage(plugin.getConfig2()
|
try {
|
||||||
.msg("already_logged_in"));
|
if (plugin.getLoggedIn().contains(name)) {
|
||||||
return true;
|
p.sendMessage(plugin.getConfig2()
|
||||||
}
|
.msg("already_logged_in"));
|
||||||
if (!plugin.getDb().userExists(name)) {
|
return true;
|
||||||
p.sendMessage(plugin.getConfig2()
|
}
|
||||||
.msg("not_registered"));
|
if (!plugin.getDb().userExists(name)) {
|
||||||
return true;
|
p.sendMessage(plugin.getConfig2()
|
||||||
}
|
.msg("not_registered"));
|
||||||
if (args.length < 1) {
|
return true;
|
||||||
p.sendMessage("§c用法: /login <密码>");
|
}
|
||||||
return true;
|
if (args.length < 1) {
|
||||||
}
|
p.sendMessage("§c用法: /login <密码>");
|
||||||
String pwd = args[0];
|
return true;
|
||||||
String salt = (String) plugin.getDb()
|
}
|
||||||
.getField(name, "password_salt");
|
String pwd = args[0];
|
||||||
if (salt == null) {
|
String salt = (String) plugin.getDb()
|
||||||
p.sendMessage(
|
.getField(name, "password_salt");
|
||||||
"§c数据异常,请联系管理员");
|
if (salt == null) {
|
||||||
plugin.getLogger().severe(
|
p.sendMessage(
|
||||||
"[Sdf1_login] 玩家 " + name
|
"§c数据异常,请联系管理员");
|
||||||
+ " 盐值为null");
|
plugin.getLogger().severe(
|
||||||
return true;
|
"[Sdf1_login] 玩家 " + name
|
||||||
}
|
+ " 盐值为null");
|
||||||
String hash =
|
return true;
|
||||||
PasswordUtils.hash(pwd, salt);
|
}
|
||||||
|
String hash =
|
||||||
boolean matchMain =
|
PasswordUtils.hash(pwd, salt);
|
||||||
plugin.getDb().checkPassword(
|
|
||||||
name, hash);
|
boolean matchMain =
|
||||||
if (matchMain) {
|
plugin.getDb().checkPassword(
|
||||||
plugin.getLoggedIn().add(name);
|
name, hash);
|
||||||
plugin.getDb().setLoggedIn(
|
if (matchMain) {
|
||||||
name, true);
|
plugin.getLoggedIn().add(name);
|
||||||
plugin.getDb().setField(name,
|
plugin.getDb().setLoggedIn(
|
||||||
"last_login_time",
|
name, true);
|
||||||
System.currentTimeMillis());
|
plugin.getDb().setLoggedIn(
|
||||||
plugin.getDb().setField(name,
|
name, true);
|
||||||
"last_online_check",
|
plugin.getDb().setField(name,
|
||||||
System.currentTimeMillis());
|
"last_login_time",
|
||||||
// 只在有有效备份时恢复
|
System.currentTimeMillis());
|
||||||
plugin.restoreInventory(p);
|
plugin.getDb().setField(name,
|
||||||
plugin.recordIPLogin(p);
|
"last_online_check",
|
||||||
plugin.giveMenuSnowball(p);
|
System.currentTimeMillis());
|
||||||
p.sendMessage(plugin.getConfig2()
|
// 只在有有效备份时恢复
|
||||||
.msg("login_success"));
|
plugin.restoreInventory(p);
|
||||||
activateCY(p, name);
|
plugin.recordIPLogin(p);
|
||||||
return true;
|
plugin.giveMenuSnowball(p);
|
||||||
}
|
p.sendMessage(plugin.getConfig2()
|
||||||
|
.msg("login_success"));
|
||||||
boolean matchTemp =
|
activateCY(p, name);
|
||||||
plugin.getDb()
|
return true;
|
||||||
.checkPasswordOrTemp(
|
}
|
||||||
name, hash);
|
|
||||||
if (matchTemp) {
|
boolean matchTemp =
|
||||||
plugin.getLoggedIn().add(name);
|
plugin.getDb()
|
||||||
plugin.getDb().setLoggedIn(
|
.checkPasswordOrTemp(
|
||||||
name, true);
|
name, hash);
|
||||||
plugin.getDb().setField(name,
|
if (matchTemp) {
|
||||||
"last_login_time",
|
plugin.getLoggedIn().add(name);
|
||||||
System.currentTimeMillis());
|
plugin.getDb().setLoggedIn(
|
||||||
plugin.getDb().setField(name,
|
name, true);
|
||||||
"last_online_check",
|
p.setAllowFlight(false);
|
||||||
System.currentTimeMillis());
|
p.setFlying(false);
|
||||||
plugin.restoreInventory(p);
|
plugin.getDb().setField(name,
|
||||||
plugin.recordIPLogin(p);
|
"last_login_time",
|
||||||
plugin.giveMenuSnowball(p);
|
System.currentTimeMillis());
|
||||||
plugin.getNeedsPasswordChange()
|
plugin.getDb().setField(name,
|
||||||
.add(name);
|
"last_online_check",
|
||||||
p.sendMessage(plugin.getConfig2()
|
System.currentTimeMillis());
|
||||||
.msg("login_success"));
|
plugin.restoreInventory(p);
|
||||||
p.sendMessage(
|
plugin.recordIPLogin(p);
|
||||||
"§c§l[警告] §f您使用的是临时密码,请尽快修改密码!");
|
plugin.giveMenuSnowball(p);
|
||||||
p.sendMessage(
|
plugin.getNeedsPasswordChange()
|
||||||
"§7用法: /sdf1_login pw");
|
.add(name);
|
||||||
activateCY(p, name);
|
p.sendMessage(plugin.getConfig2()
|
||||||
return true;
|
.msg("login_success"));
|
||||||
}
|
p.sendMessage(
|
||||||
|
"§c§l[警告] §f您使用的是临时密码,请尽快修改密码!");
|
||||||
|
p.sendMessage(
|
||||||
p.sendMessage(plugin.getConfig2()
|
"§7用法: /sdf1_login pw");
|
||||||
.msg("login_failed"));
|
activateCY(p, name);
|
||||||
} catch (Exception e) {
|
return true;
|
||||||
plugin.getLogger().severe(
|
}
|
||||||
"[Sdf1_login] handleLogin异常: "
|
|
||||||
+ e.getMessage());
|
|
||||||
e.printStackTrace();
|
p.sendMessage(plugin.getConfig2()
|
||||||
p.sendMessage(
|
.msg("login_failed"));
|
||||||
"§c登录过程出错,请联系管理员");
|
} catch (Exception e) {
|
||||||
}
|
plugin.getLogger().severe(
|
||||||
return true;
|
"[Sdf1_login] handleLogin异常: "
|
||||||
}
|
+ e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
p.sendMessage(
|
||||||
public void handleReset(Player p) {
|
"§c登录过程出错,请联系管理员");
|
||||||
String name = p.getName();
|
}
|
||||||
String emailAddr = (String)
|
return true;
|
||||||
plugin.getDb().getField(
|
}
|
||||||
name, "email");
|
|
||||||
if (emailAddr == null
|
|
||||||
|| emailAddr.isEmpty()) {
|
public void handleReset(Player p) {
|
||||||
p.sendMessage(
|
String name = p.getName();
|
||||||
"§c未设置邮箱,无法重置密码");
|
String emailAddr = (String)
|
||||||
return;
|
plugin.getDb().getField(
|
||||||
}
|
name, "email");
|
||||||
String tempPwd = PasswordUtils
|
if (emailAddr == null
|
||||||
.generateTempPassword();
|
|| emailAddr.isEmpty()) {
|
||||||
String salt = (String)
|
p.sendMessage(
|
||||||
plugin.getDb().getField(
|
"§c未设置邮箱,无法重置密码");
|
||||||
name, "password_salt");
|
return;
|
||||||
String hash = PasswordUtils.hash(
|
}
|
||||||
tempPwd, salt);
|
String tempPwd = PasswordUtils
|
||||||
plugin.getDb().setField(name,
|
.generateTempPassword();
|
||||||
"temp_password", hash);
|
String salt = (String)
|
||||||
plugin.getDb().setField(name,
|
plugin.getDb().getField(
|
||||||
"temp_pw_expire",
|
name, "password_salt");
|
||||||
System.currentTimeMillis()
|
String hash = PasswordUtils.hash(
|
||||||
+ 300000L);
|
tempPwd, salt);
|
||||||
|
plugin.getDb().setField(name,
|
||||||
plugin.getDb().setField(name,
|
"temp_password", hash);
|
||||||
"temp_pw_used", 0);
|
plugin.getDb().setField(name,
|
||||||
p.sendMessage("§e正在发送临时密码...");
|
"temp_pw_expire",
|
||||||
final String to = emailAddr;
|
System.currentTimeMillis()
|
||||||
final String fName = name;
|
+ 300000L);
|
||||||
final String pwd = tempPwd;
|
|
||||||
final Main self = plugin;
|
plugin.getDb().setField(name,
|
||||||
Bukkit.getScheduler()
|
"temp_pw_used", 0);
|
||||||
.runTaskAsynchronously(self,
|
p.sendMessage("§e正在发送临时密码...");
|
||||||
() -> {
|
final String to = emailAddr;
|
||||||
final boolean[] sent = {false};
|
final String fName = name;
|
||||||
Thread t = new Thread(() -> {
|
final String pwd = tempPwd;
|
||||||
sent[0] = self.getEmail()
|
final Main self = plugin;
|
||||||
.sendTempPassword(
|
Bukkit.getScheduler()
|
||||||
to, fName, pwd);
|
.runTaskAsynchronously(self,
|
||||||
}, "Sdf1_login-reset");
|
() -> {
|
||||||
t.setDaemon(true);
|
final boolean[] sent = {false};
|
||||||
t.start();
|
Thread t = new Thread(() -> {
|
||||||
try {
|
sent[0] = self.getEmail()
|
||||||
t.join(15000);
|
.sendTempPassword(
|
||||||
} catch (
|
to, fName, pwd);
|
||||||
InterruptedException ignored) {
|
}, "Sdf1_login-reset");
|
||||||
}
|
t.setDaemon(true);
|
||||||
if (t.isAlive()) {
|
t.start();
|
||||||
t.interrupt();
|
try {
|
||||||
Bukkit.getScheduler().runTask(
|
t.join(15000);
|
||||||
self, () ->
|
} catch (
|
||||||
p.sendMessage(
|
InterruptedException ignored) {
|
||||||
"§c邮件发送超时"));
|
}
|
||||||
return;
|
if (t.isAlive()) {
|
||||||
}
|
t.interrupt();
|
||||||
Bukkit.getScheduler().runTask(
|
Bukkit.getScheduler().runTask(
|
||||||
self, () -> {
|
self, () ->
|
||||||
if (sent[0]) {
|
p.sendMessage(
|
||||||
p.sendMessage(
|
"§c邮件发送超时"));
|
||||||
"§a临时密码已发送到 "
|
return;
|
||||||
+ to);
|
}
|
||||||
} else {
|
Bukkit.getScheduler().runTask(
|
||||||
p.sendMessage(
|
self, () -> {
|
||||||
"§c邮件发送失败");
|
if (sent[0]) {
|
||||||
}
|
p.sendMessage(
|
||||||
});
|
"§a临时密码已发送到 "
|
||||||
});
|
+ to);
|
||||||
}
|
} else {
|
||||||
|
p.sendMessage(
|
||||||
private void activateCY(Player p,
|
"§c邮件发送失败");
|
||||||
String name) {
|
}
|
||||||
try {
|
});
|
||||||
org.bukkit.plugin.Plugin cy =
|
});
|
||||||
Bukkit.getPluginManager()
|
}
|
||||||
.getPlugin("CY_beibao");
|
|
||||||
if (cy != null && cy.isEnabled()) {
|
private void activateCY(Player p,
|
||||||
cy.getClass().getMethod(
|
String name) {
|
||||||
"onSdf1Activation",
|
try {
|
||||||
String.class,
|
org.bukkit.plugin.Plugin cy =
|
||||||
int.class, int.class)
|
Bukkit.getPluginManager()
|
||||||
.invoke(cy, name, 0, 0);
|
.getPlugin("CY_beibao");
|
||||||
}
|
if (cy != null && cy.isEnabled()) {
|
||||||
} catch (Exception ignored) {
|
cy.getClass().getMethod(
|
||||||
}
|
"onSdf1Activation",
|
||||||
}
|
String.class,
|
||||||
}
|
int.class, int.class)
|
||||||
|
.invoke(cy, name, 0, 0);
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+1096
-1275
File diff suppressed because it is too large
Load Diff
@@ -23,7 +23,7 @@ import java.util.regex.Pattern;
|
|||||||
public class QuestTracker {
|
public class QuestTracker {
|
||||||
|
|
||||||
private final Plugin plugin;
|
private final Plugin plugin;
|
||||||
private final PlayerStorage storage;
|
private final QuestStorage storage;
|
||||||
private final Map<String, String>
|
private final Map<String, String>
|
||||||
playerBiome = new HashMap<>();
|
playerBiome = new HashMap<>();
|
||||||
private final Map<String, List<QuestFile>>
|
private final Map<String, List<QuestFile>>
|
||||||
@@ -76,9 +76,9 @@ public class QuestTracker {
|
|||||||
|
|
||||||
public QuestTracker(Plugin plugin) {
|
public QuestTracker(Plugin plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.storage = new PlayerStorage(
|
this.storage = new QuestStorage(
|
||||||
plugin.getDataFolder(),
|
plugin.getDataFolder());
|
||||||
plugin.getLogger());
|
|
||||||
loadAllQuests();
|
loadAllQuests();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1490,30 +1490,22 @@ public class QuestTracker {
|
|||||||
}
|
}
|
||||||
return unmet;
|
return unmet;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getProgress(
|
public String getProgress(
|
||||||
String player,
|
String player, String rawCond) {
|
||||||
String rawCond) {
|
if (player == null || rawCond == null)
|
||||||
if (player == null
|
|
||||||
|| rawCond == null)
|
|
||||||
return "§7未知";
|
return "§7未知";
|
||||||
|
|
||||||
String key = stripOptional(rawCond);
|
String key = stripOptional(rawCond);
|
||||||
// 打卡群系进度
|
|
||||||
if (key.contains("打卡")
|
|
||||||
&& (key.contains("群系")
|
|
||||||
|| key.contains("风景点"))) {
|
|
||||||
|
|
||||||
|
if (key.contains("打卡")
|
||||||
|
&& key.contains("群系")) {
|
||||||
String biome =
|
String biome =
|
||||||
extractBiome(key);
|
extractBiome(key);
|
||||||
|
|
||||||
if ("ALL".equals(biome)) {
|
if ("ALL".equals(biome)) {
|
||||||
int total = getCounter(
|
int total = getCounter(
|
||||||
player, "biome_ALL");
|
player, "biome_ALL");
|
||||||
return "§7群系打卡: §e"
|
return "§7群系打卡: §e"
|
||||||
+ total + "/1";
|
+ total + "/1";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!biome.isEmpty()) {
|
if (!biome.isEmpty()) {
|
||||||
int catCount = getCounter(
|
int catCount = getCounter(
|
||||||
player,
|
player,
|
||||||
@@ -1522,16 +1514,12 @@ public class QuestTracker {
|
|||||||
+ "群系: §e"
|
+ "群系: §e"
|
||||||
+ catCount + "/1";
|
+ catCount + "/1";
|
||||||
}
|
}
|
||||||
|
|
||||||
int total = getCounter(
|
int total = getCounter(
|
||||||
player, "biome_ALL");
|
player, "biome_ALL");
|
||||||
return "§7群系打卡: §e"
|
return "§7群系打卡: §e"
|
||||||
+ total + "/1";
|
+ total + "/1";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 阶段依赖
|
|
||||||
if (key.contains("完成")
|
if (key.contains("完成")
|
||||||
&& key.contains("阶段")) {
|
&& key.contains("阶段")) {
|
||||||
boolean done = checkStageDependency(
|
boolean done = checkStageDependency(
|
||||||
@@ -1541,9 +1529,6 @@ public class QuestTracker {
|
|||||||
: "§c✗ " + key;
|
: "§c✗ " + key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 注册登录(检查主数据库是否已注册)
|
|
||||||
// 注册登录(检查主数据库是否已注册)
|
|
||||||
if ("完成注册登录".equals(key)) {
|
if ("完成注册登录".equals(key)) {
|
||||||
boolean done = getDb() != null
|
boolean done = getDb() != null
|
||||||
&& getDb().userExists(
|
&& getDb().userExists(
|
||||||
@@ -1553,7 +1538,6 @@ public class QuestTracker {
|
|||||||
: "§c✗ 完成注册登录";
|
: "§c✗ 完成注册登录";
|
||||||
}
|
}
|
||||||
|
|
||||||
// 绑定邮箱
|
|
||||||
if (key.contains("绑定Email")
|
if (key.contains("绑定Email")
|
||||||
|| key.contains("绑定邮箱")) {
|
|| key.contains("绑定邮箱")) {
|
||||||
Object val =
|
Object val =
|
||||||
@@ -1566,7 +1550,6 @@ public class QuestTracker {
|
|||||||
: "§c✗ 绑定Email";
|
: "§c✗ 绑定Email";
|
||||||
}
|
}
|
||||||
|
|
||||||
// 在线时间
|
|
||||||
if (key.contains("在线")
|
if (key.contains("在线")
|
||||||
&& key.contains("小时")) {
|
&& key.contains("小时")) {
|
||||||
int needed = parseNumberFromText(key);
|
int needed = parseNumberFromText(key);
|
||||||
@@ -1578,17 +1561,16 @@ public class QuestTracker {
|
|||||||
+ needed + "小时";
|
+ needed + "小时";
|
||||||
}
|
}
|
||||||
|
|
||||||
// 打招呼/发消息/聊天
|
|
||||||
if (key.contains("打招呼")
|
if (key.contains("打招呼")
|
||||||
|| key.contains("打个招呼")
|
|| key.contains("打个招呼")
|
||||||
|| key.contains("发消息")
|
|| key.contains("发消息")
|
||||||
|| key.contains("聊天")) {
|
|| key.contains("聊天")) {
|
||||||
int cur = getCounter(
|
int cur = getCounter(
|
||||||
player, "CHAT");
|
player, "CHAT");
|
||||||
return "§7聊天: §e" + cur + "/1";
|
return "§7聊天: §e"
|
||||||
|
+ cur + "/1";
|
||||||
}
|
}
|
||||||
|
|
||||||
// 破坏/放置方块
|
|
||||||
if ((key.contains("破坏")
|
if ((key.contains("破坏")
|
||||||
|| key.contains("放置"))
|
|| key.contains("放置"))
|
||||||
&& key.contains("方块")) {
|
&& key.contains("方块")) {
|
||||||
@@ -1606,20 +1588,17 @@ public class QuestTracker {
|
|||||||
&& key.contains("登录")) {
|
&& key.contains("登录")) {
|
||||||
int needed = parseNumberFromText(key);
|
int needed = parseNumberFromText(key);
|
||||||
if (needed <= 0) needed = 1;
|
if (needed <= 0) needed = 1;
|
||||||
int totalDays = getIntField(
|
Object val =
|
||||||
player,
|
getDb().getField(
|
||||||
"total_checkin_days");
|
player,
|
||||||
if (totalDays == 0) {
|
"checkin_streak");
|
||||||
totalDays = getIntField(
|
int streak = val instanceof Number
|
||||||
player,
|
? ((Number) val).intValue()
|
||||||
"checkin_streak");
|
: 0;
|
||||||
}
|
|
||||||
return "§7连续登录: §e"
|
return "§7连续登录: §e"
|
||||||
+ totalDays + "/" + needed + "天";
|
+ streak + "/" + needed + "天";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 挖矿
|
|
||||||
if (key.startsWith("MINE:")) {
|
if (key.startsWith("MINE:")) {
|
||||||
String[] parts = key.split(":");
|
String[] parts = key.split(":");
|
||||||
if (parts.length >= 3) {
|
if (parts.length >= 3) {
|
||||||
@@ -1634,7 +1613,6 @@ public class QuestTracker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 击杀生物
|
|
||||||
if (key.startsWith("KILL:")) {
|
if (key.startsWith("KILL:")) {
|
||||||
String[] parts = key.split(":");
|
String[] parts = key.split(":");
|
||||||
if (parts.length >= 3) {
|
if (parts.length >= 3) {
|
||||||
@@ -1649,7 +1627,6 @@ public class QuestTracker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 击杀玩家
|
|
||||||
if (key.startsWith("KILL_PLAYER")) {
|
if (key.startsWith("KILL_PLAYER")) {
|
||||||
String[] parts = key.split(":");
|
String[] parts = key.split(":");
|
||||||
int needed = parts.length >= 2
|
int needed = parts.length >= 2
|
||||||
@@ -1660,7 +1637,6 @@ public class QuestTracker {
|
|||||||
+ cur + "/" + needed;
|
+ cur + "/" + needed;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 合成
|
|
||||||
if (key.startsWith("CRAFT")) {
|
if (key.startsWith("CRAFT")) {
|
||||||
String[] parts = key.split(":");
|
String[] parts = key.split(":");
|
||||||
int needed = parts.length >= 2
|
int needed = parts.length >= 2
|
||||||
@@ -1671,7 +1647,6 @@ public class QuestTracker {
|
|||||||
+ cur + "/" + needed;
|
+ cur + "/" + needed;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 钓鱼
|
|
||||||
if (key.startsWith("FISH")) {
|
if (key.startsWith("FISH")) {
|
||||||
String[] parts = key.split(":");
|
String[] parts = key.split(":");
|
||||||
int needed = parts.length >= 2
|
int needed = parts.length >= 2
|
||||||
@@ -1682,7 +1657,6 @@ public class QuestTracker {
|
|||||||
+ cur + "/" + needed;
|
+ cur + "/" + needed;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 在线时长(毫秒)
|
|
||||||
if (key.startsWith("PLAYTIME")) {
|
if (key.startsWith("PLAYTIME")) {
|
||||||
String[] parts = key.split(":");
|
String[] parts = key.split(":");
|
||||||
long needed = parts.length >= 2
|
long needed = parts.length >= 2
|
||||||
@@ -1694,7 +1668,7 @@ public class QuestTracker {
|
|||||||
+ formatMs(cur) + "/"
|
+ formatMs(cur) + "/"
|
||||||
+ formatMs(needed);
|
+ formatMs(needed);
|
||||||
}
|
}
|
||||||
// 上报村庄
|
|
||||||
if (key.contains("上报")
|
if (key.contains("上报")
|
||||||
&& key.contains("村庄")) {
|
&& key.contains("村庄")) {
|
||||||
int needed = parseNumberFromText(key);
|
int needed = parseNumberFromText(key);
|
||||||
@@ -1705,7 +1679,6 @@ public class QuestTracker {
|
|||||||
+ cur + "/" + needed;
|
+ cur + "/" + needed;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 探索村庄
|
|
||||||
if (key.contains("探索")
|
if (key.contains("探索")
|
||||||
&& key.contains("村庄")) {
|
&& key.contains("村庄")) {
|
||||||
int cur = getCounter(
|
int cur = getCounter(
|
||||||
@@ -1713,40 +1686,28 @@ public class QuestTracker {
|
|||||||
return "§7探索村庄: §e"
|
return "§7探索村庄: §e"
|
||||||
+ cur + "/1";
|
+ cur + "/1";
|
||||||
}
|
}
|
||||||
// ===== 修改后 =====
|
|
||||||
if (key.contains("7天")
|
if (key.contains("7天")
|
||||||
|| key.contains("七天")) {
|
|| key.contains("七天")) {
|
||||||
int needed = parseNumberFromText(key);
|
int needed = parseNumberFromText(key);
|
||||||
if (needed <= 0) needed = 1;
|
if (needed <= 0) needed = 1;
|
||||||
|
int streak = getIntField(
|
||||||
// 优先使用 total_checkin_days(累计天数)
|
|
||||||
int totalDays = getIntField(
|
|
||||||
player,
|
player,
|
||||||
"total_checkin_days");
|
"checkin_streak");
|
||||||
if (totalDays == 0) {
|
if (streak == 0) {
|
||||||
totalDays = getIntField(
|
streak = getIntField(
|
||||||
player,
|
|
||||||
"checkin_streak");
|
|
||||||
}
|
|
||||||
if (totalDays == 0) {
|
|
||||||
totalDays = getIntField(
|
|
||||||
player, "streak");
|
player, "streak");
|
||||||
}
|
}
|
||||||
|
if (streak == 0) {
|
||||||
plugin.getLogger().info(
|
streak = getIntField(
|
||||||
"[QuestTracker] 登录检测: "
|
player,
|
||||||
+ player
|
"total_checkin_days");
|
||||||
+ " 需要=" + needed
|
}
|
||||||
+ " 实际(累计天数)=" + totalDays);
|
|
||||||
return "§7近7天登录: §e"
|
return "§7近7天登录: §e"
|
||||||
+ totalDays + "/"
|
+ streak + "/"
|
||||||
+ needed + "天";
|
+ needed + "天";
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 完成新手任务全部
|
|
||||||
if (key.contains("新手任务")
|
if (key.contains("新手任务")
|
||||||
&& key.contains("全部")) {
|
&& key.contains("全部")) {
|
||||||
List<QuestFile> quests =
|
List<QuestFile> quests =
|
||||||
@@ -1763,7 +1724,6 @@ public class QuestTracker {
|
|||||||
+ quests.size();
|
+ quests.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 完成主线任务全部
|
|
||||||
if (key.contains("主线任务")
|
if (key.contains("主线任务")
|
||||||
&& key.contains("全部")) {
|
&& key.contains("全部")) {
|
||||||
List<QuestFile> quests =
|
List<QuestFile> quests =
|
||||||
@@ -1782,23 +1742,7 @@ public class QuestTracker {
|
|||||||
|
|
||||||
return "§7" + key;
|
return "§7" + key;
|
||||||
}
|
}
|
||||||
private int getIntField(
|
|
||||||
String player, String field) {
|
|
||||||
try {
|
|
||||||
Object val = getDb().getField(
|
|
||||||
player, field);
|
|
||||||
if (val instanceof Number) {
|
|
||||||
return ((Number) val).intValue();
|
|
||||||
}
|
|
||||||
if (val != null) {
|
|
||||||
return Integer.parseInt(
|
|
||||||
val.toString().trim());
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
// 忽略
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> checkInBiome(
|
public List<String> checkInBiome(
|
||||||
String player,
|
String player,
|
||||||
@@ -2051,32 +1995,42 @@ public class QuestTracker {
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
String key = stripOptional(rawCond);
|
String key = stripOptional(rawCond);
|
||||||
// 打卡群系
|
|
||||||
|
// 无条件类文本直接通过
|
||||||
|
if (key.equals("无前级条件")
|
||||||
|
|| key.equals("无条件")
|
||||||
|
|| key.equals("无")
|
||||||
|
|| key.equals("none")
|
||||||
|
|| key.equals("无需条件")
|
||||||
|
|| key.equals("无解锁条件")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (key.contains("打卡")
|
if (key.contains("打卡")
|
||||||
&& (key.contains("群系")
|
&& (key.contains("群系")
|
||||||
|| key.contains("风景点"))) {
|
|| key.contains("风景点"))) {
|
||||||
|
|
||||||
String biome =
|
String biome =
|
||||||
extractBiome(key);
|
extractBiome(key);
|
||||||
|
|
||||||
if ("ALL".equals(biome)) {
|
if ("ALL".equals(biome)) {
|
||||||
int total = getCounter(
|
int total = getCounter(
|
||||||
player, "biome_ALL");
|
player, "biome_ALL");
|
||||||
return total >= 1;
|
return total >= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!biome.isEmpty()) {
|
if (!biome.isEmpty()) {
|
||||||
int catCount = getCounter(
|
int catCount = getCounter(
|
||||||
player,
|
player,
|
||||||
"biomecat_" + biome);
|
"biomecat_" + biome);
|
||||||
return catCount >= 1; // ← 加这一行
|
return catCount >= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return getCounter(
|
return getCounter(
|
||||||
player, "biome_ALL") >= 1;
|
player, "biome_ALL") >= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 注册登录
|
if (key.contains("完成")
|
||||||
|
&& key.contains("阶段")) {
|
||||||
|
return checkStageDependency(
|
||||||
|
player, key);
|
||||||
|
}
|
||||||
|
|
||||||
if ("完成注册登录".equals(key)) {
|
if ("完成注册登录".equals(key)) {
|
||||||
return getDb() != null
|
return getDb() != null
|
||||||
@@ -2084,8 +2038,6 @@ public class QuestTracker {
|
|||||||
player);
|
player);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 绑定邮箱
|
|
||||||
if (key.contains("绑定Email")
|
if (key.contains("绑定Email")
|
||||||
|| key.contains("绑定邮箱")) {
|
|| key.contains("绑定邮箱")) {
|
||||||
Object val =
|
Object val =
|
||||||
@@ -2095,7 +2047,6 @@ public class QuestTracker {
|
|||||||
&& !val.toString().isEmpty();
|
&& !val.toString().isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 在线时间
|
|
||||||
if (key.contains("在线")
|
if (key.contains("在线")
|
||||||
&& key.contains("小时")) {
|
&& key.contains("小时")) {
|
||||||
int needed = parseNumberFromText(key);
|
int needed = parseNumberFromText(key);
|
||||||
@@ -2105,7 +2056,6 @@ public class QuestTracker {
|
|||||||
return cur >= needed * 3600000L;
|
return cur >= needed * 3600000L;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 打招呼/发消息/聊天
|
|
||||||
if (key.contains("打招呼")
|
if (key.contains("打招呼")
|
||||||
|| key.contains("打个招呼")
|
|| key.contains("打个招呼")
|
||||||
|| key.contains("发消息")
|
|| key.contains("发消息")
|
||||||
@@ -2114,7 +2064,6 @@ public class QuestTracker {
|
|||||||
player, "CHAT") >= 1;
|
player, "CHAT") >= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 破坏/放置方块
|
|
||||||
if ((key.contains("破坏")
|
if ((key.contains("破坏")
|
||||||
|| key.contains("放置"))
|
|| key.contains("放置"))
|
||||||
&& key.contains("方块")) {
|
&& key.contains("方块")) {
|
||||||
@@ -2127,25 +2076,20 @@ public class QuestTracker {
|
|||||||
return total >= needed;
|
return total >= needed;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 连续登录
|
|
||||||
if (key.contains("连续")
|
if (key.contains("连续")
|
||||||
&& key.contains("登录")) {
|
&& key.contains("登录")) {
|
||||||
int needed = parseNumberFromText(key);
|
int needed = parseNumberFromText(key);
|
||||||
if (needed <= 0) needed = 1;
|
if (needed <= 0) needed = 1;
|
||||||
// 优先用累计天数,因为
|
Object val =
|
||||||
// streak 可能大于 total(数据不一致时)
|
getDb().getField(
|
||||||
int totalDays = getIntField(
|
player,
|
||||||
player,
|
"checkin_streak");
|
||||||
"total_checkin_days");
|
int streak = val instanceof Number
|
||||||
if (totalDays == 0) {
|
? ((Number) val).intValue()
|
||||||
totalDays = getIntField(
|
: 0;
|
||||||
player,
|
return streak >= needed;
|
||||||
"checkin_streak");
|
|
||||||
}
|
|
||||||
return totalDays >= needed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 挖矿
|
|
||||||
if (key.startsWith("MINE:")) {
|
if (key.startsWith("MINE:")) {
|
||||||
String[] p = key.split(":");
|
String[] p = key.split(":");
|
||||||
if (p.length >= 3) {
|
if (p.length >= 3) {
|
||||||
@@ -2155,7 +2099,6 @@ public class QuestTracker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 击杀生物
|
|
||||||
if (key.startsWith("KILL:")) {
|
if (key.startsWith("KILL:")) {
|
||||||
String[] p = key.split(":");
|
String[] p = key.split(":");
|
||||||
if (p.length >= 3) {
|
if (p.length >= 3) {
|
||||||
@@ -2165,7 +2108,6 @@ public class QuestTracker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 击杀玩家
|
|
||||||
if (key.startsWith("KILL_PLAYER")) {
|
if (key.startsWith("KILL_PLAYER")) {
|
||||||
String[] p = key.split(":");
|
String[] p = key.split(":");
|
||||||
int n = p.length >= 2
|
int n = p.length >= 2
|
||||||
@@ -2174,7 +2116,6 @@ public class QuestTracker {
|
|||||||
"KILL_PLAYER") >= n;
|
"KILL_PLAYER") >= n;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 合成
|
|
||||||
if (key.startsWith("CRAFT")) {
|
if (key.startsWith("CRAFT")) {
|
||||||
String[] p = key.split(":");
|
String[] p = key.split(":");
|
||||||
int n = p.length >= 2
|
int n = p.length >= 2
|
||||||
@@ -2183,7 +2124,6 @@ public class QuestTracker {
|
|||||||
player, "CRAFT") >= n;
|
player, "CRAFT") >= n;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 钓鱼
|
|
||||||
if (key.startsWith("FISH")) {
|
if (key.startsWith("FISH")) {
|
||||||
String[] p = key.split(":");
|
String[] p = key.split(":");
|
||||||
int n = p.length >= 2
|
int n = p.length >= 2
|
||||||
@@ -2192,7 +2132,6 @@ public class QuestTracker {
|
|||||||
player, "FISH") >= n;
|
player, "FISH") >= n;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 在线时长
|
|
||||||
if (key.startsWith("PLAYTIME")) {
|
if (key.startsWith("PLAYTIME")) {
|
||||||
String[] p = key.split(":");
|
String[] p = key.split(":");
|
||||||
long n = p.length >= 2
|
long n = p.length >= 2
|
||||||
@@ -2200,69 +2139,27 @@ public class QuestTracker {
|
|||||||
return getCounterLong(player,
|
return getCounterLong(player,
|
||||||
"PLAYTIME") >= n;
|
"PLAYTIME") >= n;
|
||||||
}
|
}
|
||||||
// 上报村庄
|
|
||||||
if (key.contains("上报")
|
if (key.contains("上报")
|
||||||
&& key.contains("村庄")) {
|
&& key.contains("村庄")) {
|
||||||
int needed = parseNumberFromText(key);
|
int needed = parseNumberFromText(key);
|
||||||
if (needed <= 0) needed = 1;
|
if (needed <= 0) needed = 1;
|
||||||
int cur = getCounter(
|
return getCounter(
|
||||||
player, "REPORT_VILLAGE");
|
player, "REPORT_VILLAGE")
|
||||||
return cur >= needed;
|
>= needed;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 探索村庄
|
|
||||||
if (key.contains("探索")
|
if (key.contains("探索")
|
||||||
&& key.contains("村庄")) {
|
&& key.contains("村庄")) {
|
||||||
return getCounter(
|
return getCounter(
|
||||||
player, "REPORT_VILLAGE")
|
player, "REPORT_VILLAGE")
|
||||||
>= 1;
|
>= 1;
|
||||||
}
|
}
|
||||||
// 近7天登录记录
|
|
||||||
if (key.contains("7天")
|
if (key.contains("7天")
|
||||||
|| key.contains("七天")) {
|
|| key.contains("七天")) {
|
||||||
int needed = parseNumberFromText(key);
|
int needed = parseNumberFromText(key);
|
||||||
if (needed <= 0) needed = 1;
|
if (needed <= 0) needed = 1;
|
||||||
// 优先使用 total_checkin_days
|
|
||||||
int totalDays = getIntField(
|
|
||||||
player,
|
|
||||||
"total_checkin_days");
|
|
||||||
if (totalDays == 0) {
|
|
||||||
totalDays = getIntField(
|
|
||||||
player,
|
|
||||||
"checkin_streak");
|
|
||||||
}
|
|
||||||
if (totalDays == 0) {
|
|
||||||
totalDays = getIntField(
|
|
||||||
player, "streak");
|
|
||||||
return totalDays >= needed;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// 诊断:读取数据库所有字段
|
|
||||||
try {
|
|
||||||
var user = getDb().getUser(
|
|
||||||
player);
|
|
||||||
if (user != null) {
|
|
||||||
plugin.getLogger().info(
|
|
||||||
"[QuestTracker] "
|
|
||||||
+ "登录诊断 "
|
|
||||||
+ player + ": "
|
|
||||||
+ user.toString());
|
|
||||||
} else {
|
|
||||||
plugin.getLogger().info(
|
|
||||||
"[QuestTracker] "
|
|
||||||
+ "登录诊断: "
|
|
||||||
+ player
|
|
||||||
+ " getUser返回null");
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
plugin.getLogger().info(
|
|
||||||
"[QuestTracker] "
|
|
||||||
+ "登录诊断异常: "
|
|
||||||
+ e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
int streak = getIntField(
|
int streak = getIntField(
|
||||||
player,
|
player,
|
||||||
"checkin_streak");
|
"checkin_streak");
|
||||||
@@ -2275,17 +2172,9 @@ public class QuestTracker {
|
|||||||
player,
|
player,
|
||||||
"total_checkin_days");
|
"total_checkin_days");
|
||||||
}
|
}
|
||||||
|
|
||||||
plugin.getLogger().info(
|
|
||||||
"[QuestTracker] 登录检测: "
|
|
||||||
+ player
|
|
||||||
+ " 需要=" + needed
|
|
||||||
+ " 实际=" + streak);
|
|
||||||
|
|
||||||
return streak >= needed;
|
return streak >= needed;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 完成新手任务全部内容
|
|
||||||
if (key.contains("新手任务")
|
if (key.contains("新手任务")
|
||||||
&& key.contains("全部")) {
|
&& key.contains("全部")) {
|
||||||
List<QuestFile> quests =
|
List<QuestFile> quests =
|
||||||
@@ -2299,7 +2188,6 @@ public class QuestTracker {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 完成主线任务全部内容
|
|
||||||
if (key.contains("主线任务")
|
if (key.contains("主线任务")
|
||||||
&& key.contains("全部")) {
|
&& key.contains("全部")) {
|
||||||
List<QuestFile> quests =
|
List<QuestFile> quests =
|
||||||
@@ -2365,6 +2253,23 @@ public class QuestTracker {
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
private int getIntField(
|
||||||
|
String player, String field) {
|
||||||
|
try {
|
||||||
|
Object val = getDb().getField(
|
||||||
|
player, field);
|
||||||
|
if (val instanceof Number) {
|
||||||
|
return ((Number) val).intValue();
|
||||||
|
}
|
||||||
|
if (val != null) {
|
||||||
|
return Integer.parseInt(
|
||||||
|
val.toString().trim());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 忽略
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
private long getCounterLong(
|
private long getCounterLong(
|
||||||
String player, String key) {
|
String player, String key) {
|
||||||
|
|||||||
@@ -14,15 +14,20 @@ import java.util.logging.Logger;
|
|||||||
public class RadioDownloadListener
|
public class RadioDownloadListener
|
||||||
implements Listener {
|
implements Listener {
|
||||||
|
|
||||||
private final Logger log;
|
|
||||||
private final Main plugin;
|
private final Main plugin;
|
||||||
|
private final Logger log;
|
||||||
private final Map<UUID, Integer> retryCount =
|
private final Map<UUID, Integer> retryCount =
|
||||||
new ConcurrentHashMap<>();
|
new ConcurrentHashMap<>();
|
||||||
private static final int MAX_RETRY = 2;
|
private final Map<UUID, Integer> totalAttempts =
|
||||||
|
new ConcurrentHashMap<>();
|
||||||
|
private static final int MAX_RETRY = 3;
|
||||||
|
// 每位玩家最多总共尝试5次,防死循环
|
||||||
|
private static final int MAX_TOTAL = 5;
|
||||||
|
|
||||||
public RadioDownloadListener(Main plugin) {
|
public RadioDownloadListener(Main plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.log = plugin.getLogger();
|
this.log = plugin.getLogger();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
@@ -33,86 +38,81 @@ public class RadioDownloadListener
|
|||||||
String status = e.getStatus().name();
|
String status = e.getStatus().name();
|
||||||
|
|
||||||
log.info("[Radio] " + p.getName()
|
log.info("[Radio] " + p.getName()
|
||||||
+ " status: " + status);
|
+ " 资源包: " + status);
|
||||||
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case "ACCEPTED":
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "DOWNLOADED":
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "SUCCESS":
|
case "SUCCESS":
|
||||||
log.info("[Radio] " + p.getName()
|
log.info("[Radio] " + p.getName()
|
||||||
+ " 资源包加载成功");
|
+ " 资源包加载成功");
|
||||||
retryCount.remove(uuid);
|
retryCount.remove(uuid);
|
||||||
|
totalAttempts.remove(uuid);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "FAILED_DOWNLOAD":
|
case "FAILED_DOWNLOAD":
|
||||||
handleRetry(p, uuid);
|
int retry = retryCount
|
||||||
|
.getOrDefault(uuid, 0) + 1;
|
||||||
|
int total = totalAttempts
|
||||||
|
.getOrDefault(uuid, 0) + 1;
|
||||||
|
retryCount.put(uuid, retry);
|
||||||
|
totalAttempts.put(uuid, total);
|
||||||
|
|
||||||
|
log.warning("[Radio] " + p.getName()
|
||||||
|
+ " 下载失败 (重试"
|
||||||
|
+ retry + "/" + MAX_RETRY
|
||||||
|
+ ", 总计" + total
|
||||||
|
+ "/" + MAX_TOTAL + ")");
|
||||||
|
|
||||||
|
if (total >= MAX_TOTAL) {
|
||||||
|
p.sendMessage(
|
||||||
|
"§7[Radio] §f资源包加载失败,跳过");
|
||||||
|
retryCount.remove(uuid);
|
||||||
|
totalAttempts.remove(uuid);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (retry > MAX_RETRY) {
|
||||||
|
retryCount.put(uuid, 0);
|
||||||
|
Bukkit.getScheduler()
|
||||||
|
.runTaskLater(plugin,
|
||||||
|
() -> {
|
||||||
|
if (p.isOnline()
|
||||||
|
&& plugin
|
||||||
|
.radio
|
||||||
|
!= null) {
|
||||||
|
plugin.radio
|
||||||
|
.sendResourcePack(
|
||||||
|
p);
|
||||||
|
}
|
||||||
|
}, 100L);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.sendMessage(
|
||||||
|
"§e[Radio] §f下载失败,重试中...");
|
||||||
|
Bukkit.getScheduler()
|
||||||
|
.runTaskLater(plugin,
|
||||||
|
() -> {
|
||||||
|
if (p.isOnline()
|
||||||
|
&& plugin.radio
|
||||||
|
!= null) {
|
||||||
|
plugin.radio
|
||||||
|
.sendResourcePack(
|
||||||
|
p);
|
||||||
|
}
|
||||||
|
}, 60L);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "DECLINED":
|
case "DECLINED":
|
||||||
log.info("[Radio] " + p.getName()
|
log.info("[Radio] " + p.getName()
|
||||||
+ " 拒绝下载");
|
+ " 拒绝下载");
|
||||||
p.sendMessage(
|
|
||||||
"§e[Radio] §f你拒绝了资源包");
|
|
||||||
retryCount.remove(uuid);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "DISCARDED":
|
|
||||||
log.warning("[Radio] " + p.getName()
|
|
||||||
+ " DISCARDED");
|
|
||||||
p.sendMessage(
|
|
||||||
"§c[Radio] §f资源包下载失败"
|
|
||||||
+ ",可能原因:");
|
|
||||||
p.sendMessage(
|
|
||||||
"§71. CDN/防火墙拦截");
|
|
||||||
p.sendMessage(
|
|
||||||
"§72. SSL证书问题");
|
|
||||||
retryCount.remove(uuid);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "INVALID_URL":
|
|
||||||
log.warning("[Radio] " + p.getName()
|
|
||||||
+ " URL无效");
|
|
||||||
retryCount.remove(uuid);
|
retryCount.remove(uuid);
|
||||||
|
totalAttempts.remove(uuid);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
log.info("[Radio] " + p.getName()
|
retryCount.remove(uuid);
|
||||||
+ " 未知: " + status);
|
totalAttempts.remove(uuid);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
private void handleRetry(Player p, UUID uuid) {
|
|
||||||
int count = retryCount
|
|
||||||
.getOrDefault(uuid, 0) + 1;
|
|
||||||
retryCount.put(uuid, count);
|
|
||||||
|
|
||||||
log.warning("[Radio] " + p.getName()
|
|
||||||
+ " 下载失败 (" + count
|
|
||||||
+ "/" + MAX_RETRY + ")");
|
|
||||||
|
|
||||||
if (count <= MAX_RETRY) {
|
|
||||||
p.sendMessage(
|
|
||||||
"§e[Radio] §f下载失败,重试中... ("
|
|
||||||
+ count + "/" + MAX_RETRY + ")");
|
|
||||||
Bukkit.getScheduler().runTaskLater(
|
|
||||||
plugin,
|
|
||||||
() -> {
|
|
||||||
if (p.isOnline()
|
|
||||||
&& plugin.radio != null) {
|
|
||||||
plugin.radio
|
|
||||||
.sendResourcePack(p);
|
|
||||||
}
|
|
||||||
}, 60L);
|
|
||||||
} else {
|
|
||||||
p.sendMessage(
|
|
||||||
"§c[Radio] §f资源包加载失败,"
|
|
||||||
+ "部分音乐无法播放");
|
|
||||||
retryCount.remove(uuid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1641,4 +1641,4 @@ public class TicketManager {
|
|||||||
}
|
}
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,5 +86,4 @@ commands:
|
|||||||
usage: /垃圾清理
|
usage: /垃圾清理
|
||||||
menu:
|
menu:
|
||||||
description: 雪球菜单开关控制
|
description: 雪球菜单开关控制
|
||||||
usage: /menu <开/关>
|
usage: /menu <开/关>
|
||||||
commands:
|
|
||||||
Reference in New Issue
Block a user