feat(build): rework structure
This commit is contained in:
parent
6e0ef4a243
commit
d17aadc09a
68 changed files with 171 additions and 194 deletions
159
src/main/java/net/artelnatif/nicko/NickoBukkit.java
Normal file
159
src/main/java/net/artelnatif/nicko/NickoBukkit.java
Normal file
|
@ -0,0 +1,159 @@
|
|||
package net.artelnatif.nicko;
|
||||
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import com.comphenix.protocol.ProtocolManager;
|
||||
import net.artelnatif.nicko.command.NickoCommand;
|
||||
import net.artelnatif.nicko.config.Configuration;
|
||||
import net.artelnatif.nicko.config.ConfigurationManager;
|
||||
import net.artelnatif.nicko.event.PlayerJoinListener;
|
||||
import net.artelnatif.nicko.event.PlayerQuitListener;
|
||||
import net.artelnatif.nicko.gui.items.common.OptionUnavailable;
|
||||
import net.artelnatif.nicko.gui.items.main.ExitGUI;
|
||||
import net.artelnatif.nicko.i18n.Locale;
|
||||
import net.artelnatif.nicko.i18n.LocaleFileManager;
|
||||
import net.artelnatif.nicko.mojang.MojangAPI;
|
||||
import net.artelnatif.nicko.placeholder.PlaceHolderHook;
|
||||
import net.artelnatif.nicko.storage.PlayerDataStore;
|
||||
import net.artelnatif.nicko.storage.name.PlayerNameStore;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.command.PluginCommand;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.plugin.java.JavaPluginLoader;
|
||||
import xyz.xenondevs.invui.gui.structure.Structure;
|
||||
import xyz.xenondevs.invui.item.builder.ItemBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.SimpleItem;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class NickoBukkit extends JavaPlugin {
|
||||
private static NickoBukkit plugin;
|
||||
|
||||
private final boolean unitTesting;
|
||||
|
||||
private MojangAPI mojangAPI;
|
||||
private PlayerDataStore dataStore;
|
||||
private ConfigurationManager configurationManager;
|
||||
private Configuration configuration;
|
||||
private LocaleFileManager localeFileManager;
|
||||
private PlayerNameStore nameStore;
|
||||
private ProtocolManager protocolManager;
|
||||
|
||||
public NickoBukkit() { this.unitTesting = false; }
|
||||
|
||||
/**
|
||||
* Used by MockBukkit
|
||||
*/
|
||||
protected NickoBukkit(JavaPluginLoader loader, PluginDescriptionFile description, File dataFolder, File file) {
|
||||
this(loader, description, dataFolder, file, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by MockBukkit
|
||||
*/
|
||||
protected NickoBukkit(JavaPluginLoader loader, PluginDescriptionFile description, File dataFolder, File file, Configuration configuration) {
|
||||
super(loader, description, dataFolder, file);
|
||||
unitTesting = true;
|
||||
this.configuration = configuration;
|
||||
getLogger().info("Unit Testing Mode enabled.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
plugin = this;
|
||||
configurationManager = new ConfigurationManager(getDataFolder());
|
||||
configurationManager.saveDefaultConfig();
|
||||
|
||||
protocolManager = ProtocolLibrary.getProtocolManager();
|
||||
mojangAPI = new MojangAPI();
|
||||
dataStore = new PlayerDataStore(mojangAPI, getNickoConfig());
|
||||
nameStore = new PlayerNameStore();
|
||||
|
||||
if (!dataStore.getStorage().isError()) {
|
||||
getLogger().info("Loading persistence...");
|
||||
if (!dataStore.getStorage().getProvider().init()) {
|
||||
dataStore.getStorage().setError(true);
|
||||
getLogger().severe("Failed to open persistence, data will NOT be saved!");
|
||||
}
|
||||
}
|
||||
|
||||
if (!unitTesting) {
|
||||
localeFileManager = new LocaleFileManager();
|
||||
if (configuration.isCustomLocale()) {
|
||||
if (localeFileManager.dumpFromLocale(Locale.ENGLISH)) {
|
||||
getLogger().info("Successfully loaded custom language file.");
|
||||
} else {
|
||||
getLogger().severe("Failed to load custom language file!");
|
||||
}
|
||||
}
|
||||
|
||||
final PluginCommand command = getCommand("nicko");
|
||||
if (command != null) {
|
||||
command.setExecutor(new NickoCommand());
|
||||
}
|
||||
|
||||
Structure.addGlobalIngredient('#', new SimpleItem(new ItemBuilder(Material.BLACK_STAINED_GLASS_PANE).setDisplayName(" ")));
|
||||
Structure.addGlobalIngredient('%', new SimpleItem(new ItemBuilder(Material.ORANGE_STAINED_GLASS_PANE).setDisplayName(" ")));
|
||||
Structure.addGlobalIngredient('U', new OptionUnavailable());
|
||||
Structure.addGlobalIngredient('E', new ExitGUI());
|
||||
|
||||
new PlaceHolderHook(this).hook();
|
||||
|
||||
getServer().getPluginManager().registerEvents(new PlayerJoinListener(), this);
|
||||
getServer().getPluginManager().registerEvents(new PlayerQuitListener(), this);
|
||||
|
||||
getLogger().info("Nicko (Bukkit) has been enabled.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
if (!getDataStore().getStorage().isError()) {
|
||||
getLogger().info("Closing persistence...");
|
||||
nameStore.clearStoredNames();
|
||||
Bukkit.getOnlinePlayers().forEach(player -> dataStore.saveData(player));
|
||||
if (!dataStore.getStorage().getProvider().close()) {
|
||||
getLogger().severe("Failed to close persistence!");
|
||||
}
|
||||
}
|
||||
|
||||
getLogger().info("Nicko (Bukkit) has been disabled.");
|
||||
}
|
||||
|
||||
public static NickoBukkit getInstance() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
public Configuration getNickoConfig() {
|
||||
try {
|
||||
if (configuration == null) { return configuration = configurationManager.load(); }
|
||||
return configuration;
|
||||
} catch (IOException e) {
|
||||
getLogger().severe("Failed to load the configuration file!");
|
||||
getLogger().severe("It may be have been generated with an older version of Nicko.");
|
||||
getLogger().severe("Delete the configuration and restart the server please :)");
|
||||
getLogger().severe("(" + e.getMessage() + ")");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public PlayerDataStore getDataStore() {
|
||||
return dataStore;
|
||||
}
|
||||
|
||||
public PlayerNameStore getNameStore() {
|
||||
return nameStore;
|
||||
}
|
||||
|
||||
public MojangAPI getMojangAPI() {
|
||||
return mojangAPI;
|
||||
}
|
||||
|
||||
public LocaleFileManager getLocaleFileManager() {
|
||||
return localeFileManager;
|
||||
}
|
||||
|
||||
public ProtocolManager getProtocolManager() { return protocolManager; }
|
||||
}
|
106
src/main/java/net/artelnatif/nicko/anvil/AnvilManager.java
Normal file
106
src/main/java/net/artelnatif/nicko/anvil/AnvilManager.java
Normal file
|
@ -0,0 +1,106 @@
|
|||
package net.artelnatif.nicko.anvil;
|
||||
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import net.artelnatif.nicko.appearance.AppearanceManager;
|
||||
import net.artelnatif.nicko.disguise.ActionResult;
|
||||
import net.artelnatif.nicko.i18n.I18N;
|
||||
import net.artelnatif.nicko.i18n.I18NDict;
|
||||
import net.artelnatif.nicko.mojang.MojangUtils;
|
||||
import net.wesjd.anvilgui.AnvilGUI;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class AnvilManager {
|
||||
private final Player player;
|
||||
private final AppearanceManager appearanceManager;
|
||||
|
||||
public AnvilManager(Player player) {
|
||||
this.player = player;
|
||||
this.appearanceManager = AppearanceManager.get(player);
|
||||
}
|
||||
|
||||
public void openNameThenSkinAnvil() {
|
||||
getNameThenSkinAnvil().open(player);
|
||||
}
|
||||
|
||||
public void openSkinAnvil() {
|
||||
getSkinAnvil().open(player);
|
||||
}
|
||||
|
||||
public void openNameAnvil() {
|
||||
getNameAnvil().open(player);
|
||||
}
|
||||
|
||||
public AnvilGUI.Builder getNameThenSkinAnvil() {
|
||||
return new AnvilGUI.Builder()
|
||||
.plugin(NickoBukkit.getInstance())
|
||||
.itemLeft(getLeftItem(false))
|
||||
.interactableSlots(AnvilGUI.Slot.OUTPUT)
|
||||
.onComplete((completion) -> {
|
||||
if (MojangUtils.isUsernameInvalid(completion.getText())) {
|
||||
return Collections.singletonList(AnvilGUI.ResponseAction.replaceInputText("Invalid username!"));
|
||||
} else {
|
||||
appearanceManager.setName(completion.getText());
|
||||
openSkinAnvil();
|
||||
return Collections.singletonList(AnvilGUI.ResponseAction.close());
|
||||
}
|
||||
})
|
||||
.text("New name...");
|
||||
}
|
||||
|
||||
public AnvilGUI.Builder getNameAnvil() {
|
||||
return new AnvilGUI.Builder()
|
||||
.plugin(NickoBukkit.getInstance())
|
||||
.itemLeft(getLeftItem(false))
|
||||
.interactableSlots(AnvilGUI.Slot.OUTPUT)
|
||||
.onComplete((completion) -> {
|
||||
if (MojangUtils.isUsernameInvalid(completion.getText())) {
|
||||
return Collections.singletonList(AnvilGUI.ResponseAction.replaceInputText("Invalid username!"));
|
||||
} else {
|
||||
appearanceManager.setName(completion.getText());
|
||||
final ActionResult<Void> actionResult = appearanceManager.updatePlayer(false);
|
||||
return sendResultAndClose(actionResult);
|
||||
}
|
||||
})
|
||||
.text("New name...");
|
||||
}
|
||||
|
||||
private AnvilGUI.Builder getSkinAnvil() {
|
||||
return new AnvilGUI.Builder()
|
||||
.plugin(NickoBukkit.getInstance())
|
||||
.itemLeft(getLeftItem(true))
|
||||
.interactableSlots(AnvilGUI.Slot.OUTPUT)
|
||||
.onComplete((completion) -> {
|
||||
if (MojangUtils.isUsernameInvalid(completion.getText())) {
|
||||
return Collections.singletonList(AnvilGUI.ResponseAction.replaceInputText("Invalid username!"));
|
||||
} else {
|
||||
appearanceManager.setSkin(completion.getText());
|
||||
final ActionResult<Void> actionResult = appearanceManager.updatePlayer(true);
|
||||
return sendResultAndClose(actionResult);
|
||||
}
|
||||
})
|
||||
.text("New skin...");
|
||||
}
|
||||
|
||||
private List<AnvilGUI.ResponseAction> sendResultAndClose(ActionResult<Void> actionResult) {
|
||||
if (!actionResult.isError()) {
|
||||
player.sendMessage(I18N.translate(player, I18NDict.Event.Disguise.SUCCESS));
|
||||
} else {
|
||||
player.sendMessage(I18N.translate(player, I18NDict.Event.Disguise.FAIL, I18N.translateWithoutPrefix(player, actionResult.getErrorMessage())));
|
||||
}
|
||||
return Collections.singletonList(AnvilGUI.ResponseAction.close());
|
||||
}
|
||||
|
||||
private ItemStack getLeftItem(boolean skin) {
|
||||
final ItemStack item = new ItemStack(Material.PAPER);
|
||||
final ItemMeta meta = item.getItemMeta();
|
||||
meta.setDisplayName("§0New " + (skin ? "skin" : "name") + "...");
|
||||
item.setItemMeta(meta);
|
||||
return item;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,185 @@
|
|||
package net.artelnatif.nicko.appearance;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.wrappers.*;
|
||||
import com.google.common.collect.Multimap;
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import net.artelnatif.nicko.disguise.ActionResult;
|
||||
import net.artelnatif.nicko.disguise.NickoProfile;
|
||||
import net.artelnatif.nicko.i18n.I18NDict;
|
||||
import net.artelnatif.nicko.mojang.MojangAPI;
|
||||
import net.artelnatif.nicko.mojang.MojangSkin;
|
||||
import net.artelnatif.nicko.storage.PlayerDataStore;
|
||||
import net.artelnatif.nicko.storage.name.PlayerNameStore;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
public class AppearanceManager {
|
||||
private final NickoProfile profile;
|
||||
private final Player player;
|
||||
private final NickoBukkit instance = NickoBukkit.getInstance();
|
||||
private final PlayerDataStore dataStore = instance.getDataStore();
|
||||
private final PlayerNameStore nameStore = instance.getNameStore();
|
||||
|
||||
private AppearanceManager(UUID uuid) {
|
||||
this.player = Bukkit.getPlayer(uuid);
|
||||
this.profile = dataStore.getData(uuid).orElse(NickoProfile.EMPTY_PROFILE.clone());
|
||||
}
|
||||
|
||||
private AppearanceManager(String name) {
|
||||
this.player = null;
|
||||
this.profile = dataStore.getOfflineData(name).orElse(NickoProfile.EMPTY_PROFILE.clone());
|
||||
}
|
||||
|
||||
public static AppearanceManager get(Player player) {
|
||||
return new AppearanceManager(player.getUniqueId());
|
||||
}
|
||||
|
||||
public static AppearanceManager get(String name) {
|
||||
return new AppearanceManager(name);
|
||||
}
|
||||
|
||||
public boolean hasData() {
|
||||
return !profile.isEmpty();
|
||||
}
|
||||
|
||||
public void setSkin(String skin) {
|
||||
profile.setSkin(skin);
|
||||
}
|
||||
|
||||
public String getSkin() {
|
||||
return profile.getSkin();
|
||||
}
|
||||
|
||||
public boolean needsASkinChange() {
|
||||
return profile.getSkin() != null && !profile.getSkin().equals(player.getName());
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
profile.setName(name);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return profile.getName();
|
||||
}
|
||||
|
||||
public NickoProfile getProfile() {
|
||||
return profile;
|
||||
}
|
||||
|
||||
public void setNameAndSkin(String name, String skin) {
|
||||
this.profile.setName(name);
|
||||
this.profile.setSkin(skin);
|
||||
updatePlayer(true);
|
||||
}
|
||||
|
||||
public ActionResult<Void> reset() {
|
||||
final String defaultName = nameStore.getStoredName(player);
|
||||
this.profile.setName(defaultName);
|
||||
this.profile.setSkin(defaultName);
|
||||
final ActionResult<Void> actionResult = resetPlayer();
|
||||
this.profile.setSkin(null);
|
||||
this.profile.setName(null);
|
||||
return actionResult;
|
||||
}
|
||||
|
||||
public ActionResult<Void> resetPlayer() {
|
||||
// TODO: 4/3/23 Reset player
|
||||
return new ActionResult<>();
|
||||
}
|
||||
|
||||
public ActionResult<Void> updatePlayer(boolean skinChange) {
|
||||
final String displayName = profile.getName() == null ? player.getName() : profile.getName();
|
||||
final WrappedGameProfile gameProfile = new WrappedGameProfile(player.getUniqueId(), displayName);
|
||||
|
||||
final ActionResult<Void> result = updateGameProfileSkin(gameProfile, skinChange);
|
||||
if (!result.isError()) {
|
||||
updateTabList(gameProfile, displayName);
|
||||
}
|
||||
return new ActionResult<>();
|
||||
}
|
||||
|
||||
private ActionResult<Void> updateGameProfileSkin(WrappedGameProfile gameProfile, boolean skinChange) {
|
||||
final boolean changeOnlyName = profile.getSkin() != null && !profile.getSkin().equalsIgnoreCase(player.getName());
|
||||
|
||||
if (skinChange || changeOnlyName) {
|
||||
Optional<MojangSkin> skin;
|
||||
try {
|
||||
final MojangAPI mojang = NickoBukkit.getInstance().getMojangAPI();
|
||||
final Optional<String> uuid = mojang.getUUID(profile.getSkin());
|
||||
if (uuid.isPresent()) {
|
||||
skin = mojang.getSkin(uuid.get());
|
||||
if (skin.isPresent()) {
|
||||
final MojangSkin skinResult = skin.get();
|
||||
final Multimap<String, WrappedSignedProperty> properties = gameProfile.getProperties();
|
||||
properties.removeAll("textures");
|
||||
properties.put("textures", new WrappedSignedProperty("textures", skinResult.getValue(), skinResult.getSignature()));
|
||||
Bukkit.broadcastMessage("Modified properties");
|
||||
}
|
||||
}
|
||||
Bukkit.broadcastMessage("Respawning player");
|
||||
respawnPlayer();
|
||||
return new ActionResult<>();
|
||||
} catch (ExecutionException e) {
|
||||
return new ActionResult<>(I18NDict.Error.SKIN_FAIL_CACHE);
|
||||
} catch (IOException e) {
|
||||
return new ActionResult<>(I18NDict.Error.NAME_FAIL_MOJANG);
|
||||
}
|
||||
}
|
||||
return new ActionResult<>();
|
||||
}
|
||||
|
||||
private void respawnPlayer() {
|
||||
final PacketContainer respawnOtherWorld = getRespawnPacket(Bukkit.getWorld("world_the_end"));
|
||||
final PacketContainer respawn = getRespawnPacket(player.getWorld());
|
||||
instance.getProtocolManager().sendServerPacket(player, respawnOtherWorld);
|
||||
instance.getProtocolManager().sendServerPacket(player, respawn);
|
||||
}
|
||||
|
||||
private PacketContainer getRespawnPacket(World world) {
|
||||
final PacketContainer packet = new PacketContainer(PacketType.Play.Server.RESPAWN);
|
||||
final EnumWrappers.NativeGameMode gamemode = EnumWrappers.NativeGameMode.fromBukkit(player.getGameMode());
|
||||
packet.getWorldKeys().write(0, world);
|
||||
packet.getLongs().write(0, world.getSeed());
|
||||
|
||||
packet.getGameModes().write(0, gamemode); // gamemode
|
||||
packet.getGameModes().write(1, gamemode); // previous gamemode
|
||||
|
||||
packet.getBooleans().write(0, false);
|
||||
packet.getBooleans().write(1, false);
|
||||
return packet;
|
||||
}
|
||||
|
||||
private void updateTabList(WrappedGameProfile gameProfile, String displayName) {
|
||||
final PacketContainer infoAdd = new PacketContainer(PacketType.Play.Server.PLAYER_INFO);
|
||||
infoAdd.getPlayerInfoActions().write(0, Set.of(
|
||||
EnumWrappers.PlayerInfoAction.ADD_PLAYER,
|
||||
EnumWrappers.PlayerInfoAction.UPDATE_GAME_MODE,
|
||||
EnumWrappers.PlayerInfoAction.UPDATE_DISPLAY_NAME,
|
||||
EnumWrappers.PlayerInfoAction.UPDATE_LISTED,
|
||||
EnumWrappers.PlayerInfoAction.UPDATE_LATENCY
|
||||
));
|
||||
|
||||
infoAdd.getPlayerInfoDataLists().write(1, List.of(new PlayerInfoData(
|
||||
gameProfile,
|
||||
0,
|
||||
EnumWrappers.NativeGameMode.fromBukkit(player.getGameMode()),
|
||||
WrappedChatComponent.fromText(displayName)
|
||||
)));
|
||||
|
||||
final PacketContainer infoRemove = new PacketContainer(PacketType.Play.Server.PLAYER_INFO_REMOVE);
|
||||
infoRemove.getUUIDLists().write(0, List.of(player.getUniqueId()));
|
||||
|
||||
instance.getProtocolManager().broadcastServerPacket(infoRemove);
|
||||
instance.getProtocolManager().broadcastServerPacket(infoAdd);
|
||||
}
|
||||
}
|
48
src/main/java/net/artelnatif/nicko/command/NickoCommand.java
Normal file
48
src/main/java/net/artelnatif/nicko/command/NickoCommand.java
Normal file
|
@ -0,0 +1,48 @@
|
|||
package net.artelnatif.nicko.command;
|
||||
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import net.artelnatif.nicko.command.sub.NickoCheckSubCmd;
|
||||
import net.artelnatif.nicko.command.sub.NickoDebugSubCmd;
|
||||
import net.artelnatif.nicko.gui.MainGUI;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class NickoCommand implements CommandExecutor {
|
||||
private String helpMessage = "§cNicko §8§o[{version}] §f- §2Help:\n" +
|
||||
"§6/nicko §f- §7Open the GUI.\n" +
|
||||
"§6/nicko help §f- §7Print this help message.\n";
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (sender instanceof Player) {
|
||||
Player player = (Player) sender;
|
||||
if (args.length >= 1) {
|
||||
switch (args[0]) {
|
||||
case "debug":
|
||||
new NickoDebugSubCmd().execute(player, args);
|
||||
break;
|
||||
case "check":
|
||||
new NickoCheckSubCmd().execute(player, args);
|
||||
break;
|
||||
default:
|
||||
sendHelpMessage(sender);
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
new MainGUI(player).open();
|
||||
return false;
|
||||
}
|
||||
|
||||
sender.sendMessage("This plugin can only be used in-game. Sorry!");
|
||||
return false;
|
||||
}
|
||||
|
||||
public void sendHelpMessage(CommandSender sender) {
|
||||
helpMessage = helpMessage.replace("{version}", NickoBukkit.getInstance().getDescription().getVersion());
|
||||
sender.sendMessage(helpMessage);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package net.artelnatif.nicko.command.sub;
|
||||
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import net.artelnatif.nicko.appearance.AppearanceManager;
|
||||
import net.artelnatif.nicko.i18n.I18N;
|
||||
import net.artelnatif.nicko.i18n.I18NDict;
|
||||
import net.artelnatif.nicko.mojang.MojangUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.StringJoiner;
|
||||
|
||||
public class NickoCheckSubCmd {
|
||||
public void execute(Player player, String[] args) {
|
||||
final String targetName = args[1];
|
||||
final Player target = Bukkit.getPlayerExact(targetName);
|
||||
|
||||
AppearanceManager appearanceManager;
|
||||
if (MojangUtils.isUsernameInvalid(targetName)) {
|
||||
player.sendMessage(I18N.translate(player, I18NDict.Error.INVALID_USERNAME));
|
||||
return;
|
||||
}
|
||||
|
||||
if (target == null) {
|
||||
appearanceManager = AppearanceManager.get(targetName);
|
||||
} else {
|
||||
appearanceManager = AppearanceManager.get(target);
|
||||
}
|
||||
|
||||
final StringJoiner builder = new StringJoiner("\n");
|
||||
builder.add("§c" + NickoBukkit.getInstance().getNickoConfig().getPrefix() + "§6Check for: §f§o" + targetName);
|
||||
if (!appearanceManager.hasData()) {
|
||||
builder.add("§cThis player has not data.");
|
||||
} else {
|
||||
builder.add("§7- §fNicked: §a✔");
|
||||
builder.add("§7- §fName: §6" + appearanceManager.getName());
|
||||
builder.add("§7- §fSkin: §6" + appearanceManager.getSkin());
|
||||
}
|
||||
|
||||
player.sendMessage(builder.toString());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package net.artelnatif.nicko.command.sub;
|
||||
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import net.artelnatif.nicko.appearance.AppearanceManager;
|
||||
import net.artelnatif.nicko.mojang.MojangUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class NickoDebugSubCmd {
|
||||
public void execute(CommandSender sender, String[] args) {
|
||||
final String prefix = NickoBukkit.getInstance().getNickoConfig().getPrefix();
|
||||
|
||||
Player target;
|
||||
String name, skin;
|
||||
if (args.length == 3) {
|
||||
target = (Player) sender;
|
||||
name = args[1];
|
||||
skin = args[2];
|
||||
} else {
|
||||
if (args.length < 3) {
|
||||
sender.sendMessage(prefix + "§cMissing argument.");
|
||||
return;
|
||||
}
|
||||
|
||||
final String playerName = args[1];
|
||||
name = args[2];
|
||||
skin = args[3];
|
||||
|
||||
target = Bukkit.getPlayer(playerName);
|
||||
if (target == null) {
|
||||
sender.sendMessage(prefix + "§cSpecified player is offline.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
final AppearanceManager appearanceManager = AppearanceManager.get(target.getPlayer());
|
||||
|
||||
if (MojangUtils.isUsernameInvalid(name) || MojangUtils.isUsernameInvalid(skin)) {
|
||||
sender.sendMessage(prefix + "§cSpecified username is invalid.");
|
||||
}
|
||||
|
||||
appearanceManager.setNameAndSkin(name, skin);
|
||||
target.sendMessage(prefix + "§aWhoosh!");
|
||||
target.playSound(target.getLocation(), Sound.ENTITY_ITEM_FRAME_PLACE, 1, 1);
|
||||
}
|
||||
}
|
55
src/main/java/net/artelnatif/nicko/config/Configuration.java
Normal file
55
src/main/java/net/artelnatif/nicko/config/Configuration.java
Normal file
|
@ -0,0 +1,55 @@
|
|||
package net.artelnatif.nicko.config;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* TODO: 4/2/23 Convert using Bukkit YAML API
|
||||
* <a href="https://www.spigotmc.org/threads/tutorial-bukkit-custom-serialization.148781/">Link</a>
|
||||
**/
|
||||
public class Configuration {
|
||||
@JsonProperty("sql")
|
||||
private final DataSourceConfiguration sqlConfiguration;
|
||||
@JsonProperty("redis")
|
||||
private final DataSourceConfiguration redisConfiguration;
|
||||
private final String prefix;
|
||||
private final Boolean local;
|
||||
private final Boolean customLocale;
|
||||
|
||||
public Configuration(DataSourceConfiguration sqlConfiguration, DataSourceConfiguration redisConfiguration, String prefix, Boolean local, Boolean customLocale) {
|
||||
this.sqlConfiguration = sqlConfiguration;
|
||||
this.redisConfiguration = redisConfiguration;
|
||||
this.prefix = prefix;
|
||||
this.local = local;
|
||||
this.customLocale = customLocale;
|
||||
}
|
||||
|
||||
public Configuration() {
|
||||
this(
|
||||
new DataSourceConfiguration("", 3306, "", ""),
|
||||
new DataSourceConfiguration("", 6379, "", ""),
|
||||
"",
|
||||
false,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
public DataSourceConfiguration getSqlConfiguration() {
|
||||
return sqlConfiguration;
|
||||
}
|
||||
|
||||
public DataSourceConfiguration getRedisConfiguration() {
|
||||
return redisConfiguration;
|
||||
}
|
||||
|
||||
public String getPrefix() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
public Boolean isLocal() {
|
||||
return local;
|
||||
}
|
||||
|
||||
public Boolean isCustomLocale() {
|
||||
return customLocale;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package net.artelnatif.nicko.config;
|
||||
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class ConfigurationManager {
|
||||
private final Logger logger = Logger.getLogger("ConfigurationManager");
|
||||
private final ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
|
||||
private final File file;
|
||||
|
||||
public ConfigurationManager(File directory) {
|
||||
this.file = new File(directory, "config.yml");
|
||||
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
}
|
||||
|
||||
public void save(Configuration configuration) throws IOException {
|
||||
try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
|
||||
mapper.writeValue(writer, configuration);
|
||||
writer.flush();
|
||||
}
|
||||
}
|
||||
|
||||
public void saveDefaultConfig() {
|
||||
if (!file.exists()) {
|
||||
try {
|
||||
final InputStream input = getClass().getResourceAsStream("/config.yml");
|
||||
if (input != null) {
|
||||
logger.info("Saved default configuration as config.yml");
|
||||
Files.createDirectories(file.getParentFile().toPath());
|
||||
Files.createFile(file.toPath());
|
||||
Files.copy(input, file.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Configuration load() throws IOException {
|
||||
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
|
||||
return mapper.readValue(reader, Configuration.class);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package net.artelnatif.nicko.config;
|
||||
|
||||
public class DataSourceConfiguration {
|
||||
public static final DataSourceConfiguration SQL_EMPTY = new DataSourceConfiguration("127.0.0.1", 3306, "root", "");
|
||||
public static final DataSourceConfiguration REDIS_EMPTY = new DataSourceConfiguration("127.0.0.1", 6379, "", "");
|
||||
|
||||
private final String address;
|
||||
private final Integer port;
|
||||
private final String username;
|
||||
private final String password;
|
||||
|
||||
public DataSourceConfiguration(String address, Integer port, String username, String password) {
|
||||
this.address = address;
|
||||
this.port = port;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public DataSourceConfiguration() { this("", 0, "", ""); }
|
||||
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public Integer getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package net.artelnatif.nicko.disguise;
|
||||
|
||||
import net.artelnatif.nicko.i18n.I18NDict;
|
||||
|
||||
public class ActionResult<R> {
|
||||
private final I18NDict errorMessage;
|
||||
private boolean error = false;
|
||||
private R result;
|
||||
|
||||
public ActionResult() {
|
||||
this.errorMessage = null;
|
||||
}
|
||||
|
||||
public ActionResult(I18NDict errorMessage) {
|
||||
this.errorMessage = errorMessage;
|
||||
this.error = true;
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
public ActionResult(R result) {
|
||||
this.errorMessage = null;
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public R getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean isError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
public I18NDict getErrorMessage() {
|
||||
return errorMessage;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package net.artelnatif.nicko.disguise;
|
||||
|
||||
import net.artelnatif.nicko.i18n.Locale;
|
||||
|
||||
public class NickoProfile implements Cloneable {
|
||||
public static final NickoProfile EMPTY_PROFILE = new NickoProfile(null, null, Locale.ENGLISH, true);
|
||||
|
||||
private String name;
|
||||
private String skin;
|
||||
private Locale locale;
|
||||
private boolean bungeecordTransfer;
|
||||
|
||||
public NickoProfile(String name, String skin, Locale locale, boolean bungeecordTransfer) {
|
||||
this.name = name;
|
||||
this.skin = skin;
|
||||
this.locale = locale;
|
||||
this.bungeecordTransfer = bungeecordTransfer;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return name == null && skin == null;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getSkin() {
|
||||
return skin;
|
||||
}
|
||||
|
||||
public void setSkin(String skin) {
|
||||
this.skin = skin;
|
||||
}
|
||||
|
||||
public Locale getLocale() { return locale; }
|
||||
|
||||
public void setLocale(Locale locale) { this.locale = locale; }
|
||||
|
||||
public boolean isBungeecordTransfer() {
|
||||
return bungeecordTransfer;
|
||||
}
|
||||
|
||||
public void setBungeecordTransfer(boolean bungeecordTransfer) {
|
||||
this.bungeecordTransfer = bungeecordTransfer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NickoProfile{" +
|
||||
"name='" + name + '\'' +
|
||||
", skin='" + skin + '\'' +
|
||||
", locale=" + locale +
|
||||
", bungeecordTransfer=" + bungeecordTransfer +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public NickoProfile clone() {
|
||||
Object o;
|
||||
try {
|
||||
o = super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return (NickoProfile) o;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package net.artelnatif.nicko.event;
|
||||
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import net.artelnatif.nicko.appearance.AppearanceManager;
|
||||
import net.artelnatif.nicko.disguise.ActionResult;
|
||||
import net.artelnatif.nicko.disguise.NickoProfile;
|
||||
import net.artelnatif.nicko.i18n.I18N;
|
||||
import net.artelnatif.nicko.i18n.I18NDict;
|
||||
import net.artelnatif.nicko.storage.PlayerDataStore;
|
||||
import net.artelnatif.nicko.storage.name.PlayerNameStore;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
|
||||
public class PlayerJoinListener implements Listener {
|
||||
@EventHandler
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
final NickoBukkit instance = NickoBukkit.getInstance();
|
||||
|
||||
final PlayerDataStore dataStore = instance.getDataStore();
|
||||
final PlayerNameStore nameStore = instance.getNameStore();
|
||||
nameStore.storeName(player);
|
||||
|
||||
// TODO: 2/20/23 BungeeCord transfer
|
||||
|
||||
dataStore.performProfileUpdate(player.getUniqueId(), NickoProfile.EMPTY_PROFILE);
|
||||
Bukkit.getScheduler().runTaskLater(instance, () -> {
|
||||
final AppearanceManager appearanceManager = AppearanceManager.get(player);
|
||||
if (appearanceManager.hasData()) {
|
||||
final ActionResult<Void> actionResult = appearanceManager.updatePlayer(appearanceManager.needsASkinChange());
|
||||
if (!actionResult.isError()) {
|
||||
player.sendMessage(I18N.translate(player, I18NDict.Event.PreviousSkin.SUCCESS));
|
||||
} else {
|
||||
player.sendMessage(I18N.translate(player, I18NDict.Event.PreviousSkin.FAIL, I18N.translateWithoutPrefix(player, actionResult.getErrorMessage())));
|
||||
}
|
||||
}
|
||||
}, 20L);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package net.artelnatif.nicko.event;
|
||||
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import net.artelnatif.nicko.disguise.ActionResult;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
|
||||
public class PlayerQuitListener implements Listener {
|
||||
@EventHandler
|
||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
final ActionResult<Void> result = NickoBukkit.getInstance().getDataStore().saveData(player);
|
||||
if (result.isError()) {
|
||||
NickoBukkit.getInstance().getLogger().warning("Failed to save data for " + player.getName());
|
||||
}
|
||||
}
|
||||
}
|
35
src/main/java/net/artelnatif/nicko/gui/AdminGUI.java
Normal file
35
src/main/java/net/artelnatif/nicko/gui/AdminGUI.java
Normal file
|
@ -0,0 +1,35 @@
|
|||
package net.artelnatif.nicko.gui;
|
||||
|
||||
import net.artelnatif.nicko.gui.items.admin.ManageCache;
|
||||
import net.artelnatif.nicko.gui.items.common.GoBack;
|
||||
import org.bukkit.entity.Player;
|
||||
import xyz.xenondevs.invui.gui.Gui;
|
||||
import xyz.xenondevs.invui.window.Window;
|
||||
|
||||
public class AdminGUI {
|
||||
public static final String TITLE = "Nicko > Administration";
|
||||
|
||||
private final Player player;
|
||||
private final Gui gui;
|
||||
|
||||
public AdminGUI(Player player) {
|
||||
this.gui = Gui.normal()
|
||||
.setStructure(
|
||||
"# # # # # # # # #",
|
||||
"# # # S U U # # #",
|
||||
"B # # # # # # # #"
|
||||
)
|
||||
.addIngredient('S', new ManageCache())
|
||||
.addIngredient('B', new GoBack(new MainGUI(player).getGUI()))
|
||||
.build();
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public Gui getGUI() {
|
||||
return gui;
|
||||
}
|
||||
|
||||
public void open() {
|
||||
Window.single().setGui(gui).setTitle(TITLE).open(player);
|
||||
}
|
||||
}
|
46
src/main/java/net/artelnatif/nicko/gui/MainGUI.java
Normal file
46
src/main/java/net/artelnatif/nicko/gui/MainGUI.java
Normal file
|
@ -0,0 +1,46 @@
|
|||
package net.artelnatif.nicko.gui;
|
||||
|
||||
import net.artelnatif.nicko.gui.items.main.AdminSubGUI;
|
||||
import net.artelnatif.nicko.gui.items.main.ResetAppearance;
|
||||
import net.artelnatif.nicko.gui.items.main.SettingsSubGUI;
|
||||
import net.artelnatif.nicko.gui.items.skin.ChangeName;
|
||||
import net.artelnatif.nicko.gui.items.skin.ChangeNameAndSkin;
|
||||
import net.artelnatif.nicko.gui.items.skin.ChangeSkin;
|
||||
import org.bukkit.entity.Player;
|
||||
import xyz.xenondevs.invui.gui.Gui;
|
||||
import xyz.xenondevs.invui.window.Window;
|
||||
|
||||
public class MainGUI {
|
||||
private final Player player;
|
||||
private final Gui gui;
|
||||
|
||||
public MainGUI(Player player) {
|
||||
final String[] dynamicStructure = new String[]{
|
||||
"# # # # # # # # #",
|
||||
"# # # N B S # # #",
|
||||
"E P A # # # # # R"};
|
||||
|
||||
if (!player.hasPermission("nicko.admin") || !player.isOp()) {
|
||||
dynamicStructure[2] = dynamicStructure[2].replace("A", "#");
|
||||
}
|
||||
|
||||
this.gui = Gui.normal()
|
||||
.setStructure(dynamicStructure)
|
||||
.addIngredient('R', new ResetAppearance())
|
||||
.addIngredient('N', new ChangeName())
|
||||
.addIngredient('B', new ChangeNameAndSkin())
|
||||
.addIngredient('S', new ChangeSkin(player))
|
||||
.addIngredient('P', new SettingsSubGUI())
|
||||
.addIngredient('A', new AdminSubGUI())
|
||||
.build();
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public Gui getGUI() {
|
||||
return gui;
|
||||
}
|
||||
|
||||
public void open() {
|
||||
Window.single().setGui(gui).setTitle("Nicko - Home").open(player);
|
||||
}
|
||||
}
|
38
src/main/java/net/artelnatif/nicko/gui/SettingsGUI.java
Normal file
38
src/main/java/net/artelnatif/nicko/gui/SettingsGUI.java
Normal file
|
@ -0,0 +1,38 @@
|
|||
package net.artelnatif.nicko.gui;
|
||||
|
||||
import net.artelnatif.nicko.gui.items.common.GoBack;
|
||||
import net.artelnatif.nicko.gui.items.settings.BungeeCordCycling;
|
||||
import net.artelnatif.nicko.gui.items.settings.LanguageCycling;
|
||||
import org.bukkit.entity.Player;
|
||||
import xyz.xenondevs.invui.gui.Gui;
|
||||
import xyz.xenondevs.invui.window.Window;
|
||||
|
||||
public class SettingsGUI {
|
||||
public static final String TITLE = "Nicko > Settings";
|
||||
|
||||
private final Player player;
|
||||
private final Gui gui;
|
||||
|
||||
public SettingsGUI(Player player) {
|
||||
final String[] dynamicStructure = new String[]{
|
||||
"# # # # # # # # #",
|
||||
"# # # L T U # # #",
|
||||
"B # # # # # # # #"
|
||||
};
|
||||
|
||||
// TODO: 3/6/23 Replace when Redis is not enabled
|
||||
dynamicStructure[1] = dynamicStructure[1].replace("T", "U");
|
||||
|
||||
this.gui = Gui.normal()
|
||||
.setStructure(dynamicStructure)
|
||||
.addIngredient('B', new GoBack(new MainGUI(player).getGUI()))
|
||||
.addIngredient('L', new LanguageCycling().get(player))
|
||||
.addIngredient('T', new BungeeCordCycling().get(player))
|
||||
.build();
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public void open() {
|
||||
Window.single().setGui(gui).setTitle(TITLE).open(player);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package net.artelnatif.nicko.gui.admin;
|
||||
|
||||
import net.artelnatif.nicko.gui.AdminGUI;
|
||||
import net.artelnatif.nicko.gui.items.admin.cache.CacheDetailed;
|
||||
import net.artelnatif.nicko.gui.items.admin.cache.CacheInvalidate;
|
||||
import net.artelnatif.nicko.gui.items.admin.cache.CacheOverview;
|
||||
import net.artelnatif.nicko.gui.items.common.GoBack;
|
||||
import org.bukkit.entity.Player;
|
||||
import xyz.xenondevs.invui.gui.Gui;
|
||||
import xyz.xenondevs.invui.window.Window;
|
||||
|
||||
public class CacheManagementGUI {
|
||||
public static final String TITLE = "Nicko > Admin... > Cache";
|
||||
|
||||
private final Player player;
|
||||
private final Gui gui;
|
||||
|
||||
public CacheManagementGUI(Player player) {
|
||||
this.gui = Gui.normal()
|
||||
.setStructure("B # S A D")
|
||||
.addIngredient('B', new GoBack(new AdminGUI(player).getGUI()))
|
||||
.addIngredient('S', new CacheOverview())
|
||||
.addIngredient('A', new CacheInvalidate())
|
||||
.addIngredient('D', new CacheDetailed())
|
||||
.build();
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public Gui getGUI() {
|
||||
return gui;
|
||||
}
|
||||
|
||||
public void open() {
|
||||
Window.single().setGui(gui).setTitle(TITLE).open(player);
|
||||
}
|
||||
}
|
61
src/main/java/net/artelnatif/nicko/gui/admin/cache/CacheDetailedGUI.java
vendored
Normal file
61
src/main/java/net/artelnatif/nicko/gui/admin/cache/CacheDetailedGUI.java
vendored
Normal file
|
@ -0,0 +1,61 @@
|
|||
package net.artelnatif.nicko.gui.admin.cache;
|
||||
|
||||
import xyz.xenondevs.invui.gui.Gui;
|
||||
import xyz.xenondevs.invui.gui.ScrollGui;
|
||||
import xyz.xenondevs.invui.gui.structure.Markers;
|
||||
import xyz.xenondevs.invui.item.Item;
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import net.artelnatif.nicko.gui.items.admin.cache.SkinPlaceholder;
|
||||
import net.artelnatif.nicko.gui.admin.CacheManagementGUI;
|
||||
import net.artelnatif.nicko.gui.items.common.GoBack;
|
||||
import net.artelnatif.nicko.gui.items.common.ScrollDown;
|
||||
import net.artelnatif.nicko.gui.items.common.ScrollUp;
|
||||
import net.artelnatif.nicko.mojang.MojangSkin;
|
||||
import org.bukkit.entity.Player;
|
||||
import xyz.xenondevs.invui.window.Window;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class CacheDetailedGUI {
|
||||
public static final String TITLE = "... > Cache > Invalidate";
|
||||
|
||||
private final Player player;
|
||||
private final Gui gui;
|
||||
|
||||
public CacheDetailedGUI(Player player) {
|
||||
final ConcurrentMap<String, Optional<MojangSkin>> skins = NickoBukkit.getInstance().getMojangAPI().getCache().asMap();
|
||||
final List<String> loadedSkins = skins.entrySet().stream()
|
||||
.filter(entry -> entry.getValue().isPresent())
|
||||
.map(Map.Entry::getKey)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
final List<Item> items = loadedSkins.stream()
|
||||
.map(SkinPlaceholder::new)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
gui = ScrollGui.items(guiItemBuilder -> {
|
||||
guiItemBuilder.setStructure(
|
||||
"# # # # # # # # #",
|
||||
"# x x x x x x U #",
|
||||
"# x x x x x x # #",
|
||||
"# x x x x x x # #",
|
||||
"# x x x x x x D #",
|
||||
"B # # # # # # # #");
|
||||
guiItemBuilder.addIngredient('x', Markers.CONTENT_LIST_SLOT_HORIZONTAL);
|
||||
guiItemBuilder.addIngredient('U', new ScrollUp());
|
||||
guiItemBuilder.addIngredient('D', new ScrollDown());
|
||||
guiItemBuilder.addIngredient('B', new GoBack(new CacheManagementGUI(player).getGUI()));
|
||||
guiItemBuilder.setContent(items);
|
||||
});
|
||||
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public void open() {
|
||||
Window.single().setGui(gui).setTitle(TITLE).open(player);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package net.artelnatif.nicko.gui.items.admin;
|
||||
|
||||
import xyz.xenondevs.invui.item.builder.ItemBuilder;
|
||||
import xyz.xenondevs.invui.item.builder.SkullBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.AsyncItem;
|
||||
import net.artelnatif.nicko.gui.admin.CacheManagementGUI;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ManageCache extends AsyncItem {
|
||||
public ManageCache() {
|
||||
super(new ItemBuilder(Material.PAINTING)
|
||||
.setDisplayName("§fManage §6skin §fcache...")
|
||||
.addLoreLines("§7Access the skin cache management panel."),
|
||||
() -> {
|
||||
final SkullBuilder builder = new SkullBuilder("Notch");
|
||||
builder.setDisplayName("§fManage §6skin §fcache...");
|
||||
builder.addLoreLines("§7Access the skin cache management panel.");
|
||||
return builder;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleClick(@NotNull ClickType clickType, @NotNull Player player, @NotNull InventoryClickEvent event) {
|
||||
if (clickType.isLeftClick() || clickType.isRightClick()) {
|
||||
event.getView().close();
|
||||
new CacheManagementGUI(player).open();
|
||||
}
|
||||
}
|
||||
}
|
26
src/main/java/net/artelnatif/nicko/gui/items/admin/cache/CacheDetailed.java
vendored
Normal file
26
src/main/java/net/artelnatif/nicko/gui/items/admin/cache/CacheDetailed.java
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
package net.artelnatif.nicko.gui.items.admin.cache;
|
||||
|
||||
import net.artelnatif.nicko.gui.admin.cache.CacheDetailedGUI;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import xyz.xenondevs.invui.item.builder.ItemBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.SuppliedItem;
|
||||
|
||||
public class CacheDetailed extends SuppliedItem {
|
||||
public CacheDetailed() {
|
||||
super(() -> {
|
||||
final ItemBuilder builder = new ItemBuilder(Material.PAPER);
|
||||
builder.setDisplayName("§6Invalidate specific skin...");
|
||||
builder.addLoreLines("§7Select a specific skin to invalidate.");
|
||||
return builder;
|
||||
}, (click) -> {
|
||||
final ClickType clickType = click.getClickType();
|
||||
if (clickType.isLeftClick() || clickType.isRightClick()) {
|
||||
click.getEvent().getView().close();
|
||||
new CacheDetailedGUI(click.getPlayer()).open();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
36
src/main/java/net/artelnatif/nicko/gui/items/admin/cache/CacheInvalidate.java
vendored
Normal file
36
src/main/java/net/artelnatif/nicko/gui/items/admin/cache/CacheInvalidate.java
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
package net.artelnatif.nicko.gui.items.admin.cache;
|
||||
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import net.artelnatif.nicko.i18n.I18N;
|
||||
import net.artelnatif.nicko.i18n.I18NDict;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import xyz.xenondevs.invui.item.builder.ItemBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.SuppliedItem;
|
||||
|
||||
public class CacheInvalidate extends SuppliedItem {
|
||||
public CacheInvalidate() {
|
||||
super(() -> {
|
||||
final ItemBuilder builder = new ItemBuilder(Material.TNT);
|
||||
builder.setDisplayName("§fInvalidate §6skin cache");
|
||||
builder.addLoreLines(
|
||||
"§c§oNOT RECOMMENDED",
|
||||
"§7Invalidates every skin entry present in the cache.",
|
||||
"§7Does not reset player disguises.",
|
||||
"§7Could be useful if a skin has been updated",
|
||||
"§7recently and the cache is now outdated.");
|
||||
return builder;
|
||||
}, (click) -> {
|
||||
final ClickType clickType = click.getClickType();
|
||||
if (clickType.isLeftClick() || clickType.isRightClick()) {
|
||||
final Player player = click.getPlayer();
|
||||
click.getEvent().getView().close();
|
||||
player.sendMessage(I18N.translate(player, I18NDict.Event.Admin.CACHE_CLEAN));
|
||||
NickoBukkit.getInstance().getMojangAPI().getCache().invalidateAll();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
28
src/main/java/net/artelnatif/nicko/gui/items/admin/cache/CacheOverview.java
vendored
Normal file
28
src/main/java/net/artelnatif/nicko/gui/items/admin/cache/CacheOverview.java
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
package net.artelnatif.nicko.gui.items.admin.cache;
|
||||
|
||||
import com.google.common.cache.CacheStats;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import net.artelnatif.nicko.mojang.MojangSkin;
|
||||
import org.bukkit.Material;
|
||||
import xyz.xenondevs.invui.item.builder.ItemBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.SuppliedItem;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class CacheOverview extends SuppliedItem {
|
||||
public CacheOverview() {
|
||||
super(() -> {
|
||||
final ItemBuilder builder = new ItemBuilder(Material.OAK_SIGN);
|
||||
final LoadingCache<String, Optional<MojangSkin>> cache = NickoBukkit.getInstance().getMojangAPI().getCache();
|
||||
final CacheStats stats = cache.stats();
|
||||
builder.setDisplayName("§6Skin cache §foverview:");
|
||||
builder.addLoreLines(
|
||||
"Request Count: §2" + stats.requestCount(),
|
||||
"Skin Cached: §2" + Math.round(cache.size()),
|
||||
"§7§oCache is cleared every 24 hours.",
|
||||
"§7§o(Click to refresh)");
|
||||
return builder;
|
||||
}, (event) -> true);
|
||||
}
|
||||
}
|
21
src/main/java/net/artelnatif/nicko/gui/items/admin/cache/SkinPlaceholder.java
vendored
Normal file
21
src/main/java/net/artelnatif/nicko/gui/items/admin/cache/SkinPlaceholder.java
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
package net.artelnatif.nicko.gui.items.admin.cache;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import xyz.xenondevs.invui.item.builder.ItemBuilder;
|
||||
import xyz.xenondevs.invui.item.builder.SkullBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.AsyncItem;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class SkinPlaceholder extends AsyncItem {
|
||||
public SkinPlaceholder(String name) {
|
||||
super(new ItemBuilder(Material.PAINTING).setDisplayName("§7§oLoading..."), () -> {
|
||||
final String stringUUID = name.replaceAll("(.{8})(.{4})(.{4})(.{4})(.+)", "$1-$2-$3-$4-$5");
|
||||
final UUID uuid = UUID.fromString(stringUUID);
|
||||
final SkullBuilder skull = new SkullBuilder(uuid);
|
||||
skull.setDisplayName("§6Skin Entry");
|
||||
skull.addLoreLines("§7Click to invalidate skin");
|
||||
return skull;
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package net.artelnatif.nicko.gui.items.common;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import xyz.xenondevs.invui.gui.Gui;
|
||||
import xyz.xenondevs.invui.item.builder.ItemBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.SuppliedItem;
|
||||
import xyz.xenondevs.invui.window.Window;
|
||||
|
||||
public class GoBack extends SuppliedItem {
|
||||
public GoBack(Gui gui) {
|
||||
super(() -> {
|
||||
final ItemBuilder builder = new ItemBuilder(Material.ARROW);
|
||||
builder.setDisplayName("Go back");
|
||||
builder.addLoreLines("§7Return to the previous window.");
|
||||
return builder;
|
||||
}, click -> {
|
||||
click.getEvent().getView().close();
|
||||
// TODO: 4/1/23 Get title of parent GUI
|
||||
Window.single().setGui(gui).setTitle("Nicko").open(click.getPlayer());
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package net.artelnatif.nicko.gui.items.common;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import xyz.xenondevs.invui.item.builder.ItemBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.SuppliedItem;
|
||||
|
||||
public class OptionUnavailable extends SuppliedItem {
|
||||
public OptionUnavailable() {
|
||||
super(() -> {
|
||||
final ItemBuilder builder = new ItemBuilder(Material.RED_TERRACOTTA);
|
||||
builder.setDisplayName("§cFeature unavailable :(");
|
||||
builder.addLoreLines("§7This button is disabled.");
|
||||
return builder;
|
||||
}, click -> true);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package net.artelnatif.nicko.gui.items.common;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import xyz.xenondevs.invui.gui.ScrollGui;
|
||||
import xyz.xenondevs.invui.item.ItemProvider;
|
||||
import xyz.xenondevs.invui.item.builder.ItemBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.controlitem.ScrollItem;
|
||||
|
||||
public class ScrollDown extends ScrollItem {
|
||||
|
||||
public ScrollDown() {
|
||||
super(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemProvider getItemProvider(ScrollGui gui) {
|
||||
ItemBuilder builder = new ItemBuilder(Material.GREEN_STAINED_GLASS_PANE);
|
||||
builder.setDisplayName("§7Scroll down");
|
||||
if (!gui.canScroll(1))
|
||||
builder.addLoreLines("§cYou can't scroll further down");
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package net.artelnatif.nicko.gui.items.common;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import xyz.xenondevs.invui.gui.ScrollGui;
|
||||
import xyz.xenondevs.invui.item.ItemProvider;
|
||||
import xyz.xenondevs.invui.item.builder.ItemBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.controlitem.ScrollItem;
|
||||
|
||||
public class ScrollUp extends ScrollItem {
|
||||
|
||||
public ScrollUp() {
|
||||
super(-1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemProvider getItemProvider(ScrollGui gui) {
|
||||
ItemBuilder builder = new ItemBuilder(Material.RED_STAINED_GLASS_PANE);
|
||||
builder.setDisplayName("§7Scroll up");
|
||||
if (!gui.canScroll(-1))
|
||||
builder.addLoreLines("§cYou've reached the top");
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package net.artelnatif.nicko.gui.items.main;
|
||||
|
||||
import net.artelnatif.nicko.gui.AdminGUI;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import org.bukkit.inventory.ItemFlag;
|
||||
import xyz.xenondevs.invui.item.builder.ItemBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.SuppliedItem;
|
||||
|
||||
public class AdminSubGUI extends SuppliedItem {
|
||||
public AdminSubGUI() {
|
||||
super(() -> {
|
||||
final ItemBuilder builder = new ItemBuilder(Material.COMMAND_BLOCK);
|
||||
builder.addEnchantment(Enchantment.DAMAGE_ALL, 1, false);
|
||||
builder.addItemFlags(ItemFlag.HIDE_ENCHANTS);
|
||||
builder.setDisplayName("§cAdministration panel...");
|
||||
builder.addLoreLines("§7Access the administration panel.");
|
||||
return builder;
|
||||
}, click -> {
|
||||
final ClickType clickType = click.getClickType();
|
||||
if (clickType.isLeftClick() || clickType.isRightClick()) {
|
||||
click.getEvent().getView().close();
|
||||
new AdminGUI(click.getPlayer()).open();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package net.artelnatif.nicko.gui.items.main;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import xyz.xenondevs.invui.item.builder.ItemBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.SimpleItem;
|
||||
|
||||
public class ExitGUI extends SimpleItem {
|
||||
public ExitGUI() {
|
||||
super(new ItemBuilder(Material.OAK_DOOR).setDisplayName("§fExit"), click -> {
|
||||
final ClickType clickType = click.getClickType();
|
||||
if (clickType.isLeftClick() || clickType.isRightClick()) {
|
||||
click.getEvent().getView().close();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package net.artelnatif.nicko.gui.items.main;
|
||||
|
||||
import net.artelnatif.nicko.appearance.AppearanceManager;
|
||||
import net.artelnatif.nicko.i18n.I18N;
|
||||
import net.artelnatif.nicko.i18n.I18NDict;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import xyz.xenondevs.invui.item.builder.ItemBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.SuppliedItem;
|
||||
|
||||
public class ResetAppearance extends SuppliedItem {
|
||||
public ResetAppearance() {
|
||||
super(() -> {
|
||||
final ItemBuilder builder = new ItemBuilder(Material.TNT);
|
||||
builder.setDisplayName("§fReset");
|
||||
builder.addLoreLines("§7Get rid of your disguise.");
|
||||
return builder;
|
||||
}, (event) -> {
|
||||
final Player player = event.getPlayer();
|
||||
final ClickType clickType = event.getClickType();
|
||||
if (clickType.isLeftClick() || clickType.isRightClick()) {
|
||||
final AppearanceManager appearanceManager = AppearanceManager.get(player);
|
||||
|
||||
if (!appearanceManager.hasData()) {
|
||||
player.sendMessage(I18N.translate(player, I18NDict.Event.Undisguise.NONE));
|
||||
event.getEvent().getView().close();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!appearanceManager.reset().isError()) {
|
||||
player.sendMessage(I18N.translate(player, I18NDict.Event.Undisguise.SUCCESS));
|
||||
return true;
|
||||
} else {
|
||||
player.sendMessage(I18N.translate(player, I18NDict.Event.Undisguise.FAIL));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package net.artelnatif.nicko.gui.items.main;
|
||||
|
||||
import net.artelnatif.nicko.gui.SettingsGUI;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import xyz.xenondevs.invui.item.builder.ItemBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.SuppliedItem;
|
||||
|
||||
public class SettingsSubGUI extends SuppliedItem {
|
||||
public SettingsSubGUI() {
|
||||
super(() -> {
|
||||
final ItemBuilder builder = new ItemBuilder(Material.COMPARATOR);
|
||||
builder.setDisplayName("§fSettings...");
|
||||
builder.addLoreLines("§7Adjust your preferences.");
|
||||
return builder;
|
||||
}, click -> {
|
||||
final ClickType clickType = click.getClickType();
|
||||
if (clickType.isLeftClick() || clickType.isRightClick()) {
|
||||
click.getEvent().getView().close();
|
||||
new SettingsGUI(click.getPlayer()).open();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package net.artelnatif.nicko.gui.items.settings;
|
||||
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import net.artelnatif.nicko.disguise.NickoProfile;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.Player;
|
||||
import xyz.xenondevs.invui.item.ItemProvider;
|
||||
import xyz.xenondevs.invui.item.builder.ItemBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.AbstractItem;
|
||||
import xyz.xenondevs.invui.item.impl.CycleItem;
|
||||
import xyz.xenondevs.invui.item.impl.SimpleItem;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class BungeeCordCycling {
|
||||
private final ItemProvider[] providers = new ItemProvider[]{
|
||||
getItemProviderForValue(true),
|
||||
getItemProviderForValue(false)
|
||||
};
|
||||
|
||||
public AbstractItem get(Player player) {
|
||||
final Optional<NickoProfile> profile = NickoBukkit.getInstance().getDataStore().getData(player.getUniqueId());
|
||||
if (profile.isPresent()) {
|
||||
final NickoProfile nickoProfile = profile.get();
|
||||
int startingState = nickoProfile.isBungeecordTransfer() ? 0 : 1;
|
||||
return CycleItem.withStateChangeHandler((observer, integer) -> {
|
||||
nickoProfile.setBungeecordTransfer(integer != 1);
|
||||
observer.playSound(player, Sound.UI_BUTTON_CLICK, 1f, 0.707107f); // 0.707107 ~= C
|
||||
}, startingState, providers);
|
||||
}
|
||||
|
||||
return new SimpleItem(ItemProvider.EMPTY);
|
||||
}
|
||||
|
||||
private ItemProvider getItemProviderForValue(boolean enabled) {
|
||||
final ItemBuilder builder = new ItemBuilder(Material.COMPASS);
|
||||
builder.setDisplayName("§6BungeeCord transfer:");
|
||||
if (enabled) {
|
||||
builder.addLoreLines("§7> §cDisabled");
|
||||
builder.addLoreLines("§6§l> §a§lEnabled");
|
||||
} else {
|
||||
builder.addLoreLines("§6§l> §c§lDisabled");
|
||||
builder.addLoreLines("§7> §aEnabled");
|
||||
}
|
||||
builder.addLoreLines("§7§oCycle through the values by", "§7§oleft and right clicking.");
|
||||
return builder;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package net.artelnatif.nicko.gui.items.settings;
|
||||
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import net.artelnatif.nicko.disguise.NickoProfile;
|
||||
import net.artelnatif.nicko.i18n.Locale;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.Player;
|
||||
import xyz.xenondevs.invui.item.ItemProvider;
|
||||
import xyz.xenondevs.invui.item.builder.ItemBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.AbstractItem;
|
||||
import xyz.xenondevs.invui.item.impl.CycleItem;
|
||||
import xyz.xenondevs.invui.item.impl.SimpleItem;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class LanguageCycling {
|
||||
private final ItemProvider[] providers = getItems();
|
||||
|
||||
public AbstractItem get(Player player) {
|
||||
final Optional<NickoProfile> profile = NickoBukkit.getInstance().getDataStore().getData(player.getUniqueId());
|
||||
if (profile.isPresent()) {
|
||||
final NickoProfile nickoProfile = profile.get();
|
||||
int localeOrdinal = nickoProfile.getLocale().ordinal();
|
||||
return CycleItem.withStateChangeHandler((observer, integer) -> {
|
||||
nickoProfile.setLocale(Locale.values()[integer]);
|
||||
observer.playSound(player, Sound.UI_BUTTON_CLICK, 1f, 0.707107f); // 0.707107 ~= C
|
||||
}, localeOrdinal, providers);
|
||||
}
|
||||
|
||||
return new SimpleItem(ItemProvider.EMPTY);
|
||||
}
|
||||
|
||||
private ItemProvider generateItem(Locale locale, List<Locale> locales) {
|
||||
final ItemBuilder builder = new ItemBuilder(Material.OAK_SIGN);
|
||||
builder.setDisplayName("§6Select your language:");
|
||||
for (Locale value : locales) {
|
||||
if (locale != value) {
|
||||
builder.addLoreLines("§7> " + value.getName());
|
||||
} else {
|
||||
builder.addLoreLines("§6§l> §f" + value.getName());
|
||||
}
|
||||
}
|
||||
builder.addLoreLines("§7§oCycle through the values by", "§7§oleft and right clicking.");
|
||||
return builder;
|
||||
}
|
||||
|
||||
private ItemProvider[] getItems() {
|
||||
final NickoBukkit instance = NickoBukkit.getInstance();
|
||||
final ArrayList<ItemProvider> items = new ArrayList<>();
|
||||
|
||||
final ArrayList<Locale> localesToGenerate = new ArrayList<>();
|
||||
Collections.addAll(localesToGenerate, Locale.values());
|
||||
if (!instance.getNickoConfig().isCustomLocale()) {
|
||||
localesToGenerate.remove(Locale.CUSTOM);
|
||||
}
|
||||
localesToGenerate.forEach(locale -> items.add(generateItem(locale, localesToGenerate)));
|
||||
return items.toArray(new ItemProvider[]{});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package net.artelnatif.nicko.gui.items.skin;
|
||||
|
||||
import net.artelnatif.nicko.anvil.AnvilManager;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import xyz.xenondevs.invui.item.builder.ItemBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.SuppliedItem;
|
||||
|
||||
public class ChangeName extends SuppliedItem {
|
||||
public ChangeName() {
|
||||
super(() -> {
|
||||
final ItemBuilder builder = new ItemBuilder(Material.NAME_TAG);
|
||||
builder.setDisplayName("§fChange §6name");
|
||||
builder.addLoreLines("§7Only change your name.");
|
||||
return builder;
|
||||
}, click -> {
|
||||
final ClickType clickType = click.getClickType();
|
||||
if (clickType.isLeftClick() || clickType.isRightClick()) {
|
||||
click.getEvent().getView().close();
|
||||
final AnvilManager manager = new AnvilManager(click.getPlayer());
|
||||
manager.openNameAnvil();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package net.artelnatif.nicko.gui.items.skin;
|
||||
|
||||
import net.artelnatif.nicko.anvil.AnvilManager;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import xyz.xenondevs.invui.item.builder.ItemBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.SuppliedItem;
|
||||
|
||||
public class ChangeNameAndSkin extends SuppliedItem {
|
||||
public ChangeNameAndSkin() {
|
||||
super(() -> {
|
||||
final ItemBuilder builder = new ItemBuilder(Material.END_PORTAL_FRAME);
|
||||
builder.setDisplayName("§6Skin §fand §6name §fchange");
|
||||
builder.addLoreLines("§7Change both your skin and name.");
|
||||
return builder;
|
||||
}, click -> {
|
||||
final ClickType clickType = click.getClickType();
|
||||
if (clickType.isLeftClick() || clickType.isRightClick()) {
|
||||
click.getEvent().getView().close();
|
||||
final AnvilManager manager = new AnvilManager(click.getPlayer());
|
||||
manager.openNameThenSkinAnvil();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package net.artelnatif.nicko.gui.items.skin;
|
||||
|
||||
import net.artelnatif.nicko.anvil.AnvilManager;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import xyz.xenondevs.invui.item.builder.SkullBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.SuppliedItem;
|
||||
|
||||
public class ChangeSkin extends SuppliedItem {
|
||||
public ChangeSkin(Player player) {
|
||||
super(() -> {
|
||||
final SkullBuilder builder = new SkullBuilder(player.getName());
|
||||
builder.setDisplayName("§fChange §6skin");
|
||||
builder.addLoreLines("§7Only change your skin.");
|
||||
return builder;
|
||||
}, click -> {
|
||||
final ClickType clickType = click.getClickType();
|
||||
if (clickType.isLeftClick() || clickType.isRightClick()) {
|
||||
click.getEvent().getView().close();
|
||||
final AnvilManager manager = new AnvilManager(click.getPlayer());
|
||||
manager.openSkinAnvil();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
62
src/main/java/net/artelnatif/nicko/i18n/I18N.java
Normal file
62
src/main/java/net/artelnatif/nicko/i18n/I18N.java
Normal file
|
@ -0,0 +1,62 @@
|
|||
package net.artelnatif.nicko.i18n;
|
||||
|
||||
import com.github.jsixface.YamlConfig;
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import net.artelnatif.nicko.disguise.NickoProfile;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Optional;
|
||||
|
||||
public class I18N {
|
||||
private final static MessageFormat formatter = new MessageFormat("");
|
||||
|
||||
private static Locale getLocale(Player player) {
|
||||
final NickoBukkit instance = NickoBukkit.getInstance();
|
||||
try {
|
||||
final Optional<NickoProfile> profile = instance.getDataStore().getData(player.getUniqueId());
|
||||
return !profile.isPresent() ? Locale.FALLBACK_LOCALE : profile.get().getLocale();
|
||||
} catch (IllegalArgumentException exception) {
|
||||
instance.getLogger().severe("Invalid locale provided by " + player.getName() + ", defaulting to " + Locale.FALLBACK_LOCALE.getCode() + ".");
|
||||
return Locale.FALLBACK_LOCALE;
|
||||
}
|
||||
}
|
||||
|
||||
public static String translate(Player player, I18NDict key, Object... arguments) {
|
||||
final NickoBukkit instance = NickoBukkit.getInstance();
|
||||
final String translation = findTranslation(player, key);
|
||||
|
||||
try {
|
||||
formatter.applyPattern(translation);
|
||||
return instance.getNickoConfig().getPrefix() + formatter.format(arguments);
|
||||
} catch (Exception e) {
|
||||
return instance.getNickoConfig().getPrefix() + key.key();
|
||||
}
|
||||
}
|
||||
|
||||
public static String translateWithoutPrefix(Player player, I18NDict key, Object... arguments) {
|
||||
final String translation = findTranslation(player, key);
|
||||
try {
|
||||
formatter.applyPattern(translation);
|
||||
return formatter.format(arguments);
|
||||
} catch (Exception e) {
|
||||
return key.key();
|
||||
}
|
||||
}
|
||||
|
||||
private static String findTranslation(Player player, I18NDict key) {
|
||||
final NickoBukkit instance = NickoBukkit.getInstance();
|
||||
final Locale locale = getLocale(player);
|
||||
String translation;
|
||||
if (locale == Locale.CUSTOM) {
|
||||
translation = instance.getLocaleFileManager().get(key.key());
|
||||
} else {
|
||||
final InputStream resource = instance.getResource(locale.getCode() + ".yml");
|
||||
final YamlConfig yamlConfig = YamlConfig.load(resource);
|
||||
translation = yamlConfig.getString(key.key());
|
||||
}
|
||||
|
||||
return translation;
|
||||
}
|
||||
}
|
44
src/main/java/net/artelnatif/nicko/i18n/I18NDict.java
Normal file
44
src/main/java/net/artelnatif/nicko/i18n/I18NDict.java
Normal file
|
@ -0,0 +1,44 @@
|
|||
package net.artelnatif.nicko.i18n;
|
||||
|
||||
public class I18NDict {
|
||||
private final String key;
|
||||
|
||||
public I18NDict(String key) { this.key = key; }
|
||||
|
||||
public static class Event {
|
||||
public static class Admin {
|
||||
public static final I18NDict CACHE_CLEAN = new I18NDict("event.admin.cache_clear");
|
||||
}
|
||||
|
||||
public static class Disguise {
|
||||
public static final I18NDict SUCCESS = new I18NDict("event.disguise.success");
|
||||
public static final I18NDict FAIL = new I18NDict("event.disguise.fail");
|
||||
}
|
||||
|
||||
public static class Undisguise {
|
||||
public static final I18NDict SUCCESS = new I18NDict("event.undisguise.success");
|
||||
public static final I18NDict FAIL = new I18NDict("event.undisguise.fail");
|
||||
public static final I18NDict NONE = new I18NDict("event.undisguise.none");
|
||||
}
|
||||
|
||||
public static class PreviousSkin {
|
||||
public static final I18NDict SUCCESS = new I18NDict("event.previous_skin_applied.success");
|
||||
public static final I18NDict FAIL = new I18NDict("event.previous_skin_applied.fail");
|
||||
}
|
||||
}
|
||||
|
||||
public static class Error {
|
||||
public static final I18NDict PLAYER_OFFLINE = new I18NDict("error.player_offline");
|
||||
public static final I18NDict SKIN_FAIL_MOJANG = new I18NDict("error.couldnt_get_skin_from_mojang");
|
||||
public static final I18NDict SKIN_FAIL_CACHE = new I18NDict("error.couldnt_get_skin_from_cache");
|
||||
public static final I18NDict NAME_FAIL_MOJANG = new I18NDict("error.couldnt_get_name_from_mojang");
|
||||
public static final I18NDict INVALID_USERNAME = new I18NDict("error.invalid_username");
|
||||
public static final I18NDict UNEXPECTED_ERROR = new I18NDict("error.generic");
|
||||
public static final I18NDict SQL_ERROR = new I18NDict("error.sql");
|
||||
public static final I18NDict JSON_ERROR = new I18NDict("error.json");
|
||||
}
|
||||
|
||||
public String key() {
|
||||
return key;
|
||||
}
|
||||
}
|
34
src/main/java/net/artelnatif/nicko/i18n/Locale.java
Normal file
34
src/main/java/net/artelnatif/nicko/i18n/Locale.java
Normal file
|
@ -0,0 +1,34 @@
|
|||
package net.artelnatif.nicko.i18n;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public enum Locale implements Serializable {
|
||||
ENGLISH("en", "English"),
|
||||
FRENCH("fr", "Français"),
|
||||
CUSTOM("cm", "Server Custom");
|
||||
|
||||
public static final Locale FALLBACK_LOCALE = ENGLISH;
|
||||
|
||||
private final String code;
|
||||
private transient final String name;
|
||||
|
||||
Locale(String code, String name) {
|
||||
this.code = code;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public static Locale fromCode(String code) {
|
||||
for (Locale value : values()) {
|
||||
if (code.equals(value.code)) return value;
|
||||
}
|
||||
return ENGLISH;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package net.artelnatif.nicko.i18n;
|
||||
|
||||
import com.github.jsixface.YamlConfig;
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import xyz.xenondevs.invui.util.IOUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
|
||||
public class LocaleFileManager {
|
||||
private final File folder = new File(NickoBukkit.getInstance().getDataFolder() + "/lang/");
|
||||
private final File file = new File(folder, "lang.yml");
|
||||
|
||||
public String get(String key) {
|
||||
if (!file.exists()) return key;
|
||||
try (BufferedInputStream inputStream = new BufferedInputStream(Files.newInputStream(file.toPath()))) {
|
||||
final YamlConfig yamlConfig = YamlConfig.load(inputStream);
|
||||
return yamlConfig.getString(key);
|
||||
} catch (IOException e) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean dumpFromLocale(Locale locale) {
|
||||
if (locale == Locale.CUSTOM) return true;
|
||||
if (file.exists()) return true;
|
||||
final InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(locale.getCode() + ".yml");
|
||||
try {
|
||||
if (folder.mkdirs()) {
|
||||
if (file.createNewFile()) {
|
||||
try (FileOutputStream outputStream = new FileOutputStream(file)) {
|
||||
IOUtils.copy(inputStream, outputStream, 8192);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
116
src/main/java/net/artelnatif/nicko/mojang/MojangAPI.java
Normal file
116
src/main/java/net/artelnatif/nicko/mojang/MojangAPI.java
Normal file
|
@ -0,0 +1,116 @@
|
|||
package net.artelnatif.nicko.mojang;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URL;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class MojangAPI {
|
||||
public static final String URL_NAME = "https://api.mojang.com/users/profiles/minecraft/{name}";
|
||||
public static final String URL_SKIN = "https://sessionserver.mojang.com/session/minecraft/profile/{uuid}?unsigned=false";
|
||||
|
||||
private final Logger logger = Logger.getLogger("MojangAPI");
|
||||
|
||||
private final CacheLoader<String, Optional<MojangSkin>> loader = new CacheLoader<>() {
|
||||
@Nonnull
|
||||
public Optional<MojangSkin> load(@Nonnull String uuid) throws Exception {
|
||||
return getSkinFromMojang(uuid);
|
||||
}
|
||||
};
|
||||
|
||||
private final LoadingCache<String, Optional<MojangSkin>> cache = CacheBuilder
|
||||
.newBuilder()
|
||||
.recordStats()
|
||||
.expireAfterWrite(24, TimeUnit.HOURS)
|
||||
.build(loader);
|
||||
|
||||
public Optional<MojangSkin> getSkin(String uuid) throws IOException, ExecutionException {
|
||||
return cache.get(uuid);
|
||||
}
|
||||
|
||||
public Optional<MojangSkin> getSkinWithoutCaching(String uuid) throws IOException {
|
||||
return getSkinFromMojang(uuid);
|
||||
}
|
||||
|
||||
public Optional<String> getUUID(String name) throws IOException {
|
||||
final String parametrizedUrl = URL_NAME.replace("{name}", name);
|
||||
final JsonObject object = getRequestToUrl(parametrizedUrl);
|
||||
if (hasNoError(object)) {
|
||||
return Optional.of(object.get("id").getAsString());
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private Optional<MojangSkin> getSkinFromMojang(String uuid) throws IOException {
|
||||
final String parametrizedUrl = URL_SKIN.replace("{uuid}", uuid);
|
||||
final JsonObject object = getRequestToUrl(parametrizedUrl);
|
||||
if (hasNoError(object)) {
|
||||
final MojangSkin skin = MojangSkin.buildFromJson(object);
|
||||
return Optional.of(skin);
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private JsonObject getRequestToUrl(String parametrizedUrl) throws IOException {
|
||||
final URL url = new URL(parametrizedUrl);
|
||||
final HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
|
||||
con.setDoInput(true);
|
||||
con.setRequestMethod("GET");
|
||||
|
||||
switch (con.getResponseCode()) {
|
||||
case 400:
|
||||
logger.warning("Failed to parse request: Invalid Name");
|
||||
return getErrorObject();
|
||||
case 429:
|
||||
logger.warning("Failed to parse request: The connection is throttled.");
|
||||
return getErrorObject();
|
||||
case 200:
|
||||
final BufferedReader input = new BufferedReader(new InputStreamReader(con.getInputStream()));
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
String line;
|
||||
while ((line = input.readLine()) != null) {
|
||||
builder.append(line);
|
||||
}
|
||||
|
||||
try {
|
||||
final JsonElement jsonElt = JsonParser.parseString(builder.toString());
|
||||
return jsonElt.getAsJsonObject();
|
||||
} catch (JsonParseException | IllegalStateException exception) {
|
||||
logger.warning("Failed to parse request (" + parametrizedUrl + ")!");
|
||||
return getErrorObject();
|
||||
}
|
||||
default:
|
||||
logger.warning("Unhandled response code from Mojang: " + con.getResponseCode());
|
||||
return getErrorObject();
|
||||
}
|
||||
}
|
||||
|
||||
private JsonObject getErrorObject() {
|
||||
final JsonObject errorObject = new JsonObject();
|
||||
errorObject.addProperty("error", "An error occurred.");
|
||||
return errorObject;
|
||||
}
|
||||
|
||||
private boolean hasNoError(JsonObject object) {
|
||||
return object.get("error") == null;
|
||||
}
|
||||
|
||||
public LoadingCache<String, Optional<MojangSkin>> getCache() {
|
||||
return cache;
|
||||
}
|
||||
}
|
28
src/main/java/net/artelnatif/nicko/mojang/MojangSkin.java
Normal file
28
src/main/java/net/artelnatif/nicko/mojang/MojangSkin.java
Normal file
|
@ -0,0 +1,28 @@
|
|||
package net.artelnatif.nicko.mojang;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
public class MojangSkin {
|
||||
private final String value;
|
||||
private final String signature;
|
||||
|
||||
public MojangSkin(String value, String signature) {
|
||||
this.value = value;
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
public static MojangSkin buildFromJson(JsonObject object) {
|
||||
final JsonObject properties = object.get("properties").getAsJsonArray().get(0).getAsJsonObject();
|
||||
final String value = properties.get("value").getAsString();
|
||||
final String signature = properties.get("signature").getAsString();
|
||||
return new MojangSkin(value, signature);
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public String getSignature() {
|
||||
return signature;
|
||||
}
|
||||
}
|
26
src/main/java/net/artelnatif/nicko/mojang/MojangUtils.java
Normal file
26
src/main/java/net/artelnatif/nicko/mojang/MojangUtils.java
Normal file
|
@ -0,0 +1,26 @@
|
|||
package net.artelnatif.nicko.mojang;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class MojangUtils {
|
||||
public static boolean isUsernameInvalid(String username) {
|
||||
return !Pattern.matches("^\\w{3,16}$", username);
|
||||
}
|
||||
|
||||
public static UUID fromTrimmed(String trimmedUUID) throws IllegalArgumentException {
|
||||
if (trimmedUUID == null) throw new IllegalArgumentException();
|
||||
StringBuilder builder = new StringBuilder(trimmedUUID.trim());
|
||||
/* Backwards adding to avoid index adjustments */
|
||||
try {
|
||||
builder.insert(20, "-");
|
||||
builder.insert(16, "-");
|
||||
builder.insert(12, "-");
|
||||
builder.insert(8, "-");
|
||||
} catch (StringIndexOutOfBoundsException e) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
return UUID.fromString(builder.toString());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package net.artelnatif.nicko.placeholder;
|
||||
|
||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import net.artelnatif.nicko.disguise.NickoProfile;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class NickoExpansion extends PlaceholderExpansion {
|
||||
|
||||
private final NickoBukkit instance;
|
||||
|
||||
public NickoExpansion(NickoBukkit instance) {
|
||||
this.instance = instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getIdentifier() {
|
||||
return "nicko";
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getAuthor() {
|
||||
return "Aro";
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getVersion() {
|
||||
return "1.0.0";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean persist() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String onPlaceholderRequest(Player player, @NotNull String params) {
|
||||
if (player == null) return null;
|
||||
|
||||
String name, skin, locale;
|
||||
boolean bungeecord;
|
||||
|
||||
name = skin = player.getName();
|
||||
locale = "N/A";
|
||||
bungeecord = true;
|
||||
|
||||
final Optional<NickoProfile> optionalProfile = instance.getDataStore().getData(player.getUniqueId());
|
||||
if (optionalProfile.isPresent()) {
|
||||
final NickoProfile profile = optionalProfile.get();
|
||||
if (!profile.isEmpty()) {
|
||||
name = profile.getName();
|
||||
skin = profile.getSkin();
|
||||
}
|
||||
locale = profile.getLocale().getName();
|
||||
bungeecord = profile.isBungeecordTransfer();
|
||||
}
|
||||
|
||||
switch (params) {
|
||||
case "name": return name;
|
||||
case "skin": return skin;
|
||||
case "locale": return locale;
|
||||
case "bungeecord": return String.valueOf(bungeecord);
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package net.artelnatif.nicko.placeholder;
|
||||
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
public class PlaceHolderHook {
|
||||
private final NickoBukkit instance;
|
||||
|
||||
public PlaceHolderHook(NickoBukkit instance) {
|
||||
this.instance = instance;
|
||||
}
|
||||
|
||||
public void hook() {
|
||||
if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) {
|
||||
instance.getLogger().info("Enabling PlaceHolderAPI support...");
|
||||
new NickoExpansion(instance).register();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
package net.artelnatif.nicko.storage;
|
||||
|
||||
import net.artelnatif.nicko.config.Configuration;
|
||||
import net.artelnatif.nicko.disguise.ActionResult;
|
||||
import net.artelnatif.nicko.disguise.NickoProfile;
|
||||
import net.artelnatif.nicko.i18n.I18NDict;
|
||||
import net.artelnatif.nicko.mojang.MojangAPI;
|
||||
import net.artelnatif.nicko.mojang.MojangUtils;
|
||||
import net.artelnatif.nicko.storage.cache.Cache;
|
||||
import net.artelnatif.nicko.storage.cache.redis.RedisCache;
|
||||
import net.artelnatif.nicko.storage.json.JSONStorage;
|
||||
import net.artelnatif.nicko.storage.sql.SQLStorage;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PlayerDataStore {
|
||||
private final Storage storage;
|
||||
private final Cache cache;
|
||||
private final MojangAPI mojangAPI;
|
||||
private final HashMap<UUID, NickoProfile> profiles = new HashMap<>();
|
||||
|
||||
public PlayerDataStore(MojangAPI mojangAPI, Configuration configuration) {
|
||||
this.mojangAPI = mojangAPI;
|
||||
this.storage = configuration.isLocal() ? new JSONStorage() : new SQLStorage(configuration);
|
||||
this.cache = new RedisCache(); // The only option for now!
|
||||
}
|
||||
|
||||
public void performProfileUpdate(UUID uuid, NickoProfile profile) {
|
||||
if (!profiles.containsKey(uuid)) {
|
||||
profiles.put(uuid, profile);
|
||||
return;
|
||||
}
|
||||
|
||||
profiles.replace(uuid, profile);
|
||||
}
|
||||
|
||||
public Optional<NickoProfile> getData(UUID uuid) {
|
||||
if (storage.isError()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
if (profiles.containsKey(uuid)) {
|
||||
return Optional.of(profiles.get(uuid));
|
||||
} else if (storage.isStored(uuid)) {
|
||||
final Optional<NickoProfile> retrievedProfile = storage.retrieve(uuid);
|
||||
retrievedProfile.ifPresent(profile -> profiles.put(uuid, profile));
|
||||
return retrievedProfile;
|
||||
} else {
|
||||
final NickoProfile newProfile = NickoProfile.EMPTY_PROFILE.clone();
|
||||
profiles.put(uuid, newProfile);
|
||||
return Optional.of(newProfile);
|
||||
}
|
||||
}
|
||||
|
||||
public Optional<NickoProfile> getOfflineData(String name) {
|
||||
if (storage.isError()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
try {
|
||||
final Optional<String> uuidTrimmed = mojangAPI.getUUID(name);
|
||||
if (uuidTrimmed.isPresent()) {
|
||||
final UUID uuid = MojangUtils.fromTrimmed(uuidTrimmed.get());
|
||||
return getData(uuid);
|
||||
}
|
||||
return Optional.empty();
|
||||
} catch (IOException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
public ActionResult<Void> saveData(Player player) {
|
||||
if (storage.isError()) { return new ActionResult<>(I18NDict.Error.UNEXPECTED_ERROR); }
|
||||
if (!profiles.containsKey(player.getUniqueId())) { return new ActionResult<>(I18NDict.Error.UNEXPECTED_ERROR); }
|
||||
|
||||
final ActionResult<Void> store = storage.store(player.getUniqueId(), profiles.get(player.getUniqueId()));
|
||||
profiles.remove(player.getUniqueId());
|
||||
return store;
|
||||
}
|
||||
|
||||
public Storage getStorage() {
|
||||
return storage;
|
||||
}
|
||||
|
||||
public Cache getCache() {
|
||||
return cache;
|
||||
}
|
||||
}
|
27
src/main/java/net/artelnatif/nicko/storage/Storage.java
Normal file
27
src/main/java/net/artelnatif/nicko/storage/Storage.java
Normal file
|
@ -0,0 +1,27 @@
|
|||
package net.artelnatif.nicko.storage;
|
||||
|
||||
import net.artelnatif.nicko.disguise.ActionResult;
|
||||
import net.artelnatif.nicko.disguise.NickoProfile;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public abstract class Storage {
|
||||
private boolean error = false;
|
||||
|
||||
public abstract StorageProvider getProvider();
|
||||
|
||||
public abstract ActionResult<Void> store(UUID uuid, NickoProfile profile);
|
||||
|
||||
public abstract boolean isStored(UUID uuid);
|
||||
|
||||
public abstract Optional<NickoProfile> retrieve(UUID uuid);
|
||||
|
||||
public boolean isError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
public void setError(boolean error) {
|
||||
this.error = error;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package net.artelnatif.nicko.storage;
|
||||
|
||||
public interface StorageProvider {
|
||||
boolean init();
|
||||
|
||||
boolean close();
|
||||
}
|
27
src/main/java/net/artelnatif/nicko/storage/cache/Cache.java
vendored
Normal file
27
src/main/java/net/artelnatif/nicko/storage/cache/Cache.java
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
package net.artelnatif.nicko.storage.cache;
|
||||
|
||||
import net.artelnatif.nicko.disguise.ActionResult;
|
||||
import net.artelnatif.nicko.disguise.NickoProfile;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public abstract class Cache {
|
||||
private boolean error = false;
|
||||
|
||||
public abstract CacheProvider getProvider();
|
||||
|
||||
public abstract ActionResult<Void> cache(UUID uuid, NickoProfile profile);
|
||||
|
||||
public abstract boolean isCached(UUID uuid);
|
||||
|
||||
public abstract Optional<NickoProfile> retrieve(UUID uuid);
|
||||
|
||||
public boolean isError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
public void setError(boolean error) {
|
||||
this.error = error;
|
||||
}
|
||||
}
|
7
src/main/java/net/artelnatif/nicko/storage/cache/CacheProvider.java
vendored
Normal file
7
src/main/java/net/artelnatif/nicko/storage/cache/CacheProvider.java
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
package net.artelnatif.nicko.storage.cache;
|
||||
|
||||
public interface CacheProvider {
|
||||
boolean init();
|
||||
|
||||
boolean close();
|
||||
}
|
31
src/main/java/net/artelnatif/nicko/storage/cache/redis/RedisCache.java
vendored
Normal file
31
src/main/java/net/artelnatif/nicko/storage/cache/redis/RedisCache.java
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
package net.artelnatif.nicko.storage.cache.redis;
|
||||
|
||||
import net.artelnatif.nicko.disguise.ActionResult;
|
||||
import net.artelnatif.nicko.disguise.NickoProfile;
|
||||
import net.artelnatif.nicko.storage.cache.Cache;
|
||||
import net.artelnatif.nicko.storage.cache.CacheProvider;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public class RedisCache extends Cache {
|
||||
@Override
|
||||
public CacheProvider getProvider() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionResult<Void> cache(UUID uuid, NickoProfile profile) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCached(UUID uuid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<NickoProfile> retrieve(UUID uuid) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
26
src/main/java/net/artelnatif/nicko/storage/cache/redis/RedisCacheProvider.java
vendored
Normal file
26
src/main/java/net/artelnatif/nicko/storage/cache/redis/RedisCacheProvider.java
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
package net.artelnatif.nicko.storage.cache.redis;
|
||||
|
||||
import net.artelnatif.nicko.storage.cache.CacheProvider;
|
||||
import redis.clients.jedis.Jedis;
|
||||
import redis.clients.jedis.JedisPool;
|
||||
|
||||
public class RedisCacheProvider implements CacheProvider {
|
||||
private JedisPool pool;
|
||||
|
||||
@Override
|
||||
public boolean init() {
|
||||
// TODO: 3/12/23 Get port from configuration
|
||||
pool = new JedisPool("localhost", 6379);
|
||||
return !pool.isClosed() && pool.getResource() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean close() {
|
||||
pool.close();
|
||||
return pool.isClosed();
|
||||
}
|
||||
|
||||
public Jedis getJedis() {
|
||||
return pool.getResource();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
package net.artelnatif.nicko.storage.json;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import net.artelnatif.nicko.disguise.ActionResult;
|
||||
import net.artelnatif.nicko.disguise.NickoProfile;
|
||||
import net.artelnatif.nicko.i18n.I18NDict;
|
||||
import net.artelnatif.nicko.storage.Storage;
|
||||
import net.artelnatif.nicko.storage.StorageProvider;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class JSONStorage extends Storage {
|
||||
private final Logger logger = Logger.getLogger("JSONStorage");
|
||||
private final Gson gson = new GsonBuilder().serializeNulls().setPrettyPrinting().create();
|
||||
private final File directory = new File(NickoBukkit.getInstance().getDataFolder() + "/players/");
|
||||
|
||||
private JSONStorageProvider provider;
|
||||
|
||||
@Override
|
||||
public StorageProvider getProvider() {
|
||||
if (provider == null) {
|
||||
provider = new JSONStorageProvider(directory);
|
||||
}
|
||||
return provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionResult<Void> store(UUID uuid, NickoProfile profile) {
|
||||
final String profileToJson = gson.toJson(profile);
|
||||
final File file = new File(directory, uuid.toString() + ".json");
|
||||
|
||||
try {
|
||||
if (checkFileExists(file)) {
|
||||
try (FileWriter fileWriter = new FileWriter(file)) {
|
||||
try (BufferedWriter writer = new BufferedWriter(fileWriter)) {
|
||||
writer.write(profileToJson);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.warning("Could not write to file.");
|
||||
return new ActionResult<>(I18NDict.Error.JSON_ERROR);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.warning("Could not create file.");
|
||||
return new ActionResult<>(I18NDict.Error.JSON_ERROR);
|
||||
}
|
||||
|
||||
return new ActionResult<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStored(UUID uuid) {
|
||||
final File directory = new File(NickoBukkit.getInstance().getDataFolder() + "/players/");
|
||||
final File file = new File(directory, uuid.toString() + ".json");
|
||||
return file.exists();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<NickoProfile> retrieve(UUID uuid) {
|
||||
final File directory = new File(NickoBukkit.getInstance().getDataFolder() + "/players/");
|
||||
final File file = new File(directory, uuid.toString() + ".json");
|
||||
try (FileReader fileReader = new FileReader(file)) {
|
||||
try (BufferedReader reader = new BufferedReader(fileReader)) {
|
||||
final NickoProfile value = gson.fromJson(reader, NickoProfile.class);
|
||||
return Optional.of(value);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkFileExists(File file) throws IOException {
|
||||
if (!file.exists()) {
|
||||
return file.createNewFile();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package net.artelnatif.nicko.storage.json;
|
||||
|
||||
import net.artelnatif.nicko.storage.StorageProvider;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class JSONStorageProvider implements StorageProvider {
|
||||
private final File directory;
|
||||
|
||||
public JSONStorageProvider(File directory) {
|
||||
this.directory = directory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean init()
|
||||
{
|
||||
return directory.exists() || directory.mkdirs();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean close() { return true; }
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package net.artelnatif.nicko.storage.name;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PlayerNameStore {
|
||||
private final HashMap<UUID, String> names = new HashMap<>();
|
||||
|
||||
public void storeName(Player player) {
|
||||
if (!isNameStored(player)) {
|
||||
names.put(player.getUniqueId(), player.getName());
|
||||
}
|
||||
}
|
||||
|
||||
public String getStoredName(Player player) {
|
||||
return names.get(player.getUniqueId());
|
||||
}
|
||||
|
||||
private boolean isNameStored(Player player) {
|
||||
return names.containsKey(player.getUniqueId());
|
||||
}
|
||||
|
||||
public void clearStoredNames() {
|
||||
names.clear();
|
||||
}
|
||||
}
|
133
src/main/java/net/artelnatif/nicko/storage/sql/SQLStorage.java
Normal file
133
src/main/java/net/artelnatif/nicko/storage/sql/SQLStorage.java
Normal file
|
@ -0,0 +1,133 @@
|
|||
package net.artelnatif.nicko.storage.sql;
|
||||
|
||||
import net.artelnatif.nicko.config.Configuration;
|
||||
import net.artelnatif.nicko.disguise.ActionResult;
|
||||
import net.artelnatif.nicko.disguise.NickoProfile;
|
||||
import net.artelnatif.nicko.i18n.I18NDict;
|
||||
import net.artelnatif.nicko.i18n.Locale;
|
||||
import net.artelnatif.nicko.storage.Storage;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class SQLStorage extends Storage {
|
||||
private final Logger logger = Logger.getLogger("SQLStorage");
|
||||
private final Configuration configuration;
|
||||
|
||||
private SQLStorageProvider provider;
|
||||
|
||||
public SQLStorage(Configuration configuration) {
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SQLStorageProvider getProvider() {
|
||||
if (provider == null) {
|
||||
provider = new SQLStorageProvider(configuration);
|
||||
}
|
||||
return provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionResult<Void> store(UUID uuid, NickoProfile profile) {
|
||||
final Connection connection = getProvider().getConnection();
|
||||
if (connection == null) return new ActionResult<>(I18NDict.Error.SQL_ERROR);
|
||||
|
||||
try {
|
||||
final PreparedStatement statement = isStored(uuid) ?
|
||||
getUpdateStatement(connection, uuid, profile) : getInsertStatement(connection, uuid, profile);
|
||||
statement.executeUpdate();
|
||||
return new ActionResult<>();
|
||||
} catch (SQLException e) {
|
||||
logger.warning("Couldn't send SQL Request: " + e.getMessage());
|
||||
return new ActionResult<>(I18NDict.Error.SQL_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStored(UUID uuid) {
|
||||
final Connection connection = getProvider().getConnection();
|
||||
if (connection == null) return false;
|
||||
|
||||
try {
|
||||
final String sql = "SELECT * FROM nicko.DATA WHERE uuid = ?";
|
||||
|
||||
final PreparedStatement statement = connection.prepareStatement(sql);
|
||||
statement.setBinaryStream(1, uuidToBin(uuid));
|
||||
|
||||
final ResultSet resultSet = statement.executeQuery();
|
||||
return resultSet.next();
|
||||
} catch (SQLException e) {
|
||||
logger.warning("Couldn't check if data is present: " + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<NickoProfile> retrieve(UUID uuid) {
|
||||
final Connection connection = getProvider().getConnection();
|
||||
if (connection == null) return Optional.empty();
|
||||
|
||||
try {
|
||||
final String sql = "SELECT * FROM nicko.DATA WHERE uuid = ?";
|
||||
|
||||
final PreparedStatement statement = connection.prepareStatement(sql);
|
||||
statement.setBinaryStream(1, uuidToBin(uuid));
|
||||
|
||||
final ResultSet resultSet = statement.executeQuery();
|
||||
String name = "";
|
||||
String skin = "";
|
||||
String locale = "";
|
||||
boolean bungeecord = false;
|
||||
while (resultSet.next()) {
|
||||
name = resultSet.getString("name");
|
||||
skin = resultSet.getString("skin");
|
||||
locale = resultSet.getString("locale");
|
||||
bungeecord = resultSet.getBoolean("bungeecord");
|
||||
}
|
||||
|
||||
final NickoProfile profile = new NickoProfile(name, skin, Locale.fromCode(locale), bungeecord);
|
||||
return Optional.of(profile);
|
||||
} catch (SQLException e) {
|
||||
logger.warning("Couldn't fetch profile: " + e.getMessage());
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
private PreparedStatement getInsertStatement(Connection connection, UUID uuid, NickoProfile profile) throws SQLException {
|
||||
final String sql = "INSERT IGNORE INTO nicko.DATA (`uuid`, `name`, `skin`, `locale`, `bungeecord`) VALUES (?, ?, ?, ?, ?)";
|
||||
final PreparedStatement statement = connection.prepareStatement(sql);
|
||||
statement.setBinaryStream(1, uuidToBin(uuid));
|
||||
statement.setString(2, profile.getName() == null ? null : profile.getName());
|
||||
statement.setString(3, profile.getSkin() == null ? null : profile.getSkin());
|
||||
statement.setString(4, profile.getLocale().getCode());
|
||||
statement.setBoolean(5, profile.isBungeecordTransfer());
|
||||
return statement;
|
||||
}
|
||||
|
||||
private PreparedStatement getUpdateStatement(Connection connection, UUID uuid, NickoProfile profile) throws SQLException {
|
||||
final String sql = "UPDATE nicko.DATA SET name = ?, skin = ?, locale = ?, bungeecord = ? WHERE uuid = ?";
|
||||
final PreparedStatement statement = connection.prepareStatement(sql);
|
||||
statement.setString(1, profile.getName() == null ? null : profile.getName());
|
||||
statement.setString(2, profile.getSkin() == null ? null : profile.getSkin());
|
||||
statement.setString(3, profile.getLocale().getCode());
|
||||
statement.setBoolean(4, profile.isBungeecordTransfer());
|
||||
statement.setBinaryStream(5, uuidToBin(uuid));
|
||||
return statement;
|
||||
}
|
||||
|
||||
private ByteArrayInputStream uuidToBin(UUID uuid) {
|
||||
byte[] bytes = new byte[16];
|
||||
ByteBuffer.wrap(bytes)
|
||||
.putLong(uuid.getMostSignificantBits())
|
||||
.putLong(uuid.getLeastSignificantBits());
|
||||
return new ByteArrayInputStream(bytes);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
package net.artelnatif.nicko.storage.sql;
|
||||
|
||||
import net.artelnatif.nicko.config.Configuration;
|
||||
import net.artelnatif.nicko.config.DataSourceConfiguration;
|
||||
import net.artelnatif.nicko.storage.StorageProvider;
|
||||
import org.mariadb.jdbc.MariaDbDataSource;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class SQLStorageProvider implements StorageProvider {
|
||||
private final Logger logger = Logger.getLogger("SQLStorageProvider");
|
||||
private final Configuration configuration;
|
||||
|
||||
private Connection connection;
|
||||
|
||||
private final String schemaName = "nicko";
|
||||
|
||||
public SQLStorageProvider(Configuration configuration) {
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean init() {
|
||||
try {
|
||||
final MariaDbDataSource dataSource = new MariaDbDataSource();
|
||||
final DataSourceConfiguration dataSourceConfiguration = configuration.getSqlConfiguration();
|
||||
dataSource.setUrl("jdbc:mariadb://" + dataSourceConfiguration.getAddress() + ":" + dataSourceConfiguration.getPort());
|
||||
dataSource.setUser(dataSourceConfiguration.getUsername());
|
||||
dataSource.setPassword(dataSourceConfiguration.getPassword());
|
||||
connection = dataSource.getConnection();
|
||||
final boolean initialized = connection != null && !connection.isClosed();
|
||||
|
||||
if (!initialized) return false;
|
||||
|
||||
createDatabase();
|
||||
createTable();
|
||||
return true;
|
||||
} catch (SQLException e) {
|
||||
logger.severe("Couldn't establish a connection to the MySQL database: " + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean close() {
|
||||
if (connection == null) { return true; }
|
||||
try {
|
||||
connection.close();
|
||||
return connection.isClosed();
|
||||
} catch (SQLException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void createTable() throws SQLException {
|
||||
final Connection connection = getConnection();
|
||||
|
||||
String query = "CREATE TABLE IF NOT EXISTS %s.DATA " +
|
||||
"(uuid binary(16) NOT NULL," +
|
||||
"name varchar(16)," +
|
||||
"skin varchar(16)," +
|
||||
"locale char(2) NOT NULL," +
|
||||
"bungeecord boolean NOT NULL," +
|
||||
"PRIMARY KEY (UUID))";
|
||||
query = query.replace("%s", schemaName);
|
||||
|
||||
final PreparedStatement statement = connection.prepareStatement(query);
|
||||
statement.executeUpdate();
|
||||
statement.close();
|
||||
}
|
||||
|
||||
private void createDatabase() throws SQLException {
|
||||
final Connection connection = getConnection();
|
||||
|
||||
String query = "CREATE DATABASE IF NOT EXISTS %s";
|
||||
query = query.replace("%s", schemaName);
|
||||
|
||||
final PreparedStatement statement = connection.prepareStatement(query);
|
||||
statement.executeUpdate();
|
||||
statement.close();
|
||||
}
|
||||
|
||||
public Connection getConnection() {
|
||||
return connection;
|
||||
}
|
||||
}
|
59
src/main/resources/config.yml
Normal file
59
src/main/resources/config.yml
Normal file
|
@ -0,0 +1,59 @@
|
|||
# Nicko ${project.version} - Config:
|
||||
|
||||
###########
|
||||
# STORAGE #
|
||||
###########
|
||||
|
||||
# Indicates wherever the data will be stored
|
||||
# locally through a .json file or a (My)SQL database.
|
||||
# Accepted values: false (Disabled), true (Enabled)
|
||||
local: true
|
||||
|
||||
# This configuration section manages SQL.
|
||||
sql:
|
||||
# SQL database's address
|
||||
# Accepted values: valid IP address (e.g. localhost, 127.0.0.1)
|
||||
address: "localhost"
|
||||
# SQL database's port
|
||||
# Accepted values: valid integer (e.g. 3306, 25565)
|
||||
port: 3306
|
||||
# SQL database's username.
|
||||
# Accepted values: any string
|
||||
username: "username"
|
||||
# SQL database's password.
|
||||
# Accepted values: any string
|
||||
password: "password"
|
||||
|
||||
# This configuration section manages Redis (BungeeCord support).
|
||||
# It is used to transfer data between multiple servers.
|
||||
redis:
|
||||
# Indicates wherever the data will be stored through
|
||||
# Redis to transfer whenever a player switches server.
|
||||
# Accepted values: false (Disabled), true (Enabled)
|
||||
enabled: false
|
||||
# Redis server's address
|
||||
# Accepted values: valid IP address (e.g. localhost, 127.0.0.1)
|
||||
address: "localhost"
|
||||
# Redis server's port
|
||||
# Accepted values: valid integer (e.g. 3306, 25565)
|
||||
port: 6379
|
||||
# Redis server's username
|
||||
# Accepted values: any string
|
||||
username: "username"
|
||||
# Redis server's password
|
||||
# Accepted values: any string
|
||||
password: "password"
|
||||
|
||||
###########
|
||||
# DISPLAY #
|
||||
###########
|
||||
|
||||
# Nicko's messages prefix.
|
||||
# Accepted values: any string
|
||||
prefix: "§6Nicko §8§l| §r"
|
||||
|
||||
# Nicko will copy the English locale as "lang.yml"
|
||||
# and will use the translations in that file when "Server Custom"
|
||||
# is selected as the player's locale.
|
||||
# Accepted values: false (Disabled), true (Enabled)
|
||||
customLocale: false
|
22
src/main/resources/en.yml
Normal file
22
src/main/resources/en.yml
Normal file
|
@ -0,0 +1,22 @@
|
|||
error:
|
||||
couldnt_get_name_from_mojang: "Failed to get username from Mojang"
|
||||
couldnt_get_skin_from_cache: "Failed to get skin from cache"
|
||||
couldnt_get_skin_from_mojang: "Failed to get skin from Mojang"
|
||||
generic: "Unknown error"
|
||||
invalid_username: "§cThe specified username is not a valid Minecraft username."
|
||||
player_offline: "§c{0} §fis offline, please try again."
|
||||
sql: "SQL Error"
|
||||
json: "JSON Error"
|
||||
event:
|
||||
admin:
|
||||
cache_clear: "§aSkin cache cleaned."
|
||||
disguise:
|
||||
fail: "§cUnable to apply your disguise. §7§o({0})"
|
||||
success: "§aDisguise applied!"
|
||||
previous_skin_applied:
|
||||
fail: "§cFailed to apply your previous disguise back. §7§o({0})"
|
||||
success: "§aYour previous active disguise has been applied back."
|
||||
undisguise:
|
||||
fail: "§cUnable to remove your disguise. It will be set back to default on your next login. Sorry!"
|
||||
none: "§cYou do not have an active disguise."
|
||||
success: "§aDisguise removed."
|
22
src/main/resources/fr.yml
Normal file
22
src/main/resources/fr.yml
Normal file
|
@ -0,0 +1,22 @@
|
|||
error:
|
||||
couldnt_get_name_from_mojang: "Impossible de récupérer le nom d''utilisateur depuis Mojang"
|
||||
couldnt_get_skin_from_cache: "Impossible de récupérer le skin depuis le cache"
|
||||
couldnt_get_skin_from_mojang: "Impossible de récupérer le skin depuis Mojang"
|
||||
generic: "Erreur inconnue"
|
||||
invalid_username: "§cLe pseudo spécifié n''est pas un pseudo Minecraft valide."
|
||||
player_offline: "§c{0} §fest hors-ligne, veuillez réessayer."
|
||||
sql: "Erreur SQL"
|
||||
json: "Erreur JSON"
|
||||
event:
|
||||
admin:
|
||||
cache_clear: "§aCache des skins nettoyé."
|
||||
disguise:
|
||||
fail: "§cImpossible d''appliquer votre déguisement. §7§o({0})"
|
||||
success: "§aDéguisement appliqué !"
|
||||
previous_skin_applied:
|
||||
fail: "§cImpossible d''appliquer votre déguisement précédent. §7§o({0})"
|
||||
success: "§aVotre précédent déguisement a été réappliqué."
|
||||
undisguise:
|
||||
fail: "§cImpossible de retier votre déguisement. Il sera remis par défaut à votre prochaine reconnexion. Désolé !"
|
||||
none: "§cVous n''avez pas de déguisement."
|
||||
success: "§aDéguisement retiré."
|
18
src/main/resources/plugin.yml
Normal file
18
src/main/resources/plugin.yml
Normal file
|
@ -0,0 +1,18 @@
|
|||
name: Nicko
|
||||
main: net.artelnatif.nicko.NickoBukkit
|
||||
version: 1.0-SNAPSHOT
|
||||
author: Ineanto
|
||||
api-version: 1.13
|
||||
softdepend: [ PlaceholderAPI ]
|
||||
depend: [ ProtocolLib ]
|
||||
commands:
|
||||
nicko:
|
||||
description: "Opens Nicko's GUI."
|
||||
permission: nicko.admin
|
||||
permissions:
|
||||
nicko.*:
|
||||
default: op
|
||||
children:
|
||||
- nicko.use
|
||||
nicko.use:
|
||||
default: op
|
Loading…
Add table
Add a link
Reference in a new issue