Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3c694406b6 | ||
|
|
dc697b8a78 | ||
|
|
05fb8ba71f | ||
|
|
17ddc80c11 | ||
|
|
cfeabca498 | ||
|
|
2bc84ee950 | ||
|
|
aa0fa09ec3 |
+243
-143
@@ -1,6 +1,5 @@
|
|||||||
package com.CY;
|
package com.CY;
|
||||||
|
|
||||||
import net.milkbowl.vault.economy.Economy;
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.NamespacedKey;
|
import org.bukkit.NamespacedKey;
|
||||||
@@ -369,16 +368,23 @@ public class Main extends JavaPlugin
|
|||||||
private static final String T_ITEM_EDIT = "§e§l商品编辑";
|
private static final String T_ITEM_EDIT = "§e§l商品编辑";
|
||||||
private static final String T_NEW_ITEM = "§a§l发布商品";
|
private static final String T_NEW_ITEM = "§a§l发布商品";
|
||||||
|
|
||||||
|
// ===== 更新检查通道(优先级递减,共5路)=====
|
||||||
|
private static final String API_GIT = "https://git.ypshidifu.cn/api/v1/repos/youpaishidifu/CY_beibao/releases/latest";
|
||||||
|
private static final String DL_GIT = "https://git.ypshidifu.cn/youpaishidifu/CY_beibao/releases";
|
||||||
private static final String API_GH =
|
private static final String API_GH =
|
||||||
"https://api.github.com/repos/ypsdf1/CY_beibao/releases/latest";
|
"https://api.github.com/repos/ypsdf1/CY_beibao/releases/latest";
|
||||||
private static final String API_GE =
|
private static final String API_GE =
|
||||||
"https://gitee.com/api/v5/repos/nihaoshidifu/cy_beibao/releases/latest";
|
"https://gitee.com/api/v5/repos/nihaoshidifu/cy_beibao/releases/latest";
|
||||||
|
private static final String API_GC =
|
||||||
|
"https://api.gitcode.com/api/v5/repos/ypsdf1/CY_beibao/releases?per_page=1";
|
||||||
private static final String DL_GH =
|
private static final String DL_GH =
|
||||||
"https://github.com/ypsdf1/CY_beibao/releases";
|
"https://github.com/ypsdf1/CY_beibao/releases";
|
||||||
private static final String DL_GE =
|
private static final String DL_GE =
|
||||||
"https://gitee.com/nihaoshidifu/cy_beibao/releases";
|
"https://gitee.com/nihaoshidifu/cy_beibao/releases";
|
||||||
|
private static final String DL_GC =
|
||||||
|
"https://gitcode.com/ypsdf1/CY_beibao/releases";
|
||||||
|
|
||||||
// 第三路备选:宝塔静态HTML
|
// 第五路备选:宝塔静态HTML
|
||||||
private static final String FALLBACK_HTML =
|
private static final String FALLBACK_HTML =
|
||||||
"https://caoyuan.ypshidifu.cn/update_check.html";
|
"https://caoyuan.ypshidifu.cn/update_check.html";
|
||||||
|
|
||||||
@@ -389,7 +395,8 @@ public class Main extends JavaPlugin
|
|||||||
Material.REDSTONE, Material.COAL, Material.QUARTZ
|
Material.REDSTONE, Material.COAL, Material.QUARTZ
|
||||||
};
|
};
|
||||||
|
|
||||||
private Economy economy;
|
private Object economy; // Vault Economy — 可选软连接,bond优先
|
||||||
|
private boolean vaultAttempted = false; // 已尝试过Vault连接?
|
||||||
private Connection db;
|
private Connection db;
|
||||||
private NamespacedKey shopIconKey;
|
private NamespacedKey shopIconKey;
|
||||||
|
|
||||||
@@ -419,6 +426,15 @@ public class Main extends JavaPlugin
|
|||||||
private Object sdf1Plugin = null;
|
private Object sdf1Plugin = null;
|
||||||
private Object bondManager = null;
|
private Object bondManager = null;
|
||||||
private boolean bondInited = false;
|
private boolean bondInited = false;
|
||||||
|
private boolean bondConnectRetrying = true;
|
||||||
|
|
||||||
|
private boolean getBondManagerNotReady() {
|
||||||
|
if (bondInited || !isBondMode()) return false;
|
||||||
|
if (bondConnectRetrying) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private String masterPluginName = "";
|
private String masterPluginName = "";
|
||||||
@@ -489,55 +505,37 @@ public void onEnable() {
|
|||||||
|
|
||||||
initDB();
|
initDB();
|
||||||
loadShop(); // economyMode 在这里被读取
|
loadShop(); // economyMode 在这里被读取
|
||||||
// 反射发现 Sdf1_login 债券系统
|
|
||||||
// 反射发现 Sdf1_login 债券系统
|
|
||||||
// onEnable 里反射发现
|
|
||||||
Bukkit.getScheduler().runTaskLater(this, () -> {
|
|
||||||
try {
|
|
||||||
org.bukkit.plugin.Plugin pl = Bukkit.getPluginManager().getPlugin("Sdf1_login");
|
|
||||||
if (pl == null || !pl.isEnabled()) {
|
|
||||||
getLogger().warning("[经济] Sdf1_login 未就绪");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
java.lang.reflect.Method m = pl.getClass().getMethod("getBondManager");
|
|
||||||
bondManager = m.invoke(pl);
|
|
||||||
bondInited = (bondManager != null);
|
|
||||||
getLogger().info("[经济] " + (bondInited ? "连接成功" : "返回null"));
|
|
||||||
} catch (Exception e) {
|
|
||||||
getLogger().severe("[经济] 连接失败: " + e.getMessage());
|
|
||||||
}
|
|
||||||
}, 40L);
|
|
||||||
|
|
||||||
// 定期重连(万一插件延迟启动)
|
|
||||||
Bukkit.getScheduler().runTaskTimer(this, () -> {
|
|
||||||
if (bondInited) return;
|
|
||||||
try {
|
|
||||||
org.bukkit.plugin.Plugin pl = Bukkit.getPluginManager().getPlugin("Sdf1_login");
|
|
||||||
if (pl == null || !pl.isEnabled()) return;
|
|
||||||
sdf1Plugin = pl;
|
|
||||||
|
|
||||||
java.lang.reflect.Field targetField = null;
|
|
||||||
for (java.lang.reflect.Field f : pl.getClass().getDeclaredFields()) {
|
|
||||||
if (f.getType().getName().contains("BondManager")) {
|
|
||||||
targetField = f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (targetField == null) return;
|
|
||||||
|
|
||||||
targetField.setAccessible(true);
|
|
||||||
bondManager = targetField.get(pl);
|
|
||||||
if (bondManager != null) {
|
|
||||||
bondInited = true;
|
|
||||||
getLogger().info("[经济] 重连成功");
|
|
||||||
}
|
|
||||||
} catch (Exception ignored) {}
|
|
||||||
}, 100L, 200L);
|
|
||||||
|
|
||||||
|
// ★ 经济系统启动:优先 bond,其次 Vault,最后放弃
|
||||||
|
setupEconomy();
|
||||||
|
|
||||||
getCommand("cy").setExecutor(this);
|
getCommand("cy").setExecutor(this);
|
||||||
getCommand("cy").setTabCompleter(this);
|
getCommand("cy").setTabCompleter(this);
|
||||||
getServer().getPluginManager().registerEvents(this, this);
|
getServer().getPluginManager().registerEvents(this, this);
|
||||||
|
|
||||||
|
// Bond 定期重连(万一 Sdf1_login 延迟启动)
|
||||||
|
Bukkit.getScheduler().runTaskTimer(this, () -> {
|
||||||
|
if (bondInited) return;
|
||||||
|
try {
|
||||||
|
// 与 setupEconomy / invokeBond 一致的取实例方式:
|
||||||
|
// 通过 PluginManager 拿到 Sdf1_login 插件实例,再反射调用 getBonds() 取得 BondManager。
|
||||||
|
// 旧逻辑反射 Main.INSTANCE 静态字段 —— 而 Sdf1_login 根本没有该字段,
|
||||||
|
// 导致 NoSuchFieldException 被静默吞掉、重连永远失败、债券对接失效。
|
||||||
|
org.bukkit.plugin.Plugin pl = Bukkit.getPluginManager().getPlugin("Sdf1_login");
|
||||||
|
if (pl != null && pl.isEnabled()) {
|
||||||
|
java.lang.reflect.Method getBM = pl.getClass().getMethod("getBonds");
|
||||||
|
Object bm = getBM.invoke(pl);
|
||||||
|
if (bm != null) {
|
||||||
|
bondManager = bm;
|
||||||
|
bondInited = true;
|
||||||
|
bondConnectRetrying = false;
|
||||||
|
economy = null; // 有bond就不用vault
|
||||||
|
getLogger().info("[经济] Bond 重连成功(Sdf1_login延迟启动)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
}, 100L, 200L);
|
||||||
|
|
||||||
Bukkit.getScheduler().runTaskTimer(this,
|
Bukkit.getScheduler().runTaskTimer(this,
|
||||||
() -> checkAutoRenewal(), 200L, 200L);
|
() -> checkAutoRenewal(), 200L, 200L);
|
||||||
Bukkit.getScheduler().runTaskTimer(this,
|
Bukkit.getScheduler().runTaskTimer(this,
|
||||||
@@ -566,26 +564,64 @@ public void onEnable() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setupEconomy() {
|
private void setupEconomy() {
|
||||||
if (getServer().getPluginManager().getPlugin("Vault") == null) {
|
// 优先使用 Sdf1_login 债券系统
|
||||||
getLogger().warning("[Vault] 未找到,5秒后重试");
|
try {
|
||||||
Bukkit.getScheduler().runTaskLater(this,
|
org.bukkit.plugin.Plugin pl = Bukkit.getPluginManager().getPlugin("Sdf1_login");
|
||||||
() -> setupEconomy(), 100L);
|
if (pl != null && pl.isEnabled()) {
|
||||||
|
// Sdf1_login 已加载,通过 Main.getBonds() 获取 BondManager
|
||||||
|
java.lang.reflect.Method getBM = pl.getClass().getMethod("getBonds");
|
||||||
|
Object bm = getBM.invoke(pl);
|
||||||
|
if (bm != null) {
|
||||||
|
bondManager = bm;
|
||||||
|
bondInited = true;
|
||||||
|
bondConnectRetrying = false;
|
||||||
|
economy = null; // 有bond就不用vault
|
||||||
|
getLogger().info("[经济] 已连接 Sdf1_login 债券系统");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
|
||||||
|
// 其次检查是否已经在 onEnable 延迟初始化中连接了 bond
|
||||||
|
if (bondInited) {
|
||||||
|
economy = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
RegisteredServiceProvider<Economy> rsp =
|
|
||||||
getServer().getServicesManager().getRegistration(Economy.class);
|
// bond 也不可用,尝试 Vault(软连接,可选)
|
||||||
if (rsp != null) {
|
if (vaultAttempted) return; // 只尝试一次
|
||||||
economy = rsp.getProvider();
|
vaultAttempted = true;
|
||||||
getLogger().info("[Vault] 已连接: " + economy.getName());
|
|
||||||
} else {
|
if (getServer().getPluginManager().getPlugin("Vault") == null) {
|
||||||
getLogger().warning("[Vault] 未找到经济提供者");
|
getLogger().info("[经济] Vault 未安装,经济功能不可用(仅支持bond模式)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// 用字符串拼接避免直接引用 Vault 类导致 NoClassDefFoundError
|
||||||
|
String className = "net.milkbowl.vault.economy.Economy";
|
||||||
|
Class<?> ecoClass = Class.forName(className);
|
||||||
|
Object rsp = getServer().getServicesManager().getRegistration(ecoClass);
|
||||||
|
if (rsp != null) {
|
||||||
|
economy = rsp;
|
||||||
|
getLogger().info("[经济] 已连接 Vault: " + economy.getClass().getSimpleName());
|
||||||
|
} else {
|
||||||
|
getLogger().warning("[经济] Vault 存在但未注册经济提供者");
|
||||||
|
}
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
getLogger().warning("[经济] Vault Economy 类不可用");
|
||||||
|
} catch (Exception e) {
|
||||||
|
getLogger().warning("[经济] Vault 连接失败: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void checkAutoRenewal() {
|
private void checkAutoRenewal() {
|
||||||
if (db == null) return;
|
if (db == null) return;
|
||||||
|
// Bond 模式下 bondManager 未就绪则跳过(等待 onEnable 延迟初始化或定期重连)
|
||||||
|
if (isBondMode() && !bondInited) return;
|
||||||
|
// Vault 模式下必须 economy 不为 null
|
||||||
if (!isBondMode() && economy == null) return;
|
if (!isBondMode() && economy == null) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
PreparedStatement ps = db.prepareStatement(
|
PreparedStatement ps = db.prepareStatement(
|
||||||
"SELECT player_name, membership_slots, expire_time, plan_id "
|
"SELECT player_name, membership_slots, expire_time, plan_id "
|
||||||
@@ -625,19 +661,45 @@ public void onEnable() {
|
|||||||
setAutoRenew(name, false);
|
setAutoRenew(name, false);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// 统一经济接口
|
// Bond模式特有逻辑
|
||||||
if (hasEnough(name, price)) {
|
if (isBondMode()) {
|
||||||
withdraw(name, price);
|
if (isBondFrozen(name)) {
|
||||||
setExpire(name, exp + (long) days * 86400000L);
|
setAutoRenew(name, false);
|
||||||
Player online = Bukkit.getPlayer(name);
|
Player online = Bukkit.getPlayer(name);
|
||||||
if (online != null && online.isOnline()) {
|
if (online != null && online.isOnline()) {
|
||||||
online.sendMessage("§a[CY] §f自动续费成功!延长" + days + "天,扣除$" + fmt(price));
|
online.sendMessage("§c[CY] §f自动续费失败!账户已被冻结");
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (hasEnough(name, price)) {
|
||||||
|
withdraw(name, price);
|
||||||
|
setExpire(name, exp + (long) days * 86400000L);
|
||||||
|
Player online = Bukkit.getPlayer(name);
|
||||||
|
if (online != null && online.isOnline()) {
|
||||||
|
online.sendMessage("§a[CY] §f自动续费成功!延长" + days + "天,扣除" + bondName + "$" + fmt(price));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setAutoRenew(name, false);
|
||||||
|
Player online = Bukkit.getPlayer(name);
|
||||||
|
if (online != null && online.isOnline()) {
|
||||||
|
online.sendMessage("§c[CY] §f" + bondName + "不足(需要$" + fmt(price) + "),自动续费已关闭");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setAutoRenew(name, false);
|
// Vault模式
|
||||||
Player online = Bukkit.getPlayer(name);
|
if (hasEnough(name, price)) {
|
||||||
if (online != null && online.isOnline()) {
|
withdraw(name, price);
|
||||||
online.sendMessage("§c[CY] §f余额不足(需要$" + fmt(price) + "),自动续费已关闭");
|
setExpire(name, exp + (long) days * 86400000L);
|
||||||
|
Player online = Bukkit.getPlayer(name);
|
||||||
|
if (online != null && online.isOnline()) {
|
||||||
|
online.sendMessage("§a[CY] §f自动续费成功!延长" + days + "天,扣除$" + fmt(price));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setAutoRenew(name, false);
|
||||||
|
Player online = Bukkit.getPlayer(name);
|
||||||
|
if (online != null && online.isOnline()) {
|
||||||
|
online.sendMessage("§c[CY] §f余额不足(需要$" + fmt(price) + "),自动续费已关闭");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -657,14 +719,16 @@ public void onEnable() {
|
|||||||
|
|
||||||
private boolean withdraw(String name, double amount) {
|
private boolean withdraw(String name, double amount) {
|
||||||
if (isBondMode()) {
|
if (isBondMode()) {
|
||||||
boolean result = withdrawFromSdf1(name, amount);
|
return withdrawFromSdf1(name, amount);
|
||||||
getLogger().info("[调试] withdraw bond name=" + name + " amount=" + amount + " result=" + result);
|
|
||||||
return result;
|
|
||||||
} else {
|
} else {
|
||||||
if (economy == null) return false;
|
if (economy == null) return false;
|
||||||
org.bukkit.OfflinePlayer op = Bukkit.getOfflinePlayer(name);
|
org.bukkit.OfflinePlayer op = Bukkit.getOfflinePlayer(name);
|
||||||
if (!economy.has(op, amount)) return false;
|
try {
|
||||||
economy.withdrawPlayer(op, amount);
|
java.lang.reflect.Method m = economy.getClass().getMethod("has", org.bukkit.OfflinePlayer.class, double.class);
|
||||||
|
if (!(boolean)m.invoke(economy, op, amount)) return false;
|
||||||
|
java.lang.reflect.Method w = economy.getClass().getMethod("withdrawPlayer", org.bukkit.OfflinePlayer.class, double.class);
|
||||||
|
w.invoke(economy, op, amount);
|
||||||
|
} catch (NoSuchMethodException | IllegalAccessException | java.lang.reflect.InvocationTargetException e) { return false; }
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -972,16 +1036,11 @@ public void onEnable() {
|
|||||||
try {
|
try {
|
||||||
org.bukkit.plugin.Plugin pl = Bukkit.getPluginManager().getPlugin("Sdf1_login");
|
org.bukkit.plugin.Plugin pl = Bukkit.getPluginManager().getPlugin("Sdf1_login");
|
||||||
if (pl != null && pl.isEnabled()) {
|
if (pl != null && pl.isEnabled()) {
|
||||||
java.lang.reflect.Field targetField = null;
|
java.lang.reflect.Method getBM = pl.getClass().getMethod("getBonds");
|
||||||
for (java.lang.reflect.Field f : pl.getClass().getDeclaredFields()) {
|
Object bm = getBM.invoke(pl);
|
||||||
if (f.getType().getName().contains("BondManager")) {
|
if (bm != null) {
|
||||||
targetField = f;
|
bondManager = bm;
|
||||||
}
|
bondInited = true;
|
||||||
}
|
|
||||||
if (targetField != null) {
|
|
||||||
targetField.setAccessible(true);
|
|
||||||
bondManager = targetField.get(pl);
|
|
||||||
if (bondManager != null) bondInited = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {}
|
||||||
@@ -1028,18 +1087,14 @@ public void onEnable() {
|
|||||||
|
|
||||||
// ===== 债券 - 冻结状态 =====
|
// ===== 债券 - 冻结状态 =====
|
||||||
private boolean isBondFrozen(String name) {
|
private boolean isBondFrozen(String name) {
|
||||||
getLogger().info("[调试] isBondFrozen被调用 name=" + name + " bondManager=" + (bondManager != null ? "非null" : "null") + " bondInited=" + bondInited);
|
|
||||||
if (bondManager == null) {
|
if (bondManager == null) {
|
||||||
getLogger().warning("[调试] bondManager为null,无法检查冻结");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
java.lang.reflect.Method m = bondManager.getClass().getMethod("isFrozen", String.class);
|
java.lang.reflect.Method m = bondManager.getClass().getMethod("isFrozen", String.class);
|
||||||
Object r = m.invoke(bondManager, name);
|
Object r = m.invoke(bondManager, name);
|
||||||
getLogger().info("[调试] isFrozen返回: " + r);
|
|
||||||
return r instanceof Boolean && (Boolean) r;
|
return r instanceof Boolean && (Boolean) r;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
getLogger().severe("[调试] isFrozen异常: " + e.getMessage());
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1635,10 +1690,7 @@ public void onEnable() {
|
|||||||
}
|
}
|
||||||
/** 获取玩家债券余额 */
|
/** 获取玩家债券余额 */
|
||||||
private double getBonds(String name) {
|
private double getBonds(String name) {
|
||||||
if (db == null) {
|
if (db == null) return 0;
|
||||||
getLogger().info("[调试] db为null");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
PreparedStatement ps = db.prepareStatement(
|
PreparedStatement ps = db.prepareStatement(
|
||||||
"SELECT bonds FROM members WHERE player_name=?");
|
"SELECT bonds FROM members WHERE player_name=?");
|
||||||
@@ -1646,12 +1698,9 @@ public void onEnable() {
|
|||||||
ResultSet rs = ps.executeQuery();
|
ResultSet rs = ps.executeQuery();
|
||||||
boolean hasRow = rs.next();
|
boolean hasRow = rs.next();
|
||||||
double val = hasRow ? rs.getDouble("bonds") : 0;
|
double val = hasRow ? rs.getDouble("bonds") : 0;
|
||||||
getLogger().info("[调试] getBonds: name=" + name
|
|
||||||
+ " hasRow=" + hasRow + " val=" + val);
|
|
||||||
rs.close(); ps.close();
|
rs.close(); ps.close();
|
||||||
return val;
|
return val;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
getLogger().severe("[调试] getBonds异常: " + e.getMessage());
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1693,15 +1742,15 @@ public void onEnable() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private double getBalance(String name) {
|
private double getBalance(String name) {
|
||||||
getLogger().info("[调试] getBalance被调用 name=" + name + " isBondMode=" + isBondMode() + " bondInited=" + bondInited);
|
|
||||||
if (isBondMode()) {
|
if (isBondMode()) {
|
||||||
double val = getBondsFromSdf1(name);
|
return getBondsFromSdf1(name);
|
||||||
getLogger().info("[调试] 债券余额=" + val + " bondManager=" + (bondManager != null ? "非null" : "null"));
|
|
||||||
return val;
|
|
||||||
} else {
|
} else {
|
||||||
if (economy == null) return 0;
|
if (economy == null) return 0;
|
||||||
org.bukkit.OfflinePlayer op = Bukkit.getOfflinePlayer(name);
|
org.bukkit.OfflinePlayer op = Bukkit.getOfflinePlayer(name);
|
||||||
return economy.getBalance(op);
|
try {
|
||||||
|
java.lang.reflect.Method m = economy.getClass().getMethod("getBalance", org.bukkit.OfflinePlayer.class);
|
||||||
|
return (double)m.invoke(economy, op);
|
||||||
|
} catch (NoSuchMethodException | IllegalAccessException | java.lang.reflect.InvocationTargetException e) { return 0; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2232,23 +2281,57 @@ public String onSdf1GetShopItems() {
|
|||||||
sb.append(line);
|
sb.append(line);
|
||||||
br.close();
|
br.close();
|
||||||
String json = sb.toString();
|
String json = sb.toString();
|
||||||
|
|
||||||
|
// ★ 判断是否为 GitCode API 返回列表格式([]包裹)vs GitHub/Gitee 对象格式
|
||||||
|
boolean isArrayFormat = json.trim().startsWith("[");
|
||||||
String tag = "";
|
String tag = "";
|
||||||
int ti = json.indexOf("\"tag_name\"");
|
|
||||||
if (ti >= 0) {
|
|
||||||
int cs = json.indexOf("\"", ti + 11);
|
|
||||||
int ce = json.indexOf("\"", cs + 1);
|
|
||||||
if (cs >= 0 && ce >= 0)
|
|
||||||
tag = json.substring(cs + 1, ce);
|
|
||||||
}
|
|
||||||
String body = "";
|
String body = "";
|
||||||
int bi = json.indexOf("\"body\"");
|
|
||||||
if (bi >= 0) {
|
if (isArrayFormat) {
|
||||||
int bs = json.indexOf("\"", bi + 7);
|
// GitCode / Gitee v5 返回 release 列表 [ {...}, {...} ]
|
||||||
int be = json.indexOf("\"", bs + 1);
|
// 取第一个元素的 tag_name
|
||||||
if (bs >= 0 && be >= 0)
|
int arrStart = json.indexOf('[');
|
||||||
body = json.substring(bs + 1, be)
|
int objStart = json.indexOf('{', arrStart);
|
||||||
.replace("\\n", "\n");
|
if (objStart >= 0) {
|
||||||
|
int objEnd = findMatchingBracket(json, objStart);
|
||||||
|
if (objEnd >= 0) {
|
||||||
|
String obj = json.substring(objStart, objEnd);
|
||||||
|
int ti = obj.indexOf("\"tag_name\"");
|
||||||
|
if (ti >= 0) {
|
||||||
|
int cs = obj.indexOf("\"", ti + 11);
|
||||||
|
int ce = obj.indexOf("\"", cs + 1);
|
||||||
|
if (cs >= 0 && ce >= 0)
|
||||||
|
tag = obj.substring(cs + 1, ce);
|
||||||
|
}
|
||||||
|
int bi = obj.indexOf("\"body\"");
|
||||||
|
if (bi >= 0) {
|
||||||
|
int bs = obj.indexOf("\"", bi + 7);
|
||||||
|
int be = obj.indexOf("\"", bs + 1);
|
||||||
|
if (bs >= 0 && be >= 0)
|
||||||
|
body = obj.substring(bs + 1, be)
|
||||||
|
.replace("\\n", "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// GitHub / Gitea 返回单个对象 { ... }
|
||||||
|
int ti = json.indexOf("\"tag_name\"");
|
||||||
|
if (ti >= 0) {
|
||||||
|
int cs = json.indexOf("\"", ti + 11);
|
||||||
|
int ce = json.indexOf("\"", cs + 1);
|
||||||
|
if (cs >= 0 && ce >= 0)
|
||||||
|
tag = json.substring(cs + 1, ce);
|
||||||
|
}
|
||||||
|
int bi = json.indexOf("\"body\"");
|
||||||
|
if (bi >= 0) {
|
||||||
|
int bs = json.indexOf("\"", bi + 7);
|
||||||
|
int be = json.indexOf("\"", bs + 1);
|
||||||
|
if (bs >= 0 && be >= 0)
|
||||||
|
body = json.substring(bs + 1, be)
|
||||||
|
.replace("\\n", "\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tag.isEmpty()) return null;
|
if (tag.isEmpty()) return null;
|
||||||
return new String[]{tag, body};
|
return new String[]{tag, body};
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -2259,6 +2342,29 @@ public String onSdf1GetShopItems() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查找匹配的大括号,返回 closing } 的位置
|
||||||
|
*/
|
||||||
|
private int findMatchingBracket(String json, int startPos) {
|
||||||
|
if (json.charAt(startPos) != '{') return -1;
|
||||||
|
int depth = 0;
|
||||||
|
boolean inStr = false;
|
||||||
|
char prev = 0;
|
||||||
|
for (int i = startPos; i < json.length(); i++) {
|
||||||
|
char c = json.charAt(i);
|
||||||
|
if (c == '"' && prev != '\\') {
|
||||||
|
inStr = !inStr;
|
||||||
|
}
|
||||||
|
if (!inStr) {
|
||||||
|
if (c == '{') depth++;
|
||||||
|
else if (c == '}') depth--;
|
||||||
|
if (depth == 0) return i;
|
||||||
|
}
|
||||||
|
prev = c;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
// ★ 供集群更新调用
|
// ★ 供集群更新调用
|
||||||
public UpdateChecker getUpdateChecker() {
|
public UpdateChecker getUpdateChecker() {
|
||||||
return new UpdateChecker(this);
|
return new UpdateChecker(this);
|
||||||
@@ -2270,43 +2376,37 @@ public String onSdf1GetShopItems() {
|
|||||||
if (manual != null) manual.sendMessage("§e[CY_beibao] 正在检查更新...");
|
if (manual != null) manual.sendMessage("§e[CY_beibao] 正在检查更新...");
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
boolean preferGH = "GH".equalsIgnoreCase(updateCh) || updateCh.isEmpty();
|
// ★ 5通道顺序检查:git.ypshidifu.cn → GitHub → Gitee → GitCode → 宝塔
|
||||||
String pApi = preferGH ? API_GH : API_GE;
|
String[][] channels = {
|
||||||
String pDl = preferGH ? DL_GH : DL_GE;
|
{API_GIT, "git.ypshidifu.cn", DL_GIT},
|
||||||
String pName = preferGH ? "GitHub" : "Gitee";
|
{API_GH, "GitHub", DL_GH},
|
||||||
String bApi = preferGH ? API_GE : API_GH;
|
{API_GE, "Gitee", DL_GE},
|
||||||
String bDl = preferGH ? DL_GE : DL_GH;
|
{API_GC, "GitCode", DL_GC},
|
||||||
String bName = preferGH ? "Gitee" : "GitHub";
|
};
|
||||||
|
|
||||||
String[] res = fetchRelease(pApi, pName);
|
String[] res = null;
|
||||||
if (res != null) {
|
for (String[] ch : channels) {
|
||||||
String linkMsg = "[更新] " + pName + " 最新版本: " + res[0] + " | 下载: " + pDl;
|
res = fetchRelease(ch[0], ch[1]);
|
||||||
Bukkit.getConsoleSender().sendMessage("§a[CY_beibao] §e" + linkMsg);
|
if (res != null) {
|
||||||
if (manual != null)
|
String linkMsg = "[更新] " + ch[1] + " 最新版本: " + res[0] + " | 下载: " + ch[2];
|
||||||
manual.sendMessage("§a[CY_beibao] [更新] §f" + pName + " 最新版本: §e" + res[0] + " §f| 下载: §b§l" + pDl);
|
Bukkit.getConsoleSender().sendMessage("§a[CY_beibao] §e" + linkMsg);
|
||||||
applyUpdate(res[0], res[1], pDl, manual, pName);
|
if (manual != null)
|
||||||
return;
|
manual.sendMessage("§a[CY_beibao] [更新] §f" + ch[1] + " 最新版本: §e" + res[0] + " §f| 下载: §b§l" + ch[2]);
|
||||||
|
applyUpdate(res[0], res[1], ch[2], manual, ch[1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Bukkit.getConsoleSender().sendMessage("§a[CY_beibao] §e[更新] " + ch[1] + " 失败,切换下一路");
|
||||||
}
|
}
|
||||||
Bukkit.getConsoleSender().sendMessage("§a[CY_beibao] §e[更新] " + pName + " 失败,切换 " + bName);
|
|
||||||
|
|
||||||
res = fetchRelease(bApi, bName);
|
// ★ 第五路备选:宝塔静态HTML
|
||||||
if (res != null) {
|
getLogger().info("[CY_beibao] 前四路均失败,尝试第五路备选 BaoTa...");
|
||||||
String linkMsg = "[更新] " + bName + " 最新版本: " + res[0] + " | 下载: " + bDl;
|
|
||||||
Bukkit.getConsoleSender().sendMessage("§a[CY_beibao] §e" + linkMsg);
|
|
||||||
if (manual != null)
|
|
||||||
manual.sendMessage("§a[CY_beibao] [更新] §f" + bName + " 最新版本: §e" + res[0] + " §f| 下载: §b§l" + bDl);
|
|
||||||
applyUpdate(res[0], res[1], bDl, manual, bName);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// ★ 双路均失败,尝试第三路备选(宝塔静态HTML)
|
|
||||||
getLogger().info("[CY_beibao] GitHub/Gitee 均失败,尝试第三路备选 BaoTa...");
|
|
||||||
String[] fbResult = tryFallbackChannel();
|
String[] fbResult = tryFallbackChannel();
|
||||||
if (fbResult != null) {
|
if (fbResult != null) {
|
||||||
Bukkit.getConsoleSender().sendMessage("§a[CY_beibao] §e[更新] 第三路备选 BaoTa 检查成功: " + fbResult[0]);
|
Bukkit.getConsoleSender().sendMessage("§a[CY_beibao] §e[更新] 第五路备选 BaoTa 检查成功: " + fbResult[0]);
|
||||||
applyUpdate(fbResult[0], fbResult[1], DL_GH, manual, "BaoTa");
|
applyUpdate(fbResult[0], fbResult[1], DL_GE, manual, "BaoTa");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Bukkit.getConsoleSender().sendMessage("§a[CY_beibao] §c[更新] 三路均失败");
|
Bukkit.getConsoleSender().sendMessage("§a[CY_beibao] §c[更新] 五路均失败");
|
||||||
if (manual != null) manual.sendMessage("§c[CY_beibao] [更新] §f检查失败(含宝塔备选)");
|
if (manual != null) manual.sendMessage("§c[CY_beibao] [更新] §f检查失败(含宝塔备选)");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
getLogger().warning("[更新] " + e.getMessage());
|
getLogger().warning("[更新] " + e.getMessage());
|
||||||
|
|||||||
Reference in New Issue
Block a user