This commit is contained in:
yaohunya 2025-07-12 07:44:13 +08:00
commit a488c44036
11 changed files with 702 additions and 0 deletions

41
pom.xml Normal file
View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.yaohun.guaji.AuGuaJi</groupId>
<artifactId>AuConsumeReward</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<repositories>
<repository>
<id>public-rpg</id>
<url>https://repo.aurora-pixels.com/repository/public-rpg/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.12.2</version>
</dependency>
<dependency>
<groupId>me.Demon.DemonPlugin</groupId>
<artifactId>DemonAPI</artifactId>
<version>2.2.9</version>
</dependency>
<dependency>
<groupId>com.yaohun.aurechargedata</groupId>
<artifactId>AuRechargeData</artifactId>
<version>2.0.0</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,108 @@
package com.yaohun.consumereward;
import com.yaohun.consumereward.config.Config;
import com.yaohun.consumereward.data.PlayerData;
import com.yaohun.consumereward.gui.RewardGui;
import com.yaohun.consumereward.manage.PlayerManager;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
public class ConsumeReward extends JavaPlugin {
private static ConsumeReward instance;
private static PlayerManager playerManager;
@Override
public void onEnable() {
instance = this;
saveDefaultConfig();
Config.reloadConfig(this);
playerManager = new PlayerManager();
getServer().getPluginManager().registerEvents(new RewardGui(),this);
}
@Override
public void onDisable() {
super.onDisable();
}
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if(args.length == 1 && "open".equalsIgnoreCase(args[0])){
RewardGui.OpenGui((Player) sender);
return true;
}
if(!sender.isOp()){
RewardGui.OpenGui((Player) sender);
return true;
}
if(args.length == 0){
sender.sendMessage("");
sender.sendMessage("§e------- ======= §6累积消费礼包 §e======= -------");
sender.sendMessage("§2/"+label+" open §f- §2打开界面");
sender.sendMessage("§2/"+label+" reload §f- §2重载配置文件");
sender.sendMessage("§2/"+label+" convert §f- §c导入旧版奖励领取数据");
sender.sendMessage("§e------- ======= §6累积消费礼包 §e======= -------");
sender.sendMessage("");
return true;
}
if("reload".equalsIgnoreCase(args[0])){
Config.reloadConfig(this);
sender.sendMessage("[消费奖励] 配置文件已重载.");
return true;
}
if("convert".equalsIgnoreCase(args[0])){
// 转换后的 map: 玩家名 -> 参与的 key 列表
Map<String, List<String>> playerToKeys = new TreeMap<>();
File file = new File("plugins/DemonRechargeOrConsume","config.yml");
FileConfiguration config = YamlConfiguration.loadConfiguration(file);
ConfigurationSection section = config.getConfigurationSection("ClaimRecordData");
if(section == null){
return true;
}
for (String key : section.getKeys(false)){
String data = section.getString(key+".recordData");
// 去掉开头的 , 并按 , 拆分
String[] names = data.replaceFirst("^,", "").split(",");
for (String name : names) {
if (name.isEmpty()) {
continue;
}
playerToKeys.computeIfAbsent(name, k -> new ArrayList<>()).add(key);
}
}
// 打印结果
int count = 0;
for (Map.Entry<String, List<String>> entry : playerToKeys.entrySet()) {
PlayerData playerData = playerManager.getPlayerData(entry.getKey());
playerData.setRewardList(entry.getValue());
playerData.savePlayerData();
count++;
}
sender.sendMessage("[消费奖励] 数据已进行转换 "+count+"");
return true;
}
return false;
}
public static ConsumeReward inst() {
return instance;
}
public static PlayerManager getPlayerManager() {
return playerManager;
}
}

View File

@ -0,0 +1,115 @@
package com.yaohun.consumereward.config;
import com.yaohun.consumereward.ConsumeReward;
import com.yaohun.consumereward.data.RewardData;
import me.Demon.DemonPlugin.DemonAPI;
import me.Demon.DemonPlugin.data.GuiItemData;
import me.Demon.DemonPlugin.data.LangData;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class Config {
// 存储语言配置数据
public static LangData langData;
// 存储界面物品数据的映射表
private static HashMap<String, GuiItemData> guiItemDataMap = new HashMap<>();
// 存储奖励设置的列表
private static List<RewardData> rewardDataList = new ArrayList<>();
public static void reloadConfig(ConsumeReward plugin) {
// 调用了DemonAPI中的LangData
// 需要在AuLangs目录中创建一个 LevelReward.yml 文件存语言配置
langData = DemonAPI.getLangData("ConsumeReward");
// 重新加载和保存插件的配置文件
plugin.reloadConfig();
plugin.saveConfig();
FileConfiguration config = plugin.getConfig();
// 加载界面物品数据和奖励设置
loadGuiItemData(config);
loadRewardSettings(config);
}
/**
* 从配置文件中加载奖励设置
* 此方法清除现有的奖励数据列表并从配置文件的"RewardSettings"部分重新加载
* @param config 插件的配置文件
*/
private static void loadRewardSettings(FileConfiguration config){
// 清除现有的奖励数据列表
rewardDataList.clear();
// 获取"RewardSettings"配置部分
ConfigurationSection section = config.getConfigurationSection("RewardSettings");
// 如果该部分不存在则直接返回
if(section == null) {return;}
// 遍历"RewardSettings"部分的所有键并创建新的RewardData对象添加到列表中
for (String rewardKey : section.getKeys(false)){
rewardDataList.add(new RewardData(rewardKey,section));
}
}
/**
* 从配置文件中加载界面物品数据
* 此方法清除现有的界面物品数据映射表并从配置文件的"GuiItemData"部分重新加载
* @param configuration 插件的配置文件
*/
private static void loadGuiItemData(FileConfiguration configuration){
// 清除现有的界面物品数据映射表
guiItemDataMap.clear();
// 获取"GuiItemData"配置部分
ConfigurationSection section = configuration.getConfigurationSection("GuiItemData");
// 如果该部分不存在则直接返回
if(section == null){return;}
// 遍历"GuiItemData"部分的所有键并创建新的GuiItemData对象添加到映射表中
for (String itemKey : section.getKeys(false)){
guiItemDataMap.put(itemKey,new GuiItemData(itemKey,section));
}
}
/**
* 根据物品键获取对应的ItemStack对象
* 如果指定的物品键存在于映射表中则返回对应的ItemStack对象的克隆否则返回错误物品
* @param itemKey 物品键
* @return 对应的ItemStack对象的克隆或错误物品
*/
public static ItemStack getItemStack(String itemKey) {
// 检查物品键是否存在于映射表中
if(guiItemDataMap.containsKey(itemKey)){
// 返回对应的ItemStack对象的克隆
return guiItemDataMap.get(itemKey).getItemStack().clone();
}
// 如果物品键不存在则返回错误物品
return DemonAPI.getErrItems();
}
/**
* 获取奖励数据列表
* @return 奖励数据列表
*/
public static List<RewardData> getRewardDataList() {
return rewardDataList;
}
/**
* 根据奖励键获取对应的奖励数据
* 如果找到匹配的奖励键则返回对应的奖励数据否则返回null
* @param rewardKey 奖励键
* @return 对应的奖励数据或null
*/
public static RewardData getRewardData(String rewardKey) {
// 遍历奖励数据列表
for (RewardData rewardData : rewardDataList){
// 如果找到匹配的奖励键则返回对应的奖励数据
if(rewardData.getRewardKey().equals(rewardKey)){
return rewardData;
}
}
// 如果没有找到匹配的奖励键则返回null
return null;
}
}

View File

@ -0,0 +1,88 @@
package com.yaohun.consumereward.data;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.io.IOException;
import java.util.List;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.io.IOException;
import java.util.*;
public class PlayerData {
/**
* 玩家数据类用于管理玩家的奖励接收情况
*/
private final String playerName;
/**
* 存储玩家已接收的奖励列表
* 使用 Set 而不是 List 来提升 contains 方法的性能因为 Set 的查找效率更高
*/
private final Set<String> rewardList;
/**
* 构造玩家数据对象根据玩家名称加载其奖励接收数据
*
* @param playerName 玩家名称用于标识和加载玩家数据
*/
public PlayerData(String playerName) {
this.playerName = playerName;
// 加载玩家的奖励数据文件
File file = new File("plugins/AuData/ConsumeReward", playerName + ".yml");
YamlConfiguration config = YamlConfiguration.loadConfiguration(file);
List<String> rewards = config.getStringList("RewardsReceive");
// 使用 LinkedHashSet 保持插入顺序避免重复
this.rewardList = new LinkedHashSet<>(rewards);
}
/**
* 检查玩家是否已经接收了指定的奖励
*
* @param rewardKey 奖励的唯一键用于标识特定的奖励
* @return 如果玩家已经接收了指定的奖励则返回 true否则返回 false
*/
public boolean isReceive(String rewardKey) {
return rewardList.contains(rewardKey);
}
/**
* 向玩家的奖励列表中添加一个新的奖励
*
* @param rewardKey 新增奖励的唯一键用于标识特定的奖励
*/
public void addRewardReceive(String rewardKey) {
rewardList.add(rewardKey);
}
/**
* 设置玩家的奖励列表替换现有的奖励列表
*
* @param rewardList 新的奖励列表不含重复项
*/
public void setRewardList(List<String> rewardList) {
this.rewardList.clear();
// 使用 LinkedHashSet 包装列表以避免重复项并保持插入顺序
this.rewardList.addAll(new LinkedHashSet<>(rewardList));
}
/**
* 保存玩家的奖励接收数据到文件
* Set 类型的 rewardList 转换回 List 类型以保存到 YAML 文件中
*/
public void savePlayerData() {
File file = new File("plugins/AuData/ConsumeReward", playerName + ".yml");
YamlConfiguration config = YamlConfiguration.loadConfiguration(file);
// Set 转换回 List 以保存
config.set("RewardsReceive", new ArrayList<>(rewardList));
try {
config.save(file);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,65 @@
package com.yaohun.consumereward.data;
import org.bukkit.Bukkit;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import java.util.List;
public class RewardData {
private String rewardKey;
private int slot;
private int needConsume;
private int backpackSlot;
private String itemNbt;
private List<String> rewardLore;
private List<String> commandList;
public RewardData(String rewardKey, ConfigurationSection section){
this.rewardKey = rewardKey;
this.slot = section.getInt(rewardKey+".slot");
this.needConsume = section.getInt(rewardKey+".needConsume");
this.backpackSlot = section.getInt(rewardKey+".backpackSlot");
this.itemNbt = section.getString(rewardKey+".itemNbt");
this.rewardLore = section.getStringList(rewardKey+".rewardLore");
this.commandList = section.getStringList(rewardKey+".commandList");
}
public String getRewardKey() {
return rewardKey;
}
public int getSlot() {
return slot;
}
public int getNeedConsume() {
return needConsume;
}
public int getBackpackSlot() {
return backpackSlot;
}
public String getItemNbt() {
return itemNbt;
}
public List<String> getRewardLore() {
return rewardLore;
}
public void carryOutReward(Player player){
String playerName = player.getName();
// 遍历所有命令并执行
for(String command : commandList) {
if (command.contains("msg:")) {
// 如果是消息命令去掉前缀后发送消息
player.sendMessage(command.replace("msg:", "").replace("&", "§"));
continue;
}
// 替换命令中的玩家名称占位符%p%为真实名称
command = command.replace("%p%", playerName);
command = command.replace("%player%", playerName);
// 执行命令
Bukkit.dispatchCommand(Bukkit.getConsoleSender(),command);
}
// 记录日志
Bukkit.getLogger().info("[消费奖励 - 发放] " + player.getName() + " 已执行奖励命令: " + rewardKey);
}
}

View File

@ -0,0 +1,89 @@
package com.yaohun.consumereward.gui;
import com.yaohun.aurechargedata.api.ConsumeAPI;
import com.yaohun.aurechargedata.util.TimeType;
import com.yaohun.consumereward.ConsumeReward;
import com.yaohun.consumereward.config.Config;
import com.yaohun.consumereward.data.PlayerData;
import com.yaohun.consumereward.data.RewardData;
import com.yaohun.consumereward.manage.PlayerManager;
import com.yaohun.consumereward.util.MessageUtil;
import com.yaohun.consumereward.util.StackUtil;
import me.Demon.DemonPlugin.DemonAPI;
import me.Demon.DemonPlugin.data.NbtItem;
import org.bukkit.Bukkit;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
public class RewardGui implements Listener {
public static void OpenGui(Player player){
String playerName = player.getName();
Inventory inv = Bukkit.createInventory(null,54, Config.langData.getMessage("invTitle"));
for (int i = 0;i<9;i++){ inv.setItem(i, DemonAPI.glass(DemonAPI.getRandomInt(7,1),"§r")); }
inv.setItem(4, StackUtil.getDataInfo(playerName));
PlayerManager playerManager = ConsumeReward.getPlayerManager();
PlayerData playerData = playerManager.getPlayerData(playerName);
for (RewardData rewardData : Config.getRewardDataList()){
inv.setItem(rewardData.getSlot(), StackUtil.getRewardGiftBox(playerData, rewardData));
}
player.openInventory(inv);
}
@EventHandler
public void onClick(InventoryClickEvent e){
int rawSlot = e.getRawSlot();
Player player = (Player) e.getWhoClicked();
String playerName = player.getName();
if(e.getView().getTitle().equalsIgnoreCase(Config.langData.getMessage("invTitle"))) {
e.setCancelled(true);
if (rawSlot >= 0 && rawSlot < e.getInventory().getSize()) {
ItemStack stack = e.getCurrentItem();
if (DemonAPI.itemIsNull(stack) || DemonAPI.itemIsLore(stack)) {
return;
}
NbtItem nbtItem = new NbtItem(stack);
if (nbtItem.hasKey("rewardKey")) {
String value = nbtItem.getString("rewardKey");
RewardData rewardData = Config.getRewardData(value);
if (rewardData == null) {
return;
}
int backpackSlot = rewardData.getBackpackSlot();
if (!DemonAPI.hasEmptyInventorySlots(player, backpackSlot)) {
MessageUtil.sendMessageKey(player, "notEnoughInventorySlots", Sound.ENTITY_VILLAGER_NO);
return;
}
int needConsume = rewardData.getNeedConsume();
int consumeValue = ConsumeAPI.getConsumeData(playerName, TimeType.ANNUAL);
if (needConsume > consumeValue) {
String message = Config.langData.getMessage("notEnoughConsume");
int newConsume = needConsume - consumeValue;
message = message.replace("{needConsume}", String.valueOf(newConsume));
MessageUtil.sendMessage(player, message, Sound.ENTITY_VILLAGER_NO);
return;
}
PlayerManager playerManager = ConsumeReward.getPlayerManager();
PlayerData playerData = playerManager.getPlayerData(playerName);
if (playerData.isReceive(value)) {
MessageUtil.sendMessageKey(player, "alreadyReceived", Sound.ENTITY_VILLAGER_NO);
return;
}
playerData.addRewardReceive(value);
rewardData.carryOutReward(player);
String message = Config.langData.getMessage("announcement");
message = message.replace("{name}", playerName);
message = message.replace("{itemName}", DemonAPI.getItemName(stack));
Bukkit.broadcastMessage(message);
MessageUtil.sendMessageKey(player, "receivedSuccessfully", Sound.ENTITY_PLAYER_LEVELUP);
RewardGui.OpenGui(player);
}
}
}
}
}

View File

@ -0,0 +1,19 @@
package com.yaohun.consumereward.manage;
import com.yaohun.consumereward.data.PlayerData;
import java.util.HashMap;
public class PlayerManager {
private HashMap<String, PlayerData> playerDataMap = new HashMap<>();
public PlayerData getPlayerData(String playerName) {
if(!playerDataMap.containsKey(playerName)){
PlayerData playerData = new PlayerData(playerName);
playerDataMap.put(playerName, playerData);
return playerData;
}
return playerDataMap.get(playerName);
}
}

View File

@ -0,0 +1,71 @@
package com.yaohun.consumereward.util;
import com.yaohun.consumereward.config.Config;
import org.bukkit.Sound;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
/**
* 消息工具类用于向命令发送者发送消息
* 提供了向Minecraft服务器中的玩家或其他命令发送者发送消息的功能
*/
public class MessageUtil {
/**
* 向指定的命令发送者发送消息
* 如果发送者是玩家使用玩家对象的sendMessage方法发送
* 否则直接使用命令发送者的sendMessage方法
*
* @param sender 命令发送者对象可以是玩家或控制台
* @param message 要发送的消息内容
*/
public static void sendMessage(CommandSender sender, String message) {
if(sender instanceof Player){
Player player = (Player) sender;
player.sendMessage(message);
} else {
sender.sendMessage(message);
}
}
/**
* 向指定的命令发送者发送消息并播放音效
* 如果发送者是玩家则还会播放指定的音效
*
* @param sender 命令发送者可以是玩家或控制台等
* @param message 要发送的消息文本
* @param sound 要播放的音效
*/
public static void sendMessage(CommandSender sender, String message, Sound sound) {
// 判断发送者是否为玩家以便播放音效
if(sender instanceof Player){
Player player = (Player) sender;
player.sendMessage(message);
player.playSound(player.getLocation(), sound, 0.5f, 1.2f);
} else {
sender.sendMessage(message);
}
}
/**
* 根据语言键向指定的命令发送者发送消息并播放音效
* 首先从配置文件中获取对应语言键的消息文本然后发送给发送者
* 如果发送者是玩家则还会播放指定的音效
*
* @param sender 命令发送者可以是玩家或控制台等
* @param langKey 语言键用于从配置文件中获取消息文本
* @param sound 要播放的音效
*/
public static void sendMessageKey(CommandSender sender, String langKey, Sound sound) {
String message = Config.langData.getMessage(langKey);
// 判断发送者是否为玩家以便播放音效
if(sender instanceof Player){
Player player = (Player) sender;
player.sendMessage(message);
player.playSound(player.getLocation(), sound, 0.5f, 1.2f);
} else {
sender.sendMessage(message);
}
}
}

View File

@ -0,0 +1,62 @@
package com.yaohun.consumereward.util;
import com.yaohun.aurechargedata.api.ConsumeAPI;
import com.yaohun.aurechargedata.util.TimeType;
import com.yaohun.consumereward.config.Config;
import com.yaohun.consumereward.data.PlayerData;
import com.yaohun.consumereward.data.RewardData;
import me.Demon.DemonPlugin.data.NbtItem;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.ArrayList;
import java.util.List;
public class StackUtil {
public static ItemStack getDataInfo(String playerName){
ItemStack stack = Config.getItemStack("dataInfo");
ItemMeta meta = stack.getItemMeta();
List<String> lore = meta.getLore();
for (int i = 0; i < lore.size(); i++){
String line = lore.get(i);
if(line.contains("{name}")){
lore.set(i, line.replace("{name}", playerName));
continue;
}
if(line.contains("{consume}")){
int consumeValue = ConsumeAPI.getConsumeData(playerName, TimeType.ANNUAL);
lore.set(i, line.replace("{consume}", String.valueOf(consumeValue)));
}
}
meta.setLore(lore);
stack.setItemMeta(meta);
return stack;
}
public static ItemStack getRewardGiftBox(PlayerData playerData, RewardData rewardData){
String rewardKey = rewardData.getRewardKey();
ItemStack stack = Config.getItemStack("rewardGiftBox");
ItemMeta meta = stack.getItemMeta();
List<String> newLore = new ArrayList<>();
for (String line : meta.getLore()){
if(line.contains("{stats}")){
if(playerData.isReceive(rewardKey)){
newLore.add(line.replace("{stats}", Config.langData.getMessage("statsOK")));
} else {
newLore.add(line.replace("{stats}", Config.langData.getMessage("statsNO")));
}
} else if(line.contains("{rewardLore}")){
newLore.addAll(rewardData.getRewardLore());
} else {
newLore.add(line);
}
}
meta.setLore(newLore);
stack.setItemMeta(meta);
NbtItem nbtItem = new NbtItem(stack);
nbtItem.setString("rewardKey", rewardKey);
return nbtItem.getItem();
}
}

View File

@ -0,0 +1,35 @@
GuiItemData:
dataInfo:
Material: PAPER
DisplayName: "§8« §e我的数据 §8»"
Lore:
- "§a§l★§7玩家名称: §a{name}"
- "§a§l★§7累积消费: §b{consume}软"
- " "
- "§c§l★§7消费累积不含玩家之间交易"
NbtString: stex#cailiao_18
rewardGiftBox:
Material: PAPER
DisplayName: "§a§l累计消费§3§l{coins}§a§l礼盒"
Lore:
- "§8--------------------"
- "§c§l★§7领取状态: {stats}"
- "§8--------------------"
- "§9§L可获得的奖励:"
- "{rewardLore}"
RewardSettings:
key_01:
slot: 10
needConsume: 39
backpackSlot: 3
itemNbt: cailiao_42
rewardLore:
- §7- §6属性称号 §7[§e有钱任性§7]
- §7- §d§l远古精灵的秘药§7§l★§f1
- §7- §e§l灵环精片§7§l★§f2
- §7- §6§l财主金币袋§7§l★§f1
commandList:
- console:dpap give %player% 有钱任性 36500
- console:dpotion give 远古精灵的秘药 1 %player%
- console:ditem give 灵环精片 2 %player%
- console:ditem give 财主金币袋 1 %player%

View File

@ -0,0 +1,9 @@
name: AuConsumeReward
main: com.yaohun.consumereward.ConsumeReward
version: 1.2.0
depend:
- DemonAPI
commands:
consumereward:
aliases:
# - droc