mirror of
https://github.com/NLthijs48/AreaShop.git
synced 2024-11-16 07:15:23 +01:00
Add hover/click support for messages #18
- Language files support a way to add hover tooltips, click commands and click insert commands (using FancyMessageFormat created together with PhoenixIV) - Language variables support arguments - Help listing (/as help) uses the new hover/click things, more to come - See #18 for the TODO list
This commit is contained in:
parent
49b536cab0
commit
aaff36b2eb
4
.gitignore
vendored
4
.gitignore
vendored
@ -28,4 +28,6 @@ local.properties
|
||||
.buildpath
|
||||
|
||||
# IntelliJ IDEA
|
||||
*.iml
|
||||
*.iml
|
||||
.idea
|
||||
dependency-reduced-pom.xml
|
@ -3,8 +3,6 @@ package nl.evolutioncoding.areashop;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
|
||||
import net.milkbowl.vault.economy.Economy;
|
||||
import nl.evolutioncoding.areashop.Updater.UpdateResult;
|
||||
import nl.evolutioncoding.areashop.Updater.UpdateType;
|
||||
import nl.evolutioncoding.areashop.features.DebugFeature;
|
||||
import nl.evolutioncoding.areashop.features.Feature;
|
||||
import nl.evolutioncoding.areashop.features.SignDisplayFeature;
|
||||
@ -12,17 +10,21 @@ import nl.evolutioncoding.areashop.features.WorldGuardRegionFlagsFeature;
|
||||
import nl.evolutioncoding.areashop.interfaces.AreaShopInterface;
|
||||
import nl.evolutioncoding.areashop.interfaces.WorldEditInterface;
|
||||
import nl.evolutioncoding.areashop.interfaces.WorldGuardInterface;
|
||||
import nl.evolutioncoding.areashop.lib.Metrics;
|
||||
import nl.evolutioncoding.areashop.lib.Updater;
|
||||
import nl.evolutioncoding.areashop.lib.Updater.UpdateResult;
|
||||
import nl.evolutioncoding.areashop.lib.Updater.UpdateType;
|
||||
import nl.evolutioncoding.areashop.listeners.PlayerLoginLogoutListener;
|
||||
import nl.evolutioncoding.areashop.listeners.SignBreakListener;
|
||||
import nl.evolutioncoding.areashop.listeners.SignChangeListener;
|
||||
import nl.evolutioncoding.areashop.listeners.SignClickListener;
|
||||
import nl.evolutioncoding.areashop.managers.CommandManager;
|
||||
import nl.evolutioncoding.areashop.managers.FileManager;
|
||||
import nl.evolutioncoding.areashop.managers.LanguageManager;
|
||||
import nl.evolutioncoding.areashop.managers.SignLinkerManager;
|
||||
import nl.evolutioncoding.areashop.messages.LanguageManager;
|
||||
import nl.evolutioncoding.areashop.messages.Message;
|
||||
import nl.evolutioncoding.areashop.regions.GeneralRegion;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
@ -35,8 +37,8 @@ import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Main class for the AreaShop plugin
|
||||
@ -55,7 +57,7 @@ public final class AreaShop extends JavaPlugin implements AreaShopInterface {
|
||||
private CommandManager commandManager = null;
|
||||
private SignLinkerManager signLinkerManager = null;
|
||||
private boolean debug = false;
|
||||
private String chatprefix = null;
|
||||
private List<String> chatprefix = null;
|
||||
private Updater updater = null;
|
||||
private boolean updateAvailable = false;
|
||||
private boolean ready = false;
|
||||
@ -335,7 +337,7 @@ public final class AreaShop extends JavaPlugin implements AreaShopInterface {
|
||||
* Set the chatprefix to use in the chat (loaded from config normally)
|
||||
* @param chatprefix The string to use in front of chat messages (supports formatting codes like &1)
|
||||
*/
|
||||
public void setChatprefix(String chatprefix) {
|
||||
public void setChatprefix(List<String> chatprefix) {
|
||||
this.chatprefix = chatprefix;
|
||||
}
|
||||
|
||||
@ -408,7 +410,7 @@ public final class AreaShop extends JavaPlugin implements AreaShopInterface {
|
||||
* Get the current chatPrefix
|
||||
* @return The current chatPrefix
|
||||
*/
|
||||
public String getChatPrefix() {
|
||||
public List<String> getChatPrefix() {
|
||||
return chatprefix;
|
||||
}
|
||||
|
||||
@ -549,50 +551,13 @@ public final class AreaShop extends JavaPlugin implements AreaShopInterface {
|
||||
}.runTaskLater(this, 20L);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to send a message to a CommandSender, using chatprefix if it is a player
|
||||
* @param target The CommandSender you wan't to send the message to (e.g. a player)
|
||||
* @param key The key to get the translation
|
||||
* @param prefix Specify if the message should have a prefix
|
||||
* @param params The parameters to inject into the message string
|
||||
*/
|
||||
public void configurableMessage(Object target, String key, boolean prefix, Object... params) {
|
||||
if(target == null) {
|
||||
return;
|
||||
}
|
||||
String langString = Utils.applyColors(languageManager.getLang(key, params));
|
||||
if(langString == null || langString.equals("")) {
|
||||
// Do nothing, message is not available or disabled
|
||||
} else {
|
||||
if(target instanceof Player) {
|
||||
if(prefix) {
|
||||
((Player)target).sendMessage(Utils.applyColors(chatprefix)+langString);
|
||||
} else {
|
||||
((Player)target).sendMessage(langString);
|
||||
}
|
||||
} else if(target instanceof CommandSender) {
|
||||
if(!getConfig().getBoolean("useColorsInConsole")) {
|
||||
langString = ChatColor.stripColor(langString);
|
||||
}
|
||||
((CommandSender)target).sendMessage(langString);
|
||||
}
|
||||
else if(target instanceof Logger) {
|
||||
if(!getConfig().getBoolean("useColorsInConsole")) {
|
||||
langString = ChatColor.stripColor(langString);
|
||||
}
|
||||
((Logger)target).info(langString);
|
||||
} else {
|
||||
langString = ChatColor.stripColor(langString);
|
||||
this.getLogger().info("Could not send message, target is wrong: " + langString);
|
||||
}
|
||||
}
|
||||
|
||||
public void messageNoPrefix(Object target, String key, Object... replacements) {
|
||||
Message.fromKey(key).replacements(replacements).send(target);
|
||||
}
|
||||
public void messageNoPrefix(Object target, String key, Object... params) {
|
||||
configurableMessage(target, key, false, params);
|
||||
}
|
||||
public void message(Object target, String key, Object... params) {
|
||||
configurableMessage(target, key, true, params);
|
||||
|
||||
public void message(Object target, String key, Object... replacements) {
|
||||
Message.fromKey(key).prefix().replacements(replacements).send(target);
|
||||
}
|
||||
|
||||
|
||||
|
@ -5,6 +5,7 @@ import com.sk89q.worldedit.bukkit.selections.CuboidSelection;
|
||||
import com.sk89q.worldedit.bukkit.selections.Selection;
|
||||
import com.sk89q.worldguard.protection.managers.RegionManager;
|
||||
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
|
||||
import nl.evolutioncoding.areashop.messages.Message;
|
||||
import nl.evolutioncoding.areashop.regions.BuyRegion;
|
||||
import nl.evolutioncoding.areashop.regions.GeneralRegion;
|
||||
import nl.evolutioncoding.areashop.regions.GeneralRegion.RegionType;
|
||||
@ -157,6 +158,47 @@ public class Utils {
|
||||
return milliseconds/50;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert milliseconds to a human readable format
|
||||
* @param milliseconds The amount of milliseconds to convert
|
||||
* @return A formatted string based on the language file
|
||||
*/
|
||||
public static String millisToHumanFormat(long milliseconds) {
|
||||
long timeLeft = milliseconds+500;
|
||||
// To seconds
|
||||
timeLeft = timeLeft/1000;
|
||||
if(timeLeft <= 0) {
|
||||
return Message.fromKey("timeleft-ended").getPlain();
|
||||
} else if(timeLeft == 1) {
|
||||
return Message.fromKey("timeleft-second").replacements(timeLeft).getPlain();
|
||||
} else if(timeLeft <= 120) {
|
||||
return Message.fromKey("timeleft-seconds").replacements(timeLeft).getPlain();
|
||||
}
|
||||
// To minutes
|
||||
timeLeft = timeLeft/60;
|
||||
if(timeLeft <= 120) {
|
||||
return Message.fromKey("timeleft-minutes").replacements(timeLeft).getPlain();
|
||||
}
|
||||
// To hours
|
||||
timeLeft = timeLeft/60;
|
||||
if(timeLeft <= 48) {
|
||||
return Message.fromKey("timeleft-hours").replacements(timeLeft).getPlain();
|
||||
}
|
||||
// To days
|
||||
timeLeft = timeLeft/24;
|
||||
if(timeLeft <= 60) {
|
||||
return Message.fromKey("timeleft-days").replacements(timeLeft).getPlain();
|
||||
}
|
||||
// To months
|
||||
timeLeft = timeLeft/30;
|
||||
if(timeLeft <= 24) {
|
||||
return Message.fromKey("timeleft-months").replacements(timeLeft).getPlain();
|
||||
}
|
||||
// To years
|
||||
timeLeft = timeLeft/12;
|
||||
return Message.fromKey("timeleft-years").replacements(timeLeft).getPlain();
|
||||
}
|
||||
|
||||
private static final BlockFace[] facings = {BlockFace.NORTH, BlockFace.NORTH_EAST, BlockFace.EAST, BlockFace.SOUTH_EAST, BlockFace.SOUTH, BlockFace.SOUTH_WEST, BlockFace.WEST, BlockFace.NORTH_WEST};
|
||||
|
||||
/**
|
||||
|
@ -32,7 +32,7 @@ public class AddCommand extends CommandAreaShop {
|
||||
@Override
|
||||
public String getHelp(CommandSender target) {
|
||||
if(target.hasPermission("areashop.createrent") || target.hasPermission("areashop.createbuy")) {
|
||||
return plugin.getLanguageManager().getLang("help-add");
|
||||
return "help-add";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -27,9 +27,9 @@ public class AddfriendCommand extends CommandAreaShop {
|
||||
@Override
|
||||
public String getHelp(CommandSender target) {
|
||||
if(target.hasPermission("areashop.addfriendall")) {
|
||||
return plugin.getLanguageManager().getLang("help-addFriendAll");
|
||||
return "help-addFriendAll";
|
||||
} else if(target.hasPermission("areashop.addfriend")) {
|
||||
return plugin.getLanguageManager().getLang("help-addFriend");
|
||||
return "help-addFriend";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ public class AddsignCommand extends CommandAreaShop {
|
||||
@Override
|
||||
public String getHelp(CommandSender target) {
|
||||
if(target.hasPermission("areashop.addsign")) {
|
||||
return plugin.getLanguageManager().getLang("help-addsign");
|
||||
return "help-addsign";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ public class BuyCommand extends CommandAreaShop {
|
||||
@Override
|
||||
public String getHelp(CommandSender target) {
|
||||
if(target.hasPermission("areashop.buy")) {
|
||||
return plugin.getLanguageManager().getLang("help-buy");
|
||||
return "help-buy";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -49,9 +49,9 @@ public abstract class CommandAreaShop {
|
||||
public abstract String getCommandStart();
|
||||
|
||||
/**
|
||||
* Returns the correct help string for the reciever
|
||||
* Returns the correct help string key to be used on the help page
|
||||
* @param target The CommandSender that the help message is for
|
||||
* @return The help message according to the permissions of the reciever
|
||||
* @return The help message key according to the permissions of the reciever
|
||||
*/
|
||||
public abstract String getHelp(CommandSender target);
|
||||
|
||||
|
@ -28,7 +28,7 @@ public class DelCommand extends CommandAreaShop {
|
||||
@Override
|
||||
public String getHelp(CommandSender target) {
|
||||
if(target.hasPermission("areashop.destroyrent") || target.hasPermission("areashop.destroybuy")) {
|
||||
return plugin.getLanguageManager().getLang("help-del");
|
||||
return "help-del";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -27,9 +27,9 @@ public class DelfriendCommand extends CommandAreaShop {
|
||||
@Override
|
||||
public String getHelp(CommandSender target) {
|
||||
if(target.hasPermission("areashop.delfriendall")) {
|
||||
return plugin.getLanguageManager().getLang("help-delFriendAll");
|
||||
return "help-delFriendAll";
|
||||
} else if(target.hasPermission("areashop.delfriend")) {
|
||||
return plugin.getLanguageManager().getLang("help-delFriend");
|
||||
return "help-delFriend";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ public class DelsignCommand extends CommandAreaShop {
|
||||
@Override
|
||||
public String getHelp(CommandSender target) {
|
||||
if(target.hasPermission("areashop.delsign")) {
|
||||
return plugin.getLanguageManager().getLang("help-delsign");
|
||||
return "help-delsign";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package nl.evolutioncoding.areashop.commands;
|
||||
|
||||
import nl.evolutioncoding.areashop.AreaShop;
|
||||
import nl.evolutioncoding.areashop.Utils;
|
||||
import nl.evolutioncoding.areashop.messages.Message;
|
||||
import nl.evolutioncoding.areashop.regions.BuyRegion;
|
||||
import nl.evolutioncoding.areashop.regions.RegionGroup;
|
||||
import nl.evolutioncoding.areashop.regions.RentRegion;
|
||||
@ -26,7 +27,7 @@ public class FindCommand extends CommandAreaShop {
|
||||
@Override
|
||||
public String getHelp(CommandSender target) {
|
||||
if(target.hasPermission("areashop.find")) {
|
||||
return plugin.getLanguageManager().getLang("help-find");
|
||||
return "help-find";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -84,9 +85,9 @@ public class FindCommand extends CommandAreaShop {
|
||||
if(!results.isEmpty()) {
|
||||
// Draw a random one
|
||||
BuyRegion region = results.get(new Random().nextInt(results.size()));
|
||||
String onlyInGroup = "";
|
||||
Message onlyInGroup = Message.none();
|
||||
if(group != null) {
|
||||
onlyInGroup = plugin.getLanguageManager().getLang("find-onlyInGroup", args[3]);
|
||||
onlyInGroup = Message.fromKey("find-onlyInGroup").replacements(args[3]);
|
||||
}
|
||||
if(maxPriceSet) {
|
||||
plugin.message(player, "find-successMax", "buy", Utils.formatCurrency(maxPrice), onlyInGroup, region);
|
||||
@ -95,9 +96,9 @@ public class FindCommand extends CommandAreaShop {
|
||||
}
|
||||
region.teleportPlayer(player, region.getBooleanSetting("general.findTeleportToSign"), false);
|
||||
} else {
|
||||
String onlyInGroup = "";
|
||||
Message onlyInGroup = Message.none();
|
||||
if(group != null) {
|
||||
onlyInGroup = plugin.getLanguageManager().getLang("find-onlyInGroup", args[3]);
|
||||
onlyInGroup = Message.fromKey("find-onlyInGroup").replacements(args[3]);
|
||||
}
|
||||
if(maxPriceSet) {
|
||||
plugin.message(player, "find-noneFoundMax", "buy", Utils.formatCurrency(maxPrice), onlyInGroup);
|
||||
@ -118,9 +119,9 @@ public class FindCommand extends CommandAreaShop {
|
||||
if(!results.isEmpty()) {
|
||||
// Draw a random one
|
||||
RentRegion region = results.get(new Random().nextInt(results.size()));
|
||||
String onlyInGroup = "";
|
||||
Message onlyInGroup = Message.none();
|
||||
if(group != null) {
|
||||
onlyInGroup = plugin.getLanguageManager().getLang("find-onlyInGroup", args[3]);
|
||||
onlyInGroup = Message.fromKey("find-onlyInGroup").replacements(args[3]);
|
||||
}
|
||||
if(maxPriceSet) {
|
||||
plugin.message(player, "find-successMax", "rent", Utils.formatCurrency(maxPrice), onlyInGroup, region);
|
||||
@ -129,9 +130,9 @@ public class FindCommand extends CommandAreaShop {
|
||||
}
|
||||
region.teleportPlayer(player, region.getBooleanSetting("general.findTeleportToSign"), false);
|
||||
} else {
|
||||
String onlyInGroup = "";
|
||||
Message onlyInGroup = Message.none();
|
||||
if(group != null) {
|
||||
onlyInGroup = plugin.getLanguageManager().getLang("find-onlyInGroup", args[3]);
|
||||
onlyInGroup = Message.fromKey("find-onlyInGroup").replacements(args[3]);
|
||||
}
|
||||
if(maxPriceSet) {
|
||||
plugin.message(player, "find-noneFoundMax", "rent", Utils.formatCurrency(maxPrice), onlyInGroup);
|
||||
|
@ -25,7 +25,7 @@ public class GroupaddCommand extends CommandAreaShop {
|
||||
@Override
|
||||
public String getHelp(CommandSender target) {
|
||||
if(target.hasPermission("areashop.groupadd")) {
|
||||
return plugin.getLanguageManager().getLang("help-groupadd");
|
||||
return "help-groupadd";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ public class GroupdelCommand extends CommandAreaShop {
|
||||
@Override
|
||||
public String getHelp(CommandSender target) {
|
||||
if(target.hasPermission("areashop.groupdel")) {
|
||||
return plugin.getLanguageManager().getLang("help-groupdel");
|
||||
return "help-groupdel";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ public class GroupinfoCommand extends CommandAreaShop {
|
||||
@Override
|
||||
public String getHelp(CommandSender target) {
|
||||
if(target.hasPermission("areashop.groupinfo")) {
|
||||
return plugin.getLanguageManager().getLang("help-groupinfo");
|
||||
return "help-groupinfo";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ public class GrouplistCommand extends CommandAreaShop {
|
||||
@Override
|
||||
public String getHelp(CommandSender target) {
|
||||
if(target.hasPermission("areashop.grouplist")) {
|
||||
return plugin.getLanguageManager().getLang("help-grouplist");
|
||||
return "help-grouplist";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ public class HelpCommand extends CommandAreaShop {
|
||||
@Override
|
||||
public String getHelp(CommandSender target) {
|
||||
if(target.hasPermission("areashop.help")) {
|
||||
return plugin.getLanguageManager().getLang("help-help");
|
||||
return "help-help";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package nl.evolutioncoding.areashop.commands;
|
||||
|
||||
import nl.evolutioncoding.areashop.AreaShop;
|
||||
import nl.evolutioncoding.areashop.Utils;
|
||||
import nl.evolutioncoding.areashop.messages.Message;
|
||||
import nl.evolutioncoding.areashop.regions.BuyRegion;
|
||||
import nl.evolutioncoding.areashop.regions.GeneralRegion;
|
||||
import nl.evolutioncoding.areashop.regions.RegionGroup;
|
||||
@ -27,7 +28,7 @@ public class InfoCommand extends CommandAreaShop {
|
||||
@Override
|
||||
public String getHelp(CommandSender target) {
|
||||
if(target.hasPermission("areashop.info")) {
|
||||
return plugin.getLanguageManager().getLang("help-info");
|
||||
return "help-info";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -225,7 +226,7 @@ public class InfoCommand extends CommandAreaShop {
|
||||
Location teleport = rent.getTeleportLocation();
|
||||
if(teleport == null) {
|
||||
if(rent.isRented()) {
|
||||
plugin.messageNoPrefix(sender, "info-regionNoTeleport", rent, plugin.getLanguageManager().getLang("info-regionTeleportHint", rent));
|
||||
plugin.messageNoPrefix(sender, "info-regionNoTeleport", rent, Message.fromKey("info-regionTeleportHint").replacements(rent));
|
||||
} else {
|
||||
plugin.messageNoPrefix(sender, "info-regionNoTeleport", rent, "");
|
||||
}
|
||||
@ -235,17 +236,17 @@ public class InfoCommand extends CommandAreaShop {
|
||||
}
|
||||
List<String> signLocations = new ArrayList<>();
|
||||
for(Location location : rent.getSignLocations()) {
|
||||
signLocations.add(plugin.getLanguageManager().getLang("info-regionSignLocation", location.getWorld().getName(), location.getBlockX(), location.getBlockY(), location.getBlockZ()));
|
||||
signLocations.add(Message.fromKey("info-regionSignLocation").replacements(location.getWorld().getName(), location.getBlockX(), location.getBlockY(), location.getBlockZ()).getPlain());
|
||||
}
|
||||
if(!signLocations.isEmpty()) {
|
||||
plugin.messageNoPrefix(sender, "info-regionSigns", Utils.createCommaSeparatedList(signLocations));
|
||||
plugin.messageNoPrefix(sender, "info-regionSigns", signLocations.toArray());
|
||||
}
|
||||
if(sender.hasPermission("areashop.groupinfo") && !rent.getGroupNames().isEmpty()) {
|
||||
plugin.messageNoPrefix(sender, "info-regionGroups", Utils.createCommaSeparatedList(rent.getGroupNames()));
|
||||
}
|
||||
if(rent.isRestoreEnabled()) {
|
||||
if(sender.hasPermission("areashop.setrestore")) {
|
||||
plugin.messageNoPrefix(sender, "info-regionRestoringRent", rent, plugin.getLanguageManager().getLang("info-regionRestoringProfile", rent.getRestoreProfile()));
|
||||
plugin.messageNoPrefix(sender, "info-regionRestoringRent", rent, Message.fromKey("info-regionRestoringProfile").replacements(rent.getRestoreProfile()));
|
||||
} else {
|
||||
plugin.messageNoPrefix(sender, "info-regionRestoringRent", rent, "");
|
||||
}
|
||||
@ -284,7 +285,7 @@ public class InfoCommand extends CommandAreaShop {
|
||||
Location teleport = buy.getTeleportLocation();
|
||||
if(teleport == null) {
|
||||
if(buy.isSold()) {
|
||||
plugin.messageNoPrefix(sender, "info-regionNoTeleport", buy, plugin.getLanguageManager().getLang("info-regionTeleportHint", buy));
|
||||
plugin.messageNoPrefix(sender, "info-regionNoTeleport", buy, Message.fromKey("info-regionTeleportHint").replacements(buy));
|
||||
} else {
|
||||
plugin.messageNoPrefix(sender, "info-regionNoTeleport", buy, "");
|
||||
}
|
||||
@ -294,17 +295,17 @@ public class InfoCommand extends CommandAreaShop {
|
||||
}
|
||||
List<String> signLocations = new ArrayList<>();
|
||||
for(Location location : buy.getSignLocations()) {
|
||||
signLocations.add(plugin.getLanguageManager().getLang("info-regionSignLocation", location.getWorld().getName(), location.getBlockX(), location.getBlockY(), location.getBlockZ()));
|
||||
signLocations.add(Message.fromKey("info-regionSignLocation").replacements(location.getWorld().getName(), location.getBlockX(), location.getBlockY(), location.getBlockZ()).getPlain());
|
||||
}
|
||||
if(!signLocations.isEmpty()) {
|
||||
plugin.messageNoPrefix(sender, "info-regionSigns", Utils.createCommaSeparatedList(signLocations));
|
||||
plugin.messageNoPrefix(sender, "info-regionSigns", signLocations.toArray());
|
||||
}
|
||||
if(sender.hasPermission("areashop.groupinfo") && !buy.getGroupNames().isEmpty()) {
|
||||
plugin.messageNoPrefix(sender, "info-regionGroups", Utils.createCommaSeparatedList(buy.getGroupNames()));
|
||||
}
|
||||
if(buy.isRestoreEnabled()) {
|
||||
if(sender.hasPermission("areashop.setrestore")) {
|
||||
plugin.messageNoPrefix(sender, "info-regionRestoringBuy", buy, plugin.getLanguageManager().getLang("info-regionRestoringProfile", buy.getRestoreProfile()));
|
||||
plugin.messageNoPrefix(sender, "info-regionRestoringBuy", buy, Message.fromKey("info-regionRestoringProfile").replacements(buy.getRestoreProfile()));
|
||||
} else {
|
||||
plugin.messageNoPrefix(sender, "info-regionRestoringBuy", buy, "");
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ public class LinksignsCommand extends CommandAreaShop {
|
||||
@Override
|
||||
public String getHelp(CommandSender target) {
|
||||
if(target.hasPermission("areashop.linksigns")) {
|
||||
return plugin.getLanguageManager().getLang("help-linksigns");
|
||||
return "help-linksigns";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ public class MeCommand extends CommandAreaShop {
|
||||
@Override
|
||||
public String getHelp(CommandSender target) {
|
||||
if(target.hasPermission("areashop.me")) {
|
||||
return plugin.getLanguageManager().getLang("help-me");
|
||||
return "help-me";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ public class ReloadCommand extends CommandAreaShop {
|
||||
@Override
|
||||
public String getHelp(CommandSender target) {
|
||||
if(target.hasPermission("areashop.reload")) {
|
||||
return plugin.getLanguageManager().getLang("help-reload");
|
||||
return "help-reload";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ public class RentCommand extends CommandAreaShop {
|
||||
@Override
|
||||
public String getHelp(CommandSender target) {
|
||||
if(target.hasPermission("areashop.rent")) {
|
||||
return plugin.getLanguageManager().getLang("help-rent");
|
||||
return "help-rent";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -23,9 +23,9 @@ public class ResellCommand extends CommandAreaShop {
|
||||
@Override
|
||||
public String getHelp(CommandSender target) {
|
||||
if(target.hasPermission("areashop.resellall")) {
|
||||
return plugin.getLanguageManager().getLang("help-resellAll");
|
||||
return "help-resellAll";
|
||||
} else if(target.hasPermission("areashop.resell")) {
|
||||
return plugin.getLanguageManager().getLang("help-resell");
|
||||
return "help-resell";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ public class SchematiceventCommand extends CommandAreaShop {
|
||||
@Override
|
||||
public String getHelp(CommandSender target) {
|
||||
if(target.hasPermission("areashop.schematicevents")) {
|
||||
return plugin.getLanguageManager().getLang("help-schemevent");
|
||||
return "help-schemevent";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -23,9 +23,9 @@ public class SellCommand extends CommandAreaShop {
|
||||
@Override
|
||||
public String getHelp(CommandSender target) {
|
||||
if(target.hasPermission("areashop.sell")) {
|
||||
return plugin.getLanguageManager().getLang("help-sell");
|
||||
return "help-sell";
|
||||
} else if(target.hasPermission("areashop.sellown")) {
|
||||
return plugin.getLanguageManager().getLang("help-sellOwn");
|
||||
return "help-sellOwn";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ public class SetdurationCommand extends CommandAreaShop {
|
||||
@Override
|
||||
public String getHelp(CommandSender target) {
|
||||
if(target.hasPermission("areashop.setduration")) {
|
||||
return plugin.getLanguageManager().getLang("help-setduration");
|
||||
return "help-setduration";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ public class SetlandlordCommand extends CommandAreaShop {
|
||||
@Override
|
||||
public String getHelp(CommandSender target) {
|
||||
if(target.hasPermission("areashop.setlandlord")) {
|
||||
return plugin.getLanguageManager().getLang("help-setlandlord");
|
||||
return "help-setlandlord";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ public class SetownerCommand extends CommandAreaShop {
|
||||
@Override
|
||||
public String getHelp(CommandSender target) {
|
||||
if(target.hasPermission("areashop.setownerrent") || target.hasPermission("areashop.setownerbuy")) {
|
||||
return plugin.getLanguageManager().getLang("help-setowner");
|
||||
return "help-setowner";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ public class SetpriceCommand extends CommandAreaShop {
|
||||
@Override
|
||||
public String getHelp(CommandSender target) {
|
||||
if(target.hasPermission("areashop.setprice")) {
|
||||
return plugin.getLanguageManager().getLang("help-setprice");
|
||||
return "help-setprice";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ public class SetrestoreCommand extends CommandAreaShop {
|
||||
@Override
|
||||
public String getHelp(CommandSender target) {
|
||||
if(target.hasPermission("areashop.setrestore")) {
|
||||
return plugin.getLanguageManager().getLang("help-setrestore");
|
||||
return "help-setrestore";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -26,9 +26,9 @@ public class SetteleportCommand extends CommandAreaShop {
|
||||
@Override
|
||||
public String getHelp(CommandSender target) {
|
||||
if(target.hasPermission("areashop.teleportall")) {
|
||||
return plugin.getLanguageManager().getLang("help-setteleportAll");
|
||||
return "help-setteleportAll";
|
||||
} else if(target.hasPermission("areashop.teleport")) {
|
||||
return plugin.getLanguageManager().getLang("help-setteleport");
|
||||
return "help-setteleport";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import com.sk89q.worldguard.protection.managers.RegionManager;
|
||||
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
|
||||
import nl.evolutioncoding.areashop.AreaShop;
|
||||
import nl.evolutioncoding.areashop.Utils;
|
||||
import nl.evolutioncoding.areashop.messages.Message;
|
||||
import nl.evolutioncoding.areashop.regions.BuyRegion;
|
||||
import nl.evolutioncoding.areashop.regions.GeneralRegion.RegionEvent;
|
||||
import nl.evolutioncoding.areashop.regions.RegionGroup;
|
||||
@ -33,7 +34,7 @@ public class StackCommand extends CommandAreaShop {
|
||||
@Override
|
||||
public String getHelp(CommandSender target) {
|
||||
if(target.hasPermission("areashop.stack")) {
|
||||
return plugin.getLanguageManager().getLang("help-stack");
|
||||
return "help-stack";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -124,9 +125,9 @@ public class StackCommand extends CommandAreaShop {
|
||||
} else {
|
||||
type = "buy";
|
||||
}
|
||||
String groupsMessage = "";
|
||||
Message groupsMessage = Message.none();
|
||||
if(group != null) {
|
||||
groupsMessage = plugin.getLanguageManager().getLang("stack-addToGroup", group.getName());
|
||||
groupsMessage = Message.fromKey("stack-addToGroup").replacements(group.getName());
|
||||
}
|
||||
plugin.message(player, "stack-accepted", amount, type, gap, namePrefix, groupsMessage);
|
||||
plugin.message(player, "stack-addStart", amount, regionsPerTick*20);
|
||||
|
@ -23,9 +23,9 @@ public class StopresellCommand extends CommandAreaShop {
|
||||
@Override
|
||||
public String getHelp(CommandSender target) {
|
||||
if(target.hasPermission("areashop.stopresellall")) {
|
||||
return plugin.getLanguageManager().getLang("help-stopResellAll");
|
||||
return "help-stopResellAll";
|
||||
} else if(target.hasPermission("areashop.stopresell")) {
|
||||
return plugin.getLanguageManager().getLang("help-stopResell");
|
||||
return "help-stopResell";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -22,9 +22,9 @@ public class TeleportCommand extends CommandAreaShop {
|
||||
@Override
|
||||
public String getHelp(CommandSender target) {
|
||||
if(target.hasPermission("areashop.teleportall")) {
|
||||
return plugin.getLanguageManager().getLang("help-teleportAll");
|
||||
return "help-teleportAll";
|
||||
} else if(target.hasPermission("areashop.teleport")) {
|
||||
return plugin.getLanguageManager().getLang("help-teleport");
|
||||
return "help-teleport";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -23,9 +23,9 @@ public class UnrentCommand extends CommandAreaShop {
|
||||
@Override
|
||||
public String getHelp(CommandSender target) {
|
||||
if(target.hasPermission("areashop.unrent")) {
|
||||
return plugin.getLanguageManager().getLang("help-unrent");
|
||||
return "help-unrent";
|
||||
} else if(target.hasPermission("areashop.unrentown")) {
|
||||
return plugin.getLanguageManager().getLang("help-unrentOwn");
|
||||
return "help-unrentOwn";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import com.sk89q.worldguard.protection.flags.RegionGroupFlag;
|
||||
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
|
||||
import nl.evolutioncoding.areashop.AreaShop;
|
||||
import nl.evolutioncoding.areashop.events.notify.RegionUpdateEvent;
|
||||
import nl.evolutioncoding.areashop.messages.Message;
|
||||
import nl.evolutioncoding.areashop.regions.GeneralRegion;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.event.EventHandler;
|
||||
@ -49,8 +50,7 @@ public class WorldGuardRegionFlagsFeature extends Feature implements Listener {
|
||||
}
|
||||
// Loop through all flags that are set in the config
|
||||
for(String flagName : flagNames) {
|
||||
String value = flags.getString(flagName);
|
||||
value = region.applyAllReplacements(value);
|
||||
String value = Message.fromString(flags.getString(flagName)).replacements(region).getPlain();
|
||||
// In the config normal Bukkit color codes are used, those only need to be translated on 5.X WorldGuard versions
|
||||
if(plugin.getWorldGuard().getDescription().getVersion().startsWith("5.")) {
|
||||
value = translateBukkitToWorldGuardColors(value);
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,14 +1,11 @@
|
||||
package nl.evolutioncoding.areashop.managers;
|
||||
|
||||
import nl.evolutioncoding.areashop.AreaShop;
|
||||
import nl.evolutioncoding.areashop.Utils;
|
||||
import nl.evolutioncoding.areashop.commands.*;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.TabCompleter;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -78,22 +75,17 @@ public class CommandManager implements CommandExecutor, TabCompleter {
|
||||
public void showHelp(CommandSender target) {
|
||||
// Add all messages to a list
|
||||
ArrayList<String> messages = new ArrayList<>();
|
||||
messages.add(plugin.getConfig().getString("chatPrefix") + plugin.getLanguageManager().getLang("help-header"));
|
||||
messages.add(plugin.getConfig().getString("chatPrefix") + plugin.getLanguageManager().getLang("help-alias"));
|
||||
plugin.message(target, "help-header");
|
||||
plugin.message(target, "help-alias");
|
||||
for(CommandAreaShop command : commands) {
|
||||
String help = command.getHelp(target);
|
||||
if(help != null && help.length() != 0) {
|
||||
messages.add(help);
|
||||
}
|
||||
}
|
||||
|
||||
// Send the messages to the target
|
||||
for(String message : messages) {
|
||||
if(!plugin.getConfig().getBoolean("useColorsInConsole") && !(target instanceof Player)) {
|
||||
target.sendMessage(ChatColor.stripColor(Utils.applyColors(message)));
|
||||
} else {
|
||||
target.sendMessage(Utils.applyColors(message));
|
||||
}
|
||||
plugin.messageNoPrefix(target, message);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -819,7 +819,13 @@ public class FileManager {
|
||||
config.addDefaults(YamlConfiguration.loadConfiguration(normal));
|
||||
// Set the debug and chatprefix variables
|
||||
plugin.setDebug(this.getConfig().getBoolean("debug"));
|
||||
plugin.setChatprefix(this.getConfig().getString("chatPrefix"));
|
||||
if(getConfig().isList("chatPrefix")) {
|
||||
plugin.setChatprefix(getConfig().getStringList("chatPrefix"));
|
||||
} else {
|
||||
ArrayList<String> list = new ArrayList<>();
|
||||
list.add(getConfig().getString("chatPrefix"));
|
||||
plugin.setChatprefix(list);
|
||||
}
|
||||
}
|
||||
} catch(IOException e) {
|
||||
plugin.getLogger().warning("Something went wrong while reading the config.yml file: " + configFile.getAbsolutePath());
|
||||
|
@ -1,199 +0,0 @@
|
||||
package nl.evolutioncoding.areashop.managers;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import nl.evolutioncoding.areashop.AreaShop;
|
||||
import nl.evolutioncoding.areashop.regions.GeneralRegion;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class LanguageManager {
|
||||
private AreaShop plugin = null;
|
||||
private String languages[] = {"EN", "NL", "DE", "CS", "FR", "FI", "PL"};
|
||||
private HashMap<String, String> currentLanguage, defaultLanguage;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param plugin The AreaShop plugin
|
||||
*/
|
||||
public LanguageManager(AreaShop plugin) {
|
||||
this.plugin = plugin;
|
||||
startup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the default language files and open the current and backup language file
|
||||
*/
|
||||
public void startup() {
|
||||
this.saveDefaults();
|
||||
this.loadLanguage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the default language files if not already present
|
||||
*/
|
||||
public void saveDefaults() {
|
||||
// Create the language folder if it not exists
|
||||
File langFolder;
|
||||
langFolder = new File(plugin.getDataFolder() + File.separator + AreaShop.languageFolder);
|
||||
if(!langFolder.exists()) {
|
||||
if(!langFolder.mkdirs()) {
|
||||
plugin.getLogger().warning("Could not create language directory: " + langFolder.getAbsolutePath());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the language files, overwrites if a file already exists
|
||||
// Overriding is necessary because otherwise with an update the new lang
|
||||
// files would not be used, when translating your own use another
|
||||
// file name as the default
|
||||
File langFile;
|
||||
for(String language : languages) {
|
||||
langFile = new File(plugin.getDataFolder() + File.separator + AreaShop.languageFolder + File.separator + language + ".yml");
|
||||
try(
|
||||
InputStream input = plugin.getResource(AreaShop.languageFolder + "/" + language + ".yml");
|
||||
OutputStream output = new FileOutputStream(langFile)
|
||||
) {
|
||||
if(input == null) {
|
||||
plugin.getLogger().warning("Could not save default language to the '" + AreaShop.languageFolder + "' folder: " + language + ".yml");
|
||||
continue;
|
||||
}
|
||||
int read;
|
||||
byte[] bytes = new byte[1024];
|
||||
while ((read = input.read(bytes)) != -1) {
|
||||
output.write(bytes, 0, read);
|
||||
}
|
||||
input.close();
|
||||
output.close();
|
||||
} catch(IOException e) {
|
||||
plugin.getLogger().warning("Something went wrong saving a default language file: " + langFile.getPath());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the current language file specified in the config
|
||||
*/
|
||||
public void loadLanguage() {
|
||||
Map<String, Object> map;
|
||||
Set<String> set;
|
||||
YamlConfiguration ymlFile;
|
||||
|
||||
// Save the current language file to the HashMap
|
||||
currentLanguage = new HashMap<>();
|
||||
File file = new File(plugin.getDataFolder() + File.separator + AreaShop.languageFolder + File.separator + plugin.getConfig().getString("language") + ".yml");
|
||||
|
||||
try(
|
||||
InputStreamReader reader = new InputStreamReader(new FileInputStream(file), Charsets.UTF_8)
|
||||
) {
|
||||
ymlFile = YamlConfiguration.loadConfiguration(reader);
|
||||
map = ymlFile.getValues(true);
|
||||
set = map.keySet();
|
||||
for(String key : set) {
|
||||
if(map.get(key) instanceof String) {
|
||||
currentLanguage.put(key, (String)map.get(key));
|
||||
}
|
||||
}
|
||||
} catch(IOException e) {
|
||||
plugin.getLogger().warning("Could not load set language file: " + file.getAbsolutePath());
|
||||
}
|
||||
|
||||
// Save the default strings to the HashMap
|
||||
defaultLanguage = new HashMap<>();
|
||||
File standard = new File(plugin.getDataFolder() + File.separator + AreaShop.languageFolder + "/" + languages[0]+ ".yml");
|
||||
try(
|
||||
InputStreamReader reader = new InputStreamReader(new FileInputStream(standard), Charsets.UTF_8)
|
||||
) {
|
||||
ymlFile = YamlConfiguration.loadConfiguration(reader);
|
||||
map = ymlFile.getValues(true);
|
||||
set = map.keySet();
|
||||
for(String key : set) {
|
||||
if(map.get(key) instanceof String) {
|
||||
defaultLanguage.put(key, (String)map.get(key));
|
||||
}
|
||||
}
|
||||
} catch(IOException e) {
|
||||
plugin.getLogger().warning("Could not load default language file: " + file.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to get the string in the language that has been set
|
||||
* @param key Key to the language string
|
||||
* @param params The replacements for the %1% tags
|
||||
* @return String The language string specified with the key
|
||||
*/
|
||||
public String getLang(String key, Object... params) {
|
||||
String result;
|
||||
|
||||
// Get the language string
|
||||
if(currentLanguage.containsKey(key)) {
|
||||
result = currentLanguage.get(key);
|
||||
} else {
|
||||
result = defaultLanguage.get(key);
|
||||
}
|
||||
|
||||
if(result == null) {
|
||||
plugin.getLogger().info("Wrong key for getting translation: " + key + ", please contact the author about this");
|
||||
} else {
|
||||
// Replace all tags like %0% and if given a GeneralRegion apply all replacements
|
||||
int number=0;
|
||||
for(Object param : params) {
|
||||
if(param != null) {
|
||||
if(param instanceof GeneralRegion) {
|
||||
result = ((GeneralRegion)param).applyAllReplacements(result);
|
||||
} else {
|
||||
result = result.replace("%" + number + "%", param.toString());
|
||||
number++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,107 @@
|
||||
package nl.evolutioncoding.areashop.messages;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Class made by glan3b (Github: https://github.com/glen3b) for the Fanciful project (Github: https://github.com/mkremins/fanciful)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a wrapper around an array class of an arbitrary reference type,
|
||||
* which properly implements "value" hash code and equality functions.
|
||||
* <p>
|
||||
* This class is intended for use as a key to a map.
|
||||
* </p>
|
||||
* @param <E> The type of elements in the array.
|
||||
* @author Glen Husman
|
||||
* @see Arrays
|
||||
*/
|
||||
public final class ArrayWrapper<E> {
|
||||
|
||||
/**
|
||||
* Creates an array wrapper with some elements.
|
||||
* @param elements The elements of the array.
|
||||
*/
|
||||
public ArrayWrapper(E... elements) {
|
||||
setArray(elements);
|
||||
}
|
||||
|
||||
private E[] _array;
|
||||
|
||||
/**
|
||||
* Retrieves a reference to the wrapped array instance.
|
||||
* @return The array wrapped by this instance.
|
||||
*/
|
||||
public E[] getArray() {
|
||||
return _array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this wrapper to wrap a new array instance.
|
||||
* @param array The new wrapped array.
|
||||
*/
|
||||
public void setArray(E[] array) {
|
||||
Validate.notNull(array, "The array must not be null.");
|
||||
_array = array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if this object has a value equivalent to another object.
|
||||
* @see Arrays#equals(Object[], Object[])
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if(!(other instanceof ArrayWrapper)) {
|
||||
return false;
|
||||
}
|
||||
return Arrays.equals(_array, ((ArrayWrapper)other)._array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the hash code represented by this objects value.
|
||||
* @return This object's hash code.
|
||||
* @see Arrays#hashCode(Object[])
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(_array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an iterable element collection to an array of elements.
|
||||
* The iteration order of the specified object will be used as the array element order.
|
||||
* @param list The iterable of objects which will be converted to an array.
|
||||
* @param c The type of the elements of the array.
|
||||
* @return An array of elements in the specified iterable.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T[] toArray(Iterable<? extends T> list, Class<T> c) {
|
||||
int size = -1;
|
||||
if(list instanceof Collection<?>) {
|
||||
@SuppressWarnings("rawtypes")
|
||||
Collection coll = (Collection)list;
|
||||
size = coll.size();
|
||||
}
|
||||
|
||||
|
||||
if(size < 0) {
|
||||
size = 0;
|
||||
// Ugly hack: Count it ourselves
|
||||
for(@SuppressWarnings("unused") T element : list) {
|
||||
size++;
|
||||
}
|
||||
}
|
||||
|
||||
T[] result = (T[])Array.newInstance(c, size);
|
||||
int i = 0;
|
||||
for(T element : list) { // Assumes iteration order is consistent
|
||||
result[i++] = element; // Assign array element at index THEN increment counter
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
@ -0,0 +1,853 @@
|
||||
package nl.evolutioncoding.areashop.messages;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* FancyMessageFormat converter, a library that enables to convert
|
||||
* messages in the FancyMessageFormat to Minecraft's bulky tellraw
|
||||
* format.
|
||||
* @author NLThijs48 | http://wiefferink.me
|
||||
* @author Tobias aka Phoenix | http://www.phoenix-iv.de
|
||||
*/
|
||||
public class FancyMessageFormat {
|
||||
|
||||
private static final char TAG_BEFORE = '[';
|
||||
private static final char TAG_AFTER = ']';
|
||||
private static final char END_TAG_INDICATOR = '/';
|
||||
|
||||
/**
|
||||
* The special character that prefixes all basic chat formatting codes.
|
||||
*/
|
||||
private static final char SIMPLE_FORMAT_PREFIX_CHAR = '\u00A7';
|
||||
|
||||
/**
|
||||
* Resets all previous chat colors or formats.
|
||||
*/
|
||||
private static final char SIMPLE_FORMAT_RESET_CHAR = 'r';
|
||||
|
||||
/**
|
||||
* Lookup table for all continuous tags (marked by [])
|
||||
*/
|
||||
private static final HashMap<String, Tag> BRACKET_TAG_LIST = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Lookup table for all interactive tags
|
||||
*/
|
||||
private static final HashMap<String, Tag> INTERACTIVE_TAG_LIST = new HashMap<>();
|
||||
|
||||
static {
|
||||
// Enlist all possible tags
|
||||
// (They go into a HashMap for lookup purposes)
|
||||
cacheTags(BRACKET_TAG_LIST, Color.class);
|
||||
cacheTags(BRACKET_TAG_LIST, FormatType.class);
|
||||
cacheTags(BRACKET_TAG_LIST, FormatCloseTag.class);
|
||||
cacheTags(BRACKET_TAG_LIST, ControlTag.class);
|
||||
// Interactive tags
|
||||
cacheTags(INTERACTIVE_TAG_LIST, ClickType.class);
|
||||
cacheTags(INTERACTIVE_TAG_LIST, HoverType.class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Puts all constants in the given Tag class into the given lookup table.
|
||||
*/
|
||||
private static <T extends Tag> void cacheTags(HashMap<String, Tag> tagList, Class<T> tags) {
|
||||
for(Tag tag : tags.getEnumConstants()) {
|
||||
for(String key : tag.getTags()) {
|
||||
tagList.put(key, tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------
|
||||
// ------------------------------- Public / Interface -------------------------------
|
||||
// ------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* Parses the given FancyMessageFormat message to a JSON array that can be
|
||||
* used with the tellraw command and the like.
|
||||
*/
|
||||
public static String convertToJSON(final String message) {
|
||||
return convertToJSON(Collections.singleton(message));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the given FancyMessageFormat message to a JSON array that can be
|
||||
* used with the tellraw command and the like.
|
||||
* @param inputLines Input message split at line breaks.
|
||||
*/
|
||||
public static String convertToJSON(final Iterable<String> inputLines) {
|
||||
ArrayList<String> lines = cleanInputString(inputLines);
|
||||
|
||||
LinkedList<InteractiveMessagePart> message = parse(lines);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if(message.size() == 1) {
|
||||
sb.append(message.getFirst().toJSON());
|
||||
} else if(message.size() > 0) {
|
||||
sb.append("{text=\"\",extra:[");
|
||||
for(InteractiveMessagePart messagePart : message) {
|
||||
sb.append(messagePart.toJSON());
|
||||
sb.append(',');
|
||||
}
|
||||
sb.deleteCharAt(sb.length()-1);
|
||||
sb.append("]}");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parses the given FancyMessageFormat message to a String containing control characters
|
||||
* for formatting that can be used for console outputs, but also for normal player
|
||||
* messages.
|
||||
* <p>
|
||||
* The returned message will only contain colors, bold, italic, underlining and 'magic'
|
||||
* characters. Hovers and other advanced tellraw tags will be skipped.
|
||||
* @param message Input message split at line breaks.
|
||||
*/
|
||||
public static String convertToConsole(final String message) {
|
||||
return convertToConsole(Collections.singleton(message));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the given FancyMessageFormat message to a String containing control characters
|
||||
* for formatting that can be used for console outputs, but also for normal player
|
||||
* messages.
|
||||
* <p>
|
||||
* The returned message will only contain colors, bold, italic, underlining and 'magic'
|
||||
* characters. Hovers and other advanced tellraw tags will be skipped.
|
||||
*/
|
||||
public static String convertToConsole(final Iterable<String> inputLines) {
|
||||
if(inputLines == null) {
|
||||
return null;
|
||||
}
|
||||
LinkedList<InteractiveMessagePart> parts = parse(inputLines, false);
|
||||
StringBuilder result = new StringBuilder();
|
||||
for(InteractiveMessagePart part : parts) {
|
||||
result.append(part.toSimpleString());
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Insert a message at the specified position
|
||||
* @param message The current message
|
||||
* @param insert The message to insert
|
||||
* @param line The line number to insert at
|
||||
* @param start The start of the variable to replace
|
||||
* @param end The end of the variable to replace
|
||||
*/
|
||||
public static void insertMessage(List<String> message, List<String> insert, int line, int start, int end) {
|
||||
String lineContent = message.remove(line);
|
||||
if(isTaggedInteractive(lineContent)) {
|
||||
lineContent = lineContent.replace("", "");
|
||||
message.add(line, lineContent.substring(0, start)+convertToConsole(insert)+lineContent.substring(end));
|
||||
return;
|
||||
}
|
||||
// Find interactive lines meant for this message
|
||||
List<String> interactives = new ArrayList<>();
|
||||
int index = line;
|
||||
while(index < message.size() && isTaggedInteractive(message.get(index))) {
|
||||
interactives.add(message.get(index));
|
||||
index++;
|
||||
}
|
||||
// Split the line and add the parts
|
||||
int at = line;
|
||||
if(start > 0) {
|
||||
message.add(line, lineContent.substring(0, start));
|
||||
at++;
|
||||
message.addAll(at, interactives);
|
||||
at += interactives.size();
|
||||
}
|
||||
message.addAll(at, insert);
|
||||
at += insert.size();
|
||||
message.addAll(at, interactives);
|
||||
at += interactives.size();
|
||||
if(end < (lineContent.length()-1)) {
|
||||
message.add(at, lineContent.substring(end));
|
||||
at++;
|
||||
message.addAll(at, interactives);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------
|
||||
// ------------------------------- Private functions -------------------------------
|
||||
// ------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* <ul>
|
||||
* <li>Splits lines at line breaks (creating a new line in the Array).
|
||||
* <li>Removes empty lines at the beginning.
|
||||
* <li>Removes lines with properties in front of the first text-line.
|
||||
* </ul>
|
||||
*/
|
||||
private static ArrayList<String> cleanInputString(Iterable<String> inputLines) {
|
||||
// Split lines at line breaks
|
||||
// In the end we will have a list with one line per element
|
||||
ArrayList<String> lines = new ArrayList<>();
|
||||
for(String line : inputLines) {
|
||||
lines.addAll(Arrays.asList(line.split("\\r?\\n")));
|
||||
}
|
||||
|
||||
// Remove any special lines at the start (a real text line should be first)
|
||||
while(!lines.isEmpty() && isTaggedInteractive(lines.get(0))) {
|
||||
lines.remove(0);
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
|
||||
private static LinkedList<InteractiveMessagePart> parse(Iterable<String> inputLines) {
|
||||
return parse(inputLines, true);
|
||||
}
|
||||
|
||||
private static LinkedList<InteractiveMessagePart> parse(final Iterable<String> inputLines, boolean doInteractives) {
|
||||
LinkedList<InteractiveMessagePart> message = new LinkedList<>();
|
||||
|
||||
Color currentColor = null;
|
||||
Set<FormatType> currentFormatting = new HashSet<>();
|
||||
|
||||
lineLoop:
|
||||
for(String line : inputLines) {
|
||||
InteractiveMessagePart messagePart;
|
||||
TaggedContent interactiveTag = getInteractiveTag(line);
|
||||
boolean isTextLine = interactiveTag == null;
|
||||
if(!doInteractives && !isTextLine) {
|
||||
continue;
|
||||
}
|
||||
boolean isHoverLine = false;
|
||||
|
||||
if(isTextLine) {
|
||||
messagePart = new InteractiveMessagePart();
|
||||
message.add(messagePart);
|
||||
} else /* if Interactive formatting */ {
|
||||
messagePart = message.getLast();
|
||||
Tag tag = interactiveTag.tag;
|
||||
if(tag instanceof ClickType) {
|
||||
messagePart.clickType = (ClickType)interactiveTag.tag;
|
||||
messagePart.clickContent = interactiveTag.subsequentContent;
|
||||
} else if(tag instanceof HoverType) {
|
||||
line = interactiveTag.subsequentContent;
|
||||
isHoverLine = true;
|
||||
if(messagePart.hoverType != tag) {
|
||||
// Hover type changed
|
||||
messagePart.hoverContent = new LinkedList<>();
|
||||
messagePart.hoverType = (HoverType)tag;
|
||||
}
|
||||
// Add hover content below
|
||||
}
|
||||
}
|
||||
|
||||
if(isTextLine || isHoverLine) {
|
||||
// Parse inline tags
|
||||
|
||||
Color currentLineColor = currentColor;
|
||||
Set<FormatType> currentLineFormatting = currentFormatting;
|
||||
LinkedList<TextMessagePart> targetList = messagePart.content;
|
||||
boolean parseBreak = true;
|
||||
if(isHoverLine) {
|
||||
// Reset - use own
|
||||
currentLineColor = null;
|
||||
currentLineFormatting = new HashSet<>();
|
||||
targetList = messagePart.hoverContent;
|
||||
parseBreak = false;
|
||||
|
||||
// Add line break after previous hover line
|
||||
if(!targetList.isEmpty()) {
|
||||
targetList.getLast().text += '\n';
|
||||
}
|
||||
}
|
||||
|
||||
// Split into pieces at places where formatting changes
|
||||
while(!line.isEmpty()) {
|
||||
String textToAdd;
|
||||
TaggedContent nextTag = getNextTag(line, parseBreak);
|
||||
boolean tagged = nextTag != null;
|
||||
|
||||
if(!tagged) {
|
||||
textToAdd = line;
|
||||
line = "";
|
||||
} else {
|
||||
textToAdd = nextTag.precedingContent;
|
||||
line = nextTag.subsequentContent;
|
||||
}
|
||||
|
||||
if(!textToAdd.isEmpty()) {
|
||||
// Add a text part with the correct formatting
|
||||
TextMessagePart part = new TextMessagePart();
|
||||
part.text = textToAdd;
|
||||
part.formatTypes = new HashSet<>(currentLineFormatting);
|
||||
part.color = currentLineColor;
|
||||
targetList.add(part);
|
||||
}
|
||||
|
||||
// Handle the change in formatting if a Tag has been detected (this needs to be after creating the InteractiveMessagePart)
|
||||
if(tagged) {
|
||||
// Handle the formatting tag
|
||||
Tag tag = nextTag.tag;
|
||||
if(tag instanceof Color) {
|
||||
currentLineColor = (Color)tag;
|
||||
} else if(tag instanceof FormatType) {
|
||||
currentLineFormatting.add((FormatType)tag);
|
||||
} else if(tag instanceof FormatCloseTag) {
|
||||
currentLineFormatting.remove(((FormatCloseTag)tag).closes);
|
||||
} else if(tag == ControlTag.BREAK) {
|
||||
targetList.getLast().text += '\n';
|
||||
continue lineLoop;
|
||||
} else if(tag == ControlTag.RESET) {
|
||||
currentLineFormatting.clear();
|
||||
currentLineColor = Color.WHITE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!isHoverLine) {
|
||||
// Adapt global attributes
|
||||
currentColor = currentLineColor;
|
||||
if(messagePart.content.size() == 0) { // Prevent interactive parts without content
|
||||
message.removeLast();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Searches and returns the first continuous tag found in the given String.
|
||||
* @return The tag (plus its preceding and subsequent content) if found.
|
||||
* Null if nothing is found.
|
||||
*/
|
||||
private static TaggedContent getNextTag(String line, boolean parseBreak) {
|
||||
Pattern pattern = Pattern.compile("\\[[a-zA-Z1-9]\\]|&[1-9abcdeflonskr]");
|
||||
Matcher matcher = pattern.matcher(line);
|
||||
// TODO Fix for escape things, and something with parseBreak?
|
||||
if(matcher.find()) {
|
||||
Tag tag = null;
|
||||
if(matcher.group().startsWith("&")) {
|
||||
for(Color color : Color.class.getEnumConstants()) {
|
||||
if(color.getNativeFormattingCode() == matcher.group().charAt(1)) {
|
||||
tag = color;
|
||||
}
|
||||
}
|
||||
for(FormatType format : FormatType.class.getEnumConstants()) {
|
||||
if(format.getNativeFormattingCode() == matcher.group().charAt(1)) {
|
||||
tag = format;
|
||||
}
|
||||
}
|
||||
if(matcher.group().charAt(1) == 'r') {
|
||||
tag = ControlTag.RESET;
|
||||
}
|
||||
} else {
|
||||
tag = BRACKET_TAG_LIST.get(matcher.group().substring(1, matcher.group().length()-1).toLowerCase());
|
||||
}
|
||||
return new TaggedContent(line.substring(0, matcher.start()), tag, line.substring(matcher.end()));
|
||||
}
|
||||
return null;
|
||||
|
||||
/*
|
||||
for(int startIndex = 0; startIndex < line.length(); startIndex++) {
|
||||
int start = line.indexOf(TAG_BEFORE, startIndex);
|
||||
if(start != -1) {
|
||||
int end = line.indexOf(TAG_AFTER, start);
|
||||
if(end != -1) {
|
||||
String inBetween = line.substring(start+1, end).toLowerCase();
|
||||
if(BRACKET_TAG_LIST.containsKey(inBetween)) {
|
||||
Tag tag = BRACKET_TAG_LIST.get(inBetween);
|
||||
if(tag == ControlTag.ESCAPE) {
|
||||
// Ignore next char
|
||||
line = line.substring(0, start)+line.substring(end+1);
|
||||
startIndex = start;
|
||||
} else if(!parseBreak && tag == ControlTag.ESCAPE) {
|
||||
// Ignore break
|
||||
startIndex = end+1;
|
||||
} else {
|
||||
String previousContent = line.substring(0, start);
|
||||
String subsequentContent = line.substring(end+1);
|
||||
return new TaggedContent(previousContent, tag, subsequentContent);
|
||||
}
|
||||
} else {
|
||||
startIndex = start;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If the given line defines an interactive property (e.g. "hover: myText")
|
||||
* the tag / property will be returned. Otherwise null is returned.
|
||||
*/
|
||||
private static TaggedContent getInteractiveTag(String line) {
|
||||
for(int index = 0; index < line.length(); index++) {
|
||||
char c = line.charAt(index);
|
||||
if(c == ' ' || c == '\t') {
|
||||
// Ignore (Skip spacing)
|
||||
} else {
|
||||
int end = line.indexOf(": ", index);
|
||||
if(end != -1) {
|
||||
String inBetween = line.substring(index, end).toLowerCase();
|
||||
if(INTERACTIVE_TAG_LIST.containsKey(inBetween)) {
|
||||
Tag tag = INTERACTIVE_TAG_LIST.get(inBetween);
|
||||
String subsequentContent = line.substring(end+2);
|
||||
return new TaggedContent(null, tag, subsequentContent);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if a line is an advanced declaration like hover or command
|
||||
* @param line The line to check
|
||||
* @return true if the line is interactive, false when it is a text line
|
||||
*/
|
||||
public static boolean isTaggedInteractive(String line) {
|
||||
return getInteractiveTag(line) != null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Produce a string in double quotes with backslash sequences in all the
|
||||
* right places.
|
||||
* @param string A String
|
||||
* @return A String correctly formatted for insertion in a JSON text.
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2002 JSON.org
|
||||
* Licensed under the Apache License, Version 2.0
|
||||
*/
|
||||
private static String quoteStringJson(String string) {
|
||||
if(string == null || string.length() == 0) {
|
||||
return "\"\"";
|
||||
}
|
||||
|
||||
char c;
|
||||
int i;
|
||||
int len = string.length();
|
||||
StringBuilder sb = new StringBuilder(len+4);
|
||||
String t;
|
||||
|
||||
sb.append('"');
|
||||
for(i = 0; i < len; i += 1) {
|
||||
c = string.charAt(i);
|
||||
switch(c) {
|
||||
case '\\':
|
||||
case '"':
|
||||
sb.append('\\');
|
||||
sb.append(c);
|
||||
break;
|
||||
case '/':
|
||||
sb.append('\\');
|
||||
sb.append(c);
|
||||
break;
|
||||
case '\b':
|
||||
sb.append("\\b");
|
||||
break;
|
||||
case '\t':
|
||||
sb.append("\\t");
|
||||
break;
|
||||
case '\n':
|
||||
sb.append("\\n");
|
||||
break;
|
||||
case '\f':
|
||||
sb.append("\\f");
|
||||
break;
|
||||
case '\r':
|
||||
sb.append("\\r");
|
||||
break;
|
||||
default:
|
||||
if(c < ' ') {
|
||||
t = "000"+Integer.toHexString(c);
|
||||
sb.append("\\u");
|
||||
sb.append(t.substring(t.length()-4));
|
||||
} else {
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
sb.append('"');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------
|
||||
// ------------------------------- Helper classes -------------------------------
|
||||
// ------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
private static class TaggedContent {
|
||||
final String precedingContent;
|
||||
final Tag tag;
|
||||
final String subsequentContent;
|
||||
|
||||
public TaggedContent(String pre, Tag tag, String sub) {
|
||||
this.precedingContent = pre;
|
||||
this.tag = tag;
|
||||
this.subsequentContent = sub;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Holds a string with basic (non-interactive) formatting.
|
||||
*/
|
||||
private static class TextMessagePart {
|
||||
String text = "";
|
||||
Color color = null;
|
||||
Set<FormatType> formatTypes = new HashSet<>();
|
||||
|
||||
/**
|
||||
* Get a simple colored/formatted string
|
||||
* @return String with formatting
|
||||
*/
|
||||
String toSimpleString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
// Color
|
||||
if(color != null) {
|
||||
sb.append(SIMPLE_FORMAT_PREFIX_CHAR);
|
||||
sb.append(color.getNativeFormattingCode());
|
||||
}
|
||||
// Formatting
|
||||
for(FormatType format : formatTypes) {
|
||||
sb.append(SIMPLE_FORMAT_PREFIX_CHAR);
|
||||
sb.append(format.getNativeFormattingCode());
|
||||
}
|
||||
// Text
|
||||
sb.append(text);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a JSON component for this message part
|
||||
* @return This part formatted in JSON
|
||||
*/
|
||||
String toJSON() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append('{');
|
||||
sb.append("text:").append(quoteStringJson(text));
|
||||
if(color != null && color != Color.WHITE) {
|
||||
sb.append(",color:").append(color.jsonValue);
|
||||
}
|
||||
for(FormatType formatting : formatTypes) {
|
||||
sb.append(',');
|
||||
sb.append(formatting.jsonKey).append(':');
|
||||
sb.append("true");
|
||||
}
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
boolean hasFormatting() {
|
||||
return !(color == Color.WHITE && formatTypes.isEmpty());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TextMessagePart(text:"+text+", color:"+color+", formatting:"+formatTypes.toString()+")";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Holds a string with interactive formatting.
|
||||
*/
|
||||
private static class InteractiveMessagePart {
|
||||
|
||||
LinkedList<TextMessagePart> content = new LinkedList<>();
|
||||
|
||||
// Click
|
||||
ClickType clickType = null;
|
||||
String clickContent = "";
|
||||
|
||||
// Hover
|
||||
HoverType hoverType = null;
|
||||
LinkedList<TextMessagePart> hoverContent = null;
|
||||
|
||||
/**
|
||||
* Get a simple colored/formatted string
|
||||
* @return String with formatting
|
||||
*/
|
||||
String toSimpleString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for(TextMessagePart part : content) {
|
||||
sb.append(part.toSimpleString());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a JSON component for this message part
|
||||
* @return This part formatted in JSON
|
||||
*/
|
||||
String toJSON() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if(content.size() == 1) {
|
||||
// Add attributes to TextMessagePart object
|
||||
sb.append(content.getFirst().toJSON());
|
||||
sb.deleteCharAt(sb.length()-1);
|
||||
} else {
|
||||
sb.append('{');
|
||||
sb.append("text=\"\",extra:[");
|
||||
for(TextMessagePart textPart : content) {
|
||||
sb.append(textPart.toJSON());
|
||||
sb.append(',');
|
||||
}
|
||||
sb.deleteCharAt(sb.length()-1);
|
||||
sb.append(']');
|
||||
}
|
||||
if(clickType != null) {
|
||||
sb.append(',');
|
||||
sb.append("clickEvent:{");
|
||||
sb.append("action:").append(clickType.getJsonKey()).append(',');
|
||||
sb.append("value:").append(quoteStringJson(clickContent));
|
||||
sb.append('}');
|
||||
}
|
||||
if(hoverType != null) {
|
||||
sb.append(',');
|
||||
sb.append("hoverEvent:{");
|
||||
sb.append("action:").append(hoverType.getJsonKey()).append(',');
|
||||
sb.append("value:");
|
||||
if(hoverContent.size() == 1) {
|
||||
TextMessagePart hoverPart = hoverContent.getFirst();
|
||||
if(hoverPart.hasFormatting()) {
|
||||
sb.append(hoverPart.toJSON());
|
||||
} else {
|
||||
sb.append(quoteStringJson(hoverPart.text));
|
||||
}
|
||||
} else {
|
||||
sb.append('[');
|
||||
for(TextMessagePart hoverPart : hoverContent) {
|
||||
sb.append(hoverPart.toJSON());
|
||||
sb.append(',');
|
||||
}
|
||||
sb.deleteCharAt(sb.length()-1);
|
||||
sb.append(']');
|
||||
}
|
||||
sb.append('}');
|
||||
}
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "InteractiveMessagePart(textMessageParts:"+content+", clickType:"+clickType+", clickContent:"+clickContent+", hoverType:"+hoverType+", hoverContent:"+hoverContent+")";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------- Tags ---------------------------------------
|
||||
|
||||
|
||||
interface Tag {
|
||||
/**
|
||||
* Tag text(s) used in the FancyMessageFormat (The text between '[' and ']')
|
||||
*/
|
||||
String[] getTags();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Indicates formatting that is applied until explicitly stopped.
|
||||
* Can also be used in simple Minecraft messages (Non-JSON).
|
||||
*/
|
||||
interface ContinuousTag extends Tag {
|
||||
/**
|
||||
* The character that defines upcoming formatting in a native (non-JSON) Minecraft message.
|
||||
*/
|
||||
char getNativeFormattingCode();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Indicates formatting that allows cursor interaction. Requires the
|
||||
* Minecraft JSON / tellraw format.
|
||||
*/
|
||||
interface InteractiveMessageTag extends Tag {
|
||||
String getJsonKey();
|
||||
}
|
||||
|
||||
|
||||
enum Color implements ContinuousTag {
|
||||
WHITE('f'),
|
||||
BLACK('0'),
|
||||
BLUE('9'),
|
||||
DARK_BLUE('1'),
|
||||
GREEN('a'),
|
||||
DARK_GREEN('2'),
|
||||
AQUA('b'),
|
||||
DARK_AQUA('3'),
|
||||
RED('c'),
|
||||
DARK_RED('4'),
|
||||
LIGHT_PURPLE('d'),
|
||||
DARK_PURPLE('5'),
|
||||
YELLOW('e'),
|
||||
GOLD('6'),
|
||||
GRAY('7'),
|
||||
DARK_GRAY('8');
|
||||
|
||||
final char bytecode;
|
||||
final String jsonValue;
|
||||
final String[] tags;
|
||||
|
||||
Color(char bytecode) {
|
||||
this.bytecode = bytecode;
|
||||
this.jsonValue = this.name().toLowerCase();
|
||||
this.tags = new String[]{this.name().toLowerCase()};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getTags() {
|
||||
return tags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getNativeFormattingCode() {
|
||||
return bytecode;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum FormatType implements ContinuousTag {
|
||||
BOLD('l', "bold", "b", "bold"),
|
||||
ITALIC('o', "italic", "i", "italic"),
|
||||
UNDERLINE('n', "underlined", "u", "underline"),
|
||||
STRIKETHROUGH('s', "strikethrough", "s", "strikethrough"),
|
||||
OBFUSCATE('k', "obfuscated", "obfuscate");
|
||||
|
||||
final char bytecode;
|
||||
final String jsonKey;
|
||||
final String[] tags;
|
||||
|
||||
FormatType(char bytecode, String jsonKey, String... tags) {
|
||||
this.bytecode = bytecode;
|
||||
this.jsonKey = jsonKey;
|
||||
this.tags = tags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getTags() {
|
||||
return tags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getNativeFormattingCode() {
|
||||
return bytecode;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
enum FormatCloseTag implements Tag {
|
||||
BOLD_END(FormatType.BOLD),
|
||||
ITALIC_END(FormatType.ITALIC),
|
||||
UNDERLINE_END(FormatType.UNDERLINE),
|
||||
STRIKETHROUGH_END(FormatType.STRIKETHROUGH),
|
||||
OBFUSCATE_END(FormatType.OBFUSCATE);
|
||||
|
||||
/**
|
||||
* Formatting that is stopped at this point
|
||||
*/
|
||||
final FormatType closes;
|
||||
private final String[] tags;
|
||||
|
||||
FormatCloseTag(FormatType openingTag) {
|
||||
this.closes = openingTag;
|
||||
|
||||
// Auto-generate close tags
|
||||
tags = new String[closes.tags.length];
|
||||
for(int i = 0; i < tags.length; i++) {
|
||||
tags[i] = END_TAG_INDICATOR+closes.tags[i];
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getTags() {
|
||||
return tags;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
enum ControlTag implements Tag {
|
||||
BREAK("break"),
|
||||
ESCAPE("esc"),
|
||||
RESET("reset");
|
||||
|
||||
private final String[] tags;
|
||||
|
||||
ControlTag(String... tags) {
|
||||
this.tags = tags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getTags() {
|
||||
return tags;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Types of clicking
|
||||
*/
|
||||
enum ClickType implements InteractiveMessageTag {
|
||||
LINK("open_url", "link"),
|
||||
COMMAND("run_command", "command"),
|
||||
SUGGEST("suggest_command", "suggest");
|
||||
|
||||
private final String jsonKey;
|
||||
private final String[] tags;
|
||||
|
||||
ClickType(String jsonKey, String... tags) {
|
||||
this.jsonKey = jsonKey;
|
||||
this.tags = tags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getTags() {
|
||||
return tags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getJsonKey() {
|
||||
return jsonKey;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum HoverType implements InteractiveMessageTag {
|
||||
HOVER;
|
||||
|
||||
@Override
|
||||
public String[] getTags() {
|
||||
return new String[]{"hover"};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getJsonKey() {
|
||||
return "show_text";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
package nl.evolutioncoding.areashop.messages;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
import java.util.logging.Level;
|
||||
|
||||
|
||||
/**
|
||||
* Methods written by the Fanciful project (Github: https://github.com/mkremins/fanciful)
|
||||
*/
|
||||
|
||||
public class FancyMessageSender {
|
||||
|
||||
private static Constructor<?> nmsPacketPlayOutChatConstructor;
|
||||
|
||||
public static boolean sendJSON(Player player, String jsonString) {
|
||||
try {
|
||||
Object handle = Reflection.getHandle(player);
|
||||
Object connection = Reflection.getField(handle.getClass(), "playerConnection").get(handle);
|
||||
Reflection.getMethod(connection.getClass(), "sendPacket", Reflection.getNMSClass("Packet")).invoke(connection, createChatPacket(jsonString));
|
||||
return true;
|
||||
} catch(IllegalArgumentException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e);
|
||||
} catch(IllegalAccessException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e);
|
||||
} catch(InstantiationException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Underlying class is abstract.", e);
|
||||
} catch(InvocationTargetException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "A error has occured durring invoking of method.", e);
|
||||
} catch(NoSuchMethodException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Could not find method.", e);
|
||||
} catch(ClassNotFoundException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Could not find class.", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// The ChatSerializer's instance of Gson
|
||||
private static Object nmsChatSerializerGsonInstance;
|
||||
private static Method fromJsonMethod;
|
||||
|
||||
private static Object createChatPacket(String json) throws IllegalArgumentException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, ClassNotFoundException {
|
||||
if(nmsChatSerializerGsonInstance == null) {
|
||||
// Find the field and its value, completely bypassing obfuscation
|
||||
Class<?> chatSerializerClazz;
|
||||
|
||||
String version = Reflection.getVersion();
|
||||
double majorVersion = Double.parseDouble(version.replace('_', '.').substring(1, 4));
|
||||
int lesserVersion = Integer.parseInt(version.substring(6, 7));
|
||||
|
||||
if(majorVersion < 1.8 || (majorVersion == 1.8 && lesserVersion == 1)) {
|
||||
chatSerializerClazz = Reflection.getNMSClass("ChatSerializer");
|
||||
} else {
|
||||
chatSerializerClazz = Reflection.getNMSClass("IChatBaseComponent$ChatSerializer");
|
||||
}
|
||||
|
||||
if(chatSerializerClazz == null) {
|
||||
throw new ClassNotFoundException("Can't find the ChatSerializer class");
|
||||
}
|
||||
|
||||
for(Field declaredField : chatSerializerClazz.getDeclaredFields()) {
|
||||
if(Modifier.isFinal(declaredField.getModifiers()) && Modifier.isStatic(declaredField.getModifiers()) && declaredField.getType().getName().endsWith("Gson")) {
|
||||
// We've found our field
|
||||
declaredField.setAccessible(true);
|
||||
nmsChatSerializerGsonInstance = declaredField.get(null);
|
||||
fromJsonMethod = nmsChatSerializerGsonInstance.getClass().getMethod("fromJson", String.class, Class.class);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Since the method is so simple, and all the obfuscated methods have the same name, it's easier to reimplement 'IChatBaseComponent a(String)' than to reflectively call it
|
||||
// Of course, the implementation may change, but fuzzy matches might break with signature changes
|
||||
Object serializedChatComponent = fromJsonMethod.invoke(nmsChatSerializerGsonInstance, json, Reflection.getNMSClass("IChatBaseComponent"));
|
||||
if(nmsPacketPlayOutChatConstructor == null) {
|
||||
try {
|
||||
nmsPacketPlayOutChatConstructor = Reflection.getNMSClass("PacketPlayOutChat").getDeclaredConstructor(Reflection.getNMSClass("IChatBaseComponent"));
|
||||
nmsPacketPlayOutChatConstructor.setAccessible(true);
|
||||
} catch(NoSuchMethodException e) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, "Could not find Minecraft method or constructor.", e);
|
||||
} catch(SecurityException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Could not access constructor.", e);
|
||||
}
|
||||
}
|
||||
return nmsPacketPlayOutChatConstructor.newInstance(serializedChatComponent);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,164 @@
|
||||
package nl.evolutioncoding.areashop.messages;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import nl.evolutioncoding.areashop.AreaShop;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import static nl.evolutioncoding.areashop.messages.Message.CHATLANGUAGEVARIABLE;
|
||||
|
||||
|
||||
public class LanguageManager {
|
||||
private AreaShop plugin = null;
|
||||
private String languages[] = {"EN", "NL", "DE", "CS", "FR", "FI", "PL"};
|
||||
private Map<String, List<String>> currentLanguage, defaultLanguage;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param plugin The AreaShop plugin
|
||||
*/
|
||||
public LanguageManager(AreaShop plugin) {
|
||||
this.plugin = plugin;
|
||||
startup();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the default language files and open the current and backup language file
|
||||
*/
|
||||
public void startup() {
|
||||
this.saveDefaults();
|
||||
currentLanguage = loadLanguage(plugin.getConfig().getString("language"));
|
||||
defaultLanguage = loadLanguage(languages[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the default language files if not already present
|
||||
*/
|
||||
public void saveDefaults() {
|
||||
// Create the language folder if it not exists
|
||||
File langFolder;
|
||||
langFolder = new File(plugin.getDataFolder()+File.separator+AreaShop.languageFolder);
|
||||
if(!langFolder.exists()) {
|
||||
if(!langFolder.mkdirs()) {
|
||||
plugin.getLogger().warning("Could not create language directory: "+langFolder.getAbsolutePath());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the language files, overwrites if a file already exists
|
||||
// Overriding is necessary because otherwise with an update the new lang
|
||||
// files would not be used, when translating your own use another
|
||||
// file name as the default
|
||||
File langFile;
|
||||
for(String language : languages) {
|
||||
langFile = new File(plugin.getDataFolder()+File.separator+AreaShop.languageFolder+File.separator+language+".yml");
|
||||
try(
|
||||
InputStream input = plugin.getResource(AreaShop.languageFolder+"/"+language+".yml");
|
||||
OutputStream output = new FileOutputStream(langFile)
|
||||
) {
|
||||
if(input == null) {
|
||||
plugin.getLogger().warning("Could not save default language to the '"+AreaShop.languageFolder+"' folder: "+language+".yml");
|
||||
continue;
|
||||
}
|
||||
int read;
|
||||
byte[] bytes = new byte[1024];
|
||||
while((read = input.read(bytes)) != -1) {
|
||||
output.write(bytes, 0, read);
|
||||
}
|
||||
input.close();
|
||||
output.close();
|
||||
} catch(IOException e) {
|
||||
plugin.getLogger().warning("Something went wrong saving a default language file: "+langFile.getPath());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the specified language
|
||||
* @param key The language to load
|
||||
*/
|
||||
public Map<String, List<String>> loadLanguage(String key) {
|
||||
Map<String, List<String>> result = new HashMap<>();
|
||||
|
||||
// Load the strings
|
||||
File file = new File(plugin.getDataFolder()+File.separator+AreaShop.languageFolder+File.separator+key+".yml");
|
||||
try(
|
||||
InputStreamReader reader = new InputStreamReader(new FileInputStream(file), Charsets.UTF_8)
|
||||
) {
|
||||
YamlConfiguration ymlFile = YamlConfiguration.loadConfiguration(reader);
|
||||
if(ymlFile.getKeys(false).isEmpty()) {
|
||||
plugin.getLogger().warning("Language file "+key+".yml has zero messages.");
|
||||
return result;
|
||||
}
|
||||
for(String messageKey : ymlFile.getKeys(false)) {
|
||||
if(ymlFile.isList(messageKey)) {
|
||||
result.put(messageKey, new ArrayList<>(ymlFile.getStringList(messageKey)));
|
||||
} else {
|
||||
result.put(messageKey, new ArrayList<>(Collections.singletonList(ymlFile.getString(messageKey))));
|
||||
}
|
||||
}
|
||||
} catch(IOException e) {
|
||||
plugin.getLogger().warning("Could not load set language file: "+file.getAbsolutePath());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the message for a certain key, without doing any processing
|
||||
* @param key The key of the message to get
|
||||
* @return The message as a list of strings
|
||||
*/
|
||||
public List<String> getRawMessage(String key) {
|
||||
List<String> message;
|
||||
if(key.equalsIgnoreCase(CHATLANGUAGEVARIABLE)) {
|
||||
message = plugin.getChatPrefix();
|
||||
} else if(currentLanguage.containsKey(key)) {
|
||||
message = currentLanguage.get(key);
|
||||
} else {
|
||||
message = defaultLanguage.get(key);
|
||||
}
|
||||
if(message == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return new ArrayList<>(message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,282 @@
|
||||
package nl.evolutioncoding.areashop.messages;
|
||||
|
||||
import nl.evolutioncoding.areashop.AreaShop;
|
||||
import nl.evolutioncoding.areashop.regions.GeneralRegion;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class Message {
|
||||
|
||||
public static final String VARIABLESTART = "%";
|
||||
public static final String VARIABLEEND = "%";
|
||||
public static final String LANGUAGEVARIABLE = "lang:";
|
||||
public static final String CHATLANGUAGEVARIABLE = "prefix";
|
||||
public static final int REPLACEMENTLIMIT = 50;
|
||||
|
||||
private List<String> message;
|
||||
private Object[] replacements;
|
||||
private String key = null;
|
||||
|
||||
/**
|
||||
* Internal use only
|
||||
*/
|
||||
private Message() {
|
||||
message = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Empty message object
|
||||
* @return this
|
||||
*/
|
||||
public static Message none() {
|
||||
return new Message();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a message from a language key
|
||||
* @param key The key of the message to use
|
||||
* @return this
|
||||
*/
|
||||
public static Message fromKey(String key) {
|
||||
return new Message().setMessageFromKey(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a message from a string
|
||||
* @param message The message to use
|
||||
* @return this
|
||||
*/
|
||||
public static Message fromString(String message) {
|
||||
AreaShop.debug("fromString: "+message);
|
||||
return new Message().setMessage(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a message from a string list
|
||||
* @param message The message to use
|
||||
* @return this
|
||||
*/
|
||||
public static Message fromString(List<String> message) {
|
||||
return new Message().setMessage(message);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the message with all replacements done
|
||||
* @return Message as a list
|
||||
*/
|
||||
public List<String> get() {
|
||||
executeReplacements();
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a plain string for the message (for example for using in the console)
|
||||
* @return The message as simple string
|
||||
*/
|
||||
public String getPlain() {
|
||||
executeReplacements();
|
||||
return FancyMessageFormat.convertToConsole(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the default prefix to the message
|
||||
* @param doIt true if the prefix should be added, otherwise false
|
||||
* @return this
|
||||
*/
|
||||
public Message prefix(boolean doIt) {
|
||||
if(doIt) {
|
||||
message.add(0, VARIABLESTART+LANGUAGEVARIABLE+CHATLANGUAGEVARIABLE+VARIABLEEND);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Message prefix() {
|
||||
return prefix(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the replacements to apply to the message
|
||||
* @param replacements The replacements to apply
|
||||
* - GeneralRegion: All region replacements are applied
|
||||
* - Message: Message is inserted
|
||||
* - other: index tag is replaced, like %0%
|
||||
* @return this
|
||||
*/
|
||||
public Message replacements(Object... replacements) {
|
||||
this.replacements = replacements;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send the message to a target
|
||||
* @param target The target to send the message to (Player, CommandSender, Logger)
|
||||
* @return this
|
||||
*/
|
||||
public Message send(Object target) {
|
||||
if(message == null || message.size() == 0 || (message.size() == 1 && message.get(0).length() == 0)) {
|
||||
return this;
|
||||
}
|
||||
executeReplacements();
|
||||
if(target instanceof Player) {
|
||||
if(AreaShop.getInstance().getConfig().getBoolean("useFancyMessages")) {
|
||||
FancyMessageSender.sendJSON((Player)target, FancyMessageFormat.convertToJSON(message));
|
||||
} else {
|
||||
((Player)target).sendMessage(FancyMessageFormat.convertToConsole(message));
|
||||
}
|
||||
} else {
|
||||
String plainMessage = FancyMessageFormat.convertToConsole(message);
|
||||
if(!AreaShop.getInstance().getConfig().getBoolean("useColorsInConsole")) {
|
||||
plainMessage = ChatColor.stripColor(plainMessage);
|
||||
}
|
||||
if(target instanceof CommandSender) {
|
||||
((CommandSender)target).sendMessage(plainMessage);
|
||||
} else if(target instanceof Logger) {
|
||||
((Logger)target).info(plainMessage);
|
||||
} else {
|
||||
AreaShop.getInstance().getLogger().warning("Could not send message, target is wrong: "+plainMessage);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
// INTERNAL METHODS
|
||||
|
||||
/**
|
||||
* Set the internal message
|
||||
* @param message The message to set
|
||||
* @return this
|
||||
*/
|
||||
private Message setMessage(List<String> message) {
|
||||
this.message = message;
|
||||
if(this.message == null) {
|
||||
this.message = new ArrayList<>();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the internal message with a key
|
||||
* @param key The message key to get the message for
|
||||
* @return this
|
||||
*/
|
||||
private Message setMessageFromKey(String key) {
|
||||
this.key = key;
|
||||
return this.setMessage(AreaShop.getInstance().getLanguageManager().getRawMessage(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the internal message with a string
|
||||
* @param message The message to set
|
||||
* @return this
|
||||
*/
|
||||
private Message setMessage(String message) {
|
||||
List<String> list = new ArrayList<>();
|
||||
list.add(message);
|
||||
return this.setMessage(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply all replacements to the message
|
||||
*/
|
||||
private void executeReplacements() {
|
||||
// Replace variables until they are all gone, or when the limit is reached
|
||||
Pattern variable = Pattern.compile(Pattern.quote(VARIABLESTART)+"[^%\\s]+"+Pattern.quote(VARIABLEEND));
|
||||
int round = 0;
|
||||
|
||||
boolean shouldReplace = true;
|
||||
while(shouldReplace) {
|
||||
List<String> original = new ArrayList<>(message);
|
||||
|
||||
replaceLanguageVariables();
|
||||
replaceArgumentVariables();
|
||||
|
||||
shouldReplace = !message.equals(original);
|
||||
round++;
|
||||
if(round > REPLACEMENTLIMIT) {
|
||||
AreaShop.getInstance().getLogger().warning("Reached replacement limit for message "+key+", probably has replacements loops, resulting message: "+message.toString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace argument variables in a message
|
||||
* The arguments to apply as replacements:
|
||||
* - If it is a GeneralRegion the replacements of the region will be applied
|
||||
* - Else the parameter will replace its number surrounded with VARIABLESTART and VARIABLEEND
|
||||
*/
|
||||
private void replaceArgumentVariables() {
|
||||
if(message == null || message.size() == 0 || replacements == null) {
|
||||
return;
|
||||
}
|
||||
boolean result = false;
|
||||
for(int i = 0; i < message.size(); i++) {
|
||||
int number = 0;
|
||||
for(Object param : replacements) {
|
||||
if(param != null) {
|
||||
if(param instanceof GeneralRegion) {
|
||||
message.set(i, ((GeneralRegion)param).applyAllReplacements(message.get(i)));
|
||||
} else if(param instanceof Message) {
|
||||
Pattern variables = Pattern.compile(Pattern.quote(VARIABLESTART)+i+Pattern.quote(VARIABLEEND));
|
||||
Matcher matches = variables.matcher(message.get(i));
|
||||
if(matches.find()) {
|
||||
String variable = matches.group();
|
||||
// insert message
|
||||
FancyMessageFormat.insertMessage(message, ((Message)param).get(), i, matches.start(), matches.end());
|
||||
// Reset to start of the line, redo matching because the line changed and the inserted part might contain variables again
|
||||
i--;
|
||||
}
|
||||
number++;
|
||||
} else {
|
||||
message.set(i, message.get(i).replace(VARIABLESTART+number+VARIABLEEND, param.toString()));
|
||||
number++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace all language variables in a message
|
||||
*/
|
||||
private void replaceLanguageVariables() {
|
||||
if(message == null || message.size() == 0) {
|
||||
return;
|
||||
}
|
||||
Pattern variables = Pattern.compile(Pattern.quote(VARIABLESTART)+"lang:[^%\\s]+(\\|[^"+Pattern.quote(VARIABLEEND)+"]*)*"+Pattern.quote(VARIABLEEND)); // Variables cannot contain spaces and percent characters, and area enclosed by percent characters
|
||||
for(int i = 0; i < message.size(); i++) {
|
||||
Matcher matches = variables.matcher(message.get(i));
|
||||
if(matches.find()) {
|
||||
String variable = matches.group();
|
||||
String key;
|
||||
Object[] arguments = null;
|
||||
if(variable.contains("|")) {
|
||||
key = variable.substring(6, variable.indexOf("|"));
|
||||
arguments = variable.substring(variable.indexOf("|")+1, variable.length()-1).split("\\|");
|
||||
} else {
|
||||
key = variable.substring(6, variable.length()-1);
|
||||
}
|
||||
Message insert = Message.fromKey(key);
|
||||
if(arguments != null) {
|
||||
insert.replacements(arguments);
|
||||
}
|
||||
|
||||
// insert message
|
||||
//List<String> insert = AreaShop.getInstance().getLanguageManager().getRawMessage(variable.substring(6, variable.length()-1));
|
||||
FancyMessageFormat.insertMessage(message, insert.get(), i, matches.start(), matches.end());
|
||||
// Reset to start of the line, redo matching because the line changed and the inserted part might contain language tags again
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,219 @@
|
||||
package nl.evolutioncoding.areashop.messages;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Class made by glan3b (Github: https://github.com/glen3b) for the Fanciful project (Github: https://github.com/mkremins/fanciful)
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* A class containing static utility methods and caches which are intended as reflective conveniences.
|
||||
* Unless otherwise noted, upon failure methods will return {@code null}.
|
||||
*/
|
||||
public final class Reflection {
|
||||
|
||||
private static String _versionString;
|
||||
|
||||
private Reflection() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the version string from the package name of the CraftBukkit server implementation.
|
||||
* This is needed to bypass the JAR package name changing on each update.
|
||||
* @return The version string of the OBC and NMS packages, <em>including the trailing dot</em>.
|
||||
*/
|
||||
public synchronized static String getVersion() {
|
||||
if(_versionString == null) {
|
||||
if(Bukkit.getServer() == null) {
|
||||
// The server hasn't started, static initializer call?
|
||||
return null;
|
||||
}
|
||||
String name = Bukkit.getServer().getClass().getPackage().getName();
|
||||
_versionString = name.substring(name.lastIndexOf('.')+1)+".";
|
||||
}
|
||||
|
||||
return _versionString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores loaded classes from the {@code net.minecraft.server} package.
|
||||
*/
|
||||
private static final Map<String, Class<?>> _loadedNMSClasses = new HashMap<String, Class<?>>();
|
||||
/**
|
||||
* Stores loaded classes from the {@code org.bukkit.craftbukkit} package (and subpackages).
|
||||
*/
|
||||
private static final Map<String, Class<?>> _loadedOBCClasses = new HashMap<String, Class<?>>();
|
||||
|
||||
/**
|
||||
* Gets a {@link Class} object representing a type contained within the {@code net.minecraft.server} versioned package.
|
||||
* The class instances returned by this method are cached, such that no lookup will be done twice (unless multiple threads are accessing this method simultaneously).
|
||||
* @param className The name of the class, excluding the package, within NMS.
|
||||
* @return The class instance representing the specified NMS class, or {@code null} if it could not be loaded.
|
||||
*/
|
||||
public synchronized static Class<?> getNMSClass(String className) {
|
||||
if(_loadedNMSClasses.containsKey(className)) {
|
||||
return _loadedNMSClasses.get(className);
|
||||
}
|
||||
|
||||
String fullName = "net.minecraft.server."+getVersion()+className;
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
clazz = Class.forName(fullName);
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
_loadedNMSClasses.put(className, null);
|
||||
return null;
|
||||
}
|
||||
_loadedNMSClasses.put(className, clazz);
|
||||
return clazz;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a {@link Class} object representing a type contained within the {@code org.bukkit.craftbukkit} versioned package.
|
||||
* The class instances returned by this method are cached, such that no lookup will be done twice (unless multiple threads are accessing this method simultaneously).
|
||||
* @param className The name of the class, excluding the package, within OBC. This name may contain a subpackage name, such as {@code inventory.CraftItemStack}.
|
||||
* @return The class instance representing the specified OBC class, or {@code null} if it could not be loaded.
|
||||
*/
|
||||
public synchronized static Class<?> getOBCClass(String className) {
|
||||
if(_loadedOBCClasses.containsKey(className)) {
|
||||
return _loadedOBCClasses.get(className);
|
||||
}
|
||||
|
||||
String fullName = "org.bukkit.craftbukkit."+getVersion()+className;
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
clazz = Class.forName(fullName);
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
_loadedOBCClasses.put(className, null);
|
||||
return null;
|
||||
}
|
||||
_loadedOBCClasses.put(className, clazz);
|
||||
return clazz;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to get the NMS handle of a CraftBukkit object.
|
||||
* <p>
|
||||
* The only match currently attempted by this method is a retrieval by using a parameterless {@code getHandle()} method implemented by the runtime type of the specified object.
|
||||
* </p>
|
||||
* @param obj The object for which to retrieve an NMS handle.
|
||||
* @return The NMS handle of the specified object, or {@code null} if it could not be retrieved using {@code getHandle()}.
|
||||
*/
|
||||
public synchronized static Object getHandle(Object obj) {
|
||||
try {
|
||||
return getMethod(obj.getClass(), "getHandle").invoke(obj);
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static final Map<Class<?>, Map<String, Field>> _loadedFields = new HashMap<Class<?>, Map<String, Field>>();
|
||||
|
||||
/**
|
||||
* Retrieves a {@link Field} instance declared by the specified class with the specified name.
|
||||
* Java access modifiers are ignored during this retrieval. No guarantee is made as to whether the field
|
||||
* returned will be an instance or static field.
|
||||
* <p>
|
||||
* A global caching mechanism within this class is used to store fields. Combined with synchronization, this guarantees that
|
||||
* no field will be reflectively looked up twice.
|
||||
* </p>
|
||||
* <p>
|
||||
* If a field is deemed suitable for return, {@link Field#setAccessible(boolean) setAccessible} will be invoked with an argument of {@code true} before it is returned.
|
||||
* This ensures that callers do not have to check or worry about Java access modifiers when dealing with the returned instance.
|
||||
* </p>
|
||||
* @param clazz The class which contains the field to retrieve.
|
||||
* @param name The declared name of the field in the class.
|
||||
* @return A field object with the specified name declared by the specified class.
|
||||
* @see Class#getDeclaredField(String)
|
||||
*/
|
||||
public synchronized static Field getField(Class<?> clazz, String name) {
|
||||
Map<String, Field> loaded;
|
||||
if(!_loadedFields.containsKey(clazz)) {
|
||||
loaded = new HashMap<String, Field>();
|
||||
_loadedFields.put(clazz, loaded);
|
||||
} else {
|
||||
loaded = _loadedFields.get(clazz);
|
||||
}
|
||||
if(loaded.containsKey(name)) {
|
||||
// If the field is loaded (or cached as not existing), return the relevant value, which might be null
|
||||
return loaded.get(name);
|
||||
}
|
||||
try {
|
||||
Field field = clazz.getDeclaredField(name);
|
||||
field.setAccessible(true);
|
||||
loaded.put(name, field);
|
||||
return field;
|
||||
} catch(Exception e) {
|
||||
// Error loading
|
||||
e.printStackTrace();
|
||||
// Cache field as not existing
|
||||
loaded.put(name, null);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains loaded methods in a cache.
|
||||
* The map maps [types to maps of [method names to maps of [parameter types to method instances]]].
|
||||
*/
|
||||
private static final Map<Class<?>, Map<String, Map<ArrayWrapper<Class<?>>, Method>>> _loadedMethods = new HashMap<Class<?>, Map<String, Map<ArrayWrapper<Class<?>>, Method>>>();
|
||||
|
||||
/**
|
||||
* Retrieves a {@link Method} instance declared by the specified class with the specified name and argument types.
|
||||
* Java access modifiers are ignored during this retrieval. No guarantee is made as to whether the field
|
||||
* returned will be an instance or static field.
|
||||
* <p>
|
||||
* A global caching mechanism within this class is used to store method. Combined with synchronization, this guarantees that
|
||||
* no method will be reflectively looked up twice.
|
||||
* </p>
|
||||
* <p>
|
||||
* If a method is deemed suitable for return, {@link Method#setAccessible(boolean) setAccessible} will be invoked with an argument of {@code true} before it is returned.
|
||||
* This ensures that callers do not have to check or worry about Java access modifiers when dealing with the returned instance.
|
||||
* </p>
|
||||
* <p>
|
||||
* This method does <em>not</em> search superclasses of the specified type for methods with the specified signature.
|
||||
* Callers wishing this behavior should use {@link Class#getDeclaredMethod(String, Class...)}.
|
||||
* @param clazz The class which contains the method to retrieve.
|
||||
* @param name The declared name of the method in the class.
|
||||
* @param args The formal argument types of the method.
|
||||
* @return A method object with the specified name declared by the specified class.
|
||||
*/
|
||||
public synchronized static Method getMethod(Class<?> clazz, String name,
|
||||
Class<?>... args) {
|
||||
if(!_loadedMethods.containsKey(clazz)) {
|
||||
_loadedMethods.put(clazz, new HashMap<String, Map<ArrayWrapper<Class<?>>, Method>>());
|
||||
}
|
||||
|
||||
Map<String, Map<ArrayWrapper<Class<?>>, Method>> loadedMethodNames = _loadedMethods.get(clazz);
|
||||
if(!loadedMethodNames.containsKey(name)) {
|
||||
loadedMethodNames.put(name, new HashMap<ArrayWrapper<Class<?>>, Method>());
|
||||
}
|
||||
|
||||
Map<ArrayWrapper<Class<?>>, Method> loadedSignatures = loadedMethodNames.get(name);
|
||||
ArrayWrapper<Class<?>> wrappedArg = new ArrayWrapper<Class<?>>(args);
|
||||
if(loadedSignatures.containsKey(wrappedArg)) {
|
||||
return loadedSignatures.get(wrappedArg);
|
||||
}
|
||||
|
||||
for(Method m : clazz.getMethods()) {
|
||||
if(m.getName().equals(name) && Arrays.equals(args, m.getParameterTypes())) {
|
||||
m.setAccessible(true);
|
||||
loadedSignatures.put(wrappedArg, m);
|
||||
return m;
|
||||
}
|
||||
}
|
||||
loadedSignatures.put(wrappedArg, null);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -243,7 +243,7 @@ public class BuyRegion extends GeneralRegion {
|
||||
* @return String indicating the inactive time until unrent
|
||||
*/
|
||||
public String getFormattedInactiveTimeUntilSell() {
|
||||
return this.millisToHumanFormat(getInactiveTimeUntilSell());
|
||||
return Utils.millisToHumanFormat(getInactiveTimeUntilSell());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -9,6 +9,7 @@ import nl.evolutioncoding.areashop.events.NotifyAreaShopEvent;
|
||||
import nl.evolutioncoding.areashop.events.notify.RegionUpdateEvent;
|
||||
import nl.evolutioncoding.areashop.interfaces.GeneralRegionInterface;
|
||||
import nl.evolutioncoding.areashop.managers.FileManager;
|
||||
import nl.evolutioncoding.areashop.messages.Message;
|
||||
import org.apache.commons.lang.exception.ExceptionUtils;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.block.Block;
|
||||
@ -23,8 +24,6 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public abstract class GeneralRegion implements GeneralRegionInterface, Comparable<GeneralRegion> {
|
||||
YamlConfiguration config;
|
||||
@ -549,23 +548,6 @@ public abstract class GeneralRegion implements GeneralRegionInterface, Comparabl
|
||||
if(source == null || source.length() == 0) {
|
||||
return "";
|
||||
}
|
||||
// Apply language replacements
|
||||
Pattern regex = Pattern.compile("%lang:[^% [-]]+%");
|
||||
Matcher matcher = regex.matcher(source);
|
||||
while(matcher.find()) {
|
||||
String match = matcher.group();
|
||||
String key = match.substring(6, match.length()-1);
|
||||
String languageString;
|
||||
if(key.equalsIgnoreCase("prefix")) {
|
||||
languageString = plugin.getChatPrefix();
|
||||
} else {
|
||||
languageString = plugin.getLanguageManager().getLang(key);
|
||||
}
|
||||
if(languageString != null) {
|
||||
source = source.replace(match, languageString);
|
||||
}
|
||||
//AreaShop.debug("match=" + match + ", key=" + key + ", lanString=" + languageString + ", replaced=" + source);
|
||||
}
|
||||
// Apply static replacements
|
||||
HashMap<String, Object> replacements = getAllReplacements();
|
||||
for(String tag : replacements.keySet()) {
|
||||
@ -781,7 +763,7 @@ public abstract class GeneralRegion implements GeneralRegionInterface, Comparabl
|
||||
Object[] newParams = new Object[params.length + 1];
|
||||
newParams[0] = this;
|
||||
System.arraycopy(params, 0, newParams, 1, params.length);
|
||||
plugin.configurableMessage(target, key, prefix, newParams);
|
||||
Message.fromKey(key).prefix(prefix).replacements(newParams).send(target);
|
||||
}
|
||||
|
||||
public void messageNoPrefix(Object target, String key, Object... params) {
|
||||
@ -892,47 +874,6 @@ public abstract class GeneralRegion implements GeneralRegionInterface, Comparabl
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert milliseconds to a human readable format
|
||||
* @param milliseconds The amount of milliseconds to convert
|
||||
* @return A formatted string based on the language file
|
||||
*/
|
||||
public String millisToHumanFormat(long milliseconds) {
|
||||
long timeLeft = milliseconds + 500;
|
||||
// To seconds
|
||||
timeLeft = timeLeft/1000;
|
||||
if(timeLeft <= 0) {
|
||||
return plugin.getLanguageManager().getLang("timeleft-ended");
|
||||
} else if(timeLeft == 1) {
|
||||
return plugin.getLanguageManager().getLang("timeleft-second", timeLeft);
|
||||
} else if(timeLeft <= 120) {
|
||||
return plugin.getLanguageManager().getLang("timeleft-seconds", timeLeft);
|
||||
}
|
||||
// To minutes
|
||||
timeLeft = timeLeft/60;
|
||||
if(timeLeft <= 120) {
|
||||
return plugin.getLanguageManager().getLang("timeleft-minutes", timeLeft);
|
||||
}
|
||||
// To hours
|
||||
timeLeft = timeLeft/60;
|
||||
if(timeLeft <= 48) {
|
||||
return plugin.getLanguageManager().getLang("timeleft-hours", timeLeft);
|
||||
}
|
||||
// To days
|
||||
timeLeft = timeLeft/24;
|
||||
if(timeLeft <= 60) {
|
||||
return plugin.getLanguageManager().getLang("timeleft-days", timeLeft);
|
||||
}
|
||||
// To months
|
||||
timeLeft = timeLeft/30;
|
||||
if(timeLeft <= 24) {
|
||||
return plugin.getLanguageManager().getLang("timeleft-months", timeLeft);
|
||||
}
|
||||
// To years
|
||||
timeLeft = timeLeft/12;
|
||||
return plugin.getLanguageManager().getLang("timeleft-years", timeLeft);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset all flags of the region
|
||||
*/
|
||||
@ -1123,7 +1064,7 @@ public abstract class GeneralRegion implements GeneralRegionInterface, Comparabl
|
||||
if(safeLocation.getBlockY()>256 || safeLocation.getBlockY()<0) {
|
||||
continue;
|
||||
}
|
||||
if((insideRegion && region.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ())) || !insideRegion) {
|
||||
if(region.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ()) || !insideRegion) {
|
||||
checked++;
|
||||
done = isSafe(safeLocation) || checked > maxTries;
|
||||
blocksInRegion = true;
|
||||
@ -1141,7 +1082,7 @@ public abstract class GeneralRegion implements GeneralRegionInterface, Comparabl
|
||||
if(safeLocation.getBlockY()>256 || safeLocation.getBlockY()<0) {
|
||||
continue;
|
||||
}
|
||||
if((insideRegion && region.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ())) || !insideRegion) {
|
||||
if(region.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ()) || !insideRegion) {
|
||||
checked++;
|
||||
done = isSafe(safeLocation) || checked > maxTries;
|
||||
blocksInRegion = true;
|
||||
@ -1159,7 +1100,7 @@ public abstract class GeneralRegion implements GeneralRegionInterface, Comparabl
|
||||
if(safeLocation.getBlockY()>256 || safeLocation.getBlockY()<0) {
|
||||
continue;
|
||||
}
|
||||
if((insideRegion && region.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ())) || !insideRegion) {
|
||||
if(region.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ()) || !insideRegion) {
|
||||
checked++;
|
||||
done = isSafe(safeLocation) || checked > maxTries;
|
||||
blocksInRegion = true;
|
||||
@ -1177,7 +1118,7 @@ public abstract class GeneralRegion implements GeneralRegionInterface, Comparabl
|
||||
if(safeLocation.getBlockY()>256 || safeLocation.getBlockY()<0) {
|
||||
continue;
|
||||
}
|
||||
if((insideRegion && region.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ())) || !insideRegion) {
|
||||
if(region.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ()) || !insideRegion) {
|
||||
checked++;
|
||||
done = isSafe(safeLocation) || checked > maxTries;
|
||||
blocksInRegion = true;
|
||||
@ -1195,7 +1136,7 @@ public abstract class GeneralRegion implements GeneralRegionInterface, Comparabl
|
||||
}
|
||||
if(!done && !top) {
|
||||
safeLocation = startLocation.clone().add(0, radius, 0);
|
||||
if((insideRegion && region.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ())) || !insideRegion) {
|
||||
if(region.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ()) || !insideRegion) {
|
||||
checked++;
|
||||
done = isSafe(safeLocation) || checked > maxTries;
|
||||
blocksInRegion = true;
|
||||
@ -1206,7 +1147,7 @@ public abstract class GeneralRegion implements GeneralRegionInterface, Comparabl
|
||||
// North
|
||||
for(int x=-r+1; x<=r && !done; x++) {
|
||||
safeLocation = startLocation.clone().add(x, radius, -r);
|
||||
if((insideRegion && region.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ())) || !insideRegion) {
|
||||
if(region.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ()) || !insideRegion) {
|
||||
checked++;
|
||||
done = isSafe(safeLocation) || checked > maxTries;
|
||||
blocksInRegion = true;
|
||||
@ -1216,7 +1157,7 @@ public abstract class GeneralRegion implements GeneralRegionInterface, Comparabl
|
||||
// East
|
||||
for(int z=-r+1; z<=r && !done; z++) {
|
||||
safeLocation = startLocation.clone().add(r, radius, z);
|
||||
if((insideRegion && region.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ())) || !insideRegion) {
|
||||
if(region.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ()) || !insideRegion) {
|
||||
checked++;
|
||||
done = isSafe(safeLocation) || checked > maxTries;
|
||||
blocksInRegion = true;
|
||||
@ -1226,7 +1167,7 @@ public abstract class GeneralRegion implements GeneralRegionInterface, Comparabl
|
||||
// South side
|
||||
for(int x=r-1; x>=-r && !done; x--) {
|
||||
safeLocation = startLocation.clone().add(x, radius, r);
|
||||
if((insideRegion && region.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ())) || !insideRegion) {
|
||||
if(region.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ()) || !insideRegion) {
|
||||
checked++;
|
||||
done = isSafe(safeLocation) || checked > maxTries;
|
||||
blocksInRegion = true;
|
||||
@ -1236,7 +1177,7 @@ public abstract class GeneralRegion implements GeneralRegionInterface, Comparabl
|
||||
// West side
|
||||
for(int z=r-1; z>=-r && !done; z--) {
|
||||
safeLocation = startLocation.clone().add(-r, radius, z);
|
||||
if((insideRegion && region.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ())) || !insideRegion) {
|
||||
if(region.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ()) || !insideRegion) {
|
||||
checked++;
|
||||
done = isSafe(safeLocation) || checked > maxTries;
|
||||
blocksInRegion = true;
|
||||
@ -1254,7 +1195,7 @@ public abstract class GeneralRegion implements GeneralRegionInterface, Comparabl
|
||||
}
|
||||
if(!done && !bottom) {
|
||||
safeLocation = startLocation.clone().add(0, -radius, 0);
|
||||
if((insideRegion && region.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ())) || !insideRegion) {
|
||||
if(region.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ()) || !insideRegion) {
|
||||
checked++;
|
||||
done = isSafe(safeLocation) || checked > maxTries;
|
||||
blocksInRegion = true;
|
||||
@ -1265,7 +1206,7 @@ public abstract class GeneralRegion implements GeneralRegionInterface, Comparabl
|
||||
// North
|
||||
for(int x=-r+1; x<=r && !done; x++) {
|
||||
safeLocation = startLocation.clone().add(x, -radius, -r);
|
||||
if((insideRegion && region.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ())) || !insideRegion) {
|
||||
if(region.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ()) || !insideRegion) {
|
||||
checked++;
|
||||
done = isSafe(safeLocation) || checked > maxTries;
|
||||
blocksInRegion = true;
|
||||
@ -1275,7 +1216,7 @@ public abstract class GeneralRegion implements GeneralRegionInterface, Comparabl
|
||||
// East
|
||||
for(int z=-r+1; z<=r && !done; z++) {
|
||||
safeLocation = startLocation.clone().add(r, -radius, z);
|
||||
if((insideRegion && region.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ())) || !insideRegion) {
|
||||
if(region.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ()) || !insideRegion) {
|
||||
checked++;
|
||||
done = isSafe(safeLocation) || checked > maxTries;
|
||||
blocksInRegion = true;
|
||||
@ -1285,7 +1226,7 @@ public abstract class GeneralRegion implements GeneralRegionInterface, Comparabl
|
||||
// South side
|
||||
for(int x=r-1; x>=-r && !done; x--) {
|
||||
safeLocation = startLocation.clone().add(x, -radius, r);
|
||||
if((insideRegion && region.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ())) || !insideRegion) {
|
||||
if(region.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ()) || !insideRegion) {
|
||||
checked++;
|
||||
done = isSafe(safeLocation) || checked > maxTries;
|
||||
blocksInRegion = true;
|
||||
@ -1295,7 +1236,7 @@ public abstract class GeneralRegion implements GeneralRegionInterface, Comparabl
|
||||
// West side
|
||||
for(int z=r-1; z>=-r && !done; z--) {
|
||||
safeLocation = startLocation.clone().add(-r, -radius, z);
|
||||
if((insideRegion && region.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ())) || !insideRegion) {
|
||||
if(region.contains(safeLocation.getBlockX(), safeLocation.getBlockY(), safeLocation.getBlockZ()) || !insideRegion) {
|
||||
checked++;
|
||||
done = isSafe(safeLocation) || checked > maxTries;
|
||||
blocksInRegion = true;
|
||||
|
@ -21,6 +21,8 @@ import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.UUID;
|
||||
|
||||
import static nl.evolutioncoding.areashop.Utils.millisToHumanFormat;
|
||||
|
||||
public class RentRegion extends GeneralRegion {
|
||||
private long warningsDoneUntil = Calendar.getInstance().getTimeInMillis();
|
||||
|
||||
@ -154,7 +156,7 @@ public class RentRegion extends GeneralRegion {
|
||||
}
|
||||
result.put(AreaShop.tagMaxExtends, this.getMaxExtends());
|
||||
result.put(AreaShop.tagExtendsLeft, getMaxExtends() - getTimesExtended());
|
||||
result.put(AreaShop.tagMaxRentTime, this.millisToHumanFormat(getMaxRentTime()));
|
||||
result.put(AreaShop.tagMaxRentTime, millisToHumanFormat(getMaxRentTime()));
|
||||
result.put(AreaShop.tagMaxInactiveTime, this.getFormattedInactiveTimeUntilUnrent());
|
||||
return result;
|
||||
}
|
||||
@ -251,7 +253,7 @@ public class RentRegion extends GeneralRegion {
|
||||
* @return Time left on the rent, for example '29 days', '3 months', '1 second'
|
||||
*/
|
||||
public String getTimeLeftString() {
|
||||
return millisToHumanFormat(getTimeLeft());
|
||||
return Utils.millisToHumanFormat(getTimeLeft());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -267,7 +269,7 @@ public class RentRegion extends GeneralRegion {
|
||||
* @return String indicating the inactive time until unrent
|
||||
*/
|
||||
public String getFormattedInactiveTimeUntilUnrent() {
|
||||
return this.millisToHumanFormat(getInactiveTimeUntilUnrent());
|
||||
return Utils.millisToHumanFormat(getInactiveTimeUntilUnrent());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -7,7 +7,12 @@
|
||||
# │ GENERAL: Options that influence the global state of the plugin │
|
||||
# └────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
## Chatprefix used for all messages in the chat, also changes the greeting messages.
|
||||
chatPrefix: '&2[AreaShop]&r '
|
||||
chatPrefix:
|
||||
- '&2[AreaShop]&r'
|
||||
- ' hover: &fAreaShop region management plugin'
|
||||
- ' hover: &fClick to check the available commands'
|
||||
- ' command: /areashop help'
|
||||
- ' '
|
||||
## The language file that should be used, check the 'lang' folder for build-in languages (use the filename without .yml here).
|
||||
## More information can be found here: https://github.com/NLthijs48/AreaShop/wiki/Language-support.
|
||||
language: EN
|
||||
@ -319,6 +324,8 @@ sendStats: true
|
||||
checkForUpdates: true
|
||||
## Use colors when sending messages to console and log files.
|
||||
useColorsInConsole: false
|
||||
## Use tellraw style messages
|
||||
useFancyMessages: true
|
||||
## Post error messages in the console when a command run from the config fails (from the 'runCommands' section for example).
|
||||
postCommandErrors: true
|
||||
## Update all region flags and signs after starting the plugin (uses the 'regionsPerTick' setting from the 'update' section).
|
||||
|
@ -1,4 +1,4 @@
|
||||
# ╔════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗
|
||||
# ╔════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗
|
||||
# ║ Language file of the AreaShop plugin created by NLThijs48, Github can be found at https://github.com/NLthijs48/AreaShop ║
|
||||
# ║ Language: English, Version: V2.2.2, Percentage translated: 100% (source), author: NLThijs48 ║
|
||||
# ║ This file will be overwritten at each startup/reload of the plugin, if you want to change anything then do the following: ║
|
||||
@ -8,6 +8,11 @@
|
||||
# ║ 4: Change the strings in the new file to your liking and save the file ║
|
||||
# ║ 5: Use '/as reload' or reload/restart your server to see the changes ║
|
||||
# ╚════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝
|
||||
command:
|
||||
- "&6%0% &7-&r"
|
||||
- " hover: &9&l<use %0%>"
|
||||
- " command: %0%"
|
||||
|
||||
total-maximum: "You can't rent and buy more than %0% region(s) in total (you already have %1% in group '%2%')."
|
||||
|
||||
general-notReady: "AreaShop has not fully loaded yet, please wait."
|
||||
@ -29,45 +34,45 @@ cmd-automaticRegionOnlyByPlayer: "Automatically determining the region is only p
|
||||
|
||||
help-header: "Help page, commands that you can execute."
|
||||
help-alias: "Command aliases: /areashop, /as."
|
||||
help-help: "&6/as help &7-&r Shows this help page."
|
||||
help-info: "&6/as info &7-&r Get info about current regions."
|
||||
help-rent: "&6/as rent &7-&r Rent a region or extend your current rent."
|
||||
help-buy: "&6/as buy &7-&r Buy a region."
|
||||
help-unrent: "&6/as unrent &7-&r Unrent a region."
|
||||
help-unrentOwn: "&6/as unrent &7-&r Unrent your own region."
|
||||
help-sell: "&6/as sell &7-&r Sell a region."
|
||||
help-sellOwn: "&6/as sell &7-&r Sell your own region."
|
||||
help-reload: "&6/as reload &7-&r Reload all files and update the regions."
|
||||
help-setrestore: "&6/as setrestore &7-&r Set restoring on/off and choose profile."
|
||||
help-setprice: "&6/as setprice &7-&r Change the price of a region."
|
||||
help-setduration: "&6/as setduration &7-&r Change the duration of a rent region."
|
||||
help-teleport: "&6/as tp &7-&r Teleport to your bought/rented regions."
|
||||
help-teleportAll: "&6/as tp &7-&r Teleport to a rent/buy region."
|
||||
help-setteleport: "&6/as settp &7-&r Set teleport position for bought/rented regions."
|
||||
help-setteleportAll: "&6/as settp &7-&r Set teleport position for a region."
|
||||
help-find: "&6/as find &7-&r Find an empty buy or rent."
|
||||
help-groupadd: "&6/as groupadd &7-&r Add a region to a group."
|
||||
help-groupdel: "&6/as groupdel &7-&r Delete a region from a group."
|
||||
help-grouplist: "&6/as grouplist &7-&r Display all groups currently registered."
|
||||
help-groupinfo: "&6/as groupinfo &7-&r Display information about a group."
|
||||
help-schemevent: "&6/as schemevent &7-&r Trigger a schematic event for a region."
|
||||
help-add: "&6/as add &7-&r Register a region as rent or buy."
|
||||
help-del: "&6/as del &7-&r Delete a registered region from AreaShop."
|
||||
help-addsign: "&6/as addsign &7-&r Add a sign to an existing region."
|
||||
help-delsign: "&6/as delsign &7-&r Delete the sign you are looking at."
|
||||
help-me: "&6/as me &7-&r Check which regions you have (+expiration)."
|
||||
help-setowner: "&6/as setowner &7-&r Set region owner or extend the rent."
|
||||
help-resell: "&6/as resell &7-&r Put one of your regions into resell mode."
|
||||
help-resellAll: "&6/as resell &7-&r Put a region into resell mode."
|
||||
help-stopResell: "&6/as stopresell &7-&r Put your region back into sold mode."
|
||||
help-stopResellAll: "&6/as stopresell &7-&r Put a region back into sold mode."
|
||||
help-addFriend: "&6/as addfriend &7-&r Add a friend to your region."
|
||||
help-addFriendAll: "&6/as addfriend &7-&r Add a friend to a region."
|
||||
help-delFriend: "&6/as delfriend &7-&r Delete a friend from your region."
|
||||
help-delFriendAll: "&6/as delfriend &7-&r Delete a friend from a region."
|
||||
help-linksigns: "&6/as linksigns &7-&r Use bulk sign linking mode."
|
||||
help-stack: "&6/as stack &7-&r Create multiple regions and add them."
|
||||
help-setlandlord: "&6/as setlandlord &7-&r Set the landlord of a region."
|
||||
help-help: "%lang:command|/as help% Shows this help page."
|
||||
help-info: "%lang:command|/as info% Get info about current regions."
|
||||
help-rent: "%lang:command|/as rent% Rent a region or extend your current rent."
|
||||
help-buy: "%lang:command|/as buy% Buy a region."
|
||||
help-unrent: "%lang:command|/as unrent% Unrent a region."
|
||||
help-unrentOwn: "%lang:command|/as unrent% Unrent your own region."
|
||||
help-sell: "%lang:command|/as sell% Sell a region."
|
||||
help-sellOwn: "%lang:command|/as sell% Sell your own region."
|
||||
help-reload: "%lang:command|/as reload% Reload all files and update the regions."
|
||||
help-setrestore: "%lang:command|/as setrestore% Set restoring on/off and choose profile."
|
||||
help-setprice: "%lang:command|/as setprice% Change the price of a region."
|
||||
help-setduration: "%lang:command|/as setduration% Change the duration of a rent region."
|
||||
help-teleport: "%lang:command|/as tp% Teleport to your bought/rented regions."
|
||||
help-teleportAll: "%lang:command|/as tp% Teleport to a rent/buy region."
|
||||
help-setteleport: "%lang:command|/as settp% Set teleport position for bought/rented regions."
|
||||
help-setteleportAll: "%lang:command|/as settp% Set teleport position for a region."
|
||||
help-find: "%lang:command|/as find% Find an empty buy or rent."
|
||||
help-groupadd: "%lang:command|/as groupadd% Add a region to a group."
|
||||
help-groupdel: "%lang:command|/as groupdel% Delete a region from a group."
|
||||
help-grouplist: "%lang:command|/as grouplist% Display all groups currently registered."
|
||||
help-groupinfo: "%lang:command|/as groupinfo% Display information about a group."
|
||||
help-schemevent: "%lang:command|/as schemevent% Trigger a schematic event for a region."
|
||||
help-add: "%lang:command|/as add% Register a region as rent or buy."
|
||||
help-del: "%lang:command|/as del% Delete a registered region from AreaShop."
|
||||
help-addsign: "%lang:command|/as addsign% Add a sign to an existing region."
|
||||
help-delsign: "%lang:command|/as delsign% Delete the sign you are looking at."
|
||||
help-me: "%lang:command|/as me% Check which regions you have (+expiration)."
|
||||
help-setowner: "%lang:command|/as setowner% Set region owner or extend the rent."
|
||||
help-resell: "%lang:command|/as resell% Put one of your regions into resell mode."
|
||||
help-resellAll: "%lang:command|/as resell% Put a region into resell mode."
|
||||
help-stopResell: "%lang:command|/as stopresell% Put your region back into sold mode."
|
||||
help-stopResellAll: "%lang:command|/as stopresell% Put a region back into sold mode."
|
||||
help-addFriend: "%lang:command|/as addfriend% Add a friend to your region."
|
||||
help-addFriendAll: "%lang:command|/as addfriend% Add a friend to a region."
|
||||
help-delFriend: "%lang:command|/as delfriend% Delete a friend from your region."
|
||||
help-delFriendAll: "%lang:command|/as delfriend% Delete a friend from a region."
|
||||
help-linksigns: "%lang:command|/as linksigns% Use bulk sign linking mode."
|
||||
help-stack: "%lang:command|/as stack% Create multiple regions and add them."
|
||||
help-setlandlord: "%lang:command|/as setlandlord% Set the landlord of a region."
|
||||
|
||||
rent-help: "/as rent [regionname], the region you stand in will be used if not specified."
|
||||
rent-noPermission: "You don't have permission to rent a region."
|
||||
@ -100,7 +105,7 @@ buy-succes: "You successfully bought %region%."
|
||||
buy-successResale: "You successfully bought %region% from %0%."
|
||||
buy-successSeller: "Your region %region% has been sold to %player% for %0%."
|
||||
buy-lowMoney: "You don't have enough money to buy this region (you have %0% and you need %price%)."
|
||||
buy-lowMoneyResell: "You don't have enugh money to buy this region (you have %0% and you need %resellprice%)."
|
||||
buy-lowMoneyResell: "You don't have enough money to buy this region (you have %0% and you need %resellprice%)."
|
||||
buy-yours: "You already own this region."
|
||||
buy-someoneElse: "Someone else already bought this region."
|
||||
buy-restrictedToWorld: "You need to be in the '%world%' world to buy this region (you are in '%0%')."
|
||||
|
Loading…
Reference in New Issue
Block a user