diff --git a/ci-pom.xml b/ci-pom.xml
index 810f033..d497512 100644
--- a/ci-pom.xml
+++ b/ci-pom.xml
@@ -7,7 +7,7 @@
us.mytheria
BlobLib
- 1.697.67
+ 1.698.02
pom.xml
bloblib
diff --git a/local-pom.xml b/local-pom.xml
index acbfdc3..72fb727 100644
--- a/local-pom.xml
+++ b/local-pom.xml
@@ -5,7 +5,7 @@
us.mytheria
BlobLib
- 1.697.69
+ 1.698.02
pom.xml
bloblib
diff --git a/pom.xml b/pom.xml
index b263140..566fb30 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
4.0.0
us.mytheria
BlobLib
- 1.697.69
+ 1.698.02
pom
diff --git a/src/main/java/us/mytheria/bloblib/api/BlobLibInventoryAPI.java b/src/main/java/us/mytheria/bloblib/api/BlobLibInventoryAPI.java
index 54d23b8..ad5037a 100644
--- a/src/main/java/us/mytheria/bloblib/api/BlobLibInventoryAPI.java
+++ b/src/main/java/us/mytheria/bloblib/api/BlobLibInventoryAPI.java
@@ -419,11 +419,13 @@ public BlobSelector customSelector(@NotNull String blobInventoryKey,
dataType, selectorList.get(), onReturn);
selector.setItemsPerPage(selector.getSlots(buttonRangeKey)
== null ? 1 : selector.getSlots(buttonRangeKey).size());
+ selector.setWhiteBackgroundName(buttonRangeKey);
if (display != null)
selector.selectElement(player,
onSelect,
null,
- display);
+ display,
+ selectorList::get);
else
selector.selectElement(player,
onSelect,
@@ -556,7 +558,8 @@ public BlobEditor customEditor(@NotNull String blobInventoryKey,
playerSelector.selectElement(player,
onAdd,
null,
- addDisplay);
+ addDisplay,
+ viewCollection);
}, viewCollection.get(), onReturn));
BlobEditor editor = uber.thanks();
editor.setItemsPerPage(editor.getSlots(buttonRangeKey) == null
diff --git a/src/main/java/us/mytheria/bloblib/displayentity/BlockDisplayPackFloatingPet.java b/src/main/java/us/mytheria/bloblib/displayentity/BlockDisplayPackFloatingPet.java
new file mode 100644
index 0000000..2f21b80
--- /dev/null
+++ b/src/main/java/us/mytheria/bloblib/displayentity/BlockDisplayPackFloatingPet.java
@@ -0,0 +1,48 @@
+package us.mytheria.bloblib.displayentity;
+
+import org.bukkit.Location;
+import org.bukkit.Particle;
+import org.bukkit.block.data.BlockData;
+import org.bukkit.entity.BlockDisplay;
+import org.bukkit.entity.EntityType;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import us.mytheria.bloblib.BlobLib;
+
+public class BlockDisplayPackFloatingPet extends DisplayPackFloatingPet {
+ /**
+ * Creates a pet
+ *
+ * @param owner - the FloatingPet owner
+ * @param display - the display (like BlockData/ItemStack)
+ * (must be an item or a block)
+ * @param particle - the Particle to itemStack
+ * @param customName - the CustomName of the pet
+ * (if null will be used 'owner's Pet')
+ */
+ public BlockDisplayPackFloatingPet(Player owner,
+ BlockData display,
+ @Nullable Particle particle,
+ @Nullable String customName,
+ DisplayFloatingPetSettings settings,
+ @NotNull PackMaster packMaster,
+ int index) {
+ super(owner, display, particle, customName, settings, packMaster, index);
+ }
+
+ void spawnEntity(Location location) {
+ BlobLib plugin = BlobLib.getInstance();
+ entity = (BlockDisplay) location.getWorld().spawnEntity(location,
+ EntityType.BLOCK_DISPLAY);
+ entity.setPersistent(false);
+ entity.setTeleportDuration(1);
+ setCustomName(getCustomName());
+ entity.setBlock(getDisplay());
+ initAnimations(plugin);
+ }
+
+ public void setDisplay(BlockData display) {
+ this.display = display;
+ }
+}
diff --git a/src/main/java/us/mytheria/bloblib/displayentity/DisplayFloatingPet.java b/src/main/java/us/mytheria/bloblib/displayentity/DisplayFloatingPet.java
index 9425450..e39bded 100644
--- a/src/main/java/us/mytheria/bloblib/displayentity/DisplayFloatingPet.java
+++ b/src/main/java/us/mytheria/bloblib/displayentity/DisplayFloatingPet.java
@@ -31,10 +31,10 @@ public abstract class DisplayFloatingPet
private UUID owner;
private boolean activated, pauseLogic;
private String customName;
- private SyncDisplayEntityAnimations animations;
- private BukkitTask logicTask;
+ protected SyncDisplayEntityAnimations animations;
+ protected BukkitTask logicTask;
protected R display;
- private final DisplayFloatingPetSettings settings;
+ protected final DisplayFloatingPetSettings settings;
/**
* Creates a pet
@@ -45,6 +45,7 @@ public abstract class DisplayFloatingPet
* @param particle - the Particle to itemStack
* @param customName - the CustomName of the pet
* (if null will be used 'owner's Pet')
+ * @param settings - the settings of the pet
*/
public DisplayFloatingPet(@NotNull Player owner,
@NotNull R display,
@@ -110,7 +111,7 @@ protected void initAnimations(JavaPlugin plugin) {
initLogic(plugin);
}
- private void initLogic(JavaPlugin plugin) {
+ protected void initLogic(JavaPlugin plugin) {
EntityAnimationsCarrier animationsCarrier = settings.animationsCarrier();
logicTask = Bukkit.getScheduler().runTaskTimer(plugin, () -> {
Player owner = findOwner();
@@ -140,11 +141,11 @@ private void moveAway() {
this.location = animations.moveAway(findOwnerOrFail(), location);
}
- private void move() {
+ protected void move() {
this.location = animations.move(findOwnerOrFail(), location);
}
- private void idle() {
+ protected void idle() {
this.location = animations.idle(findOwnerOrFail(), location);
}
@@ -265,7 +266,7 @@ public Location getLocation() {
return location;
}
- private void setLocation(Location location) {
+ protected void setLocation(Location location) {
this.location = location;
}
@@ -281,7 +282,7 @@ public boolean isActive() {
return activated;
}
- private void setActive(boolean activated) {
+ protected void setActive(boolean activated) {
this.activated = activated;
}
diff --git a/src/main/java/us/mytheria/bloblib/displayentity/DisplayPackFloatingPet.java b/src/main/java/us/mytheria/bloblib/displayentity/DisplayPackFloatingPet.java
new file mode 100644
index 0000000..686fe79
--- /dev/null
+++ b/src/main/java/us/mytheria/bloblib/displayentity/DisplayPackFloatingPet.java
@@ -0,0 +1,79 @@
+package us.mytheria.bloblib.displayentity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Particle;
+import org.bukkit.entity.Display;
+import org.bukkit.entity.Player;
+import org.bukkit.plugin.java.JavaPlugin;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Represents a FloatingPet.
+ * Uses 1.20.2+ Bukkit API
+ *
+ * @param - the Display entity
+ * @param - (BlockData/ItemStack)
+ */
+public abstract class DisplayPackFloatingPet
+ extends DisplayFloatingPet {
+ protected final PackMaster> packMaster;
+ private final int index, holdIndex;
+
+ /**
+ * Creates a pet
+ *
+ * @param owner - the FloatingPet owner
+ * @param display - the display (like BlockData/ItemStack)
+ * (must be an item or a block)
+ * @param particle - the Particle to itemStack
+ * @param customName - the CustomName of the pet
+ * (if null will be used 'owner's Pet')
+ * @param settings - the settings of the pet
+ */
+ public DisplayPackFloatingPet(@NotNull Player owner,
+ @NotNull R display,
+ @Nullable Particle particle,
+ @Nullable String customName,
+ @NotNull DisplayFloatingPetSettings settings,
+ @NotNull PackMaster> packMaster,
+ int index) {
+ super(owner, display, particle, customName, settings);
+ this.packMaster = packMaster;
+ this.index = index;
+ this.holdIndex = packMaster.addComponent(this, index);
+ }
+
+ @Override
+ protected void initLogic(JavaPlugin plugin) {
+ EntityAnimationsCarrier animationsCarrier = settings.animationsCarrier();
+ logicTask = Bukkit.getScheduler().runTaskTimer(plugin, () -> {
+ Player owner = findOwner();
+ if (owner == null || !owner.isOnline()) {
+ destroy();
+ return;
+ }
+ spawnParticles(animationsCarrier.particlesOffset(), 0);
+ if (!isPauseLogic())
+ move();
+ }, 0, 1);
+ }
+
+ @Override
+ public void destroy() {
+ super.destroy();
+ }
+
+ @Override
+ protected void initAnimations(JavaPlugin plugin) {
+ animations = new SyncDisplayPackEntityAnimations<>(this,
+ settings.animationsCarrier(),
+ packMaster,
+ holdIndex);
+ initLogic(plugin);
+ }
+
+ public int getIndex() {
+ return index;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/us/mytheria/bloblib/displayentity/ItemDisplayPackFloatingPet.java b/src/main/java/us/mytheria/bloblib/displayentity/ItemDisplayPackFloatingPet.java
new file mode 100644
index 0000000..4fbb08b
--- /dev/null
+++ b/src/main/java/us/mytheria/bloblib/displayentity/ItemDisplayPackFloatingPet.java
@@ -0,0 +1,58 @@
+package us.mytheria.bloblib.displayentity;
+
+import org.bukkit.Location;
+import org.bukkit.Particle;
+import org.bukkit.entity.EntityType;
+import org.bukkit.entity.ItemDisplay;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.util.Transformation;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import us.mytheria.bloblib.BlobLib;
+import us.mytheria.bloblib.entities.display.DisplayDecorator;
+
+public class ItemDisplayPackFloatingPet extends DisplayPackFloatingPet {
+ /**
+ * Creates a pet
+ *
+ * @param owner - the FloatingPet owner
+ * @param display - the display (like BlockData/ItemStack)
+ * (must be an item or a block)
+ * @param particle - the Particle to itemStack
+ * @param customName - the CustomName of the pet
+ * (if null will be used 'owner's Pet')
+ */
+ public ItemDisplayPackFloatingPet(Player owner,
+ ItemStack display,
+ @Nullable Particle particle,
+ @Nullable String customName,
+ DisplayFloatingPetSettings settings,
+ @NotNull PackMaster packMaster,
+ int index) {
+ super(owner, display, particle, customName, settings, packMaster, index);
+ }
+
+ void spawnEntity(Location location) {
+ BlobLib plugin = BlobLib.getInstance();
+ entity = (ItemDisplay) location.getWorld().spawnEntity(location,
+ EntityType.ITEM_DISPLAY);
+ entity.setItemDisplayTransform(ItemDisplay.ItemDisplayTransform.FIXED);
+ entity.setPersistent(false);
+ entity.setTeleportDuration(1);
+ setCustomName(getCustomName());
+ entity.setItemStack(getDisplay());
+ Transformation transformation = entity.getTransformation();
+ entity.setTransformation(new Transformation(
+ transformation.getTranslation().add(0f, -0.5f, 0f),
+ transformation.getLeftRotation(), transformation.getScale(),
+ transformation.getRightRotation()));
+ DisplayDecorator decorator = new DisplayDecorator<>(entity, plugin);
+ decorator.transformLeft(1, 0, 0, 90, 1);
+ initAnimations(plugin);
+ }
+
+ public void setDisplay(ItemStack display) {
+ this.display = display;
+ }
+}
diff --git a/src/main/java/us/mytheria/bloblib/displayentity/PackMaster.java b/src/main/java/us/mytheria/bloblib/displayentity/PackMaster.java
new file mode 100644
index 0000000..3eaf5d1
--- /dev/null
+++ b/src/main/java/us/mytheria/bloblib/displayentity/PackMaster.java
@@ -0,0 +1,54 @@
+package us.mytheria.bloblib.displayentity;
+
+import org.bukkit.Location;
+import org.bukkit.entity.Player;
+import org.bukkit.util.Vector;
+import org.jetbrains.annotations.NotNull;
+import org.joml.Vector2d;
+import us.mytheria.bloblib.entities.SquareMaster;
+import us.mytheria.bloblib.gists.RelativeLocation;
+
+import java.util.Map;
+import java.util.Objects;
+
+public class PackMaster extends SquareMaster {
+ private @NotNull Vector pivot;
+
+ public static PackMaster of(int maxPerRow,
+ double componentLength,
+ @NotNull Map components,
+ @NotNull Vector pivot) {
+ Objects.requireNonNull(components, "'components' cannot be null!");
+ Objects.requireNonNull(pivot, "'pivot' cannot be null!");
+ return new PackMaster<>(maxPerRow, componentLength, components, pivot);
+ }
+
+ private PackMaster(int maxPerRow,
+ double componentLength,
+ @NotNull Map components,
+ @NotNull Vector pivot) {
+ super(maxPerRow, componentLength, components);
+ this.pivot = pivot;
+ }
+
+ @NotNull
+ public Vector getPivot() {
+ return pivot;
+ }
+
+ public Location pivot(Player player, int index) {
+ Location location = player.getLocation().clone();
+ location.setPitch(Location.normalizePitch(0));
+ Vector2d offset = getOffset(index);
+ return RelativeLocation.getInstance()
+ .getRelativeLocation(location,
+ pivot.getX() - (offset.y * getComponentLength()),
+ pivot.getZ() + (offset.x * getComponentLength()),
+ pivot.getY());
+ }
+
+ public void setPivot(@NotNull Vector pivot) {
+ Objects.requireNonNull(pivot, "'pivot' cannot be null!");
+ this.pivot = pivot;
+ }
+}
diff --git a/src/main/java/us/mytheria/bloblib/displayentity/SyncDisplayEntityAnimations.java b/src/main/java/us/mytheria/bloblib/displayentity/SyncDisplayEntityAnimations.java
index ef01549..24b7623 100644
--- a/src/main/java/us/mytheria/bloblib/displayentity/SyncDisplayEntityAnimations.java
+++ b/src/main/java/us/mytheria/bloblib/displayentity/SyncDisplayEntityAnimations.java
@@ -6,10 +6,10 @@
public class SyncDisplayEntityAnimations {
- private final double followSpeed, walkAwaySpeed, hoverSpeed, hoverHeightCeiling,
+ protected final double followSpeed, walkAwaySpeed, hoverSpeed, hoverHeightCeiling,
hoverHeightFloor, yOffset;
- private double hoverVelocity, hoverHeight;
- private final DisplayEntity, ?> pet;
+ protected double hoverVelocity, hoverHeight;
+ protected final DisplayEntity, ?> pet;
public SyncDisplayEntityAnimations(DisplayEntity, ?> pet,
double followSpeed,
@@ -37,11 +37,15 @@ public SyncDisplayEntityAnimations(DisplayEntity, ?> pet,
}
public Location move(Player player, Location loc) {
- Vector goal = vectorFromLocation(player.getLocation());
+ Location playerLocation = player.getLocation();
+ double playerX = playerLocation.getX();
+ double playerZ = playerLocation.getZ();
+ Vector goal = vectorFromLocation(playerLocation);
goal.setY(goal.getY() + yOffset);
- double distance = Math.sqrt(Math.pow(loc.getX() - player.getLocation().getX(), 2) + Math.pow(loc.getZ() - player.getLocation().getZ(), 2));
+ double distance = Math.sqrt(Math.pow(loc.getX() - playerX, 2) +
+ Math.pow(loc.getZ() - playerZ, 2));
if (distance < 2.5D) {
- goal.setY(goal.getY() + player.getLocation().getY() - loc.getY());
+ goal.setY(goal.getY() + playerLocation.getY() - loc.getY());
goal.setX(loc.getX());
goal.setZ(loc.getZ());
}
@@ -49,11 +53,11 @@ public Location move(Player player, Location loc) {
Vector direction = normalize(goal.subtract(start));
Location newLoc = loc.clone();
newLoc.add(direction.multiply(followSpeed));
- double a = player.getLocation().getX() - newLoc.getX();
- double b = player.getLocation().getZ() - newLoc.getZ();
+ double a = playerX - newLoc.getX();
+ double b = playerZ - newLoc.getZ();
double angle = Math.atan(b / a);
angle = angle * (180 / Math.PI);
- if (player.getLocation().getX() - newLoc.getX() >= 0) {
+ if (playerX - newLoc.getX() >= 0) {
angle += 180;
}
angle += 270;
diff --git a/src/main/java/us/mytheria/bloblib/displayentity/SyncDisplayPackEntityAnimations.java b/src/main/java/us/mytheria/bloblib/displayentity/SyncDisplayPackEntityAnimations.java
new file mode 100644
index 0000000..0b77658
--- /dev/null
+++ b/src/main/java/us/mytheria/bloblib/displayentity/SyncDisplayPackEntityAnimations.java
@@ -0,0 +1,29 @@
+package us.mytheria.bloblib.displayentity;
+
+import org.bukkit.Location;
+import org.bukkit.entity.Display;
+import org.bukkit.entity.Player;
+
+public class SyncDisplayPackEntityAnimations extends SyncDisplayEntityAnimations {
+ private final PackMaster> packMaster;
+ private final int index;
+
+ public SyncDisplayPackEntityAnimations(DisplayEntity, ?> pet,
+ EntityAnimationsCarrier carrier,
+ PackMaster> packMaster,
+ int index) {
+ super(pet, carrier);
+ this.packMaster = packMaster;
+ this.index = index;
+ }
+
+ @Override
+ public Location move(Player player, Location loc) {
+ Location pivot = packMaster.pivot(player, index);
+ pivot.setPitch(Location.normalizePitch(0.0f));
+ pivot.setY(player.getLocation().getY() + yOffset);
+ pet.teleport(pivot);
+ return pivot;
+ }
+
+}
diff --git a/src/main/java/us/mytheria/bloblib/entities/BlobEditor.java b/src/main/java/us/mytheria/bloblib/entities/BlobEditor.java
index 9fa545e..212412f 100644
--- a/src/main/java/us/mytheria/bloblib/entities/BlobEditor.java
+++ b/src/main/java/us/mytheria/bloblib/entities/BlobEditor.java
@@ -217,29 +217,6 @@ public void loadPage(int page, boolean whiteBackgroundRefill) {
}
}
- /**
- * loads the page with the given page number
- *
- * @param page the page number
- * @param refill if the background should be refilled
- * @param function the function to apply
- */
- public void loadCustomPage(int page, boolean refill, Function function) {
- if (page < 1) {
- return;
- }
- if (getTotalPages() < page) {
- return;
- }
- if (refill)
- refillButton("White-Background");
- clearValues();
- List> values = this.customPage(page, getItemsPerPage(), function);
- for (int i = 0; i < values.size(); i++) {
- setValue(i, values.get(i));
- }
- }
-
/**
* returns the page with the given page number without loading
*
@@ -267,33 +244,6 @@ public List> page(int page, int itemsPerPage) {
return values;
}
- /**
- * returns specific page with provided function without loading
- *
- * @param page the page
- * @param itemsPerPage the items per page
- * @param function the function to apply
- * @return the list of values
- */
- public List> customPage(int page, int itemsPerPage, Function function) {
- int start = (page - 1) * itemsPerPage;
- int end = start + (itemsPerPage);
- ArrayList> values = new ArrayList<>();
- for (int i = start; i < end; i++) {
- T get;
- try {
- get = getList().get(i);
- ItemStack itemStack = function.apply(get);
- if (itemStack == null)
- continue;
- values.add(new VariableValue<>(itemStack, get));
- } catch (IndexOutOfBoundsException e) {
- break;
- }
- }
- return values;
- }
-
/**
* Selects an object from the editor.
*
@@ -389,6 +339,7 @@ public void add(T t) {
/**
* @return the list
*/
+ @Override
public List getList() {
if (collection != null) {
return new ArrayList<>(collection);
diff --git a/src/main/java/us/mytheria/bloblib/entities/BlobSelector.java b/src/main/java/us/mytheria/bloblib/entities/BlobSelector.java
index a035efb..885fc91 100644
--- a/src/main/java/us/mytheria/bloblib/entities/BlobSelector.java
+++ b/src/main/java/us/mytheria/bloblib/entities/BlobSelector.java
@@ -17,6 +17,7 @@
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
+import java.util.function.Supplier;
/**
* @author anjoismysign
@@ -144,29 +145,6 @@ public void loadPage(int page, boolean whiteBackgroundRefill) {
}
}
- /**
- * loads the page with the given page number
- *
- * @param page the page number
- * @param refill if the background should be refilled
- * @param function the function to apply
- */
- public void loadCustomPage(int page, boolean refill, Function function) {
- if (page < 1) {
- return;
- }
- if (getTotalPages() < page) {
- return;
- }
- if (refill)
- refillButton("White-Background");
- clearValues();
- List> values = this.customPage(page, getItemsPerPage(), function);
- for (int i = 0; i < values.size(); i++) {
- setValue(i, values.get(i));
- }
- }
-
/**
* returns the page with the given page number without loading
*
@@ -194,33 +172,6 @@ public List> page(int page, int itemsPerPage) {
return values;
}
- /**
- * returns specific page with provided function without loading
- *
- * @param page the page
- * @param itemsPerPage the items per page
- * @param function the function to apply
- * @return the list of values
- */
- public List> customPage(int page, int itemsPerPage, Function function) {
- int start = (page - 1) * itemsPerPage;
- int end = start + (itemsPerPage);
- ArrayList> values = new ArrayList<>();
- for (int i = start; i < end; i++) {
- T get;
- try {
- get = getList().get(i);
- ItemStack itemStack = function.apply(get);
- if (itemStack == null)
- continue;
- values.add(new VariableValue<>(itemStack, get));
- } catch (IndexOutOfBoundsException e) {
- break;
- }
- }
- return values;
- }
-
public void selectElement(Player player, Consumer consumer, String timerMessageKey) {
loadPage(getPage(), true);
selectorManager.addSelectorListener(player, BlobSelectorListener.wise(player,
@@ -228,8 +179,11 @@ public void selectElement(Player player, Consumer consumer, String timerMessa
this));
}
- public void selectElement(Player player, Consumer consumer, String timerMessageKey, Function function) {
+ public void selectElement(Player player, Consumer consumer, String timerMessageKey, Function function,
+ Supplier> selectorList) {
loadCustomPage(getPage(), true, function);
+ setLoadFunction(function);
+ setCollectionSupplier(selectorList);
selectorManager.addSelectorListener(player, BlobSelectorListener.wise(player,
consumer, timerMessageKey,
this));
@@ -257,6 +211,7 @@ public int getTotalPages() {
/**
* @return the list
*/
+ @Override
public List getList() {
if (collection != null) {
return new ArrayList<>(collection);
diff --git a/src/main/java/us/mytheria/bloblib/entities/SquareMaster.java b/src/main/java/us/mytheria/bloblib/entities/SquareMaster.java
new file mode 100644
index 0000000..198ec5f
--- /dev/null
+++ b/src/main/java/us/mytheria/bloblib/entities/SquareMaster.java
@@ -0,0 +1,165 @@
+package us.mytheria.bloblib.entities;
+
+import me.anjoismysign.anjo.entities.Tuple2;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.joml.Vector2d;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+public class SquareMaster {
+ private double width, height;
+ private int rows, maxPerRow;
+ private final Map components;
+ private final Map indexes;
+ private double componentLength;
+
+ public SquareMaster(int maxPerRow,
+ double componentLength,
+ @NotNull Map components) {
+ this.components = components;
+ this.indexes = new HashMap<>();
+ this.maxPerRow = maxPerRow;
+ this.componentLength = componentLength;
+ }
+
+ private void reload() {
+ int components = this.components.size();
+ rows = (int) Math.ceil((double) components / maxPerRow);
+ width = Math.min(components, maxPerRow) * componentLength;
+ height = rows * componentLength;
+ }
+
+ /**
+ * Merges the indexes with the master
+ *
+ * @param indexes - the indexes
+ */
+ public void mergeIndexes(Map indexes) {
+ this.indexes.putAll(indexes);
+ }
+
+ public void setComponentLength(double componentLength) {
+ this.componentLength = componentLength;
+ reload();
+ }
+
+ public void setMaxPerRow(int maxPerRow) {
+ this.maxPerRow = maxPerRow;
+ }
+
+ public int getMaxPerRow() {
+ return maxPerRow;
+ }
+
+ /**
+ * Adds a component to the master at the specified index (real index)
+ *
+ * @param component - the component
+ * @param realIndex - the index
+ * @return the index the component was added at
+ */
+ public int addComponent(T component, int realIndex) {
+ components.put(realIndex, component);
+ int lowestMissing = getLowestMissing(indexes.keySet());
+ indexes.put(lowestMissing, realIndex);
+ reload();
+ return lowestMissing;
+ }
+
+ private int getLowestMissing(Set indexes) {
+ int i = 0;
+ while (indexes.contains(i))
+ i++;
+ return i;
+ }
+
+ /**
+ * Removes a component from the master at the specified index (real index)
+ *
+ * @param index - the index
+ */
+ public void removeComponent(int index) {
+ Integer real = indexes.get(index);
+ if (real == null)
+ return;
+ components.remove(real);
+ indexes.remove(index);
+ reload();
+ }
+
+ /**
+ * Gets the component at the specified index
+ *
+ * @param index - the index
+ * @return the component
+ */
+ @Nullable
+ public Tuple2 getComponent(int index) {
+ Integer real = indexes.get(index);
+ if (real == null)
+ return null;
+ T component = components.get(real);
+ if (component == null)
+ return null;
+ return new Tuple2<>(real, component);
+ }
+
+ /**
+ * Gets the index of the specified component
+ *
+ * @param realIndex - the real index
+ * @return the index
+ */
+ public Integer getIndex(int realIndex) {
+ return indexes.entrySet().stream()
+ .filter(entry -> entry.getValue().equals(realIndex))
+ .map(Map.Entry::getKey)
+ .findFirst()
+ .orElse(null);
+ }
+
+ public Vector2d getOffset(int index) {
+ int row = getRow(index);
+ int column = getColumn(index);
+ double componentLength = getComponentLength();
+ double x = column + (componentLength / 2);
+ double z = row + (componentLength / 2);
+ return new Vector2d(x, z);
+ }
+
+ public double getComponentLength() {
+ return componentLength;
+ }
+
+ public double getWidth() {
+ return width;
+ }
+
+ public double getHeight() {
+ return height;
+ }
+
+ public int getRows() {
+ return rows;
+ }
+
+ public int getRow(int index) {
+ return index / maxPerRow;
+ }
+
+ public int getColumn(int index) {
+ return index % maxPerRow;
+ }
+
+ /**
+ * Gets an unmodifiable copy of the map of the indexes.
+ *
+ * @return the indexes
+ */
+ public Map getIndexes() {
+ return Map.copyOf(indexes);
+ }
+}
diff --git a/src/main/java/us/mytheria/bloblib/entities/inventory/VariableSelector.java b/src/main/java/us/mytheria/bloblib/entities/inventory/VariableSelector.java
index 888170d..5f6dcff 100644
--- a/src/main/java/us/mytheria/bloblib/entities/inventory/VariableSelector.java
+++ b/src/main/java/us/mytheria/bloblib/entities/inventory/VariableSelector.java
@@ -14,6 +14,7 @@
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
+import java.util.function.Supplier;
/**
* @param type of the variable
@@ -30,6 +31,12 @@ public abstract class VariableSelector extends BlobInventory {
private final UUID builderId;
private final VariableFiller filler;
private final Consumer returnAction;
+ @Nullable
+ private Function loadFunction;
+ @Nullable
+ private Supplier> collectionSupplier;
+ @Nullable
+ private String whiteBackgroundName;
private int page;
private int itemsPerPage;
@@ -60,12 +67,35 @@ public static BlobInventory DEFAULT() {
* @param builderId the id of the builder
* @param dataType the data type
* @param filler the filler to use
+ * @param returnAction the action to run when the return button is clicked
*/
public VariableSelector(BlobInventory blobInventory, UUID builderId,
String dataType, VariableFiller filler,
@Nullable Consumer returnAction) {
+ this(blobInventory, builderId, dataType, filler, returnAction, null, null, null);
+ }
+
+ /**
+ * creates a new VariableSelector
+ *
+ * @param blobInventory the inventory to use
+ * @param builderId the id of the builder
+ * @param dataType the data type
+ * @param filler the filler to use
+ * @param returnAction the action to run when the return button is clicked
+ * @param loadFunction the function to use to convert the list to an itemstack
+ */
+ public VariableSelector(BlobInventory blobInventory, UUID builderId,
+ String dataType, VariableFiller filler,
+ @Nullable Consumer returnAction,
+ @Nullable Function loadFunction,
+ @Nullable Supplier> collectionSupplier,
+ @Nullable String whiteBackgroundName) {
super(blobInventory.getTitle(), blobInventory.getSize(), blobInventory.getButtonManager());
this.returnAction = returnAction == null ? HumanEntity::closeInventory : returnAction;
+ this.loadFunction = loadFunction;
+ this.collectionSupplier = collectionSupplier;
+ this.whiteBackgroundName = whiteBackgroundName;
this.filler = filler;
this.builderId = builderId;
this.values = new HashMap<>();
@@ -75,7 +105,7 @@ public VariableSelector(BlobInventory blobInventory, UUID builderId,
buildInventory();
this.page = 1;
this.itemsPerPage = 1;
- Set slots = getSlots("White-Background");
+ Set slots = getSlots(getWhiteBackgroundName());
if (slots != null)
setItemsPerPage(slots.size());
loadFirstPage();
@@ -101,7 +131,7 @@ public void loadPage(int page, boolean whiteBackgroundRefill) {
return;
}
if (whiteBackgroundRefill)
- refillButton("White-Background");
+ refillButton(getWhiteBackgroundName());
values.clear();
List> values = filler.page(page, itemsPerPage);
for (int i = 0; i < values.size(); i++) {
@@ -124,7 +154,7 @@ public void loadCustomPage(int page, boolean refill, List list, Function> values = filler.customPage(page, itemsPerPage, list, function);
for (int i = 0; i < values.size(); i++) {
@@ -132,13 +162,39 @@ public void loadCustomPage(int page, boolean refill, List list, Function function) {
+ if (page < 1) {
+ return;
+ }
+ if (getTotalPages() < page) {
+ return;
+ }
+ if (refill)
+ refillButton(getWhiteBackgroundName());
+ clearValues();
+ List> values = this.customPage(page, getItemsPerPage(), function);
+ for (int i = 0; i < values.size(); i++) {
+ setValue(i, values.get(i));
+ }
+ }
+
/**
* loads the specified page
*
* @param page the page to load
*/
public void loadPage(int page) {
- loadPage(page, true);
+ if (loadFunction != null && collectionSupplier != null)
+ loadCustomPage(page, true, loadFunction);
+ else
+ loadPage(page, true);
}
/**
@@ -356,4 +412,60 @@ public void addValues(Collection collection) {
public void setItemsPerPage(int itemsPerPage) {
this.itemsPerPage = itemsPerPage;
}
+
+ /**
+ * @return the list
+ */
+ public List getList() {
+ if (collectionSupplier == null)
+ return new ArrayList<>();
+ return collectionSupplier.get().stream().toList();
+ }
+
+ /**
+ * returns specific page with provided function without loading
+ *
+ * @param page the page
+ * @param itemsPerPage the items per page
+ * @param function the function to apply
+ * @return the list of values
+ */
+ public List> customPage(int page, int itemsPerPage, Function function) {
+ int start = (page - 1) * itemsPerPage;
+ int end = start + (itemsPerPage);
+ ArrayList> values = new ArrayList<>();
+ for (int i = start; i < end; i++) {
+ T get;
+ try {
+ get = getList().get(i);
+ ItemStack itemStack = function.apply(get);
+ if (itemStack == null)
+ continue;
+ values.add(new VariableValue<>(itemStack, get));
+ } catch (IndexOutOfBoundsException e) {
+ break;
+ }
+ }
+ return values;
+ }
+
+ public void setLoadFunction(@NotNull Function loadFunction) {
+ Objects.requireNonNull(loadFunction, "loadFunction cannot be null");
+ this.loadFunction = loadFunction;
+ }
+
+ public void setCollectionSupplier(@NotNull Supplier> collectionSupplier) {
+ Objects.requireNonNull(collectionSupplier, "listSupplier cannot be null");
+ this.collectionSupplier = collectionSupplier;
+ }
+
+ public void setWhiteBackgroundName(@NotNull String whiteBackgroundName) {
+ Objects.requireNonNull(whiteBackgroundName, "whiteBackgroundName cannot be null");
+ this.whiteBackgroundName = whiteBackgroundName;
+ }
+
+ @NotNull
+ private String getWhiteBackgroundName() {
+ return whiteBackgroundName == null ? "White-Background" : whiteBackgroundName;
+ }
}
diff --git a/src/main/java/us/mytheria/bloblib/gists/RelativeLocation.java b/src/main/java/us/mytheria/bloblib/gists/RelativeLocation.java
new file mode 100644
index 0000000..f76513a
--- /dev/null
+++ b/src/main/java/us/mytheria/bloblib/gists/RelativeLocation.java
@@ -0,0 +1,71 @@
+package us.mytheria.bloblib.gists;
+
+import org.bukkit.Location;
+import org.bukkit.util.Vector;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Objects;
+
+/**
+ * @author Wasabi_Thumbs (...)
+ */
+public class RelativeLocation {
+ private static RelativeLocation instance;
+
+ public static RelativeLocation getInstance() {
+ if (instance == null) {
+ instance = new RelativeLocation();
+ }
+ return instance;
+ }
+
+ private final double epsilon = Math.ulp(1.0d) * 2d;
+
+ private boolean isSignificant(double value) {
+ return Math.abs(value) >= epsilon;
+ }
+
+ public Location getRelativeLocation(@NotNull Location location,
+ double forward,
+ double right) {
+ return getRelativeLocation(location, forward, right, 0d);
+ }
+
+ public Location getRelativeLocation(@NotNull Location location,
+ double forward,
+ double right,
+ double up) {
+ Objects.requireNonNull(location, "'location' cannot be null!");
+ Vector direction = null;
+ if (isSignificant(forward)) {
+ direction = location.getDirection();
+ location.add(direction.clone().multiply(forward));
+ }
+ boolean hasUp = isSignificant(up);
+ if (hasUp && direction == null) direction = location.getDirection();
+ if (isSignificant(right) || hasUp) {
+ Vector rightDirection;
+ if (direction != null && isSignificant(Math.abs(direction.getY()) - 1)) {
+ rightDirection = direction.clone();
+ double factor = Math.sqrt(1 - Math.pow(rightDirection.getY(), 2)); // a shortcut that lets us not normalize which is slow
+ double nx = -rightDirection.getZ() / factor;
+ double nz = rightDirection.getX() / factor;
+ rightDirection.setX(nx);
+ rightDirection.setY(0d);
+ rightDirection.setZ(nz);
+ } else {
+ float yaw = location.getYaw() + 90f;
+ double yawRad = yaw * (Math.PI / 180d);
+ double z = Math.cos(yawRad);
+ double x = -Math.sin(yawRad);
+ rightDirection = new Vector(x, 0d, z);
+ }
+ location.add(rightDirection.clone().multiply(right));
+ if (hasUp) {
+ Vector upDirection = rightDirection.crossProduct(direction);
+ location.add(upDirection.clone().multiply(up));
+ }
+ }
+ return location;
+ }
+}