fix: 修复自定义附魔只能单个附魔的问题
This commit is contained in:
@@ -52,6 +52,34 @@ public class BondBridge {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/** 查询玩家当前债券余额 */
|
||||
public int getBonds(String playerName) {
|
||||
if (!isHooked()) return 0;
|
||||
try {
|
||||
org.bukkit.plugin.Plugin plug =
|
||||
org.bukkit.Bukkit
|
||||
.getPluginManager()
|
||||
.getPlugin("Sdf1_login");
|
||||
if (plug == null) return 0;
|
||||
|
||||
Object bondManager =
|
||||
plug.getClass()
|
||||
.getMethod("getBondManager")
|
||||
.invoke(plug);
|
||||
|
||||
Object result =
|
||||
bondManager.getClass()
|
||||
.getMethod("getBonds",
|
||||
String.class)
|
||||
.invoke(bondManager,
|
||||
playerName);
|
||||
|
||||
return (int) result;
|
||||
} catch (Exception e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Object findManager(Plugin sdf1) {
|
||||
Class<?> c = sdf1.getClass();
|
||||
|
||||
@@ -95,5 +95,22 @@ public class FileGenerator {
|
||||
l.add("| M.C的全称是什么? | Mojang Studios | 10 |");
|
||||
return l;
|
||||
}
|
||||
public static void ensureTreasureConfig(
|
||||
File dir) {
|
||||
dir.mkdirs();
|
||||
File f = new File(dir, "设置.txt");
|
||||
if (f.exists()) return;
|
||||
try {
|
||||
OutputStreamWriter w =
|
||||
new OutputStreamWriter(
|
||||
new FileOutputStream(f),
|
||||
StandardCharsets.UTF_8);
|
||||
w.write("# 寻宝全局设置\n");
|
||||
w.write("保底债券: 是\n");
|
||||
w.write("随机数量: 1~3\n");
|
||||
w.close();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -59,9 +59,9 @@ public class Main extends JavaPlugin
|
||||
new TreasureListener(
|
||||
this, treasureManager),
|
||||
this);
|
||||
spawnTask = new TreasureSpawnTask(
|
||||
this, treasureManager)
|
||||
.runTaskTimer(this, 600L, 600L);
|
||||
new TreasureSpawnTask(this, treasureManager)
|
||||
.runTaskTimer(this, 100L, 100L);
|
||||
|
||||
|
||||
// ★ 安全注册 Tab 补全
|
||||
if (getCommand("quiz") != null) {
|
||||
@@ -81,6 +81,14 @@ public class Main extends JavaPlugin
|
||||
.setTabCompleter(this);
|
||||
}
|
||||
|
||||
// ★ 启动时清除残留宝箱
|
||||
if (treasureManager != null) {
|
||||
treasureManager.cleanResidualChests();
|
||||
}
|
||||
if (treasureManager != null) {
|
||||
treasureManager.forceCleanClaims();
|
||||
treasureManager.cleanResidualChests();
|
||||
}
|
||||
getLogger().info("=== Sdf1_game v1.0 ===");
|
||||
getLogger().info("债券桥接: "
|
||||
+ (bondBridge.isHooked()
|
||||
@@ -118,6 +126,41 @@ public class Main extends JavaPlugin
|
||||
public void onDisable() {
|
||||
if (quizManager != null) quizManager.stopAuto();
|
||||
if (spawnTask != null) spawnTask.cancel();
|
||||
// ★ 卸载时清除所有宝箱
|
||||
treasureManager.cleanResidualChests();
|
||||
treasureManager.removeAllChests();
|
||||
treasureManager.forceCleanClaims();
|
||||
if (treasureManager != null) {
|
||||
treasureManager.forceCleanClaims();
|
||||
treasureManager.cleanResidualChests();
|
||||
}
|
||||
saveConfig();
|
||||
getLogger().info("\n" +
|
||||
" __ __ _ \n" +
|
||||
" \\ \\ / / | | \n" +
|
||||
" \\ \\ /\\ / /__ ___ ___ _ __ ___ ___ | |_ ___ \n" +
|
||||
" \\ \\/ \\/ / _ \\/ __/ _ \\| '_ ` _ \\ / _ \\ | __/ _ \\ \n" +
|
||||
" \\ /\\ / __/ (_| (_) | | | | | | __/ | || (_) | \n" +
|
||||
" \\/ \\/ \\___|\\___\\___/|_| |_| |_|\\___| \\__\\___/ _ \n" +
|
||||
" | | (_) \n" +
|
||||
" ___ __ _ ___ _ _ _ _ __ _ _ __ | |_ __ _ _ __ __ ___ __ _ _ __ ___ ___ _ ____ _____ _ __ \n" +
|
||||
" / __/ _` |/ _ \\ | | | | | | |/ _` | '_ \\ | __/ _` | '_ \\ \\ \\/ / |/ _` | '_ \\ / __|/ _ \\ '__\\ \\ / / _ \\ '__| \n" +
|
||||
" | (_| (_| | (_) | | |_| | |_| | (_| | | | | | || (_| | | | | > <| | (_| | | | | \\__ \\ __/ | \\ V / __/ | \n" +
|
||||
" \\___\\__,_|\\___/ \\__, |\\__,_|\\__,_|_| |_| \\__\\__,_|_| |_|_/_/\\_\\_|\\__,_|_| |_|_|___/\\___|_| _ \\_/ \\___|_| \n" +
|
||||
" __/ | (_) _ |__ \\ | | (_) | (_)/ _| \n" +
|
||||
" ___ ___ _ ____ |___/ _ __ _ _ __ (_) _ __ ___ ___ ) | _ _ _ __ ___| |__ _ __| |_| |_ _ _ ___ _ __ \n" +
|
||||
" / __|/ _ \\ '__\\ \\ / / _ \\ '__| | '_ \\ | '_ ` _ \\ / __| / / | | | | '_ \\/ __| '_ \\| |/ _` | | _| | | | / __| '_ \\ \n" +
|
||||
" \\__ \\ __/ | \\ V / __/ | | | |_) | _ | | | | | | (__ / /_ | |_| | |_) \\__ \\ | | | | (_| | | | | |_| || (__| | | |\n" +
|
||||
" |___/\\___|_| \\_/ \\___|_| |_| .__/ (_) |_| |_| |_|\\___|____(_)__, | .__/|___/_| |_|_|\\__,_|_|_| \\__,_(_)___|_| |_|\n" +
|
||||
" | | __/ | | \n" +
|
||||
" _ ____ _|_| ________ ___ |___/|_| \n" +
|
||||
" | | _|___ \\ / _ \\ / /____ / _ \\ \n" +
|
||||
" _ __ ___ ___| |_(_) __) | | | |/ /_ / / (_) | \n" +
|
||||
" | '_ \\ / _ \\/ __| __| |__ <| | | | '_ \\ / / \\__, | \n" +
|
||||
" | |_) | (_) \\__ \\ |_ _ ___) | |_| | (_) / / / / \n" +
|
||||
" | .__/ \\___/|___/\\__(_)____/ \\___/ \\___/_/ /_/ \n" +
|
||||
" | | \n" +
|
||||
" |_| ");
|
||||
}
|
||||
|
||||
// ========== 命令 ==========
|
||||
@@ -199,6 +242,10 @@ public class Main extends JavaPlugin
|
||||
return false;
|
||||
}
|
||||
|
||||
public TreasureManager getTreasureManager() {
|
||||
return treasureManager;
|
||||
}
|
||||
|
||||
// ========== 快问快答 ==========
|
||||
|
||||
private String[] shiftArgs(String[] a) {
|
||||
@@ -342,8 +389,19 @@ public class Main extends JavaPlugin
|
||||
sendTreasureList(s);
|
||||
return true;
|
||||
case "reload":
|
||||
treasureManager.loadAll();
|
||||
s.sendMessage("§a已重载");
|
||||
case "重载":
|
||||
treasureManager.forceCleanClaims();
|
||||
for (org.bukkit.entity.Player p :
|
||||
Bukkit.getOnlinePlayers()) {
|
||||
treasureManager
|
||||
.reclaimAllTreasureItems(p);
|
||||
}
|
||||
treasureManager.reload();
|
||||
s.sendMessage(
|
||||
"§a[寻宝] 重载完成,领取记录已清空");
|
||||
s.sendMessage("§b§l\n欢迎游玩草原探险服务器");
|
||||
s.sendMessage("§b§l服务器ip:mc2.ypshidifu.cn\n端口30679");
|
||||
s.sendMessage("");
|
||||
return true;
|
||||
case "工具":
|
||||
case "tool":
|
||||
@@ -359,6 +417,9 @@ public class Main extends JavaPlugin
|
||||
}
|
||||
treasureManager.removeRegion(a[1]);
|
||||
s.sendMessage("§a已删除: " + a[1]);
|
||||
s.sendMessage("§b§l\n欢迎游玩草原探险服务器");
|
||||
s.sendMessage("§b§l服务器ip:mc2.ypshidifu.cn\n端口30679");
|
||||
s.sendMessage("");
|
||||
return true;
|
||||
// ★ on/off 代替 border
|
||||
case "on":
|
||||
@@ -394,6 +455,9 @@ public class Main extends JavaPlugin
|
||||
.containsKey(regionName)) {
|
||||
s.sendMessage("§c区域不存在: "
|
||||
+ regionName);
|
||||
s.sendMessage("§b§l\n欢迎游玩草原探险服务器");
|
||||
s.sendMessage("§b§l服务器ip:mc2.ypshidifu.cn\n端口30679");
|
||||
s.sendMessage("");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -426,6 +490,9 @@ public class Main extends JavaPlugin
|
||||
if (tr.getPos1() == null) {
|
||||
s.sendMessage("§c请先获取工具并设置AB点");
|
||||
s.sendMessage("§7或: /寻宝 on 区域名");
|
||||
s.sendMessage("§b§l\n欢迎游玩草原探险服务器");
|
||||
s.sendMessage("§b§l服务器ip:mc2.ypshidifu.cn\n端口30679");
|
||||
s.sendMessage("");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -456,6 +523,9 @@ public class Main extends JavaPlugin
|
||||
TreasureRegion.giveTool((Player) s);
|
||||
s.sendMessage("§a已获得圈地工具");
|
||||
s.sendMessage("§7左键=A点 右键=B点");
|
||||
s.sendMessage("§b§l\n欢迎游玩草原探险服务器");
|
||||
s.sendMessage("§b§l服务器ip:mc2.ypshidifu.cn\n端口30679");
|
||||
s.sendMessage("");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -605,6 +675,9 @@ public class Main extends JavaPlugin
|
||||
+ hMin + "~Y" + hMax);
|
||||
s.sendMessage("§7使用 §e/寻宝 off "
|
||||
+ name + " §7关闭边框");
|
||||
s.sendMessage("§b§l\n欢迎游玩草原探险服务器");
|
||||
s.sendMessage("§b§l服务器ip:mc2.ypshidifu.cn\n端口30679");
|
||||
s.sendMessage("");
|
||||
}
|
||||
|
||||
boolean o1k = treasureManager.saveRegion(
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
package Sdf1_game;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -18,20 +23,47 @@ public class TreasureConfig {
|
||||
public List<TreasureReward> rewards =
|
||||
new ArrayList<>();
|
||||
|
||||
// ★ 开箱设置
|
||||
public boolean guaranteeBond = true;
|
||||
public int bondMin = 1;
|
||||
public int bondMax = 3;
|
||||
public int randomMin = 1;
|
||||
public int randomMax = 3;
|
||||
public long lastSpawnTime = 0;
|
||||
// ★ 中文名映射:奖励索引→显示名
|
||||
public java.util.Map<Integer, String>
|
||||
rewardNames = new java.util.LinkedHashMap<>();
|
||||
|
||||
|
||||
|
||||
public TreasureConfig(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public int getTotalWeight() {
|
||||
int w = 0;
|
||||
for (TreasureReward r : rewards) {
|
||||
for (TreasureReward r : rewards)
|
||||
w += r.getWeight();
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
public String getBoundsStr() {
|
||||
return "[" + minX + "," + minZ + "] ~ ["
|
||||
+ maxX + "," + maxZ + "]";
|
||||
public static void ensureTreasureConfig(
|
||||
File dir) {
|
||||
dir.mkdirs();
|
||||
File f = new File(dir, "设置.txt");
|
||||
if (f.exists()) return;
|
||||
try {
|
||||
OutputStreamWriter w =
|
||||
new OutputStreamWriter(
|
||||
new FileOutputStream(f),
|
||||
StandardCharsets.UTF_8);
|
||||
w.write("# 寻宝全局设置\n");
|
||||
w.write("# 保底债券: 是/否\n");
|
||||
w.write("保底债券: 是\n");
|
||||
w.write("# 随机奖励数量范围\n");
|
||||
w.write("随机数量: 1~3\n");
|
||||
w.close();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package Sdf1_game;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
@@ -19,6 +21,9 @@ public class TreasureInventory {
|
||||
// ★ 奖励索引标记(写在lore里用于精确匹配)
|
||||
private static final String LORE_INDEX_PREFIX =
|
||||
"§0§k";
|
||||
// ★ 唯一的标记前缀
|
||||
private static final String MARK = "§0§k";
|
||||
|
||||
|
||||
public static class GuiHolder
|
||||
implements InventoryHolder {
|
||||
@@ -26,6 +31,8 @@ public class TreasureInventory {
|
||||
private final Player player;
|
||||
private Inventory inv;
|
||||
|
||||
|
||||
|
||||
public GuiHolder(TreasureConfig config,
|
||||
Player player) {
|
||||
this.config = config;
|
||||
@@ -50,45 +57,455 @@ public class TreasureInventory {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void open(Player player,
|
||||
TreasureConfig config) {
|
||||
GuiHolder holder =
|
||||
new GuiHolder(config, player);
|
||||
Main plugin = (Main) Bukkit
|
||||
.getPluginManager()
|
||||
.getPlugin("Sdf1_game");
|
||||
|
||||
Inventory inv = Bukkit.createInventory(
|
||||
holder, 27,
|
||||
"§6§l寻宝宝箱 - " + config.name);
|
||||
|
||||
holder.setInventory(inv);
|
||||
|
||||
List<TreasureReward> selected =
|
||||
rollRewards(config, 6);
|
||||
|
||||
int[] slots = {10, 12, 14, 16, 22, 24};
|
||||
for (int i = 0;
|
||||
i < selected.size()
|
||||
&& i < slots.length; i++) {
|
||||
TreasureReward r = selected.get(i);
|
||||
inv.setItem(slots[i],
|
||||
buildDisplayItem(r, i));
|
||||
// 保底债券
|
||||
int bondAmount = 0;
|
||||
if (config.guaranteeBond) {
|
||||
for (TreasureReward r : config.rewards) {
|
||||
if (r.getType()
|
||||
== TreasureReward.Type.BOND) {
|
||||
bondAmount = r.rollBondAmount();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 边框
|
||||
ItemStack glass = new ItemStack(
|
||||
// 随机非债券奖励
|
||||
List<TreasureReward> others =
|
||||
new ArrayList<>();
|
||||
for (TreasureReward r : config.rewards) {
|
||||
if (r.getType()
|
||||
!= TreasureReward.Type.BOND) {
|
||||
others.add(r);
|
||||
}
|
||||
}
|
||||
|
||||
List<TreasureReward> rolled =
|
||||
new ArrayList<>();
|
||||
int count = ThreadLocalRandom.current()
|
||||
.nextInt(
|
||||
config.randomMin,
|
||||
config.randomMax + 1);
|
||||
int totalW = 0;
|
||||
for (TreasureReward r : others)
|
||||
totalW += r.getWeight();
|
||||
|
||||
if (totalW > 0 && !others.isEmpty()) {
|
||||
List<TreasureReward> pool =
|
||||
new ArrayList<>(others);
|
||||
for (int i = 0;
|
||||
i < count && !pool.isEmpty(); i++) {
|
||||
int roll = ThreadLocalRandom
|
||||
.current().nextInt(totalW);
|
||||
int acc = 0;
|
||||
TreasureReward pick = null;
|
||||
for (TreasureReward r : pool) {
|
||||
acc += r.getWeight();
|
||||
if (roll < acc) {
|
||||
pick = r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pick == null)
|
||||
pick = pool.get(
|
||||
pool.size() - 1);
|
||||
rolled.add(pick);
|
||||
pool.remove(pick);
|
||||
totalW = 0;
|
||||
for (TreasureReward r : pool)
|
||||
totalW += r.getWeight();
|
||||
}
|
||||
// ★ 显示GUI让玩家确认
|
||||
GuiHolder gh = new GuiHolder(
|
||||
config, player);
|
||||
Inventory inv = Bukkit.createInventory(
|
||||
gh, 27,
|
||||
"§6§l═══ 寻宝 ═══ " + config.name);
|
||||
|
||||
// 奖励预览
|
||||
List<TreasureReward> preview =
|
||||
new ArrayList<>();
|
||||
preview.add(new TreasureReward(
|
||||
TreasureReward.Type.BOND, null,
|
||||
1, bondAmount, null, 0,
|
||||
"§6债券+" + bondAmount));
|
||||
preview.addAll(rolled);
|
||||
|
||||
for (int i = 0;
|
||||
i < preview.size() && i < 9; i++) {
|
||||
TreasureReward r = preview.get(i);
|
||||
Material mat;
|
||||
if (r.getType()
|
||||
== TreasureReward.Type.BOND) {
|
||||
mat = Material.PAPER;
|
||||
} else {
|
||||
mat = Material.matchMaterial(
|
||||
r.getMaterialName());
|
||||
if (mat == null)
|
||||
mat = Material.PAPER;
|
||||
}
|
||||
ItemStack slot =
|
||||
new ItemStack(mat,
|
||||
r.getAmount());
|
||||
ItemMeta sm = slot.getItemMeta();
|
||||
if (sm != null) {
|
||||
sm.displayName(
|
||||
Component.text(
|
||||
r.getDisplayName()));
|
||||
slot.setItemMeta(sm);
|
||||
}
|
||||
inv.setItem(i, slot);
|
||||
}
|
||||
|
||||
// 装饰边框
|
||||
ItemStack filler = new ItemStack(
|
||||
Material.BLACK_STAINED_GLASS_PANE);
|
||||
ItemMeta gm = glass.getItemMeta();
|
||||
if (gm != null) {
|
||||
gm.displayName(Component.text(" "));
|
||||
glass.setItemMeta(gm);
|
||||
ItemMeta fm = filler.getItemMeta();
|
||||
if (fm != null) {
|
||||
fm.displayName(Component.text(""));
|
||||
filler.setItemMeta(fm);
|
||||
}
|
||||
for (int i = 0; i < 27; i++) {
|
||||
if (inv.getItem(i) == null) {
|
||||
inv.setItem(i, glass);
|
||||
if (inv.getItem(i) == null)
|
||||
inv.setItem(i, filler);
|
||||
}
|
||||
|
||||
gh.setInventory(inv);
|
||||
player.openInventory(inv);
|
||||
|
||||
}
|
||||
|
||||
// ★ 直接发放+延迟显示结果
|
||||
final int fBond = bondAmount;
|
||||
final List<TreasureReward> fRolled =
|
||||
rolled;
|
||||
Bukkit.getScheduler().runTaskLater(plugin,
|
||||
() -> giveRewards(player, config,
|
||||
fBond, fRolled), 40L);
|
||||
}
|
||||
|
||||
// ★ isCustomItem
|
||||
public static boolean isCustomItem(
|
||||
ItemStack item) {
|
||||
if (item == null) return false;
|
||||
if (!item.hasItemMeta()) return false;
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta == null) return false;
|
||||
if (!meta.hasLore()) return false;
|
||||
List<Component> lore = meta.lore();
|
||||
if (lore == null) return false;
|
||||
for (Component lc : lore) {
|
||||
String line = net.kyori.adventure.text
|
||||
.serializer.legacy
|
||||
.LegacyComponentSerializer
|
||||
.legacySection().serialize(lc);
|
||||
if (line.contains(MARK + "CUSTOM"))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// ===== buildCustomItem =====
|
||||
private static ItemStack buildCustomItem(
|
||||
TreasureReward r,
|
||||
String playerName,
|
||||
String regionName,
|
||||
Main plugin) {
|
||||
Material mat = Material.matchMaterial(
|
||||
r.getMaterialName());
|
||||
if (mat == null) {
|
||||
mat = Material.PAPER;
|
||||
}
|
||||
ItemStack item =
|
||||
new ItemStack(mat, r.getAmount());
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta == null) {
|
||||
return item;
|
||||
}
|
||||
meta.displayName(Component.text(
|
||||
"§b" + r.getDisplayName()));
|
||||
// 附魔
|
||||
String enchStr = r.getEnchant();
|
||||
if (enchStr != null
|
||||
&& !enchStr.isEmpty()) {
|
||||
String[] pairs = enchStr.split(";");
|
||||
for (String pair : pairs) {
|
||||
String[] ep = pair.split(",");
|
||||
if (ep.length != 2) continue;
|
||||
String id = ep[0].trim()
|
||||
.toLowerCase();
|
||||
int lvl = 1;
|
||||
try {
|
||||
lvl = Integer.parseInt(
|
||||
ep[1].trim());
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
Enchantment ench =
|
||||
Enchantment.getByKey(
|
||||
NamespacedKey
|
||||
.minecraft(id));
|
||||
if (ench != null) {
|
||||
// ★ 每个附魔单独打,不共享meta
|
||||
meta.addEnchant(ench, lvl, true);
|
||||
}
|
||||
}
|
||||
// ★ 所有附魔加完后一次性设置
|
||||
item.setItemMeta(meta);
|
||||
|
||||
}
|
||||
|
||||
|
||||
String tag = "§0§kCUSTOM|"
|
||||
+ playerName + "|"
|
||||
+ regionName + "|"
|
||||
+ r.getDisplayName() + "|"
|
||||
+ r.getAttackUsesLimit() + "|0";
|
||||
List<Component> lore = new ArrayList<>();
|
||||
if (r.getDurationSec() > 0) {
|
||||
lore.add(Component.text(
|
||||
"§7时限: "
|
||||
+ TreasureReward
|
||||
.formatTime(
|
||||
r.getDurationSec())));
|
||||
lore.add(Component.text(
|
||||
"§c§o到期自动收回"));
|
||||
}
|
||||
if (r.getAttackUsesLimit() > 0) {
|
||||
lore.add(Component.text(
|
||||
"§c攻击上限: "
|
||||
+ r.getAttackUsesLimit()
|
||||
+ "次"));
|
||||
}
|
||||
lore.add(Component.text(tag));
|
||||
meta.lore(lore);
|
||||
item.setItemMeta(meta);
|
||||
return item;
|
||||
}
|
||||
|
||||
// ===== giveRewards =====
|
||||
private static void giveRewards(
|
||||
Player player,
|
||||
TreasureConfig config,
|
||||
int bondAmount,
|
||||
List<TreasureReward> rolled) {
|
||||
Main plugin = (Main) Bukkit
|
||||
.getPluginManager()
|
||||
.getPlugin("Sdf1_game");
|
||||
BondBridge bb = plugin.getBondBridge();
|
||||
TreasureManager tm =
|
||||
plugin.getTreasureManager();
|
||||
StringBuilder msg = new StringBuilder();
|
||||
msg.append("§6§l═══ 寻宝结果 ═══\n");
|
||||
// ★ 控制台打印开箱结果
|
||||
StringBuilder log = new StringBuilder();
|
||||
log.append("[寻宝开箱] ");
|
||||
log.append(player.getName());
|
||||
log.append(" | 区域=" + config.name);
|
||||
|
||||
// 债券
|
||||
if (bondAmount > 0) {
|
||||
int oldBond = 0;
|
||||
if (bb != null && bb.isHooked()) {
|
||||
// ★ 先查原始余额
|
||||
oldBond = bb.getBonds(
|
||||
player.getName());
|
||||
bb.addBonds(player.getName(),
|
||||
bondAmount, "寻宝奖励");
|
||||
}
|
||||
int newBond = oldBond + bondAmount;
|
||||
msg.append("§6保底债券: §e")
|
||||
.append(oldBond)
|
||||
.append(" §7→§a ")
|
||||
.append(newBond)
|
||||
.append(" §6(+" + bondAmount + ")\n");
|
||||
|
||||
msg.append("§6债券: §e+")
|
||||
.append(bondAmount)
|
||||
.append(" 张\n");
|
||||
}
|
||||
for (TreasureReward r : rolled) {
|
||||
if (r.getType()
|
||||
== TreasureReward.Type.ITEM) {
|
||||
if (r.getDurationSec() > 0
|
||||
&& tm.isClaimed(
|
||||
player.getName(),
|
||||
r.getDisplayName(),
|
||||
config.name)) {
|
||||
msg.append("§c")
|
||||
.append(r.getDisplayName())
|
||||
.append(" 已领过\n");
|
||||
continue;
|
||||
}
|
||||
ItemStack give;
|
||||
if (r.getDurationSec() > 0
|
||||
|| r.getAttackUsesLimit()
|
||||
> 0) {
|
||||
give = buildCustomItem(r,
|
||||
player.getName(),
|
||||
config.name, plugin);
|
||||
if (r.getDurationSec() > 0) {
|
||||
tm.addClaim(
|
||||
player.getName(),
|
||||
r.getDisplayName(),
|
||||
config.name);
|
||||
}
|
||||
} else {
|
||||
Material m =
|
||||
Material.matchMaterial(
|
||||
r.getMaterialName());
|
||||
if (m == null) {
|
||||
m = Material.PAPER;
|
||||
}
|
||||
give = new ItemStack(m,
|
||||
r.getAmount());
|
||||
}
|
||||
player.getInventory()
|
||||
.addItem(give);
|
||||
msg.append("§f")
|
||||
.append(r.getDisplayName())
|
||||
.append("\n");
|
||||
if (r.getDurationSec() > 0) {
|
||||
final int dur =
|
||||
r.getDurationSec();
|
||||
final String rn =
|
||||
r.getDisplayName();
|
||||
final String pn =
|
||||
player.getName();
|
||||
final String rc =
|
||||
config.name;
|
||||
Bukkit.getScheduler()
|
||||
.runTaskLater(plugin,
|
||||
() -> {
|
||||
for (int i = 0;
|
||||
i < player
|
||||
.getInventory()
|
||||
.getSize();
|
||||
i++) {
|
||||
ItemStack it =
|
||||
player
|
||||
.getInventory()
|
||||
.getItem(i);
|
||||
if (it != null
|
||||
&& isCustomItem(
|
||||
it)
|
||||
&& getMarkName(
|
||||
it)
|
||||
.equals(
|
||||
rn)) {
|
||||
player
|
||||
.getInventory()
|
||||
.setItem(
|
||||
i,
|
||||
null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
tm.removeClaim(
|
||||
pn, rn, rc);
|
||||
if (player
|
||||
.isOnline()) {
|
||||
player
|
||||
.sendMessage(
|
||||
"§c[寻宝] "
|
||||
+ rn
|
||||
+ " 已到期收回");
|
||||
}
|
||||
},
|
||||
dur * 20L);
|
||||
}
|
||||
} else if (r.getType()
|
||||
== TreasureReward.Type.COMMAND) {
|
||||
String cmd = r.getCommand()
|
||||
.replace("{player}",
|
||||
player.getName());
|
||||
Bukkit.dispatchCommand(
|
||||
Bukkit.getConsoleSender(),
|
||||
cmd);
|
||||
msg.append("§a命令已执行\n");
|
||||
}
|
||||
}
|
||||
msg.append("§6§l══════════════");
|
||||
// ★ 打印到控制台
|
||||
plugin.getLogger().info(log.toString());
|
||||
|
||||
player.sendMessage(msg.toString());
|
||||
}
|
||||
|
||||
// ★ parseMark
|
||||
public static String[] parseMark(
|
||||
ItemStack item) {
|
||||
if (!isCustomItem(item)) return null;
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta == null) return null;
|
||||
List<Component> lore = meta.lore();
|
||||
if (lore == null) return null;
|
||||
for (Component lc : lore) {
|
||||
String line = net.kyori.adventure.text
|
||||
.serializer.legacy
|
||||
.LegacyComponentSerializer
|
||||
.legacySection().serialize(lc);
|
||||
if (line.contains(MARK + "CUSTOM")) {
|
||||
String data = line.substring(
|
||||
line.indexOf(MARK + "CUSTOM")
|
||||
+ MARK.length());
|
||||
String[] p = data.split("\\|");
|
||||
if (p.length >= 6)
|
||||
return new String[]{
|
||||
p[1], p[2], p[3],
|
||||
p[4], p[5]};
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// ★ getMarkName
|
||||
private static String getMarkName(
|
||||
ItemStack item) {
|
||||
String[] m = parseMark(item);
|
||||
return m != null ? m[2] : "";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private static void expiryTimer(
|
||||
Player player,
|
||||
TreasureManager tm,
|
||||
int dur,
|
||||
String rName,
|
||||
String pName,
|
||||
String regionName) {
|
||||
// 收回物品
|
||||
for (int si = 0;
|
||||
si < player.getInventory().getSize();
|
||||
si++) {
|
||||
ItemStack siItem =
|
||||
player.getInventory()
|
||||
.getItem(si);
|
||||
if (siItem != null
|
||||
&& isCustomItem(siItem)
|
||||
&& getMarkName(siItem)
|
||||
.equals(rName)) {
|
||||
player.getInventory()
|
||||
.setItem(si, null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 清记录
|
||||
tm.removeClaim(pName, rName, regionName);
|
||||
if (player.isOnline()) {
|
||||
player.sendMessage(
|
||||
"§c[寻宝] " + rName
|
||||
+ " 已到期收回");
|
||||
}
|
||||
}
|
||||
|
||||
player.openInventory(inv);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 构建GUI显示物品(含索引标记用于匹配)
|
||||
@@ -240,7 +657,9 @@ public class TreasureInventory {
|
||||
TreasureReward matched =
|
||||
config.rewards.get(rewardIndex);
|
||||
|
||||
giveReward(player, matched, bb, plugin);
|
||||
player.closeInventory();
|
||||
open(player, config);
|
||||
|
||||
|
||||
// 领取后删除GUI物品
|
||||
event.getInventory()
|
||||
@@ -251,101 +670,7 @@ public class TreasureInventory {
|
||||
return true;
|
||||
}
|
||||
|
||||
// ===== 发放奖励 =====
|
||||
|
||||
private static void giveReward(Player player,
|
||||
TreasureReward r,
|
||||
BondBridge bb,
|
||||
Main plugin) {
|
||||
switch (r.getType()) {
|
||||
case BOND:
|
||||
// ★ 直接发债券
|
||||
if (bb != null && bb.isHooked()) {
|
||||
bb.addBonds(player.getName(),
|
||||
r.getBondAmount(),
|
||||
"寻宝奖励");
|
||||
}
|
||||
player.sendMessage("§e获得了 §6"
|
||||
+ r.getBondAmount()
|
||||
+ " §e债券");
|
||||
break;
|
||||
|
||||
case COMMAND:
|
||||
String cmd = r.getCommand()
|
||||
.replace("{player}",
|
||||
player.getName());
|
||||
Bukkit.dispatchCommand(
|
||||
Bukkit.getConsoleSender(), cmd);
|
||||
player.sendMessage(
|
||||
"§e执行了命令奖励");
|
||||
break;
|
||||
|
||||
case ITEM:
|
||||
// ★ 给原版物品:不设自定义名称
|
||||
Material mat =
|
||||
Material.matchMaterial(
|
||||
r.getMaterialName());
|
||||
if (mat == null) mat = Material.PAPER;
|
||||
ItemStack give =
|
||||
new ItemStack(mat,
|
||||
r.getAmount());
|
||||
|
||||
if (r.getDurationSec() > 0) {
|
||||
// ★ 限时贴标物品
|
||||
ItemMeta meta =
|
||||
give.getItemMeta();
|
||||
if (meta != null) {
|
||||
meta.displayName(
|
||||
Component.text(
|
||||
"§b" + r.getDisplayName()));
|
||||
List<Component> lore =
|
||||
new ArrayList<>();
|
||||
lore.add(Component.text(
|
||||
"§7时限: "
|
||||
+ TreasureReward
|
||||
.formatTime(
|
||||
r.getDurationSec())));
|
||||
lore.add(Component.text(
|
||||
"§c§o到期自动收回"));
|
||||
meta.lore(lore);
|
||||
TreasureReward.applyEnchant(
|
||||
meta, r.getEnchant());
|
||||
give.setItemMeta(meta);
|
||||
}
|
||||
player.getInventory()
|
||||
.addItem(give);
|
||||
|
||||
// 定时收回
|
||||
final ItemStack ref =
|
||||
give.clone();
|
||||
final int dur =
|
||||
r.getDurationSec();
|
||||
final String rName =
|
||||
r.getDisplayName();
|
||||
Bukkit.getScheduler()
|
||||
.runTaskLater(plugin,
|
||||
() -> {
|
||||
player.getInventory()
|
||||
.remove(ref);
|
||||
if (player.isOnline()) {
|
||||
player.sendMessage(
|
||||
"§c[寻宝] " + rName
|
||||
+ " §7已到期,自动收回");
|
||||
}
|
||||
},
|
||||
dur * 20L);
|
||||
} else {
|
||||
// ★ 普通物品:纯原版,无自定义名称
|
||||
player.getInventory()
|
||||
.addItem(give);
|
||||
}
|
||||
|
||||
player.sendMessage("§e获得了 §f"
|
||||
+ mat.name()
|
||||
+ " §ex" + r.getAmount());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 权重随机 =====
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package Sdf1_game;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
@@ -11,7 +12,10 @@ import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class TreasureListener implements Listener {
|
||||
@@ -24,6 +28,213 @@ public class TreasureListener implements Listener {
|
||||
this.plugin = plugin;
|
||||
this.manager = manager;
|
||||
}
|
||||
// ★ 玩家攻击玩家时计数
|
||||
@org.bukkit.event.EventHandler
|
||||
public void onDamage(
|
||||
org.bukkit.event.entity
|
||||
.EntityDamageByEntityEvent e) {
|
||||
|
||||
if (!(e.getDamager()
|
||||
instanceof org.bukkit.entity.Player))
|
||||
return;
|
||||
if (!(e.getEntity()
|
||||
instanceof org.bukkit.entity.Player))
|
||||
return;
|
||||
|
||||
org.bukkit.entity.Player attacker =
|
||||
(org.bukkit.entity.Player)
|
||||
e.getDamager();
|
||||
ItemStack hand =
|
||||
attacker.getInventory()
|
||||
.getItemInMainHand();
|
||||
|
||||
if (hand == null) return;
|
||||
if (!TreasureInventory
|
||||
.isCustomItem(hand)) return;
|
||||
|
||||
String[] mark =
|
||||
TreasureInventory.parseMark(hand);
|
||||
if (mark == null) return;
|
||||
|
||||
String owner = mark[0];
|
||||
String region = mark[1];
|
||||
String rName = mark[2];
|
||||
int maxUse =
|
||||
Integer.parseInt(mark[3]);
|
||||
int useCount =
|
||||
Integer.parseInt(mark[4]) + 1;
|
||||
|
||||
// ★ 只有攻击上限>0的物品才计数
|
||||
if (maxUse <= 0) return;
|
||||
|
||||
// ★ 检查归属
|
||||
if (!owner.equalsIgnoreCase(
|
||||
attacker.getName())) return;
|
||||
|
||||
plugin.getLogger().info(
|
||||
"[寻宝] ★攻击: "
|
||||
+ attacker.getName()
|
||||
+ " " + rName
|
||||
+ " " + useCount
|
||||
+ "/" + maxUse);
|
||||
|
||||
// ★ 更新lore里的次数
|
||||
ItemMeta meta = hand.getItemMeta();
|
||||
if (meta != null && meta.hasLore()) {
|
||||
List<Component> lore = meta.lore();
|
||||
for (int i = 0;
|
||||
i < lore.size(); i++) {
|
||||
String line =
|
||||
net.kyori.adventure.text
|
||||
.serializer.legacy
|
||||
.LegacyComponentSerializer
|
||||
.legacySection()
|
||||
.serialize(lore.get(i));
|
||||
if (line.contains("§0§kCUSTOM")) {
|
||||
String newMark =
|
||||
"§0§kCUSTOM|"
|
||||
+ owner + "|"
|
||||
+ region + "|"
|
||||
+ rName + "|"
|
||||
+ maxUse + "|"
|
||||
+ useCount;
|
||||
lore.set(i,
|
||||
Component.text(newMark));
|
||||
break;
|
||||
}
|
||||
}
|
||||
meta.lore(lore);
|
||||
hand.setItemMeta(meta);
|
||||
}
|
||||
|
||||
// ★ 打印给玩家看
|
||||
attacker.sendMessage(
|
||||
"§e[寻宝] " + rName
|
||||
+ " 攻击次数: "
|
||||
+ useCount + "/" + maxUse);
|
||||
|
||||
// 达到上限 → 回收
|
||||
if (useCount >= maxUse) {
|
||||
attacker.getInventory()
|
||||
.setItemInMainHand(null);
|
||||
plugin.getTreasureManager()
|
||||
.removeClaim(owner, rName,
|
||||
region);
|
||||
attacker.sendMessage(
|
||||
"§c[寻宝] " + rName
|
||||
+ " 攻击次数用完,已回收");
|
||||
attacker.getWorld().dropItemNaturally(
|
||||
attacker.getLocation(),
|
||||
new ItemStack(Material.AIR));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ★ 禁止丢弃寻宝物品
|
||||
@org.bukkit.event.EventHandler
|
||||
public void onDrop(
|
||||
org.bukkit.event.player
|
||||
.PlayerDropItemEvent e) {
|
||||
if (TreasureInventory
|
||||
.isCustomItem(
|
||||
e.getItemDrop().getItemStack())) {
|
||||
e.setCancelled(true);
|
||||
e.getPlayer().sendMessage(
|
||||
"§c[寻宝] 寻宝物品不可丢弃");
|
||||
}
|
||||
}
|
||||
// ★ 死亡时回收寻宝物品(不掉落)
|
||||
@org.bukkit.event.EventHandler
|
||||
public void onDeath(
|
||||
org.bukkit.event.entity
|
||||
.PlayerDeathEvent e) {
|
||||
org.bukkit.entity.Player player =
|
||||
e.getEntity();
|
||||
List<ItemStack> drops = e.getDrops();
|
||||
|
||||
// ★ 检查背包里所有物品
|
||||
ItemStack[] contents =
|
||||
player.getInventory().getContents();
|
||||
for (int i = 0;
|
||||
i < contents.length; i++) {
|
||||
ItemStack item = contents[i];
|
||||
if (item == null) continue;
|
||||
if (!TreasureInventory
|
||||
.isCustomItem(item)) continue;
|
||||
|
||||
String[] mark =
|
||||
TreasureInventory.parseMark(item);
|
||||
if (mark != null) {
|
||||
// 从掉落列表移除
|
||||
drops.remove(item);
|
||||
// 清除记录
|
||||
plugin.getTreasureManager()
|
||||
.removeClaim(mark[0],
|
||||
mark[2], mark[1]);
|
||||
}
|
||||
}
|
||||
// 清空背包里所有寻宝物品
|
||||
for (int i = 0;
|
||||
i < contents.length; i++) {
|
||||
ItemStack item = contents[i];
|
||||
if (item == null) continue;
|
||||
if (TreasureInventory
|
||||
.isCustomItem(item)) {
|
||||
player.getInventory()
|
||||
.setItem(i, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
// ★ 物品掉落到地上时检测(丢弃后立即清除)
|
||||
@org.bukkit.event.EventHandler
|
||||
public void onItemSpawn(
|
||||
org.bukkit.event.entity
|
||||
.ItemSpawnEvent e) {
|
||||
ItemStack item =
|
||||
e.getEntity().getItemStack();
|
||||
if (!TreasureInventory
|
||||
.isCustomItem(item)) return;
|
||||
|
||||
// ★ 延迟1秒后检查,如果还在地上就销毁
|
||||
// (已捡起的不会被销毁)
|
||||
final org.bukkit.Location loc =
|
||||
e.getLocation();
|
||||
final String itemKey =
|
||||
item.getType().name()
|
||||
+ "_" + item.getAmount();
|
||||
org.bukkit.Bukkit.getScheduler()
|
||||
.runTaskLater(plugin, () -> {
|
||||
for (org.bukkit.entity.Entity ent :
|
||||
loc.getChunk()
|
||||
.getEntities()) {
|
||||
if (ent instanceof
|
||||
org.bukkit.entity.Item) {
|
||||
org.bukkit.entity.Item di =
|
||||
(org.bukkit.entity.Item)
|
||||
ent;
|
||||
if (TreasureInventory
|
||||
.isCustomItem(
|
||||
di.getItemStack())) {
|
||||
String[] mark =
|
||||
TreasureInventory
|
||||
.parseMark(
|
||||
di.getItemStack());
|
||||
if (mark != null) {
|
||||
// 清除领取记录
|
||||
plugin
|
||||
.getTreasureManager()
|
||||
.removeClaim(
|
||||
mark[0],
|
||||
mark[2],
|
||||
mark[1]);
|
||||
}
|
||||
di.remove();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 20L);
|
||||
}
|
||||
|
||||
// ===== 圈地工具选点 =====
|
||||
|
||||
@@ -113,6 +324,16 @@ public class TreasureListener implements Listener {
|
||||
}
|
||||
}
|
||||
}
|
||||
// ★ 玩家下线时标记待回收
|
||||
@org.bukkit.event.EventHandler
|
||||
public void onQuit(
|
||||
org.bukkit.event.player.PlayerQuitEvent e) {
|
||||
String name = e.getPlayer().getName();
|
||||
// 标记该玩家有物品需要在上线时回收
|
||||
plugin.getTreasureManager()
|
||||
.getPendingReclaims().add(name);
|
||||
}
|
||||
|
||||
|
||||
// ===== 阻止破坏宝箱 =====
|
||||
|
||||
@@ -140,6 +361,132 @@ public class TreasureListener implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
@org.bukkit.event.EventHandler(priority =
|
||||
org.bukkit.event.EventPriority.HIGH)
|
||||
public void onClick(
|
||||
org.bukkit.event.inventory
|
||||
.InventoryClickEvent e) {
|
||||
if (e.getCursor() == null) return;
|
||||
if (!TreasureInventory
|
||||
.isCustomItem(e.getCursor()))
|
||||
return;
|
||||
String type = e.getView()
|
||||
.getTopInventory().getType().name();
|
||||
if (!type.equals("PLAYER")
|
||||
&& !type.equals("CRAFTING")
|
||||
&& !type.equals("CREATIVE")) {
|
||||
e.setCancelled(true);
|
||||
if (e.getWhoClicked()
|
||||
instanceof org.bukkit.entity.Player) {
|
||||
((org.bukkit.entity.Player)
|
||||
e.getWhoClicked())
|
||||
.sendMessage(
|
||||
"§c[寻宝] 不可放入容器");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@org.bukkit.event.EventHandler(priority =
|
||||
org.bukkit.event.EventPriority.HIGH)
|
||||
public void onDrag(
|
||||
org.bukkit.event.inventory
|
||||
.InventoryDragEvent e) {
|
||||
for (ItemStack item :
|
||||
e.getNewItems().values()) {
|
||||
if (TreasureInventory
|
||||
.isCustomItem(item)) {
|
||||
String type = e.getView()
|
||||
.getTopInventory()
|
||||
.getType().name();
|
||||
if (!type.equals("PLAYER")
|
||||
&& !type.equals("CRAFTING")) {
|
||||
e.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@org.bukkit.event.EventHandler(priority =
|
||||
org.bukkit.event.EventPriority.HIGH)
|
||||
public void onAnvil(
|
||||
org.bukkit.event.inventory
|
||||
.PrepareAnvilEvent e) {
|
||||
ItemStack first =
|
||||
e.getInventory().getItem(0);
|
||||
if (first != null
|
||||
&& TreasureInventory
|
||||
.isCustomItem(first)) {
|
||||
e.setResult(null);
|
||||
}
|
||||
}
|
||||
|
||||
@org.bukkit.event.EventHandler(priority =
|
||||
org.bukkit.event.EventPriority.HIGH)
|
||||
public void onInteract(
|
||||
org.bukkit.event.player
|
||||
.PlayerInteractEvent e) {
|
||||
if (e.getItem() == null) return;
|
||||
if (!TreasureInventory
|
||||
.isCustomItem(e.getItem())) return;
|
||||
if (!e.getAction().name()
|
||||
.contains("RIGHT_CLICK")) return;
|
||||
if (e.getClickedBlock() == null) return;
|
||||
String b = e.getClickedBlock()
|
||||
.getType().name();
|
||||
if (b.contains("SHULKER")
|
||||
|| b.contains("CHEST")
|
||||
|| b.equals("BARREL")
|
||||
|| b.equals("ENDER_CHEST")
|
||||
|| b.equals("HOPPER")
|
||||
|| b.equals("DROPPER")
|
||||
|| b.equals("DISPENSER")) {
|
||||
e.setCancelled(true);
|
||||
e.getPlayer().sendMessage(
|
||||
"§c[寻宝] 不可放入容器");
|
||||
}
|
||||
}
|
||||
|
||||
// ★ 上线时扫描背包回收
|
||||
@org.bukkit.event.EventHandler
|
||||
public void onJoin(
|
||||
org.bukkit.event.player
|
||||
.PlayerJoinEvent e) {
|
||||
plugin.getTreasureManager()
|
||||
.reclaimPlayerItems(
|
||||
e.getPlayer().getName());
|
||||
}
|
||||
|
||||
// ★ 手持寻宝物品切换槽位时检查归属
|
||||
@org.bukkit.event.EventHandler
|
||||
public void onHeld(
|
||||
org.bukkit.event.player
|
||||
.PlayerItemHeldEvent e) {
|
||||
ItemStack item =
|
||||
e.getPlayer().getInventory()
|
||||
.getItem(
|
||||
e.getNewSlot());
|
||||
if (item == null) return;
|
||||
if (!TreasureInventory
|
||||
.isCustomItem(item)) return;
|
||||
|
||||
String[] mark =
|
||||
TreasureInventory.parseMark(item);
|
||||
if (mark == null) return;
|
||||
|
||||
if (!mark[0].equalsIgnoreCase(
|
||||
e.getPlayer().getName())) {
|
||||
// 不是本人的→立即回收
|
||||
e.getPlayer().getInventory()
|
||||
.setItem(e.getNewSlot(), null);
|
||||
plugin.getTreasureManager()
|
||||
.removeClaim(mark[0], mark[2],
|
||||
mark[1]);
|
||||
e.getPlayer().sendMessage(
|
||||
"§c[寻宝] " + mark[2]
|
||||
+ " 不属于你,已回收");
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 预览区域范围 =====
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,32 +1,26 @@
|
||||
package Sdf1_game;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.inventory.ItemFlag;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
public class TreasureReward {
|
||||
|
||||
public enum Type {
|
||||
ITEM, BOND, COMMAND
|
||||
BOND, COMMAND, ITEM
|
||||
}
|
||||
|
||||
private final Type type;
|
||||
private final String materialName;
|
||||
private final int amount;
|
||||
private final int bondAmount;
|
||||
private final String command;
|
||||
private final int weight;
|
||||
private final String displayName;
|
||||
private final int durationSec;
|
||||
private final String enchant;
|
||||
private final String rewardLore;
|
||||
private Type type;
|
||||
private String materialName;
|
||||
private int amount;
|
||||
private int bondAmount;
|
||||
private int bondMin;
|
||||
private int bondMax;
|
||||
private String command;
|
||||
private int weight;
|
||||
private String displayName;
|
||||
private int durationSec;
|
||||
private String enchant;
|
||||
private String rewardLore;
|
||||
private int attackUsesLimit;
|
||||
|
||||
public TreasureReward(Type type,
|
||||
String materialName,
|
||||
@@ -37,112 +31,94 @@ public class TreasureReward {
|
||||
String displayName,
|
||||
int durationSec,
|
||||
String enchant,
|
||||
String rewardLore) {
|
||||
String lore,
|
||||
int attackUsesLimit) {
|
||||
this.type = type;
|
||||
this.materialName = materialName;
|
||||
this.amount = Math.max(1, amount);
|
||||
this.amount = amount;
|
||||
this.bondAmount = bondAmount;
|
||||
this.bondMin = bondAmount;
|
||||
this.bondMax = bondAmount;
|
||||
this.command = command;
|
||||
this.weight = weight;
|
||||
this.displayName = displayName;
|
||||
this.durationSec = durationSec;
|
||||
this.enchant = enchant;
|
||||
this.rewardLore = rewardLore;
|
||||
this.rewardLore = lore;
|
||||
this.attackUsesLimit = attackUsesLimit;
|
||||
}
|
||||
|
||||
public TreasureReward(Type type,
|
||||
String materialName,
|
||||
int amount,
|
||||
int bondAmount,
|
||||
String command,
|
||||
int weight,
|
||||
String displayName) {
|
||||
this(type, materialName, amount, bondAmount,
|
||||
command, weight, displayName,
|
||||
0, null, null);
|
||||
String mat, int amt,
|
||||
int bond, String cmd,
|
||||
int w, String name) {
|
||||
this(type, mat, amt, bond, cmd, w, name,
|
||||
0, null, null, 0);
|
||||
}
|
||||
|
||||
public TreasureReward(Type type,
|
||||
String mat, int amt,
|
||||
int bond, String cmd,
|
||||
int w, String name,
|
||||
int dur, String ench,
|
||||
String lore) {
|
||||
this(type, mat, amt, bond, cmd, w, name,
|
||||
dur, ench, lore, 0);
|
||||
}
|
||||
|
||||
public Type getType() { return type; }
|
||||
public String getMaterialName() { return materialName; }
|
||||
public int getAmount() { return amount; }
|
||||
public int getBondAmount() { return bondAmount; }
|
||||
public int getBondMin() { return bondMin; }
|
||||
public int getBondMax() { return bondMax; }
|
||||
public String getCommand() { return command; }
|
||||
public int getWeight() { return weight; }
|
||||
public String getDisplayName() { return displayName; }
|
||||
public int getDurationSec() { return durationSec; }
|
||||
public String getEnchant() { return enchant; }
|
||||
public String getLore() { return rewardLore; }
|
||||
public int getAttackUsesLimit() { return attackUsesLimit; }
|
||||
|
||||
public ItemStack toItemStack() {
|
||||
Material mat = Material.PAPER;
|
||||
if (materialName != null
|
||||
&& !materialName.isEmpty()) {
|
||||
Material found =
|
||||
Material.matchMaterial(materialName);
|
||||
if (found != null) mat = found;
|
||||
public void setBondRange(int min, int max) {
|
||||
this.bondMin = min;
|
||||
this.bondMax = max;
|
||||
this.bondAmount = min;
|
||||
}
|
||||
|
||||
ItemStack item = new ItemStack(mat, amount);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta != null) {
|
||||
meta.displayName(
|
||||
Component.text(displayName));
|
||||
|
||||
List<Component> lore = new ArrayList<>();
|
||||
if (durationSec > 0) {
|
||||
lore.add(Component.text(
|
||||
"§7时限: " + formatTime(durationSec)));
|
||||
}
|
||||
if (rewardLore != null
|
||||
&& !rewardLore.isEmpty()) {
|
||||
lore.add(Component.text(rewardLore));
|
||||
}
|
||||
lore.add(Component.text("§7点击领取"));
|
||||
meta.lore(lore);
|
||||
|
||||
applyEnchant(meta, enchant);
|
||||
|
||||
item.setItemMeta(meta);
|
||||
}
|
||||
return item;
|
||||
public int rollBondAmount() {
|
||||
if (bondMax <= bondMin) return bondMin;
|
||||
return ThreadLocalRandom.current()
|
||||
.nextInt(bondMin, bondMax + 1);
|
||||
}
|
||||
|
||||
/** ★ 安全附魔:用 NamespacedKey */
|
||||
static void applyEnchant(ItemMeta meta,
|
||||
String enchant) {
|
||||
if (enchant == null || enchant.isEmpty())
|
||||
return;
|
||||
String[] ep = enchant.split(",");
|
||||
if (ep.length != 2) return;
|
||||
try {
|
||||
// 支持 "KNOCKBACK" 或 "minecraft:knockback"
|
||||
String key = ep[0].trim();
|
||||
if (!key.contains(":")) {
|
||||
key = "minecraft:" + key.toLowerCase();
|
||||
}
|
||||
NamespacedKey nk =
|
||||
NamespacedKey.fromString(key);
|
||||
if (nk == null) return;
|
||||
Enchantment ench =
|
||||
Enchantment.getByKey(nk);
|
||||
if (ench == null) return;
|
||||
int lvl = Integer.parseInt(ep[1].trim());
|
||||
meta.addEnchant(ench, lvl, true);
|
||||
meta.addItemFlags(
|
||||
ItemFlag.HIDE_ENCHANTS);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
public static String formatTime(int s) {
|
||||
if (s <= 0) return "永久";
|
||||
int h = s / 3600;
|
||||
int m = (s % 3600) / 60;
|
||||
int sec = s % 60;
|
||||
if (h > 0) return h + "小时" + m + "分钟";
|
||||
if (m > 0) return m + "分钟" + sec + "秒";
|
||||
return sec + "秒";
|
||||
}
|
||||
|
||||
static String formatTime(int sec) {
|
||||
if (sec >= 3600) {
|
||||
int h = sec / 3600;
|
||||
int m = (sec % 3600) / 60;
|
||||
return m > 0 ? h + "小时" + m + "分钟"
|
||||
: h + "小时";
|
||||
public static int parseDuration(String input) {
|
||||
if (input == null || input.isEmpty()) return 0;
|
||||
String s = input.trim().toLowerCase();
|
||||
if (s.matches("\\d+")) return Integer.parseInt(s);
|
||||
if (s.contains("小时") || s.contains("时")) {
|
||||
return Integer.parseInt(s.replaceAll("[^\\d]", "")) * 3600;
|
||||
}
|
||||
int m = sec / 60;
|
||||
int s = sec % 60;
|
||||
return s > 0 ? m + "分钟" + s + "秒"
|
||||
: m + "分钟";
|
||||
if (s.contains("分钟") || s.contains("分")) {
|
||||
return Integer.parseInt(s.replaceAll("[^\\d]", "")) * 60;
|
||||
}
|
||||
if (s.contains("秒")) {
|
||||
return Integer.parseInt(s.replaceAll("[^\\d]", ""));
|
||||
}
|
||||
if (s.contains("天")) {
|
||||
return Integer.parseInt(s.replaceAll("[^\\d]", "")) * 86400;
|
||||
}
|
||||
try { return Integer.parseInt(s); }
|
||||
catch (Exception e) { return 0; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package Sdf1_game;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
@@ -8,6 +9,8 @@ public class TreasureSpawnTask extends BukkitRunnable {
|
||||
|
||||
private final Main plugin;
|
||||
private final TreasureManager manager;
|
||||
private int offlineCount = 0;
|
||||
private boolean paused = false;
|
||||
|
||||
public TreasureSpawnTask(Main plugin,
|
||||
TreasureManager manager) {
|
||||
@@ -17,12 +20,75 @@ public class TreasureSpawnTask extends BukkitRunnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
int online =
|
||||
Bukkit.getOnlinePlayers().size();
|
||||
|
||||
// 无人在线
|
||||
if (online == 0) {
|
||||
offlineCount++;
|
||||
if (offlineCount == 1) {
|
||||
plugin.getLogger().info(
|
||||
"[寻宝] 无人在线,60秒后暂停");
|
||||
}
|
||||
if (offlineCount >= 12 && !paused) {
|
||||
paused = true;
|
||||
manager.removeAllChests();
|
||||
plugin.getLogger().info(
|
||||
"[寻宝] ★暂停+收回");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (paused) {
|
||||
paused = false;
|
||||
plugin.getLogger().info(
|
||||
"[寻宝] ★玩家上线");
|
||||
}
|
||||
|
||||
offlineCount = 0;
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
for (TreasureConfig tc
|
||||
: manager.getConfigs().values()) {
|
||||
int roll = ThreadLocalRandom.current()
|
||||
.nextInt(100);
|
||||
if (roll >= tc.spawnChance) continue;
|
||||
|
||||
// ★ 首次生成
|
||||
if (tc.lastSpawnTime == 0) {
|
||||
manager.spawnChest(tc);
|
||||
tc.lastSpawnTime = now;
|
||||
// ★ 通知所有玩家
|
||||
broadcastSpawn(tc);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 正常计时
|
||||
long elapsed = now - tc.lastSpawnTime;
|
||||
long need = tc.spawnInterval * 1000L;
|
||||
if (elapsed < need) continue;
|
||||
|
||||
int roll = ThreadLocalRandom.current()
|
||||
.nextInt(1, 101);
|
||||
if (roll > tc.spawnChance) {
|
||||
tc.lastSpawnTime = now;
|
||||
continue;
|
||||
}
|
||||
|
||||
manager.spawnChest(tc);
|
||||
tc.lastSpawnTime = now;
|
||||
// ★ 通知所有玩家
|
||||
broadcastSpawn(tc);
|
||||
plugin.getLogger().info(
|
||||
"[寻宝] ★生成: " + tc.name);
|
||||
}
|
||||
}
|
||||
private void broadcastSpawn(TreasureConfig tc) {
|
||||
for (org.bukkit.entity.Player p
|
||||
: Bukkit.getOnlinePlayers()) {
|
||||
p.sendMessage("§6§l[寻宝] §e"
|
||||
+ tc.name + " §a区域刷新了宝箱!");
|
||||
}
|
||||
plugin.getLogger().info(
|
||||
"[寻宝] " + tc.name
|
||||
+ " 区域刷新了宝箱!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user