mirror of
https://github.com/PlaceholderAPI/PlaceholderAPI
synced 2025-09-08 00:46:15 +02:00
Changed command system (#304)
* Save Cacheable expansions data on shutdown * Prepare for 1.16 * 1.16.1 is out apparently * Further fixes, still not done * Inline JSONMessages & fix for 1.16 * Done :O * Done for real now, (hopefully) * Changed to static instead of DI for plugin instance * Cleanup * Modified tab completions. Removed extra command. * Apparently this is needed * Started cleaning stuff up basically just pushing so I can continue on laptop * did more cleaning, probs like half way done * more cleaning. reverted back to a min arg system somewhat similar to what frosty had, but less boilerplate. * Started debugging and fixing runtime/compile errors * Fixed bugs, still needs thorough testing * Re-enable metrics * relocated stuff again * - Remove json message relocation - uncomment other relocations - reformat pom - remove useless scope declaration - Fix metrics constructor - Switch commands to use inline json message Co-authored-by: iGabyTM <contactgabytm@gmail.com> Co-authored-by: darbyjack <admin@glaremasters.me> Co-authored-by: PiggyPiglet <noreply@piggypiglet.me>
This commit is contained in:
9
src/main/java/me/clip/placeholderapi/util/Constants.java
Normal file
9
src/main/java/me/clip/placeholderapi/util/Constants.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package me.clip.placeholderapi.util;
|
||||
|
||||
public class Constants {
|
||||
public static final String ADMIN_PERMISSION = "placeholderapi.admin";
|
||||
public static final String ECLOUD_PERMISSION = "placeholderapi.ecloud";
|
||||
public static final String INFO_PERMISSION = "placeholderapi.info";
|
||||
public static final String LIST_PERMISSION = "placeholderapi.list";
|
||||
public static final String RELOAD_PERMISSION = "placeholderapi.reload";
|
||||
}
|
@@ -33,76 +33,76 @@ import java.util.jar.JarInputStream;
|
||||
|
||||
public class FileUtil {
|
||||
|
||||
public static List<Class<?>> getClasses(String folder, Class<?> type) {
|
||||
return getClasses(folder, null, type);
|
||||
}
|
||||
public static List<Class<?>> getClasses(String folder, Class<?> type) {
|
||||
return getClasses(folder, null, type);
|
||||
}
|
||||
|
||||
public static List<Class<?>> getClasses(String folder, String fileName, Class<?> type) {
|
||||
List<Class<?>> list = new ArrayList<>();
|
||||
public static List<Class<?>> getClasses(String folder, String fileName, Class<?> type) {
|
||||
List<Class<?>> list = new ArrayList<>();
|
||||
|
||||
try {
|
||||
File f = new File(PlaceholderAPIPlugin.getInstance().getDataFolder(), folder);
|
||||
if (!f.exists()) {
|
||||
return list;
|
||||
}
|
||||
|
||||
FilenameFilter fileNameFilter = (dir, name) -> {
|
||||
if (fileName != null) {
|
||||
return name.endsWith(".jar") && name.replace(".jar", "")
|
||||
.equalsIgnoreCase(fileName.replace(".jar", ""));
|
||||
}
|
||||
|
||||
return name.endsWith(".jar");
|
||||
};
|
||||
|
||||
File[] jars = f.listFiles(fileNameFilter);
|
||||
if (jars == null) {
|
||||
return list;
|
||||
}
|
||||
|
||||
for (File file : jars) {
|
||||
list = gather(file.toURI().toURL(), list, type);
|
||||
}
|
||||
|
||||
return list;
|
||||
} catch (Throwable t) {
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static List<Class<?>> gather(URL jar, List<Class<?>> list, Class<?> clazz) {
|
||||
if (list == null) {
|
||||
list = new ArrayList<>();
|
||||
}
|
||||
|
||||
try (URLClassLoader cl = new URLClassLoader(new URL[]{jar}, clazz.getClassLoader());
|
||||
JarInputStream jis = new JarInputStream(jar.openStream())) {
|
||||
|
||||
while (true) {
|
||||
JarEntry j = jis.getNextJarEntry();
|
||||
if (j == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
String name = j.getName();
|
||||
if (name == null || name.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (name.endsWith(".class")) {
|
||||
name = name.replace("/", ".");
|
||||
String cname = name.substring(0, name.lastIndexOf(".class"));
|
||||
|
||||
Class<?> c = cl.loadClass(cname);
|
||||
if (clazz.isAssignableFrom(c)) {
|
||||
list.add(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
}
|
||||
|
||||
try {
|
||||
File f = new File(PlaceholderAPIPlugin.getInstance().getDataFolder(), folder);
|
||||
if (!f.exists()) {
|
||||
return list;
|
||||
}
|
||||
|
||||
FilenameFilter fileNameFilter = (dir, name) -> {
|
||||
if (fileName != null) {
|
||||
return name.endsWith(".jar") && name.replace(".jar", "")
|
||||
.equalsIgnoreCase(fileName.replace(".jar", ""));
|
||||
}
|
||||
|
||||
return name.endsWith(".jar");
|
||||
};
|
||||
|
||||
File[] jars = f.listFiles(fileNameFilter);
|
||||
if (jars == null) {
|
||||
return list;
|
||||
}
|
||||
|
||||
for (File file : jars) {
|
||||
list = gather(file.toURI().toURL(), list, type);
|
||||
}
|
||||
|
||||
return list;
|
||||
} catch (Throwable t) {
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static List<Class<?>> gather(URL jar, List<Class<?>> list, Class<?> clazz) {
|
||||
if (list == null) {
|
||||
list = new ArrayList<>();
|
||||
}
|
||||
|
||||
try (URLClassLoader cl = new URLClassLoader(new URL[]{jar}, clazz.getClassLoader());
|
||||
JarInputStream jis = new JarInputStream(jar.openStream())) {
|
||||
|
||||
while (true) {
|
||||
JarEntry j = jis.getNextJarEntry();
|
||||
if (j == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
String name = j.getName();
|
||||
if (name == null || name.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (name.endsWith(".class")) {
|
||||
name = name.replace("/", ".");
|
||||
String cname = name.substring(0, name.lastIndexOf(".class"));
|
||||
|
||||
Class<?> c = cl.loadClass(cname);
|
||||
if (clazz.isAssignableFrom(c)) {
|
||||
list.add(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
985
src/main/java/me/clip/placeholderapi/util/JSONMessage.java
Normal file
985
src/main/java/me/clip/placeholderapi/util/JSONMessage.java
Normal file
@@ -0,0 +1,985 @@
|
||||
package me.clip.placeholderapi.util;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.ImmutableBiMap;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* This is a complete JSON message builder class. To create a new JSONMessage do
|
||||
* {@link #create(String)}
|
||||
*
|
||||
* @author Rayzr
|
||||
*/
|
||||
@SuppressWarnings({"WeakerAccess", "unused"})
|
||||
public class JSONMessage {
|
||||
private static final BiMap<ChatColor, String> stylesToNames;
|
||||
|
||||
static {
|
||||
ImmutableBiMap.Builder<ChatColor, String> builder = ImmutableBiMap.builder();
|
||||
for (final ChatColor style : ChatColor.values()) {
|
||||
if (!style.isFormat()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String styleName;
|
||||
switch (style) {
|
||||
case MAGIC:
|
||||
styleName = "obfuscated";
|
||||
break;
|
||||
case UNDERLINE:
|
||||
styleName = "underlined";
|
||||
break;
|
||||
default:
|
||||
styleName = style.name().toLowerCase();
|
||||
break;
|
||||
}
|
||||
|
||||
builder.put(style, styleName);
|
||||
}
|
||||
stylesToNames = builder.build();
|
||||
}
|
||||
|
||||
|
||||
private final List<MessagePart> parts = new ArrayList<>();
|
||||
private int centeringStartIndex = -1;
|
||||
|
||||
/**
|
||||
* Creates a new {@link JSONMessage} object
|
||||
*
|
||||
* @param text The text to start with
|
||||
*/
|
||||
private JSONMessage(String text) {
|
||||
parts.add(new MessagePart(text));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link JSONMessage} object
|
||||
*
|
||||
* @param text The text to start with
|
||||
* @return A new {@link JSONMessage} object
|
||||
*/
|
||||
public static JSONMessage create(String text) {
|
||||
return new JSONMessage(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link JSONMessage} object
|
||||
*
|
||||
* @return A new {@link JSONMessage} object
|
||||
*/
|
||||
public static JSONMessage create() {
|
||||
return create("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an action bar message
|
||||
*
|
||||
* @param message The message to send
|
||||
* @param players The players you want to send it to
|
||||
*/
|
||||
public static void actionbar(String message, Player... players) {
|
||||
ReflectionHelper.sendPacket(ReflectionHelper.createActionbarPacket(ChatColor.translateAlternateColorCodes('&', message)), players);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The latest {@link MessagePart}
|
||||
* @throws ArrayIndexOutOfBoundsException If {@code parts.size() <= 0}.
|
||||
*/
|
||||
public MessagePart last() {
|
||||
if (parts.size() <= 0) {
|
||||
throw new ArrayIndexOutOfBoundsException("No MessageParts exist!");
|
||||
}
|
||||
return parts.get(parts.size() - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this {@link JSONMessage} instance to actual JSON
|
||||
*
|
||||
* @return The JSON representation of this {@link JSONMessage}
|
||||
*/
|
||||
public JsonObject toJSON() {
|
||||
JsonObject obj = new JsonObject();
|
||||
|
||||
obj.addProperty("text", "");
|
||||
|
||||
JsonArray array = new JsonArray();
|
||||
|
||||
parts.stream()
|
||||
.map(MessagePart::toJSON)
|
||||
.forEach(array::add);
|
||||
|
||||
obj.add("extra", array);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this {@link JSONMessage} object to a String representation of the JSON.
|
||||
* This is an alias of {@code toJSON().toString()}.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return toJSON().toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this {@link JSONMessage} object to the legacy formatting system, which
|
||||
* uses formatting codes (like &6, &l, &4, etc.)
|
||||
*
|
||||
* @return This {@link JSONMessage} instance {@link JSONMessage} in legacy format
|
||||
*/
|
||||
public String toLegacy() {
|
||||
StringBuilder output = new StringBuilder();
|
||||
|
||||
parts.stream()
|
||||
.map(MessagePart::toLegacy)
|
||||
.forEach(output::append);
|
||||
|
||||
return output.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends this {@link JSONMessage} to all the players specified
|
||||
*
|
||||
* @param players The players you want to send this to
|
||||
*/
|
||||
public void send(Player... players) {
|
||||
if (ReflectionHelper.getStringVersion().equalsIgnoreCase("v1_16_R1")) {
|
||||
ReflectionHelper.sendTextPacket(toString(), players);
|
||||
return;
|
||||
}
|
||||
|
||||
ReflectionHelper.sendPacket(ReflectionHelper.createTextPacket(toString()), players);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends this as a title to all the players specified
|
||||
*
|
||||
* @param fadeIn How many ticks to fade in
|
||||
* @param stay How many ticks to stay
|
||||
* @param fadeOut How many ticks to fade out
|
||||
* @param players The players to send this to
|
||||
*/
|
||||
public void title(int fadeIn, int stay, int fadeOut, Player... players) {
|
||||
ReflectionHelper.sendPacket(ReflectionHelper.createTitleTimesPacket(fadeIn, stay, fadeOut), players);
|
||||
ReflectionHelper.sendPacket(ReflectionHelper.createTitlePacket(toString()), players);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends this as a subtitle to all the players specified. Must be used after sending a {@link #title(int, int, int, Player...) title}.
|
||||
*
|
||||
* @param players The players to send this to
|
||||
*/
|
||||
public void subtitle(Player... players) {
|
||||
ReflectionHelper.sendPacket(ReflectionHelper.createSubtitlePacket(toString()), players);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an action bar message
|
||||
*
|
||||
* @param players The players you want to send this to
|
||||
*/
|
||||
public void actionbar(Player... players) {
|
||||
actionbar(toLegacy(), players);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the color of the current message part.
|
||||
*
|
||||
* @param color The color to set
|
||||
* @return This {@link JSONMessage} instance
|
||||
*/
|
||||
public JSONMessage color(ChatColor color) {
|
||||
last().setColor(color);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a style to the current message part.
|
||||
*
|
||||
* @param style The style to add
|
||||
* @return This {@link JSONMessage} instance
|
||||
*/
|
||||
public JSONMessage style(ChatColor style) {
|
||||
last().addStyle(style);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the text run a command.
|
||||
*
|
||||
* @param command The command to run
|
||||
* @return This {@link JSONMessage} instance
|
||||
*/
|
||||
public JSONMessage runCommand(String command) {
|
||||
last().setOnClick(ClickEvent.runCommand(command));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the text suggest a command.
|
||||
*
|
||||
* @param command The command to suggest
|
||||
* @return This {@link JSONMessage} instance
|
||||
*/
|
||||
public JSONMessage suggestCommand(String command) {
|
||||
last().setOnClick(ClickEvent.suggestCommand(command));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a URL.
|
||||
*
|
||||
* @param url The url to open
|
||||
* @return This {@link JSONMessage} instance
|
||||
*/
|
||||
public JSONMessage openURL(String url) {
|
||||
last().setOnClick(ClickEvent.openURL(url));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the page of a book. Using this in a non-book context is useless
|
||||
* and will probably error.
|
||||
*
|
||||
* @param page The page to change to
|
||||
* @return This {@link JSONMessage} instance
|
||||
*/
|
||||
public JSONMessage changePage(int page) {
|
||||
last().setOnClick(ClickEvent.changePage(page));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows text when you hover over it
|
||||
*
|
||||
* @param text The text to show
|
||||
* @return This {@link JSONMessage} instance
|
||||
*/
|
||||
public JSONMessage tooltip(String text) {
|
||||
last().setOnHover(HoverEvent.showText(text));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows text when you hover over it
|
||||
*
|
||||
* @param message The text to show
|
||||
* @return This {@link JSONMessage} instance
|
||||
*/
|
||||
public JSONMessage tooltip(JSONMessage message) {
|
||||
last().setOnHover(HoverEvent.showText(message));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows an achievement when you hover over it
|
||||
*
|
||||
* @param id The id of the achievement
|
||||
* @return This {@link JSONMessage} instance
|
||||
*/
|
||||
public JSONMessage achievement(String id) {
|
||||
last().setOnHover(HoverEvent.showAchievement(id));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds another part to this {@link JSONMessage}
|
||||
*
|
||||
* @param text The text to start the next {@link MessagePart} with
|
||||
* @return This {@link JSONMessage} instance
|
||||
*/
|
||||
public JSONMessage then(String text) {
|
||||
return then(new MessagePart(text));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds another part to this {@link JSONMessage}
|
||||
*
|
||||
* @param nextPart The next {@link MessagePart}
|
||||
* @return This {@link JSONMessage} instance
|
||||
*/
|
||||
public JSONMessage then(MessagePart nextPart) {
|
||||
parts.add(nextPart);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a horizontal bar to the message of the given length
|
||||
*
|
||||
* @param length The length of the horizontal bar
|
||||
* @return This {@link JSONMessage} instance
|
||||
*/
|
||||
public JSONMessage bar(int length) {
|
||||
return then(Strings.repeat("-", length)).color(ChatColor.DARK_GRAY).style(ChatColor.STRIKETHROUGH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a horizontal bar to the message that's 53 characters long. This is
|
||||
* the default width of the player's chat window.
|
||||
*
|
||||
* @return This {@link JSONMessage} instance
|
||||
*/
|
||||
public JSONMessage bar() {
|
||||
return bar(53);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a blank line to the message
|
||||
*
|
||||
* @return This {@link JSONMessage} instance
|
||||
*/
|
||||
public JSONMessage newline() {
|
||||
return then("\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the starting point to begin centering JSONMessages.
|
||||
*
|
||||
* @return This {@link JSONMessage} instance
|
||||
*/
|
||||
public JSONMessage beginCenter() {
|
||||
// Start with the NEXT message part.
|
||||
centeringStartIndex = parts.size();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends the centering of the JSONMessage text.
|
||||
*
|
||||
* @return This {@link JSONMessage} instance
|
||||
*/
|
||||
public JSONMessage endCenter() {
|
||||
int current = centeringStartIndex;
|
||||
|
||||
while (current < parts.size()) {
|
||||
Vector<MessagePart> currentLine = new Vector<>();
|
||||
int totalLineLength = 0;
|
||||
|
||||
for (; ; current++) {
|
||||
MessagePart part = current < parts.size() ? parts.get(current) : null;
|
||||
String raw = part == null ? null : ChatColor.stripColor(part.toLegacy());
|
||||
|
||||
if (current >= parts.size() || totalLineLength + raw.length() >= 53) {
|
||||
int padding = Math.max(0, (53 - totalLineLength) / 2);
|
||||
currentLine.firstElement().setText(Strings.repeat(" ", padding) + currentLine.firstElement().getText());
|
||||
currentLine.lastElement().setText(currentLine.lastElement().getText() + "\n");
|
||||
currentLine.clear();
|
||||
break;
|
||||
}
|
||||
|
||||
totalLineLength += raw.length();
|
||||
currentLine.add(part);
|
||||
}
|
||||
}
|
||||
|
||||
MessagePart last = parts.get(parts.size() - 1);
|
||||
last.setText(last.getText().substring(0, last.getText().length() - 1));
|
||||
|
||||
centeringStartIndex = -1;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
// BEGIN UTILITY CLASSES //
|
||||
///////////////////////////
|
||||
|
||||
/**
|
||||
* Represents the JSON format that all click/hover events in JSON messages must follow.
|
||||
* <br>
|
||||
* <br>
|
||||
* <a href="http://minecraft.gamepedia.com/Commands#Raw_JSON_text">Reference</a>
|
||||
*
|
||||
* @author Rayzr
|
||||
*/
|
||||
public static class MessageEvent {
|
||||
|
||||
private String action;
|
||||
private Object value;
|
||||
|
||||
public MessageEvent(String action, Object value) {
|
||||
this.action = action;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A {@link JsonObject} representing the properties of this {@link MessageEvent}
|
||||
*/
|
||||
public JsonObject toJSON() {
|
||||
JsonObject obj = new JsonObject();
|
||||
obj.addProperty("action", action);
|
||||
if (value instanceof JsonElement) {
|
||||
obj.add("value", (JsonElement) value);
|
||||
} else {
|
||||
obj.addProperty("value", value.toString());
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The action
|
||||
*/
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param action The action to set
|
||||
*/
|
||||
public void setAction(String action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The value
|
||||
*/
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value The value to set
|
||||
*/
|
||||
public void setValue(Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class ClickEvent {
|
||||
|
||||
/**
|
||||
* Runs a command.
|
||||
*
|
||||
* @param command The command to run
|
||||
* @return The {@link MessageEvent}
|
||||
*/
|
||||
public static MessageEvent runCommand(String command) {
|
||||
return new MessageEvent("run_command", command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Suggests a command by putting inserting it in chat.
|
||||
*
|
||||
* @param command The command to suggest
|
||||
* @return The {@link MessageEvent}
|
||||
*/
|
||||
public static MessageEvent suggestCommand(String command) {
|
||||
return new MessageEvent("suggest_command", command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requires web links to be enabled on the client.
|
||||
*
|
||||
* @param url The url to open
|
||||
* @return The {@link MessageEvent}
|
||||
*/
|
||||
public static MessageEvent openURL(String url) {
|
||||
return new MessageEvent("open_url", url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Only used with written books.
|
||||
*
|
||||
* @param page The page to switch to
|
||||
* @return The {@link MessageEvent}
|
||||
*/
|
||||
public static MessageEvent changePage(int page) {
|
||||
return new MessageEvent("change_page", page);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class HoverEvent {
|
||||
|
||||
/**
|
||||
* Shows text when you hover over it
|
||||
*
|
||||
* @param text The text to show
|
||||
* @return The {@link MessageEvent}
|
||||
*/
|
||||
public static MessageEvent showText(String text) {
|
||||
return new MessageEvent("show_text", text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows text when you hover over it
|
||||
*
|
||||
* @param message The {@link JSONMessage} to show
|
||||
* @return The {@link MessageEvent}
|
||||
*/
|
||||
public static MessageEvent showText(JSONMessage message) {
|
||||
JsonArray arr = new JsonArray();
|
||||
arr.add(new JsonPrimitive(""));
|
||||
arr.add(message.toJSON());
|
||||
return new MessageEvent("show_text", arr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows an achievement when you hover over it
|
||||
*
|
||||
* @param id The id of the achievement
|
||||
* @return The {@link MessageEvent}
|
||||
*/
|
||||
public static MessageEvent showAchievement(String id) {
|
||||
return new MessageEvent("show_achievement", id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class ReflectionHelper {
|
||||
|
||||
private static final String version;
|
||||
private static Class<?> craftPlayer;
|
||||
private static Constructor<?> chatComponentText;
|
||||
private static Class<?> packetPlayOutChat;
|
||||
private static Class<?> packetPlayOutTitle;
|
||||
private static Class<?> iChatBaseComponent;
|
||||
private static Class<?> titleAction;
|
||||
private static Field connection;
|
||||
private static MethodHandle GET_HANDLE;
|
||||
private static MethodHandle SEND_PACKET;
|
||||
private static MethodHandle STRING_TO_CHAT;
|
||||
private static Object enumActionTitle;
|
||||
private static Object enumActionSubtitle;
|
||||
private static Object enumChatMessage;
|
||||
private static Object enumActionbarMessage;
|
||||
private static boolean SETUP;
|
||||
private static int MAJOR_VER = -1;
|
||||
|
||||
static {
|
||||
String[] split = Bukkit.getServer().getClass().getPackage().getName().split("\\.");
|
||||
version = split[split.length - 1];
|
||||
|
||||
try {
|
||||
SETUP = true;
|
||||
|
||||
MAJOR_VER = getVersion();
|
||||
|
||||
craftPlayer = getClass("{obc}.entity.CraftPlayer");
|
||||
Method getHandle = craftPlayer.getMethod("getHandle");
|
||||
connection = getHandle.getReturnType().getField("playerConnection");
|
||||
Method sendPacket = connection.getType().getMethod("sendPacket", getClass("{nms}.Packet"));
|
||||
|
||||
chatComponentText = getClass("{nms}.ChatComponentText").getConstructor(String.class);
|
||||
|
||||
iChatBaseComponent = getClass("{nms}.IChatBaseComponent");
|
||||
|
||||
Method stringToChat;
|
||||
|
||||
if (MAJOR_VER < 8) {
|
||||
stringToChat = getClass("{nms}.ChatSerializer").getMethod("a", String.class);
|
||||
} else {
|
||||
stringToChat = getClass("{nms}.IChatBaseComponent$ChatSerializer").getMethod("a", String.class);
|
||||
}
|
||||
|
||||
GET_HANDLE = MethodHandles.lookup().unreflect(getHandle);
|
||||
SEND_PACKET = MethodHandles.lookup().unreflect(sendPacket);
|
||||
STRING_TO_CHAT = MethodHandles.lookup().unreflect(stringToChat);
|
||||
|
||||
packetPlayOutChat = getClass("{nms}.PacketPlayOutChat");
|
||||
packetPlayOutTitle = getClass("{nms}.PacketPlayOutTitle");
|
||||
|
||||
titleAction = getClass("{nms}.PacketPlayOutTitle$EnumTitleAction");
|
||||
|
||||
enumActionTitle = titleAction.getField("TITLE").get(null);
|
||||
enumActionSubtitle = titleAction.getField("SUBTITLE").get(null);
|
||||
|
||||
if (MAJOR_VER >= 12) {
|
||||
Method getChatMessageType = getClass("{nms}.ChatMessageType").getMethod("a", byte.class);
|
||||
|
||||
enumChatMessage = getChatMessageType.invoke(null, (byte) 1);
|
||||
enumActionbarMessage = getChatMessageType.invoke(null, (byte) 2);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
SETUP = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void sendPacket(Object packet, Player... players) {
|
||||
if (!SETUP) {
|
||||
throw new IllegalStateException("ReflectionHelper is not set up!");
|
||||
}
|
||||
if (packet == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Player player : players) {
|
||||
try {
|
||||
SEND_PACKET.bindTo(connection.get(GET_HANDLE.bindTo(player).invoke())).invoke(packet);
|
||||
} catch (Throwable e) {
|
||||
System.err.println("Failed to send packet");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void setType(Object object, byte type) {
|
||||
if (MAJOR_VER < 12) {
|
||||
set("b", object, type);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case 1:
|
||||
set("b", object, enumChatMessage);
|
||||
break;
|
||||
case 2:
|
||||
set("b", object, enumActionbarMessage);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("type must be 1 or 2");
|
||||
}
|
||||
}
|
||||
|
||||
static Object createActionbarPacket(String message) {
|
||||
if (!SETUP) {
|
||||
throw new IllegalStateException("ReflectionHelper is not set up!");
|
||||
}
|
||||
Object packet = createTextPacket(message);
|
||||
setType(packet, (byte) 2);
|
||||
return packet;
|
||||
}
|
||||
|
||||
static Object createTextPacket(String message) {
|
||||
if (!SETUP) {
|
||||
throw new IllegalStateException("ReflectionHelper is not set up!");
|
||||
}
|
||||
try {
|
||||
Object packet = packetPlayOutChat.newInstance();
|
||||
set("a", packet, fromJson(message));
|
||||
setType(packet, (byte) 1);
|
||||
return packet;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void sendTextPacket(String message, Player... players) {
|
||||
try {
|
||||
for (Player player : players) {
|
||||
Class chatTypeClass = getClass("{nms}.ChatMessageType");
|
||||
Constructor<?> constructor = packetPlayOutChat.getConstructor(getClass("{nms}.IChatBaseComponent"), chatTypeClass, UUID.class);
|
||||
Object packet = constructor.newInstance(fromJson(message), Enum.valueOf(chatTypeClass, "CHAT"), player.getUniqueId());
|
||||
|
||||
Object handler = player.getClass().getMethod("getHandle").invoke(player);
|
||||
Object playerConnection = handler.getClass().getField("playerConnection").get(handler);
|
||||
playerConnection.getClass().getMethod("sendPacket", getClass("{nms}.Packet")).invoke(playerConnection, packet);
|
||||
}
|
||||
} catch (IllegalArgumentException | NoSuchMethodException | NoSuchFieldException | IllegalAccessException | InvocationTargetException | InstantiationException | ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
static Object createTitlePacket(String message) {
|
||||
if (!SETUP) {
|
||||
throw new IllegalStateException("ReflectionHelper is not set up!");
|
||||
}
|
||||
try {
|
||||
return packetPlayOutTitle.getConstructor(titleAction, iChatBaseComponent).newInstance(enumActionTitle, fromJson(message));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static Object createSubtitlePacket(String message) {
|
||||
if (!SETUP) {
|
||||
throw new IllegalStateException("ReflectionHelper is not set up!");
|
||||
}
|
||||
try {
|
||||
return packetPlayOutTitle.getConstructor(titleAction, iChatBaseComponent).newInstance(enumActionSubtitle, fromJson(message));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static Object createTitleTimesPacket(int fadeIn, int stay, int fadeOut) {
|
||||
if (!SETUP) {
|
||||
throw new IllegalStateException("ReflectionHelper is not set up!");
|
||||
}
|
||||
try {
|
||||
return packetPlayOutTitle.getConstructor(int.class, int.class, int.class).newInstance(fadeIn, stay, fadeOut);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ChatComponentText from plain text
|
||||
*
|
||||
* @param message The text to convert to a chat component
|
||||
* @return The chat component
|
||||
*/
|
||||
static Object componentText(String message) {
|
||||
if (!SETUP) {
|
||||
throw new IllegalStateException("ReflectionHelper is not set up!");
|
||||
}
|
||||
try {
|
||||
return chatComponentText.newInstance(message);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to convert a String representing a JSON message into a usable object
|
||||
*
|
||||
* @param json The JSON to attempt to parse
|
||||
* @return The object representing the text in JSON form, or <code>null</code> if something went wrong converting the String to JSON data
|
||||
*/
|
||||
static Object fromJson(String json) {
|
||||
if (!SETUP) {
|
||||
throw new IllegalStateException("ReflectionHelper is not set up!");
|
||||
}
|
||||
if (!json.trim().startsWith("{")) {
|
||||
return componentText(json);
|
||||
}
|
||||
|
||||
try {
|
||||
return STRING_TO_CHAT.invoke(json);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a class with the given package and name. This method replaces <code>{nms}</code> with <code>net.minecraft.server.[version]</code> and <code>{obc}</code> with <code>org.bukkit.craft.[version]</code>
|
||||
* <br>
|
||||
* <br>
|
||||
* Example:
|
||||
*
|
||||
* <pre>
|
||||
* Class<?> entityPlayer = ReflectionHelper.getClass("{nms}.EntityPlayer");
|
||||
* </pre>
|
||||
*
|
||||
* @param path The path to the {@link Class}
|
||||
* @return The class
|
||||
* @throws ClassNotFoundException If the class was not found
|
||||
*/
|
||||
static Class<?> getClass(String path) throws ClassNotFoundException {
|
||||
if (!SETUP) {
|
||||
throw new IllegalStateException("ReflectionHelper is not set up!");
|
||||
}
|
||||
return Class.forName(path.replace("{nms}", "net.minecraft.server." + version).replace("{obc}", "org.bukkit.craftbukkit." + version));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a field with the given name on an object to the value specified
|
||||
*
|
||||
* @param field The name of the field to change
|
||||
* @param obj The object to change the field of
|
||||
* @param value The new value to set
|
||||
*/
|
||||
static void set(String field, Object obj, Object value) {
|
||||
try {
|
||||
Field f = obj.getClass().getDeclaredField(field);
|
||||
f.setAccessible(true);
|
||||
f.set(obj, value);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static String getStringVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
static int getVersion() {
|
||||
if (!SETUP) {
|
||||
throw new IllegalStateException("ReflectionHelper is not set up!");
|
||||
}
|
||||
try {
|
||||
return Integer.parseInt(version.split("_")[1]);
|
||||
} catch (NumberFormatException e) {
|
||||
e.printStackTrace();
|
||||
return 10;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a section of the message, and represents the format that all JSON messages must follow in Minecraft.
|
||||
* <br>
|
||||
* <br>
|
||||
* <a href="http://minecraft.gamepedia.com/Commands#Raw_JSON_text">Reference</a>
|
||||
*
|
||||
* @author Rayzr
|
||||
*/
|
||||
public static class MessagePart {
|
||||
|
||||
private final List<ChatColor> styles = new ArrayList<>();
|
||||
private MessageEvent onClick;
|
||||
private MessageEvent onHover;
|
||||
private ChatColor color;
|
||||
private String text;
|
||||
|
||||
public MessagePart(String text) {
|
||||
this.text = text == null ? "null" : text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this {@link MessagePart} into a {@link JsonObject}
|
||||
*
|
||||
* @return The Minecraft-compatible {@link JsonObject}
|
||||
*/
|
||||
public JsonObject toJSON() {
|
||||
Objects.requireNonNull(text);
|
||||
|
||||
JsonObject obj = new JsonObject();
|
||||
obj.addProperty("text", text);
|
||||
|
||||
if (color != null) {
|
||||
obj.addProperty("color", color.name().toLowerCase());
|
||||
}
|
||||
|
||||
for (ChatColor style : styles) {
|
||||
obj.addProperty(stylesToNames.get(style), true);
|
||||
}
|
||||
|
||||
if (onClick != null) {
|
||||
obj.add("clickEvent", onClick.toJSON());
|
||||
}
|
||||
|
||||
if (onHover != null) {
|
||||
obj.add("hoverEvent", onHover.toJSON());
|
||||
}
|
||||
|
||||
return obj;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return This {@link MessagePart} in legacy-style color/formatting codes
|
||||
*/
|
||||
public String toLegacy() {
|
||||
StringBuilder output = new StringBuilder();
|
||||
if (color != null) {
|
||||
output.append(color.toString());
|
||||
}
|
||||
styles.stream()
|
||||
.map(ChatColor::toString)
|
||||
.forEach(output::append);
|
||||
|
||||
return output.append(text).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The click event bound
|
||||
*/
|
||||
public MessageEvent getOnClick() {
|
||||
return onClick;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param onClick The new click event to bind
|
||||
*/
|
||||
public void setOnClick(MessageEvent onClick) {
|
||||
this.onClick = onClick;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The hover event bound
|
||||
*/
|
||||
public MessageEvent getOnHover() {
|
||||
return onHover;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param onHover The new hover event to bind
|
||||
*/
|
||||
public void setOnHover(MessageEvent onHover) {
|
||||
this.onHover = onHover;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The color
|
||||
*/
|
||||
public ChatColor getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param color The color to set
|
||||
*/
|
||||
public void setColor(ChatColor color) {
|
||||
if (!color.isColor()) {
|
||||
throw new IllegalArgumentException(color.name() + " is not a color!");
|
||||
}
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The list of styles
|
||||
*/
|
||||
public List<ChatColor> getStyles() {
|
||||
return styles;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param style The new style to add
|
||||
*/
|
||||
public void addStyle(ChatColor style) {
|
||||
if (style == null) {
|
||||
throw new IllegalArgumentException("Style cannot be null!");
|
||||
}
|
||||
if (!style.isFormat()) {
|
||||
throw new IllegalArgumentException(color.name() + " is not a style!");
|
||||
}
|
||||
styles.add(style);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The raw text
|
||||
*/
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param text The raw text to set
|
||||
*/
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -25,18 +25,19 @@ import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Msg {
|
||||
public final class Msg {
|
||||
public static void msg(CommandSender s, String... msg) {
|
||||
s.sendMessage(Arrays.stream(msg).filter(Objects::nonNull).map(Msg::color).collect(Collectors.joining("\n")));
|
||||
}
|
||||
|
||||
public static void msg(CommandSender s, String... msg) {
|
||||
Arrays.stream(msg).map(Msg::color).forEach(s::sendMessage);
|
||||
}
|
||||
public static void broadcast(String... msg) {
|
||||
Arrays.stream(msg).filter(Objects::nonNull).map(Msg::color).forEach(Bukkit::broadcastMessage);
|
||||
}
|
||||
|
||||
public static void broadcast(String... msg) {
|
||||
Arrays.stream(msg).map(Msg::color).forEach(Bukkit::broadcastMessage);
|
||||
}
|
||||
|
||||
public static String color(String text) {
|
||||
return ChatColor.translateAlternateColorCodes('&', text);
|
||||
}
|
||||
public static String color(String text) {
|
||||
return ChatColor.translateAlternateColorCodes('&', text);
|
||||
}
|
||||
}
|
||||
|
@@ -21,8 +21,8 @@
|
||||
package me.clip.placeholderapi.util;
|
||||
|
||||
public enum TimeFormat {
|
||||
DAYS,
|
||||
HOURS,
|
||||
MINUTES,
|
||||
SECONDS
|
||||
DAYS,
|
||||
HOURS,
|
||||
MINUTES,
|
||||
SECONDS
|
||||
}
|
||||
|
@@ -20,156 +20,151 @@
|
||||
*/
|
||||
package me.clip.placeholderapi.util;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
|
||||
public class TimeUtil {
|
||||
|
||||
public static String getRemaining(int seconds, TimeFormat type) {
|
||||
if (seconds < 60) {
|
||||
switch (type) {
|
||||
case DAYS:
|
||||
case HOURS:
|
||||
case MINUTES:
|
||||
return "0";
|
||||
case SECONDS:
|
||||
return String.valueOf(seconds);
|
||||
}
|
||||
public static String getRemaining(int seconds, TimeFormat type) {
|
||||
if (seconds < 60) {
|
||||
switch (type) {
|
||||
case DAYS:
|
||||
case HOURS:
|
||||
case MINUTES:
|
||||
return "0";
|
||||
case SECONDS:
|
||||
return String.valueOf(seconds);
|
||||
}
|
||||
|
||||
return String.valueOf(seconds);
|
||||
return String.valueOf(seconds);
|
||||
}
|
||||
|
||||
int minutes = seconds / 60;
|
||||
int s = 60 * minutes;
|
||||
int secondsLeft = seconds - s;
|
||||
|
||||
if (minutes < 60) {
|
||||
switch (type) {
|
||||
case DAYS:
|
||||
case HOURS:
|
||||
return "0";
|
||||
case MINUTES:
|
||||
return String.valueOf(minutes);
|
||||
case SECONDS:
|
||||
return String.valueOf(secondsLeft);
|
||||
}
|
||||
|
||||
return String.valueOf(seconds);
|
||||
}
|
||||
|
||||
if (minutes < 1440) {
|
||||
int hours = minutes / 60;
|
||||
int inMins = 60 * hours;
|
||||
int leftOver = minutes - inMins;
|
||||
|
||||
switch (type) {
|
||||
case DAYS:
|
||||
return "0";
|
||||
case HOURS:
|
||||
return String.valueOf(hours);
|
||||
case MINUTES:
|
||||
return String.valueOf(leftOver);
|
||||
case SECONDS:
|
||||
return String.valueOf(secondsLeft);
|
||||
}
|
||||
|
||||
return String.valueOf(seconds);
|
||||
}
|
||||
|
||||
int days = minutes / 1440;
|
||||
int inMins = 1440 * days;
|
||||
int leftOver = minutes - inMins;
|
||||
|
||||
if (leftOver < 60) {
|
||||
switch (type) {
|
||||
case DAYS:
|
||||
return String.valueOf(days);
|
||||
case HOURS:
|
||||
return String.valueOf(0);
|
||||
case MINUTES:
|
||||
return String.valueOf(leftOver);
|
||||
case SECONDS:
|
||||
return String.valueOf(secondsLeft);
|
||||
}
|
||||
|
||||
return String.valueOf(seconds);
|
||||
|
||||
} else {
|
||||
int hours = leftOver / 60;
|
||||
int hoursInMins = 60 * hours;
|
||||
int minsLeft = leftOver - hoursInMins;
|
||||
|
||||
switch (type) {
|
||||
case DAYS:
|
||||
return String.valueOf(days);
|
||||
case HOURS:
|
||||
return String.valueOf(hours);
|
||||
case MINUTES:
|
||||
return String.valueOf(minsLeft);
|
||||
case SECONDS:
|
||||
return String.valueOf(secondsLeft);
|
||||
}
|
||||
|
||||
return String.valueOf(seconds);
|
||||
}
|
||||
}
|
||||
|
||||
int minutes = seconds / 60;
|
||||
int s = 60 * minutes;
|
||||
int secondsLeft = seconds - s;
|
||||
|
||||
if (minutes < 60) {
|
||||
switch (type) {
|
||||
case DAYS:
|
||||
case HOURS:
|
||||
return "0";
|
||||
case MINUTES:
|
||||
return String.valueOf(minutes);
|
||||
case SECONDS:
|
||||
return String.valueOf(secondsLeft);
|
||||
}
|
||||
|
||||
return String.valueOf(seconds);
|
||||
public static String getTime(int seconds) {
|
||||
return getTime(Duration.ofSeconds(seconds));
|
||||
}
|
||||
|
||||
if (minutes < 1440) {
|
||||
int hours = minutes / 60;
|
||||
int inMins = 60 * hours;
|
||||
int leftOver = minutes - inMins;
|
||||
/**
|
||||
* Format the given value with s, m, h and d (seconds, minutes, hours and days)
|
||||
*
|
||||
* @param duration {@link Duration} (eg, Duration.of(20, {@link ChronoUnit#SECONDS}) for 20 seconds)
|
||||
* @return formatted time
|
||||
*/
|
||||
public static String getTime(final Duration duration) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
|
||||
switch (type) {
|
||||
case DAYS:
|
||||
return "0";
|
||||
case HOURS:
|
||||
return String.valueOf(hours);
|
||||
case MINUTES:
|
||||
return String.valueOf(leftOver);
|
||||
case SECONDS:
|
||||
return String.valueOf(secondsLeft);
|
||||
}
|
||||
long seconds = duration.getSeconds();
|
||||
long minutes = seconds / 60;
|
||||
long hours = minutes / 60;
|
||||
long days = hours / 24;
|
||||
|
||||
return String.valueOf(seconds);
|
||||
seconds %= 60;
|
||||
minutes %= 60;
|
||||
hours %= 60;
|
||||
days %= 24;
|
||||
|
||||
if (seconds > 0) {
|
||||
builder.insert(0, seconds + "s");
|
||||
}
|
||||
|
||||
if (minutes > 0) {
|
||||
if (builder.length() > 0) {
|
||||
builder.insert(0, ' ');
|
||||
}
|
||||
|
||||
builder.insert(0, minutes + "m");
|
||||
}
|
||||
|
||||
if (hours > 0) {
|
||||
if (builder.length() > 0) {
|
||||
builder.insert(0, ' ');
|
||||
}
|
||||
|
||||
builder.insert(0, hours + "h");
|
||||
}
|
||||
|
||||
if (days > 0) {
|
||||
if (builder.length() > 0) {
|
||||
builder.insert(0, ' ');
|
||||
}
|
||||
|
||||
builder.insert(0, days + "d");
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
int days = minutes / 1440;
|
||||
int inMins = 1440 * days;
|
||||
int leftOver = minutes - inMins;
|
||||
|
||||
if (leftOver < 60) {
|
||||
switch (type) {
|
||||
case DAYS:
|
||||
return String.valueOf(days);
|
||||
case HOURS:
|
||||
return String.valueOf(0);
|
||||
case MINUTES:
|
||||
return String.valueOf(leftOver);
|
||||
case SECONDS:
|
||||
return String.valueOf(secondsLeft);
|
||||
}
|
||||
|
||||
return String.valueOf(seconds);
|
||||
|
||||
} else {
|
||||
int hours = leftOver / 60;
|
||||
int hoursInMins = 60 * hours;
|
||||
int minsLeft = leftOver - hoursInMins;
|
||||
|
||||
switch (type) {
|
||||
case DAYS:
|
||||
return String.valueOf(days);
|
||||
case HOURS:
|
||||
return String.valueOf(hours);
|
||||
case MINUTES:
|
||||
return String.valueOf(minsLeft);
|
||||
case SECONDS:
|
||||
return String.valueOf(secondsLeft);
|
||||
}
|
||||
|
||||
return String.valueOf(seconds);
|
||||
}
|
||||
}
|
||||
|
||||
public static String getTime(int seconds) {
|
||||
|
||||
if (seconds < 60) {
|
||||
return seconds + "s";
|
||||
}
|
||||
|
||||
int minutes = seconds / 60;
|
||||
int s = 60 * minutes;
|
||||
int secondsLeft = seconds - s;
|
||||
|
||||
if (minutes < 60) {
|
||||
if (secondsLeft > 0) {
|
||||
return minutes + "m " + secondsLeft + "s";
|
||||
} else {
|
||||
return minutes + "m";
|
||||
}
|
||||
}
|
||||
|
||||
if (minutes < 1440) {
|
||||
String time;
|
||||
int hours = minutes / 60;
|
||||
time = hours + "h";
|
||||
int inMins = 60 * hours;
|
||||
int leftOver = minutes - inMins;
|
||||
|
||||
if (leftOver >= 1) {
|
||||
time = time + " " + leftOver + "m";
|
||||
}
|
||||
|
||||
if (secondsLeft > 0) {
|
||||
time = time + " " + secondsLeft + "s";
|
||||
}
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
String time;
|
||||
int days = minutes / 1440;
|
||||
time = days + "d";
|
||||
int inMins = 1440 * days;
|
||||
int leftOver = minutes - inMins;
|
||||
|
||||
if (leftOver >= 1) {
|
||||
if (leftOver < 60) {
|
||||
time = time + " " + leftOver + "m";
|
||||
} else {
|
||||
int hours = leftOver / 60;
|
||||
time = time + " " + hours + "h";
|
||||
|
||||
int hoursInMins = 60 * hours;
|
||||
int minsLeft = leftOver - hoursInMins;
|
||||
time = time + " " + minsLeft + "m";
|
||||
}
|
||||
}
|
||||
|
||||
if (secondsLeft > 0) {
|
||||
time = time + " " + secondsLeft + "s";
|
||||
}
|
||||
|
||||
return time;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user