15 Commits
0.7 ... ver/0.8

Author SHA1 Message Date
afd793cdba Plex 0.8 2022-03-05 22:54:02 -06:00
1d9662acde Merge branch 'master' of https://github.com/PlexDevelopment/Plex 2022-03-05 19:56:51 -06:00
89199eb580 Let's not make ourselves permbanned by default 2022-03-05 19:56:46 -06:00
0aa9669f5f lol i disabled modules on reload 2022-03-05 17:22:30 -08:00
46d8debd18 - don't reload indefinite bans 2022-03-05 17:20:51 -08:00
69541a20b8 - Add command and listener support 2022-03-05 17:17:14 -08:00
87ddf355b5 - Begin BETA module system 2022-03-05 17:04:34 -08:00
2804f6bc41 - Change indefinite bans config system to be more organized
- Store indefinite bans through an object instead
- Add debug redis messages
- Make loading keys from the jar optional
2022-03-05 15:44:38 -08:00
aa5e184a56 Don't check for updates if it's a snapshot version 2022-03-05 17:28:52 -06:00
0a3594370a Merge pull request #5 from PlexDevelopment/dev/1.18.2
Update to 1.18.2
2022-03-04 15:50:47 -06:00
2cdd3a0e78 Merge branch 'master' into dev/1.18.2 2022-03-04 15:50:34 -06:00
14fb24a380 Bump to 0.8-SNAPSHOT 2022-03-03 19:51:07 -06:00
e258e27814 Replace with Kyori 2022-03-03 16:56:52 -06:00
41f4029877 Merge branch 'master' of https://github.com/PlexDevelopment/Plex into dev/1.18.2 2022-03-03 15:45:51 -06:00
0b5425b8d2 Begin work on 1.18.2
- Add update checking
- World generation is broken
- Won't compile unless 1.18.2 is in your local Maven repository
- No longer need MiniMessage bundled in Plex
- Customizable namehistory
- Set comments in config.yml if they're missing
2022-03-03 15:45:19 -06:00
23 changed files with 403 additions and 218 deletions

View File

@ -19,10 +19,6 @@ repositories {
url = uri("https://repo.maven.apache.org/maven2/") url = uri("https://repo.maven.apache.org/maven2/")
} }
maven {
name = "sonatype-oss-snapshots"
url = uri("https://oss.sonatype.org/content/repositories/snapshots/")
}
mavenCentral() mavenCentral()
} }
@ -36,17 +32,13 @@ dependencies {
library "org.mariadb.jdbc:mariadb-java-client:3.0.3" library "org.mariadb.jdbc:mariadb-java-client:3.0.3"
library "org.apache.httpcomponents:httpclient:4.5.13" library "org.apache.httpcomponents:httpclient:4.5.13"
library "org.apache.commons:commons-lang3:3.12.0" library "org.apache.commons:commons-lang3:3.12.0"
compileOnly "io.papermc.paper:paper-api:1.18.1-R0.1-SNAPSHOT" compileOnly "io.papermc.paper:paper-api:1.18.2-R0.1-SNAPSHOT"
implementation "org.bstats:bstats-base:3.0.0" implementation "org.bstats:bstats-base:3.0.0"
implementation "org.bstats:bstats-bukkit:3.0.0" implementation "org.bstats:bstats-bukkit:3.0.0"
implementation("net.kyori:adventure-text-minimessage:4.2.0-SNAPSHOT") {
exclude group: "net.kyori", module: "adventure-api"
exclude group: "org.jetbrains", module: "annotations"
}
} }
group = "dev.plex" group = "dev.plex"
version = "0.7" version = "0.8"
description = "Plex" description = "Plex"
shadowJar { shadowJar {

View File

@ -9,6 +9,7 @@ import dev.plex.cache.SQLPlayerData;
import dev.plex.config.Config; import dev.plex.config.Config;
import dev.plex.handlers.CommandHandler; import dev.plex.handlers.CommandHandler;
import dev.plex.handlers.ListenerHandler; import dev.plex.handlers.ListenerHandler;
import dev.plex.module.ModuleManager;
import dev.plex.player.PlexPlayer; import dev.plex.player.PlexPlayer;
import dev.plex.player.PunishedPlayer; import dev.plex.player.PunishedPlayer;
import dev.plex.punishment.PunishmentManager; import dev.plex.punishment.PunishmentManager;
@ -22,21 +23,25 @@ import dev.plex.util.PlexLog;
import dev.plex.util.PlexUtils; import dev.plex.util.PlexUtils;
import dev.plex.util.UpdateChecker; import dev.plex.util.UpdateChecker;
import dev.plex.world.CustomWorld; import dev.plex.world.CustomWorld;
import java.util.UUID;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import org.bstats.bukkit.Metrics; import org.bstats.bukkit.Metrics;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
import java.util.UUID;
@Getter @Getter
@Setter @Setter
public class Plex extends JavaPlugin public class Plex extends JavaPlugin {
{
private static Plex plugin; private static Plex plugin;
public Config config; public Config config;
public Config messages; public Config messages;
public Config indefBans; public Config indefBans;
public File modulesFolder;
private StorageType storageType = StorageType.SQLITE; private StorageType storageType = StorageType.SQLITE;
private SQLConnection sqlConnection; private SQLConnection sqlConnection;
@ -46,6 +51,7 @@ public class Plex extends JavaPlugin
private MongoPlayerData mongoPlayerData; private MongoPlayerData mongoPlayerData;
private SQLPlayerData sqlPlayerData; private SQLPlayerData sqlPlayerData;
private ModuleManager moduleManager;
private RankManager rankManager; private RankManager rankManager;
private ServiceManager serviceManager; private ServiceManager serviceManager;
@ -57,39 +63,43 @@ public class Plex extends JavaPlugin
private String system; private String system;
public static Plex get() public static Plex get() {
{
return plugin; return plugin;
} }
@Override @Override
public void onLoad() public void onLoad() {
{
plugin = this; plugin = this;
config = new Config(this, "config.yml"); config = new Config(this, "config.yml");
messages = new Config(this, "messages.yml"); messages = new Config(this, "messages.yml");
indefBans = new Config(this, "indefbans.yml"); indefBans = new Config(this, "indefbans.yml");
modulesFolder = new File(this.getDataFolder() + File.separator + "modules");
if (!modulesFolder.exists()) modulesFolder.mkdir();
sqlConnection = new SQLConnection(); sqlConnection = new SQLConnection();
mongoConnection = new MongoConnection(); mongoConnection = new MongoConnection();
redisConnection = new RedisConnection(); redisConnection = new RedisConnection();
moduleManager = new ModuleManager();
moduleManager.loadAllModules();
moduleManager.loadModules();
} }
@Override @Override
public void onEnable() public void onEnable() {
{
config.load(); config.load();
messages.load(); messages.load();
indefBans.load(); indefBans.load(false);
moduleManager.enableModules();
system = config.getString("commands.permissions"); system = config.getString("commands.permissions");
try try {
{
PlexUtils.testConnections(); PlexUtils.testConnections();
PlexLog.log("Connected to " + storageType.name().toUpperCase()); PlexLog.log("Connected to " + storageType.name().toUpperCase());
} } catch (Exception e) {
catch (Exception e)
{
PlexLog.error("Failed to connect to " + storageType.name().toUpperCase()); PlexLog.error("Failed to connect to " + storageType.name().toUpperCase());
e.printStackTrace(); e.printStackTrace();
} }
@ -101,29 +111,22 @@ public class Plex extends JavaPlugin
Metrics metrics = new Metrics(this, 14143); Metrics metrics = new Metrics(this, 14143);
PlexLog.log("Enabled Metrics"); PlexLog.log("Enabled Metrics");
if (redisConnection.isEnabled()) if (redisConnection.isEnabled()) {
{
redisConnection.getJedis(); redisConnection.getJedis();
PlexLog.log("Connected to Redis!"); PlexLog.log("Connected to Redis!");
} } else {
else
{
PlexLog.log("Redis is disabled in the configuration file, not connecting."); PlexLog.log("Redis is disabled in the configuration file, not connecting.");
} }
if (storageType == StorageType.MONGODB) if (storageType == StorageType.MONGODB) {
{
mongoPlayerData = new MongoPlayerData(); mongoPlayerData = new MongoPlayerData();
} } else {
else
{
sqlPlayerData = new SQLPlayerData(); sqlPlayerData = new SQLPlayerData();
} }
new ListenerHandler(); new ListenerHandler();
new CommandHandler(); new CommandHandler();
rankManager = new RankManager(); rankManager = new RankManager();
rankManager.generateDefaultRanks(); rankManager.generateDefaultRanks();
rankManager.importDefaultRanks(); rankManager.importDefaultRanks();
@ -145,52 +148,46 @@ public class Plex extends JavaPlugin
} }
@Override @Override
public void onDisable() public void onDisable() {
{
Bukkit.getOnlinePlayers().forEach(player -> Bukkit.getOnlinePlayers().forEach(player ->
{ {
PlexPlayer plexPlayer = PlayerCache.getPlexPlayerMap().get(player.getUniqueId()); //get the player because it's literally impossible for them to not have an object PlexPlayer plexPlayer = PlayerCache.getPlexPlayerMap().get(player.getUniqueId()); //get the player because it's literally impossible for them to not have an object
if (plugin.getRankManager().isAdmin(plexPlayer)) if (plugin.getRankManager().isAdmin(plexPlayer)) {
{
plugin.getAdminList().removeFromCache(UUID.fromString(plexPlayer.getUuid())); plugin.getAdminList().removeFromCache(UUID.fromString(plexPlayer.getUuid()));
} }
if (mongoPlayerData != null) //back to mongo checking if (mongoPlayerData != null) //back to mongo checking
{ {
mongoPlayerData.update(plexPlayer); //update the player's document mongoPlayerData.update(plexPlayer); //update the player's document
} } else if (sqlPlayerData != null) //sql checking
else if (sqlPlayerData != null) //sql checking
{ {
sqlPlayerData.update(plexPlayer); sqlPlayerData.update(plexPlayer);
} }
}); });
if (redisConnection.isEnabled() && redisConnection.getJedis().isConnected()) if (redisConnection.isEnabled() && redisConnection.getJedis().isConnected()) {
{
PlexLog.log("Disabling Redis/Jedis. No memory leaks in this Anarchy server!"); PlexLog.log("Disabling Redis/Jedis. No memory leaks in this Anarchy server!");
redisConnection.getJedis().close(); redisConnection.getJedis().close();
} }
moduleManager.disableModules();
} }
private void generateWorlds() private void generateWorlds() {
{
PlexLog.log("Generating any worlds if needed..."); PlexLog.log("Generating any worlds if needed...");
for (String key : config.getConfigurationSection("worlds").getKeys(false)) for (String key : config.getConfigurationSection("worlds").getKeys(false)) {
{
CustomWorld.generateConfigFlatWorld(key); CustomWorld.generateConfigFlatWorld(key);
} }
PlexLog.log("Finished with world generation!"); PlexLog.log("Finished with world generation!");
} }
private void reloadPlayers() private void reloadPlayers() {
{
Bukkit.getOnlinePlayers().forEach(player -> Bukkit.getOnlinePlayers().forEach(player ->
{ {
PlexPlayer plexPlayer = DataUtils.getPlayer(player.getUniqueId()); PlexPlayer plexPlayer = DataUtils.getPlayer(player.getUniqueId());
PlayerCache.getPlexPlayerMap().put(player.getUniqueId(), plexPlayer); //put them into the cache PlayerCache.getPlexPlayerMap().put(player.getUniqueId(), plexPlayer); //put them into the cache
PlayerCache.getPunishedPlayerMap().put(player.getUniqueId(), new PunishedPlayer(player.getUniqueId())); PlayerCache.getPunishedPlayerMap().put(player.getUniqueId(), new PunishedPlayer(player.getUniqueId()));
if (plugin.getRankManager().isAdmin(plexPlayer)) if (plugin.getRankManager().isAdmin(plexPlayer)) {
{
Admin admin = new Admin(UUID.fromString(plexPlayer.getUuid())); Admin admin = new Admin(UUID.fromString(plexPlayer.getUuid()));
admin.setRank(plexPlayer.getRankFromString()); admin.setRank(plexPlayer.getRankFromString());

View File

@ -29,19 +29,19 @@ public class Admin
/** /**
* Returns if the admin has command spy or not * Returns if the admin has command spy or not
* <br> * <br>
* Contains a #isCommandSpy and #setCommandSpy by lombok * Contains a #isCommandSpy and #setCommandSpy by Lombok
*/ */
private boolean commandSpy = true; private boolean commandSpy = false;
/** /**
* Returns if the admin has staff chat toggled or not * Returns if the admin has admin chat toggled or not
* <br> * <br>
* Contains a #isStaffChat and #setStaffChat by lombok * Contains a #isAdminChat and #setAdminChat by Lombok
*/ */
private boolean staffChat = false; private boolean adminChat = false;
/** /**
* Creates an admin with the startig ADMIN rank * Creates an admin with the ADMIN rank as the default rank
* *
* @param uuid * @param uuid
* @see UUID * @see UUID
@ -52,6 +52,4 @@ public class Admin
this.uuid = uuid; this.uuid = uuid;
this.rank = Rank.ADMIN; this.rank = Rank.ADMIN;
} }
} }

View File

@ -5,6 +5,7 @@ import com.google.common.collect.Maps;
import dev.morphia.Datastore; import dev.morphia.Datastore;
import dev.morphia.query.Query; import dev.morphia.query.Query;
import dev.plex.Plex; import dev.plex.Plex;
import dev.plex.PlexBase;
import dev.plex.player.PlexPlayer; import dev.plex.player.PlexPlayer;
import dev.plex.rank.enums.Rank; import dev.plex.rank.enums.Rank;
import dev.plex.storage.StorageType; import dev.plex.storage.StorageType;
@ -23,7 +24,7 @@ import java.util.stream.Collectors;
* @see Admin * @see Admin
*/ */
public class AdminList public class AdminList extends PlexBase
{ {
/** /**
* Key/Value storage, where the key is the unique ID of the admin * Key/Value storage, where the key is the unique ID of the admin
@ -59,15 +60,15 @@ public class AdminList
public List<String> getAllAdmins() public List<String> getAllAdmins()
{ {
List<String> admins = Lists.newArrayList(); List<String> admins = Lists.newArrayList();
if (Plex.get().getStorageType() == StorageType.MONGODB) if (plugin.getStorageType() == StorageType.MONGODB)
{ {
Datastore store = Plex.get().getMongoConnection().getDatastore(); Datastore store = plugin.getMongoConnection().getDatastore();
Query<PlexPlayer> query = store.find(PlexPlayer.class); Query<PlexPlayer> query = store.find(PlexPlayer.class);
admins.addAll(query.stream().filter(plexPlayer -> plexPlayer.getRankFromString().isAtLeast(Rank.ADMIN)).map(PlexPlayer::getName).collect(Collectors.toList())); admins.addAll(query.stream().filter(plexPlayer -> plexPlayer.getRankFromString().isAtLeast(Rank.ADMIN)).map(PlexPlayer::getName).collect(Collectors.toList()));
} }
else else
{ {
try (Connection con = Plex.get().getSqlConnection().getCon()) try (Connection con = plugin.getSqlConnection().getCon())
{ {
PreparedStatement statement = con.prepareStatement("SELECT * FROM `players` WHERE rank IN(?, ?, ?)"); PreparedStatement statement = con.prepareStatement("SELECT * FROM `players` WHERE rank IN(?, ?, ?)");
statement.setString(1, Rank.ADMIN.name().toLowerCase()); statement.setString(1, Rank.ADMIN.name().toLowerCase());
@ -79,7 +80,6 @@ public class AdminList
{ {
admins.add(set.getString("name")); admins.add(set.getString("name"));
} }
} }
catch (SQLException throwables) catch (SQLException throwables)
{ {
@ -88,5 +88,4 @@ public class AdminList
} }
return admins; return admins;
} }
} }

View File

@ -516,7 +516,7 @@ public abstract class PlexCommand extends Command implements PluginIdentifiableC
*/ */
protected Component mmString(String s) protected Component mmString(String s)
{ {
return MiniMessage.miniMessage().parse(s); return MiniMessage.miniMessage().deserialize(s);
} }
public Rank getLevel() public Rank getLevel()

View File

@ -26,7 +26,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@CommandPermissions(level = Rank.OP, source = RequiredCommandSource.ANY) @CommandPermissions(level = Rank.OP, source = RequiredCommandSource.ANY)
@CommandParameters(name = "admin", usage = "/<command> <add | remove | setrank | list> [player] [rank]", aliases = "saconfig,slconfig,adminconfig,adminmanage", description = "Manage all admins") @CommandParameters(name = "admin", usage = "/<command> <add <player> | remove <player> | setrank <player> <rank> | list>", aliases = "saconfig,slconfig,adminconfig,adminmanage", description = "Manage all admins")
public class AdminCMD extends PlexCommand public class AdminCMD extends PlexCommand
{ {
//TODO: Better return messages //TODO: Better return messages

View File

@ -49,7 +49,7 @@ public class LockupCMD extends PlexCommand
} }
punishedPlayer.setLockedUp(!punishedPlayer.isLockedUp()); punishedPlayer.setLockedUp(!punishedPlayer.isLockedUp());
PlexUtils.broadcast(messageComponent(punishedPlayer.isLockedUp() ? "lockedUpPlayer" : "unlockedUpPlayer", sender.getName(), player.getName())); PlexUtils.broadcast(messageComponent(punishedPlayer.isLockedUp() ? "lockedUpPlayer" : "unlockedPlayer", sender.getName(), player.getName()));
return null; return null;
} }

View File

@ -49,11 +49,9 @@ public class NameHistoryCMD extends PlexCommand
if (history.getLocalDateTime() != null) if (history.getLocalDateTime() != null)
{ {
historyList.add( historyList.add(
Component.text(history.getUsername()).color(NamedTextColor.GOLD) messageComponent("nameHistoryBody",
.append(Component.space()) history.getUsername(),
.append(Component.text("-").color(NamedTextColor.DARK_GRAY)) DATE_FORMAT.format(history.getLocalDateTime())));
.append(Component.space())
.append(Component.text(DATE_FORMAT.format(history.getLocalDateTime())).color(NamedTextColor.GOLD)));
} }
else else
{ {
@ -62,8 +60,8 @@ public class NameHistoryCMD extends PlexCommand
.append(Component.space())); .append(Component.space()));
} }
}); });
send(sender, Component.text("Name History (" + username + ")").color(NamedTextColor.GOLD)); send(sender, messageComponent("nameHistoryTitle", username));
send(sender, Component.text("-----------------------------").color(NamedTextColor.GOLD).decoration(TextDecoration.STRIKETHROUGH, true)); send(sender, messageComponent("nameHistorySeparator"));
historyList.forEach(component -> send(sender, component)); historyList.forEach(component -> send(sender, component));
return null; return null;
} }

View File

@ -1,54 +1,52 @@
package dev.plex.command.impl; package dev.plex.command.impl;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import dev.plex.Plex;
import dev.plex.command.PlexCommand; import dev.plex.command.PlexCommand;
import dev.plex.command.annotation.CommandParameters; import dev.plex.command.annotation.CommandParameters;
import dev.plex.command.annotation.CommandPermissions; import dev.plex.command.annotation.CommandPermissions;
import dev.plex.command.exception.CommandFailException; import dev.plex.command.exception.CommandFailException;
import dev.plex.command.source.RequiredCommandSource; import dev.plex.command.source.RequiredCommandSource;
import dev.plex.module.PlexModule;
import dev.plex.module.PlexModuleFile;
import dev.plex.rank.enums.Rank; import dev.plex.rank.enums.Rank;
import java.util.List;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.apache.commons.lang.StringUtils;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.stream.Collectors;
@CommandPermissions(level = Rank.OP, permission = "plex.plex", source = RequiredCommandSource.ANY) @CommandPermissions(level = Rank.OP, permission = "plex.plex", source = RequiredCommandSource.ANY)
@CommandParameters(name = "plex", usage = "/<command> [reload | redis]", aliases = "plexhelp", description = "Show information about Plex or reload it") @CommandParameters(name = "plex", usage = "/<command> [reload | redis | modules] [reload]", aliases = "plexhelp", description = "Show information about Plex or reload it")
public class PlexCMD extends PlexCommand public class PlexCMD extends PlexCommand {
{
// Don't modify this command // Don't modify this command
@Override @Override
protected Component execute(@NotNull CommandSender sender, @Nullable Player playerSender, String[] args) protected Component execute(@NotNull CommandSender sender, @Nullable Player playerSender, String[] args) {
{ if (args.length == 0) {
if (args.length == 0)
{
send(sender, ChatColor.LIGHT_PURPLE + "Plex - A new freedom plugin."); send(sender, ChatColor.LIGHT_PURPLE + "Plex - A new freedom plugin.");
send(sender, ChatColor.LIGHT_PURPLE + "Plugin version: " + plugin.getDescription().getVersion()); send(sender, ChatColor.LIGHT_PURPLE + "Plugin version: " + plugin.getDescription().getVersion());
return componentFromString(ChatColor.LIGHT_PURPLE + "Authors: " + ChatColor.GOLD + "Telesphoreo, Taahh"); return componentFromString(ChatColor.LIGHT_PURPLE + "Authors: " + ChatColor.GOLD + "Telesphoreo, Taahh");
} }
if (args[0].equalsIgnoreCase("reload")) if (args[0].equalsIgnoreCase("reload")) {
{
checkRank(sender, Rank.SENIOR_ADMIN, "plex.reload"); checkRank(sender, Rank.SENIOR_ADMIN, "plex.reload");
plugin.config.load(); plugin.config.load();
send(sender, "Reloaded config file"); send(sender, "Reloaded config file");
plugin.messages.load(); plugin.messages.load();
send(sender, "Reloaded messages file"); send(sender, "Reloaded messages file");
plugin.indefBans.load(); plugin.indefBans.load(false);
plugin.getPunishmentManager().mergeIndefiniteBans(); plugin.getPunishmentManager().mergeIndefiniteBans();
send(sender, "Reloaded indefinite bans"); send(sender, "Reloaded indefinite bans");
plugin.getRankManager().importDefaultRanks(); plugin.getRankManager().importDefaultRanks();
send(sender, "Imported ranks"); send(sender, "Imported ranks");
send(sender, "Plex successfully reloaded."); send(sender, "Plex successfully reloaded.");
} } else if (args[0].equalsIgnoreCase("redis")) {
else if (args[0].equalsIgnoreCase("redis"))
{
checkRank(sender, Rank.SENIOR_ADMIN, "plex.redis"); checkRank(sender, Rank.SENIOR_ADMIN, "plex.redis");
if (!plugin.getRedisConnection().isEnabled()) if (!plugin.getRedisConnection().isEnabled()) {
{
throw new CommandFailException("&cRedis is not enabled."); throw new CommandFailException("&cRedis is not enabled.");
} }
plugin.getRedisConnection().getJedis().set("test", "123"); plugin.getRedisConnection().getJedis().set("test", "123");
@ -56,16 +54,24 @@ public class PlexCMD extends PlexCommand
send(sender, plugin.getRedisConnection().getJedis().get("test")); send(sender, plugin.getRedisConnection().getJedis().get("test"));
plugin.getRedisConnection().getJedis().close(); plugin.getRedisConnection().getJedis().close();
} }
else if (args[0].equalsIgnoreCase("modules")) {
{ if (args.length == 1) {
return MiniMessage.miniMessage().deserialize("<gold>Modules (" + plugin.getModuleManager().getModules().size() + "): <yellow>" + StringUtils.join(plugin.getModuleManager().getModules().stream().map(PlexModule::getPlexModuleFile).map(PlexModuleFile::getName).collect(Collectors.toList()), ", "));
}
if (args[1].equalsIgnoreCase("reload")) {
plugin.getModuleManager().unloadModules();
plugin.getModuleManager().loadAllModules();
plugin.getModuleManager().loadModules();
plugin.getModuleManager().enableModules();
}
} else {
return usage(); return usage();
} }
return null; return null;
} }
@Override @Override
public @NotNull List<String> tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) throws IllegalArgumentException public @NotNull List<String> tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) throws IllegalArgumentException {
{
return ImmutableList.of("reload", "redis"); return ImmutableList.of("reload", "redis");
} }
} }

View File

@ -2,16 +2,16 @@ package dev.plex.config;
import dev.plex.Plex; import dev.plex.Plex;
import dev.plex.util.PlexLog; import dev.plex.util.PlexLog;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File; import java.io.File;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import org.bukkit.configuration.file.YamlConfiguration;
/** /**
* Creates a custom Config object * Creates a custom Config object
*/ */
public class Config extends YamlConfiguration public class Config extends YamlConfiguration {
{
/** /**
* The plugin instance * The plugin instance
*/ */
@ -38,35 +38,35 @@ public class Config extends YamlConfiguration
* @param plugin The plugin instance * @param plugin The plugin instance
* @param name The file name * @param name The file name
*/ */
public Config(Plex plugin, String name) public Config(Plex plugin, String name) {
{
this.plugin = plugin; this.plugin = plugin;
this.file = new File(plugin.getDataFolder(), name); this.file = new File(plugin.getDataFolder(), name);
this.name = name; this.name = name;
if (!file.exists()) if (!file.exists()) {
{
saveDefault(); saveDefault();
} }
} }
public void load()
{
this.load(true);
}
/** /**
* Loads the configuration file * Loads the configuration file
*/ */
public void load() public void load(boolean loadFromFile) {
{ try {
try if (loadFromFile) {
{
YamlConfiguration externalYamlConfig = YamlConfiguration.loadConfiguration(file); YamlConfiguration externalYamlConfig = YamlConfiguration.loadConfiguration(file);
InputStreamReader internalConfigFileStream = new InputStreamReader(Plex.get().getResource(name), StandardCharsets.UTF_8); InputStreamReader internalConfigFileStream = new InputStreamReader(Plex.get().getResource(name), StandardCharsets.UTF_8);
YamlConfiguration internalYamlConfig = YamlConfiguration.loadConfiguration(internalConfigFileStream); YamlConfiguration internalYamlConfig = YamlConfiguration.loadConfiguration(internalConfigFileStream);
// Gets all the keys inside the internal file and iterates through all of it's key pairs // Gets all the keys inside the internal file and iterates through all of it's key pairs
for (String string : internalYamlConfig.getKeys(true)) for (String string : internalYamlConfig.getKeys(true)) {
{
// Checks if the external file contains the key already. // Checks if the external file contains the key already.
if (!externalYamlConfig.contains(string)) if (!externalYamlConfig.contains(string)) {
{
// If it doesn't contain the key, we set the key based off what was found inside the plugin jar // If it doesn't contain the key, we set the key based off what was found inside the plugin jar
externalYamlConfig.setComments(string, internalYamlConfig.getComments(string)); externalYamlConfig.setComments(string, internalYamlConfig.getComments(string));
externalYamlConfig.set(string, internalYamlConfig.get(string)); externalYamlConfig.set(string, internalYamlConfig.get(string));
@ -74,16 +74,14 @@ public class Config extends YamlConfiguration
added = true; added = true;
} }
} }
if (added) if (added) {
{
externalYamlConfig.save(file); externalYamlConfig.save(file);
PlexLog.log("Saving new file..."); PlexLog.log("Saving new file...");
added = false; added = false;
} }
super.load(file);
} }
catch (Exception ex) super.load(file);
{ } catch (Exception ex) {
ex.printStackTrace(); ex.printStackTrace();
} }
} }
@ -91,14 +89,10 @@ public class Config extends YamlConfiguration
/** /**
* Saves the configuration file * Saves the configuration file
*/ */
public void save() public void save() {
{ try {
try
{
super.save(file); super.save(file);
} } catch (Exception ex) {
catch (Exception ex)
{
ex.printStackTrace(); ex.printStackTrace();
} }
} }
@ -106,8 +100,7 @@ public class Config extends YamlConfiguration
/** /**
* Moves the configuration file from the plugin's resources folder to the data folder (plugins/Plex/) * Moves the configuration file from the plugin's resources folder to the data folder (plugins/Plex/)
*/ */
private void saveDefault() private void saveDefault() {
{
plugin.saveResource(name, false); plugin.saveResource(name, false);
} }
} }

View File

@ -0,0 +1,112 @@
package dev.plex.module;
import com.google.common.collect.Lists;
import dev.plex.Plex;
import dev.plex.module.exception.ModuleLoadException;
import dev.plex.util.PlexLog;
import lombok.Getter;
import org.apache.logging.log4j.LogManager;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
@Getter
public class ModuleManager {
private final List<PlexModule> modules = Lists.newArrayList();
public void loadAllModules() {
this.modules.clear();
PlexLog.debug(String.valueOf(Plex.get().getModulesFolder().listFiles().length));
Arrays.stream(Plex.get().getModulesFolder().listFiles()).forEach(file -> {
if (file.getName().endsWith(".jar")) {
try {
URLClassLoader loader = new URLClassLoader(
new URL[]{file.toURI().toURL()},
Plex.class.getClassLoader()
);
InputStreamReader internalModuleFile = new InputStreamReader(loader.getResourceAsStream("module.yml"), StandardCharsets.UTF_8);
YamlConfiguration internalModuleConfig = YamlConfiguration.loadConfiguration(internalModuleFile);
String name = internalModuleConfig.getString("name");
if (name == null)
{
throw new ModuleLoadException("Plex module name can't be null!");
}
String main = internalModuleConfig.getString("main");
if (main == null)
{
throw new ModuleLoadException("Plex module main class can't be null!");
}
String description = internalModuleConfig.getString("description", "A Plex module");
String version = internalModuleConfig.getString("version", "1.0");
PlexModuleFile plexModuleFile = new PlexModuleFile(name, main, description, version);
Class<? extends PlexModule> module = (Class<? extends PlexModule>) Class.forName(main, true, loader);
PlexModule plexModule = module.getConstructor().newInstance();
plexModule.setPlex(Plex.get());
plexModule.setPlexModuleFile(plexModuleFile);
plexModule.setDataFolder(new File(Plex.get().getModulesFolder() + File.separator + plexModuleFile.getName()));
if (!plexModule.getDataFolder().exists()) plexModule.getDataFolder().mkdir();
plexModule.setLogger(LogManager.getLogger(plexModuleFile.getName()));
modules.add(plexModule);
} catch (MalformedURLException | ClassNotFoundException | InvocationTargetException | InstantiationException | IllegalAccessException | NoSuchMethodException e) {
e.printStackTrace();
}
}
});
}
public void loadModules() {
this.modules.forEach(module -> {
PlexLog.log("Loading module " + module.getPlexModuleFile().getName() + " with version " + module.getPlexModuleFile().getVersion());
module.load();
});
}
public void enableModules() {
this.modules.forEach(module -> {
PlexLog.log("Enabling module " + module.getPlexModuleFile().getName() + " with version " + module.getPlexModuleFile().getVersion());
module.enable();
});
}
public void disableModules() {
this.modules.forEach(module -> {
PlexLog.log("Disabling module " + module.getPlexModuleFile().getName() + " with version " + module.getPlexModuleFile().getVersion());
module.getCommands().stream().toList().forEach(plexCommand -> {
module.unregisterCommand(plexCommand);
Plex.get().getServer().getCommandMap().getKnownCommands().remove(plexCommand.getName());
plexCommand.getAliases().forEach(alias -> Plex.get().getServer().getCommandMap().getKnownCommands().remove(alias));
});
module.getListeners().forEach(module::unregisterListener);
module.disable();
});
}
public void unloadModules() {
this.disableModules();
this.modules.forEach(module -> {
try {
((URLClassLoader)module.getClass().getClassLoader()).close();
} catch (IOException e) {
e.printStackTrace();
}
});
}
}

View File

@ -0,0 +1,65 @@
package dev.plex.module;
import com.google.common.collect.Lists;
import dev.plex.Plex;
import dev.plex.command.PlexCommand;
import dev.plex.listener.PlexListener;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bukkit.event.HandlerList;
import java.io.File;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
@Getter
@Setter(AccessLevel.MODULE)
public abstract class PlexModule
{
@Getter(AccessLevel.MODULE)
private final List<PlexCommand> commands = Lists.newArrayList();
@Getter(AccessLevel.MODULE)
private final List<PlexListener> listeners = Lists.newArrayList();
private Plex plex;
private PlexModuleFile plexModuleFile;
private File dataFolder;
private Logger logger;
public void load() {}
public void enable() {}
public void disable() {}
public void registerListener(PlexListener listener)
{
listeners.add(listener);
}
public void unregisterListener(PlexListener listener)
{
listeners.remove(listener);
HandlerList.unregisterAll(listener);
}
public void registerCommand(PlexCommand command)
{
commands.add(command);
}
public void unregisterCommand(PlexCommand command)
{
commands.remove(command);
}
public PlexCommand getCommand(String name)
{
return commands.stream().filter(plexCommand -> plexCommand.getName().equalsIgnoreCase(name) || plexCommand.getAliases().stream().map(String::toLowerCase).toList().contains(name.toLowerCase(Locale.ROOT))).findFirst().orElse(null);
}
}

View File

@ -0,0 +1,12 @@
package dev.plex.module;
import lombok.Data;
@Data
public class PlexModuleFile
{
private final String name;
private final String main;
private final String description;
private final String version;
}

View File

@ -0,0 +1,10 @@
package dev.plex.module.exception;
public class ModuleLoadException extends RuntimeException
{
public ModuleLoadException(String s)
{
super(s);
}
}

View File

@ -19,10 +19,13 @@ import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import lombok.Data;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -33,43 +36,26 @@ import redis.clients.jedis.Jedis;
public class PunishmentManager extends PlexBase public class PunishmentManager extends PlexBase
{ {
private final List<String> bannedIPs = Lists.newArrayList(); private final List<IndefiniteBan> indefiniteBans = Lists.newArrayList();
private final List<String> bannedUsernames = Lists.newArrayList();
private final List<UUID> bannedUUIDs = Lists.newArrayList();
public void mergeIndefiniteBans() public void mergeIndefiniteBans()
{ {
this.bannedUsernames.clear(); this.indefiniteBans.clear();
this.bannedIPs.clear(); Plex.get().indefBans.getKeys(false).forEach(key -> {
this.bannedUUIDs.clear(); IndefiniteBan ban = new IndefiniteBan();
ban.ips.addAll(Plex.get().getIndefBans().getStringList(key + ".ips"));
ban.usernames.addAll(Plex.get().getIndefBans().getStringList(key + ".users"));
ban.uuids.addAll(Plex.get().getIndefBans().getStringList(key + ".uuids").stream().map(UUID::fromString).toList());
this.indefiniteBans.add(ban);
});
this.bannedUUIDs.addAll(Plex.get().indefBans.getStringList("uuids").stream().filter(string -> PlexLog.log("Loaded {0} UUID(s), {1} IP(s), and {2} username(s) as indefinitely banned", this.indefiniteBans.stream().map(IndefiniteBan::getUuids).mapToLong(Collection::size).sum(), this.indefiniteBans.stream().map(IndefiniteBan::getIps).mapToLong(Collection::size).sum(), this.indefiniteBans.stream().map(IndefiniteBan::getUsernames).mapToLong(Collection::size).sum());
{
try
{
UUID uuid = UUID.fromString(string);
return true;
} catch (IllegalArgumentException e)
{
return false;
}
}).map(UUID::fromString).toList());
this.bannedIPs.addAll(Plex.get().indefBans.getStringList("ips"));
this.bannedUsernames.addAll(Plex.get().indefBans.getStringList("usernames"));
PlexLog.log("Loaded {0} UUID(s), {1} IP(s), and {2} username(s) as indefinitely banned", this.bannedUUIDs.size(), this.bannedIPs.size(), this.bannedUsernames.size());
if (Plex.get().getRedisConnection().isEnabled()) if (Plex.get().getRedisConnection().isEnabled())
{ {
PlexLog.log("Asynchronously uploading all indefinite bans to Redis"); PlexLog.log("Asynchronously uploading all indefinite bans to Redis");
Plex.get().getRedisConnection().runAsync(jedis -> { Plex.get().getRedisConnection().runAsync(jedis -> {
jedis.set("indefbanned-uuids", new Gson().toJson(this.bannedUUIDs)); jedis.set("indefbans", new Gson().toJson(indefiniteBans));
jedis.set("indefbanned-ips", new Gson().toJson(this.bannedIPs));
jedis.set("indefbanned-users", new Gson().toJson(this.bannedUsernames));
this.bannedIPs.clear();
this.bannedUsernames.clear();
this.bannedUUIDs.clear();
}); });
} }
} }
@ -78,30 +64,33 @@ public class PunishmentManager extends PlexBase
{ {
if (Plex.get().getRedisConnection().isEnabled()) if (Plex.get().getRedisConnection().isEnabled())
{ {
List<UUID> uuids = new Gson().fromJson(Plex.get().getRedisConnection().getJedis().get("indefbanned-uuids"), new TypeToken<List<UUID>>(){}.getType()); PlexLog.debug("Checking if UUID is banned in Redis");
return uuids.contains(uuid); List<IndefiniteBan> bans = new Gson().fromJson(Plex.get().getRedisConnection().getJedis().get("indefbans"), new TypeToken<List<IndefiniteBan>>(){}.getType());
return bans.stream().anyMatch(indefiniteBan -> indefiniteBan.getUuids().contains(uuid));
} }
return this.bannedUUIDs.contains(uuid); return this.indefiniteBans.stream().anyMatch(indefiniteBan -> indefiniteBan.getUuids().contains(uuid));
} }
public boolean isIndefIPBanned(String ip) public boolean isIndefIPBanned(String ip)
{ {
if (Plex.get().getRedisConnection().isEnabled()) if (Plex.get().getRedisConnection().isEnabled())
{ {
List<String> ips = new Gson().fromJson(Plex.get().getRedisConnection().getJedis().get("indefbanned-ips"), new TypeToken<List<String>>(){}.getType()); PlexLog.debug("Checking if IP is banned in Redis");
return ips.contains(ip); List<IndefiniteBan> bans = new Gson().fromJson(Plex.get().getRedisConnection().getJedis().get("indefbans"), new TypeToken<List<IndefiniteBan>>(){}.getType());
return bans.stream().anyMatch(indefiniteBan -> indefiniteBan.getIps().contains(ip));
} }
return this.bannedIPs.contains(ip); return this.indefiniteBans.stream().anyMatch(indefiniteBan -> indefiniteBan.getIps().contains(ip));
} }
public boolean isIndefUserBanned(String username) public boolean isIndefUserBanned(String username)
{ {
if (Plex.get().getRedisConnection().isEnabled()) if (Plex.get().getRedisConnection().isEnabled())
{ {
List<String> users = new Gson().fromJson(Plex.get().getRedisConnection().getJedis().get("indefbanned-users"), new TypeToken<List<String>>(){}.getType()); PlexLog.debug("Checking if username is banned in Redis");
return users.contains(username); List<IndefiniteBan> bans = new Gson().fromJson(Plex.get().getRedisConnection().getJedis().get("indefbans"), new TypeToken<List<IndefiniteBan>>(){}.getType());
return bans.stream().anyMatch(indefiniteBan -> indefiniteBan.getUsernames().contains(username));
} }
return this.bannedUsernames.contains(username); return this.indefiniteBans.stream().anyMatch(indefiniteBan -> indefiniteBan.getUsernames().contains(username));
} }
public void insertPunishment(PunishedPlayer player, Punishment punishment) public void insertPunishment(PunishedPlayer player, Punishment punishment)
@ -320,4 +309,12 @@ public class PunishmentManager extends PlexBase
issuePunishment(player, punishment); issuePunishment(player, punishment);
insertPunishment(player, punishment); insertPunishment(player, punishment);
} }
@Data
public static class IndefiniteBan
{
private final List<String> usernames = Lists.newArrayList();
private final List<UUID> uuids = Lists.newArrayList();
private final List<String> ips = Lists.newArrayList();
}
} }

View File

@ -32,7 +32,8 @@ public class RedisConnection extends PlexBase
public void runAsync(Consumer<Jedis> jedisConsumer) public void runAsync(Consumer<Jedis> jedisConsumer)
{ {
new Thread(() -> { new Thread(() ->
{
try (Jedis jedis = getJedis()) try (Jedis jedis = getJedis())
{ {
jedisConsumer.accept(jedis); jedisConsumer.accept(jedis);

View File

@ -131,7 +131,7 @@ public class PlexUtils extends PlexBase
public static Component messageComponent(String entry, Object... objects) public static Component messageComponent(String entry, Object... objects)
{ {
return MiniMessage.miniMessage().parse(LegacyComponentSerializer.legacySection().serialize(LegacyComponentSerializer.legacyAmpersand().deserialize(messageString(entry, objects)))); return MiniMessage.miniMessage().deserialize(LegacyComponentSerializer.legacySection().serialize(LegacyComponentSerializer.legacyAmpersand().deserialize(messageString(entry, objects))));
} }
public static String messageString(String entry, Object... objects) public static String messageString(String entry, Object... objects)

View File

@ -14,6 +14,11 @@ public class UpdateChecker extends PlexBase
public boolean check() public boolean check()
{ {
if (currentVersion.contains("-SNAPSHOT"))
{
PlexLog.log("Snapshot version detected, not checking for updates.");
return true;
}
try try
{ {
String versionLink = "https://plex.us.org/updater/check/"; String versionLink = "https://plex.us.org/updater/check/";

View File

@ -11,7 +11,6 @@ import java.time.ZoneId;
public class LocalDateTimeDeserializer implements JsonDeserializer<LocalDateTime> public class LocalDateTimeDeserializer implements JsonDeserializer<LocalDateTime>
{ {
@Override @Override
public LocalDateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException public LocalDateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
{ {

View File

@ -38,14 +38,14 @@ public class CustomWorld extends WorldCreator
{ {
boolean existed = new File(name).exists(); boolean existed = new File(name).exists();
World world = super.generate(); World world = super.generate();
if (!existed) if (!existed)
{ {
Block block = world.getBlockAt(0, world.getHighestBlockYAt(0, 0) + 1, 0); Block block = world.getBlockAt(0, world.getHighestBlockYAt(0, 0) + 1, 0);
block.setType(Material.OAK_SIGN); block.setType(Material.OAK_SIGN);
BlockState state = block.getState(); BlockState state = block.getState();
if (state instanceof Sign) if (state instanceof Sign sign)
{ {
Sign sign = (Sign)state;
sign.line(1, Component.text( sign.line(1, Component.text(
Objects.requireNonNull(plugin.config.getString("worlds." + name + ".name")))); Objects.requireNonNull(plugin.config.getString("worlds." + name + ".name"))));
sign.line(2, Component.text("- 0, 0 -")); sign.line(2, Component.text("- 0, 0 -"));

View File

@ -1,16 +1,21 @@
# Plex Indefinite Bans File # Plex Indefinite Bans File
# Players with their UUID / IP / Usernames in here will be indefinitely banned until removed # Players with their UUID / IP / Usernames in here will be indefinitely banned until removed
# List of permanently banned UUIDs
# If you want to get someone's UUID, use https://api.ashcon.app/mojang/v2/user/<username> # If you want to get someone's UUID, use https://api.ashcon.app/mojang/v2/user/<username>
uuids: griefers:
users:
- "badplayer123"
- "badplayer321"
uuids:
- 1dac0e92-f565-4479-afd5-38c7df5f9732 # badplayer123 - 1dac0e92-f565-4479-afd5-38c7df5f9732 # badplayer123
ips:
- 123.123.123.123
# List of permanently banned IP addresses # Note that these keys can be anything, they are simply to help you keep things organized.
ips: # They are not used within the plugin. Duplicate keys are not allowed, and will not work.
- 169.254.69.69 bypassers:
users:
# List of permanently banned UUIDs - "bypasser1"
# If you want to get someone's username, use https://api.ashcon.app/mojang/v2/user/<uuid>, or just remember it ips:
usernames: - 321.321.321.321
- badplayer123 - 169.254.1.2

View File

@ -15,14 +15,13 @@
# 3. Expiry # 3. Expiry
# 4. Punisher # 4. Punisher
banMessage: "<red>You have been banned! You may appeal at <gold><v>.\n<red>Reason: <gold><v>\n<red>End date: <gold><v>\n<red>Banned by: <gold><v>" banMessage: "<red>You have been banned! You may appeal at <gold><v>.\n<red>Reason: <gold><v>\n<red>End date: <gold><v>\n<red>Banned by: <gold><v>"
indefBanMessage: "<red>Your <v> is currently banned! You may appeal at <gold><v>." # The type of indefinite ban
test: "this is a test message!" # Appeal URL
# 1. The command sender's username indefBanMessage: "<red>Your <v> is indefinitely banned! You may appeal at <gold><v>."
variableTest: "variable test with <v>!" playerNotFound: "<red>Player not found!"
playerNotFound: "Player not found!" worldNotFound: "<red>World not found!"
worldNotFound: "World not found!"
# 1. The world you have been teleported to # 1. The world you have been teleported to
playerWorldTeleport: "You have been teleported to <v>." playerWorldTeleport: "<aqua>You have been teleported to <v>."
# 1. The sender who opped everyone # 1. The sender who opped everyone
oppedAllPlayers: "<aqua><v> - Opped all players on the server" oppedAllPlayers: "<aqua><v> - Opped all players on the server"
# 1. The sender who de-opped everyone # 1. The sender who de-opped everyone
@ -50,8 +49,7 @@ unmutedPlayer: "<aqua><v> - Unmuted <v>"
lockedUpPlayer: "<aqua><v> - Locking up <v>" lockedUpPlayer: "<aqua><v> - Locking up <v>"
# 1. The person who is unlocking # 1. The person who is unlocking
# 2. The person who has been unlocked # 2. The person who has been unlocked
unlockedUpPlayer: "<aqua><v> - Unlocking <v>" unlockedPlayer: "<aqua><v> - Unlocking <v>"
noPermission: "<red>You cannot use this command!"
# 1. The rank required to use the command # 1. The rank required to use the command
noPermissionRank: "<red>You must be at least <v> to use this command!" noPermissionRank: "<red>You must be at least <v> to use this command!"
# 1. The permission node required to use the command # 1. The permission node required to use the command
@ -59,25 +57,23 @@ noPermissionNode: "<red>You must have the permission: <v> to use this command!"
noPermissionInGame: "<red>You must be in console to use this command!" noPermissionInGame: "<red>You must be in console to use this command!"
noPermissionConsole: "<red>You must be in-game to use this command!" noPermissionConsole: "<red>You must be in-game to use this command!"
# 1. The username of the name history # 1. The username of the name history
nameHistoryTitle: "Name History of <v>" nameHistoryTitle: "<gold>Name History of <v>"
# 1. A username of the found user nameHistorySeparator: "<gold><strikethrough>-----------------------------"
# 2. When the user changed to that username # 1. The name
nameHistoryBody: " - <v> (<v>)" # 2. The date and time of the name change
# 1. The username that failed nameHistoryBody: "<gold><v> <dark_gray>- <gold><v>"
nameHistoryFail: "<red>Something went wrong while trying to retrieve name history of <v>! Try again later!"
nameHistoryDoesntExist: "<red>Couldn't find this user! Please check if your spelling was correct and this player exists"
# 1. The gamemode # 1. The gamemode
gameModeSetTo: "Your gamemode has been set to <v>." gameModeSetTo: "<gray>Your gamemode has been set to <v>."
# 1. The player's name # 1. The player's name
# 2. The gamemode # 2. The gamemode
setOtherPlayerGameModeTo: "You set <v>'s gamemode to <v>." setOtherPlayerGameModeTo: "<gray>You set <v>'s gamemode to <v>."
# 1. The command sender # 1. The command sender
# 2. The gamemode # 2. The gamemode
playerSetOtherGameMode: "<v> set your gamemode to <v>." playerSetOtherGameMode: "<gray><v> set your gamemode to <v>."
# 1. The command sender # 1. The command sender
# 2. The gamemode # 2. The gamemode
setEveryoneGameMode: "<aqua><v> - Changing everyone's gamemode to <v>" setEveryoneGameMode: "<aqua><v> - Changing everyone's gamemode to <v>"
consoleMustDefinePlayer: "You must define a player since you are running this command from console." consoleMustDefinePlayer: "<red>You must define a player since you are running this command from console."
# 1. The command sender # 1. The command sender
# 2. The player # 2. The player
newAdminAdded: "<aqua><v> - Adding <v> to the admin list" newAdminAdded: "<aqua><v> - Adding <v> to the admin list"
@ -116,9 +112,9 @@ playerLockedUp: "<red>That player is already locked up!"
muted: "<red>You are currently muted - STFU!" muted: "<red>You are currently muted - STFU!"
kickedPlayer: "<red><v> - Kicking <v>" kickedPlayer: "<red><v> - Kicking <v>"
teleportedToWorldSpawn: "<aqua>Teleporting to the local spawn" teleportedToWorldSpawn: "<aqua>Teleporting to the local spawn"
toggleCommandSpy: "CommandSpy has been" toggleCommandSpy: "<gray>CommandSpy has been"
enabled: "enabled." enabled: "<gray>enabled."
disabled: "disabled." disabled: "<gray>disabled."
adminChatFormat: '<dark_gray>[<blue>AdminChat<dark_gray>] <dark_red><v> <gray>» <gold><v>' adminChatFormat: '<dark_gray>[<blue>AdminChat<dark_gray>] <dark_red><v> <gray>» <gold><v>'
maximumPrefixLength: "<red>The maximum length for a tag may only be <v>." maximumPrefixLength: "<red>The maximum length for a tag may only be <v>."
prefixCleared: "<aqua>Your prefix has been cleared." prefixCleared: "<aqua>Your prefix has been cleared."