first commit
This commit is contained in:
@@ -0,0 +1,59 @@
|
|||||||
|
<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.bitnix</groupId>
|
||||||
|
<artifactId>DirtTaxes</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<name>DirtTaxes</name>
|
||||||
|
<description>Offline balance tax plugin for Paper 1.21.x</description>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<java.version>21</java.version>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<maven.compiler.release>21</maven.compiler.release>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>papermc</id>
|
||||||
|
<url>https://repo.papermc.io/repository/maven-public/</url>
|
||||||
|
</repository>
|
||||||
|
<repository>
|
||||||
|
<id>jitpack.io</id>
|
||||||
|
<url>https://jitpack.io</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.papermc.paper</groupId>
|
||||||
|
<artifactId>paper-api</artifactId>
|
||||||
|
<version>1.21.1-R0.1-SNAPSHOT</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.MilkBowl</groupId>
|
||||||
|
<artifactId>VaultAPI</artifactId>
|
||||||
|
<version>1.7</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<finalName>DirtTaxes</finalName>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.13.0</version>
|
||||||
|
<configuration>
|
||||||
|
<release>21</release>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,630 @@
|
|||||||
|
package com.bitnix.dirttaxes;
|
||||||
|
|
||||||
|
import net.milkbowl.vault.economy.Economy;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.OfflinePlayer;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.command.PluginCommand;
|
||||||
|
import org.bukkit.command.TabExecutor;
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.plugin.RegisteredServiceProvider;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
import org.bukkit.scheduler.BukkitTask;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.text.DecimalFormat;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class DirtTaxesPlugin extends JavaPlugin implements TabExecutor {
|
||||||
|
|
||||||
|
private Economy economy;
|
||||||
|
private BukkitTask taxTask;
|
||||||
|
private File pendingFile;
|
||||||
|
private FileConfiguration pendingConfig;
|
||||||
|
private final Random random = new Random();
|
||||||
|
private final DecimalFormat moneyFormat = new DecimalFormat("0.00");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
saveDefaultConfig();
|
||||||
|
createDataFiles();
|
||||||
|
|
||||||
|
if (!setupEconomy()) {
|
||||||
|
getLogger().severe("Vault economy provider not found. Disabling DirtTaxes.");
|
||||||
|
getServer().getPluginManager().disablePlugin(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PluginCommand command = getCommand("dirttaxes");
|
||||||
|
if (command != null) {
|
||||||
|
command.setExecutor(this);
|
||||||
|
command.setTabCompleter(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
scheduleTaxTask();
|
||||||
|
registerJoinListener();
|
||||||
|
|
||||||
|
if (getConfig().getBoolean("tax.startup-tax-check", false)) {
|
||||||
|
long delayTicks = Math.max(20L, getConfig().getLong("tax.startup-tax-delay-seconds", 30L) * 20L);
|
||||||
|
Bukkit.getScheduler().runTaskLater(this, this::runOfflineTaxCycle, delayTicks);
|
||||||
|
}
|
||||||
|
|
||||||
|
getLogger().info("DirtTaxes enabled.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable() {
|
||||||
|
if (taxTask != null) {
|
||||||
|
taxTask.cancel();
|
||||||
|
taxTask = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bukkit.getScheduler().cancelTasks(this);
|
||||||
|
savePendingMessages();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createDataFiles() {
|
||||||
|
if (!getDataFolder().exists()) {
|
||||||
|
getDataFolder().mkdirs();
|
||||||
|
}
|
||||||
|
|
||||||
|
pendingFile = new File(getDataFolder(), "pending_messages.yml");
|
||||||
|
if (!pendingFile.exists()) {
|
||||||
|
try {
|
||||||
|
pendingFile.createNewFile();
|
||||||
|
} catch (IOException e) {
|
||||||
|
getLogger().severe("Could not create pending_messages.yml");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pendingConfig = YamlConfiguration.loadConfiguration(pendingFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean setupEconomy() {
|
||||||
|
RegisteredServiceProvider<Economy> rsp = getServer().getServicesManager().getRegistration(Economy.class);
|
||||||
|
if (rsp == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
economy = rsp.getProvider();
|
||||||
|
return economy != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void scheduleTaxTask() {
|
||||||
|
if (taxTask != null) {
|
||||||
|
taxTask.cancel();
|
||||||
|
taxTask = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
long intervalMinutes = Math.max(1L, getConfig().getLong("tax.interval-minutes", 1440L));
|
||||||
|
long intervalTicks = intervalMinutes * 60L * 20L;
|
||||||
|
|
||||||
|
taxTask = Bukkit.getScheduler().runTaskTimer(this, this::runOfflineTaxCycle, intervalTicks, intervalTicks);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerJoinListener() {
|
||||||
|
getServer().getPluginManager().registerEvents(new TaxJoinListener(this), this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleJoin(Player player) {
|
||||||
|
String path = "players." + player.getUniqueId();
|
||||||
|
if (!pendingConfig.contains(path)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> messages = pendingConfig.getStringList(path + ".messages");
|
||||||
|
for (String message : messages) {
|
||||||
|
player.sendMessage(color(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
pendingConfig.set(path, null);
|
||||||
|
savePendingMessages();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void runOfflineTaxCycle() {
|
||||||
|
if (!getConfig().getBoolean("tax.enabled", true)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
long requiredOfflineMinutes = Math.max(0L, getConfig().getLong("tax.offline-minutes-required", 1440L));
|
||||||
|
long requiredOfflineMillis = requiredOfflineMinutes * 60L * 1000L;
|
||||||
|
|
||||||
|
for (OfflinePlayer offlinePlayer : Bukkit.getOfflinePlayers()) {
|
||||||
|
if (offlinePlayer == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offlinePlayer.isOnline()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offlinePlayer.getName() == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
long lastPlayed = offlinePlayer.getLastPlayed();
|
||||||
|
if (lastPlayed <= 0L) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
long offlineFor = Instant.now().toEpochMilli() - lastPlayed;
|
||||||
|
if (offlineFor < requiredOfflineMillis) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
taxSinglePlayer(offlinePlayer, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getConfig().getBoolean("storage.save-pending-messages", true)) {
|
||||||
|
savePendingMessages();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean taxSinglePlayer(OfflinePlayer offlinePlayer, boolean automatic) {
|
||||||
|
if (offlinePlayer == null || offlinePlayer.getName() == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getConfig().getBoolean("tax.permission-exempt", true) && offlinePlayer.isOnline()) {
|
||||||
|
Player player = offlinePlayer.getPlayer();
|
||||||
|
if (player != null && player.hasPermission("dirttaxes.exempt")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getConfig().getBoolean("tax.op-exempt", true) && offlinePlayer.isOp()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
double balance = economy.getBalance(offlinePlayer);
|
||||||
|
double oldBalance = balance;
|
||||||
|
double newBalance = balance;
|
||||||
|
double amountTaken = 0.0;
|
||||||
|
|
||||||
|
double maxDebt = getConfig().getDouble("tax.max-debt", -1000000.0);
|
||||||
|
if (maxDebt > 0) {
|
||||||
|
maxDebt = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (balance > 0) {
|
||||||
|
double ratePercent = Math.max(0.0, getConfig().getDouble("tax.rate-percent", 5.0));
|
||||||
|
double minimumTax = Math.max(0.0, getConfig().getDouble("tax.minimum-tax", 1.0));
|
||||||
|
amountTaken = Math.max(minimumTax, balance * (ratePercent / 100.0));
|
||||||
|
|
||||||
|
if (amountTaken > balance) {
|
||||||
|
amountTaken = balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getConfig().getBoolean("tax.round-to-cents", true)) {
|
||||||
|
amountTaken = roundMoney(amountTaken);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (amountTaken <= 0.0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
economy.withdrawPlayer(offlinePlayer, amountTaken);
|
||||||
|
newBalance = economy.getBalance(offlinePlayer);
|
||||||
|
|
||||||
|
if (sameMoney(oldBalance, newBalance)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
amountTaken = Math.abs(oldBalance - newBalance);
|
||||||
|
} else if (getConfig().getBoolean("debt.enabled", true)) {
|
||||||
|
double interestPercent = Math.max(0.0, getConfig().getDouble("debt.negative-interest-percent", 2.5));
|
||||||
|
double flatDebt = Math.max(0.0, getConfig().getDouble("debt.flat-debt-per-cycle", 500.0));
|
||||||
|
|
||||||
|
double debtIncrease = Math.abs(balance) * (interestPercent / 100.0) + flatDebt;
|
||||||
|
if (getConfig().getBoolean("tax.round-to-cents", true)) {
|
||||||
|
debtIncrease = roundMoney(debtIncrease);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debtIncrease <= 0.0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
double targetBalance = balance - debtIncrease;
|
||||||
|
if (targetBalance < maxDebt) {
|
||||||
|
targetBalance = maxDebt;
|
||||||
|
}
|
||||||
|
|
||||||
|
amountTaken = Math.abs(targetBalance - balance);
|
||||||
|
if (amountTaken <= 0.0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean usedCommand = getConfig().getBoolean("debt.use-command-for-debt", true);
|
||||||
|
|
||||||
|
if (usedCommand) {
|
||||||
|
runDebtCommand(offlinePlayer, amountTaken, balance, targetBalance);
|
||||||
|
newBalance = economy.getBalance(offlinePlayer);
|
||||||
|
|
||||||
|
if (sameMoney(oldBalance, newBalance)) {
|
||||||
|
if (getConfig().getBoolean("debt.warn-if-command-fails", true)) {
|
||||||
|
String fail = prefixed("messages.debt-command-failed").replace("%player%", offlinePlayer.getName());
|
||||||
|
Bukkit.getConsoleSender().sendMessage(fail);
|
||||||
|
for (Player online : Bukkit.getOnlinePlayers()) {
|
||||||
|
if (online.hasPermission("dirttaxes.notify")) {
|
||||||
|
online.sendMessage(fail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
amountTaken = Math.abs(oldBalance - newBalance);
|
||||||
|
} else {
|
||||||
|
economy.withdrawPlayer(offlinePlayer, amountTaken);
|
||||||
|
newBalance = economy.getBalance(offlinePlayer);
|
||||||
|
|
||||||
|
if (sameMoney(oldBalance, newBalance)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
amountTaken = Math.abs(oldBalance - newBalance);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getConfig().getBoolean("announcement.enabled", true)) {
|
||||||
|
announceTax(offlinePlayer, amountTaken, newBalance);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (automatic && getConfig().getBoolean("announcement.store-offline-message", true)) {
|
||||||
|
storeJoinMessages(offlinePlayer.getUniqueId(), amountTaken, newBalance);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newBalance < 0 && getConfig().getBoolean("debt.announce-debt", true)) {
|
||||||
|
String debtMsg = getConfig().getString("debt.debt-message", "&4IRS &8- &c%player% is now drowning in debt. Balance: $%new_balance%");
|
||||||
|
debtMsg = debtMsg.replace("%player%", offlinePlayer.getName())
|
||||||
|
.replace("%new_balance%", formatMoney(newBalance));
|
||||||
|
broadcastToStaffAndConsole(color(debtMsg));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void runDebtCommand(OfflinePlayer offlinePlayer, double amountTaken, double oldBalance, double targetBalance) {
|
||||||
|
String raw = getConfig().getString("debt.command", "cmi money set %player% %new_balance%");
|
||||||
|
if (raw == null || raw.isBlank()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String command = raw
|
||||||
|
.replace("%player%", offlinePlayer.getName())
|
||||||
|
.replace("%amount%", formatMoney(amountTaken))
|
||||||
|
.replace("%old_balance%", formatMoney(oldBalance))
|
||||||
|
.replace("%new_balance%", formatMoney(targetBalance));
|
||||||
|
|
||||||
|
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void announceTax(OfflinePlayer offlinePlayer, double amountTaken, double newBalance) {
|
||||||
|
String message = getConfig().getString("announcement.staff-message",
|
||||||
|
"&6IRS &8- &eTook &c$%amount% &efrom &b%player%&e. New balance: &a$%new_balance%");
|
||||||
|
|
||||||
|
message = message.replace("%amount%", formatMoney(amountTaken))
|
||||||
|
.replace("%player%", offlinePlayer.getName())
|
||||||
|
.replace("%new_balance%", formatMoney(newBalance));
|
||||||
|
|
||||||
|
broadcastToStaffAndConsole(color(message));
|
||||||
|
|
||||||
|
if (getConfig().getBoolean("fun.enabled", true)
|
||||||
|
&& getConfig().getBoolean("fun.include-funny-line-in-staff-alerts", true)
|
||||||
|
&& getConfig().getBoolean("fun.random-funny-lines", true)) {
|
||||||
|
String funny = getRandomFunnyLine();
|
||||||
|
if (funny != null && !funny.isBlank()) {
|
||||||
|
broadcastToStaffAndConsole(color(funny));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void broadcastToStaffAndConsole(String message) {
|
||||||
|
if (getConfig().getBoolean("announcement.notify-online-staff", true)) {
|
||||||
|
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||||
|
if (player.hasPermission("dirttaxes.notify")) {
|
||||||
|
player.sendMessage(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getConfig().getBoolean("announcement.log-to-console", true)) {
|
||||||
|
Bukkit.getConsoleSender().sendMessage(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void storeJoinMessages(UUID uuid, double amountTaken, double newBalance) {
|
||||||
|
String path = "players." + uuid + ".messages";
|
||||||
|
List<String> messages = pendingConfig.getStringList(path);
|
||||||
|
|
||||||
|
String joinMessage = getConfig().getString("announcement.join-message",
|
||||||
|
"&6IRS &8- &eTook &c$%amount% &efrom your account while you were away. New balance: &a$%new_balance%");
|
||||||
|
joinMessage = joinMessage.replace("%amount%", formatMoney(amountTaken))
|
||||||
|
.replace("%new_balance%", formatMoney(newBalance));
|
||||||
|
|
||||||
|
messages.add(joinMessage);
|
||||||
|
|
||||||
|
if (getConfig().getBoolean("fun.enabled", true)
|
||||||
|
&& getConfig().getBoolean("fun.send-funny-line-to-player", true)
|
||||||
|
&& getConfig().getBoolean("fun.random-funny-lines", true)) {
|
||||||
|
String funny = getRandomFunnyLine();
|
||||||
|
if (funny != null && !funny.isBlank()) {
|
||||||
|
messages.add(funny);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pendingConfig.set(path, messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getRandomFunnyLine() {
|
||||||
|
List<String> lines = getConfig().getStringList("fun.funny-lines");
|
||||||
|
if (lines.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return lines.get(random.nextInt(lines.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void savePendingMessages() {
|
||||||
|
if (pendingConfig == null || pendingFile == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
pendingConfig.save(pendingFile);
|
||||||
|
} catch (IOException e) {
|
||||||
|
getLogger().severe("Failed to save pending_messages.yml");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private double roundMoney(double amount) {
|
||||||
|
return Math.round(amount * 100.0D) / 100.0D;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean sameMoney(double a, double b) {
|
||||||
|
return Math.abs(a - b) < 0.009D;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String formatMoney(double amount) {
|
||||||
|
return moneyFormat.format(amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String color(String text) {
|
||||||
|
return ChatColor.translateAlternateColorCodes('&', text);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String msg(String path) {
|
||||||
|
return color(getConfig().getString(path, path));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String prefixed(String path) {
|
||||||
|
return msg("messages.prefix") + msg(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||||
|
if (args.length == 0) {
|
||||||
|
if (!sender.hasPermission("dirttaxes.use")) {
|
||||||
|
sender.sendMessage(prefixed("messages.no-permission"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
String info = msg("messages.info")
|
||||||
|
.replace("%rate%", String.valueOf(getConfig().getDouble("tax.rate-percent", 5.0)))
|
||||||
|
.replace("%interval%", String.valueOf(getConfig().getLong("tax.interval-minutes", 1440L)))
|
||||||
|
.replace("%maxdebt%", formatMoney(getConfig().getDouble("tax.max-debt", -1000000.0)));
|
||||||
|
sender.sendMessage(msg("messages.prefix") + info);
|
||||||
|
sender.sendMessage(msg("messages.prefix") + msg("messages.usage"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
String sub = args[0].toLowerCase(Locale.ROOT);
|
||||||
|
|
||||||
|
switch (sub) {
|
||||||
|
case "reload" -> {
|
||||||
|
if (!sender.hasPermission("dirttaxes.reload")) {
|
||||||
|
sender.sendMessage(prefixed("messages.no-permission"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
reloadConfig();
|
||||||
|
scheduleTaxTask();
|
||||||
|
sender.sendMessage(prefixed("messages.reloaded"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "info" -> {
|
||||||
|
if (!sender.hasPermission("dirttaxes.use")) {
|
||||||
|
sender.sendMessage(prefixed("messages.no-permission"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
String info = msg("messages.info")
|
||||||
|
.replace("%rate%", String.valueOf(getConfig().getDouble("tax.rate-percent", 5.0)))
|
||||||
|
.replace("%interval%", String.valueOf(getConfig().getLong("tax.interval-minutes", 1440L)))
|
||||||
|
.replace("%maxdebt%", formatMoney(getConfig().getDouble("tax.max-debt", -1000000.0)));
|
||||||
|
sender.sendMessage(msg("messages.prefix") + info);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "setrate" -> {
|
||||||
|
if (!sender.hasPermission("dirttaxes.setrate")) {
|
||||||
|
sender.sendMessage(prefixed("messages.no-permission"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length < 2) {
|
||||||
|
sender.sendMessage(prefixed("messages.usage"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Double value = parseDouble(args[1]);
|
||||||
|
if (value == null) {
|
||||||
|
sender.sendMessage(prefixed("messages.invalid-number"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value < 0) {
|
||||||
|
sender.sendMessage(prefixed("messages.rate-must-be-nonnegative"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
getConfig().set("tax.rate-percent", value);
|
||||||
|
saveConfig();
|
||||||
|
sender.sendMessage(prefixed("messages.set-rate-success").replace("%rate%", String.valueOf(value)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "setmaxdebt" -> {
|
||||||
|
if (!sender.hasPermission("dirttaxes.setmaxdebt")) {
|
||||||
|
sender.sendMessage(prefixed("messages.no-permission"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length < 2) {
|
||||||
|
sender.sendMessage(prefixed("messages.usage"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Double value = parseDouble(args[1]);
|
||||||
|
if (value == null) {
|
||||||
|
sender.sendMessage(prefixed("messages.invalid-number"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value > 0) {
|
||||||
|
sender.sendMessage(prefixed("messages.max-debt-must-be-negative"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
getConfig().set("tax.max-debt", value);
|
||||||
|
saveConfig();
|
||||||
|
sender.sendMessage(prefixed("messages.set-max-debt-success").replace("%maxdebt%", formatMoney(value)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "setinterval" -> {
|
||||||
|
if (!sender.hasPermission("dirttaxes.setinterval")) {
|
||||||
|
sender.sendMessage(prefixed("messages.no-permission"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length < 2) {
|
||||||
|
sender.sendMessage(prefixed("messages.usage"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Long value = parseLong(args[1]);
|
||||||
|
if (value == null) {
|
||||||
|
sender.sendMessage(prefixed("messages.invalid-number"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value <= 0) {
|
||||||
|
sender.sendMessage(prefixed("messages.interval-must-be-positive"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
getConfig().set("tax.interval-minutes", value);
|
||||||
|
saveConfig();
|
||||||
|
scheduleTaxTask();
|
||||||
|
sender.sendMessage(prefixed("messages.set-interval-success").replace("%interval%", String.valueOf(value)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "forcetax" -> {
|
||||||
|
if (!sender.hasPermission("dirttaxes.forcetax")) {
|
||||||
|
sender.sendMessage(prefixed("messages.no-permission"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length >= 2) {
|
||||||
|
OfflinePlayer target = Bukkit.getOfflinePlayer(args[1]);
|
||||||
|
if (target == null || target.getName() == null) {
|
||||||
|
sender.sendMessage(prefixed("messages.player-not-found"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
taxSinglePlayer(target, true);
|
||||||
|
sender.sendMessage(prefixed("messages.force-tax-player-success").replace("%player%", target.getName()));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
runOfflineTaxCycle();
|
||||||
|
sender.sendMessage(prefixed("messages.force-tax-all-success"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
default -> {
|
||||||
|
sender.sendMessage(prefixed("messages.usage"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Double parseDouble(String input) {
|
||||||
|
try {
|
||||||
|
return Double.parseDouble(input);
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Long parseLong(String input) {
|
||||||
|
try {
|
||||||
|
return Long.parseLong(input);
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
|
||||||
|
if (args.length == 1) {
|
||||||
|
List<String> subs = new ArrayList<>();
|
||||||
|
subs.add("reload");
|
||||||
|
subs.add("info");
|
||||||
|
subs.add("setrate");
|
||||||
|
subs.add("setmaxdebt");
|
||||||
|
subs.add("setinterval");
|
||||||
|
subs.add("forcetax");
|
||||||
|
return partial(args[0], subs);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length == 2 && args[0].equalsIgnoreCase("forcetax")) {
|
||||||
|
List<String> names = new ArrayList<>();
|
||||||
|
for (OfflinePlayer player : Bukkit.getOfflinePlayers()) {
|
||||||
|
if (player.getName() != null) {
|
||||||
|
names.add(player.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return partial(args[1], names);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> partial(String input, List<String> options) {
|
||||||
|
String lower = input.toLowerCase(Locale.ROOT);
|
||||||
|
List<String> matches = new ArrayList<>();
|
||||||
|
for (String option : options) {
|
||||||
|
if (option.toLowerCase(Locale.ROOT).startsWith(lower)) {
|
||||||
|
matches.add(option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return matches;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package com.bitnix.dirttaxes;
|
||||||
|
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
|
|
||||||
|
public class TaxJoinListener implements Listener {
|
||||||
|
|
||||||
|
private final DirtTaxesPlugin plugin;
|
||||||
|
|
||||||
|
public TaxJoinListener(DirtTaxesPlugin plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onJoin(PlayerJoinEvent event) {
|
||||||
|
plugin.handleJoin(event.getPlayer());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
tax:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
# How often offline players are taxed, in minutes.
|
||||||
|
# 1440 = once per day
|
||||||
|
interval-minutes: 1440
|
||||||
|
|
||||||
|
# Percentage of current balance removed each tax cycle.
|
||||||
|
# 5.0 = 5%
|
||||||
|
rate-percent: 5.0
|
||||||
|
|
||||||
|
# Minimum tax amount if balance is above 0
|
||||||
|
minimum-tax: 1.0
|
||||||
|
|
||||||
|
# Maximum debt allowed. Once a player reaches this negative value,
|
||||||
|
# no more debt is added.
|
||||||
|
max-debt: -1000000.0
|
||||||
|
|
||||||
|
# Players offline at least this many minutes before they can be taxed
|
||||||
|
offline-minutes-required: 1440
|
||||||
|
|
||||||
|
# If true, tax all offline players on plugin startup after delay
|
||||||
|
startup-tax-check: false
|
||||||
|
|
||||||
|
# Delay in seconds before startup tax check runs
|
||||||
|
startup-tax-delay-seconds: 30
|
||||||
|
|
||||||
|
# If true, players with exempt permission bypass taxes
|
||||||
|
permission-exempt: true
|
||||||
|
|
||||||
|
# If true, OP players bypass taxes
|
||||||
|
op-exempt: true
|
||||||
|
|
||||||
|
# If true, tax amount is rounded to 2 decimals
|
||||||
|
round-to-cents: true
|
||||||
|
|
||||||
|
announcement:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
# Broadcast to online players with dirttaxes.notify
|
||||||
|
notify-online-staff: true
|
||||||
|
|
||||||
|
# Also send to console
|
||||||
|
log-to-console: true
|
||||||
|
|
||||||
|
# Message for staff/console announcements
|
||||||
|
staff-message: "&6IRS &8- &eTook &c$%amount% &efrom &b%player%&e. New balance: &a$%new_balance%"
|
||||||
|
|
||||||
|
# Optional message sent to the player next time they join
|
||||||
|
store-offline-message: true
|
||||||
|
join-message: "&6IRS &8- &eTook &c$%amount% &efrom your account while you were away. New balance: &a$%new_balance%"
|
||||||
|
|
||||||
|
debt:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
# If player balance is 0 or below, add this flat debt per cycle
|
||||||
|
flat-debt-per-cycle: 500.0
|
||||||
|
|
||||||
|
# Funny extra interest percent applied to negative balances
|
||||||
|
# Example: -1000 with 2.5% becomes -1025 before flat debt
|
||||||
|
negative-interest-percent: 2.5
|
||||||
|
|
||||||
|
# IMPORTANT:
|
||||||
|
# When true, negative/debt taxation uses a configurable console command
|
||||||
|
# instead of Vault withdrawPlayer().
|
||||||
|
#
|
||||||
|
# Use this for economies like CMI where Vault may not push balances below 0.
|
||||||
|
use-command-for-debt: true
|
||||||
|
|
||||||
|
# Console command used to apply debt.
|
||||||
|
# Placeholders:
|
||||||
|
# %player% = player name
|
||||||
|
# %amount% = amount being added as debt this cycle
|
||||||
|
# %old_balance% = previous balance
|
||||||
|
# %new_balance% = expected new balance after tax
|
||||||
|
#
|
||||||
|
# Examples you can try on your server:
|
||||||
|
# command: "cmi money take %player% %amount%"
|
||||||
|
# command: "money take %player% %amount%"
|
||||||
|
# command: "cmi money set %player% %new_balance%"
|
||||||
|
command: "cmi money set %player% %new_balance%"
|
||||||
|
|
||||||
|
# If true, announce/log if command mode fails to actually change balance
|
||||||
|
warn-if-command-fails: true
|
||||||
|
|
||||||
|
# Broadcast when someone falls deeper into debt
|
||||||
|
announce-debt: true
|
||||||
|
debt-message: "&4IRS &8- &c%player% is now drowning in debt. Balance: $%new_balance%"
|
||||||
|
|
||||||
|
fun:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
# Send a random funny IRS line to the player on join if they were taxed offline
|
||||||
|
send-funny-line-to-player: true
|
||||||
|
|
||||||
|
# Also include funny line in staff alerts
|
||||||
|
include-funny-line-in-staff-alerts: true
|
||||||
|
|
||||||
|
random-funny-lines: true
|
||||||
|
funny-lines:
|
||||||
|
- "&7[IRS] Asset seizure successful."
|
||||||
|
- "&7[IRS] Another loyal citizen has contributed."
|
||||||
|
- "&7[IRS] Freedom isn’t free."
|
||||||
|
- "&7[IRS] Thank you for your involuntary donation."
|
||||||
|
- "&7[IRS] The tax goblin smiles."
|
||||||
|
- "&7[IRS] Audit complete. Wallet lighter."
|
||||||
|
- "&7[IRS] Your wallet has been selected for routine maintenance."
|
||||||
|
- "&7[IRS] We noticed you looked too comfortable."
|
||||||
|
- "&7[IRS] This concludes your surprise patriotism fee."
|
||||||
|
- "&7[IRS] You were fined for excessive wealth retention."
|
||||||
|
|
||||||
|
storage:
|
||||||
|
# Save pending join notifications to disk every tax cycle
|
||||||
|
save-pending-messages: true
|
||||||
|
|
||||||
|
messages:
|
||||||
|
prefix: "&6[DirtTaxes] &r"
|
||||||
|
no-permission: "&cYou do not have permission."
|
||||||
|
reloaded: "&aDirtTaxes reloaded."
|
||||||
|
usage: "&e/dirttaxes reload|info|setrate <percent>|setmaxdebt <negative>|setinterval <minutes>|forcetax [player]"
|
||||||
|
info: "&eTax rate: &f%rate%% &8| &eInterval: &f%interval%m &8| &eMax debt: &f$%maxdebt%"
|
||||||
|
set-rate-success: "&aTax rate set to &f%rate%%"
|
||||||
|
set-max-debt-success: "&aMax debt set to &f$%maxdebt%"
|
||||||
|
set-interval-success: "&aTax interval set to &f%interval% minutes"
|
||||||
|
force-tax-all-success: "&aForced tax cycle for all offline players."
|
||||||
|
force-tax-player-success: "&aForced tax for &f%player%"
|
||||||
|
player-not-found: "&cPlayer not found."
|
||||||
|
invalid-number: "&cInvalid number."
|
||||||
|
max-debt-must-be-negative: "&cMax debt must be 0 or less."
|
||||||
|
interval-must-be-positive: "&cInterval must be greater than 0."
|
||||||
|
rate-must-be-nonnegative: "&cTax rate must be 0 or greater."
|
||||||
|
debt-command-failed: "&cDebt command did not appear to change %player%'s balance."
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
name: DirtTaxes
|
||||||
|
version: 1.0.0
|
||||||
|
main: com.bitnix.dirttaxes.DirtTaxesPlugin
|
||||||
|
api-version: '1.21'
|
||||||
|
depend: [Vault]
|
||||||
|
|
||||||
|
commands:
|
||||||
|
dirttaxes:
|
||||||
|
description: Main DirtTaxes command
|
||||||
|
usage: /dirttaxes
|
||||||
|
aliases: [taxes, irs]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
dirttaxes.use:
|
||||||
|
default: op
|
||||||
|
dirttaxes.reload:
|
||||||
|
default: op
|
||||||
|
dirttaxes.setrate:
|
||||||
|
default: op
|
||||||
|
dirttaxes.setmaxdebt:
|
||||||
|
default: op
|
||||||
|
dirttaxes.setinterval:
|
||||||
|
default: op
|
||||||
|
dirttaxes.forcetax:
|
||||||
|
default: op
|
||||||
|
dirttaxes.exempt:
|
||||||
|
default: false
|
||||||
|
dirttaxes.notify:
|
||||||
|
default: op
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,132 @@
|
|||||||
|
tax:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
# How often offline players are taxed, in minutes.
|
||||||
|
# 1440 = once per day
|
||||||
|
interval-minutes: 1440
|
||||||
|
|
||||||
|
# Percentage of current balance removed each tax cycle.
|
||||||
|
# 5.0 = 5%
|
||||||
|
rate-percent: 5.0
|
||||||
|
|
||||||
|
# Minimum tax amount if balance is above 0
|
||||||
|
minimum-tax: 1.0
|
||||||
|
|
||||||
|
# Maximum debt allowed. Once a player reaches this negative value,
|
||||||
|
# no more debt is added.
|
||||||
|
max-debt: -1000000.0
|
||||||
|
|
||||||
|
# Players offline at least this many minutes before they can be taxed
|
||||||
|
offline-minutes-required: 1440
|
||||||
|
|
||||||
|
# If true, tax all offline players on plugin startup after delay
|
||||||
|
startup-tax-check: false
|
||||||
|
|
||||||
|
# Delay in seconds before startup tax check runs
|
||||||
|
startup-tax-delay-seconds: 30
|
||||||
|
|
||||||
|
# If true, players with exempt permission bypass taxes
|
||||||
|
permission-exempt: true
|
||||||
|
|
||||||
|
# If true, OP players bypass taxes
|
||||||
|
op-exempt: true
|
||||||
|
|
||||||
|
# If true, tax amount is rounded to 2 decimals
|
||||||
|
round-to-cents: true
|
||||||
|
|
||||||
|
announcement:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
# Broadcast to online players with dirttaxes.notify
|
||||||
|
notify-online-staff: true
|
||||||
|
|
||||||
|
# Also send to console
|
||||||
|
log-to-console: true
|
||||||
|
|
||||||
|
# Message for staff/console announcements
|
||||||
|
staff-message: "&6IRS &8- &eTook &c$%amount% &efrom &b%player%&e. New balance: &a$%new_balance%"
|
||||||
|
|
||||||
|
# Optional message sent to the player next time they join
|
||||||
|
store-offline-message: true
|
||||||
|
join-message: "&6IRS &8- &eTook &c$%amount% &efrom your account while you were away. New balance: &a$%new_balance%"
|
||||||
|
|
||||||
|
debt:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
# If player balance is 0 or below, add this flat debt per cycle
|
||||||
|
flat-debt-per-cycle: 500.0
|
||||||
|
|
||||||
|
# Funny extra interest percent applied to negative balances
|
||||||
|
# Example: -1000 with 2.5% becomes -1025 before flat debt
|
||||||
|
negative-interest-percent: 2.5
|
||||||
|
|
||||||
|
# IMPORTANT:
|
||||||
|
# When true, negative/debt taxation uses a configurable console command
|
||||||
|
# instead of Vault withdrawPlayer().
|
||||||
|
#
|
||||||
|
# Use this for economies like CMI where Vault may not push balances below 0.
|
||||||
|
use-command-for-debt: true
|
||||||
|
|
||||||
|
# Console command used to apply debt.
|
||||||
|
# Placeholders:
|
||||||
|
# %player% = player name
|
||||||
|
# %amount% = amount being added as debt this cycle
|
||||||
|
# %old_balance% = previous balance
|
||||||
|
# %new_balance% = expected new balance after tax
|
||||||
|
#
|
||||||
|
# Examples you can try on your server:
|
||||||
|
# command: "cmi money take %player% %amount%"
|
||||||
|
# command: "money take %player% %amount%"
|
||||||
|
# command: "cmi money set %player% %new_balance%"
|
||||||
|
command: "cmi money set %player% %new_balance%"
|
||||||
|
|
||||||
|
# If true, announce/log if command mode fails to actually change balance
|
||||||
|
warn-if-command-fails: true
|
||||||
|
|
||||||
|
# Broadcast when someone falls deeper into debt
|
||||||
|
announce-debt: true
|
||||||
|
debt-message: "&4IRS &8- &c%player% is now drowning in debt. Balance: $%new_balance%"
|
||||||
|
|
||||||
|
fun:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
# Send a random funny IRS line to the player on join if they were taxed offline
|
||||||
|
send-funny-line-to-player: true
|
||||||
|
|
||||||
|
# Also include funny line in staff alerts
|
||||||
|
include-funny-line-in-staff-alerts: true
|
||||||
|
|
||||||
|
random-funny-lines: true
|
||||||
|
funny-lines:
|
||||||
|
- "&7[IRS] Asset seizure successful."
|
||||||
|
- "&7[IRS] Another loyal citizen has contributed."
|
||||||
|
- "&7[IRS] Freedom isn’t free."
|
||||||
|
- "&7[IRS] Thank you for your involuntary donation."
|
||||||
|
- "&7[IRS] The tax goblin smiles."
|
||||||
|
- "&7[IRS] Audit complete. Wallet lighter."
|
||||||
|
- "&7[IRS] Your wallet has been selected for routine maintenance."
|
||||||
|
- "&7[IRS] We noticed you looked too comfortable."
|
||||||
|
- "&7[IRS] This concludes your surprise patriotism fee."
|
||||||
|
- "&7[IRS] You were fined for excessive wealth retention."
|
||||||
|
|
||||||
|
storage:
|
||||||
|
# Save pending join notifications to disk every tax cycle
|
||||||
|
save-pending-messages: true
|
||||||
|
|
||||||
|
messages:
|
||||||
|
prefix: "&6[DirtTaxes] &r"
|
||||||
|
no-permission: "&cYou do not have permission."
|
||||||
|
reloaded: "&aDirtTaxes reloaded."
|
||||||
|
usage: "&e/dirttaxes reload|info|setrate <percent>|setmaxdebt <negative>|setinterval <minutes>|forcetax [player]"
|
||||||
|
info: "&eTax rate: &f%rate%% &8| &eInterval: &f%interval%m &8| &eMax debt: &f$%maxdebt%"
|
||||||
|
set-rate-success: "&aTax rate set to &f%rate%%"
|
||||||
|
set-max-debt-success: "&aMax debt set to &f$%maxdebt%"
|
||||||
|
set-interval-success: "&aTax interval set to &f%interval% minutes"
|
||||||
|
force-tax-all-success: "&aForced tax cycle for all offline players."
|
||||||
|
force-tax-player-success: "&aForced tax for &f%player%"
|
||||||
|
player-not-found: "&cPlayer not found."
|
||||||
|
invalid-number: "&cInvalid number."
|
||||||
|
max-debt-must-be-negative: "&cMax debt must be 0 or less."
|
||||||
|
interval-must-be-positive: "&cInterval must be greater than 0."
|
||||||
|
rate-must-be-nonnegative: "&cTax rate must be 0 or greater."
|
||||||
|
debt-command-failed: "&cDebt command did not appear to change %player%'s balance."
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
name: DirtTaxes
|
||||||
|
version: 1.0.0
|
||||||
|
main: com.bitnix.dirttaxes.DirtTaxesPlugin
|
||||||
|
api-version: '1.21'
|
||||||
|
depend: [Vault]
|
||||||
|
|
||||||
|
commands:
|
||||||
|
dirttaxes:
|
||||||
|
description: Main DirtTaxes command
|
||||||
|
usage: /dirttaxes
|
||||||
|
aliases: [taxes, irs]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
dirttaxes.use:
|
||||||
|
default: op
|
||||||
|
dirttaxes.reload:
|
||||||
|
default: op
|
||||||
|
dirttaxes.setrate:
|
||||||
|
default: op
|
||||||
|
dirttaxes.setmaxdebt:
|
||||||
|
default: op
|
||||||
|
dirttaxes.setinterval:
|
||||||
|
default: op
|
||||||
|
dirttaxes.forcetax:
|
||||||
|
default: op
|
||||||
|
dirttaxes.exempt:
|
||||||
|
default: false
|
||||||
|
dirttaxes.notify:
|
||||||
|
default: op
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#Generated by Maven
|
||||||
|
#Sat Jun 20 11:12:19 EDT 2026
|
||||||
|
artifactId=DirtTaxes
|
||||||
|
groupId=com.bitnix
|
||||||
|
version=1.0.0
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
com/bitnix/dirttaxes/TaxJoinListener.class
|
||||||
|
com/bitnix/dirttaxes/DirtTaxesPlugin.class
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
/home/bitnix/Desktop/DirtTaxes/src/main/java/com/bitnix/dirttaxes/DirtTaxesPlugin.java
|
||||||
|
/home/bitnix/Desktop/DirtTaxes/src/main/java/com/bitnix/dirttaxes/TaxJoinListener.java
|
||||||
Reference in New Issue
Block a user