mirror of
https://github.com/BentoBoxWorld/BentoBox.git
synced 2024-11-27 13:15:28 +01:00
Merge branch 'develop' of https://github.com/BentoBoxWorld/BentoBox.git into develop
This commit is contained in:
commit
969b413588
@ -138,12 +138,28 @@ public class Settings implements ConfigObject {
|
||||
@ConfigEntry(path = "panel.filler-material", since = "1.14.0")
|
||||
private Material panelFillerMaterial = Material.LIGHT_BLUE_STAINED_GLASS_PANE;
|
||||
|
||||
@ConfigComment("Toggle whether player head texture should be gathered from Mojang API or mc-heads.net cache server.")
|
||||
@ConfigComment("Mojang API sometime may be slow and may limit requests to the player data, so this will allow to")
|
||||
@ConfigComment("get player heads a bit faster then Mojang API.")
|
||||
@ConfigEntry(path = "panel.use-cache-server", since = "1.16.0")
|
||||
private boolean useCacheServer = false;
|
||||
|
||||
@ConfigComment("Defines how long player skin texture link is stored into local cache before it is requested again.")
|
||||
@ConfigComment("Defined value is in the minutes.")
|
||||
@ConfigComment("Value 0 will not clear cache until server restart.")
|
||||
@ConfigEntry(path = "panel.head-cache-time", since = "1.14.1")
|
||||
private long playerHeadCacheTime = 60;
|
||||
|
||||
@ConfigComment("Defines a number of player heads requested per tasks.")
|
||||
@ConfigComment("Setting it too large may lead to temporarily being blocked from head gatherer API.")
|
||||
@ConfigEntry(path = "panel.heads-per-call", since = "1.16.0")
|
||||
private int headsPerCall = 9;
|
||||
|
||||
@ConfigComment("Defines a number of ticks between each player head request task.")
|
||||
@ConfigComment("Setting it too large may lead to temporarily being blocked from head gatherer API.")
|
||||
@ConfigEntry(path = "panel.ticks-between-calls", since = "1.16.0", needsRestart = true)
|
||||
private long ticksBetweenCalls = 10;
|
||||
|
||||
/*
|
||||
* Logs
|
||||
*/
|
||||
@ -783,4 +799,76 @@ public class Settings implements ConfigObject {
|
||||
{
|
||||
this.playerHeadCacheTime = playerHeadCacheTime;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Is use cache server boolean.
|
||||
*
|
||||
* @return the boolean
|
||||
* @since 1.16.0
|
||||
*/
|
||||
public boolean isUseCacheServer()
|
||||
{
|
||||
return useCacheServer;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets use cache server.
|
||||
*
|
||||
* @param useCacheServer the use cache server
|
||||
* @since 1.16.0
|
||||
*/
|
||||
public void setUseCacheServer(boolean useCacheServer)
|
||||
{
|
||||
this.useCacheServer = useCacheServer;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets heads per call.
|
||||
*
|
||||
* @return the heads per call
|
||||
* @since 1.16.0
|
||||
*/
|
||||
public int getHeadsPerCall()
|
||||
{
|
||||
return headsPerCall;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets heads per call.
|
||||
*
|
||||
* @param headsPerCall the heads per call
|
||||
* @since 1.16.0
|
||||
*/
|
||||
public void setHeadsPerCall(int headsPerCall)
|
||||
{
|
||||
this.headsPerCall = headsPerCall;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets ticks between calls.
|
||||
*
|
||||
* @return the ticks between calls
|
||||
* @since 1.16.0
|
||||
*/
|
||||
public long getTicksBetweenCalls()
|
||||
{
|
||||
return ticksBetweenCalls;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets ticks between calls.
|
||||
*
|
||||
* @param ticksBetweenCalls the ticks between calls
|
||||
* @since 1.16.0
|
||||
*/
|
||||
public void setTicksBetweenCalls(long ticksBetweenCalls)
|
||||
{
|
||||
this.ticksBetweenCalls = ticksBetweenCalls;
|
||||
}
|
||||
}
|
||||
|
@ -78,9 +78,9 @@ public class AdminSettingsCommand extends CompositeCommand {
|
||||
// Player settings
|
||||
new TabbedPanelBuilder()
|
||||
.user(user)
|
||||
.world(getWorld())
|
||||
.tab(1, new SettingsTab(getWorld(), user, island, Flag.Type.PROTECTION))
|
||||
.tab(2, new SettingsTab(getWorld(), user, island, Flag.Type.SETTING))
|
||||
.world(island.getWorld())
|
||||
.tab(1, new SettingsTab(user, island, Flag.Type.PROTECTION))
|
||||
.tab(2, new SettingsTab(user, island, Flag.Type.SETTING))
|
||||
.startingSlot(1)
|
||||
.size(54)
|
||||
.build().openPanel();
|
||||
|
@ -15,6 +15,8 @@ import world.bentobox.bentobox.util.Util;
|
||||
*/
|
||||
public class IslandSettingsCommand extends CompositeCommand {
|
||||
|
||||
private Island island;
|
||||
|
||||
public IslandSettingsCommand(CompositeCommand islandCommand) {
|
||||
super(islandCommand, "settings", "flags", "options");
|
||||
}
|
||||
@ -28,23 +30,26 @@ public class IslandSettingsCommand extends CompositeCommand {
|
||||
|
||||
@Override
|
||||
public boolean canExecute(User user, String label, List<String> args) {
|
||||
// Settings are only shown if you are in the right world
|
||||
if (Util.getWorld(user.getWorld()).equals(getWorld())) {
|
||||
return true;
|
||||
// Player is in same world
|
||||
island = getIslands().getIslandAt(user.getLocation()).orElseGet(() -> getIslands().getIsland(user.getWorld(), user.getUniqueId()));
|
||||
} else {
|
||||
user.sendMessage("general.errors.wrong-world");
|
||||
island = getIslands().getIsland(getWorld(), user);
|
||||
}
|
||||
if (island == null) {
|
||||
user.sendMessage("general.errors.no-island");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(User user, String label, List<String> args) {
|
||||
Island island = getIslands().getIslandAt(user.getLocation()).orElseGet(() -> getIslands().getIsland(user.getWorld(), user.getUniqueId()));
|
||||
new TabbedPanelBuilder()
|
||||
.user(user)
|
||||
.world(getWorld())
|
||||
.tab(1, new SettingsTab(getWorld(), user, island, Flag.Type.PROTECTION))
|
||||
.tab(2, new SettingsTab(getWorld(), user, island, Flag.Type.SETTING))
|
||||
.world(island.getWorld())
|
||||
.tab(1, new SettingsTab(user, island, Flag.Type.PROTECTION))
|
||||
.tab(2, new SettingsTab(user, island, Flag.Type.SETTING))
|
||||
.startingSlot(1)
|
||||
.size(54)
|
||||
.hideIfEmpty()
|
||||
|
@ -4,12 +4,14 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.InventoryType;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.InventoryHolder;
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
|
||||
import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.listeners.PanelListenerManager;
|
||||
import world.bentobox.bentobox.util.heads.HeadGetter;
|
||||
@ -27,6 +29,7 @@ public class Panel implements HeadRequester, InventoryHolder {
|
||||
private PanelListener listener;
|
||||
private User user;
|
||||
private String name;
|
||||
private World world;
|
||||
|
||||
/**
|
||||
* Various types of Panel that can be created.
|
||||
@ -51,6 +54,17 @@ public class Panel implements HeadRequester, InventoryHolder {
|
||||
makePanel(name, items, size, user, listener, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param pb - PanelBuilder
|
||||
* @since 1.16.0
|
||||
*/
|
||||
public Panel(PanelBuilder pb) {
|
||||
this.world = pb.getWorld();
|
||||
this.makePanel(pb.getName(), pb.getItems(),
|
||||
Math.max(pb.getSize(), pb.getItems().isEmpty() ? pb.getSize() : pb.getItems().lastKey() + 1),
|
||||
pb.getUser(), pb.getListener(), pb.getPanelType());
|
||||
}
|
||||
|
||||
protected void makePanel(String name, Map<Integer, PanelItem> items, int size, User user,
|
||||
PanelListener listener) {
|
||||
this.makePanel(name, items, size, user, listener, Type.INVENTORY);
|
||||
@ -200,4 +214,23 @@ public class Panel implements HeadRequester, InventoryHolder {
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the world that applies to this panel
|
||||
* @return the optional world
|
||||
* @since 1.16.0
|
||||
*/
|
||||
public Optional<World> getWorld() {
|
||||
return Optional.ofNullable(world);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param world the world to set
|
||||
* @since 1.16.0
|
||||
*/
|
||||
public void setWorld(World world) {
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -42,6 +42,7 @@ public class TabbedPanel extends Panel implements PanelListener {
|
||||
*/
|
||||
public TabbedPanel(TabbedPanelBuilder tpb) {
|
||||
this.tpb = tpb;
|
||||
this.setWorld(tpb.getWorld());
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
|
@ -4,6 +4,7 @@ import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.World;
|
||||
|
||||
import world.bentobox.bentobox.api.panels.Panel;
|
||||
import world.bentobox.bentobox.api.panels.PanelItem;
|
||||
@ -22,6 +23,7 @@ public class PanelBuilder {
|
||||
private User user;
|
||||
private PanelListener listener;
|
||||
private Panel.Type type = Panel.Type.INVENTORY;
|
||||
private World world;
|
||||
|
||||
public PanelBuilder name(String name) {
|
||||
this.name = ChatColor.translateAlternateColorCodes('&', name);
|
||||
@ -115,13 +117,22 @@ public class PanelBuilder {
|
||||
return items.containsKey(slot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the game world that applies this panel
|
||||
* @param world
|
||||
* @return PanelBuilder
|
||||
*/
|
||||
public PanelBuilder world(World world) {
|
||||
this.world = world;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the panel
|
||||
* @return Panel
|
||||
*/
|
||||
public Panel build() {
|
||||
// items.lastKey() is a slot position, so the panel size is this value + 1
|
||||
return new Panel(name, items, Math.max(size, items.isEmpty() ? size : items.lastKey() + 1), user, listener, type);
|
||||
return new Panel(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -167,4 +178,14 @@ public class PanelBuilder {
|
||||
public Panel.Type getPanelType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the world
|
||||
* @since 1.16.0
|
||||
*/
|
||||
public World getWorld() {
|
||||
return world;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package world.bentobox.bentobox.listeners.flags.clicklisteners;
|
||||
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
@ -32,8 +33,9 @@ public class CommandCycleClick implements ClickHandler {
|
||||
public boolean onClick(Panel panel, User user, ClickType click, int slot) {
|
||||
// Left clicking increases the rank required
|
||||
// Right clicking decreases the rank required
|
||||
// Get the user's island
|
||||
Island island = plugin.getIslands().getIsland(user.getWorld(), user.getUniqueId());
|
||||
// Get the user's island for the game world
|
||||
World world = panel.getWorld().orElse(user.getWorld());
|
||||
Island island = plugin.getIslands().getIsland(world, user.getUniqueId());
|
||||
if (island != null && island.getOwner().equals(user.getUniqueId())) {
|
||||
RanksManager rm = plugin.getRanksManager();
|
||||
int currentRank = island.getRankCommand(command);
|
||||
@ -53,7 +55,7 @@ public class CommandCycleClick implements ClickHandler {
|
||||
user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_STONE_BUTTON_CLICK_ON, 1F, 1F);
|
||||
}
|
||||
// Apply change to panel
|
||||
panel.getInventory().setItem(slot, commandRankClickListener.getPanelItem(command, user).getItem());
|
||||
panel.getInventory().setItem(slot, commandRankClickListener.getPanelItem(command, user, world).getItem());
|
||||
// Save island
|
||||
plugin.getIslands().save(island);
|
||||
|
||||
|
@ -43,7 +43,7 @@ public class CommandRankClickListener implements ClickHandler {
|
||||
}
|
||||
|
||||
// Check if has permission
|
||||
String prefix = plugin.getIWM().getPermissionPrefix(Util.getWorld(user.getWorld()));
|
||||
String prefix = plugin.getIWM().getPermissionPrefix(Util.getWorld(panel.getWorld().orElse(user.getWorld())));
|
||||
String reqPerm = prefix + "settings." + Flags.COMMAND_RANKS.getID();
|
||||
String allPerms = prefix + "settings.*";
|
||||
if (!user.hasPermission(reqPerm) && !user.hasPermission(allPerms)
|
||||
@ -54,7 +54,7 @@ public class CommandRankClickListener implements ClickHandler {
|
||||
}
|
||||
|
||||
// Get the user's island
|
||||
Island island = plugin.getIslands().getIsland(user.getWorld(), user.getUniqueId());
|
||||
Island island = plugin.getIslands().getIsland(panel.getWorld().orElse(user.getWorld()), user.getUniqueId());
|
||||
if (island == null || !island.getOwner().equals(user.getUniqueId())) {
|
||||
user.sendMessage("general.errors.not-owner");
|
||||
user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_METAL_HIT, 1F, 1F);
|
||||
@ -65,24 +65,24 @@ public class CommandRankClickListener implements ClickHandler {
|
||||
if (panel.getName().equals(panelName)) {
|
||||
// This is a click on the panel
|
||||
// Slot relates to the command
|
||||
String c = getCommands(user.getWorld()).get(slot);
|
||||
String c = getCommands(panel.getWorld().orElse(user.getWorld())).get(slot);
|
||||
// Apply change to panel
|
||||
panel.getInventory().setItem(slot, getPanelItem(c, user).getItem());
|
||||
panel.getInventory().setItem(slot, getPanelItem(c, user, panel.getWorld().orElse(user.getWorld())).getItem());
|
||||
} else {
|
||||
// Open the Sub Settings panel
|
||||
openPanel(user, panelName);
|
||||
openPanel(user, panelName, panel.getWorld().orElse(user.getWorld()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void openPanel(User user, String panelName) {
|
||||
private void openPanel(User user, String panelName, World world) {
|
||||
// Close the current panel
|
||||
user.closeInventory();
|
||||
// Open a new panel
|
||||
PanelBuilder pb = new PanelBuilder();
|
||||
pb.user(user).name(panelName);
|
||||
pb.user(user).name(panelName).world(world);
|
||||
// Make panel items
|
||||
getCommands(user.getWorld()).forEach(c -> pb.item(getPanelItem(c, user)));
|
||||
getCommands(world).forEach(c -> pb.item(getPanelItem(c, user, world)));
|
||||
pb.build();
|
||||
|
||||
}
|
||||
@ -91,10 +91,11 @@ public class CommandRankClickListener implements ClickHandler {
|
||||
* Gets the rank command panel item
|
||||
* @param c - rank string
|
||||
* @param user - user
|
||||
* @param world - world for this panel
|
||||
* @return panel item for this command
|
||||
*/
|
||||
public PanelItem getPanelItem(String c, User user) {
|
||||
Island island = plugin.getIslands().getIsland(user.getWorld(), user);
|
||||
public PanelItem getPanelItem(String c, User user, World world) {
|
||||
Island island = plugin.getIslands().getIsland(world, user);
|
||||
PanelItemBuilder pib = new PanelItemBuilder();
|
||||
pib.name(c);
|
||||
pib.clickHandler(new CommandCycleClick(this, c));
|
||||
|
@ -1,6 +1,7 @@
|
||||
package world.bentobox.bentobox.listeners.flags.clicklisteners;
|
||||
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
@ -26,8 +27,9 @@ public class GeoLimitClickListener implements ClickHandler {
|
||||
user.sendMessage("general.errors.wrong-world");
|
||||
return true;
|
||||
}
|
||||
World world = panel.getWorld().orElse(user.getWorld());
|
||||
IslandWorldManager iwm = BentoBox.getInstance().getIWM();
|
||||
String reqPerm = iwm.getPermissionPrefix(Util.getWorld(user.getWorld())) + "admin.settings.GEO_LIMIT_MOBS";
|
||||
String reqPerm = iwm.getPermissionPrefix(Util.getWorld(world)) + "admin.settings.GEO_LIMIT_MOBS";
|
||||
if (!user.hasPermission(reqPerm)) {
|
||||
user.sendMessage("general.errors.no-permission", "[permission]", reqPerm);
|
||||
user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_METAL_HIT, 1F, 1F);
|
||||
@ -35,19 +37,19 @@ public class GeoLimitClickListener implements ClickHandler {
|
||||
}
|
||||
|
||||
// Open the Sub Settings panel
|
||||
openPanel(user);
|
||||
openPanel(user, world);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void openPanel(User user) {
|
||||
private void openPanel(User user, World world) {
|
||||
// Close the current panel
|
||||
user.closeInventory();
|
||||
// Open a new panel
|
||||
new TabbedPanelBuilder()
|
||||
.user(user)
|
||||
.world(user.getWorld())
|
||||
.tab(1, new GeoMobLimitTab(user, EntityLimitTabType.GEO_LIMIT))
|
||||
.world(world)
|
||||
.tab(1, new GeoMobLimitTab(user, EntityLimitTabType.GEO_LIMIT, world))
|
||||
.startingSlot(1)
|
||||
.size(54)
|
||||
.build().openPanel();
|
||||
|
@ -7,11 +7,13 @@ import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.api.addons.GameModeAddon;
|
||||
import world.bentobox.bentobox.api.panels.Panel;
|
||||
@ -47,43 +49,45 @@ public class GeoMobLimitTab implements Tab, ClickHandler {
|
||||
private final BentoBox plugin = BentoBox.getInstance();
|
||||
private final User user;
|
||||
private final EntityLimitTabType type;
|
||||
private final World world;
|
||||
|
||||
/**
|
||||
* @param user - user viewing the tab
|
||||
* @param type - type of tab to show - Geo limit or Mob limit
|
||||
* @param world - world where this tab is being used
|
||||
*/
|
||||
public GeoMobLimitTab(@NonNull User user, @NonNull EntityLimitTabType type) {
|
||||
public GeoMobLimitTab(@NonNull User user, @NonNull EntityLimitTabType type, World world) {
|
||||
super();
|
||||
this.user = user;
|
||||
this.type = type;
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onClick(Panel panel, User user, ClickType clickType, int slot) {
|
||||
// This is a click on the mob limit panel
|
||||
// Case panel to Tabbed Panel to get the active page
|
||||
TabbedPanel tp = (TabbedPanel)panel;
|
||||
// Convert the slot and active page to an index
|
||||
int index = tp.getActivePage() * 36 + slot - 9;
|
||||
EntityType c = LIVING_ENTITY_TYPES.get(index);
|
||||
if (type == EntityLimitTabType.MOB_LIMIT) {
|
||||
if (plugin.getIWM().getMobLimitSettings(user.getWorld()).contains(c.name())) {
|
||||
plugin.getIWM().getMobLimitSettings(user.getWorld()).remove(c.name());
|
||||
if (plugin.getIWM().getMobLimitSettings(world).contains(c.name())) {
|
||||
plugin.getIWM().getMobLimitSettings(world).remove(c.name());
|
||||
} else {
|
||||
plugin.getIWM().getMobLimitSettings(user.getWorld()).add(c.name());
|
||||
plugin.getIWM().getMobLimitSettings(world).add(c.name());
|
||||
}
|
||||
} else {
|
||||
if (plugin.getIWM().getGeoLimitSettings(user.getWorld()).contains(c.name())) {
|
||||
plugin.getIWM().getGeoLimitSettings(user.getWorld()).remove(c.name());
|
||||
if (plugin.getIWM().getGeoLimitSettings(world).contains(c.name())) {
|
||||
plugin.getIWM().getGeoLimitSettings(world).remove(c.name());
|
||||
} else {
|
||||
plugin.getIWM().getGeoLimitSettings(user.getWorld()).add(c.name());
|
||||
plugin.getIWM().getGeoLimitSettings(world).add(c.name());
|
||||
}
|
||||
}
|
||||
// Apply change to panel
|
||||
panel.getInventory().setItem(slot, getPanelItem(c, user).getItem());
|
||||
// Save settings
|
||||
plugin.getIWM().getAddon(Util.getWorld(user.getWorld())).ifPresent(GameModeAddon::saveWorldSettings);
|
||||
plugin.getIWM().getAddon(Util.getWorld(world)).ifPresent(GameModeAddon::saveWorldSettings);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -119,7 +123,7 @@ public class GeoMobLimitTab implements Tab, ClickHandler {
|
||||
pib.name(Util.prettifyText(c.toString()));
|
||||
pib.clickHandler(this);
|
||||
if (type == EntityLimitTabType.MOB_LIMIT) {
|
||||
if (!BentoBox.getInstance().getIWM().getMobLimitSettings(user.getWorld()).contains(c.name())) {
|
||||
if (!BentoBox.getInstance().getIWM().getMobLimitSettings(world).contains(c.name())) {
|
||||
pib.icon(Material.GREEN_SHULKER_BOX);
|
||||
pib.description(user.getTranslation("protection.flags.LIMIT_MOBS.can"));
|
||||
} else {
|
||||
@ -127,7 +131,7 @@ public class GeoMobLimitTab implements Tab, ClickHandler {
|
||||
pib.description(user.getTranslation("protection.flags.LIMIT_MOBS.cannot"));
|
||||
}
|
||||
} else {
|
||||
if (BentoBox.getInstance().getIWM().getGeoLimitSettings(user.getWorld()).contains(c.name())) {
|
||||
if (BentoBox.getInstance().getIWM().getGeoLimitSettings(world).contains(c.name())) {
|
||||
pib.icon(Material.GREEN_SHULKER_BOX);
|
||||
pib.description(user.getTranslation("protection.panel.flag-item.setting-active"));
|
||||
} else {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package world.bentobox.bentobox.listeners.flags.clicklisteners;
|
||||
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
@ -26,8 +27,9 @@ public class MobLimitClickListener implements ClickHandler {
|
||||
user.sendMessage("general.errors.wrong-world");
|
||||
return true;
|
||||
}
|
||||
World world = panel.getWorld().orElse(user.getWorld());
|
||||
IslandWorldManager iwm = BentoBox.getInstance().getIWM();
|
||||
String reqPerm = iwm.getPermissionPrefix(Util.getWorld(user.getWorld())) + "admin.settings.LIMIT_MOBS";
|
||||
String reqPerm = iwm.getPermissionPrefix(Util.getWorld(world)) + "admin.settings.LIMIT_MOBS";
|
||||
if (!user.hasPermission(reqPerm)) {
|
||||
user.sendMessage("general.errors.no-permission", "[permission]", reqPerm);
|
||||
user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_METAL_HIT, 1F, 1F);
|
||||
@ -35,19 +37,19 @@ public class MobLimitClickListener implements ClickHandler {
|
||||
}
|
||||
|
||||
// Open the Sub Settings panel
|
||||
openPanel(user);
|
||||
openPanel(user, world);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void openPanel(User user) {
|
||||
private void openPanel(User user, World world) {
|
||||
// Close the current panel
|
||||
user.closeInventory();
|
||||
// Open a new panel
|
||||
new TabbedPanelBuilder()
|
||||
.user(user)
|
||||
.world(user.getWorld())
|
||||
.tab(1, new GeoMobLimitTab(user, EntityLimitTabType.MOB_LIMIT))
|
||||
.world(world)
|
||||
.tab(1, new GeoMobLimitTab(user, EntityLimitTabType.MOB_LIMIT, world))
|
||||
.startingSlot(1)
|
||||
.size(54)
|
||||
.build().openPanel();
|
||||
|
@ -47,16 +47,15 @@ public class SettingsTab implements Tab, ClickHandler {
|
||||
|
||||
/**
|
||||
* Show a tab of settings
|
||||
* @param world - world
|
||||
* @param user - user who is viewing the tab
|
||||
* @param island - the island
|
||||
* @param type - flag type
|
||||
*/
|
||||
public SettingsTab(World world, User user, Island island, Type type) {
|
||||
this.world = world;
|
||||
public SettingsTab(User user, Island island, Type type) {
|
||||
this.user = user;
|
||||
this.island = island;
|
||||
this.type = type;
|
||||
this.world = island.getWorld();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2,8 +2,8 @@ package world.bentobox.bentobox.util.heads;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
@ -14,6 +14,7 @@ import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
@ -114,48 +115,96 @@ public class HeadGetter {
|
||||
|
||||
|
||||
/**
|
||||
* This is main task that runs once every 20 ticks and tries to get a player head.
|
||||
* This is main task that runs once every Settings#ticksBetweenCalls ticks and tries to get
|
||||
* Settings#headsPerCall player heads at once.
|
||||
*
|
||||
* @since 1.14.1
|
||||
*/
|
||||
private void runPlayerHeadGetter() {
|
||||
Bukkit.getScheduler().runTaskTimerAsynchronously(plugin, () -> {
|
||||
synchronized (HeadGetter.names)
|
||||
{
|
||||
if (!HeadGetter.names.isEmpty())
|
||||
int counter = 0;
|
||||
|
||||
while (!HeadGetter.names.isEmpty() && counter < plugin.getSettings().getHeadsPerCall())
|
||||
{
|
||||
Pair<String, PanelItem> elementEntry = HeadGetter.names.poll();
|
||||
|
||||
// TODO: In theory BentoBox could use User instance to find existing user UUID's.
|
||||
// It would avoid one API call.
|
||||
final String userName = elementEntry.getKey();
|
||||
|
||||
// Use cached userId as userId will not change :)
|
||||
UUID userId = HeadGetter.cachedHeads.containsKey(userName) ?
|
||||
HeadGetter.cachedHeads.get(userName).getUserId() :
|
||||
HeadGetter.getUserIdFromName(userName);
|
||||
// Hmm, task in task in task. That is a weird structure.
|
||||
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
|
||||
// Check if we can get user Id.
|
||||
UUID userId;
|
||||
|
||||
// Create new cache object.
|
||||
HeadCache cache = new HeadCache(userName,
|
||||
userId,
|
||||
HeadGetter.getTextureFromUUID(userId));
|
||||
|
||||
// Save in cache
|
||||
HeadGetter.cachedHeads.put(userName, cache);
|
||||
|
||||
// Tell requesters the head came in
|
||||
if (HeadGetter.headRequesters.containsKey(userName))
|
||||
{
|
||||
for (HeadRequester req : HeadGetter.headRequesters.get(userName))
|
||||
if (HeadGetter.cachedHeads.containsKey(userName))
|
||||
{
|
||||
elementEntry.getValue().setHead(cache.getPlayerHead());
|
||||
|
||||
Bukkit.getServer().getScheduler().runTaskAsynchronously(this.plugin,
|
||||
() -> req.setHead(elementEntry.getValue()));
|
||||
// If cache contains userName, it means that it was already stored.
|
||||
// We can reuse stored data, as they should not be changed.
|
||||
userId = HeadGetter.cachedHeads.get(userName).getUserId();
|
||||
}
|
||||
}
|
||||
else if (Bukkit.getServer().getOnlineMode())
|
||||
{
|
||||
// If server is in online mode we can relay that UUID is correct.
|
||||
// So we use thing that is stored in BentoBox players data.
|
||||
userId = plugin.getPlayers().getUUID(userName);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Assign null for later check, as I do not want to write ifs inside
|
||||
// previous 2 checks.
|
||||
userId = null;
|
||||
}
|
||||
|
||||
HeadCache cache;
|
||||
|
||||
if (plugin.getSettings().isUseCacheServer())
|
||||
{
|
||||
// Cache server has an implementation to get a skin just from player name.
|
||||
Pair<UUID, String> playerSkin = HeadGetter.getTextureFromName(userName, userId);
|
||||
|
||||
// Create new cache object.
|
||||
cache = new HeadCache(userName,
|
||||
playerSkin.getKey(),
|
||||
playerSkin.getValue());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (userId == null)
|
||||
{
|
||||
// Use MojangAPI to get userId from userName.
|
||||
userId = HeadGetter.getUserIdFromName(userName);
|
||||
}
|
||||
|
||||
// Create new cache object.
|
||||
cache = new HeadCache(userName,
|
||||
userId,
|
||||
HeadGetter.getTextureFromUUID(userId));
|
||||
}
|
||||
|
||||
// Save in cache
|
||||
HeadGetter.cachedHeads.put(userName, cache);
|
||||
|
||||
// Tell requesters the head came in, but only if the texture is usable.
|
||||
if (cache.encodedTextureLink != null && HeadGetter.headRequesters.containsKey(userName))
|
||||
{
|
||||
for (HeadRequester req : HeadGetter.headRequesters.get(userName))
|
||||
{
|
||||
elementEntry.getValue().setHead(cache.getPlayerHead());
|
||||
|
||||
if (!plugin.isShutdown())
|
||||
{
|
||||
// Do not run task if plugin is shutting down.
|
||||
Bukkit.getScheduler().runTaskAsynchronously(this.plugin,
|
||||
() -> req.setHead(elementEntry.getValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
}, 0L, 10L);
|
||||
}, 0, plugin.getSettings().getTicksBetweenCalls());
|
||||
}
|
||||
|
||||
|
||||
@ -189,8 +238,7 @@ public class HeadGetter {
|
||||
// UUID just looks more fancy :)
|
||||
String userIdString = jsonObject.get("id").toString().
|
||||
replace("\"", "").
|
||||
replaceFirst("([0-9a-fA-F]{8})([0-9a-fA-F]{4})([0-9a-fA-F]{4})([0-9a-fA-F]{4})([0-9a-fA-F]+)",
|
||||
"$1-$2-$3-$4-$5");
|
||||
replaceFirst("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5");
|
||||
|
||||
userId = UUID.fromString(userIdString);
|
||||
}
|
||||
@ -260,6 +308,70 @@ public class HeadGetter {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method gets and returns base64 encoded link to player skin texture from mc-heads.net.
|
||||
* It tries to use UUID if it is a valid, otherwise it uses given username.
|
||||
*
|
||||
* @param userName userName
|
||||
* @param userId UUID for the user.
|
||||
* @return Encoded player skin texture or null.
|
||||
* @since 1.16.0
|
||||
*/
|
||||
private static @NonNull Pair<UUID, String> getTextureFromName(String userName, @Nullable UUID userId) {
|
||||
try
|
||||
{
|
||||
Gson gsonReader = new Gson();
|
||||
|
||||
// Get user encoded texture value.
|
||||
// mc-heads returns correct skin with providing just a name, unlike mojang api, which
|
||||
// requires UUID.
|
||||
JsonObject jsonObject = gsonReader.fromJson(
|
||||
HeadGetter.getURLContent("https://mc-heads.net/minecraft/profile/" + (userId == null ? userName : userId.toString())),
|
||||
JsonObject.class);
|
||||
|
||||
/*
|
||||
* Returned Json Object:
|
||||
{
|
||||
id: USER_ID,
|
||||
name: USER_NAME,
|
||||
properties: [
|
||||
{
|
||||
name: "textures",
|
||||
value: ENCODED_BASE64_TEXTURE
|
||||
}
|
||||
]
|
||||
}
|
||||
*/
|
||||
|
||||
String decodedTexture = "";
|
||||
|
||||
String userIdString = jsonObject.get("id").toString().
|
||||
replace("\"", "").
|
||||
replaceFirst("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5");
|
||||
|
||||
for (JsonElement element : jsonObject.getAsJsonArray("properties"))
|
||||
{
|
||||
JsonObject object = element.getAsJsonObject();
|
||||
|
||||
if (object.has("name") &&
|
||||
object.get("name").getAsString().equals("textures"))
|
||||
{
|
||||
decodedTexture = object.get("value").getAsString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return new Pair<>(UUID.fromString(userIdString), decodedTexture);
|
||||
}
|
||||
catch (Exception ignored)
|
||||
{
|
||||
}
|
||||
|
||||
// return random uuid and null, to assign some values for cache.
|
||||
return new Pair<>(userId, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method gets page content of requested url
|
||||
*
|
||||
@ -270,12 +382,15 @@ public class HeadGetter {
|
||||
private static String getURLContent(String requestedUrl) {
|
||||
String returnValue;
|
||||
|
||||
try (BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(new URL(requestedUrl).openStream(), StandardCharsets.UTF_8)))
|
||||
try
|
||||
{
|
||||
returnValue = reader.lines().collect(Collectors.joining());
|
||||
URL url = new URL(requestedUrl);
|
||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
|
||||
returnValue = br.lines().collect(Collectors.joining());
|
||||
br.close();
|
||||
}
|
||||
catch (Exception ignored)
|
||||
catch (Exception e)
|
||||
{
|
||||
returnValue = "";
|
||||
}
|
||||
|
@ -82,11 +82,25 @@ panel:
|
||||
# Defines the Material of the item that fills the gaps (in the header, etc.) of most panels.
|
||||
# Added since 1.14.0.
|
||||
filler-material: LIGHT_BLUE_STAINED_GLASS_PANE
|
||||
# Toggle whether player head texture should be gathered from Mojang API or mc-heads.net cache server.
|
||||
# Mojang API sometime may be slow and may limit requests to the player data, so this will allow to
|
||||
# get player heads a bit faster then Mojang API.
|
||||
# Added since 1.16.0.
|
||||
use-cache-server: true
|
||||
# Defines how long player skin texture link is stored into local cache before it is requested again.
|
||||
# Defined value is in the minutes.
|
||||
# Value 0 will not clear cache until server restart.
|
||||
# Added since 1.14.1.
|
||||
head-cache-time: 60
|
||||
# Defines a number of player heads requested per tasks.
|
||||
# Setting it too large may lead to temporarily being blocked from head gatherer API.
|
||||
# Added since 1.16.0.
|
||||
heads-per-call: 9
|
||||
# Defines a number of ticks between each player head request task.
|
||||
# Setting it too large may lead to temporarily being blocked from head gatherer API.
|
||||
# Added since 1.16.0.
|
||||
# /!\ In order to apply the changes made to this option, you must restart your server. Reloading BentoBox or the server won't work.
|
||||
ticks-between-calls: 10
|
||||
logs:
|
||||
# Toggle whether superflat chunks regeneration should be logged in the server logs or not.
|
||||
# It can be spammy if there are a lot of superflat chunks to regenerate.
|
||||
|
@ -15,6 +15,7 @@ import java.util.Optional;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
@ -38,18 +39,21 @@ import world.bentobox.bentobox.api.panels.TabbedPanel;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.listeners.flags.clicklisteners.GeoMobLimitTab.EntityLimitTabType;
|
||||
import world.bentobox.bentobox.managers.IslandWorldManager;
|
||||
import world.bentobox.bentobox.util.Util;
|
||||
|
||||
/**
|
||||
* @author tastybento
|
||||
*
|
||||
*/
|
||||
@RunWith(PowerMockRunner.class)
|
||||
@PrepareForTest({Bukkit.class, BentoBox.class})
|
||||
@PrepareForTest({Bukkit.class, BentoBox.class, Util.class})
|
||||
public class GeoMobLimitTabTest {
|
||||
|
||||
@Mock
|
||||
private User user;
|
||||
@Mock
|
||||
private World world;
|
||||
@Mock
|
||||
private TabbedPanel panel;
|
||||
@Mock
|
||||
private BentoBox plugin;
|
||||
@ -82,6 +86,9 @@ public class GeoMobLimitTabTest {
|
||||
when(panel.getInventory()).thenReturn(inv);
|
||||
// User
|
||||
when(user.getTranslation(anyString())).thenAnswer((Answer<String>) invocation -> invocation.getArgument(0, String.class));
|
||||
// Util
|
||||
PowerMockito.mockStatic(Util.class, Mockito.CALLS_REAL_METHODS);
|
||||
when(Util.getWorld(any())).thenReturn(world);
|
||||
}
|
||||
|
||||
@After
|
||||
@ -94,7 +101,7 @@ public class GeoMobLimitTabTest {
|
||||
*/
|
||||
@Test
|
||||
public void testOnClick() {
|
||||
GeoMobLimitTab tab = new GeoMobLimitTab(user, EntityLimitTabType.GEO_LIMIT);
|
||||
GeoMobLimitTab tab = new GeoMobLimitTab(user, EntityLimitTabType.GEO_LIMIT, world);
|
||||
// BAT and COW in list
|
||||
assertEquals(2, list.size());
|
||||
assertEquals("COW", list.get(1));
|
||||
@ -116,7 +123,7 @@ public class GeoMobLimitTabTest {
|
||||
*/
|
||||
@Test
|
||||
public void testOnClickMobLimit() {
|
||||
GeoMobLimitTab tab = new GeoMobLimitTab(user, EntityLimitTabType.MOB_LIMIT);
|
||||
GeoMobLimitTab tab = new GeoMobLimitTab(user, EntityLimitTabType.MOB_LIMIT, world);
|
||||
// BAT and COW in list
|
||||
assertEquals(2, list.size());
|
||||
assertEquals("COW", list.get(1));
|
||||
@ -138,7 +145,7 @@ public class GeoMobLimitTabTest {
|
||||
*/
|
||||
@Test
|
||||
public void testGetIcon() {
|
||||
GeoMobLimitTab tab = new GeoMobLimitTab(user, EntityLimitTabType.MOB_LIMIT);
|
||||
GeoMobLimitTab tab = new GeoMobLimitTab(user, EntityLimitTabType.MOB_LIMIT, world);
|
||||
PanelItem icon = tab.getIcon();
|
||||
assertEquals("protection.flags.LIMIT_MOBS.name", icon.getName());
|
||||
assertEquals(Material.IRON_BOOTS, icon.getItem().getType());
|
||||
@ -149,7 +156,7 @@ public class GeoMobLimitTabTest {
|
||||
*/
|
||||
@Test
|
||||
public void testGetIconGeoLimit() {
|
||||
GeoMobLimitTab tab = new GeoMobLimitTab(user, EntityLimitTabType.GEO_LIMIT);
|
||||
GeoMobLimitTab tab = new GeoMobLimitTab(user, EntityLimitTabType.GEO_LIMIT, world);
|
||||
PanelItem icon = tab.getIcon();
|
||||
assertEquals("protection.flags.GEO_LIMIT_MOBS.name", icon.getName());
|
||||
assertEquals(Material.CHAINMAIL_CHESTPLATE, icon.getItem().getType());
|
||||
@ -160,9 +167,9 @@ public class GeoMobLimitTabTest {
|
||||
*/
|
||||
@Test
|
||||
public void testGetName() {
|
||||
GeoMobLimitTab tab = new GeoMobLimitTab(user, EntityLimitTabType.MOB_LIMIT);
|
||||
GeoMobLimitTab tab = new GeoMobLimitTab(user, EntityLimitTabType.MOB_LIMIT, world);
|
||||
assertEquals("protection.flags.LIMIT_MOBS.name", tab.getName());
|
||||
tab = new GeoMobLimitTab(user, EntityLimitTabType.GEO_LIMIT);
|
||||
tab = new GeoMobLimitTab(user, EntityLimitTabType.GEO_LIMIT, world);
|
||||
assertEquals("protection.flags.GEO_LIMIT_MOBS.name", tab.getName());
|
||||
}
|
||||
|
||||
@ -171,14 +178,14 @@ public class GeoMobLimitTabTest {
|
||||
*/
|
||||
@Test
|
||||
public void testGetPanelItemsMobLimit() {
|
||||
GeoMobLimitTab tab = new GeoMobLimitTab(user, EntityLimitTabType.MOB_LIMIT);
|
||||
GeoMobLimitTab tab = new GeoMobLimitTab(user, EntityLimitTabType.MOB_LIMIT, world);
|
||||
List<@Nullable PanelItem> items = tab.getPanelItems();
|
||||
assertFalse(items.isEmpty());
|
||||
items.forEach(i -> {
|
||||
if (i.getName().equals("Cow") || i.getName().equals("Bat")) {
|
||||
assertEquals(Material.RED_SHULKER_BOX, i.getItem().getType());
|
||||
assertEquals("Name : " + i.getName(), Material.RED_SHULKER_BOX, i.getItem().getType());
|
||||
} else {
|
||||
assertEquals(Material.GREEN_SHULKER_BOX, i.getItem().getType());
|
||||
assertEquals("Name : " + i.getName(), Material.GREEN_SHULKER_BOX, i.getItem().getType());
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -188,14 +195,14 @@ public class GeoMobLimitTabTest {
|
||||
*/
|
||||
@Test
|
||||
public void testGetPanelItemsGeoLimit() {
|
||||
GeoMobLimitTab tab = new GeoMobLimitTab(user, EntityLimitTabType.GEO_LIMIT);
|
||||
GeoMobLimitTab tab = new GeoMobLimitTab(user, EntityLimitTabType.GEO_LIMIT, world);
|
||||
List<@Nullable PanelItem> items = tab.getPanelItems();
|
||||
assertFalse(items.isEmpty());
|
||||
items.forEach(i -> {
|
||||
if (i.getName().equals("Cow") || i.getName().equals("Bat")) {
|
||||
assertEquals(Material.GREEN_SHULKER_BOX, i.getItem().getType());
|
||||
assertEquals("Name : " + i.getName(), Material.GREEN_SHULKER_BOX, i.getItem().getType());
|
||||
} else {
|
||||
assertEquals(Material.RED_SHULKER_BOX, i.getItem().getType());
|
||||
assertEquals("Name : " + i.getName(), Material.RED_SHULKER_BOX, i.getItem().getType());
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -205,7 +212,7 @@ public class GeoMobLimitTabTest {
|
||||
*/
|
||||
@Test
|
||||
public void testGetPermission() {
|
||||
GeoMobLimitTab tab = new GeoMobLimitTab(user, EntityLimitTabType.GEO_LIMIT);
|
||||
GeoMobLimitTab tab = new GeoMobLimitTab(user, EntityLimitTabType.GEO_LIMIT, world);
|
||||
assertTrue(tab.getPermission().isEmpty());
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user