mirror of
https://github.com/plexusorg/Plex.git
synced 2025-06-28 22:46:40 +00:00
Move Plex to API-driven plugin and fix NoClassDefFoundError on startup
This commit is contained in:
51
server/src/main/java/dev/plex/util/AshconInfo.java
Normal file
51
server/src/main/java/dev/plex/util/AshconInfo.java
Normal file
@ -0,0 +1,51 @@
|
||||
package dev.plex.util;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class AshconInfo
|
||||
{
|
||||
private String uuid;
|
||||
private String username;
|
||||
|
||||
@SerializedName("username_history")
|
||||
private UsernameHistory[] usernameHistories;
|
||||
|
||||
private Textures textures;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
public static class UsernameHistory
|
||||
{
|
||||
private String username;
|
||||
@SerializedName("changed_at")
|
||||
private ZonedDateTime zonedDateTime;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
public static class Textures
|
||||
{
|
||||
private boolean custom;
|
||||
private boolean slim;
|
||||
private SkinData raw;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
public static class SkinData
|
||||
{
|
||||
private String value;
|
||||
private String signature;
|
||||
}
|
||||
}
|
39
server/src/main/java/dev/plex/util/BuildInfo.java
Normal file
39
server/src/main/java/dev/plex/util/BuildInfo.java
Normal file
@ -0,0 +1,39 @@
|
||||
package dev.plex.util;
|
||||
|
||||
import dev.plex.Plex;
|
||||
import java.io.InputStream;
|
||||
import java.util.Properties;
|
||||
import lombok.Getter;
|
||||
|
||||
public class BuildInfo
|
||||
{
|
||||
@Getter
|
||||
public static String number;
|
||||
@Getter
|
||||
public static String author;
|
||||
@Getter
|
||||
public static String date;
|
||||
@Getter
|
||||
public static String head;
|
||||
|
||||
public void load(Plex plugin)
|
||||
{
|
||||
try
|
||||
{
|
||||
Properties props;
|
||||
try (InputStream in = plugin.getResource("build.properties"))
|
||||
{
|
||||
props = new Properties();
|
||||
props.load(in);
|
||||
}
|
||||
|
||||
number = props.getProperty("buildNumber", "unknown");
|
||||
author = props.getProperty("buildAuthor", "unknown");
|
||||
date = props.getProperty("buildDate", "unknown");
|
||||
head = props.getProperty("buildHead", "unknown");
|
||||
}
|
||||
catch (Exception ignored)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
56
server/src/main/java/dev/plex/util/GameRuleUtil.java
Normal file
56
server/src/main/java/dev/plex/util/GameRuleUtil.java
Normal file
@ -0,0 +1,56 @@
|
||||
package dev.plex.util;
|
||||
|
||||
import dev.plex.Plex;
|
||||
import java.util.Locale;
|
||||
import org.apache.commons.lang.math.NumberUtils;
|
||||
import org.bukkit.GameRule;
|
||||
import org.bukkit.World;
|
||||
|
||||
public class GameRuleUtil
|
||||
{
|
||||
public static <T> void commitGlobalGameRules(World world)
|
||||
{
|
||||
for (String s : Plex.get().config.getStringList("global_gamerules"))
|
||||
{
|
||||
readGameRules(world, s);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> void commitSpecificGameRules(World world)
|
||||
{
|
||||
for (String s : Plex.get().config.getStringList("worlds." + world.getName().toLowerCase(Locale.ROOT) + ".gameRules"))
|
||||
{
|
||||
readGameRules(world, s);
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> void readGameRules(World world, String s)
|
||||
{
|
||||
String gameRule = s.split(";")[0];
|
||||
T value = (T)s.split(";")[1];
|
||||
GameRule<T> rule = (GameRule<T>)GameRule.getByName(gameRule);
|
||||
if (rule != null && check(value).getClass().equals(rule.getType()))
|
||||
{
|
||||
world.setGameRule(rule, value);
|
||||
PlexLog.debug("Setting game rule " + gameRule + " for world " + world.getName() + " with value " + value);
|
||||
}
|
||||
else
|
||||
{
|
||||
PlexLog.error(String.format("Failed to set game rule %s for world %s with value %s!", gameRule, world.getName().toLowerCase(Locale.ROOT), value));
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> Object check(T value)
|
||||
{
|
||||
if (value.toString().equalsIgnoreCase("true") || value.toString().equalsIgnoreCase("false"))
|
||||
{
|
||||
return Boolean.parseBoolean(value.toString());
|
||||
}
|
||||
|
||||
if (NumberUtils.isNumber(value.toString()))
|
||||
{
|
||||
return Integer.parseInt(value.toString());
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
62
server/src/main/java/dev/plex/util/MojangUtils.java
Normal file
62
server/src/main/java/dev/plex/util/MojangUtils.java
Normal file
@ -0,0 +1,62 @@
|
||||
package dev.plex.util;
|
||||
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Arrays;
|
||||
|
||||
import dev.plex.Plex;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class MojangUtils
|
||||
{
|
||||
|
||||
public static AshconInfo getInfo(String nameOrUuid)
|
||||
{
|
||||
CloseableHttpClient client = HttpClients.createDefault();
|
||||
HttpGet get = new HttpGet("https://api.ashcon.app/mojang/v2/user/" + nameOrUuid);
|
||||
try
|
||||
{
|
||||
HttpResponse response = client.execute(get);
|
||||
if (response == null || response.getEntity() == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
String json = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
|
||||
JSONObject object = new JSONObject(json);
|
||||
if (!object.isNull("code") && object.getInt("code") == 404)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
client.close();
|
||||
AshconInfo ashconInfo = new GsonBuilder().registerTypeAdapter(ZonedDateTime.class, (JsonDeserializer<ZonedDateTime>)(json1, typeOfT, context) ->
|
||||
ZonedDateTime.ofInstant(Instant.from(DateTimeFormatter.ISO_INSTANT.parse(json1.getAsJsonPrimitive().getAsString())), ZoneId.of(Plex.get().config.getString("server.timezone")))).create().fromJson(json, AshconInfo.class);
|
||||
|
||||
Arrays.sort(ashconInfo.getUsernameHistories(), (o1, o2) ->
|
||||
{
|
||||
if (o1.getZonedDateTime() == null || o2.getZonedDateTime() == null)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return o1.getZonedDateTime().compareTo(o2.getZonedDateTime());
|
||||
});
|
||||
|
||||
return ashconInfo;
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
65
server/src/main/java/dev/plex/util/PermissionsUtil.java
Normal file
65
server/src/main/java/dev/plex/util/PermissionsUtil.java
Normal file
@ -0,0 +1,65 @@
|
||||
package dev.plex.util;
|
||||
|
||||
import dev.plex.Plex;
|
||||
import dev.plex.cache.DataUtils;
|
||||
import dev.plex.permission.Permission;
|
||||
import dev.plex.player.PlexPlayer;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.permissions.PermissionAttachment;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class PermissionsUtil
|
||||
{
|
||||
public static void setupPermissions(@NotNull Player player)
|
||||
{
|
||||
PlexPlayer plexPlayer = DataUtils.getPlayer(player.getUniqueId());
|
||||
PermissionAttachment attachment = player.addAttachment(Plex.get());
|
||||
plexPlayer.getPermissions().forEach(permission -> attachment.setPermission(permission.getPermission(), permission.isAllowed()));
|
||||
plexPlayer.setPermissionAttachment(attachment);
|
||||
}
|
||||
|
||||
public static void addPermission(PlexPlayer player, Permission permission)
|
||||
{
|
||||
Plex.get().getSqlPermissions().addPermission(PlexUtils.addToArrayList(player.getPermissions(), permission));
|
||||
Player p = Bukkit.getPlayer(player.getUuid());
|
||||
if (p == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
player.getPermissionAttachment().setPermission(permission.getPermission(), permission.isAllowed());
|
||||
}
|
||||
|
||||
public static void addPermission(PlexPlayer player, String permission)
|
||||
{
|
||||
addPermission(player, new Permission(player.getUuid(), permission));
|
||||
}
|
||||
|
||||
public static void removePermission(PlexPlayer player, String permission)
|
||||
{
|
||||
Plex.get().getSqlPermissions().removePermission(player.getUuid(), permission);
|
||||
player.getPermissions().removeIf(permission1 -> permission1.getPermission().equalsIgnoreCase(permission));
|
||||
Player p = Bukkit.getPlayer(player.getUuid());
|
||||
if (p == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
player.getPermissionAttachment().unsetPermission(permission);
|
||||
}
|
||||
|
||||
public static void updatePermission(PlexPlayer player, String permission, boolean newValue)
|
||||
{
|
||||
player.getPermissions().stream().filter(permission1 -> permission.equalsIgnoreCase(permission)).findFirst().ifPresent(permission1 ->
|
||||
{
|
||||
Plex.get().getSqlPermissions().updatePermission(permission1, newValue);
|
||||
});
|
||||
player.getPermissions().removeIf(permission1 -> permission1.getPermission().equalsIgnoreCase(permission));
|
||||
Player p = Bukkit.getPlayer(player.getUuid());
|
||||
if (p == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
player.getPermissionAttachment().unsetPermission(permission);
|
||||
|
||||
}
|
||||
}
|
69
server/src/main/java/dev/plex/util/PlexLog.java
Normal file
69
server/src/main/java/dev/plex/util/PlexLog.java
Normal file
@ -0,0 +1,69 @@
|
||||
package dev.plex.util;
|
||||
|
||||
import dev.plex.Plex;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
|
||||
public class PlexLog
|
||||
{
|
||||
public static void log(String message, Object... strings)
|
||||
{
|
||||
for (int i = 0; i < strings.length; i++)
|
||||
{
|
||||
if (message.contains("{" + i + "}"))
|
||||
{
|
||||
message = message.replace("{" + i + "}", strings[i].toString());
|
||||
}
|
||||
}
|
||||
Bukkit.getConsoleSender().sendMessage(String.format(ChatColor.YELLOW + "[Plex] " + ChatColor.GRAY + "%s", message));
|
||||
}
|
||||
|
||||
public static void log(Component component)
|
||||
{
|
||||
Bukkit.getConsoleSender().sendMessage(Component.text("[Plex] ").color(NamedTextColor.YELLOW).append(component).colorIfAbsent(NamedTextColor.GRAY));
|
||||
}
|
||||
|
||||
public static void error(String message, Object... strings)
|
||||
{
|
||||
for (int i = 0; i < strings.length; i++)
|
||||
{
|
||||
if (message.contains("{" + i + "}"))
|
||||
{
|
||||
message = message.replace("{" + i + "}", strings[i].toString());
|
||||
}
|
||||
}
|
||||
Bukkit.getConsoleSender().sendMessage(PlexUtils.mmDeserialize("<red>[Plex Error] <gold>" + message));
|
||||
// Bukkit.getConsoleSender().sendMessage(String.format(ChatColor.RED + "[Plex Error] " + ChatColor.GOLD + "%s", message));
|
||||
}
|
||||
|
||||
public static void warn(String message, Object... strings)
|
||||
{
|
||||
for (int i = 0; i < strings.length; i++)
|
||||
{
|
||||
if (message.contains("{" + i + "}"))
|
||||
{
|
||||
message = message.replace("{" + i + "}", strings[i].toString());
|
||||
}
|
||||
}
|
||||
// Bukkit.getConsoleSender().sendMessage(String.format(ChatColor.YELLOW + "[Plex Warning] " + ChatColor.GOLD + "%s", message));
|
||||
Bukkit.getConsoleSender().sendMessage(PlexUtils.mmDeserialize("<#eb7c0e>[Plex Warning] <gold>" + message));
|
||||
}
|
||||
|
||||
public static void debug(String message, Object... strings)
|
||||
{
|
||||
for (int i = 0; i < strings.length; i++)
|
||||
{
|
||||
if (message.contains("{" + i + "}"))
|
||||
{
|
||||
message = message.replace("{" + i + "}", strings[i].toString());
|
||||
}
|
||||
}
|
||||
if (Plex.get().config.getBoolean("debug"))
|
||||
{
|
||||
Bukkit.getConsoleSender().sendMessage(PlexUtils.mmDeserialize("<dark_purple>[Plex Debug] <gold>" + message));
|
||||
// Bukkit.getConsoleSender().sendMessage(String.format(ChatColor.DARK_PURPLE + "[Plex Debug] " + ChatColor.GOLD + "%s", message));
|
||||
}
|
||||
}
|
||||
}
|
190
server/src/main/java/dev/plex/util/PlexUtils.java
Normal file
190
server/src/main/java/dev/plex/util/PlexUtils.java
Normal file
@ -0,0 +1,190 @@
|
||||
package dev.plex.util;
|
||||
|
||||
import dev.plex.Plex;
|
||||
import dev.plex.PlexBase;
|
||||
import dev.plex.cache.PlayerCache;
|
||||
import dev.plex.storage.StorageType;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.time.Month;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
|
||||
import net.kyori.adventure.text.minimessage.tag.standard.StandardTags;
|
||||
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||
import org.apache.commons.lang.time.DateUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.PluginCommandYamlParser;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
public class PlexUtils implements PlexBase
|
||||
{
|
||||
public static List<String> DEVELOPERS =
|
||||
Arrays.asList("78408086-1991-4c33-a571-d8fa325465b2", // Telesphoreo
|
||||
"f5cd54c4-3a24-4213-9a56-c06c49594dff", // Taahh
|
||||
"53b1512e-3481-4702-9f4f-63cb9c8be6a1", // supernt
|
||||
"ca83b658-c03b-4106-9edc-72f70a80656d", // ayunami2000
|
||||
"2e06e049-24c8-42e4-8bcf-d35372af31e6" // Fleek
|
||||
);
|
||||
|
||||
public static <T> T addToArrayList(List<T> list, T object)
|
||||
{
|
||||
list.add(object);
|
||||
return object;
|
||||
}
|
||||
|
||||
public static void disabledEffect(Player player, Location location)
|
||||
{
|
||||
Particle.CLOUD.builder().location(location).receivers(player).extra(0).offset(0.5, 0.5, 0.5).count(5).spawn();
|
||||
Particle.FLAME.builder().location(location).receivers(player).extra(0).offset(0.5, 0.5, 0.5).count(3).spawn();
|
||||
Particle.SOUL_FIRE_FLAME.builder().location(location).receivers(player).offset(0.5, 0.5, 0.5).extra(0).count(2).spawn();
|
||||
player.playSound(location, org.bukkit.Sound.BLOCK_FIRE_EXTINGUISH, 0.5f, 0.5f);
|
||||
}
|
||||
|
||||
public static void disabledEffectMultiple(Player[] players, Location location)
|
||||
{
|
||||
Particle.CLOUD.builder().location(location).receivers(players).extra(0).offset(0.5, 0.5, 0.5).count(5).spawn();
|
||||
Particle.FLAME.builder().location(location).receivers(players).extra(0).offset(0.5, 0.5, 0.5).count(3).spawn();
|
||||
Particle.SOUL_FIRE_FLAME.builder().location(location).receivers(players).offset(0.5, 0.5, 0.5).extra(0).count(2).spawn();
|
||||
// note that the sound is played to everyone who is close enough to hear it
|
||||
players[0].getWorld().playSound(location, org.bukkit.Sound.BLOCK_FIRE_EXTINGUISH, 0.5f, 0.5f);
|
||||
}
|
||||
|
||||
public static void testConnections()
|
||||
{
|
||||
if (Plex.get().getSqlConnection().getDataSource() != null)
|
||||
{
|
||||
try (Connection con = Plex.get().getSqlConnection().getCon())
|
||||
{
|
||||
if (Plex.get().getStorageType() == StorageType.MARIADB)
|
||||
{
|
||||
PlexLog.log("Successfully enabled MySQL!");
|
||||
}
|
||||
else if (Plex.get().getStorageType() == StorageType.SQLITE)
|
||||
{
|
||||
PlexLog.log("Successfully enabled SQLite!");
|
||||
}
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
if (Plex.get().getMongoConnection().getDatastore() != null)
|
||||
{
|
||||
PlexLog.log("Successfully enabled MongoDB!");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Plex.get().getMongoConnection().getDatastore() != null)
|
||||
{
|
||||
PlexLog.log("Successfully enabled MongoDB!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isPluginCMD(String cmd, String pluginName)
|
||||
{
|
||||
Plugin plugin = Bukkit.getServer().getPluginManager().getPlugin(pluginName);
|
||||
if (plugin == null)
|
||||
{
|
||||
PlexLog.error(pluginName + " can not be found on the server! Make sure it is spelt correctly!");
|
||||
return false;
|
||||
}
|
||||
List<Command> cmds = PluginCommandYamlParser.parse(plugin);
|
||||
for (Command pluginCmd : cmds)
|
||||
{
|
||||
List<String> cmdAliases = pluginCmd.getAliases().size() > 0 ? pluginCmd.getAliases().stream().map(String::toLowerCase).collect(Collectors.toList()) : null;
|
||||
if (pluginCmd.getName().equalsIgnoreCase(cmd) || (cmdAliases != null && cmdAliases.contains(cmd.toLowerCase())))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static final MiniMessage safeMessage = MiniMessage.builder().tags(TagResolver.builder().resolvers(
|
||||
StandardTags.color(),
|
||||
StandardTags.decorations(),
|
||||
StandardTags.gradient(),
|
||||
StandardTags.rainbow(),
|
||||
StandardTags.reset()
|
||||
).build()).build();
|
||||
|
||||
public static String mmStripColor(String input)
|
||||
{
|
||||
return PlainTextComponentSerializer.plainText().serialize(mmDeserialize(input));
|
||||
}
|
||||
|
||||
public static Component mmDeserialize(String input)
|
||||
{
|
||||
boolean aprilFools = true; // true by default
|
||||
if (plugin.config.contains("april_fools"))
|
||||
{
|
||||
aprilFools = plugin.config.getBoolean("april_fools");
|
||||
}
|
||||
ZonedDateTime date = ZonedDateTime.now(ZoneId.of(TimeUtils.TIMEZONE));
|
||||
if (aprilFools && date.getMonth() == Month.APRIL && date.getDayOfMonth() == 1)
|
||||
{
|
||||
Component component = MiniMessage.miniMessage().deserialize(input); // removes existing tags
|
||||
return MiniMessage.miniMessage().deserialize("<rainbow>" + PlainTextComponentSerializer.plainText().serialize(component));
|
||||
}
|
||||
return MiniMessage.miniMessage().deserialize(input);
|
||||
}
|
||||
|
||||
public static Component mmCustomDeserialize(String input, TagResolver... resolvers)
|
||||
{
|
||||
return MiniMessage.builder().tags(TagResolver.builder().resolvers(resolvers).build()).build().deserialize(input);
|
||||
}
|
||||
|
||||
public static Component messageComponent(String entry, Object... objects)
|
||||
{
|
||||
return MiniMessage.miniMessage().deserialize(messageString(entry, objects));
|
||||
}
|
||||
|
||||
public static String messageString(String entry, Object... objects)
|
||||
{
|
||||
String f = plugin.messages.getString(entry);
|
||||
if (f == null)
|
||||
{
|
||||
throw new NullPointerException();
|
||||
}
|
||||
for (int i = 0; i < objects.length; i++)
|
||||
{
|
||||
f = f.replace("{" + i + "}", String.valueOf(objects[i]));
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
public static List<String> getPlayerNameList()
|
||||
{
|
||||
return Bukkit.getOnlinePlayers().stream().map(Player::getName).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static void broadcast(String s)
|
||||
{
|
||||
Bukkit.broadcast(MiniMessage.miniMessage().deserialize(s));
|
||||
}
|
||||
|
||||
public static void broadcast(Component component)
|
||||
{
|
||||
Bukkit.broadcast(component);
|
||||
}
|
||||
|
||||
public static void broadcastToAdmins(Component component)
|
||||
{
|
||||
Bukkit.getOnlinePlayers().stream().filter(pl -> PlayerCache.getPlexPlayer(pl.getUniqueId()).isAdminActive()).forEach(pl ->
|
||||
{
|
||||
pl.sendMessage(component);
|
||||
});
|
||||
}
|
||||
}
|
34
server/src/main/java/dev/plex/util/RandomUtil.java
Normal file
34
server/src/main/java/dev/plex/util/RandomUtil.java
Normal file
@ -0,0 +1,34 @@
|
||||
package dev.plex.util;
|
||||
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
|
||||
public class RandomUtil
|
||||
{
|
||||
|
||||
public static NamedTextColor getRandomColor()
|
||||
{
|
||||
NamedTextColor[] colors = NamedTextColor.NAMES.values().stream().filter(namedTextColor -> namedTextColor != NamedTextColor.BLACK && namedTextColor != NamedTextColor.DARK_BLUE).toArray(NamedTextColor[]::new);
|
||||
return colors[randomNum(colors.length)];
|
||||
}
|
||||
|
||||
public static boolean randomBoolean()
|
||||
{
|
||||
return ThreadLocalRandom.current().nextBoolean();
|
||||
}
|
||||
|
||||
public static int randomNum()
|
||||
{
|
||||
return ThreadLocalRandom.current().nextInt();
|
||||
}
|
||||
|
||||
public static int randomNum(int limit)
|
||||
{
|
||||
return ThreadLocalRandom.current().nextInt(limit);
|
||||
}
|
||||
|
||||
public static int randomNum(int start, int limit)
|
||||
{
|
||||
return ThreadLocalRandom.current().nextInt(start, limit);
|
||||
}
|
||||
}
|
57
server/src/main/java/dev/plex/util/ReflectionsUtil.java
Normal file
57
server/src/main/java/dev/plex/util/ReflectionsUtil.java
Normal file
@ -0,0 +1,57 @@
|
||||
package dev.plex.util;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.reflect.ClassPath;
|
||||
import dev.plex.Plex;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class ReflectionsUtil
|
||||
{
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
public static Set<Class<?>> getClassesFrom(String packageName)
|
||||
{
|
||||
Set<Class<?>> classes = new HashSet<>();
|
||||
try
|
||||
{
|
||||
ClassPath path = ClassPath.from(Plex.class.getClassLoader());
|
||||
ImmutableSet<ClassPath.ClassInfo> infoSet = path.getTopLevelClasses(packageName);
|
||||
infoSet.forEach(info ->
|
||||
{
|
||||
try
|
||||
{
|
||||
Class<?> clazz = Class.forName(info.getName());
|
||||
classes.add(clazz);
|
||||
}
|
||||
catch (ClassNotFoundException ex)
|
||||
{
|
||||
PlexLog.error("Unable to find class " + info.getName() + " in " + packageName);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
PlexLog.error("Something went wrong while fetching classes from " + packageName);
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
return Collections.unmodifiableSet(classes);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> Set<Class<? extends T>> getClassesBySubType(String packageName, Class<T> subType)
|
||||
{
|
||||
Set<Class<?>> loadedClasses = getClassesFrom(packageName);
|
||||
Set<Class<? extends T>> classes = new HashSet<>();
|
||||
loadedClasses.forEach(clazz ->
|
||||
{
|
||||
if (clazz.getSuperclass() == subType || Arrays.asList(clazz.getInterfaces()).contains(subType))
|
||||
{
|
||||
classes.add((Class<? extends T>)clazz);
|
||||
}
|
||||
});
|
||||
return Collections.unmodifiableSet(classes);
|
||||
}
|
||||
}
|
81
server/src/main/java/dev/plex/util/TimeUtils.java
Normal file
81
server/src/main/java/dev/plex/util/TimeUtils.java
Normal file
@ -0,0 +1,81 @@
|
||||
package dev.plex.util;
|
||||
|
||||
import dev.plex.Plex;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
import org.apache.commons.lang.math.NumberUtils;
|
||||
|
||||
public class TimeUtils
|
||||
{
|
||||
public static String TIMEZONE = Plex.get().config.getString("server.timezone");
|
||||
private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("MM/dd/yyyy 'at' hh:mm:ss a z");
|
||||
private static final Set<String> TIMEZONES = Set.of(TimeZone.getAvailableIDs());
|
||||
private static final List<String> timeUnits = new ArrayList<>()
|
||||
{{
|
||||
add("s");
|
||||
add("m");
|
||||
add("h");
|
||||
add("d");
|
||||
add("w");
|
||||
add("mo");
|
||||
add("y");
|
||||
}};
|
||||
|
||||
private static int parseInteger(String s) throws NumberFormatException
|
||||
{
|
||||
if (!NumberUtils.isNumber(s))
|
||||
{
|
||||
throw new NumberFormatException();
|
||||
}
|
||||
return Integer.parseInt(s);
|
||||
}
|
||||
|
||||
public static ZonedDateTime createDate(String arg)
|
||||
{
|
||||
ZonedDateTime time = ZonedDateTime.now(ZoneId.of(TimeUtils.TIMEZONE));
|
||||
for (String unit : timeUnits)
|
||||
{
|
||||
if (arg.endsWith(unit))
|
||||
{
|
||||
int duration = parseInteger(arg.replace(unit, ""));
|
||||
switch (unit)
|
||||
{
|
||||
case "y" -> time = time.plusYears(duration);
|
||||
case "mo" -> time = time.plusMonths(duration);
|
||||
case "w" -> time = time.plusWeeks(duration);
|
||||
case "d" -> time = time.plusDays(duration);
|
||||
case "h" -> time = time.plusHours(duration);
|
||||
case "m" -> time = time.plusMinutes(duration);
|
||||
case "s" -> time = time.plusSeconds(duration);
|
||||
}
|
||||
}
|
||||
}
|
||||
return time;
|
||||
}
|
||||
|
||||
public static String useTimezone(LocalDateTime date)
|
||||
{
|
||||
// Use UTC if the timezone is null or not set correctly
|
||||
if (TIMEZONE == null || !TIMEZONES.contains(TIMEZONE))
|
||||
{
|
||||
TIMEZONE = "Etc/UTC";
|
||||
}
|
||||
return DATE_FORMAT.withZone(ZoneId.of(TIMEZONE)).format(date);
|
||||
}
|
||||
|
||||
public static String useTimezone(ZonedDateTime date)
|
||||
{
|
||||
// Use UTC if the timezone is null or not set correctly
|
||||
if (TIMEZONE == null || !TIMEZONES.contains(TIMEZONE))
|
||||
{
|
||||
TIMEZONE = "Etc/UTC";
|
||||
}
|
||||
return DATE_FORMAT.withZone(ZoneId.of(TIMEZONE)).format(date);
|
||||
}
|
||||
}
|
199
server/src/main/java/dev/plex/util/UpdateChecker.java
Normal file
199
server/src/main/java/dev/plex/util/UpdateChecker.java
Normal file
@ -0,0 +1,199 @@
|
||||
package dev.plex.util;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import dev.plex.PlexBase;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import javax.annotation.Nonnull;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class UpdateChecker implements PlexBase
|
||||
{
|
||||
/*
|
||||
* -4 = Never checked for updates
|
||||
* -3 = Likely rate limited
|
||||
* -2 = Unknown commit
|
||||
* -1 = Error occurred
|
||||
* 0 = Up to date
|
||||
* > 0 = Number of commits behind
|
||||
*/
|
||||
private final String DOWNLOAD_PAGE = "https://ci.plex.us.org/job/";
|
||||
private String branch = plugin.config.getString("update_branch");
|
||||
private int distance = -4;
|
||||
|
||||
// Adapted from Paper
|
||||
private int fetchDistanceFromGitHub(@Nonnull String repo, @Nonnull String branch, @Nonnull String hash)
|
||||
{
|
||||
try
|
||||
{
|
||||
HttpURLConnection connection = (HttpURLConnection)new URL("https://api.github.com/repos/" + repo + "/compare/" + branch + "..." + hash).openConnection();
|
||||
connection.connect();
|
||||
if (connection.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND)
|
||||
{
|
||||
return -2; // Unknown commit
|
||||
}
|
||||
if (connection.getResponseCode() == HttpURLConnection.HTTP_FORBIDDEN)
|
||||
{
|
||||
return -3; // Rate limited likely
|
||||
}
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), Charsets.UTF_8)))
|
||||
{
|
||||
JsonObject obj = new Gson().fromJson(reader, JsonObject.class);
|
||||
String status = obj.get("status").getAsString();
|
||||
return switch (status)
|
||||
{
|
||||
case "identical" -> 0;
|
||||
case "behind" -> obj.get("behind_by").getAsInt();
|
||||
default -> -1;
|
||||
};
|
||||
}
|
||||
catch (JsonSyntaxException | NumberFormatException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// If verbose is 0, it will display nothing
|
||||
// If verbose is 1, it will only display a message if there is an update available
|
||||
// If verbose is 2, it will display all messages
|
||||
public boolean getUpdateStatusMessage(CommandSender sender, boolean cached, int verbosity)
|
||||
{
|
||||
if (branch == null)
|
||||
{
|
||||
PlexLog.error("You did not specify a branch to use for update checking. Defaulting to master.");
|
||||
branch = "master";
|
||||
}
|
||||
// If it's -4, it hasn't checked for updates yet
|
||||
if (distance == -4)
|
||||
{
|
||||
distance = fetchDistanceFromGitHub("plexusorg/Plex", branch, BuildInfo.getHead());
|
||||
PlexLog.debug("Never checked for updates, checking now...");
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the request isn't asked to be cached, fetch it
|
||||
if (!cached)
|
||||
{
|
||||
distance = fetchDistanceFromGitHub("plexusorg/Plex", branch, BuildInfo.getHead());
|
||||
PlexLog.debug("We have checked for updates before, but this request was not asked to be cached.");
|
||||
}
|
||||
else
|
||||
{
|
||||
PlexLog.debug("We have checked for updates before, using cache.");
|
||||
}
|
||||
}
|
||||
|
||||
switch (distance)
|
||||
{
|
||||
case -1 ->
|
||||
{
|
||||
if (verbosity == 2)
|
||||
{
|
||||
sender.sendMessage(Component.text("There was an error checking for updates.").color(NamedTextColor.RED));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case 0 ->
|
||||
{
|
||||
if (verbosity == 2)
|
||||
{
|
||||
sender.sendMessage(Component.text("Plex is up to date!").color(NamedTextColor.GREEN));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case -2 ->
|
||||
{
|
||||
if (verbosity == 2)
|
||||
{
|
||||
sender.sendMessage(Component.text("Unknown version, unable to check for updates.").color(NamedTextColor.RED));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
default ->
|
||||
{
|
||||
if (verbosity >= 1)
|
||||
{
|
||||
sender.sendMessage(Component.text("Plex is not up to date!", NamedTextColor.RED));
|
||||
sender.sendMessage(Component.text("Download a new version at: " + DOWNLOAD_PAGE).color(NamedTextColor.RED));
|
||||
sender.sendMessage(Component.text("Or run: /plex update").color(NamedTextColor.RED));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void updateJar(CommandSender sender, String name, boolean module)
|
||||
{
|
||||
CloseableHttpClient client = HttpClients.createDefault();
|
||||
AtomicReference<String> url = new AtomicReference<>(DOWNLOAD_PAGE + name);
|
||||
if (!module)
|
||||
{
|
||||
url.set(url.get() + "/job/" + branch);
|
||||
}
|
||||
PlexLog.debug(url.toString());
|
||||
HttpGet get = new HttpGet(url + "/lastSuccessfulBuild/api/json");
|
||||
try
|
||||
{
|
||||
HttpResponse response = client.execute(get);
|
||||
JSONObject object = new JSONObject(EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8));
|
||||
JSONObject artifact = object.getJSONArray("artifacts").getJSONObject(0);
|
||||
String jarFile = artifact.getString("fileName");
|
||||
sender.sendMessage(PlexUtils.mmDeserialize("<green>Downloading latest JAR file: " + jarFile));
|
||||
File copyTo;
|
||||
if (!module)
|
||||
{
|
||||
copyTo = new File(Bukkit.getUpdateFolderFile(), jarFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
copyTo = new File(plugin.getModulesFolder().getPath(), jarFile);
|
||||
}
|
||||
CompletableFuture.runAsync(() ->
|
||||
{
|
||||
try
|
||||
{
|
||||
FileUtils.copyURLToFile(
|
||||
new URL(url + "/lastSuccessfulBuild/artifact/build/libs/" + jarFile),
|
||||
copyTo
|
||||
);
|
||||
sender.sendMessage(PlexUtils.mmDeserialize("<green>New JAR file downloaded successfully."));
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
51
server/src/main/java/dev/plex/util/WebUtils.java
Normal file
51
server/src/main/java/dev/plex/util/WebUtils.java
Normal file
@ -0,0 +1,51 @@
|
||||
package dev.plex.util;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.UUID;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
public class WebUtils
|
||||
{
|
||||
public static Object simpleGET(String url)
|
||||
{
|
||||
try
|
||||
{
|
||||
URL u = new URL(url);
|
||||
HttpURLConnection connection = (HttpURLConnection)u.openConnection();
|
||||
connection.setRequestMethod("GET");
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
||||
String line;
|
||||
StringBuilder content = new StringBuilder();
|
||||
while ((line = in.readLine()) != null)
|
||||
{
|
||||
content.append(line);
|
||||
}
|
||||
in.close();
|
||||
connection.disconnect();
|
||||
return new JSONParser().parse(content.toString());
|
||||
}
|
||||
catch (IOException | ParseException ex)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static UUID getFromName(String name)
|
||||
{
|
||||
JSONObject profile;
|
||||
profile = (JSONObject)simpleGET("https://api.ashcon.app/mojang/v2/user/" + name);
|
||||
if (profile == null)
|
||||
{
|
||||
PlexLog.error("Profile from Ashcon API returned null!");
|
||||
return null;
|
||||
}
|
||||
String uuidString = (String)profile.get("uuid");
|
||||
return UUID.fromString(uuidString);
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package dev.plex.util.adapter;
|
||||
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParseException;
|
||||
import dev.plex.Plex;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
public class ZonedDateTimeDeserializer implements JsonDeserializer<ZonedDateTime>
|
||||
{
|
||||
private static String TIMEZONE = Plex.get().config.getString("server.timezone");
|
||||
@Override
|
||||
public ZonedDateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
|
||||
{
|
||||
Instant instant = Instant.ofEpochMilli(json.getAsJsonPrimitive().getAsLong());
|
||||
return ZonedDateTime.ofInstant(instant, ZoneId.of(TIMEZONE));
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package dev.plex.util.adapter;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
import dev.plex.Plex;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
public class ZonedDateTimeSerializer implements JsonSerializer<ZonedDateTime>
|
||||
{
|
||||
private static String TIMEZONE = Plex.get().config.getString("server.timezone");
|
||||
@Override
|
||||
public JsonElement serialize(ZonedDateTime src, Type typeOfSrc, JsonSerializationContext context)
|
||||
{
|
||||
return new JsonPrimitive(src.toInstant().toEpochMilli());
|
||||
}
|
||||
}
|
61
server/src/main/java/dev/plex/util/item/ItemBuilder.java
Normal file
61
server/src/main/java/dev/plex/util/item/ItemBuilder.java
Normal file
@ -0,0 +1,61 @@
|
||||
package dev.plex.util.item;
|
||||
|
||||
import java.util.Arrays;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.attribute.Attribute;
|
||||
import org.bukkit.attribute.AttributeModifier;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.inventory.ItemFlag;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
public class ItemBuilder
|
||||
{
|
||||
|
||||
private final ItemStack itemStack;
|
||||
private final ItemMeta meta;
|
||||
|
||||
public ItemBuilder(Material material)
|
||||
{
|
||||
this.itemStack = new ItemStack(material);
|
||||
this.meta = itemStack.getItemMeta();
|
||||
}
|
||||
|
||||
public ItemBuilder lore(Component... lore)
|
||||
{
|
||||
this.meta.lore(Arrays.asList(lore));
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemBuilder displayName(Component displayName)
|
||||
{
|
||||
this.meta.displayName(displayName);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemBuilder addEnchantment(Enchantment enchantment, int level)
|
||||
{
|
||||
this.meta.addEnchant(enchantment, level, true);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemBuilder addItemFlag(ItemFlag... flags)
|
||||
{
|
||||
this.meta.addItemFlags(flags);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemBuilder addAttributeModifier(Attribute attribute, AttributeModifier modifier)
|
||||
{
|
||||
this.meta.addAttributeModifier(attribute, modifier);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemStack build()
|
||||
{
|
||||
this.itemStack.setItemMeta(this.meta);
|
||||
return this.itemStack;
|
||||
}
|
||||
|
||||
}
|
21
server/src/main/java/dev/plex/util/menu/AbstractMenu.java
Normal file
21
server/src/main/java/dev/plex/util/menu/AbstractMenu.java
Normal file
@ -0,0 +1,21 @@
|
||||
package dev.plex.util.menu;
|
||||
|
||||
import dev.plex.Plex;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
public abstract class AbstractMenu implements Listener
|
||||
{
|
||||
private String name;
|
||||
|
||||
public AbstractMenu(String name)
|
||||
{
|
||||
this.name = name;
|
||||
|
||||
Plex.get().getServer().getPluginManager().registerEvents(this, Plex.get());
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
}
|
20
server/src/main/java/dev/plex/util/menu/IMenu.java
Normal file
20
server/src/main/java/dev/plex/util/menu/IMenu.java
Normal file
@ -0,0 +1,20 @@
|
||||
package dev.plex.util.menu;
|
||||
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
|
||||
public interface IMenu
|
||||
{
|
||||
|
||||
Inventory getInventory();
|
||||
|
||||
|
||||
void openInv(Player player);
|
||||
|
||||
@EventHandler
|
||||
void onClick(InventoryClickEvent event);
|
||||
|
||||
}
|
Reference in New Issue
Block a user