GiftPack.java v2.0
新手礼包插件,注册指令/giftpack,分页显示奖励及在线时长,支持Vault、帮助命令、性能最优。
命令列表
- giftpack主命令,包含open、reload、help子命令
package com.yourdomain.giftpack;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.PluginCommand;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
import java.sql.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
* @pluginName GiftPack
* @author Scriptirc Engine
* @version 2.0
* @description 新手礼包插件,注册指令/giftpack,分页显示奖励及在线时长,支持Vault、帮助命令、性能最优。
* [command]giftpack|主命令,包含open、reload、help子命令[/command]
* [Permission]giftpack.user|允许玩家领取或查看新手礼包[/Permission]
* [Permission]giftpack.admin|允许管理员管理并reload礼包[/Permission]
*/
public class GiftPack extends JavaPlugin implements Listener {
// Vault简化接口
public interface Economy {
boolean depositPlayer(OfflinePlayer player, double amount);
}
private static class VaultEconomy implements Economy {
private final Object econ;
private final java.lang.reflect.Method depositPlayerMethod;
public VaultEconomy(Object econ) throws Exception {
this.econ = econ;
this.depositPlayerMethod = econ.getClass().getMethod("depositPlayer", OfflinePlayer.class, double.class);
}
public boolean depositPlayer(OfflinePlayer player, double amount) {
try { depositPlayerMethod.invoke(econ, player, amount); return true; } catch (Exception e) { return false; }
}
}
// 配置与数据库字段
private File configFile;
private FileConfiguration config;
private Connection conn;
private Economy economy;
private final String databaseName = "giftpack.db";
private final String mainPerm = "giftpack.user";
private final String adminPerm = "giftpack.admin";
private final Map<UUID, Long> sessionJoinTime = new ConcurrentHashMap<>();
@Override
public void onEnable() {
saveDefaultConfigYML();
loadYamlConfig();
initDatabase();
setupEconomy();
// 注册事件
PluginManager pm = getServer().getPluginManager();
pm.registerEvents(this, this);
// 注册/giftpack和别名/help命令(如果需要更多别名,可补充)
PluginCommand cmd = getCommand("giftpack");
if (cmd != null) {
cmd.setExecutor(this);
cmd.setPermission(mainPerm);
cmd.setDescription("礼包主命令");
}
getLogger().info("GiftPack插件已启动");
}
@Override
public void onDisable() {
try { if(conn!=null && !conn.isClosed()) conn.close(); }catch(Exception ignored){}
}
// ---------------------- YML配置操作 ----------------------
private void saveDefaultConfigYML() {
configFile = new File(getDataFolder(), "giftpack.yml");
if(!configFile.exists()) {
getDataFolder().mkdirs();
try {
configFile.createNewFile();
YamlConfiguration yml = new YamlConfiguration();
yml.set("rewards.1.desc", "第1天奖励:石头x10和100金币");
yml.set("rewards.1.items", Arrays.asList("STONE:10"));
yml.set("rewards.1.money", 100);
yml.set("rewards.1.permission", "");
yml.set("rewards.2.desc", "第2天奖励:铁锭x5和150金币");
yml.set("rewards.2.items", Arrays.asList("IRON_INGOT:5"));
yml.set("rewards.2.money", 150);
yml.set("rewards.2.permission", "");
yml.save(configFile);
} catch(Exception e) { e.printStackTrace(); }
}
}
private void loadYamlConfig() {
config = YamlConfiguration.loadConfiguration(configFile);
}
// ---------------------- 数据库初始化 ----------------------
private void initDatabase() {
try {
File dbFile = new File(getDataFolder(), databaseName);
getDataFolder().mkdirs();
conn = DriverManager.getConnection("jdbc:sqlite:" + dbFile.getAbsolutePath());
Statement st = conn.createStatement();
st.executeUpdate("CREATE TABLE IF NOT EXISTS player_giftpack (uuid TEXT PRIMARY KEY, first_join_time INTEGER, total_play_seconds INTEGER, login_days INTEGER, rewarded INTEGER)");
st.close();
}catch (Exception e){ e.printStackTrace(); }
}
// ---------------------- Vault 兼容 ----------------------
private boolean setupEconomy() {
try {
if(getServer().getPluginManager().getPlugin("Vault") == null){
getLogger().warning("未检测到Vault,金币奖励功能无法使用!");
return false;
}
RegisteredServiceProvider<?> rsp = getServer().getServicesManager().getRegistration(Class.forName("net.milkbowl.vault.economy.Economy"));
if(rsp == null){
getLogger().warning("Vault经济服务未找到!");
return false;
}
Object econ = rsp.getProvider();
this.economy = new VaultEconomy(econ);
return true;
}catch(Exception e){
getLogger().warning("Vault兼容失败: "+e.getMessage());
return false;
}
}
// ---------------------- 玩家数据刷新 ----------------------
private void refreshPlayerData(Player p) {
try {
String uuid = p.getUniqueId().toString();
long now = System.currentTimeMillis();
PreparedStatement getps = conn.prepareStatement("SELECT * FROM player_giftpack WHERE uuid = ?");
getps.setString(1, uuid);
ResultSet rs = getps.executeQuery();
if(rs.next()) {
long lastJoin = rs.getLong("first_join_time");
int loginDays = rs.getInt("login_days");
// 跨天判断
if(!isSameDay(lastJoin, now)){
loginDays++;
// 更新
PreparedStatement up = conn.prepareStatement("UPDATE player_giftpack SET first_join_time=?, login_days=? WHERE uuid = ?");
up.setLong(1, now);
up.setInt(2, loginDays);
up.setString(3, uuid);
up.executeUpdate(); up.close();
}
}else{
PreparedStatement ins = conn.prepareStatement("INSERT INTO player_giftpack (uuid, first_join_time, total_play_seconds, login_days, rewarded) VALUES (?, ?, ?, ?, ?)");
ins.setString(1, uuid); ins.setLong(2, now);
ins.setInt(3, 0); ins.setInt(4, 1); ins.setInt(5, 0);
ins.executeUpdate(); ins.close();
}
rs.close(); getps.close();
}catch(Exception e){ e.printStackTrace(); }
}
// 事件:玩家加入
@EventHandler
public void onJoin(PlayerJoinEvent e) {
final Player p = e.getPlayer();
Bukkit.getScheduler().runTaskAsynchronously(this, () -> refreshPlayerData(p));
sessionJoinTime.put(p.getUniqueId(), System.currentTimeMillis());
}
// 事件:玩家退出
@EventHandler
public void onQuit(PlayerQuitEvent e) {
final Player p = e.getPlayer();
final UUID uid = p.getUniqueId();
final long quit = System.currentTimeMillis();
final Long join = sessionJoinTime.get(uid);
if(join != null){
final long sess = (quit - join) / 1000L;
Bukkit.getScheduler().runTaskAsynchronously(this, ()->accumulatePlayTime(uid, sess));
sessionJoinTime.remove(uid);
}
}
// 累计时长入库
private void accumulatePlayTime(UUID uid, long sessionSec){
try {
PreparedStatement ps = conn.prepareStatement("UPDATE player_giftpack SET total_play_seconds = total_play_seconds + ? WHERE uuid = ?");
ps.setLong(1, sessionSec);
ps.setString(2, uid.toString());
ps.executeUpdate();
ps.close();
}catch(Exception ex){ ex.printStackTrace(); }
}
// 判断是否同一天(00:00以后算新一天,按服务器本地)
private boolean isSameDay(long t1, long t2){
Calendar c1 = Calendar.getInstance();
c1.setTimeInMillis(t1);
Calendar c2 = Calendar.getInstance();
c2.setTimeInMillis(t2);
return (c1.get(Calendar.YEAR)==c2.get(Calendar.YEAR)) && (c1.get(Calendar.DAY_OF_YEAR)==c2.get(Calendar.DAY_OF_YEAR));
}
// ---------------------- 命令分发 ----------------------
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if(!(sender instanceof Player)){
sender.sendMessage("[GiftPack] 仅限玩家操作本命令");
return true;
}
Player p = (Player) sender;
if(args.length == 0 || args[0].equalsIgnoreCase("open")){
if(p.hasPermission(mainPerm)){
openGui(p, 1); // 支持分页
return true;
}else{
p.sendMessage(ChatColor.RED+"你没有权限访问新手礼包!");
return true;
}
}else if(args[0].equalsIgnoreCase("help")){
sendHelp(p);
return true;
}else if(args[0].equalsIgnoreCase("reload")){
if(p.hasPermission(adminPerm)){
loadYamlConfig();
p.sendMessage(ChatColor.GREEN+"[GiftPack] 礼包配置与奖励YML已重载");
}else{
p.sendMessage(ChatColor.RED+"你没有管理权限");
}
return true;
}
return false;
}
// 帮助文本
private void sendHelp(Player p) {
p.sendMessage(ChatColor.YELLOW+"---- 新手礼包系统帮助 ----");
p.sendMessage(ChatColor.AQUA+"/giftpack open 打开礼包界面");
p.sendMessage(ChatColor.AQUA+"/giftpack reload [管理员] 重载礼包配置");
p.sendMessage(ChatColor.AQUA+"/giftpack help 查看帮助文档");
}
// ---------------------- 奖励配置解析 ----------------------
public class Reward {
public int day; public String desc; public List<String> items; public double money; public String perm;
public Reward(int day, String desc, List<String> items, double money, String perm){
this.day=day;this.desc=desc;this.items=items;this.money=money;this.perm=perm; }
}
public Map<Integer, Reward> parseRewardList(){
Map<Integer, Reward> map = new HashMap<>(); if(config==null) loadYamlConfig();
if(config.contains("rewards")){
for(String i : config.getConfigurationSection("rewards").getKeys(false)){
int day=0; try{day=Integer.parseInt(i);}catch(Exception ignore){}
if(day<=0) continue;
String desc = config.getString("rewards."+i+".desc","奖励");
List<String> items = config.getStringList("rewards."+i+".items");
double money = config.getDouble("rewards."+i+".money",0);
String perm = config.getString("rewards."+i+".permission","");
map.put(day, new Reward(day,desc,items,money,perm));
}
}
return map;
}
// ---------------------- GUI 界面分页奖励 ----------------------
private static final int REWARD_GRID_START = 2*9+2;
private static final int REWARD_GRID_END = 5*9+8;
private static final int GRID_WIDTH = 7;
private static final int GRID_HEIGHT = 4;
private static final int REWARD_PER_PAGE = GRID_WIDTH*GRID_HEIGHT; // 28
private void openGui(Player p, int page) {
final GiftPack plugin = this;
Bukkit.getScheduler().runTaskAsynchronously(this, ()->{
try {
Map<Integer, Reward> rewards = parseRewardList();
PreparedStatement ps = conn.prepareStatement("SELECT * FROM player_giftpack WHERE uuid = ?");
ps.setString(1, p.getUniqueId().toString());
ResultSet rs = ps.executeQuery();
int total_seconds = 0, login_days = 0, rewarded = 0;
if(rs.next()){
total_seconds = rs.getInt("total_play_seconds");
login_days = rs.getInt("login_days");
rewarded = rs.getInt("rewarded");
}
rs.close(); ps.close();
final int f_total_seconds = total_seconds;
final int f_login_days = login_days;
final int f_rewarded = rewarded;
final int maxDay = rewards.keySet().stream().max(Integer::compareTo).orElse(0);
final int totalPages = (maxDay + REWARD_PER_PAGE - 1) / REWARD_PER_PAGE == 0 ? 1 : (maxDay + REWARD_PER_PAGE -1)/REWARD_PER_PAGE;
final int pageNow = Math.max(1, Math.min(page, totalPages));
Bukkit.getScheduler().runTask(plugin, ()->{
Inventory inv = Bukkit.createInventory(null, 9*6, ChatColor.GOLD+"新手累计登录奖励 - 第" + pageNow + "/" + totalPages + "页");
ItemStack border = new ItemStack(Material.GRAY_STAINED_GLASS_PANE,1);
ItemMeta bm = border.getItemMeta(); bm.setDisplayName(ChatColor.DARK_GRAY+"——"); border.setItemMeta(bm);
for(int r=0;r<6;r++) for(int c=0;c<9;c++) if(r==0||r==5||c==0||c==8) inv.setItem(r*9+c, border);
// 累计在线时间/天数(主界面底部中间)
ItemStack timeBtn = makeButton(Material.CLOCK, ChatColor.AQUA+"累计在线时长", Arrays.asList(getTimeString(f_total_seconds), ChatColor.GRAY+"登录天数: "+f_login_days));
inv.setItem(9*5, timeBtn);
inv.setItem(0, makeButton(Material.BOOK, ChatColor.YELLOW+"帮助", Arrays.asList("§7鼠标右键: 查看奖励说明")));
inv.setItem(8, makeButton(Material.REDSTONE, ChatColor.RED+"刷新", Arrays.asList("§7点我刷新界面")));
// 分页奖励格
int baseIdx = (pageNow-1)*REWARD_PER_PAGE+1;
int count=0;
for(int i=baseIdx; i<baseIdx+REWARD_PER_PAGE && i<=maxDay; i++){
Reward rew = rewards.get(i); if(rew==null) continue;
boolean got = (f_rewarded&(1<<(i-1)))!=0;
boolean avail = f_login_days>=i;
boolean rightPerm = rew.perm==null||rew.perm.isEmpty()||p.hasPermission(rew.perm);
ItemStack icon; String title; List<String> lore = new ArrayList<>();
if(got) {icon=new ItemStack(Material.EMERALD_BLOCK);title=ChatColor.GREEN+"已领取: 第"+i+"天";}
else if(avail&&rightPerm) {icon=new ItemStack(Material.CHEST);title=ChatColor.GOLD+"可领取: 第"+i+"天";lore.add(ChatColor.YELLOW+rew.desc);lore.add(ChatColor.GRAY+"左键领取,右键查看奖品详情");}
else {icon=new ItemStack(Material.BARRIER);title=ChatColor.GRAY+"未达成: 第"+i+"天";}
if(!rightPerm)lore.add(ChatColor.RED+"没有礼包权限(管理员可配置)");
int row = count / GRID_WIDTH;
int col = count % GRID_WIDTH;
int slot = (row+2)*9+(col+2);
inv.setItem(slot, makeButton(icon.getType(), title, lore));
count++;
}
// 分页按钮
if(pageNow>1) inv.setItem(45, makeButton(Material.ARROW, ChatColor.YELLOW+"上一页",Arrays.asList("§7前往上一页")));
if(pageNow<totalPages) inv.setItem(53, makeButton(Material.ARROW, ChatColor.YELLOW+"下一页",Arrays.asList("§7前往下一页")));
p.openInventory(inv);
});
}catch(Exception ex){ ex.printStackTrace(); }
});
}
private String getTimeString(int sec){
int days=sec/86400; sec%=86400;
int hours=sec/3600; sec%=3600;
int min=sec/60; sec%=60;
StringBuilder sb = new StringBuilder();
if(days>0)sb.append(days+"天");
if(hours>0||days>0)sb.append(hours+"小时");
if(min>0||hours>0||days>0)sb.append(min+"分");
sb.append(sec+"秒");
return sb.toString();
}
private int getCurrentPageFromTitle(String title) {
try {
int idx = title.indexOf("第"); int idx2 = title.indexOf("/");
if(idx>=0&&idx2>idx){
String pstr = title.substring(idx+1,idx2).replaceAll("[^0-9]","");
return Integer.parseInt(pstr);
}
}catch(Exception ignore){}
return 1;
}
private ItemStack makeButton(Material mat, String title, List<String> lore) {
ItemStack is = new ItemStack(mat, 1); ItemMeta im = is.getItemMeta(); im.setDisplayName(title); im.setLore(lore); is.setItemMeta(im); return is;
}
// ---------------------- GUI点击事件 ----------------------
@EventHandler
public void onGuiClick(InventoryClickEvent e) {
if(!(e.getWhoClicked() instanceof Player)) return;
if(e.getInventory()==null||e.getView().getTitle()==null) return;
if(!e.getView().getTitle().contains("新手累计登录奖励")) return;
e.setCancelled(true);
final Player p = (Player) e.getWhoClicked();
final int slot = e.getRawSlot();
if(slot < 0 || slot >= 54) return;
if(slot == 0){ if(e.isRightClick()) sendHelp(p); return;}
if(slot == 8){ if(e.isLeftClick()) openGui(p, 1); return;}
// 分页按钮
if(slot == 45) { openGui(p, getCurrentPageFromTitle(e.getView().getTitle())-1); return; }
if(slot == 53) { openGui(p, getCurrentPageFromTitle(e.getView().getTitle())+1); return; }
// 奖励领取与详情
int gridSlot=slot;
if(gridSlot>=REWARD_GRID_START&&gridSlot<=REWARD_GRID_END&&(gridSlot%9>=2&&gridSlot%9<=8)){
int row = (gridSlot/9)-2;
int col = (gridSlot%9)-2;
int idx = row*GRID_WIDTH+col;
int page = getCurrentPageFromTitle(e.getView().getTitle());
int day = (page-1)*REWARD_PER_PAGE+1+idx;
if(e.isRightClick()) {
showRewardDetail(p, day); return;
} else if(e.isLeftClick()) {
getRewardForDay(p, day); return;
}
}
}
// 查看某日奖励详情
public void showRewardDetail(Player p, int day){
Map<Integer, Reward> rewards = parseRewardList();
Reward r = rewards.get(day);
if(r == null){ p.sendMessage(ChatColor.RED+"奖励未配置。"); return; }
p.sendMessage(ChatColor.AQUA+"——第"+day+"天 新手奖励内容——");
p.sendMessage(ChatColor.YELLOW+r.desc);
if(r.items!=null && r.items.size()>0) p.sendMessage(ChatColor.GRAY+"物品奖励: "+r.items);
if(r.money > 0) p.sendMessage(ChatColor.GRAY+"金币奖励: "+r.money);
if(r.perm != null && !r.perm.isEmpty()) p.sendMessage(ChatColor.GRAY+"领取此礼包需权限: "+r.perm);
}
// 领取指定天数奖励
private void getRewardForDay(final Player p, final int day) {
final GiftPack plugin = this;
Bukkit.getScheduler().runTaskAsynchronously(this, ()->{
try {
Map<Integer, Reward> rewards = parseRewardList(); Reward r = rewards.get(day);
if(r == null){ p.sendMessage(ChatColor.RED+"该天礼包奖励不存在!"); return; }
String uuid = p.getUniqueId().toString();
PreparedStatement ps = conn.prepareStatement("SELECT * FROM player_giftpack WHERE uuid = ?");
ps.setString(1, uuid);
ResultSet rs = ps.executeQuery();
int login_days = 0, rewarded = 0;
if(rs.next()){
login_days = rs.getInt("login_days");
rewarded = rs.getInt("rewarded");
}
rs.close(); ps.close();
if(login_days < day){ p.sendMessage(ChatColor.RED+"累计登录数不足,无法领取第"+day+"天奖励!"); return; }
if( (rewarded&(1<<(day-1))) != 0 ){ p.sendMessage(ChatColor.YELLOW+"本日奖励已领取!"); return; }
if(r.perm!=null && !r.perm.isEmpty() && !p.hasPermission(r.perm)){ p.sendMessage(ChatColor.RED+"无领取权限: "+r.perm); return; }
Bukkit.getScheduler().runTask(plugin, ()->{
// 发放物品
if(r.items!=null){
for(String it : r.items){
String[] args = it.split(":");
try{
Material m = Material.matchMaterial(args[0]);
int num = args.length>1 ? Integer.parseInt(args[1]) : 1;
if(m!=null && num>0){
ItemStack stack = new ItemStack(m, num);
p.getInventory().addItem(stack);
}
}catch(Exception ignore){}
}
}
// 发放金币
if(r.money > 0 && economy != null){
boolean ok = economy.depositPlayer(p, r.money);
if(ok) p.sendMessage(ChatColor.GREEN+"已获得金币: "+r.money);
}
// 数据库标记奖励发放
Bukkit.getScheduler().runTaskAsynchronously(plugin, ()->{
try{
PreparedStatement upd = conn.prepareStatement("UPDATE player_giftpack SET rewarded = rewarded | ? WHERE uuid = ?");
upd.setInt(1, 1<<(day-1));
upd.setString(2, uuid);
upd.executeUpdate(); upd.close();
}catch(Exception e){ e.printStackTrace(); }
});
p.sendMessage(ChatColor.AQUA+"恭喜领取第"+day+"天新手奖励!请查看背包和账户");
openGui(p, getCurrentPageFromTitle(p.getOpenInventory().getTitle()));
});
}catch(Exception e){ e.printStackTrace(); }
});
}
}