本文档提供多个完整的 UltiTools 模块开发示例。
一个完整的服务器经济系统实现。
economy-plugin/
├── src/main/java/com/example/economy/
│ ├── EconomyPlugin.java
│ ├── commands/
│ │ └── MoneyCommand.java
│ ├── services/
│ │ └── EconomyService.java
│ ├── entities/
│ │ └── Account.java
│ ├── configs/
│ │ └── EconomyConfig.java
│ └── listeners/
│ └── JoinListener.java
└── src/main/resources/
├── plugin.yml
└── lang/zh.json
package com.example.economy.entities;
import com.ultikits.ultitools.abstracts.AbstractDataEntity;
import com.ultikits.ultitools.annotations.Column;
import com.ultikits.ultitools.annotations.Table;
import lombok.*;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@Table("economy_accounts")
public class Account extends AbstractDataEntity {
@Column("uuid")
private String uuid;
@Column("name")
private String name;
@Column(value = "balance", type = "DECIMAL(15,2)")
private double balance;
@Column(value = "total_earned", type = "DECIMAL(15,2)")
private double totalEarned;
@Column(value = "total_spent", type = "DECIMAL(15,2)")
private double totalSpent;
@Column(value = "created_at", type = "BIGINT")
private long createdAt;
@Column(value = "last_transaction", type = "BIGINT")
private long lastTransaction;
}package com.example.economy.configs;
import com.ultikits.ultitools.abstracts.AbstractConfigEntity;
import com.ultikits.ultitools.annotations.ConfigEntity;
import com.ultikits.ultitools.annotations.ConfigEntry;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@ConfigEntity(path = "config/economy.yml")
public class EconomyConfig extends AbstractConfigEntity {
@ConfigEntry(path = "currency.name", comment = "货币名称")
private String currencyName = "金币";
@ConfigEntry(path = "currency.symbol", comment = "货币符号")
private String currencySymbol = "💰";
@ConfigEntry(path = "starting-balance", comment = "新玩家初始余额")
private double startingBalance = 100.0;
@ConfigEntry(path = "max-balance", comment = "最大余额限制 (0 = 无限制)")
private double maxBalance = 0;
@ConfigEntry(path = "transfer.enabled", comment = "是否允许玩家转账")
private boolean transferEnabled = true;
@ConfigEntry(path = "transfer.min-amount", comment = "最小转账金额")
private double minTransferAmount = 1.0;
@ConfigEntry(path = "transfer.fee-rate", comment = "转账手续费率 (0.05 = 5%)")
private double transferFeeRate = 0.0;
@ConfigEntry(path = "daily-reward.enabled", comment = "是否启用每日奖励")
private boolean dailyRewardEnabled = true;
@ConfigEntry(path = "daily-reward.amount", comment = "每日奖励金额")
private double dailyRewardAmount = 50.0;
public EconomyConfig() {
super("config/economy.yml");
}
}package com.example.economy.services;
import com.example.economy.EconomyPlugin;
import com.example.economy.configs.EconomyConfig;
import com.example.economy.entities.Account;
import com.ultikits.ultitools.annotations.Autowired;
import com.ultikits.ultitools.annotations.Service;
import com.ultikits.ultitools.entities.WhereCondition;
import com.ultikits.ultitools.interfaces.DataOperator;
import org.bukkit.entity.Player;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@Service
public class EconomyService {
private final DataOperator<Account> accountOperator;
@Autowired
private EconomyConfig config;
public EconomyService() {
this.accountOperator = EconomyPlugin.getInstance().getDataOperator(Account.class);
}
/**
* 获取玩家账户
*/
public Account getAccount(Player player) {
return getAccountByUuid(player.getUniqueId().toString())
.orElseGet(() -> createAccount(player));
}
/**
* 根据 UUID 获取账户
*/
public Optional<Account> getAccountByUuid(String uuid) {
List<Account> accounts = accountOperator.getAll(
WhereCondition.builder().column("uuid").value(uuid).build()
);
return accounts.isEmpty() ? Optional.empty() : Optional.of(accounts.get(0));
}
/**
* 创建新账户
*/
private Account createAccount(Player player) {
Account account = Account.builder()
.uuid(player.getUniqueId().toString())
.name(player.getName())
.balance(config.getStartingBalance())
.totalEarned(config.getStartingBalance())
.totalSpent(0)
.createdAt(System.currentTimeMillis())
.lastTransaction(System.currentTimeMillis())
.build();
accountOperator.insert(account);
return account;
}
/**
* 获取余额
*/
public double getBalance(Player player) {
return getAccount(player).getBalance();
}
/**
* 存款
*/
public boolean deposit(Player player, double amount) {
if (amount <= 0) return false;
Account account = getAccount(player);
double newBalance = account.getBalance() + amount;
// 检查最大余额限制
if (config.getMaxBalance() > 0 && newBalance > config.getMaxBalance()) {
return false;
}
account.setBalance(newBalance);
account.setTotalEarned(account.getTotalEarned() + amount);
account.setLastTransaction(System.currentTimeMillis());
try {
accountOperator.update(account);
return true;
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
/**
* 取款
*/
public boolean withdraw(Player player, double amount) {
if (amount <= 0) return false;
Account account = getAccount(player);
if (account.getBalance() < amount) {
return false;
}
account.setBalance(account.getBalance() - amount);
account.setTotalSpent(account.getTotalSpent() + amount);
account.setLastTransaction(System.currentTimeMillis());
try {
accountOperator.update(account);
return true;
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
/**
* 转账
*/
public TransferResult transfer(Player from, Player to, double amount) {
if (!config.isTransferEnabled()) {
return TransferResult.DISABLED;
}
if (amount < config.getMinTransferAmount()) {
return TransferResult.BELOW_MINIMUM;
}
double fee = amount * config.getTransferFeeRate();
double totalDeduct = amount + fee;
Account fromAccount = getAccount(from);
if (fromAccount.getBalance() < totalDeduct) {
return TransferResult.INSUFFICIENT_FUNDS;
}
Account toAccount = getAccount(to);
double newToBalance = toAccount.getBalance() + amount;
if (config.getMaxBalance() > 0 && newToBalance > config.getMaxBalance()) {
return TransferResult.RECEIVER_MAX_BALANCE;
}
// 执行转账
if (!withdraw(from, totalDeduct)) {
return TransferResult.FAILED;
}
if (!deposit(to, amount)) {
// 回滚
deposit(from, totalDeduct);
return TransferResult.FAILED;
}
return TransferResult.SUCCESS;
}
/**
* 获取财富排行榜
*/
public List<Account> getTopAccounts(int limit) {
return accountOperator.getAll().stream()
.sorted((a, b) -> Double.compare(b.getBalance(), a.getBalance()))
.limit(limit)
.collect(Collectors.toList());
}
/**
* 格式化金额显示
*/
public String formatBalance(double amount) {
return config.getCurrencySymbol() + String.format("%.2f", amount) + " " + config.getCurrencyName();
}
public enum TransferResult {
SUCCESS,
DISABLED,
BELOW_MINIMUM,
INSUFFICIENT_FUNDS,
RECEIVER_MAX_BALANCE,
FAILED
}
}package com.example.economy.commands;
import com.example.economy.configs.EconomyConfig;
import com.example.economy.entities.Account;
import com.example.economy.services.EconomyService;
import com.ultikits.ultitools.abstracts.AbstractCommandExecutor;
import com.ultikits.ultitools.annotations.Autowired;
import com.ultikits.ultitools.annotations.command.*;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.List;
@CmdTarget(CmdTarget.CmdTargetType.BOTH)
@CmdExecutor(
alias = {"money", "eco", "balance", "bal"},
permission = "economy.use",
description = "经济系统命令"
)
public class MoneyCommand extends AbstractCommandExecutor {
@Autowired
private EconomyService economyService;
@Autowired
private EconomyConfig config;
/**
* /money - 查看自己余额
*/
@CmdMapping(format = "")
public void checkBalance(@CmdSender Player player) {
double balance = economyService.getBalance(player);
player.sendMessage(ChatColor.GREEN + "你的余额: " +
ChatColor.GOLD + economyService.formatBalance(balance));
}
/**
* /money <player> - 查看他人余额
*/
@CmdMapping(format = "<target>", permission = "economy.check.others")
public void checkOtherBalance(
@CmdSender CommandSender sender,
@CmdParam("target") Player target
) {
double balance = economyService.getBalance(target);
sender.sendMessage(ChatColor.GREEN + target.getName() + " 的余额: " +
ChatColor.GOLD + economyService.formatBalance(balance));
}
/**
* /money pay <player> <amount> - 转账
*/
@CmdMapping(format = "pay <target> <amount>")
@CmdCD(value = 5, unit = java.util.concurrent.TimeUnit.SECONDS)
public void transfer(
@CmdSender Player sender,
@CmdParam("target") Player target,
@CmdParam("amount") double amount
) {
if (sender.equals(target)) {
sender.sendMessage(ChatColor.RED + "不能给自己转账!");
return;
}
EconomyService.TransferResult result = economyService.transfer(sender, target, amount);
switch (result) {
case SUCCESS:
double fee = amount * config.getTransferFeeRate();
sender.sendMessage(ChatColor.GREEN + "成功转账 " +
economyService.formatBalance(amount) + " 给 " + target.getName());
if (fee > 0) {
sender.sendMessage(ChatColor.GRAY + "手续费: " +
economyService.formatBalance(fee));
}
target.sendMessage(ChatColor.GREEN + sender.getName() + " 向你转账 " +
economyService.formatBalance(amount));
break;
case DISABLED:
sender.sendMessage(ChatColor.RED + "转账功能已禁用!");
break;
case BELOW_MINIMUM:
sender.sendMessage(ChatColor.RED + "最小转账金额: " +
economyService.formatBalance(config.getMinTransferAmount()));
break;
case INSUFFICIENT_FUNDS:
sender.sendMessage(ChatColor.RED + "余额不足!");
break;
case RECEIVER_MAX_BALANCE:
sender.sendMessage(ChatColor.RED + "对方余额已达上限!");
break;
default:
sender.sendMessage(ChatColor.RED + "转账失败,请稍后重试!");
}
}
/**
* /money top [数量] - 财富排行榜
*/
@CmdMapping(format = "top")
public void showTop(@CmdSender CommandSender sender) {
showTopN(sender, 10);
}
@CmdMapping(format = "top <count>")
public void showTopN(
@CmdSender CommandSender sender,
@CmdParam("count") int count
) {
if (count < 1 || count > 100) {
count = 10;
}
List<Account> topAccounts = economyService.getTopAccounts(count);
sender.sendMessage(ChatColor.GOLD + "===== 财富排行榜 Top " + count + " =====");
for (int i = 0; i < topAccounts.size(); i++) {
Account account = topAccounts.get(i);
String rank = getRankColor(i + 1) + "" + (i + 1);
sender.sendMessage(rank + ". " + ChatColor.WHITE + account.getName() +
ChatColor.GRAY + " - " + ChatColor.GOLD +
economyService.formatBalance(account.getBalance()));
}
}
/**
* /money give <player> <amount> - 管理员给钱
*/
@CmdMapping(format = "give <target> <amount>", permission = "economy.admin")
public void give(
@CmdSender CommandSender sender,
@CmdParam("target") Player target,
@CmdParam("amount") double amount
) {
if (economyService.deposit(target, amount)) {
sender.sendMessage(ChatColor.GREEN + "已给予 " + target.getName() + " " +
economyService.formatBalance(amount));
target.sendMessage(ChatColor.GREEN + "你收到了 " +
economyService.formatBalance(amount));
} else {
sender.sendMessage(ChatColor.RED + "操作失败!");
}
}
/**
* /money take <player> <amount> - 管理员扣钱
*/
@CmdMapping(format = "take <target> <amount>", permission = "economy.admin")
public void take(
@CmdSender CommandSender sender,
@CmdParam("target") Player target,
@CmdParam("amount") double amount
) {
if (economyService.withdraw(target, amount)) {
sender.sendMessage(ChatColor.GREEN + "已从 " + target.getName() + " 扣除 " +
economyService.formatBalance(amount));
target.sendMessage(ChatColor.RED + "你被扣除了 " +
economyService.formatBalance(amount));
} else {
sender.sendMessage(ChatColor.RED + "操作失败(可能余额不足)!");
}
}
private ChatColor getRankColor(int rank) {
switch (rank) {
case 1: return ChatColor.GOLD;
case 2: return ChatColor.GRAY;
case 3: return ChatColor.DARK_RED;
default: return ChatColor.WHITE;
}
}
@Override
protected void handleHelp(CommandSender sender) {
sender.sendMessage(ChatColor.GOLD + "===== 经济系统帮助 =====");
sender.sendMessage(ChatColor.YELLOW + "/money" + ChatColor.GRAY + " - 查看余额");
sender.sendMessage(ChatColor.YELLOW + "/money <玩家>" + ChatColor.GRAY + " - 查看他人余额");
sender.sendMessage(ChatColor.YELLOW + "/money pay <玩家> <金额>" + ChatColor.GRAY + " - 转账");
sender.sendMessage(ChatColor.YELLOW + "/money top [数量]" + ChatColor.GRAY + " - 财富排行");
if (sender.hasPermission("economy.admin")) {
sender.sendMessage(ChatColor.RED + "--- 管理员命令 ---");
sender.sendMessage(ChatColor.YELLOW + "/money give <玩家> <金额>" + ChatColor.GRAY + " - 给予金币");
sender.sendMessage(ChatColor.YELLOW + "/money take <玩家> <金额>" + ChatColor.GRAY + " - 扣除金币");
}
}
}一个完整的家和传送点系统。
package com.example.teleport.entities;
import com.ultikits.ultitools.abstracts.AbstractDataEntity;
import com.ultikits.ultitools.annotations.Column;
import com.ultikits.ultitools.annotations.Table;
import lombok.*;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@Table("player_homes")
public class Home extends AbstractDataEntity {
@Column("owner_uuid")
private String ownerUuid;
@Column("name")
private String name;
@Column("world")
private String world;
@Column(value = "x", type = "DOUBLE")
private double x;
@Column(value = "y", type = "DOUBLE")
private double y;
@Column(value = "z", type = "DOUBLE")
private double z;
@Column(value = "yaw", type = "FLOAT")
private float yaw;
@Column(value = "pitch", type = "FLOAT")
private float pitch;
@Column(value = "created_at", type = "BIGINT")
private long createdAt;
}package com.example.teleport.services;
import com.example.teleport.TeleportPlugin;
import com.example.teleport.entities.Home;
import com.ultikits.ultitools.annotations.Service;
import com.ultikits.ultitools.entities.WhereCondition;
import com.ultikits.ultitools.interfaces.DataOperator;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
import java.util.List;
import java.util.Optional;
@Service
public class HomeService {
private final DataOperator<Home> homeOperator;
public HomeService() {
this.homeOperator = TeleportPlugin.getInstance().getDataOperator(Home.class);
}
/**
* 获取玩家的所有家
*/
public List<Home> getHomes(Player player) {
return homeOperator.getAll(
WhereCondition.builder()
.column("owner_uuid")
.value(player.getUniqueId().toString())
.build()
);
}
/**
* 获取指定的家
*/
public Optional<Home> getHome(Player player, String name) {
List<Home> homes = homeOperator.getAll(
WhereCondition.builder()
.column("owner_uuid")
.value(player.getUniqueId().toString())
.build(),
WhereCondition.builder()
.column("name")
.value(name)
.build()
);
return homes.isEmpty() ? Optional.empty() : Optional.of(homes.get(0));
}
/**
* 设置家
*/
public boolean setHome(Player player, String name, int maxHomes) {
List<Home> existingHomes = getHomes(player);
// 检查是否已存在同名的家
Optional<Home> existing = existingHomes.stream()
.filter(h -> h.getName().equalsIgnoreCase(name))
.findFirst();
Location loc = player.getLocation();
if (existing.isPresent()) {
// 更新现有的家
Home home = existing.get();
home.setWorld(loc.getWorld().getName());
home.setX(loc.getX());
home.setY(loc.getY());
home.setZ(loc.getZ());
home.setYaw(loc.getYaw());
home.setPitch(loc.getPitch());
try {
homeOperator.update(home);
return true;
} catch (IllegalAccessException e) {
return false;
}
}
// 检查家的数量限制
if (existingHomes.size() >= maxHomes) {
return false;
}
// 创建新的家
Home home = Home.builder()
.ownerUuid(player.getUniqueId().toString())
.name(name)
.world(loc.getWorld().getName())
.x(loc.getX())
.y(loc.getY())
.z(loc.getZ())
.yaw(loc.getYaw())
.pitch(loc.getPitch())
.createdAt(System.currentTimeMillis())
.build();
homeOperator.insert(home);
return true;
}
/**
* 删除家
*/
public boolean deleteHome(Player player, String name) {
Optional<Home> home = getHome(player, name);
if (home.isPresent()) {
homeOperator.delById(home.get().getId());
return true;
}
return false;
}
/**
* 传送到家
*/
public boolean teleportToHome(Player player, String name) {
Optional<Home> homeOpt = getHome(player, name);
if (!homeOpt.isPresent()) {
return false;
}
Home home = homeOpt.get();
World world = Bukkit.getWorld(home.getWorld());
if (world == null) {
return false;
}
Location location = new Location(
world,
home.getX(),
home.getY(),
home.getZ(),
home.getYaw(),
home.getPitch()
);
player.teleport(location);
return true;
}
}package com.example.teleport.commands;
import com.example.teleport.entities.Home;
import com.example.teleport.services.HomeService;
import com.ultikits.ultitools.abstracts.AbstractCommandExecutor;
import com.ultikits.ultitools.annotations.Autowired;
import com.ultikits.ultitools.annotations.command.*;
import org.bukkit.ChatColor;
import org.bukkit.Sound;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.List;
import java.util.stream.Collectors;
@CmdTarget(CmdTarget.CmdTargetType.PLAYER)
@CmdExecutor(
alias = {"home", "h"},
permission = "teleport.home",
description = "家传送命令"
)
public class HomeCommand extends AbstractCommandExecutor {
@Autowired
private HomeService homeService;
private static final int DEFAULT_MAX_HOMES = 3;
/**
* /home - 传送到默认家
*/
@CmdMapping(format = "")
public void goHome(@CmdSender Player player) {
teleportHome(player, "home");
}
/**
* /home <name> - 传送到指定家
*/
@CmdMapping(format = "<name>")
@CmdCD(value = 3, unit = java.util.concurrent.TimeUnit.SECONDS)
public void teleportHome(
@CmdSender Player player,
@CmdParam("name") @CmdSuggest({"home", "base", "farm"}) String name
) {
if (homeService.teleportToHome(player, name)) {
player.sendMessage(ChatColor.GREEN + "已传送到家: " + name);
player.playSound(player.getLocation(), Sound.ENTITY_ENDERMAN_TELEPORT, 1, 1);
} else {
player.sendMessage(ChatColor.RED + "找不到名为 '" + name + "' 的家!");
}
}
/**
* /home set <name> - 设置家
*/
@CmdMapping(format = "set <name>")
public void setHome(
@CmdSender Player player,
@CmdParam("name") String name
) {
int maxHomes = getMaxHomes(player);
if (homeService.setHome(player, name, maxHomes)) {
player.sendMessage(ChatColor.GREEN + "家 '" + name + "' 已设置!");
player.playSound(player.getLocation(), Sound.BLOCK_NOTE_BLOCK_PLING, 1, 1);
} else {
player.sendMessage(ChatColor.RED + "无法设置家!你可能已达到上限 (" + maxHomes + " 个)");
}
}
/**
* /home del <name> - 删除家
*/
@CmdMapping(format = "del <name>")
public void deleteHome(
@CmdSender Player player,
@CmdParam("name") String name
) {
if (homeService.deleteHome(player, name)) {
player.sendMessage(ChatColor.GREEN + "家 '" + name + "' 已删除!");
} else {
player.sendMessage(ChatColor.RED + "找不到名为 '" + name + "' 的家!");
}
}
/**
* /home list - 列出所有家
*/
@CmdMapping(format = "list")
public void listHomes(@CmdSender Player player) {
List<Home> homes = homeService.getHomes(player);
if (homes.isEmpty()) {
player.sendMessage(ChatColor.YELLOW + "你还没有设置任何家!");
player.sendMessage(ChatColor.GRAY + "使用 /home set <名称> 设置一个家");
return;
}
int maxHomes = getMaxHomes(player);
player.sendMessage(ChatColor.GOLD + "===== 你的家 (" + homes.size() + "/" + maxHomes + ") =====");
for (Home home : homes) {
String info = String.format(
"%s%s %s- %s(%s, %.0f, %.0f, %.0f)",
ChatColor.YELLOW,
home.getName(),
ChatColor.GRAY,
ChatColor.WHITE,
home.getWorld(),
home.getX(),
home.getY(),
home.getZ()
);
player.sendMessage(info);
}
}
private int getMaxHomes(Player player) {
// 可以根据权限或VIP等级返回不同数量
if (player.hasPermission("teleport.home.unlimited")) {
return Integer.MAX_VALUE;
}
if (player.hasPermission("teleport.home.vip")) {
return 10;
}
return DEFAULT_MAX_HOMES;
}
@Override
protected List<String> suggest(Player player, org.bukkit.command.Command command, String[] args) {
if (args.length == 1) {
// 补全家的名称
return homeService.getHomes(player).stream()
.map(Home::getName)
.filter(name -> name.toLowerCase().startsWith(args[0].toLowerCase()))
.collect(Collectors.toList());
}
return super.suggest(player, command, args);
}
@Override
protected void handleHelp(CommandSender sender) {
sender.sendMessage(ChatColor.GOLD + "===== 家命令帮助 =====");
sender.sendMessage(ChatColor.YELLOW + "/home" + ChatColor.GRAY + " - 传送到默认家");
sender.sendMessage(ChatColor.YELLOW + "/home <名称>" + ChatColor.GRAY + " - 传送到指定家");
sender.sendMessage(ChatColor.YELLOW + "/home set <名称>" + ChatColor.GRAY + " - 设置家");
sender.sendMessage(ChatColor.YELLOW + "/home del <名称>" + ChatColor.GRAY + " - 删除家");
sender.sendMessage(ChatColor.YELLOW + "/home list" + ChatColor.GRAY + " - 列出所有家");
}
}一个支持定时公告的系统。
package com.example.announce.entities;
import com.ultikits.ultitools.abstracts.AbstractDataEntity;
import com.ultikits.ultitools.annotations.Column;
import com.ultikits.ultitools.annotations.Table;
import lombok.*;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@Table("announcements")
public class Announcement extends AbstractDataEntity {
@Column("name")
private String name;
@Column(value = "message", type = "TEXT")
private String message;
@Column(value = "interval_seconds", type = "INT")
private int intervalSeconds;
@Column("enabled")
private boolean enabled;
@Column("permission")
private String permission;
@Column(value = "created_at", type = "BIGINT")
private long createdAt;
}package com.example.announce.services;
import com.example.announce.AnnouncePlugin;
import com.example.announce.entities.Announcement;
import com.ultikits.ultitools.UltiTools;
import com.ultikits.ultitools.annotations.PostConstruct;
import com.ultikits.ultitools.annotations.PreDestroy;
import com.ultikits.ultitools.annotations.Service;
import com.ultikits.ultitools.entities.WhereCondition;
import com.ultikits.ultitools.interfaces.DataOperator;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitTask;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@Service
public class AnnouncementService {
private final DataOperator<Announcement> announcementOperator;
private final Map<String, BukkitTask> scheduledTasks = new HashMap<>();
public AnnouncementService() {
this.announcementOperator = AnnouncePlugin.getInstance().getDataOperator(Announcement.class);
}
@PostConstruct
public void init() {
// 启动时加载所有启用的公告
loadEnabledAnnouncements();
}
@PreDestroy
public void cleanup() {
// 取消所有定时任务
scheduledTasks.values().forEach(BukkitTask::cancel);
scheduledTasks.clear();
}
/**
* 加载所有启用的公告
*/
public void loadEnabledAnnouncements() {
List<Announcement> enabled = announcementOperator.getAll(
WhereCondition.builder().column("enabled").value(true).build()
);
for (Announcement announcement : enabled) {
scheduleAnnouncement(announcement);
}
Bukkit.getLogger().info("[Announce] 已加载 " + enabled.size() + " 条定时公告");
}
/**
* 调度公告
*/
private void scheduleAnnouncement(Announcement announcement) {
if (scheduledTasks.containsKey(announcement.getName())) {
scheduledTasks.get(announcement.getName()).cancel();
}
long intervalTicks = announcement.getIntervalSeconds() * 20L;
BukkitTask task = Bukkit.getScheduler().runTaskTimer(
UltiTools.getInstance(),
() -> broadcastAnnouncement(announcement),
intervalTicks,
intervalTicks
);
scheduledTasks.put(announcement.getName(), task);
}
/**
* 广播公告
*/
public void broadcastAnnouncement(Announcement announcement) {
String message = ChatColor.translateAlternateColorCodes('&', announcement.getMessage());
String permission = announcement.getPermission();
for (Player player : Bukkit.getOnlinePlayers()) {
if (permission == null || permission.isEmpty() || player.hasPermission(permission)) {
player.sendMessage(message);
}
}
}
/**
* 创建公告
*/
public void createAnnouncement(String name, String message, int intervalSeconds) {
Announcement announcement = Announcement.builder()
.name(name)
.message(message)
.intervalSeconds(intervalSeconds)
.enabled(true)
.createdAt(System.currentTimeMillis())
.build();
announcementOperator.insert(announcement);
scheduleAnnouncement(announcement);
}
/**
* 删除公告
*/
public boolean deleteAnnouncement(String name) {
Optional<Announcement> announcement = getAnnouncement(name);
if (announcement.isPresent()) {
// 取消定时任务
if (scheduledTasks.containsKey(name)) {
scheduledTasks.get(name).cancel();
scheduledTasks.remove(name);
}
announcementOperator.delById(announcement.get().getId());
return true;
}
return false;
}
/**
* 启用/禁用公告
*/
public boolean toggleAnnouncement(String name, boolean enabled) {
Optional<Announcement> announcementOpt = getAnnouncement(name);
if (announcementOpt.isPresent()) {
Announcement announcement = announcementOpt.get();
announcement.setEnabled(enabled);
try {
announcementOperator.update(announcement);
} catch (IllegalAccessException e) {
return false;
}
if (enabled) {
scheduleAnnouncement(announcement);
} else {
if (scheduledTasks.containsKey(name)) {
scheduledTasks.get(name).cancel();
scheduledTasks.remove(name);
}
}
return true;
}
return false;
}
/**
* 获取所有公告
*/
public List<Announcement> getAllAnnouncements() {
return announcementOperator.getAll();
}
/**
* 获取指定公告
*/
public Optional<Announcement> getAnnouncement(String name) {
List<Announcement> results = announcementOperator.getAll(
WhereCondition.builder().column("name").value(name).build()
);
return results.isEmpty() ? Optional.empty() : Optional.of(results.get(0));
}
}这些示例展示了 UltiTools-API 的核心功能:
- IoC 容器:
@Service、@Autowired自动装配 - 命令系统:
@CmdExecutor、@CmdMapping注解驱动 - 数据存储:
@Table、@ColumnORM 映射 - 配置管理:
@ConfigEntity、@ConfigEntry类型安全配置 - 生命周期:
@PostConstruct、@PreDestroy钩子
更多资源: 查看 API 参考 获取完整 API 文档