Merge branch 'develop' into team_gui
This commit is contained in:
commit
37de29b5f6
2
pom.xml
2
pom.xml
|
@ -73,7 +73,7 @@
|
|||
<postgresql.version>42.2.18</postgresql.version>
|
||||
<hikaricp.version>5.0.1</hikaricp.version>
|
||||
<!-- More visible way to change dependency versions -->
|
||||
<spigot.version>1.20.4-R0.1-SNAPSHOT</spigot.version>
|
||||
<spigot.version>1.20.3-R0.1-SNAPSHOT</spigot.version>
|
||||
<!-- Might differ from the last Spigot release for short periods
|
||||
of time -->
|
||||
<paper.version>1.20.2-R0.1-SNAPSHOT</paper.version>
|
||||
|
|
|
@ -463,6 +463,10 @@ public class BentoBox extends JavaPlugin implements Listener {
|
|||
getPluginLoader().disablePlugin(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
log("Saving default panels...");
|
||||
this.saveResource("panels/island_creation_panel.yml", false);
|
||||
this.saveResource("panels/language_panel.yml", false);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import java.util.Optional;
|
|||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Server;
|
||||
|
@ -263,7 +264,7 @@ public abstract class Addon {
|
|||
throw new IllegalArgumentException("ResourcePath cannot be null or empty");
|
||||
}
|
||||
|
||||
jarResource = jarResource.replace("\\", File.separator).replace("/", File.separator);
|
||||
jarResource = jarResource.replace('\\', '/');
|
||||
try (JarFile jar = new JarFile(file)) {
|
||||
JarEntry jarConfig = jar.getJarEntry(jarResource);
|
||||
if (jarConfig != null) {
|
||||
|
@ -273,7 +274,9 @@ public abstract class Addon {
|
|||
"The embedded resource '" + jarResource + "' cannot be found in " + jar.getName());
|
||||
}
|
||||
// There are two options, use the path of the resource or not
|
||||
File outFile = new File(destinationFolder, jarResource);
|
||||
File outFile = new File(destinationFolder,
|
||||
jarResource.replaceAll("/", Matcher.quoteReplacement(File.separator)));
|
||||
|
||||
if (noPath) {
|
||||
outFile = new File(destinationFolder, outFile.getName());
|
||||
}
|
||||
|
@ -308,7 +311,7 @@ public abstract class Addon {
|
|||
throw new IllegalArgumentException("jarResource cannot be null or empty");
|
||||
}
|
||||
YamlConfiguration result = new YamlConfiguration();
|
||||
jarResource = jarResource.replace("\\", File.separator).replace("/", File.separator);
|
||||
jarResource = jarResource.replace('\\', '/');
|
||||
try (JarFile jar = new JarFile(file)) {
|
||||
JarEntry jarConfig = jar.getJarEntry(jarResource);
|
||||
if (jarConfig != null) {
|
||||
|
@ -330,7 +333,7 @@ public abstract class Addon {
|
|||
throw new IllegalArgumentException("ResourcePath cannot be null or empty");
|
||||
}
|
||||
|
||||
jarResource = jarResource.replace("\\", File.separator).replace("/", File.separator);
|
||||
jarResource = jarResource.replace('\\', '/');
|
||||
try (JarFile jar = new JarFile(file)) {
|
||||
JarEntry jarConfig = jar.getJarEntry(jarResource);
|
||||
if (jarConfig != null) {
|
||||
|
|
|
@ -12,7 +12,7 @@ import world.bentobox.bentobox.api.user.User;
|
|||
import world.bentobox.bentobox.database.objects.Island;
|
||||
import world.bentobox.bentobox.managers.BlueprintsManager;
|
||||
import world.bentobox.bentobox.managers.island.NewIsland;
|
||||
import world.bentobox.bentobox.panels.IslandCreationPanel;
|
||||
import world.bentobox.bentobox.panels.customizable.IslandCreationPanel;
|
||||
import world.bentobox.bentobox.util.Util;
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,7 +7,7 @@ import java.util.Optional;
|
|||
|
||||
import world.bentobox.bentobox.api.commands.CompositeCommand;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.panels.LanguagePanel;
|
||||
import world.bentobox.bentobox.panels.customizable.LanguagePanel;
|
||||
import world.bentobox.bentobox.util.Util;
|
||||
|
||||
/**
|
||||
|
@ -46,7 +46,7 @@ public class IslandLanguageCommand extends CompositeCommand {
|
|||
return false;
|
||||
}
|
||||
} else {
|
||||
LanguagePanel.openPanel(user);
|
||||
LanguagePanel.openPanel(this, user);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ import world.bentobox.bentobox.database.objects.Island;
|
|||
import world.bentobox.bentobox.managers.BlueprintsManager;
|
||||
import world.bentobox.bentobox.managers.island.NewIsland;
|
||||
import world.bentobox.bentobox.managers.island.NewIsland.Builder;
|
||||
import world.bentobox.bentobox.panels.IslandCreationPanel;
|
||||
import world.bentobox.bentobox.panels.customizable.IslandCreationPanel;
|
||||
import world.bentobox.bentobox.util.Util;
|
||||
|
||||
/**
|
||||
|
|
|
@ -3,6 +3,7 @@ package world.bentobox.bentobox.database.json;
|
|||
import java.util.Map;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.configuration.serialization.ConfigurationSerializable;
|
||||
|
@ -23,6 +24,7 @@ import world.bentobox.bentobox.database.json.adapters.EnumTypeAdapter;
|
|||
import world.bentobox.bentobox.database.json.adapters.FlagTypeAdapter;
|
||||
import world.bentobox.bentobox.database.json.adapters.ItemStackTypeAdapter;
|
||||
import world.bentobox.bentobox.database.json.adapters.LocationTypeAdapter;
|
||||
import world.bentobox.bentobox.database.json.adapters.MaterialTypeAdapter;
|
||||
import world.bentobox.bentobox.database.json.adapters.PotionEffectTypeAdapter;
|
||||
import world.bentobox.bentobox.database.json.adapters.VectorTypeAdapter;
|
||||
import world.bentobox.bentobox.database.json.adapters.WorldTypeAdapter;
|
||||
|
@ -55,6 +57,8 @@ public class BentoboxTypeAdapterFactory implements TypeAdapterFactory {
|
|||
if (Location.class.isAssignableFrom(rawType)) {
|
||||
// Use our current location adapter for backward compatibility
|
||||
return (TypeAdapter<T>) new LocationTypeAdapter();
|
||||
} else if (Material.class.isAssignableFrom(rawType)) {
|
||||
return (TypeAdapter<T>) new MaterialTypeAdapter();
|
||||
} else if (Biome.class.isAssignableFrom(rawType)) {
|
||||
return (TypeAdapter<T>) new BiomeTypeAdapter();
|
||||
} else if (Enum.class.isAssignableFrom(rawType)) {
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
package world.bentobox.bentobox.database.json.adapters;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.Material;
|
||||
|
||||
import com.google.gson.TypeAdapter;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonToken;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
|
||||
/**
|
||||
* Minecraft 1.20 changed GRASS to SHORT_GRASS. This class provides and backwards compatibility when loading
|
||||
* databased files stored with previous versions. It can be extended in the future if further enum changes are made.
|
||||
* @author tastybento
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public final class MaterialTypeAdapter extends TypeAdapter<Material>
|
||||
{
|
||||
/**
|
||||
* Map that contains string value to the actual Material enum object.
|
||||
*/
|
||||
final Map<String, Material> materialMap;
|
||||
|
||||
public MaterialTypeAdapter() {
|
||||
this.materialMap = new HashMap<>();
|
||||
|
||||
// Put in current values.
|
||||
Arrays.stream(Material.values()).forEach(mat -> this.materialMap.put(mat.name(), mat));
|
||||
|
||||
// Put in renamed material values.
|
||||
this.materialMap.put("GRASS", Material.SHORT_GRASS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Material read(JsonReader input) throws IOException
|
||||
{
|
||||
if (JsonToken.NULL.equals(input.peek())) {
|
||||
input.nextNull();
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.materialMap.get(input.nextString().toUpperCase());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(JsonWriter output, Material enumValue) throws IOException {
|
||||
output.value(enumValue != null ? enumValue.name() : null);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,91 +0,0 @@
|
|||
package world.bentobox.bentobox.panels;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.api.commands.CompositeCommand;
|
||||
import world.bentobox.bentobox.api.panels.PanelItem;
|
||||
import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
|
||||
import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintBundle;
|
||||
import world.bentobox.bentobox.managers.BlueprintsManager;
|
||||
import world.bentobox.bentobox.util.Util;
|
||||
|
||||
|
||||
/**
|
||||
* Displays the available BlueprintBundles to pick up as the island.
|
||||
* @author tastybento
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public class IslandCreationPanel {
|
||||
|
||||
private IslandCreationPanel() {}
|
||||
|
||||
/**
|
||||
* Shows a player a panel of selectable blueprint bundles. Checks user's permission
|
||||
* @param command - the command requesting the panel, e.g., create or reset
|
||||
* @param user - the user
|
||||
* @param label - label
|
||||
*/
|
||||
public static void openPanel(@NonNull CompositeCommand command, @NonNull User user, @NonNull String label) {
|
||||
BentoBox plugin = BentoBox.getInstance();
|
||||
// Create the panel
|
||||
PanelBuilder pb = new PanelBuilder().name(user.getTranslation("commands.island.create.pick")).user(user);
|
||||
// Get the bundles
|
||||
Comparator<BlueprintBundle> sortByDisplayName = (p, o) -> p.getDisplayName().compareToIgnoreCase(o.getDisplayName());
|
||||
List<BlueprintBundle> bbs = plugin.getBlueprintsManager().getBlueprintBundles(command.getAddon()).values()
|
||||
.stream().sorted(sortByDisplayName).toList();
|
||||
// Loop through them and create items in the panel
|
||||
for (BlueprintBundle bb : bbs) {
|
||||
String perm = command.getPermissionPrefix() + "island.create." + bb.getUniqueId();
|
||||
if (bb.getUniqueId().equals(BlueprintsManager.DEFAULT_BUNDLE_NAME)
|
||||
|| !bb.isRequirePermission()
|
||||
|| user.hasPermission(perm)) {
|
||||
// Add an item
|
||||
PanelItem item = new PanelItemBuilder()
|
||||
.name(bb.getDisplayName())
|
||||
.description(bb.getDescription().stream().map(Util::translateColorCodes).toList())
|
||||
.icon(bb.getIcon()).clickHandler((panel, user1, clickType, slot1) -> {
|
||||
user1.closeInventory();
|
||||
command.execute(user1, label, Collections.singletonList(bb.getUniqueId()));
|
||||
return true;
|
||||
}).build();
|
||||
// Determine slot
|
||||
if (bb.getSlot() < 0 || bb.getSlot() > BlueprintManagementPanel.MAX_BP_SLOT) {
|
||||
bb.setSlot(0);
|
||||
}
|
||||
if (pb.slotOccupied(bb.getSlot())) {
|
||||
int slot = getFirstAvailableSlot(pb);
|
||||
if (slot == -1) {
|
||||
// TODO add paging
|
||||
plugin.logError("Too many blueprint bundles to show!");
|
||||
pb.item(item);
|
||||
} else {
|
||||
pb.item(slot, item);
|
||||
}
|
||||
} else {
|
||||
pb.item(bb.getSlot(), item);
|
||||
}
|
||||
}
|
||||
}
|
||||
pb.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param pb - panel builder
|
||||
* @return first available slot, or -1 if none
|
||||
*/
|
||||
private static int getFirstAvailableSlot(PanelBuilder pb) {
|
||||
for (int i = 0; i < BlueprintManagementPanel.MAX_BP_SLOT; i++) {
|
||||
if (!pb.slotOccupied(i)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
package world.bentobox.bentobox.panels;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.apache.commons.lang.WordUtils;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.api.localization.BentoBoxLocale;
|
||||
import world.bentobox.bentobox.api.localization.TextVariables;
|
||||
import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
|
||||
import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.managers.LocalesManager;
|
||||
|
||||
/**
|
||||
* @author Poslovitch
|
||||
*/
|
||||
public class LanguagePanel {
|
||||
|
||||
private LanguagePanel() {}
|
||||
|
||||
/**
|
||||
* Dynamically creates the panel.
|
||||
* @param user the User to show the panel to
|
||||
*/
|
||||
public static void openPanel(User user) {
|
||||
PanelBuilder panelBuilder = new PanelBuilder()
|
||||
.name(user.getTranslation("language.panel-title"));
|
||||
|
||||
LocalesManager localesManager = BentoBox.getInstance().getLocalesManager();
|
||||
|
||||
for (Locale locale : localesManager.getAvailableLocales(true)) {
|
||||
PanelItemBuilder localeIcon = new PanelItemBuilder();
|
||||
|
||||
BentoBoxLocale language = localesManager.getLanguages().get(locale);
|
||||
|
||||
ItemStack localeBanner = language.getBanner();
|
||||
// Set to a blank banner.
|
||||
localeIcon.icon(Objects.requireNonNullElseGet(localeBanner, () -> new ItemStack(Material.WHITE_BANNER, 1)));
|
||||
localeIcon.name(ChatColor.WHITE + WordUtils.capitalize(locale.getDisplayName(user.getLocale())))
|
||||
.clickHandler((panel, u, click, slot) -> {
|
||||
BentoBox.getInstance().getPlayers().setLocale(u.getUniqueId(), locale.toLanguageTag());
|
||||
u.sendMessage("language.edited", "[lang]", WordUtils.capitalize(locale.getDisplayName(user.getLocale())));
|
||||
openPanel(u);
|
||||
return true;
|
||||
});
|
||||
if (user.getLocale().equals(locale)) {
|
||||
localeIcon.description(user.getTranslation("language.description.selected"), "");
|
||||
} else {
|
||||
localeIcon.description(user.getTranslation("language.description.click-to-select"), "");
|
||||
}
|
||||
|
||||
localeIcon.description(user.getTranslation("language.description.authors"));
|
||||
for (String author : language.getAuthors()) {
|
||||
localeIcon.description(user.getTranslation("language.description.author", TextVariables.NAME, author));
|
||||
}
|
||||
|
||||
panelBuilder.item(localeIcon.build());
|
||||
}
|
||||
|
||||
panelBuilder.build().open(user);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,544 @@
|
|||
//
|
||||
// Created by BONNe
|
||||
// Copyright - 2023
|
||||
//
|
||||
|
||||
|
||||
package world.bentobox.bentobox.panels.customizable;
|
||||
|
||||
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.api.addons.GameModeAddon;
|
||||
import world.bentobox.bentobox.api.commands.CompositeCommand;
|
||||
import world.bentobox.bentobox.api.localization.TextVariables;
|
||||
import world.bentobox.bentobox.api.panels.PanelItem;
|
||||
import world.bentobox.bentobox.api.panels.TemplatedPanel;
|
||||
import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
|
||||
import world.bentobox.bentobox.api.panels.builders.TemplatedPanelBuilder;
|
||||
import world.bentobox.bentobox.api.panels.reader.ItemTemplateRecord;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.blueprints.dataobjects.BlueprintBundle;
|
||||
import world.bentobox.bentobox.util.Util;
|
||||
|
||||
|
||||
/**
|
||||
* This class generates Island Creation Panel based on user specified file with name: "island_creation_panel.yml".
|
||||
* If file with such name is located at gamemode panels directory, then that file will be used.
|
||||
* Otherwise, file in BentoBox/panels is used.
|
||||
*/
|
||||
public class IslandCreationPanel
|
||||
{
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Constructor
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* This is internal constructor. It is used internally in current class to avoid creating objects everywhere.
|
||||
*
|
||||
* @param command CompositeCommand object
|
||||
* @param label The main command label
|
||||
* @param user User who opens panel
|
||||
*/
|
||||
private IslandCreationPanel(@NonNull CompositeCommand command,
|
||||
@NonNull User user,
|
||||
@NonNull String label)
|
||||
{
|
||||
this.plugin = BentoBox.getInstance();
|
||||
this.user = user;
|
||||
this.mainLabel = label;
|
||||
|
||||
this.elementList = this.plugin.getBlueprintsManager().getBlueprintBundles(command.getAddon()).values().stream().
|
||||
sorted(Comparator.comparingInt(BlueprintBundle::getSlot).thenComparing(BlueprintBundle::getUniqueId)).
|
||||
filter(bundle -> !bundle.isRequirePermission() ||
|
||||
this.user.hasPermission(command.getPermissionPrefix() + "island.create." + bundle.getUniqueId())).
|
||||
toList();
|
||||
|
||||
this.mainCommand = command;
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Methods
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* Build method manages current panel opening. It uses BentoBox PanelAPI that is easy to use and users can get nice
|
||||
* panels.
|
||||
*/
|
||||
private void build()
|
||||
{
|
||||
// Do not open gui if there is no magic sticks.
|
||||
if (this.elementList.isEmpty())
|
||||
{
|
||||
this.plugin.logError("There are no available phases for selection!");
|
||||
this.user.sendMessage("no-phases",
|
||||
TextVariables.GAMEMODE, this.plugin.getDescription().getName());
|
||||
return;
|
||||
}
|
||||
|
||||
// Start building panel.
|
||||
TemplatedPanelBuilder panelBuilder = new TemplatedPanelBuilder();
|
||||
|
||||
// Set main template.
|
||||
if (this.doesCustomPanelExists(this.mainCommand.getAddon(), "island_creation_panel"))
|
||||
{
|
||||
// Addon has its own island creation panel. Use it.
|
||||
panelBuilder.template("island_creation_panel", new File(this.mainCommand.getAddon().getDataFolder(), "panels"));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use default island creation panel.
|
||||
panelBuilder.template("island_creation_panel", new File(this.plugin.getDataFolder(), "panels"));
|
||||
}
|
||||
|
||||
panelBuilder.user(this.user);
|
||||
panelBuilder.world(this.user.getWorld());
|
||||
|
||||
// Register button builders
|
||||
panelBuilder.registerTypeBuilder(BUNDLES, this::createBundleButton);
|
||||
|
||||
// Register next and previous builders
|
||||
panelBuilder.registerTypeBuilder(NEXT, this::createNextButton);
|
||||
panelBuilder.registerTypeBuilder(PREVIOUS, this::createPreviousButton);
|
||||
|
||||
// Register unknown type builder.
|
||||
panelBuilder.build();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method returns if panel with the requested name is located in GameModeAddon folder.
|
||||
* @param addon GameModeAddon that need to be checked.
|
||||
* @param name Name of the panel.
|
||||
* @return {@code true} if panel exists, {@code false} otherwise.
|
||||
*/
|
||||
private boolean doesCustomPanelExists(GameModeAddon addon, String name)
|
||||
{
|
||||
return addon.getDataFolder().exists() &&
|
||||
new File(addon.getDataFolder(), "panels").exists() &&
|
||||
new File(addon.getDataFolder(), "panels" + File.separator + name + ".yml").exists();
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Buttons
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* Create next button panel item.
|
||||
*
|
||||
* @param template the template
|
||||
* @param slot the slot
|
||||
* @return the panel item
|
||||
*/
|
||||
@Nullable
|
||||
private PanelItem createNextButton(@NonNull ItemTemplateRecord template, TemplatedPanel.ItemSlot slot)
|
||||
{
|
||||
int size = this.elementList.size();
|
||||
|
||||
if (size <= slot.amountMap().getOrDefault(BUNDLES, 1) ||
|
||||
1.0 * size / slot.amountMap().getOrDefault(BUNDLES, 1) <= this.pageIndex + 1)
|
||||
{
|
||||
// There are no next elements
|
||||
return null;
|
||||
}
|
||||
|
||||
int nextPageIndex = this.pageIndex + 2;
|
||||
|
||||
PanelItemBuilder builder = new PanelItemBuilder();
|
||||
|
||||
if (template.icon() != null)
|
||||
{
|
||||
ItemStack clone = template.icon().clone();
|
||||
|
||||
if ((boolean) template.dataMap().getOrDefault(INDEXING, false))
|
||||
{
|
||||
clone.setAmount(nextPageIndex);
|
||||
}
|
||||
|
||||
builder.icon(clone);
|
||||
}
|
||||
|
||||
if (template.title() != null)
|
||||
{
|
||||
builder.name(this.user.getTranslation(this.mainCommand.getWorld(), template.title()));
|
||||
}
|
||||
|
||||
if (template.description() != null)
|
||||
{
|
||||
builder.description(this.user.getTranslation(this.mainCommand.getWorld(), template.description(),
|
||||
TextVariables.NUMBER, String.valueOf(nextPageIndex)));
|
||||
}
|
||||
|
||||
// Add ClickHandler
|
||||
builder.clickHandler((panel, user, clickType, i) ->
|
||||
{
|
||||
template.actions().forEach(action -> {
|
||||
if ((clickType == action.clickType() ||
|
||||
action.clickType() == ClickType.UNKNOWN) && NEXT.equalsIgnoreCase(action.actionType()))
|
||||
{
|
||||
// Next button ignores click type currently.
|
||||
this.pageIndex++;
|
||||
this.build();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Always return true.
|
||||
return true;
|
||||
});
|
||||
|
||||
// Collect tooltips.
|
||||
List<String> tooltips = template.actions().stream().
|
||||
filter(action -> action.tooltip() != null).
|
||||
map(action -> this.user.getTranslation(this.mainCommand.getWorld(), action.tooltip())).
|
||||
filter(text -> !text.isBlank()).
|
||||
collect(Collectors.toCollection(() -> new ArrayList<>(template.actions().size())));
|
||||
|
||||
// Add tooltips.
|
||||
if (!tooltips.isEmpty())
|
||||
{
|
||||
// Empty line and tooltips.
|
||||
builder.description("");
|
||||
builder.description(tooltips);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create previous button panel item.
|
||||
*
|
||||
* @param template the template
|
||||
* @param slot the slot
|
||||
* @return the panel item
|
||||
*/
|
||||
@Nullable
|
||||
private PanelItem createPreviousButton(@NonNull ItemTemplateRecord template, TemplatedPanel.ItemSlot slot)
|
||||
{
|
||||
if (this.pageIndex == 0)
|
||||
{
|
||||
// There are no next elements
|
||||
return null;
|
||||
}
|
||||
|
||||
int previousPageIndex = this.pageIndex;
|
||||
|
||||
PanelItemBuilder builder = new PanelItemBuilder();
|
||||
|
||||
if (template.icon() != null)
|
||||
{
|
||||
ItemStack clone = template.icon().clone();
|
||||
|
||||
if ((boolean) template.dataMap().getOrDefault(INDEXING, false))
|
||||
{
|
||||
clone.setAmount(previousPageIndex);
|
||||
}
|
||||
|
||||
builder.icon(clone);
|
||||
}
|
||||
|
||||
if (template.title() != null)
|
||||
{
|
||||
builder.name(this.user.getTranslation(this.mainCommand.getWorld(), template.title()));
|
||||
}
|
||||
|
||||
if (template.description() != null)
|
||||
{
|
||||
builder.description(this.user.getTranslation(this.mainCommand.getWorld(), template.description(),
|
||||
TextVariables.NUMBER, String.valueOf(previousPageIndex)));
|
||||
}
|
||||
|
||||
// Add ClickHandler
|
||||
// Add ClickHandler
|
||||
builder.clickHandler((panel, user, clickType, i) ->
|
||||
{
|
||||
template.actions().forEach(action -> {
|
||||
if ((clickType == action.clickType() ||
|
||||
action.clickType() == ClickType.UNKNOWN) && PREVIOUS.equalsIgnoreCase(action.actionType()))
|
||||
{
|
||||
// Next button ignores click type currently.
|
||||
this.pageIndex--;
|
||||
this.build();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Always return true.
|
||||
return true;
|
||||
});
|
||||
|
||||
// Collect tooltips.
|
||||
List<String> tooltips = template.actions().stream().
|
||||
filter(action -> action.tooltip() != null).
|
||||
map(action -> this.user.getTranslation(this.mainCommand.getWorld(), action.tooltip())).
|
||||
filter(text -> !text.isBlank()).
|
||||
collect(Collectors.toCollection(() -> new ArrayList<>(template.actions().size())));
|
||||
|
||||
// Add tooltips.
|
||||
if (!tooltips.isEmpty())
|
||||
{
|
||||
// Empty line and tooltips.
|
||||
builder.description("");
|
||||
builder.description(tooltips);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method creates and returns bundle button.
|
||||
*
|
||||
* @return PanelItem that represents bundle button.
|
||||
*/
|
||||
@Nullable
|
||||
private PanelItem createBundleButton(ItemTemplateRecord template, TemplatedPanel.ItemSlot slot)
|
||||
{
|
||||
if (this.elementList.isEmpty())
|
||||
{
|
||||
// Does not contain any sticks.
|
||||
return null;
|
||||
}
|
||||
|
||||
int index = this.pageIndex * slot.amountMap().getOrDefault(BUNDLES, 1) + slot.slot();
|
||||
|
||||
BlueprintBundle blueprintBundle;
|
||||
|
||||
if (index >= this.elementList.size())
|
||||
{
|
||||
// Out of index.
|
||||
blueprintBundle = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
blueprintBundle = this.elementList.get(index);
|
||||
}
|
||||
|
||||
if (template.dataMap().containsKey("unique_id"))
|
||||
{
|
||||
// Try to find bundle with requested ID. if not found, use already collected bundle.
|
||||
blueprintBundle = this.elementList.stream().
|
||||
filter(bundle -> bundle.getUniqueId().equals(template.dataMap().get("unique_id"))).
|
||||
findFirst().
|
||||
orElse(blueprintBundle);
|
||||
}
|
||||
|
||||
return this.createBundleButton(template, blueprintBundle);
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Other methods
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* This method creates bundle button.
|
||||
*
|
||||
* @return PanelItem that allows to select bundle button
|
||||
*/
|
||||
private PanelItem createBundleButton(ItemTemplateRecord template, BlueprintBundle bundle)
|
||||
{
|
||||
if (bundle == null)
|
||||
{
|
||||
// return as bundle is null. Empty button will be created.
|
||||
return null;
|
||||
}
|
||||
|
||||
final String reference = "panels.island_creation.buttons.bundle.";
|
||||
|
||||
// Get settings for island.
|
||||
PanelItemBuilder builder = new PanelItemBuilder();
|
||||
|
||||
if (template.icon() != null)
|
||||
{
|
||||
builder.icon(template.icon().clone());
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.icon(bundle.getIcon());
|
||||
}
|
||||
|
||||
if (template.title() != null)
|
||||
{
|
||||
builder.name(this.user.getTranslation(this.mainCommand.getWorld(), template.title(),
|
||||
TextVariables.NAME, bundle.getDisplayName()));
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.name(this.user.getTranslation(reference + "name",
|
||||
TextVariables.NAME, bundle.getDisplayName()));
|
||||
}
|
||||
|
||||
if (template.description() != null)
|
||||
{
|
||||
builder.description(this.user.getTranslation(this.mainCommand.getWorld(), template.description(),
|
||||
TextVariables.DESCRIPTION, String.join("\n", bundle.getDescription())));
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.description(this.user.getTranslation(reference + "description",
|
||||
TextVariables.DESCRIPTION, String.join("\n", bundle.getDescription())));
|
||||
}
|
||||
|
||||
List<ItemTemplateRecord.ActionRecords> actions = template.actions().stream().
|
||||
filter(action -> SELECT_ACTION.equalsIgnoreCase(action.actionType()) ||
|
||||
COMMANDS_ACTION.equalsIgnoreCase(action.actionType())).
|
||||
toList();
|
||||
|
||||
// Add ClickHandler
|
||||
builder.clickHandler((panel, user, clickType, i) ->
|
||||
{
|
||||
actions.forEach(action -> {
|
||||
if (clickType == action.clickType() || action.clickType() == ClickType.UNKNOWN)
|
||||
{
|
||||
if (SELECT_ACTION.equalsIgnoreCase(action.actionType()))
|
||||
{
|
||||
user.closeInventory();
|
||||
this.mainCommand.execute(user, this.mainLabel, Collections.singletonList(bundle.getUniqueId()));
|
||||
}
|
||||
else if (COMMANDS_ACTION.equalsIgnoreCase(action.actionType()))
|
||||
{
|
||||
Util.runCommands(user,
|
||||
Arrays.stream(action.content().
|
||||
replaceAll(Pattern.quote(TextVariables.LABEL), this.mainCommand.getTopLabel()).
|
||||
split("\n")).
|
||||
toList(),
|
||||
ISLAND_CREATION_COMMANDS);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Always return true.
|
||||
return true;
|
||||
});
|
||||
|
||||
// Collect tooltips.
|
||||
List<String> tooltips = actions.stream().
|
||||
filter(action -> action.tooltip() != null).
|
||||
map(action -> this.user.getTranslation(this.mainCommand.getWorld(), action.tooltip())).
|
||||
filter(text -> !text.isBlank()).
|
||||
collect(Collectors.toCollection(() -> new ArrayList<>(actions.size())));
|
||||
|
||||
// Add tooltips.
|
||||
if (!tooltips.isEmpty())
|
||||
{
|
||||
// Empty line and tooltips.
|
||||
builder.description("");
|
||||
builder.description(tooltips);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Static methods
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* This method is used to open Panel outside this class. It will be much easier to open panel with single method
|
||||
* call then initializing new object.
|
||||
*
|
||||
* @param command CompositeCommand object
|
||||
* @param label The main command label
|
||||
* @param user User who opens panel
|
||||
*/
|
||||
public static void openPanel(@NonNull CompositeCommand command,
|
||||
@NonNull User user,
|
||||
@NonNull String label)
|
||||
{
|
||||
new IslandCreationPanel(command, user, label).build();
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Constants
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* This constant is used for button to indicate that it is Blueprint Bundle type.
|
||||
*/
|
||||
private static final String BUNDLES = "BUNDLE";
|
||||
|
||||
/**
|
||||
* This constant is used for button to indicate that it is previous page type.
|
||||
*/
|
||||
private static final String PREVIOUS = "PREVIOUS";
|
||||
|
||||
/**
|
||||
* This constant is used for button to indicate that it is next page type.
|
||||
*/
|
||||
private static final String NEXT = "NEXT";
|
||||
|
||||
/**
|
||||
* This constant is used for indicating that pages should contain numbering.
|
||||
*/
|
||||
private static final String INDEXING = "indexing";
|
||||
|
||||
/**
|
||||
* This constant stores value for SELECT action that is used in panels.
|
||||
*/
|
||||
private static final String SELECT_ACTION = "SELECT";
|
||||
|
||||
/**
|
||||
* This constant stores value for COMMAND action that is used in panels.
|
||||
*/
|
||||
private static final String COMMANDS_ACTION = "COMMANDS";
|
||||
|
||||
/**
|
||||
* This constant stores value for ERROR message that will be displayed upon failing to run creation commands.
|
||||
*/
|
||||
private static final String ISLAND_CREATION_COMMANDS = "ISLAND_CREATION_COMMANDS";
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Variables
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* This variable allows to access plugin object.
|
||||
*/
|
||||
private final BentoBox plugin;
|
||||
|
||||
/**
|
||||
* This variable stores main command that was triggered.
|
||||
*/
|
||||
private final CompositeCommand mainCommand;
|
||||
|
||||
/**
|
||||
* This variable holds user who opens panel. Without it panel cannot be opened.
|
||||
*/
|
||||
private final User user;
|
||||
|
||||
/**
|
||||
* This variable holds world where panel is opened. Without it panel cannot be opened.
|
||||
*/
|
||||
private final String mainLabel;
|
||||
|
||||
/**
|
||||
* This variable stores filtered elements.
|
||||
*/
|
||||
private final List<BlueprintBundle> elementList;
|
||||
|
||||
/**
|
||||
* This variable holds current pageIndex for multi-page island choosing.
|
||||
*/
|
||||
private int pageIndex;
|
||||
}
|
|
@ -0,0 +1,569 @@
|
|||
//
|
||||
// Created by BONNe
|
||||
// Copyright - 2022
|
||||
//
|
||||
|
||||
|
||||
package world.bentobox.bentobox.panels.customizable;
|
||||
|
||||
|
||||
import org.apache.commons.lang.WordUtils;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.api.addons.GameModeAddon;
|
||||
import world.bentobox.bentobox.api.commands.CompositeCommand;
|
||||
import world.bentobox.bentobox.api.localization.BentoBoxLocale;
|
||||
import world.bentobox.bentobox.api.localization.TextVariables;
|
||||
import world.bentobox.bentobox.api.panels.PanelItem;
|
||||
import world.bentobox.bentobox.api.panels.TemplatedPanel;
|
||||
import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
|
||||
import world.bentobox.bentobox.api.panels.builders.TemplatedPanelBuilder;
|
||||
import world.bentobox.bentobox.api.panels.reader.ItemTemplateRecord;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.util.Util;
|
||||
|
||||
|
||||
/**
|
||||
* This class generates Language Panel based on user specified file with name: "language_panel.yml".
|
||||
* If file with such name is located at gamemode panels directory, then that file will be used.
|
||||
* Otherwise, file in BentoBox/panels is used.
|
||||
*/
|
||||
public class LanguagePanel
|
||||
{
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Constructor
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* This is internal constructor. It is used internally in current class to avoid creating objects everywhere.
|
||||
*
|
||||
* @param command The main addon command.
|
||||
* @param user User who opens panel
|
||||
*/
|
||||
private LanguagePanel(@NonNull CompositeCommand command, @NonNull User user)
|
||||
{
|
||||
this.plugin = BentoBox.getInstance();
|
||||
this.mainCommand = command;
|
||||
this.user = user;
|
||||
|
||||
this.elementList = BentoBox.getInstance().getLocalesManager().getAvailableLocales(true);
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Methods
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* Build method manages current panel opening. It uses BentoBox PanelAPI that is easy to use and users can get nice
|
||||
* panels.
|
||||
*/
|
||||
private void build()
|
||||
{
|
||||
// Do not open gui if there is no magic sticks.
|
||||
if (this.elementList.isEmpty())
|
||||
{
|
||||
this.plugin.logError("There are no available locales for selection!");
|
||||
this.user.sendMessage("no-locales",
|
||||
TextVariables.GAMEMODE, this.plugin.getDescription().getName());
|
||||
return;
|
||||
}
|
||||
|
||||
// Start building panel.
|
||||
TemplatedPanelBuilder panelBuilder = new TemplatedPanelBuilder();
|
||||
|
||||
// Set main template.
|
||||
if (this.doesCustomPanelExists(this.mainCommand.getAddon(), "language_panel"))
|
||||
{
|
||||
// Addon has its own island creation panel. Use it.
|
||||
panelBuilder.template("language_panel", new File(this.mainCommand.getAddon().getDataFolder(), "panels"));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use default island creation panel.
|
||||
panelBuilder.template("language_panel", new File(this.plugin.getDataFolder(), "panels"));
|
||||
}
|
||||
|
||||
panelBuilder.user(this.user);
|
||||
panelBuilder.world(this.user.getWorld());
|
||||
|
||||
// Register button builders
|
||||
panelBuilder.registerTypeBuilder(LOCALE, this::createLocaleButton);
|
||||
|
||||
// Register next and previous builders
|
||||
panelBuilder.registerTypeBuilder(NEXT, this::createNextButton);
|
||||
panelBuilder.registerTypeBuilder(PREVIOUS, this::createPreviousButton);
|
||||
|
||||
// Register unknown type builder.
|
||||
panelBuilder.build();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method returns if panel with the requested name is located in GameModeAddon folder.
|
||||
* @param addon GameModeAddon that need to be checked.
|
||||
* @param name Name of the panel.
|
||||
* @return {@code true} if panel exists, {@code false} otherwise.
|
||||
*/
|
||||
private boolean doesCustomPanelExists(GameModeAddon addon, String name)
|
||||
{
|
||||
return addon.getDataFolder().exists() &&
|
||||
new File(addon.getDataFolder(), "panels").exists() &&
|
||||
new File(addon.getDataFolder(), "panels" + File.separator + name + ".yml").exists();
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Buttons
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* Create next button panel item.
|
||||
*
|
||||
* @param template the template
|
||||
* @param slot the slot
|
||||
* @return the panel item
|
||||
*/
|
||||
@Nullable
|
||||
private PanelItem createNextButton(@NonNull ItemTemplateRecord template, TemplatedPanel.ItemSlot slot)
|
||||
{
|
||||
int size = this.elementList.size();
|
||||
|
||||
if (size <= slot.amountMap().getOrDefault(LOCALE, 1) ||
|
||||
1.0 * size / slot.amountMap().getOrDefault(LOCALE, 1) <= this.pageIndex + 1)
|
||||
{
|
||||
// There are no next elements
|
||||
return null;
|
||||
}
|
||||
|
||||
int nextPageIndex = this.pageIndex + 2;
|
||||
|
||||
PanelItemBuilder builder = new PanelItemBuilder();
|
||||
|
||||
if (template.icon() != null)
|
||||
{
|
||||
ItemStack clone = template.icon().clone();
|
||||
|
||||
if ((boolean) template.dataMap().getOrDefault(INDEXING, false))
|
||||
{
|
||||
clone.setAmount(nextPageIndex);
|
||||
}
|
||||
|
||||
builder.icon(clone);
|
||||
}
|
||||
|
||||
if (template.title() != null)
|
||||
{
|
||||
builder.name(this.user.getTranslation(template.title()));
|
||||
}
|
||||
|
||||
if (template.description() != null)
|
||||
{
|
||||
builder.description(this.user.getTranslation(template.description(),
|
||||
TextVariables.NUMBER, String.valueOf(nextPageIndex)));
|
||||
}
|
||||
|
||||
// Add ClickHandler
|
||||
builder.clickHandler((panel, user, clickType, i) ->
|
||||
{
|
||||
template.actions().forEach(action -> {
|
||||
if ((clickType == action.clickType() ||
|
||||
action.clickType() == ClickType.UNKNOWN) && NEXT.equalsIgnoreCase(action.actionType()))
|
||||
{
|
||||
// Next button ignores click type currently.
|
||||
this.pageIndex++;
|
||||
this.build();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Always return true.
|
||||
return true;
|
||||
});
|
||||
|
||||
// Collect tooltips.
|
||||
List<String> tooltips = template.actions().stream().
|
||||
filter(action -> action.tooltip() != null).
|
||||
map(action -> this.user.getTranslation( action.tooltip())).
|
||||
filter(text -> !text.isBlank()).
|
||||
collect(Collectors.toCollection(() -> new ArrayList<>(template.actions().size())));
|
||||
|
||||
// Add tooltips.
|
||||
if (!tooltips.isEmpty())
|
||||
{
|
||||
// Empty line and tooltips.
|
||||
builder.description("");
|
||||
builder.description(tooltips);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create previous button panel item.
|
||||
*
|
||||
* @param template the template
|
||||
* @param slot the slot
|
||||
* @return the panel item
|
||||
*/
|
||||
@Nullable
|
||||
private PanelItem createPreviousButton(@NonNull ItemTemplateRecord template, TemplatedPanel.ItemSlot slot)
|
||||
{
|
||||
if (this.pageIndex == 0)
|
||||
{
|
||||
// There are no next elements
|
||||
return null;
|
||||
}
|
||||
|
||||
int previousPageIndex = this.pageIndex;
|
||||
|
||||
PanelItemBuilder builder = new PanelItemBuilder();
|
||||
|
||||
if (template.icon() != null)
|
||||
{
|
||||
ItemStack clone = template.icon().clone();
|
||||
|
||||
if ((boolean) template.dataMap().getOrDefault(INDEXING, false))
|
||||
{
|
||||
clone.setAmount(previousPageIndex);
|
||||
}
|
||||
|
||||
builder.icon(clone);
|
||||
}
|
||||
|
||||
if (template.title() != null)
|
||||
{
|
||||
builder.name(this.user.getTranslation(this.mainCommand.getWorld(), template.title()));
|
||||
}
|
||||
|
||||
if (template.description() != null)
|
||||
{
|
||||
builder.description(this.user.getTranslation(this.mainCommand.getWorld(), template.description(),
|
||||
TextVariables.NUMBER, String.valueOf(previousPageIndex)));
|
||||
}
|
||||
|
||||
// Add ClickHandler
|
||||
// Add ClickHandler
|
||||
builder.clickHandler((panel, user, clickType, i) ->
|
||||
{
|
||||
template.actions().forEach(action -> {
|
||||
if ((clickType == action.clickType() ||
|
||||
action.clickType() == ClickType.UNKNOWN) && PREVIOUS.equalsIgnoreCase(action.actionType()))
|
||||
{
|
||||
// Next button ignores click type currently.
|
||||
this.pageIndex--;
|
||||
this.build();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Always return true.
|
||||
return true;
|
||||
});
|
||||
|
||||
// Collect tooltips.
|
||||
List<String> tooltips = template.actions().stream().
|
||||
filter(action -> action.tooltip() != null).
|
||||
map(action -> this.user.getTranslation(this.mainCommand.getWorld(), action.tooltip())).
|
||||
filter(text -> !text.isBlank()).
|
||||
collect(Collectors.toCollection(() -> new ArrayList<>(template.actions().size())));
|
||||
|
||||
// Add tooltips.
|
||||
if (!tooltips.isEmpty())
|
||||
{
|
||||
// Empty line and tooltips.
|
||||
builder.description("");
|
||||
builder.description(tooltips);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method creates and returns locale button.
|
||||
*
|
||||
* @return PanelItem that represents locale button.
|
||||
*/
|
||||
@Nullable
|
||||
private PanelItem createLocaleButton(ItemTemplateRecord template, TemplatedPanel.ItemSlot slot)
|
||||
{
|
||||
if (this.elementList.isEmpty())
|
||||
{
|
||||
// Does not contain any sticks.
|
||||
return null;
|
||||
}
|
||||
|
||||
int index = this.pageIndex * slot.amountMap().getOrDefault(LOCALE, 1) + slot.slot();
|
||||
|
||||
Locale locale;
|
||||
|
||||
if (index >= this.elementList.size())
|
||||
{
|
||||
// Out of index.
|
||||
locale = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
locale = this.elementList.get(index);
|
||||
}
|
||||
|
||||
if (template.dataMap().containsKey("lang_id"))
|
||||
{
|
||||
// Try to find locale with requested ID. if not found, use already collected locale.
|
||||
locale = this.elementList.stream().
|
||||
filter(localeID -> localeID.toLanguageTag().equals(template.dataMap().get("lang_id"))).
|
||||
findFirst().
|
||||
orElse(locale);
|
||||
}
|
||||
|
||||
return this.createLocaleButton(template, locale);
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Other methods
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* This method creates locale button.
|
||||
*
|
||||
* @return PanelItem that allows to select locale button
|
||||
*/
|
||||
private PanelItem createLocaleButton(ItemTemplateRecord template, Locale locale)
|
||||
{
|
||||
if (locale == null)
|
||||
{
|
||||
// return as locale is null. Empty button will be created.
|
||||
return null;
|
||||
}
|
||||
|
||||
final String reference = "panels.language.buttons.language.";
|
||||
|
||||
// Get settings for island.
|
||||
PanelItemBuilder builder = new PanelItemBuilder();
|
||||
|
||||
BentoBoxLocale language = this.plugin.getLocalesManager().getLanguages().get(locale);
|
||||
|
||||
if (template.icon() != null)
|
||||
{
|
||||
builder.icon(template.icon().clone());
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.icon(Objects.requireNonNullElseGet(language.getBanner(),
|
||||
() -> new ItemStack(Material.WHITE_BANNER, 1)));
|
||||
}
|
||||
|
||||
if (template.title() != null)
|
||||
{
|
||||
builder.name(this.user.getTranslation(this.mainCommand.getWorld(), template.title(),
|
||||
TextVariables.NAME, WordUtils.capitalize(locale.getDisplayName(this.user.getLocale()))));
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.name(this.user.getTranslation(reference + "name",
|
||||
TextVariables.NAME, WordUtils.capitalize(locale.getDisplayName(this.user.getLocale()))));
|
||||
}
|
||||
|
||||
final StringBuilder authors = new StringBuilder();
|
||||
authors.append(this.user.getTranslation(reference + "authors"));
|
||||
|
||||
for (String author : language.getAuthors())
|
||||
{
|
||||
authors.append("\n").append(this.user.getTranslation(reference + "author", TextVariables.NAME, author));
|
||||
}
|
||||
|
||||
final StringBuilder selected = new StringBuilder();
|
||||
|
||||
if (this.user.getLocale().equals(locale))
|
||||
{
|
||||
selected.append(this.user.getTranslation(reference + "selected"));
|
||||
}
|
||||
|
||||
String descriptionText;
|
||||
|
||||
if (template.description() != null)
|
||||
{
|
||||
descriptionText = this.user.getTranslationOrNothing(template.description(),
|
||||
AUTHORS, authors.toString(),
|
||||
SELECTED, selected.toString());
|
||||
}
|
||||
else
|
||||
{
|
||||
descriptionText = this.user.getTranslationOrNothing(reference + "description",
|
||||
AUTHORS, authors.toString(),
|
||||
SELECTED, selected.toString());
|
||||
}
|
||||
|
||||
descriptionText = descriptionText.replaceAll("(?m)^[ \\t]*\\r?\\n", "").
|
||||
replaceAll("(?<!\\\\)\\|", "\n").
|
||||
replaceAll("\\\\\\|", "|");
|
||||
|
||||
builder.description(descriptionText);
|
||||
|
||||
// Display actions only for non-selected locales.
|
||||
List<ItemTemplateRecord.ActionRecords> actions = template.actions().stream().
|
||||
filter(action -> !this.user.getLocale().equals(locale) &&
|
||||
(SELECT_ACTION.equalsIgnoreCase(action.actionType()) ||
|
||||
COMMANDS_ACTION.equalsIgnoreCase(action.actionType()))).
|
||||
toList();
|
||||
|
||||
// Add ClickHandler
|
||||
builder.clickHandler((panel, user, clickType, i) ->
|
||||
{
|
||||
actions.forEach(action -> {
|
||||
if (clickType == action.clickType() || action.clickType() == ClickType.UNKNOWN)
|
||||
{
|
||||
if (SELECT_ACTION.equalsIgnoreCase(action.actionType()))
|
||||
{
|
||||
this.plugin.getPlayers().setLocale(this.user.getUniqueId(), locale.toLanguageTag());
|
||||
this.user.sendMessage("language.edited", "[lang]",
|
||||
WordUtils.capitalize(locale.getDisplayName(this.user.getLocale())));
|
||||
|
||||
// Rebuild panel
|
||||
this.build();
|
||||
}
|
||||
else if (COMMANDS_ACTION.equalsIgnoreCase(action.actionType()))
|
||||
{
|
||||
Util.runCommands(user,
|
||||
Arrays.stream(action.content().
|
||||
replaceAll(Pattern.quote(TextVariables.LABEL), this.mainCommand.getTopLabel()).
|
||||
split("\n")).
|
||||
toList(),
|
||||
"CHANGE_LOCALE_COMMANDS");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Always return true.
|
||||
return true;
|
||||
});
|
||||
|
||||
// Collect tooltips.
|
||||
List<String> tooltips = actions.stream().
|
||||
filter(action -> action.tooltip() != null).
|
||||
map(action -> this.user.getTranslation(this.mainCommand.getWorld(), action.tooltip())).
|
||||
filter(text -> !text.isBlank()).
|
||||
collect(Collectors.toCollection(() -> new ArrayList<>(actions.size())));
|
||||
|
||||
// Add tooltips.
|
||||
if (!tooltips.isEmpty())
|
||||
{
|
||||
// Empty line and tooltips.
|
||||
builder.description("");
|
||||
builder.description(tooltips);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Static methods
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* This method is used to open Panel outside this class. It will be much easier to open panel with single method
|
||||
* call then initializing new object.
|
||||
*
|
||||
* @param command The main addon command.
|
||||
* @param user User who opens panel
|
||||
*/
|
||||
public static void openPanel(@NonNull CompositeCommand command, @NonNull User user)
|
||||
{
|
||||
new LanguagePanel(command, user).build();
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Constants
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* This constant is used for button to indicate that it is Language type.
|
||||
*/
|
||||
private static final String LOCALE = "LOCALE";
|
||||
|
||||
/**
|
||||
* This constant is used for button to indicate that it is previous page type.
|
||||
*/
|
||||
private static final String PREVIOUS = "PREVIOUS";
|
||||
|
||||
/**
|
||||
* This constant is used for button to indicate that it is next page type.
|
||||
*/
|
||||
private static final String NEXT = "NEXT";
|
||||
|
||||
/**
|
||||
* This constant is used for indicating that pages should contain numbering.
|
||||
*/
|
||||
private static final String INDEXING = "indexing";
|
||||
|
||||
/**
|
||||
* This constant stores value for SELECT action that is used in panels.
|
||||
*/
|
||||
private static final String SELECT_ACTION = "SELECT";
|
||||
|
||||
/**
|
||||
* This constant stores value for COMMANDS action that is used in panels.
|
||||
*/
|
||||
private static final String COMMANDS_ACTION = "COMMANDS";
|
||||
|
||||
/**
|
||||
* This constant stores value for AUTHORS label that is used in panels.
|
||||
*/
|
||||
public static final String AUTHORS = "[authors]";
|
||||
|
||||
/**
|
||||
* This constant stores value for SELECTED label that is used in panels.
|
||||
*/
|
||||
public static final String SELECTED = "[selected]";
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Variables
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* This variable allows to access plugin object.
|
||||
*/
|
||||
private final BentoBox plugin;
|
||||
|
||||
/**
|
||||
* This variable stores the main command object.
|
||||
*/
|
||||
private final CompositeCommand mainCommand;
|
||||
|
||||
/**
|
||||
* This variable holds user who opens panel. Without it panel cannot be opened.
|
||||
*/
|
||||
private final User user;
|
||||
|
||||
/**
|
||||
* This variable stores filtered elements.
|
||||
*/
|
||||
private final List<Locale> elementList;
|
||||
|
||||
/**
|
||||
* This variable holds current pageIndex for multi-page island choosing.
|
||||
*/
|
||||
private int pageIndex;
|
||||
}
|
|
@ -1,16 +1,14 @@
|
|||
package world.bentobox.bentobox.util;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
import java.util.MissingFormatArgumentException;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.DyeColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.banner.Pattern;
|
||||
import org.bukkit.block.banner.PatternType;
|
||||
import org.bukkit.inventory.ItemFactory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.BannerMeta;
|
||||
import org.bukkit.inventory.meta.Damageable;
|
||||
|
@ -19,10 +17,12 @@ import org.bukkit.inventory.meta.PotionMeta;
|
|||
import org.bukkit.inventory.meta.SkullMeta;
|
||||
import org.bukkit.potion.PotionData;
|
||||
import org.bukkit.potion.PotionType;
|
||||
import org.bukkit.profile.PlayerProfile;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.properties.Property;
|
||||
import com.google.common.base.Enums;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
|
||||
|
@ -55,6 +55,33 @@ public class ItemParser {
|
|||
*/
|
||||
@Nullable
|
||||
public static ItemStack parse(@Nullable String text, @Nullable ItemStack defaultItemStack) {
|
||||
if (text == null || text.isBlank()) {
|
||||
// Text does not exist or is empty.
|
||||
return defaultItemStack;
|
||||
}
|
||||
|
||||
ItemStack returnValue;
|
||||
|
||||
try {
|
||||
// Check if item can be parsed using bukkit item factory.
|
||||
returnValue = Bukkit.getItemFactory().createItemStack(text);
|
||||
}
|
||||
catch (IllegalArgumentException exception) {
|
||||
returnValue = ItemParser.parseOld(text, defaultItemStack);
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse given string to ItemStack.
|
||||
* @param text String value of item stack.
|
||||
* @param defaultItemStack Material that should be returned if parsing failed.
|
||||
* @return ItemStack of parsed item or defaultItemStack.
|
||||
*/
|
||||
@Nullable
|
||||
private static ItemStack parseOld(@Nullable String text, @Nullable ItemStack defaultItemStack) {
|
||||
|
||||
if (text == null || text.isBlank()) {
|
||||
// Text does not exist or is empty.
|
||||
|
@ -113,22 +140,25 @@ public class ItemParser {
|
|||
returnValue = parseItemDurabilityAndQuantity(part);
|
||||
}
|
||||
|
||||
if (returnValue != null
|
||||
// If wrapper is just for code-style null-pointer checks.
|
||||
&& customModelData != null) {
|
||||
return customValue(returnValue, customModelData);
|
||||
// Update item meta with custom data model.
|
||||
if (returnValue != null && customModelData != null) {
|
||||
ItemParser.setCustomModelData(returnValue, customModelData);
|
||||
}
|
||||
|
||||
} catch (Exception exception) {
|
||||
BentoBox.getInstance().logError("Could not parse item " + text + " " + exception.getLocalizedMessage());
|
||||
returnValue = defaultItemStack;
|
||||
}
|
||||
return returnValue;
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
|
||||
private static @Nullable ItemStack customValue(ItemStack returnValue, Integer customModelData) {
|
||||
/**
|
||||
* This method assigns custom model data to the item stack.
|
||||
* @param returnValue Item stack that should be updated.
|
||||
* @param customModelData Integer value of custom model data.
|
||||
*/
|
||||
private static void setCustomModelData(ItemStack returnValue, Integer customModelData) {
|
||||
// We have custom data model. Now assign it to the item-stack.
|
||||
ItemMeta itemMeta = returnValue.getItemMeta();
|
||||
|
||||
|
@ -138,8 +168,9 @@ public class ItemParser {
|
|||
// Update meta to the return item.
|
||||
returnValue.setItemMeta(itemMeta);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method parses array of 2 items into an item stack.
|
||||
* First array element is material, while second array element is integer, that represents item count.
|
||||
|
@ -197,8 +228,10 @@ public class ItemParser {
|
|||
* }</pre>
|
||||
* @param part String array that contains 6 elements.
|
||||
* @return Potion with given properties.
|
||||
* @deprecated due to the spigot potion changes.
|
||||
*/
|
||||
private static ItemStack parsePotion(String[] part) {
|
||||
@Deprecated
|
||||
private static ItemStack parsePotionOld(String[] part) {
|
||||
if (part.length != 6) {
|
||||
throw new MissingFormatArgumentException("Potion parsing requires 6 parts.");
|
||||
}
|
||||
|
@ -235,6 +268,61 @@ public class ItemParser {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method parses array of 6 items into an item stack.
|
||||
* Format:
|
||||
* <pre>{@code
|
||||
* POTION:<POTION_TYPE>:QTY
|
||||
* }</pre>
|
||||
* Example:
|
||||
* <pre>{@code
|
||||
* POTION:STRENGTH:1
|
||||
* }</pre>
|
||||
* @link <a href="https://hub.spigotmc.org/javadocs/spigot/org/bukkit/potion/PotionType.html">Potion Type</a>
|
||||
* @param part String array that contains 3 elements.
|
||||
* @return Potion with given properties.
|
||||
*/
|
||||
private static ItemStack parsePotion(String[] part) {
|
||||
if (part.length == 6) {
|
||||
BentoBox.getInstance().logWarning("The old potion parsing detected for " + part[0] +
|
||||
". Please update your configs, as SPIGOT changed potion types.");
|
||||
return parsePotionOld(part);
|
||||
}
|
||||
|
||||
if (part.length != 3) {
|
||||
throw new MissingFormatArgumentException("Potion parsing requires 3 parts.");
|
||||
}
|
||||
|
||||
/*
|
||||
# Format POTION:<POTION_TYPE>:QTY
|
||||
# Potion Type can be found out in: https://hub.spigotmc.org/javadocs/spigot/org/bukkit/potion/PotionType.html
|
||||
# Examples:
|
||||
# POTION:STRENGTH:1
|
||||
# POTION:INSTANT_DAMAGE:2
|
||||
# POTION:JUMP:1
|
||||
# POTION:WEAKNESS:1 - any weakness potion
|
||||
*/
|
||||
|
||||
Material material = Material.matchMaterial(part[0]);
|
||||
|
||||
if (material == null) {
|
||||
BentoBox.getInstance().logWarning("Could not parse potion item " + part[0] + " so using a regular potion.");
|
||||
material = Material.POTION;
|
||||
}
|
||||
|
||||
ItemStack result = new ItemStack(material, Integer.parseInt(part[2]));
|
||||
|
||||
if (result.getItemMeta() instanceof PotionMeta meta) {
|
||||
PotionType potionType = Enums.getIfPresent(PotionType.class, part[1].toUpperCase(Locale.ENGLISH)).
|
||||
or(PotionType.WATER);
|
||||
meta.setBasePotionType(potionType);
|
||||
result.setItemMeta(meta);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method parses array of multiple elements for the Banner.
|
||||
* @param part String array that contains at least 2 elements.
|
||||
|
@ -298,39 +386,62 @@ public class ItemParser {
|
|||
|
||||
// Set correct Skull texture
|
||||
try {
|
||||
SkullMeta meta = (SkullMeta) playerHead.getItemMeta();
|
||||
if (playerHead.getItemMeta() instanceof SkullMeta meta)
|
||||
{
|
||||
PlayerProfile profile;
|
||||
|
||||
if (part[1].length() < 17) {
|
||||
// Minecraft player names are in length between 3 and 16 chars.
|
||||
meta.setOwner(part[1]);
|
||||
} else if (part[1].length() == 32) {
|
||||
// trimmed UUID length are 32 chars.
|
||||
meta.setOwningPlayer(Bukkit.getOfflinePlayer(
|
||||
UUID.fromString(part[1].replaceAll("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5"))));
|
||||
} else if (part[1].length() == 36) {
|
||||
// full UUID length are 36 chars.
|
||||
meta.setOwningPlayer(Bukkit.getOfflinePlayer(UUID.fromString(part[1])));
|
||||
} else {
|
||||
// If chars are more than 36, apparently it is base64 encoded texture.
|
||||
GameProfile profile = new GameProfile(UUID.randomUUID(), "");
|
||||
profile.getProperties().put("textures", new Property("textures", part[1]));
|
||||
if (part[1].length() < 17) {
|
||||
// Minecraft player names are in length between 3 and 16 chars.
|
||||
profile = Bukkit.createPlayerProfile(part[1]);
|
||||
} else if (part[1].length() == 32) {
|
||||
// trimmed UUID length are 32 chars.
|
||||
profile = Bukkit.createPlayerProfile(UUID.fromString(part[1].replaceAll("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5")));
|
||||
} else if (part[1].length() == 36) {
|
||||
// full UUID length are 36 chars.
|
||||
profile = Bukkit.createPlayerProfile(UUID.fromString(part[1]));
|
||||
} else {
|
||||
// If chars are more than 36, apparently it is base64 encoded texture.
|
||||
profile = Bukkit.createPlayerProfile(UUID.randomUUID(), "");
|
||||
profile.getTextures().setSkin(ItemParser.getSkinURLFromBase64(part[1]));
|
||||
}
|
||||
|
||||
// Null pointer will be caught and ignored.
|
||||
Field profileField = meta.getClass().getDeclaredField("profile");
|
||||
profileField.setAccessible(true);
|
||||
profileField.set(meta, profile);
|
||||
// Apply item meta.
|
||||
meta.setOwnerProfile(profile);
|
||||
playerHead.setItemMeta(meta);
|
||||
}
|
||||
|
||||
// Apply new meta to the item.
|
||||
playerHead.setItemMeta(meta);
|
||||
} catch (Exception ignored) {
|
||||
// Ignored
|
||||
// Could not parse player head.
|
||||
BentoBox.getInstance().logError("Could not parse player head item " + part[1] + " so using a Steve head.");
|
||||
}
|
||||
|
||||
return playerHead;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method parses base64 encoded string into URL.
|
||||
* @param base64 Base64 encoded string.
|
||||
* @return URL of the skin.
|
||||
*/
|
||||
private static URL getSkinURLFromBase64(String base64) {
|
||||
/*
|
||||
* Base64 encoded string is in format: { "timestamp": 0, "profileId": "UUID",
|
||||
* "profileName": "USERNAME", "textures": { "SKIN": { "url":
|
||||
* "https://textures.minecraft.net/texture/TEXTURE_ID" }, "CAPE": { "url":
|
||||
* "https://textures.minecraft.net/texture/TEXTURE_ID" } } }
|
||||
*/
|
||||
try {
|
||||
String decoded = new String(Base64.getDecoder().decode(base64));
|
||||
JsonObject json = new Gson().fromJson(decoded, JsonObject.class);
|
||||
String url = json.getAsJsonObject("textures").getAsJsonObject("SKIN").get("url").getAsString();
|
||||
return new URL(url);
|
||||
}
|
||||
catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if given sting is an integer.
|
||||
* @param string Value that must be checked.
|
||||
|
|
|
@ -1622,15 +1622,6 @@ protection:
|
|||
setting-active: '&a Active'
|
||||
setting-disabled: '&c Disabled'
|
||||
|
||||
language:
|
||||
panel-title: Select your language
|
||||
description:
|
||||
selected: '&a Currently selected.'
|
||||
click-to-select: '&e Click &a to select.'
|
||||
authors: '&a Authors:'
|
||||
author: '&3 - &b [name]'
|
||||
edited: '&a Changed your language to &e [lang]&a .'
|
||||
|
||||
management:
|
||||
panel:
|
||||
title: BentoBox Management
|
||||
|
@ -1788,6 +1779,51 @@ panel:
|
|||
|
||||
&a Allow BentoBox to connect to GitHub in
|
||||
&a the configuration or try again later.
|
||||
|
||||
# This section contains values for BentoBox panels.
|
||||
panels:
|
||||
# The section of translations used in Island Creation Panel
|
||||
island_creation:
|
||||
title: "&2&l Pick an island"
|
||||
buttons:
|
||||
# This button is used for displaying blueprint bundle in the island creation panel.
|
||||
bundle:
|
||||
name: "&l [name]"
|
||||
description: |-
|
||||
[description]
|
||||
# The section of translations used in Language Panel
|
||||
language:
|
||||
title: "&2&l Select your language"
|
||||
buttons:
|
||||
# This button is used for displaying different locales that are available in language selection panel.
|
||||
language:
|
||||
name: "&f&l [name]"
|
||||
description: |-
|
||||
[authors]
|
||||
|[selected]
|
||||
authors: "&7 Authors: "
|
||||
author: "&7 - &b [name]"
|
||||
selected: "&a Currently selected."
|
||||
# The set of common buttons used in multiple panels.
|
||||
buttons:
|
||||
# Button that is used in multi-page GUIs which allows to return to previous page.
|
||||
previous:
|
||||
name: "&f&l Previous Page"
|
||||
description: |-
|
||||
&7 Switch to [number] page
|
||||
# Button that is used in multi-page GUIs which allows to go to next page.
|
||||
next:
|
||||
name: "&f&l Next Page"
|
||||
description: |-
|
||||
&7 Switch to [number] page
|
||||
tips:
|
||||
click-to-next: "&e Click &7 for next."
|
||||
click-to-previous: "&e Click &7 for previous."
|
||||
click-to-choose: "&e Click &7 to select."
|
||||
click-to-toggle: "&e Click &7 to toggle."
|
||||
left-click-to-cycle-down: "&e Left Click &7 to cycle downwards."
|
||||
right-click-to-cycle-up: "&e Right Click &7 to cycle upwards."
|
||||
|
||||
successfully-loaded: |2
|
||||
|
||||
&6 ____ _ ____
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
# This is default island creation panel. It is used in all situations when gamemode addon does not have specified their
|
||||
# of panel.
|
||||
island_creation_panel:
|
||||
title: panels.island_creation.title # The title of panel or link to the localization location.
|
||||
type: INVENTORY # The type of inventory: INVENTORY, DROPPER, HOPPER
|
||||
background: # The item that will be displayed in empty spots. This section can be removed.
|
||||
icon: BLACK_STAINED_GLASS_PANE # The icon of background item
|
||||
title: "&b&r" # Empty text # The text of background item
|
||||
border: # The item that will be displayed around the inventory. This section can be removed.
|
||||
icon: BLACK_STAINED_GLASS_PANE # The icon of background item
|
||||
title: "&b&r" # Empty text # The text of background item
|
||||
force-shown: [] # Allow to specify (1-6, 1-3, 1) which rows must be showed regardless of empty elements.
|
||||
content: # Allow to define buttons in your panel.
|
||||
2:
|
||||
2: blueprint_bundle_button # String values are expected to be `reusables` that are defined at the end of this file.
|
||||
3: blueprint_bundle_button
|
||||
4: blueprint_bundle_button
|
||||
5: blueprint_bundle_button
|
||||
6: blueprint_bundle_button
|
||||
7: blueprint_bundle_button
|
||||
8: blueprint_bundle_button
|
||||
3:
|
||||
1:
|
||||
icon: TIPPED_ARROW:INSTANT_HEAL::::1 # The icon for button
|
||||
title: panels.buttons.previous.name # The name of button, or link to the localization.
|
||||
description: panels.buttons.previous.description # The description of button, or link to the localization.
|
||||
data:
|
||||
type: PREVIOUS # Indicates what button is doing. Available values depends on panel
|
||||
indexing: true # Parameter for button.
|
||||
actions: # List of actions that button can do. Available values depends on button
|
||||
previous:
|
||||
click-type: UNKNOWN # UNKNOWN means that any click type is respected.
|
||||
tooltip: panels.tips.click-to-previous # Tooltips are always generated an empty line bellow description/title. Not required.
|
||||
2: blueprint_bundle_button
|
||||
3: blueprint_bundle_button
|
||||
4: blueprint_bundle_button
|
||||
5: blueprint_bundle_button
|
||||
6: blueprint_bundle_button
|
||||
7: blueprint_bundle_button
|
||||
8: blueprint_bundle_button
|
||||
9:
|
||||
icon: TIPPED_ARROW:JUMP::::1
|
||||
title: panels.buttons.next.name
|
||||
description: panels.buttons.next.description
|
||||
data:
|
||||
type: NEXT
|
||||
indexing: true
|
||||
actions:
|
||||
next:
|
||||
click-type: UNKNOWN
|
||||
tooltip: panels.tips.click-to-next
|
||||
4:
|
||||
2: blueprint_bundle_button
|
||||
3: blueprint_bundle_button
|
||||
4: blueprint_bundle_button
|
||||
5: blueprint_bundle_button
|
||||
6: blueprint_bundle_button
|
||||
7: blueprint_bundle_button
|
||||
8: blueprint_bundle_button
|
||||
reusable: # List of reoccurring buttons in the panels.
|
||||
blueprint_bundle_button: # The ID of the button
|
||||
# icon: GRASS_BLOCK
|
||||
title: panels.island_creation.buttons.bundle.name
|
||||
description: panels.island_creation.buttons.bundle.description
|
||||
data:
|
||||
type: BUNDLE
|
||||
# unique_id: default # Specifying unique_id will force to show the requested bundle if it is available.
|
||||
actions:
|
||||
select:
|
||||
click-type: UNKNOWN
|
||||
tooltip: panels.tips.click-to-choose
|
|
@ -0,0 +1,71 @@
|
|||
# This is default language selection panel. It is used in all situations when gamemode addon does not have specified their
|
||||
# of panel.
|
||||
language_panel:
|
||||
title: panels.language.title # The title of panel or link to the localization location.
|
||||
type: INVENTORY # The type of inventory: INVENTORY, DROPPER, HOPPER
|
||||
background: # The item that will be displayed in empty spots. This section can be removed.
|
||||
icon: BLACK_STAINED_GLASS_PANE # The icon of background item
|
||||
title: "&b&r" # Empty text # The text of background item
|
||||
border: # The item that will be displayed around the inventory. This section can be removed.
|
||||
icon: BLACK_STAINED_GLASS_PANE # The icon of background item
|
||||
title: "&b&r" # Empty text # The text of background item
|
||||
force-shown: [] # Allow to specify (1-6, 1-3, 1) which rows must be showed regardless of empty elements.
|
||||
content: # Allow to define buttons in your panel.
|
||||
2:
|
||||
2: language_button # String values are expected to be `reusables` that are defined at the end of this file.
|
||||
3: language_button
|
||||
4: language_button
|
||||
5: language_button
|
||||
6: language_button
|
||||
7: language_button
|
||||
8: language_button
|
||||
3:
|
||||
1:
|
||||
icon: TIPPED_ARROW:INSTANT_HEAL::::1 # The icon for button
|
||||
title: panels.buttons.previous.name # The name of button, or link to the localization.
|
||||
description: panels.buttons.previous.description # The description of button, or link to the localization.
|
||||
data:
|
||||
type: PREVIOUS # Indicates what button is doing. Available values depends on panel
|
||||
indexing: true # Parameter for button.
|
||||
actions: # List of actions that button can do. Available values depends on button
|
||||
previous:
|
||||
click-type: UNKNOWN # UNKNOWN means that any click type is respected.
|
||||
tooltip: panels.tips.click-to-previous # Tooltips are always generated an empty line bellow description/title. Not required.
|
||||
2: language_button
|
||||
3: language_button
|
||||
4: language_button
|
||||
5: language_button
|
||||
6: language_button
|
||||
7: language_button
|
||||
8: language_button
|
||||
9:
|
||||
icon: TIPPED_ARROW:JUMP::::1
|
||||
title: panels.buttons.next.name
|
||||
description: panels.buttons.next.description
|
||||
data:
|
||||
type: NEXT
|
||||
indexing: true
|
||||
actions:
|
||||
next:
|
||||
click-type: UNKNOWN
|
||||
tooltip: panels.tips.click-to-next
|
||||
4:
|
||||
2: language_button
|
||||
3: language_button
|
||||
4: language_button
|
||||
5: language_button
|
||||
6: language_button
|
||||
7: language_button
|
||||
8: language_button
|
||||
reusable: # List of reoccurring buttons in the panels.
|
||||
language_button: # The ID of the button
|
||||
# icon: GRASS_BLOCK
|
||||
title: panels.language.buttons.language.name
|
||||
description: panels.language.buttons.language.description
|
||||
data:
|
||||
type: LOCALE
|
||||
# lang_id: default # Specifying lang_id will force to show the requested locale if it is available.
|
||||
actions:
|
||||
select:
|
||||
click-type: UNKNOWN
|
||||
tooltip: panels.tips.click-to-choose
|
|
@ -54,7 +54,7 @@ import world.bentobox.bentobox.managers.IslandsManager;
|
|||
import world.bentobox.bentobox.managers.PlayersManager;
|
||||
import world.bentobox.bentobox.managers.island.NewIsland;
|
||||
import world.bentobox.bentobox.managers.island.NewIsland.Builder;
|
||||
import world.bentobox.bentobox.panels.IslandCreationPanel;
|
||||
import world.bentobox.bentobox.panels.customizable.IslandCreationPanel;
|
||||
|
||||
/**
|
||||
* @author tastybento
|
||||
|
|
|
@ -50,6 +50,7 @@ public class BentoBoxLocaleTest {
|
|||
ItemFactory itemFactory = mock(ItemFactory.class);
|
||||
bannerMeta = mock(BannerMeta.class);
|
||||
when(itemFactory.getItemMeta(any())).thenReturn(bannerMeta);
|
||||
when(itemFactory.createItemStack(any())).thenThrow(IllegalArgumentException.class);
|
||||
when(Bukkit.getItemFactory()).thenReturn(itemFactory);
|
||||
|
||||
Locale locale = Locale.US;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package world.bentobox.bentobox.panels;
|
||||
package world.bentobox.bentobox.panels.customizable;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
|
@ -7,18 +7,18 @@ import static org.mockito.Mockito.mock;
|
|||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.*;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemFactory;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
@ -43,7 +43,6 @@ import world.bentobox.bentobox.managers.CommandsManager;
|
|||
import world.bentobox.bentobox.managers.IslandWorldManager;
|
||||
import world.bentobox.bentobox.managers.IslandsManager;
|
||||
import world.bentobox.bentobox.managers.PlayersManager;
|
||||
import world.bentobox.bentobox.managers.island.NewIsland.Builder;
|
||||
|
||||
/**
|
||||
* @author tastybento
|
||||
|
@ -60,8 +59,6 @@ public class IslandCreationPanelTest {
|
|||
@Mock
|
||||
private IslandWorldManager iwm;
|
||||
@Mock
|
||||
private Builder builder;
|
||||
@Mock
|
||||
private BentoBox plugin;
|
||||
@Mock
|
||||
private Settings settings;
|
||||
|
@ -78,6 +75,11 @@ public class IslandCreationPanelTest {
|
|||
@Mock
|
||||
private BlueprintBundle bb3;
|
||||
|
||||
/**
|
||||
* Location of the resources folder
|
||||
*/
|
||||
private final Path resourcePath = Paths.get("src","test","resources");
|
||||
|
||||
/**
|
||||
*/
|
||||
@Before
|
||||
|
@ -100,14 +102,25 @@ public class IslandCreationPanelTest {
|
|||
when(user.getUniqueId()).thenReturn(uuid);
|
||||
when(user.getPlayer()).thenReturn(player);
|
||||
when(user.hasPermission(anyString())).thenReturn(true);
|
||||
when(user.getTranslation(any()))
|
||||
.thenAnswer((Answer<String>) invocation -> invocation.getArgument(0, String.class));
|
||||
User.setPlugin(plugin);
|
||||
// Set up user already
|
||||
User.getInstance(player);
|
||||
|
||||
// Addon
|
||||
GameModeAddon addon = mock(GameModeAddon.class);
|
||||
when(addon.getDataFolder()).thenReturn(resourcePath.toFile());
|
||||
|
||||
when(user.getTranslation(any())).thenAnswer((Answer<String>) invocation -> invocation.getArgument(0, String.class));
|
||||
when(user.getTranslation(any(World.class), any(), any())).thenAnswer((Answer<String>) invocation -> invocation.getArgument(1, String.class));
|
||||
when(user.getTranslation(any(String.class), any())).thenAnswer((Answer<String>) invocation -> invocation.getArgument(0, String.class));
|
||||
when(user.getTranslationOrNothing(any(), any())).thenAnswer((Answer<String>) invocation -> invocation.getArgument(0, String.class));
|
||||
|
||||
when(user.getTranslation(any(World.class), eq("panels.island_creation.buttons.bundle.name"), any())).
|
||||
thenAnswer((Answer<String>) invocation -> invocation.getArgument(3, String.class));
|
||||
when(user.getTranslation(any(World.class), eq("panels.island_creation.buttons.bundle.description"), any())).
|
||||
thenAnswer((Answer<String>) invocation -> invocation.getArgument(3, String.class));
|
||||
when(plugin.getDescription()).thenAnswer((Answer<PluginDescriptionFile>) invocation ->
|
||||
new PluginDescriptionFile("BentoBox", "1.0", "world.bentobox.bentobox"));
|
||||
|
||||
// Parent command has no aliases
|
||||
when(ic.getSubCommandAliases()).thenReturn(new HashMap<>());
|
||||
|
@ -117,6 +130,8 @@ public class IslandCreationPanelTest {
|
|||
when(ic.getUsage()).thenReturn("");
|
||||
when(ic.getSubCommand(Mockito.anyString())).thenReturn(Optional.empty());
|
||||
when(ic.getAddon()).thenReturn(addon);
|
||||
World world = mock(World.class);
|
||||
when(ic.getWorld()).thenReturn(world);
|
||||
|
||||
// No island for player to begin with (set it later in the tests)
|
||||
when(im.hasIsland(any(), eq(uuid))).thenReturn(false);
|
||||
|
@ -184,42 +199,41 @@ public class IslandCreationPanelTest {
|
|||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link world.bentobox.bentobox.panels.IslandCreationPanel#openPanel(world.bentobox.bentobox.api.commands.CompositeCommand, world.bentobox.bentobox.api.user.User, java.lang.String)}.
|
||||
* {@link world.bentobox.bentobox.panels.customizable.IslandCreationPanel#openPanel(world.bentobox.bentobox.api.commands.CompositeCommand, world.bentobox.bentobox.api.user.User, java.lang.String)}.
|
||||
*/
|
||||
@Test
|
||||
public void testOpenPanel() {
|
||||
IslandCreationPanel.openPanel(ic, user, "");
|
||||
// Check for slot being set to 0
|
||||
verify(bb2).setSlot(eq(0));
|
||||
verify(bb3).setSlot(eq(0));
|
||||
|
||||
// Set correctly
|
||||
verify(inv).setItem(eq(5), any());
|
||||
verify(inv).setItem(eq(0), any());
|
||||
verify(inv).setItem(eq(1), any());
|
||||
verify(meta).setDisplayName(eq("test"));
|
||||
verify(meta).setLocalizedName(eq("test"));
|
||||
verify(meta).setLore(eq(Collections.singletonList("A description")));
|
||||
verify(meta).setLore(eq(List.of("A description", "", "panels.tips.click-to-choose")));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link world.bentobox.bentobox.panels.IslandCreationPanel#openPanel(world.bentobox.bentobox.api.commands.CompositeCommand, world.bentobox.bentobox.api.user.User, java.lang.String)}.
|
||||
* Test method for {@link world.bentobox.bentobox.panels.customizable.IslandCreationPanel#openPanel(world.bentobox.bentobox.api.commands.CompositeCommand, world.bentobox.bentobox.api.user.User, java.lang.String)}.
|
||||
*/
|
||||
@Test
|
||||
public void testOpenPanelSameSlot() {
|
||||
when(bb2.getSlot()).thenReturn(5);
|
||||
when(bb3.getSlot()).thenReturn(5);
|
||||
IslandCreationPanel.openPanel(ic, user, "");
|
||||
verify(inv).setItem(eq(5), any());
|
||||
verify(inv).setItem(eq(0), any());
|
||||
verify(inv).setItem(eq(1), any());
|
||||
verify(meta).setDisplayName(eq("test"));
|
||||
verify(meta).setLocalizedName(eq("test"));
|
||||
verify(meta).setLore(eq(Collections.singletonList("A description")));
|
||||
verify(meta).setLore(eq(List.of("A description", "", "panels.tips.click-to-choose")));
|
||||
verify(inv).setItem(eq(0), any());
|
||||
verify(meta).setDisplayName(eq("test2"));
|
||||
verify(meta).setLocalizedName(eq("test2"));
|
||||
verify(meta).setLore(eq(Collections.singletonList("A description 2")));
|
||||
verify(meta).setLore(eq(List.of("A description 2", "", "panels.tips.click-to-choose")));
|
||||
verify(inv).setItem(eq(1), any());
|
||||
verify(meta).setDisplayName(eq("test3"));
|
||||
verify(meta).setLocalizedName(eq("test3"));
|
||||
verify(meta).setLore(eq(Collections.singletonList("A description 3")));
|
||||
|
||||
verify(meta).setLore(eq(List.of("A description 3", "", "panels.tips.click-to-choose")));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,28 +1,15 @@
|
|||
package world.bentobox.bentobox.panels;
|
||||
package world.bentobox.bentobox.panels.customizable;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.awt.Panel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemFactory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
@ -36,14 +23,23 @@ import org.powermock.api.mockito.PowerMockito;
|
|||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
import org.powermock.reflect.Whitebox;
|
||||
import java.awt.Panel;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.*;
|
||||
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.api.addons.GameModeAddon;
|
||||
import world.bentobox.bentobox.api.commands.CompositeCommand;
|
||||
import world.bentobox.bentobox.api.localization.BentoBoxLocale;
|
||||
import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.managers.LocalesManager;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* @author tastybento
|
||||
*
|
||||
|
@ -61,20 +57,24 @@ public class LanguagePanelTest {
|
|||
|
||||
private ArrayList<Locale> localeList;
|
||||
|
||||
@Mock
|
||||
private PanelBuilder pb;
|
||||
@Mock
|
||||
private Panel panel;
|
||||
@Mock
|
||||
private Inventory inv;
|
||||
@Mock
|
||||
private ItemMeta meta;
|
||||
|
||||
@Mock
|
||||
private CompositeCommand command;
|
||||
|
||||
@Captor
|
||||
private ArgumentCaptor<ItemStack> argument;
|
||||
|
||||
private Map<Locale, BentoBoxLocale> map;
|
||||
|
||||
/**
|
||||
* Location of the resources folder
|
||||
*/
|
||||
private final Path resourcePath = Paths.get("src","test","resources");
|
||||
|
||||
/**
|
||||
*/
|
||||
@Before
|
||||
|
@ -90,7 +90,24 @@ public class LanguagePanelTest {
|
|||
when(user.getPlayer()).thenReturn(player);
|
||||
when(user.hasPermission(anyString())).thenReturn(true);
|
||||
when(user.getTranslation(any())).thenAnswer((Answer<String>) invocation -> invocation.getArgument(0, String.class));
|
||||
when(user.getTranslation(any(World.class), any(), any())).thenAnswer((Answer<String>) invocation -> invocation.getArgument(1, String.class));
|
||||
when(user.getTranslation(any(String.class), any())).thenAnswer((Answer<String>) invocation -> invocation.getArgument(0, String.class));
|
||||
when(user.getTranslationOrNothing(any(), any())).thenAnswer((Answer<String>) invocation -> invocation.getArgument(0, String.class));
|
||||
when(user.getLocale()).thenReturn(Locale.ENGLISH);
|
||||
|
||||
when(user.getTranslation(any(World.class), eq("panels.language.buttons.language.name"), any())).
|
||||
thenAnswer((Answer<String>) invocation -> invocation.getArgument(3, String.class));
|
||||
|
||||
GameModeAddon addon = mock(GameModeAddon.class);
|
||||
when(command.getAddon()).thenReturn(addon);
|
||||
when(addon.getDataFolder()).thenReturn(resourcePath.toFile());
|
||||
|
||||
World world = mock(World.class);
|
||||
when(command.getWorld()).thenReturn(world);
|
||||
|
||||
when(plugin.getDescription()).thenAnswer((Answer<PluginDescriptionFile>) invocation ->
|
||||
new PluginDescriptionFile("BentoBox", "1.0", "world.bentobox.bentobox"));
|
||||
|
||||
User.setPlugin(plugin);
|
||||
// Set up user already
|
||||
User.getInstance(player);
|
||||
|
@ -123,17 +140,17 @@ public class LanguagePanelTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link world.bentobox.bentobox.panels.LanguagePanel#openPanel(world.bentobox.bentobox.api.user.User)}.
|
||||
* Test method for {@link world.bentobox.bentobox.panels.customizable.LanguagePanel#openPanel(world.bentobox.bentobox.api.commands.CompositeCommand,world.bentobox.bentobox.api.user.User)}.
|
||||
*/
|
||||
@Test
|
||||
public void testOpenPanelNoLocales() {
|
||||
LanguagePanel.openPanel(user);
|
||||
LanguagePanel.openPanel(command, user);
|
||||
verify(plugin).getLocalesManager();
|
||||
verify(lm).getAvailableLocales(eq(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link world.bentobox.bentobox.panels.LanguagePanel#openPanel(world.bentobox.bentobox.api.user.User)}.
|
||||
* Test method for {@link world.bentobox.bentobox.panels.customizable.LanguagePanel#openPanel(world.bentobox.bentobox.api.commands.CompositeCommand,world.bentobox.bentobox.api.user.User)}.
|
||||
*/
|
||||
@Test
|
||||
public void testOpenPanelLocalesNullBanner() {
|
||||
|
@ -146,29 +163,30 @@ public class LanguagePanelTest {
|
|||
map.put(Locale.CHINA, bbl);
|
||||
map.put(Locale.ENGLISH, bbl);
|
||||
|
||||
LanguagePanel.openPanel(user);
|
||||
LanguagePanel.openPanel(command, user);
|
||||
verify(lm, times(3)).getLanguages();
|
||||
verify(bbl, times(3)).getBanner();
|
||||
verify(user).getTranslation("language.panel-title");
|
||||
verify(user).getTranslation("panels.language.title");
|
||||
// Other langs
|
||||
verify(user, times(2)).getTranslation(eq("language.description.click-to-select"));
|
||||
verify(user, times(3)).getTranslation(eq("language.description.authors"));
|
||||
// Selected language
|
||||
verify(user, Mockito.atMostOnce()).getTranslation(eq("language.description.selected"));
|
||||
verify(user, times(3)).getTranslation(eq("panels.language.buttons.language.authors"));
|
||||
verify(user, times(1)).getTranslation(eq("panels.language.buttons.language.selected"));
|
||||
verify(user, times(3)).getTranslationOrNothing(eq("panels.language.buttons.language.description"), any());
|
||||
verify(user, times(2)).getTranslation(any(World.class), eq("panels.tips.click-to-choose"));
|
||||
|
||||
verify(inv).setItem(eq(0), argument.capture());
|
||||
assertEquals(Material.WHITE_BANNER, argument.getValue().getType());
|
||||
assertEquals(1, argument.getValue().getAmount());
|
||||
assertEquals(meta, argument.getValue().getItemMeta());
|
||||
verify(meta).setDisplayName(eq(ChatColor.WHITE + "Chinese (China)"));
|
||||
verify(meta).setDisplayName(eq(ChatColor.WHITE + "English (Canada)"));
|
||||
|
||||
verify(meta).setDisplayName(eq("Chinese (China)"));
|
||||
verify(meta).setDisplayName(eq("English (Canada)"));
|
||||
verify(inv).setItem(eq(1), any());
|
||||
verify(inv).setItem(eq(2), any());
|
||||
verify(inv, Mockito.never()).setItem(eq(3), any());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link world.bentobox.bentobox.panels.LanguagePanel#openPanel(world.bentobox.bentobox.api.user.User)}.
|
||||
* Test method for {@link world.bentobox.bentobox.panels.customizable.LanguagePanel#openPanel(world.bentobox.bentobox.api.commands.CompositeCommand,world.bentobox.bentobox.api.user.User)}.
|
||||
*/
|
||||
@Test
|
||||
public void testOpenPanelLocalesNotNullBanner() {
|
||||
|
@ -178,7 +196,7 @@ public class LanguagePanelTest {
|
|||
map.put(Locale.CANADA, bbl);
|
||||
when(bbl.getBanner()).thenReturn(new ItemStack(Material.CYAN_BANNER));
|
||||
|
||||
LanguagePanel.openPanel(user);
|
||||
LanguagePanel.openPanel(command, user);
|
||||
verify(inv).setItem(eq(0), argument.capture());
|
||||
assertEquals(Material.CYAN_BANNER, argument.getValue().getType());
|
||||
}
|
|
@ -21,8 +21,10 @@ import org.bukkit.inventory.ItemStack;
|
|||
import org.bukkit.inventory.meta.BannerMeta;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.inventory.meta.PotionMeta;
|
||||
import org.bukkit.inventory.meta.SkullMeta;
|
||||
import org.bukkit.potion.PotionData;
|
||||
import org.bukkit.potion.PotionType;
|
||||
import org.bukkit.profile.PlayerProfile;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
|
@ -50,6 +52,9 @@ public class ItemParserTest {
|
|||
private ItemMeta itemMeta;
|
||||
@Mock
|
||||
private ItemFactory itemFactory;
|
||||
@Mock
|
||||
private SkullMeta skullMeta;
|
||||
|
||||
private ItemStack defaultItem;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
|
@ -61,6 +66,8 @@ public class ItemParserTest {
|
|||
|
||||
PowerMockito.mockStatic(Bukkit.class);
|
||||
when(Bukkit.getItemFactory()).thenReturn(itemFactory);
|
||||
// Do not test Bukkit createItemStack method output as I assume Bukkit has their tests covered.
|
||||
when(itemFactory.createItemStack(any())).thenThrow(IllegalArgumentException.class);
|
||||
/*
|
||||
when(itemFactory.getItemMeta(Mockito.eq(Material.POTION))).thenReturn(potionMeta);
|
||||
when(itemFactory.getItemMeta(Mockito.eq(Material.SPLASH_POTION))).thenReturn(potionMeta);
|
||||
|
@ -106,148 +113,66 @@ public class ItemParserTest {
|
|||
assertEquals(defaultItem, ItemParser.parse("NOCOLONS", defaultItem));
|
||||
}
|
||||
|
||||
/*
|
||||
* # Format POTION:NAME:<LEVEL>:<EXTENDED>:<SPLASH/LINGER>:QTY
|
||||
# LEVEL, EXTENDED, SPLASH, LINGER are optional.
|
||||
# LEVEL is a number, 1 or 2
|
||||
# LINGER is for V1.9 servers and later
|
||||
# Examples:
|
||||
# POTION:STRENGTH:1:EXTENDED:SPLASH:1
|
||||
# POTION:INSTANT_DAMAGE:2::LINGER:2
|
||||
# POTION:JUMP:2:NOTEXTENDED:NOSPLASH:1
|
||||
# POTION:WEAKNESS::::1 - any weakness potion
|
||||
*/
|
||||
|
||||
@Ignore("Extended potions now have their own names and are not extended like this")
|
||||
@Test
|
||||
public void testParsePotionStrengthExtended() {
|
||||
when(itemFactory.getItemMeta(any())).thenReturn(potionMeta);
|
||||
ItemStack result = ItemParser.parse("POTION:STRENGTH:1:EXTENDED::5");
|
||||
assertNotNull(result);
|
||||
assertEquals(Material.POTION, result.getType());
|
||||
PotionType type = PotionType.STRENGTH;
|
||||
boolean isExtended = true;
|
||||
boolean isUpgraded = false;
|
||||
PotionData data = new PotionData(type, isExtended, isUpgraded);
|
||||
verify(potionMeta).setBasePotionData(Mockito.eq(data));
|
||||
assertEquals(5, result.getAmount());
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Test
|
||||
public void testParsePotionStrengthNotExtended() {
|
||||
when(itemFactory.getItemMeta(any())).thenReturn(potionMeta);
|
||||
ItemStack result = ItemParser.parse("POTION:STRENGTH:1:::4");
|
||||
assertNotNull(result);
|
||||
assertEquals(Material.POTION, result.getType());
|
||||
PotionType type = PotionType.STRENGTH;
|
||||
boolean isExtended = false;
|
||||
boolean isUpgraded = false;
|
||||
PotionData data = new PotionData(type, isExtended, isUpgraded);
|
||||
verify(potionMeta).setBasePotionData(Mockito.eq(data));
|
||||
assertEquals(4, result.getAmount());
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Test
|
||||
public void testParsePotionStrengthNotExtendedSplash() {
|
||||
when(itemFactory.getItemMeta(any())).thenReturn(potionMeta);
|
||||
ItemStack result = ItemParser.parse("POTION:STRENGTH:1::SPLASH:3");
|
||||
assertNotNull(result);
|
||||
assertEquals(Material.SPLASH_POTION, result.getType());
|
||||
PotionType type = PotionType.STRENGTH;
|
||||
boolean isExtended = false;
|
||||
boolean isUpgraded = false;
|
||||
PotionData data = new PotionData(type, isExtended, isUpgraded);
|
||||
verify(potionMeta).setBasePotionData(Mockito.eq(data));
|
||||
assertEquals(3, result.getAmount());
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Ignore("Potions are no longer upgraded like this")
|
||||
@Test
|
||||
public void testParsePotionStrengthNotExtendedUpgradedSplash() {
|
||||
when(itemFactory.getItemMeta(any())).thenReturn(potionMeta);
|
||||
ItemStack result = ItemParser.parse("POTION:STRENGTH:2::SPLASH:3");
|
||||
assertNotNull(result);
|
||||
assertEquals(Material.SPLASH_POTION, result.getType());
|
||||
PotionType type = PotionType.STRENGTH;
|
||||
boolean isExtended = false;
|
||||
boolean isUpgraded = true;
|
||||
PotionData data = new PotionData(type, isExtended, isUpgraded);
|
||||
verify(potionMeta).setBasePotionData(Mockito.eq(data));
|
||||
assertEquals(3, result.getAmount());
|
||||
}
|
||||
|
||||
enum extend {
|
||||
NOT_EXTENDED,
|
||||
EXTENDED
|
||||
}
|
||||
|
||||
enum type {
|
||||
NO_SPLASH,
|
||||
SPLASH,
|
||||
LINGER
|
||||
}
|
||||
|
||||
List<PotionType> notExtendable = Arrays.asList(
|
||||
PotionType.UNCRAFTABLE,
|
||||
PotionType.WATER,
|
||||
PotionType.MUNDANE,
|
||||
PotionType.THICK,
|
||||
PotionType.AWKWARD,
|
||||
PotionType.INSTANT_HEAL,
|
||||
PotionType.INSTANT_DAMAGE,
|
||||
PotionType.LUCK,
|
||||
PotionType.NIGHT_VISION
|
||||
);
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Test
|
||||
public void testParsePotion() {
|
||||
when(itemFactory.getItemMeta(any())).thenReturn(potionMeta);
|
||||
for (PotionType type : PotionType.values()) {
|
||||
if (type.name().contains("LONG") || type.name().contains("STRONG")) {
|
||||
continue;
|
||||
}
|
||||
for (ItemParserTest.type t: ItemParserTest.type.values()) {
|
||||
for (int up = 1; up < 2; up++) {
|
||||
boolean isUpgraded = up > 1;
|
||||
String req = "POTION:" + type.name() + ":" + up + "::"+ t.name() + ":3";
|
||||
ItemStack result = ItemParser.parse(req);
|
||||
assertNotNull(result);
|
||||
switch (t) {
|
||||
case LINGER:
|
||||
assertEquals(Material.LINGERING_POTION, result.getType());
|
||||
PotionData data = new PotionData(type, false, isUpgraded);
|
||||
verify(potionMeta, times(3)).setBasePotionData(Mockito.eq(data));
|
||||
break;
|
||||
case NO_SPLASH:
|
||||
assertEquals(Material.POTION, result.getType());
|
||||
data = new PotionData(type, false, isUpgraded);
|
||||
verify(potionMeta).setBasePotionData(Mockito.eq(data));
|
||||
break;
|
||||
case SPLASH:
|
||||
assertEquals(Material.SPLASH_POTION, result.getType());
|
||||
data = new PotionData(type, false, isUpgraded);
|
||||
verify(potionMeta, times(2)).setBasePotionData(Mockito.eq(data));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ItemStack itemStack = ItemParser.parse("POTION:" + type.name() + ":1");
|
||||
assertEquals(itemStack.getType(), Material.POTION);
|
||||
// Not sure how this can be tested.
|
||||
// assertEquals(type, ((PotionMeta) itemStack.getItemMeta()).getBasePotionType());
|
||||
assertEquals(1, itemStack.getAmount());
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals(3, result.getAmount());
|
||||
}
|
||||
}
|
||||
@Test
|
||||
public void testParseSplashPotion() {
|
||||
when(itemFactory.getItemMeta(any())).thenReturn(potionMeta);
|
||||
for (PotionType type : PotionType.values()) {
|
||||
ItemStack itemStack = ItemParser.parse("SPLASH_POTION:" + type.name() + ":1");
|
||||
assertEquals(itemStack.getType(), Material.SPLASH_POTION);
|
||||
// Not sure how this can be tested.
|
||||
// assertEquals(type, ((PotionMeta) itemStack.getItemMeta()).getBasePotionType());
|
||||
assertEquals(1, itemStack.getAmount());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseLingeringPotion() {
|
||||
when(itemFactory.getItemMeta(any())).thenReturn(potionMeta);
|
||||
for (PotionType type : PotionType.values()) {
|
||||
ItemStack itemStack = ItemParser.parse("LINGERING_POTION:" + type.name() + ":1");
|
||||
assertEquals(itemStack.getType(), Material.LINGERING_POTION);
|
||||
// Not sure how this can be tested.
|
||||
// assertEquals(type, ((PotionMeta) itemStack.getItemMeta()).getBasePotionType());
|
||||
assertEquals(1, itemStack.getAmount());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseTippedArrow() {
|
||||
when(itemFactory.getItemMeta(any())).thenReturn(potionMeta);
|
||||
ItemStack result = ItemParser.parse("TIPPED_ARROW:WEAKNESS::::1");
|
||||
assertNotNull(result);
|
||||
assertEquals(Material.TIPPED_ARROW, result.getType());
|
||||
for (PotionType type : PotionType.values()) {
|
||||
ItemStack itemStack = ItemParser.parse("TIPPED_ARROW:" + type.name() + ":1");
|
||||
assertEquals(itemStack.getType(), Material.TIPPED_ARROW);
|
||||
// Not sure how this can be tested.
|
||||
// assertEquals(type, ((PotionMeta) itemStack.getItemMeta()).getBasePotionType());
|
||||
assertEquals(1, itemStack.getAmount());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseBadPotion()
|
||||
{
|
||||
when(itemFactory.getItemMeta(any())).thenReturn(potionMeta);
|
||||
ItemStack itemStack = ItemParser.parse("POTION::5");
|
||||
assertEquals(5, itemStack.getAmount());
|
||||
// Not sure how this can be tested
|
||||
// assertEquals(PotionType.WATER, ((PotionMeta) itemStack.getItemMeta()).getBasePotionType());
|
||||
itemStack = ItemParser.parse("POTION:NO_POTION:1");
|
||||
assertEquals(1, itemStack.getAmount());
|
||||
// Not sure how this can be tested
|
||||
// assertEquals(PotionType.WATER, ((PotionMeta) itemStack.getItemMeta()).getBasePotionType());
|
||||
}
|
||||
|
||||
|
||||
|
@ -318,7 +243,6 @@ public class ItemParserTest {
|
|||
assertEquals(defaultItem, ItemParser.parse("WOODEN_SWORD:4:AA", defaultItem));
|
||||
}
|
||||
|
||||
@Ignore("This doesn't work for some reason")
|
||||
@Test
|
||||
public void parseCustomModelData() {
|
||||
ItemStack result = ItemParser.parse("WOODEN_SWORD:CMD-23151212:2");
|
||||
|
@ -327,4 +251,21 @@ public class ItemParserTest {
|
|||
assertEquals(2, result.getAmount());
|
||||
assertNull(ItemParser.parse("WOODEN_SWORD:CMD-23151212:2:CMD-23151212"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parsePlayerHead() {
|
||||
when(itemFactory.getItemMeta(any())).thenReturn(skullMeta);
|
||||
ItemStack result = ItemParser.parse("PLAYER_HEAD:2");
|
||||
assertNotNull(result);
|
||||
assertEquals(Material.PLAYER_HEAD, result.getType());
|
||||
assertEquals(2, result.getAmount());
|
||||
|
||||
result = ItemParser.parse("PLAYER_HEAD:BONNe1704");
|
||||
assertNotNull(result);
|
||||
assertEquals(Material.PLAYER_HEAD, result.getType());
|
||||
assertEquals(1, result.getAmount());
|
||||
|
||||
// I do not know if it is possible to test metadata, as skull meta is not applied to player heads in testing.
|
||||
//assertEquals("BONNe1704", ((SkullMeta) result.getItemMeta()).getOwnerProfile().getName());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
# This is default island creation panel. It is used in all situations when gamemode addon does not have specified their
|
||||
# of panel.
|
||||
island_creation_panel:
|
||||
title: panels.island_creation.title # The title of panel or link to the localization location.
|
||||
type: INVENTORY # The type of inventory: INVENTORY, DROPPER, HOPPER
|
||||
force-shown: [] # Allow to specify (1-6, 1-3, 1) which rows must be showed regardless of empty elements.
|
||||
content: # Allow to define buttons in your panel.
|
||||
1:
|
||||
1: blueprint_bundle_button # String values are expected to be `reusables` that are defined at the end of this file.
|
||||
2: blueprint_bundle_button
|
||||
3: blueprint_bundle_button
|
||||
4: blueprint_bundle_button
|
||||
5: blueprint_bundle_button
|
||||
6: blueprint_bundle_button
|
||||
7: blueprint_bundle_button
|
||||
8: blueprint_bundle_button
|
||||
9: blueprint_bundle_button
|
||||
reusable: # List of reoccurring buttons in the panels.
|
||||
blueprint_bundle_button: # The ID of the button
|
||||
# icon: GRASS_BLOCK
|
||||
title: panels.island_creation.buttons.bundle.name
|
||||
description: panels.island_creation.buttons.bundle.description
|
||||
data:
|
||||
type: BUNDLE
|
||||
# unique_id: default # Specifying unique_id will force to show the requested bundle if it is available.
|
||||
actions:
|
||||
select:
|
||||
click-type: UNKNOWN
|
||||
tooltip: panels.tips.click-to-choose
|
|
@ -0,0 +1,29 @@
|
|||
# This is default language selection panel. It is used in all situations when gamemode addon does not have specified their
|
||||
# of panel.
|
||||
language_panel:
|
||||
title: panels.language.title # The title of panel or link to the localization location.
|
||||
type: INVENTORY # The type of inventory: INVENTORY, DROPPER, HOPPER
|
||||
force-shown: [] # Allow to specify (1-6, 1-3, 1) which rows must be showed regardless of empty elements.
|
||||
content: # Allow to define buttons in your panel.
|
||||
1:
|
||||
1: language_button # String values are expected to be `reusables` that are defined at the end of this file.
|
||||
2: language_button
|
||||
3: language_button
|
||||
4: language_button
|
||||
5: language_button
|
||||
6: language_button
|
||||
7: language_button
|
||||
8: language_button
|
||||
9: language_button
|
||||
reusable: # List of reoccurring buttons in the panels.
|
||||
language_button: # The ID of the button
|
||||
# icon: GRASS_BLOCK
|
||||
title: panels.language.buttons.language.name
|
||||
description: panels.language.buttons.language.description
|
||||
data:
|
||||
type: LOCALE
|
||||
# lang_id: default # Specifying lang_id will force to show the requested locale if it is available.
|
||||
actions:
|
||||
select:
|
||||
click-type: UNKNOWN
|
||||
tooltip: panels.tips.click-to-choose
|
Loading…
Reference in New Issue