feat: 修复数据保存增加异步
This commit is contained in:
@@ -47,18 +47,16 @@ public class AuOnlineReward extends JavaPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void startOnlineTimeTask() {
|
public void startOnlineTimeTask() {
|
||||||
Bukkit.getScheduler().runTaskTimerAsynchronously(this, () -> {
|
Bukkit.getScheduler().runTaskTimer(this, () -> {
|
||||||
RefreshData refreshData = DataRefreshUtil.getSetting("OnlineDaily");
|
RefreshData refreshData = DataRefreshUtil.getSetting("OnlineDaily");
|
||||||
if(refreshData != null && !refreshData.isSameDayAsRecord()){
|
if(refreshData != null && !refreshData.isSameDayAsRecord()){
|
||||||
refreshData.setRecordTime(System.currentTimeMillis());
|
refreshData.setRecordTime(System.currentTimeMillis());
|
||||||
DataRefreshUtil.SaveRefreshDataRecord(refreshData);
|
DataRefreshUtil.SaveRefreshDataRecord(refreshData);
|
||||||
// 每日数据刷新处理
|
// 每日数据刷新处理
|
||||||
getPlayerManager().clearAllPlayerData();
|
|
||||||
getPlayerManager().refreshLocalPlayerData(TimeType.DAILY);
|
getPlayerManager().refreshLocalPlayerData(TimeType.DAILY);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(TimeCheckUtil.isMonthlySettleAccounts()){
|
if(TimeCheckUtil.isMonthlySettleAccounts()){
|
||||||
getPlayerManager().clearAllPlayerData();
|
|
||||||
getPlayerManager().refreshLocalPlayerData(TimeType.MONTHLY);
|
getPlayerManager().refreshLocalPlayerData(TimeType.MONTHLY);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -73,12 +71,16 @@ public class AuOnlineReward extends JavaPlugin {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisable() {
|
public void onDisable() {
|
||||||
getPlayerManager().saveAllPlayerData();
|
getPlayerManager().clearAllPlayerData();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||||
if(args.length == 1 && args[0].equalsIgnoreCase("open")){
|
if(args.length == 1 && args[0].equalsIgnoreCase("open")){
|
||||||
|
if(!(sender instanceof Player)){
|
||||||
|
sender.sendMessage("§c该命令只能由玩家执行.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
OnlineGui.OpenGui((Player) sender);
|
OnlineGui.OpenGui((Player) sender);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -135,15 +137,28 @@ public class AuOnlineReward extends JavaPlugin {
|
|||||||
if("top".equalsIgnoreCase(args[0]) || "topDay".equalsIgnoreCase(args[0])){
|
if("top".equalsIgnoreCase(args[0]) || "topDay".equalsIgnoreCase(args[0])){
|
||||||
HashMap<String,Integer> hashMap = new HashMap<>();
|
HashMap<String,Integer> hashMap = new HashMap<>();
|
||||||
for (PlayerData playerData : getPlayerManager().getPlayerDataMap().values()) {
|
for (PlayerData playerData : getPlayerManager().getPlayerDataMap().values()) {
|
||||||
hashMap.put(playerData.getPlayerName(),playerData.todayOnline);
|
if ("topDay".equalsIgnoreCase(args[0])) {
|
||||||
|
hashMap.put(playerData.getPlayerName(), playerData.todayOnline / 60);
|
||||||
|
} else {
|
||||||
|
hashMap.put(playerData.getPlayerName(), playerData.totalOnline / 60);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ranking ranking = new Ranking(hashMap);
|
Ranking ranking = new Ranking(hashMap);
|
||||||
sender.sendMessage(" ");
|
sender.sendMessage(" ");
|
||||||
sender.sendMessage("§e§l★ §a"+DemonAPI.getTime("yyyy-MM-dd")+"在线排行榜 §7(不定时更新数据)");
|
sender.sendMessage("§e§l★ §a"+DemonAPI.getTime("yyyy-MM-dd")+"在线排行榜 §7(不定时更新数据)");
|
||||||
for (int rank = 1; rank < 15; rank++) {
|
for (int rank = 1; rank < 15; rank++) {
|
||||||
String rankingPlayer = ranking.getRankingPlayer(rank, "name");
|
String rankingPlayer = ranking.getRankingPlayer(rank, "name");
|
||||||
String onlineTime = ranking.getRankingPlayer(rank, "value");
|
String valueString = ranking.getRankingPlayer(rank, "value");
|
||||||
sender.sendMessage("§a§l★ §7第 §e" + rank + " §7名: §e" + rankingPlayer + "§7累积在线: §e"+onlineTime+"分钟");
|
if(valueString.contains("§")){
|
||||||
|
sender.sendMessage("§a§l★ §7第 §e" + rank + " §7名: §e" + rankingPlayer + "§7累积在线: §e" + valueString);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ("topDay".equalsIgnoreCase(args[0])) {
|
||||||
|
sender.sendMessage("§a§l★ §7第 §e" + rank + " §7名: §e" + rankingPlayer + "§7累积在线: §e" + valueString + "分钟");
|
||||||
|
} else {
|
||||||
|
int onlineTime = Integer.parseInt(valueString);
|
||||||
|
sender.sendMessage("§a§l★ §7第 §e" + rank + " §7名: §e" + rankingPlayer + "§7累积在线: §e" + (onlineTime/60) + "小时");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
sender.sendMessage(" ");
|
sender.sendMessage(" ");
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ public class Config {
|
|||||||
plugin.saveConfig();
|
plugin.saveConfig();
|
||||||
}
|
}
|
||||||
FileConfiguration config = plugin.getConfig();
|
FileConfiguration config = plugin.getConfig();
|
||||||
|
onlineDataMap.clear();
|
||||||
loadRewardData(config);
|
loadRewardData(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import org.bukkit.entity.Player;
|
|||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class OnlineData {
|
public class OnlineData {
|
||||||
@@ -52,11 +53,17 @@ public class OnlineData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ItemStack getItemStack(PlayerData playerData) {
|
public ItemStack getItemStack(PlayerData playerData) {
|
||||||
|
if(DemonAPI.itemIsNull(this.itemStack)){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
if(this.rewardKey.contains("MinuteReward_")) {
|
if(this.rewardKey.contains("MinuteReward_")) {
|
||||||
long collectionTime = playerData.collectionTime;
|
long collectionTime = playerData.collectionTime;
|
||||||
ItemStack stack = itemStack.clone();
|
ItemStack stack = itemStack.clone();
|
||||||
ItemMeta meta = itemStack.getItemMeta();
|
ItemMeta meta = stack.getItemMeta();
|
||||||
List<String> lore = meta.getLore();
|
if(meta == null || meta.getLore() == null){
|
||||||
|
return stack;
|
||||||
|
}
|
||||||
|
List<String> lore = new ArrayList<>(meta.getLore());
|
||||||
for (int i = 0; i < lore.size(); i++) {
|
for (int i = 0; i < lore.size(); i++) {
|
||||||
String s = lore.get(i);
|
String s = lore.get(i);
|
||||||
if (s.contains("%time%")) {
|
if (s.contains("%time%")) {
|
||||||
@@ -88,8 +95,11 @@ public class OnlineData {
|
|||||||
return stack;
|
return stack;
|
||||||
} else {
|
} else {
|
||||||
ItemStack stack = itemStack.clone();
|
ItemStack stack = itemStack.clone();
|
||||||
ItemMeta meta = itemStack.getItemMeta();
|
ItemMeta meta = stack.getItemMeta();
|
||||||
List<String> lore = meta.getLore();
|
if(meta == null || meta.getLore() == null){
|
||||||
|
return stack;
|
||||||
|
}
|
||||||
|
List<String> lore = new ArrayList<>(meta.getLore());
|
||||||
for (int i = 0; i < lore.size(); i++) {
|
for (int i = 0; i < lore.size(); i++) {
|
||||||
String s = lore.get(i);
|
String s = lore.get(i);
|
||||||
if(s.contains("%amounut%")){
|
if(s.contains("%amounut%")){
|
||||||
@@ -116,7 +126,10 @@ public class OnlineData {
|
|||||||
|
|
||||||
public void carryOut(Player player){
|
public void carryOut(Player player){
|
||||||
String playerName = player.getName();
|
String playerName = player.getName();
|
||||||
String itemName = this.itemStack.getItemMeta().getDisplayName();
|
String itemName = this.rewardKey;
|
||||||
|
if(!DemonAPI.itemIsNull(this.itemStack) && this.itemStack.getItemMeta() != null && this.itemStack.getItemMeta().hasDisplayName()){
|
||||||
|
itemName = this.itemStack.getItemMeta().getDisplayName();
|
||||||
|
}
|
||||||
for (String cmd : commands) {
|
for (String cmd : commands) {
|
||||||
cmd = cmd.replace("%player%", playerName);
|
cmd = cmd.replace("%player%", playerName);
|
||||||
cmd = cmd.replace("%itemName%", itemName);
|
cmd = cmd.replace("%itemName%", itemName);
|
||||||
|
|||||||
@@ -117,13 +117,13 @@ public class PlayerData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setCurrentReward(){
|
public void setCurrentReward(){
|
||||||
if(this.currentReward.equalsIgnoreCase("MinuteReward_30")){
|
if("MinuteReward_30".equalsIgnoreCase(this.currentReward)){
|
||||||
this.currentReward = "MinuteReward_60";
|
this.currentReward = "MinuteReward_60";
|
||||||
} else if(this.currentReward.equalsIgnoreCase("MinuteReward_60")){
|
} else if("MinuteReward_60".equalsIgnoreCase(this.currentReward)){
|
||||||
this.currentReward = "MinuteReward_120";
|
this.currentReward = "MinuteReward_120";
|
||||||
} else if(this.currentReward.equalsIgnoreCase("MinuteReward_120")){
|
} else if("MinuteReward_120".equalsIgnoreCase(this.currentReward)){
|
||||||
this.currentReward = "MinuteReward_240";
|
this.currentReward = "MinuteReward_240";
|
||||||
} else if(this.currentReward.equalsIgnoreCase("MinuteReward_240")){
|
} else if("MinuteReward_240".equalsIgnoreCase(this.currentReward)){
|
||||||
this.currentReward = "MinuteReward_MAX";
|
this.currentReward = "MinuteReward_MAX";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,8 +20,6 @@ import java.util.HashMap;
|
|||||||
|
|
||||||
public class OnlineGui {
|
public class OnlineGui {
|
||||||
|
|
||||||
private static String invTitle = MessageUtil.getLanguage("Title");
|
|
||||||
|
|
||||||
public static void OpenGui(Player player){
|
public static void OpenGui(Player player){
|
||||||
PlayerManager playerManager = AuOnlineReward.getPlayerManager();
|
PlayerManager playerManager = AuOnlineReward.getPlayerManager();
|
||||||
RefreshData refreshData = DataRefreshUtil.getSetting("OnlineDaily");
|
RefreshData refreshData = DataRefreshUtil.getSetting("OnlineDaily");
|
||||||
@@ -29,7 +27,6 @@ public class OnlineGui {
|
|||||||
refreshData.setRecordTime(System.currentTimeMillis());
|
refreshData.setRecordTime(System.currentTimeMillis());
|
||||||
DataRefreshUtil.SaveRefreshDataRecord(refreshData);
|
DataRefreshUtil.SaveRefreshDataRecord(refreshData);
|
||||||
// 每日数据刷新处理
|
// 每日数据刷新处理
|
||||||
playerManager.clearAllPlayerData();
|
|
||||||
playerManager.refreshLocalPlayerData(TimeType.DAILY);
|
playerManager.refreshLocalPlayerData(TimeType.DAILY);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -40,13 +37,15 @@ public class OnlineGui {
|
|||||||
String playerName = player.getName();
|
String playerName = player.getName();
|
||||||
PlayerData playerData = playerManager.getPlayerData(playerName);
|
PlayerData playerData = playerManager.getPlayerData(playerName);
|
||||||
playerData.updataOnlineData();
|
playerData.updataOnlineData();
|
||||||
Inventory inv = Bukkit.createInventory(null, 36, invTitle);
|
Inventory inv = Bukkit.createInventory(null, 36, MessageUtil.getLanguage("Title"));
|
||||||
inv.setItem(4, StackUtil.showSignStats(playerData));
|
inv.setItem(4, StackUtil.showSignStats(playerData));
|
||||||
HashMap<String,OnlineData> dataMap = Config.getOnlineDataMap();
|
HashMap<String,OnlineData> dataMap = Config.getOnlineDataMap();
|
||||||
for (String key : dataMap.keySet()) {
|
for (String key : dataMap.keySet()) {
|
||||||
OnlineData data = dataMap.get(key);
|
OnlineData data = dataMap.get(key);
|
||||||
|
if(data != null) {
|
||||||
inv.setItem(data.slot,data.getItemStack(playerData));
|
inv.setItem(data.slot,data.getItemStack(playerData));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
player.openInventory(inv);
|
player.openInventory(inv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,15 +29,11 @@ public class GuiClickListener implements Listener {
|
|||||||
this.playerManager = playerManager;
|
this.playerManager = playerManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String invTitle = MessageUtil.getLanguage("Title");
|
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onClick(InventoryClickEvent e){
|
public void onClick(InventoryClickEvent e){
|
||||||
int rawSlot = e.getRawSlot();
|
|
||||||
Player player = (Player) e.getWhoClicked();
|
Player player = (Player) e.getWhoClicked();
|
||||||
String playerName = player.getName();
|
String playerName = player.getName();
|
||||||
Inventory inventory = e.getInventory();
|
if(e.getView().getTitle().equalsIgnoreCase(MessageUtil.getLanguage("Title"))){
|
||||||
if(e.getView().getTitle().equalsIgnoreCase(invTitle)){
|
|
||||||
e.setCancelled(true);
|
e.setCancelled(true);
|
||||||
ItemStack stack = e.getCurrentItem();
|
ItemStack stack = e.getCurrentItem();
|
||||||
if(!DemonAPI.itemIsNull(stack)){
|
if(!DemonAPI.itemIsNull(stack)){
|
||||||
@@ -46,6 +42,10 @@ public class GuiClickListener implements Listener {
|
|||||||
if(nbtItem.hasKey("rewardKey")){
|
if(nbtItem.hasKey("rewardKey")){
|
||||||
String onlineKey = nbtItem.getString("rewardKey");
|
String onlineKey = nbtItem.getString("rewardKey");
|
||||||
OnlineData onlineData = Config.getOnlineData(onlineKey);
|
OnlineData onlineData = Config.getOnlineData(onlineKey);
|
||||||
|
if(onlineData == null){
|
||||||
|
DemonAPI.sendMessage(player,MessageUtil.getLanguage("Not-Available"), Sound.ENTITY_VILLAGER_NO);
|
||||||
|
return;
|
||||||
|
}
|
||||||
// 获取玩家已累积打卡多少次
|
// 获取玩家已累积打卡多少次
|
||||||
int signAmount = playerData.signAmount;
|
int signAmount = playerData.signAmount;
|
||||||
// 获取领取此奖励需要累积领取奖励
|
// 获取领取此奖励需要累积领取奖励
|
||||||
@@ -82,6 +82,10 @@ public class GuiClickListener implements Listener {
|
|||||||
if(nbtItem.hasKey("onlineKey")){
|
if(nbtItem.hasKey("onlineKey")){
|
||||||
String onlineKey = nbtItem.getString("onlineKey");
|
String onlineKey = nbtItem.getString("onlineKey");
|
||||||
OnlineData onlineData = Config.getOnlineData(onlineKey);
|
OnlineData onlineData = Config.getOnlineData(onlineKey);
|
||||||
|
if(onlineData == null){
|
||||||
|
DemonAPI.sendMessage(player,MessageUtil.getLanguage("Not-Available"), Sound.ENTITY_VILLAGER_NO);
|
||||||
|
return;
|
||||||
|
}
|
||||||
// 获取玩家是否已领取该奖励
|
// 获取玩家是否已领取该奖励
|
||||||
if(playerData.isPlayerMinuteRewardExit(onlineKey)){
|
if(playerData.isPlayerMinuteRewardExit(onlineKey)){
|
||||||
DemonAPI.sendMessage(player,MessageUtil.getLanguage("Already-Claimed"), Sound.ENTITY_VILLAGER_NO);
|
DemonAPI.sendMessage(player,MessageUtil.getLanguage("Already-Claimed"), Sound.ENTITY_VILLAGER_NO);
|
||||||
@@ -109,6 +113,7 @@ public class GuiClickListener implements Listener {
|
|||||||
if(onlineTime >= needOnlineTime){
|
if(onlineTime >= needOnlineTime){
|
||||||
// 添加玩家领取印记
|
// 添加玩家领取印记
|
||||||
playerData.signAmount += 1;
|
playerData.signAmount += 1;
|
||||||
|
playerData.totalSignAmount += 1;
|
||||||
playerData.addPlayerMinuteReward(onlineKey);
|
playerData.addPlayerMinuteReward(onlineKey);
|
||||||
// 设置相关参数
|
// 设置相关参数
|
||||||
playerData.setCurrentReward();
|
playerData.setCurrentReward();
|
||||||
@@ -119,6 +124,7 @@ public class GuiClickListener implements Listener {
|
|||||||
}
|
}
|
||||||
// 执行命令并重新打开Gui界面
|
// 执行命令并重新打开Gui界面
|
||||||
onlineData.carryOut(player);
|
onlineData.carryOut(player);
|
||||||
|
playerData.SavePlayerData();
|
||||||
OnlineGui.OpenGui(player);
|
OnlineGui.OpenGui(player);
|
||||||
player.playSound(player.getLocation(),Sound.ENTITY_EXPERIENCE_ORB_PICKUP,1,1);
|
player.playSound(player.getLocation(),Sound.ENTITY_EXPERIENCE_ORB_PICKUP,1,1);
|
||||||
OnlineRewardEvent onlineRewardEvent = new OnlineRewardEvent(player,onlineData);
|
OnlineRewardEvent onlineRewardEvent = new OnlineRewardEvent(player,onlineData);
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
package com.yaohun.onlinereward.manage;
|
package com.yaohun.onlinereward.manage;
|
||||||
|
|
||||||
|
import com.yaohun.onlinereward.AuOnlineReward;
|
||||||
import com.yaohun.onlinereward.data.PlayerData;
|
import com.yaohun.onlinereward.data.PlayerData;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
import org.bukkit.entity.Arrow;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.Map;
|
||||||
|
|
||||||
public class PlayerManager {
|
public class PlayerManager {
|
||||||
|
|
||||||
@@ -41,6 +40,7 @@ public class PlayerManager {
|
|||||||
|
|
||||||
public void clearAllPlayerData(){
|
public void clearAllPlayerData(){
|
||||||
for (PlayerData playerData : playerDataMap.values()){
|
for (PlayerData playerData : playerDataMap.values()){
|
||||||
|
playerData.updataOnlineData();
|
||||||
playerData.SavePlayerData();
|
playerData.SavePlayerData();
|
||||||
}
|
}
|
||||||
playerDataMap.clear();
|
playerDataMap.clear();
|
||||||
@@ -48,12 +48,16 @@ public class PlayerManager {
|
|||||||
|
|
||||||
public void saveAllPlayerData(){
|
public void saveAllPlayerData(){
|
||||||
for (PlayerData playerData : playerDataMap.values()){
|
for (PlayerData playerData : playerDataMap.values()){
|
||||||
|
playerData.updataOnlineData();
|
||||||
playerData.SavePlayerData();
|
playerData.SavePlayerData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removePlayerData(String playerName){
|
public void removePlayerData(String playerName){
|
||||||
getPlayerData(playerName).SavePlayerData();
|
PlayerData playerData = getPlayerData(playerName);
|
||||||
|
playerData.updataOnlineData();
|
||||||
|
playerData.setOfflineTime(System.currentTimeMillis());
|
||||||
|
playerData.SavePlayerData();
|
||||||
playerDataMap.remove(playerName);
|
playerDataMap.remove(playerName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,72 +70,24 @@ public class PlayerManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void refreshLocalPlayerData(TimeType timeType){
|
public void refreshLocalPlayerData(TimeType timeType){
|
||||||
|
saveAllPlayerData();
|
||||||
|
playerDataMap.clear();
|
||||||
String folderPath = "plugins/AuData/AuOnlineReward";
|
String folderPath = "plugins/AuData/AuOnlineReward";
|
||||||
File folder = new File(folderPath);
|
File folder = new File(folderPath);
|
||||||
if (!folder.exists() || !folder.isDirectory()) {
|
if (!folder.exists() || !folder.isDirectory()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
File[] files = folder.listFiles((dir, name) -> name.endsWith(".yml"));
|
Bukkit.getScheduler().runTaskAsynchronously(AuOnlineReward.inst(), () -> {
|
||||||
if (files == null || files.length == 0) {
|
RefreshResult result = refreshLocalPlayerFiles(folder, timeType);
|
||||||
return;
|
Bukkit.getScheduler().runTask(AuOnlineReward.inst(), () -> {
|
||||||
}
|
sendRefreshLog(timeType, result);
|
||||||
long nowTime = System.currentTimeMillis();
|
|
||||||
int count = 0;
|
|
||||||
// 2. 统计玩家今日在线总计时长
|
|
||||||
HashMap<String,Integer> integerHashMap = new HashMap<>();
|
|
||||||
for (File file : files) {
|
|
||||||
String playerName = file.getName().replace(".yml", "");
|
|
||||||
FileConfiguration config = YamlConfiguration.loadConfiguration(file);
|
|
||||||
if(timeType.equals(TimeType.DAILY)){
|
|
||||||
int todayOnline = config.getInt("OnlineData.todayOnline");
|
|
||||||
if(todayOnline >= 600){
|
|
||||||
integerHashMap.put(playerName, todayOnline);
|
|
||||||
}
|
|
||||||
config.set("OnlineData.todayOnline", 0);
|
|
||||||
config.set("OnlineData.currentReward", "MinuteReward_30");
|
|
||||||
config.set("OnlineData.collectionTime", nowTime);
|
|
||||||
config.set("OnlineData.receivedList", new ArrayList<>());
|
|
||||||
try {
|
|
||||||
config.save(file);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
count++;
|
|
||||||
} else if(timeType.equals(TimeType.MONTHLY)){
|
|
||||||
int monthOnline = config.getInt("OnlineData.monthOnline");
|
|
||||||
if(monthOnline >= 600 * 180){
|
|
||||||
integerHashMap.put(playerName, monthOnline);
|
|
||||||
}
|
|
||||||
config.set("OnlineData.monthOnline", 0);
|
|
||||||
try {
|
|
||||||
config.save(file);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(timeType.equals(TimeType.DAILY)) {
|
|
||||||
Bukkit.getConsoleSender().sendMessage("[日志 - 在线福利] 昨日在线时长大于1小时的玩家:");
|
|
||||||
for (String playerName : integerHashMap.keySet()) {
|
|
||||||
int value = integerHashMap.get(playerName);
|
|
||||||
Bukkit.getConsoleSender().sendMessage(" - " + playerName + ": " + (value / 60) + "分钟");
|
|
||||||
}
|
|
||||||
Bukkit.getConsoleSender().sendMessage("[日志 - 在线福利] 每日在线数据已刷新<" + count + "名>玩家数据");
|
|
||||||
}
|
|
||||||
if(timeType.equals(TimeType.MONTHLY)){
|
|
||||||
Bukkit.getConsoleSender().sendMessage("[日志 - 在线福利] 上月在线时长大于180小时的玩家:");
|
|
||||||
for (String playerName : integerHashMap.keySet()) {
|
|
||||||
int value = integerHashMap.get(playerName);
|
|
||||||
Bukkit.getConsoleSender().sendMessage(" - " + playerName + ": " + (value / 600) + "小时");
|
|
||||||
}
|
|
||||||
Bukkit.getConsoleSender().sendMessage("[日志 - 在线福利] 每月在线数据已刷新<" + count + "名>玩家数据");
|
|
||||||
}
|
|
||||||
// 重新载入在线玩家
|
|
||||||
loadOnlineAllPlayer();
|
loadOnlineAllPlayer();
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void refreshLocalPlayerData(String playerName,TimeType timeType){
|
public void refreshLocalPlayerData(String playerName,TimeType timeType){
|
||||||
|
boolean cached = playerDataMap.containsKey(playerName);
|
||||||
PlayerData playerData = getPlayerData(playerName);
|
PlayerData playerData = getPlayerData(playerName);
|
||||||
if(timeType.equals(TimeType.DAILY)) {
|
if(timeType.equals(TimeType.DAILY)) {
|
||||||
playerData.refreshDailyData();
|
playerData.refreshDailyData();
|
||||||
@@ -140,5 +96,78 @@ public class PlayerManager {
|
|||||||
playerData.refreshMonthlyData();
|
playerData.refreshMonthlyData();
|
||||||
playerData.SavePlayerData();
|
playerData.SavePlayerData();
|
||||||
}
|
}
|
||||||
|
if(!cached && Bukkit.getPlayerExact(playerName) == null){
|
||||||
|
playerDataMap.remove(playerName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private RefreshResult refreshLocalPlayerFiles(File folder, TimeType timeType) {
|
||||||
|
File[] files = folder.listFiles((dir, name) -> name.endsWith(".yml"));
|
||||||
|
if (files == null || files.length == 0) {
|
||||||
|
return new RefreshResult(0, new HashMap<>());
|
||||||
|
}
|
||||||
|
long nowTime = System.currentTimeMillis();
|
||||||
|
int count = 0;
|
||||||
|
HashMap<String,Integer> reportMap = new HashMap<>();
|
||||||
|
for (File file : files) {
|
||||||
|
String playerName = file.getName().replace(".yml", "");
|
||||||
|
FileConfiguration config = YamlConfiguration.loadConfiguration(file);
|
||||||
|
if(timeType.equals(TimeType.DAILY)){
|
||||||
|
int todayOnline = config.getInt("OnlineData.todayOnline");
|
||||||
|
if(todayOnline >= 600){
|
||||||
|
reportMap.put(playerName, todayOnline);
|
||||||
|
}
|
||||||
|
config.set("OnlineData.todayOnline", 0);
|
||||||
|
config.set("OnlineData.currentReward", "MinuteReward_30");
|
||||||
|
config.set("OnlineData.collectionTime", nowTime);
|
||||||
|
config.set("OnlineData.receivedList", new ArrayList<>());
|
||||||
|
savePlayerFile(config, file);
|
||||||
|
count++;
|
||||||
|
} else if(timeType.equals(TimeType.MONTHLY)){
|
||||||
|
int monthOnline = config.getInt("OnlineData.monthOnline");
|
||||||
|
if(monthOnline >= 600 * 180){
|
||||||
|
reportMap.put(playerName, monthOnline);
|
||||||
|
}
|
||||||
|
config.set("OnlineData.monthOnline", 0);
|
||||||
|
savePlayerFile(config, file);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new RefreshResult(count, reportMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void savePlayerFile(FileConfiguration config, File file) {
|
||||||
|
try {
|
||||||
|
config.save(file);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendRefreshLog(TimeType timeType, RefreshResult result) {
|
||||||
|
if(timeType.equals(TimeType.DAILY)) {
|
||||||
|
Bukkit.getConsoleSender().sendMessage("[日志 - 在线福利] 昨日在线时长大于1小时的玩家:");
|
||||||
|
for (Map.Entry<String, Integer> entry : result.reportMap.entrySet()) {
|
||||||
|
Bukkit.getConsoleSender().sendMessage(" - " + entry.getKey() + ": " + (entry.getValue() / 60) + "分钟");
|
||||||
|
}
|
||||||
|
Bukkit.getConsoleSender().sendMessage("[日志 - 在线福利] 每日在线数据已刷新<" + result.count + "名>玩家数据");
|
||||||
|
}
|
||||||
|
if(timeType.equals(TimeType.MONTHLY)){
|
||||||
|
Bukkit.getConsoleSender().sendMessage("[日志 - 在线福利] 上月在线时长大于180小时的玩家:");
|
||||||
|
for (Map.Entry<String, Integer> entry : result.reportMap.entrySet()) {
|
||||||
|
Bukkit.getConsoleSender().sendMessage(" - " + entry.getKey() + ": " + (entry.getValue() / 600) + "小时");
|
||||||
|
}
|
||||||
|
Bukkit.getConsoleSender().sendMessage("[日志 - 在线福利] 每月在线数据已刷新<" + result.count + "名>玩家数据");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class RefreshResult {
|
||||||
|
private final int count;
|
||||||
|
private final HashMap<String, Integer> reportMap;
|
||||||
|
|
||||||
|
private RefreshResult(int count, HashMap<String, Integer> reportMap) {
|
||||||
|
this.count = count;
|
||||||
|
this.reportMap = reportMap;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ public class MessageUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void init(AuOnlineReward plugin) {
|
public static void init(AuOnlineReward plugin) {
|
||||||
|
languageMap.clear();
|
||||||
File file = new File(plugin.getDataFolder(), "language.yml");
|
File file = new File(plugin.getDataFolder(), "language.yml");
|
||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
plugin.saveResource("language.yml", false);
|
plugin.saveResource("language.yml", false);
|
||||||
@@ -27,8 +28,11 @@ public class MessageUtil {
|
|||||||
FileConfiguration config = YamlConfiguration.loadConfiguration(file);
|
FileConfiguration config = YamlConfiguration.loadConfiguration(file);
|
||||||
for (String key : config.getKeys(false)){
|
for (String key : config.getKeys(false)){
|
||||||
ConfigurationSection section = config.getConfigurationSection(key);
|
ConfigurationSection section = config.getConfigurationSection(key);
|
||||||
|
if(section == null){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
for (String key2 : section.getKeys(false)){
|
for (String key2 : section.getKeys(false)){
|
||||||
String message = section.getString(key2).replace("&","§");
|
String message = section.getString(key2,"").replace("&","§");
|
||||||
languageMap.put(key2,message);
|
languageMap.put(key2,message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
name: AuOnlineReward
|
name: AuOnlineReward
|
||||||
main: com.yaohun.onlinereward.AuOnlineReward
|
main: com.yaohun.onlinereward.AuOnlineReward
|
||||||
version: 1.8.0
|
version: 1.8.3
|
||||||
depend:
|
depend:
|
||||||
- DemonAPI
|
- DemonAPI
|
||||||
commands:
|
commands:
|
||||||
|
|||||||
604
使用手册.md
Normal file
604
使用手册.md
Normal file
@@ -0,0 +1,604 @@
|
|||||||
|
# 1.AuOnlineReward 是什么?
|
||||||
|
|
||||||
|
AuOnlineReward 是一个 Minecraft 1.12.2 Bukkit / Spigot 在线奖励插件。
|
||||||
|
|
||||||
|
它用于根据玩家在线时间发放阶段奖励,并根据阶段奖励领取次数解锁累积奖励。
|
||||||
|
|
||||||
|
核心功能:
|
||||||
|
|
||||||
|
- 玩家通过 GUI 查看在线信息和奖励状态
|
||||||
|
- 支持每日在线阶段奖励
|
||||||
|
- 支持累积领取次数奖励
|
||||||
|
- 支持每日在线数据刷新
|
||||||
|
- 支持月度在线数据刷新
|
||||||
|
- 支持配置奖励物品和奖励命令
|
||||||
|
- 支持通过 API 获取玩家在线时间
|
||||||
|
- 支持奖励领取事件,方便其他插件监听
|
||||||
|
|
||||||
|
简单理解:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
AuOnlineReward = 在线时长统计 + 在线奖励 GUI + 奖励命令执行
|
||||||
|
玩家 = 在线积累时间并领取奖励
|
||||||
|
管理员 = 配置奖励物品、奖励条件和发奖命令
|
||||||
|
```
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
# 2.运行环境
|
||||||
|
|
||||||
|
## 服务端版本
|
||||||
|
|
||||||
|
```yml
|
||||||
|
Minecraft: 1.12.2
|
||||||
|
服务端: Bukkit / Spigot / Paper
|
||||||
|
Java: 8
|
||||||
|
```
|
||||||
|
|
||||||
|
## 前置插件
|
||||||
|
|
||||||
|
AuOnlineReward 依赖 DemonAPI。
|
||||||
|
|
||||||
|
`plugin.yml` 中已经声明:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
depend:
|
||||||
|
- DemonAPI
|
||||||
|
```
|
||||||
|
|
||||||
|
服务器启动前必须确保 DemonAPI 已放入插件目录。
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
# 3.安装方式
|
||||||
|
|
||||||
|
## 第一步:放入插件
|
||||||
|
|
||||||
|
将插件 jar 放入服务器插件目录:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
plugins/AuOnlineReward.jar
|
||||||
|
```
|
||||||
|
|
||||||
|
同时放入前置插件:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
plugins/DemonAPI.jar
|
||||||
|
```
|
||||||
|
|
||||||
|
## 第二步:启动服务器
|
||||||
|
|
||||||
|
首次启动后会生成插件配置文件。
|
||||||
|
|
||||||
|
## 第三步:检查加载
|
||||||
|
|
||||||
|
控制台应能看到插件正常启用,没有缺少 DemonAPI 的报错。
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
# 4.目录结构
|
||||||
|
|
||||||
|
## 插件配置目录
|
||||||
|
|
||||||
|
默认配置和语言文件位于:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
plugins/AuOnlineReward/config.yml
|
||||||
|
plugins/AuOnlineReward/language.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
## 玩家数据目录
|
||||||
|
|
||||||
|
玩家在线数据会保存到:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
plugins/AuData/AuOnlineReward/玩家名.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
玩家数据示例:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
OnlineData:
|
||||||
|
todayOnline: 0
|
||||||
|
totalOnline: 0
|
||||||
|
monthOnline: 0
|
||||||
|
totalSign: 0
|
||||||
|
signAmount: 0
|
||||||
|
currentReward: MinuteReward_30
|
||||||
|
collectionTime: 1717200000000
|
||||||
|
offlineTime: 1717200000000
|
||||||
|
receivedList: []
|
||||||
|
permanentReceived: []
|
||||||
|
```
|
||||||
|
|
||||||
|
字段说明:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
todayOnline: 今日在线秒数
|
||||||
|
totalOnline: 累积在线秒数
|
||||||
|
monthOnline: 本月在线秒数
|
||||||
|
totalSign: 总计领取阶段奖励次数
|
||||||
|
signAmount: 当前轮累积领取阶段奖励次数
|
||||||
|
currentReward: 当前可领取的阶段奖励
|
||||||
|
collectionTime: 上次阶段奖励领取时间
|
||||||
|
offlineTime: 上次离线时间
|
||||||
|
receivedList: 今日已领取阶段奖励
|
||||||
|
permanentReceived: 当前轮已领取累积奖励
|
||||||
|
```
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
# 5.玩家命令
|
||||||
|
|
||||||
|
## 打开在线奖励界面
|
||||||
|
|
||||||
|
```yml
|
||||||
|
/auonline open
|
||||||
|
```
|
||||||
|
|
||||||
|
玩家执行后会打开在线福利 GUI。
|
||||||
|
|
||||||
|
GUI 中会显示:
|
||||||
|
|
||||||
|
- 累积在线时间
|
||||||
|
- 本月在线时间
|
||||||
|
- 今日在线时间
|
||||||
|
- 总计领取奖励次数
|
||||||
|
- 阶段奖励状态
|
||||||
|
- 累积奖励状态
|
||||||
|
|
||||||
|
注意:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
每日 00:10 前无法打开 GUI
|
||||||
|
这是为了避免跨日数据刷新期间领取状态异常
|
||||||
|
```
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
# 6.管理员命令
|
||||||
|
|
||||||
|
管理员命令需要 OP 权限。
|
||||||
|
|
||||||
|
## 查看命令帮助
|
||||||
|
|
||||||
|
```yml
|
||||||
|
/auonline
|
||||||
|
```
|
||||||
|
|
||||||
|
## 重载配置
|
||||||
|
|
||||||
|
```yml
|
||||||
|
/auonline reload
|
||||||
|
```
|
||||||
|
|
||||||
|
重载内容:
|
||||||
|
|
||||||
|
- 奖励配置
|
||||||
|
- 语言配置
|
||||||
|
- GUI 标题
|
||||||
|
- 奖励显示文本
|
||||||
|
|
||||||
|
## 刷新所有玩家每日数据
|
||||||
|
|
||||||
|
```yml
|
||||||
|
/auonline dayrefresh
|
||||||
|
```
|
||||||
|
|
||||||
|
作用:
|
||||||
|
|
||||||
|
- 清空今日在线时间
|
||||||
|
- 重置当前阶段奖励
|
||||||
|
- 重置今日阶段奖励领取记录
|
||||||
|
- 重新载入在线玩家数据
|
||||||
|
|
||||||
|
## 刷新指定玩家每日数据
|
||||||
|
|
||||||
|
```yml
|
||||||
|
/auonline dayrefresh 玩家名
|
||||||
|
```
|
||||||
|
|
||||||
|
只刷新指定玩家的每日在线奖励数据。
|
||||||
|
|
||||||
|
## 查看玩家数据
|
||||||
|
|
||||||
|
```yml
|
||||||
|
/auonline info 玩家名
|
||||||
|
/auonline look 玩家名
|
||||||
|
```
|
||||||
|
|
||||||
|
不填写玩家名时,默认查看执行者自己的数据。
|
||||||
|
|
||||||
|
## 查看今日在线排行
|
||||||
|
|
||||||
|
```yml
|
||||||
|
/auonline topDay
|
||||||
|
/auonline top
|
||||||
|
```
|
||||||
|
|
||||||
|
显示当前已缓存玩家的今日在线排行。
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
# 7.奖励类型
|
||||||
|
|
||||||
|
AuOnlineReward 当前包含两类奖励。
|
||||||
|
|
||||||
|
## 阶段奖励
|
||||||
|
|
||||||
|
配置节点通常以 `MinuteReward_` 开头。
|
||||||
|
|
||||||
|
示例:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
RewardData:
|
||||||
|
MinuteReward_30:
|
||||||
|
slot: 10
|
||||||
|
needOnline: 1800
|
||||||
|
needOnlineTime: 1800
|
||||||
|
itemStack:
|
||||||
|
==: org.bukkit.inventory.ItemStack
|
||||||
|
type: IRON_INGOT
|
||||||
|
commands:
|
||||||
|
- eco give %player% 500
|
||||||
|
```
|
||||||
|
|
||||||
|
字段说明:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
slot: GUI 中的格子位置
|
||||||
|
needOnline: 距离上次阶段奖励领取需要等待的秒数
|
||||||
|
needOnlineTime: 今日在线秒数要求
|
||||||
|
itemStack: GUI 中展示的奖励物品
|
||||||
|
commands: 领取后执行的命令
|
||||||
|
```
|
||||||
|
|
||||||
|
阶段奖励领取成功后:
|
||||||
|
|
||||||
|
- 增加当前轮阶段领取次数
|
||||||
|
- 增加总计阶段领取次数
|
||||||
|
- 写入今日已领取记录
|
||||||
|
- 切换到下一个阶段奖励
|
||||||
|
- 执行奖励命令
|
||||||
|
- 保存玩家数据
|
||||||
|
|
||||||
|
## 累积奖励
|
||||||
|
|
||||||
|
配置节点通常以 `SignReward_` 开头。
|
||||||
|
|
||||||
|
示例:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
RewardData:
|
||||||
|
SignReward_15:
|
||||||
|
slot: 29
|
||||||
|
needOnline: 25
|
||||||
|
itemStack:
|
||||||
|
==: org.bukkit.inventory.ItemStack
|
||||||
|
type: CHEST
|
||||||
|
commands:
|
||||||
|
- eco give %player% 10000
|
||||||
|
```
|
||||||
|
|
||||||
|
字段说明:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
slot: GUI 中的格子位置
|
||||||
|
needOnline: 需要累计领取多少次阶段奖励
|
||||||
|
itemStack: GUI 中展示的奖励物品
|
||||||
|
commands: 领取后执行的命令
|
||||||
|
```
|
||||||
|
|
||||||
|
累积奖励领取成功后会写入 `permanentReceived`。
|
||||||
|
|
||||||
|
当领取 `SignReward_Max` 后:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
signAmount 会重置为 0
|
||||||
|
permanentReceived 会清空
|
||||||
|
进入下一轮累积奖励
|
||||||
|
```
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
# 8.奖励命令怎么写?
|
||||||
|
|
||||||
|
奖励命令写在 `commands` 列表中。
|
||||||
|
|
||||||
|
示例:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
commands:
|
||||||
|
- eco give %player% 500
|
||||||
|
- points give %player% 10
|
||||||
|
- bcm &a玩家 &e%player% &a领取了在线奖励
|
||||||
|
```
|
||||||
|
|
||||||
|
支持占位符:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
%player% 玩家名
|
||||||
|
%itemName% 奖励物品显示名
|
||||||
|
```
|
||||||
|
|
||||||
|
如果命令包含 `msg:`,会向玩家发送消息,而不是由控制台执行命令。
|
||||||
|
|
||||||
|
示例:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
commands:
|
||||||
|
- "msg:&a你领取了在线奖励"
|
||||||
|
```
|
||||||
|
|
||||||
|
颜色代码支持:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
&a &b &c &e &f
|
||||||
|
```
|
||||||
|
|
||||||
|
插件执行时会转换为 Minecraft 颜色符号。
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
# 9.语言文件怎么写?
|
||||||
|
|
||||||
|
语言文件为:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
plugins/AuOnlineReward/language.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
主要节点:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
Online-Gui:
|
||||||
|
Title: "§r日常福利 - 累积在线豪礼相赠"
|
||||||
|
Received: "§a§l★ §7领取状态: §a已领取"
|
||||||
|
Not-Started: "§c§l★ §7领取状态: §c未开始"
|
||||||
|
Pending: "§b§l★ §7领取状态: §b待领取"
|
||||||
|
Total-Online: "§7累积在线: §a%time%"
|
||||||
|
Monthly-Online: "§7本月在线: §a%time%"
|
||||||
|
Daily-Online: "§7今日在线: §a%time%"
|
||||||
|
Total-Rewards: "§7总计领取奖励: §a%amount%次"
|
||||||
|
Message:
|
||||||
|
Reward-Progress: "你还需要获取§e[%amount%次]§a阶段奖励才能领取奖励。"
|
||||||
|
Wait-Time: "您还需要等待§e[%time%秒]§a才能领取该奖励。"
|
||||||
|
Daily-Requirement: "你需要今日在线§e[%time%秒]§a才能领取该奖励。"
|
||||||
|
Already-Claimed: "你已经领取过这个累积奖励。"
|
||||||
|
Not-Available: "这个阶段奖励尚未开启,暂时无法领取。"
|
||||||
|
```
|
||||||
|
|
||||||
|
修改语言文件后执行:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
/auonline reload
|
||||||
|
```
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
# 10.在线时间刷新机制
|
||||||
|
|
||||||
|
## 在线计时
|
||||||
|
|
||||||
|
插件会定时统计在线玩家的在线时长。
|
||||||
|
|
||||||
|
统计字段:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
todayOnline: 今日在线
|
||||||
|
monthOnline: 本月在线
|
||||||
|
totalOnline: 累积在线
|
||||||
|
```
|
||||||
|
|
||||||
|
玩家退出时会补算最后一段在线时间,并保存玩家数据。
|
||||||
|
|
||||||
|
## 每日刷新
|
||||||
|
|
||||||
|
每日刷新会处理:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
todayOnline = 0
|
||||||
|
currentReward = MinuteReward_30
|
||||||
|
receivedList = []
|
||||||
|
collectionTime = 当前时间
|
||||||
|
```
|
||||||
|
|
||||||
|
## 月度刷新
|
||||||
|
|
||||||
|
月度刷新会处理:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
monthOnline = 0
|
||||||
|
```
|
||||||
|
|
||||||
|
## 刷新性能说明
|
||||||
|
|
||||||
|
批量刷新玩家文件时,插件会将 YAML 文件读写放到异步任务中执行。
|
||||||
|
|
||||||
|
刷新完成后,再回到主线程重新载入在线玩家。
|
||||||
|
|
||||||
|
这样可以降低大量玩家数据文件刷新时对主线程的影响。
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
# 11.API 调用
|
||||||
|
|
||||||
|
其他插件可以通过 `OnlineAPI` 获取玩家在线时间。
|
||||||
|
|
||||||
|
## 获取今日在线分钟数
|
||||||
|
|
||||||
|
```java
|
||||||
|
int minutes = OnlineAPI.getTime(playerName);
|
||||||
|
```
|
||||||
|
|
||||||
|
## 获取本月在线分钟数
|
||||||
|
|
||||||
|
```java
|
||||||
|
int minutes = OnlineAPI.getTimeMonth(playerName);
|
||||||
|
```
|
||||||
|
|
||||||
|
## 获取累积在线分钟数
|
||||||
|
|
||||||
|
```java
|
||||||
|
int minutes = OnlineAPI.getTimeTotal(playerName);
|
||||||
|
```
|
||||||
|
|
||||||
|
注意:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
API 返回单位是分钟
|
||||||
|
底层玩家数据保存单位是秒
|
||||||
|
```
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
# 12.事件监听
|
||||||
|
|
||||||
|
玩家成功领取奖励后会触发:
|
||||||
|
|
||||||
|
```java
|
||||||
|
OnlineRewardEvent
|
||||||
|
```
|
||||||
|
|
||||||
|
监听示例:
|
||||||
|
|
||||||
|
```java
|
||||||
|
@EventHandler
|
||||||
|
public void onOnlineReward(OnlineRewardEvent event) {
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
String playerName = event.getPlayerName();
|
||||||
|
String rewardKey = event.getOnlineData().getRewardKey();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
事件可用于:
|
||||||
|
|
||||||
|
- 记录领奖日志
|
||||||
|
- 触发额外奖励
|
||||||
|
- 接入活动系统
|
||||||
|
- 接入统计系统
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
# 13.配置示例
|
||||||
|
|
||||||
|
## 阶段奖励示例
|
||||||
|
|
||||||
|
```yml
|
||||||
|
RewardData:
|
||||||
|
MinuteReward_30:
|
||||||
|
slot: 10
|
||||||
|
needOnline: 1800
|
||||||
|
needOnlineTime: 1800
|
||||||
|
itemStack:
|
||||||
|
==: org.bukkit.inventory.ItemStack
|
||||||
|
type: IRON_INGOT
|
||||||
|
meta:
|
||||||
|
==: ItemMeta
|
||||||
|
meta-type: UNSPECIFIC
|
||||||
|
display-name: §6§l阶段奖励 I
|
||||||
|
lore:
|
||||||
|
- §7还差 §c%time% §7才能领取
|
||||||
|
- §e金币 §e*500
|
||||||
|
commands:
|
||||||
|
- eco give %player% 500
|
||||||
|
```
|
||||||
|
|
||||||
|
## 累积奖励示例
|
||||||
|
|
||||||
|
```yml
|
||||||
|
RewardData:
|
||||||
|
SignReward_15:
|
||||||
|
slot: 29
|
||||||
|
needOnline: 25
|
||||||
|
itemStack:
|
||||||
|
==: org.bukkit.inventory.ItemStack
|
||||||
|
type: CHEST
|
||||||
|
meta:
|
||||||
|
==: ItemMeta
|
||||||
|
meta-type: TILE_ENTITY
|
||||||
|
display-name: §6§l累积打卡奖励 I
|
||||||
|
lore:
|
||||||
|
- §7还需领取 §c%amounut% §7阶段奖励
|
||||||
|
- §e金币 §e*10000
|
||||||
|
commands:
|
||||||
|
- eco give %player% 10000
|
||||||
|
```
|
||||||
|
|
||||||
|
注意:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
阶段奖励 lore 中需要包含 %time%
|
||||||
|
累积奖励 lore 中需要包含 %amounut%
|
||||||
|
```
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
# 14.常见问题
|
||||||
|
|
||||||
|
## 执行 /auonline open 没反应
|
||||||
|
|
||||||
|
检查:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
是否在每日 00:10 之前
|
||||||
|
DemonAPI 是否正常加载
|
||||||
|
language.yml 中 Title 是否存在
|
||||||
|
config.yml 中 RewardData 是否存在
|
||||||
|
```
|
||||||
|
|
||||||
|
## 奖励无法领取
|
||||||
|
|
||||||
|
检查:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
今日在线秒数是否达到 needOnlineTime
|
||||||
|
距离上次领取是否达到 needOnline
|
||||||
|
currentReward 是否等于当前点击的阶段奖励
|
||||||
|
该奖励是否已经在 receivedList 中
|
||||||
|
```
|
||||||
|
|
||||||
|
## 累积奖励无法领取
|
||||||
|
|
||||||
|
检查:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
signAmount 是否达到 needOnline
|
||||||
|
该奖励是否已经在 permanentReceived 中
|
||||||
|
```
|
||||||
|
|
||||||
|
## 修改配置后没有变化
|
||||||
|
|
||||||
|
执行:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
/auonline reload
|
||||||
|
```
|
||||||
|
|
||||||
|
如果删除了奖励节点,重载后旧奖励缓存会被清理。
|
||||||
|
|
||||||
|
## 玩家数据异常
|
||||||
|
|
||||||
|
可以刷新指定玩家每日数据:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
/auonline dayrefresh 玩家名
|
||||||
|
```
|
||||||
|
|
||||||
|
也可以检查玩家数据文件:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
plugins/AuData/AuOnlineReward/玩家名.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
# 15.维护建议
|
||||||
|
|
||||||
|
- 修改奖励配置前,先备份 `config.yml`。
|
||||||
|
- 大量玩家数据刷新建议避开服务器高峰期。
|
||||||
|
- 奖励命令应先在测试服验证,避免命令拼写错误导致奖励无法发放。
|
||||||
|
- 不建议把高耗时命令放入奖励命令列表。
|
||||||
|
- 修改语言或奖励配置后,使用 `/auonline reload` 重载。
|
||||||
|
- 发布新版本时,应同步检查 `plugin.yml` 的版本号。
|
||||||
|
- 每次更新后建议至少完成一次登录、打开 GUI、领取奖励、退出保存的冒烟测试。
|
||||||
459
使用手册案例.md
Normal file
459
使用手册案例.md
Normal file
@@ -0,0 +1,459 @@
|
|||||||
|
<<<<<<< HEAD
|
||||||
|
# 1.LangUtil 是什么?
|
||||||
|
|
||||||
|
LangUtil 是一个 Minecraft 1.12.2 Bukkit / Spigot 多语言管理插件。
|
||||||
|
|
||||||
|
它的作用不是替代业务插件,而是给其他插件提供统一的语言 API:
|
||||||
|
|
||||||
|
- 每个插件维护自己的语言文件
|
||||||
|
- 玩家可以切换自己的语言
|
||||||
|
- 不同玩家可以看到不同语言
|
||||||
|
- 修改语言文件后可以不重启服务器直接重载
|
||||||
|
- 支持物品名称、物品 lore、普通消息、占位符和颜色代码
|
||||||
|
|
||||||
|
简单理解:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
LangUtil = 公共语言管理器
|
||||||
|
其他插件 = 自己提供 lang 文件
|
||||||
|
玩家 = 自己选择 zh_CN / en_US 等语言
|
||||||
|
```
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
# 2.目录结构
|
||||||
|
|
||||||
|
## LangUtil 自己的数据
|
||||||
|
|
||||||
|
玩家语言选择会保存到:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
plugins/LangUtil/player-language.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
格式示例:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
player-language:
|
||||||
|
550e8400-e29b-41d4-a716-446655440000: zh_CN
|
||||||
|
```
|
||||||
|
|
||||||
|
## 其他插件的语言文件
|
||||||
|
|
||||||
|
其他插件必须把语言文件放在自己的插件目录下:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
plugins/OtherPlugin/lang/zh_CN.yml
|
||||||
|
plugins/OtherPlugin/lang/en_US.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
注意:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
语言文件不是放在 LangUtil 的 lang 目录
|
||||||
|
语言文件是放在调用 register 的插件自己的 lang 目录
|
||||||
|
```
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
# 3.其他插件如何注册?
|
||||||
|
|
||||||
|
其他插件需要依赖 LangUtil。
|
||||||
|
|
||||||
|
## plugin.yml
|
||||||
|
|
||||||
|
```yml
|
||||||
|
depend:
|
||||||
|
- LangUtil
|
||||||
|
```
|
||||||
|
|
||||||
|
## 插件入口
|
||||||
|
|
||||||
|
```java
|
||||||
|
import com.io.yaohun.langutil.LangUtil;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
|
public final class OtherPlugin extends JavaPlugin {
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
LangUtil.register(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
当执行:
|
||||||
|
|
||||||
|
```java
|
||||||
|
LangUtil.register(this);
|
||||||
|
```
|
||||||
|
|
||||||
|
LangUtil 会读取:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
plugins/OtherPlugin/lang/*.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
# 4.语言文件怎么写?
|
||||||
|
|
||||||
|
## zh_CN.yml
|
||||||
|
|
||||||
|
```yml
|
||||||
|
message:
|
||||||
|
reload: "&a语言文件已重载"
|
||||||
|
no-permission: "&c你没有权限使用该命令。"
|
||||||
|
|
||||||
|
item:
|
||||||
|
flame-sword:
|
||||||
|
name: "&c烈焰长剑"
|
||||||
|
lore:
|
||||||
|
- "&7伤害: &c{damage}"
|
||||||
|
- "&7品质: &6{quality}"
|
||||||
|
- ""
|
||||||
|
- "&e右键释放火焰"
|
||||||
|
```
|
||||||
|
|
||||||
|
## en_US.yml
|
||||||
|
|
||||||
|
```yml
|
||||||
|
message:
|
||||||
|
reload: "&aLanguage files reloaded"
|
||||||
|
no-permission: "&cYou do not have permission."
|
||||||
|
|
||||||
|
item:
|
||||||
|
flame-sword:
|
||||||
|
name: "&cFlame Sword"
|
||||||
|
lore:
|
||||||
|
- "&7Damage: &c{damage}"
|
||||||
|
- "&7Quality: &6{quality}"
|
||||||
|
- ""
|
||||||
|
- "&eRight-click to release fire"
|
||||||
|
```
|
||||||
|
|
||||||
|
文件名就是语言 ID:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
zh_CN.yml → zh_CN
|
||||||
|
en_US.yml → en_US
|
||||||
|
```
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
# 5.玩家命令
|
||||||
|
|
||||||
|
## 查看可用语言
|
||||||
|
|
||||||
|
```yml
|
||||||
|
/lang
|
||||||
|
```
|
||||||
|
|
||||||
|
玩家会看到当前已经加载的语言 ID。
|
||||||
|
|
||||||
|
## 切换语言
|
||||||
|
|
||||||
|
```yml
|
||||||
|
/lang zh_CN
|
||||||
|
/lang en_US
|
||||||
|
```
|
||||||
|
|
||||||
|
切换后会按玩家 UUID 保存。
|
||||||
|
|
||||||
|
玩家退出服务器再进入,仍然保持上次选择。
|
||||||
|
|
||||||
|
## 重载语言文件
|
||||||
|
|
||||||
|
```yml
|
||||||
|
/lang reload
|
||||||
|
```
|
||||||
|
|
||||||
|
修改语言文件后,不需要重启服务器,执行该命令即可重新读取所有已注册插件的语言文件。
|
||||||
|
|
||||||
|
控制台也可以执行:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
lang reload
|
||||||
|
```
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
# 6.权限节点
|
||||||
|
|
||||||
|
```yml
|
||||||
|
langutil.use # 允许玩家使用 /lang 查看和切换语言
|
||||||
|
langutil.reload # 允许使用 /lang reload
|
||||||
|
```
|
||||||
|
|
||||||
|
推荐配置:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
普通玩家: langutil.use
|
||||||
|
管理员: langutil.use + langutil.reload
|
||||||
|
```
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
# 7.API 调用
|
||||||
|
|
||||||
|
## 获取普通消息
|
||||||
|
|
||||||
|
```java
|
||||||
|
String message = LangUtil.get(player, this, "message.reload");
|
||||||
|
```
|
||||||
|
|
||||||
|
## 发送普通消息
|
||||||
|
|
||||||
|
```java
|
||||||
|
LangUtil.send(player, this, "message.reload");
|
||||||
|
```
|
||||||
|
|
||||||
|
## 发送消息并播放音效
|
||||||
|
|
||||||
|
```java
|
||||||
|
LangUtil.send(player, this, "message.reload", Sound.LEVEL_UP);
|
||||||
|
```
|
||||||
|
|
||||||
|
## 使用占位符
|
||||||
|
|
||||||
|
```java
|
||||||
|
Map<String, String> placeholders = new HashMap<String, String>();
|
||||||
|
placeholders.put("damage", "12");
|
||||||
|
placeholders.put("quality", "史诗");
|
||||||
|
|
||||||
|
String name = LangUtil.get(player, this, "item.flame-sword.name", placeholders);
|
||||||
|
```
|
||||||
|
|
||||||
|
语言文件:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
item:
|
||||||
|
flame-sword:
|
||||||
|
name: "&c烈焰长剑"
|
||||||
|
```
|
||||||
|
|
||||||
|
结果:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
烈焰长剑
|
||||||
|
```
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
# 8.物品 name 和 lore 怎么做?
|
||||||
|
|
||||||
|
物品 name 是字符串,可以用:
|
||||||
|
|
||||||
|
```java
|
||||||
|
LangUtil.get(player, this, "item.flame-sword.name", placeholders);
|
||||||
|
```
|
||||||
|
|
||||||
|
物品 lore 是 List,可以用:
|
||||||
|
|
||||||
|
```java
|
||||||
|
LangUtil.getList(player, this, "item.flame-sword.lore", placeholders);
|
||||||
|
```
|
||||||
|
|
||||||
|
完整示例:
|
||||||
|
|
||||||
|
```java
|
||||||
|
Map<String, String> placeholders = new HashMap<String, String>();
|
||||||
|
placeholders.put("damage", "12");
|
||||||
|
placeholders.put("quality", "史诗");
|
||||||
|
|
||||||
|
ItemMeta meta = item.getItemMeta();
|
||||||
|
meta.setDisplayName(LangUtil.get(player, this, "item.flame-sword.name", placeholders));
|
||||||
|
meta.setLore(LangUtil.getList(player, this, "item.flame-sword.lore", placeholders));
|
||||||
|
item.setItemMeta(meta);
|
||||||
|
```
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
# 9.推荐封装方式
|
||||||
|
|
||||||
|
为了让业务代码更短,其他插件可以自己封装一个 `Lang` 工具类。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public final class Lang {
|
||||||
|
private static JavaPlugin plugin;
|
||||||
|
|
||||||
|
private Lang() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void init(JavaPlugin javaPlugin) {
|
||||||
|
plugin = javaPlugin;
|
||||||
|
LangUtil.register(javaPlugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void send(CommandSender sender, String path) {
|
||||||
|
LangUtil.send(sender, plugin, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String get(CommandSender sender, String path) {
|
||||||
|
return LangUtil.get(sender, plugin, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<String> getList(CommandSender sender, String path) {
|
||||||
|
return LangUtil.getList(sender, plugin, path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
插件启动时:
|
||||||
|
|
||||||
|
```java
|
||||||
|
Lang.init(this);
|
||||||
|
```
|
||||||
|
|
||||||
|
业务代码:
|
||||||
|
|
||||||
|
```java
|
||||||
|
Lang.send(player, "message.reload");
|
||||||
|
```
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
# 10.重载机制说明
|
||||||
|
|
||||||
|
LangUtil 不会每次发送消息都读取本地 YAML。
|
||||||
|
|
||||||
|
语言文件读取时机:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
插件启动 register 时
|
||||||
|
/lang reload 时
|
||||||
|
再次调用 register 时
|
||||||
|
```
|
||||||
|
|
||||||
|
平时调用:
|
||||||
|
|
||||||
|
```java
|
||||||
|
LangUtil.get(...)
|
||||||
|
LangUtil.getList(...)
|
||||||
|
LangUtil.send(...)
|
||||||
|
```
|
||||||
|
|
||||||
|
都是从内存缓存读取。
|
||||||
|
|
||||||
|
这样可以避免每次发消息都读磁盘,降低主线程压力。
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
# 11.异常与回退规则
|
||||||
|
|
||||||
|
## 玩家没有选择语言
|
||||||
|
|
||||||
|
默认使用:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
zh_CN
|
||||||
|
```
|
||||||
|
|
||||||
|
## 玩家选择的语言文件不存在
|
||||||
|
|
||||||
|
回退:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
zh_CN
|
||||||
|
```
|
||||||
|
|
||||||
|
## zh_CN 也不存在
|
||||||
|
|
||||||
|
返回 path 原文:
|
||||||
|
|
||||||
|
```java
|
||||||
|
LangUtil.get(player, this, "message.not-found");
|
||||||
|
```
|
||||||
|
|
||||||
|
返回:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
message.not-found
|
||||||
|
```
|
||||||
|
|
||||||
|
## lore 不存在
|
||||||
|
|
||||||
|
返回单行 List:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
- item.xxx.lore
|
||||||
|
```
|
||||||
|
|
||||||
|
## YAML 格式错误
|
||||||
|
|
||||||
|
控制台会输出:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
插件名
|
||||||
|
语言文件名
|
||||||
|
错误原因
|
||||||
|
```
|
||||||
|
|
||||||
|
不会因为单个语言文件错误导致服务器关闭。
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
# 12.实战使用流程
|
||||||
|
|
||||||
|
## 第一步:安装 LangUtil
|
||||||
|
|
||||||
|
把插件放入服务器:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
plugins/LangUtil-1.2.0.jar
|
||||||
|
```
|
||||||
|
|
||||||
|
启动服务器。
|
||||||
|
|
||||||
|
## 第二步:业务插件依赖 LangUtil
|
||||||
|
|
||||||
|
```yml
|
||||||
|
depend:
|
||||||
|
- LangUtil
|
||||||
|
```
|
||||||
|
|
||||||
|
## 第三步:业务插件注册语言文件
|
||||||
|
|
||||||
|
```java
|
||||||
|
LangUtil.register(this);
|
||||||
|
```
|
||||||
|
|
||||||
|
## 第四步:创建语言文件
|
||||||
|
|
||||||
|
```yml
|
||||||
|
plugins/OtherPlugin/lang/zh_CN.yml
|
||||||
|
plugins/OtherPlugin/lang/en_US.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
## 第五步:玩家切换语言
|
||||||
|
|
||||||
|
```yml
|
||||||
|
/lang zh_CN
|
||||||
|
/lang en_US
|
||||||
|
```
|
||||||
|
|
||||||
|
## 第六步:业务插件发送消息
|
||||||
|
|
||||||
|
```java
|
||||||
|
LangUtil.send(player, this, "message.reload");
|
||||||
|
```
|
||||||
|
|
||||||
|
## 第七步:修改语言后重载
|
||||||
|
|
||||||
|
```yml
|
||||||
|
/lang reload
|
||||||
|
```
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
# 13.注意事项
|
||||||
|
|
||||||
|
- 推荐始终使用带 `JavaPlugin plugin` 参数的 API。
|
||||||
|
- 不推荐使用 `LangUtil.get(String path)`,因为它无法稳定判断读取哪个插件的语言。
|
||||||
|
- 其他插件必须先调用 `LangUtil.register(this)`,否则读取不到自己的语言文件。
|
||||||
|
- 语言文件必须放在调用注册方法的插件自己的 `lang` 目录。
|
||||||
|
- 物品 lore 必须用 YAML List 格式编写。
|
||||||
|
- 修改语言文件后必须执行 `/lang reload` 才会进入缓存。
|
||||||
|
=======
|
||||||
|
# LangUtil
|
||||||
|
|
||||||
|
>>>>>>> 12c7b3f43c6113b170b9e83dedf75650d51b9040
|
||||||
Reference in New Issue
Block a user