GiftPack

GiftPack.java v2.0
新手礼包插件,注册指令/giftpack,分页显示奖励及在线时长,支持Vault、帮助命令、性能最优。
作者: Scriptirc Engine

命令列表

  • giftpack主命令,包含open、reload、help子命令

权限列表

  • giftpack.user允许玩家领取或查看新手礼包
  • giftpack.admin允许管理员管理并reload礼包
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(); }
        });
    }
}
上一篇: RPGItemBinder下一篇: GiftPack

举报内容

意见反馈