9
0
mirror of https://github.com/Xiao-MoMi/Custom-Fishing.git synced 2025-12-26 10:29:16 +00:00

2.0-backup-3

This commit is contained in:
XiaoMoMi
2023-09-03 03:11:21 +08:00
parent 637d38013d
commit b73dd6cf51
22 changed files with 411 additions and 3457 deletions

View File

@@ -1,189 +0,0 @@
package net.momirealms.customfishing.libraries.inventorygui;
/*
* Copyright 2017 Max Lee (https://github.com/Phoenix616)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* Represents an element in a gui that will query all it's data when drawn.
*/
public class DynamicGuiElement extends GuiElement {
private Function<HumanEntity, GuiElement> query;
private Map<UUID, CacheEntry> cachedElements = new ConcurrentHashMap<>();
/**
* Represents an element in a gui that will query all it's data when drawn.
* @param slotChar The character to replace in the gui setup string
* @param query Query the element data, this should return an element with the information
*/
public DynamicGuiElement(char slotChar, Supplier<GuiElement> query) {
this(slotChar, (h) -> query.get());
}
/**
* Represents an element in a gui that will query all it's data when drawn.
* @param slotChar The character to replace in the gui setup string
* @param query Query the element data, this should return an element with the information and handle null players properly
*/
public DynamicGuiElement(char slotChar, Function<HumanEntity, GuiElement> query) {
super(slotChar);
this.query = query;
}
/**
* Query this element's state for every player who had it cached
*/
public void update() {
for (UUID playerId : new ArrayList<>(cachedElements.keySet())) {
Player p = gui.getPlugin().getServer().getPlayer(playerId);
if (p != null && p.isOnline()) {
update(p);
} else {
cachedElements.remove(playerId);
}
}
}
/**
* Query this element's state for a certain player
* @param player The player for whom to update the element
*/
public CacheEntry update(HumanEntity player) {
CacheEntry cacheEntry = new CacheEntry(queryElement(player));
if (cacheEntry.element instanceof DynamicGuiElement) {
((DynamicGuiElement) cacheEntry.element).update(player);
} else if (cacheEntry.element instanceof GuiElementGroup) {
InventoryGui.updateElements(player, ((GuiElementGroup) cacheEntry.element).getElements());
}
cachedElements.put(player.getUniqueId(), cacheEntry);
return cacheEntry;
}
@Override
public void setGui(InventoryGui gui) {
super.setGui(gui);
}
@Override
public ItemStack getItem(HumanEntity who, int slot) {
GuiElement element = getCachedElement(who);
return element != null ? element.getItem(who, slot) : null;
}
@Override
public Action getAction(HumanEntity who) {
GuiElement element = getCachedElement(who);
return element != null ? element.getAction(who) : null;
}
/**
* Get the supplier for this element's content
* @return The supplier query
*/
public Function<HumanEntity, GuiElement> getQuery() {
return query;
}
/**
* Set the supplier for this element's content
* @param query The supplier query to set
*/
public void setQuery(Function<HumanEntity, GuiElement> query) {
this.query = query;
}
/**
* Query the element for a player
* @param who The player
* @return The GuiElement or null
*/
public GuiElement queryElement(HumanEntity who) {
GuiElement element = getQuery().apply(who);
if (element != null) {
element.setGui(gui);
element.setSlots(slots);
}
return element;
}
/**
* Get the cached element, creates a new one if there is none for that player.
* Use {@link #getLastCached(HumanEntity)} to check if a player has something cached.
* @param who The player to get the element for
* @return The element that is currently cached
*/
public GuiElement getCachedElement(HumanEntity who) {
CacheEntry cached = cachedElements.get(who.getUniqueId());
if (cached == null) {
cached = update(who);
}
return cached.getElement();
}
/**
* Remove the cached element if the player has one.
* @param who The player to remove the cached element for
* @return The element that was cached or null if none was cached
*/
public GuiElement removeCachedElement(HumanEntity who) {
CacheEntry cached = cachedElements.remove(who.getUniqueId());
return cached != null ? cached.getElement() : null;
}
/**
* Get the time at which this element was last cached for a certain player
* @param who The player to get the last cache time for
* @return The timestamp from when it was last cached or -1 if it wasn't cached
*/
public long getLastCached(HumanEntity who) {
CacheEntry cached = cachedElements.get(who.getUniqueId());
return cached != null ? cached.getCreated() : -1;
}
public class CacheEntry {
private final GuiElement element;
private final long created = System.currentTimeMillis();
CacheEntry(GuiElement element) {
this.element = element;
}
public GuiElement getElement() {
return element;
}
public long getCreated() {
return created;
}
}
}

View File

@@ -1,77 +0,0 @@
package net.momirealms.customfishing.libraries.inventorygui;
import org.bukkit.entity.HumanEntity;
import org.bukkit.inventory.ItemStack;
/**
* An element that will not appear if there is no previous history,
* but will go back one step if there is
*/
public class GuiBackElement extends StaticGuiElement {
private boolean close;
/**
* An element used to go back in history of the gui if there is something to go back to.
* Will not display when there is nothing to go back to.
*
* @param slotChar The character to replace in the gui setup string
* @param item The {@link ItemStack} representing this element
* @param text The text to display on this element, placeholders are automatically
* replaced, see {@link InventoryGui#replaceVars} for a list of the
* placeholder variables. Empty text strings are also filter out, use
* a single space if you want to add an empty line!<br>
* If it's not set/empty the item's default name will be used
*/
public GuiBackElement(char slotChar, ItemStack item, String... text) {
this(slotChar, item, false, text);
}
/**
* An element used to go back in history of the gui
*
* @param slotChar The character to replace in the gui setup string
* @param item The {@link ItemStack} representing this element
* @param close Whether to close the GUI if there is nothing to go back to.
* Will not display item if set to false and nothing to go back to.
* @param text The text to display on this element, placeholders are automatically
* replaced, see {@link InventoryGui#replaceVars} for a list of the
* placeholder variables. Empty text strings are also filter out, use
* a single space if you want to add an empty line!<br>
* If it's not set/empty the item's default name will be used
*/
public GuiBackElement(char slotChar, ItemStack item, boolean close, String... text) {
super(slotChar, item, text);
this.close = close;
setAction(click -> {
if (canGoBack(click.getWhoClicked())) {
InventoryGui.goBack(click.getWhoClicked());
} else if (close) {
click.getGui().close();
}
return true;
});
}
@Override
public ItemStack getItem(HumanEntity who, int slot) {
if (!canGoBack(who) && !close) {
return gui.getFiller() != null ? gui.getFiller().getItem(who, slot) : null;
}
return super.getItem(who, slot);
}
/**
* Whether this element can close the GUI when nothing to go back to
* @return Close the GUI when nothing to go back
*/
public boolean canClose() {
return close;
}
private boolean canGoBack(HumanEntity who) {
return InventoryGui.getHistory(who).size() > 1 || (InventoryGui.getHistory(who).size() == 1 && InventoryGui.getHistory(who).peekLast() != gui);
}
}

View File

@@ -1,235 +0,0 @@
package net.momirealms.customfishing.libraries.inventorygui;
/*
* Copyright 2017 Max Lee (https://github.com/Phoenix616)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import org.bukkit.entity.HumanEntity;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryInteractEvent;
import org.bukkit.inventory.ItemStack;
/**
* Represents an element in a gui
*/
public abstract class GuiElement {
private final char slotChar;
private Action action;
protected int[] slots = new int[0];
protected InventoryGui gui;
/**
* Represents an element in a gui
* @param slotChar The character to replace in the gui setup string
* @param action The action to run when the player clicks on this element
*/
public GuiElement(char slotChar, Action action) {
this.slotChar = slotChar;
setAction(action);
}
/**
* Represents an element in a gui that doesn't have any action when clicked
* @param slotChar The character to replace in the gui setup string
*/
public GuiElement(char slotChar) {
this(slotChar, null);
}
/**
* Get the character in the gui setup that corresponds with this element
* @return The character
*/
public char getSlotChar() {
return slotChar;
}
/**
* Get the item that is displayed by this element on a certain page
* @param who The player who views the page
* @param slot The slot to get the item for
* @return The ItemStack that is displayed as this element
*/
public abstract ItemStack getItem(HumanEntity who, int slot);
/**
* Get the action that is executed when clicking on this element
* @param who The player who views the page
* @return The action to run
*/
public Action getAction(HumanEntity who) {
return action;
}
/**
* Set the action that is executed when clicking on this element
* @param action The action to run. The {@link Action#onClick} method should
* return whether or not the click event should be cancelled
*/
public void setAction(Action action) {
this.action = action;
}
/**
* Get the indexes of the lots that this element is displayed in
* @return An array of the lost indexes
*/
public int[] getSlots() {
return slots;
}
/**
* Set the ids of the slots where this element is assigned to
* @param slots An array of the slot ids where this element is displayed
*/
public void setSlots(int[] slots) {
this.slots = slots;
}
/**
* Get the index that this slot has in the list of slots that this element is displayed in
* @param slot The id of the slot
* @return The index in the list of slots that this id has or <code>-1</code> if it isn't in that list
*/
public int getSlotIndex(int slot) {
return getSlotIndex(slot, 0);
}
/**
* Get the index that this slot has in the list of slots that this element is displayed in
* @param slot The id of the slot
* @param pageNumber The number of the page that the gui is on
* @return The index in the list of slots that this id has or <code>-1</code> if it isn't in that list
*/
public int getSlotIndex(int slot, int pageNumber) {
for (int i = 0; i < slots.length; i++) {
if (slots[i] == slot) {
return i + slots.length * pageNumber;
}
}
return -1;
}
/**
* Set the gui this element belongs to
* @param gui The GUI that this element is in
*/
public void setGui(InventoryGui gui) {
this.gui = gui;
}
/**
* Get the gui this element belongs to
* @return The GUI that this element is in
*/
public InventoryGui getGui() {
return gui;
}
public static interface Action {
/**
* Executed when a player clicks on an element
* @param click The Click class containing information about the click
* @return Whether or not the click event should be cancelled
*/
boolean onClick(Click click);
}
public static class Click {
private final InventoryGui gui;
private final int slot;
private final ClickType clickType;
private ItemStack cursor;
private final GuiElement element;
private final InventoryInteractEvent event;
public Click(InventoryGui gui, int slot, ClickType clickType, ItemStack cursor, GuiElement element, InventoryInteractEvent event) {
this.gui = gui;
this.slot = slot;
this.clickType = clickType;
this.cursor = cursor;
this.element = element;
this.event = event;
}
/**
* Get the slot of the GUI that was clicked
* @return The clicked slot
*/
public int getSlot() {
return slot;
}
/**
* Get the element that was clicked
* @return The clicked GuiElement
*/
public GuiElement getElement() {
return element;
}
/**
* Get the type of the click
* @return The type of the click
*/
public ClickType getType() {
return clickType;
}
/**
* Get the item on the cursor
* @return The item on the cursor when this click occurred
*/
public ItemStack getCursor() {
return cursor;
}
/**
* Set the item on the cursor after the click
* @param cursor The new item on the cursor
*/
public void setCursor(ItemStack cursor) {
this.cursor = cursor;
}
/**
* Get who clicked the element
* @return The player that clicked
*/
public HumanEntity getWhoClicked() {
return event.getWhoClicked();
}
/**
* Get the event of the inventory interaction
* @return The InventoryInteractEvent associated with this Click
*/
public InventoryInteractEvent getRawEvent() {
return event;
}
public InventoryGui getGui() {
return gui;
}
}
}

View File

@@ -1,276 +0,0 @@
package net.momirealms.customfishing.libraries.inventorygui;
/*
* Copyright 2017 Max Lee (https://github.com/Phoenix616)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import org.bukkit.entity.HumanEntity;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* Represents a group of multiple elements. Will be left-aligned by default.
*/
public class GuiElementGroup extends GuiElement {
private List<GuiElement> elements = new ArrayList<>();
private GuiElement filler = null;
private Alignment alignment = Alignment.LEFT;
/**
* A group of elements
* @param slotChar The character to replace in the gui setup string
* @param elements The elements in this group
*/
public GuiElementGroup(char slotChar, GuiElement... elements) {
super(slotChar, null);
setAction(click -> {
GuiElement element = getElement(click.getSlot(), click.getGui().getPageNumber(click.getWhoClicked()));
if (element != null && element.getAction(click.getRawEvent().getWhoClicked()) != null) {
return element.getAction(click.getWhoClicked()).onClick(click);
}
return true;
});
Collections.addAll(this.elements, elements);
}
@Override
public ItemStack getItem(HumanEntity who, int slot) {
GuiElement element = getElement(slot, gui.getPageNumber(who));
if (element != null) {
return element.getItem(who, slot);
}
return null;
}
@Override
public void setGui(InventoryGui gui) {
super.setGui(gui);
for (GuiElement element : elements) {
if (element != null) {
element.setGui(gui);
}
}
if (filler != null) {
filler.setGui(gui);
}
}
@Override
public void setSlots(int[] slots) {
super.setSlots(slots);
for (GuiElement element : elements) {
if (element != null) {
element.setSlots(slots);
}
}
}
/**
* Add an element to this group
* @param element The element to add
*/
public void addElement(GuiElement element){
elements.add(element);
if (element != null) {
element.setGui(gui);
element.setSlots(slots);
}
}
/**
* Add elements to this group
* @param elements The elements to add
*/
public void addElements(GuiElement... elements){
for (GuiElement element : elements) {
addElement(element);
}
}
/**
* Add elements to this group
* @param elements The elements to add
*/
public void addElements(Collection<GuiElement> elements){
for (GuiElement element : elements) {
addElement(element);
}
}
/**
* Get the element in a certain slot
* @param slot The slot to get the element for
* @return The GuiElement in that slot or <code>null</code>
*/
public GuiElement getElement(int slot) {
return getElement(slot, 0);
}
/**
* Get the element in a certain slot on a certain page
* @param slot The slot to get the element for
* @param pageNumber The number of the page that the gui is on
* @return The GuiElement in that slot or <code>null</code>
*/
public GuiElement getElement(int slot, int pageNumber) {
if (elements.isEmpty()) {
return null;
}
int index = getSlotIndex(slot, slots.length < elements.size() ? pageNumber : 0);
if (index > -1) {
if (alignment == Alignment.LEFT) {
if (index < elements.size()) {
return elements.get(index);
}
} else {
int lineWidth = getLineWidth(slot);
int linePosition = getLinePosition(slot);
if (elements.size() - index > lineWidth - linePosition) {
return elements.get(index);
}
int rest = elements.size() - (index - linePosition);
int blankBefore = alignment == Alignment.CENTER ? (lineWidth - rest) / 2 : lineWidth - rest;
if (linePosition < blankBefore || index - blankBefore >= elements.size()) {
return filler;
}
return elements.get(index - blankBefore);
}
}
return filler;
}
/**
* Get the width of the line the slot is in
* @param slot The slot
* @return The width of the line in the GUI setup of this group
*/
private int getLineWidth(int slot) {
int width = gui.getWidth();
int row = slot / width;
int amount = 0;
for (int s : slots) {
if (s >= row * width && s < (row + 1) * width) {
amount++;
}
}
return amount;
}
/**
* Get the position of the slot in its line
* @param slot The slot ID
* @return The line position or -1 if not in its line. wat
*/
private int getLinePosition(int slot) {
int width = gui.getWidth();
int row = slot / width;
int position = -1;
for (int s : slots) {
if (s >= row * width && s < (row + 1) * width) {
position++;
if (s == slot) {
return position;
}
}
}
return position;
}
/**
* Get all elements of this group. This list is immutable, use {@link #addElement(GuiElement)}
* and {@link #clearElements()} to modify the elements in this group.
* @return An immutable list of all elements in this group
*/
public List<GuiElement> getElements() {
return Collections.unmodifiableList(elements);
}
/**
* Removes all elements in the group
*/
public void clearElements() {
elements.clear();
}
/**
* Set the filler element for empty slots
* @param item The item for the filler element
*/
public void setFiller(ItemStack item) {
filler = new StaticGuiElement(' ', item, " ");
filler.setGui(gui);
}
/**
* Set the filler element for empty slots
* @param filler The item for the filler element
*/
public void setFiller(GuiElement filler) {
this.filler = filler;
if (filler != null) {
filler.setGui(gui);
}
}
/**
* Get the filler element
* @return The filler element
*/
public GuiElement getFiller() {
return filler;
}
/**
* Get the size of this group
* @return The amount of elements that this group has
*/
public int size() {
return elements.size();
}
/**
* Set the alignment of the elements in this group
* @param alignment The alignment
*/
public void setAlignment(Alignment alignment) {
this.alignment = alignment;
}
/**
* Get the alignment of the elements in this group
* @return The alignment
*/
public Alignment getAlignment() {
return alignment;
}
public enum Alignment {
LEFT,
CENTER,
RIGHT;
}
}

View File

@@ -1,124 +0,0 @@
package net.momirealms.customfishing.libraries.inventorygui;
/*
* Copyright 2017 Max Lee (https://github.com/Phoenix616)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import org.bukkit.entity.HumanEntity;
import org.bukkit.inventory.ItemStack;
/**
* This is an element that allows for controlling the pagination of the gui.
* <b>Untested und potentially unfinished.</b>
*/
public class GuiPageElement extends StaticGuiElement {
private PageAction pageAction;
private boolean silent = false;
/**
* An element that allows for controlling the pagination of the gui.
* @param slotChar The character to replace in the gui setup string
* @param item The {@link ItemStack} representing this element
* @param pageAction What kind of page action you want to happen when interacting with the element.
* @param text The text to display on this element, placeholders are automatically
* replaced, see {@link InventoryGui#replaceVars} for a list of the
* placeholder variables. Empty text strings are also filter out, use
* a single space if you want to add an empty line!<br>
* If it's not set/empty the item's default name will be used
*/
public GuiPageElement(char slotChar, ItemStack item, PageAction pageAction, String... text) {
super(slotChar, item, text);
setAction(click -> {
switch (pageAction) {
case NEXT:
if (click.getGui().getPageNumber(click.getWhoClicked()) + 1 < click.getGui().getPageAmount(click.getWhoClicked())) {
if (!isSilent()) {
click.getGui().playClickSound();
}
click.getGui().setPageNumber(click.getWhoClicked(), click.getGui().getPageNumber(click.getWhoClicked()) + 1);
}
break;
case PREVIOUS:
if (click.getGui().getPageNumber(click.getWhoClicked()) > 0) {
if (!isSilent()) {
click.getGui().playClickSound();
}
click.getGui().setPageNumber(click.getWhoClicked(), click.getGui().getPageNumber(click.getWhoClicked()) - 1);
}
break;
case FIRST:
if (!isSilent()) {
click.getGui().playClickSound();
}
click.getGui().setPageNumber(click.getWhoClicked(), 0);
break;
case LAST:
if (!isSilent()) {
click.getGui().playClickSound();
}
click.getGui().setPageNumber(click.getWhoClicked(), click.getGui().getPageAmount(click.getWhoClicked()) - 1);
break;
}
return true;
});
this.pageAction = pageAction;
}
/**
* Get whether or not this element should make a sound when interacted with
* @return Whether or not to make a sound when interacted with
*/
public boolean isSilent() {
return silent;
}
/**
* Set whether or not this element should make a sound when interacted with
* @param silent Whether or not to make a sound when interacted with
*/
public void setSilent(boolean silent) {
this.silent = silent;
}
@Override
public ItemStack getItem(HumanEntity who, int slot) {
if (((pageAction == PageAction.FIRST || pageAction == PageAction.LAST) && gui.getPageAmount(who) < 3)
|| (pageAction == PageAction.NEXT && gui.getPageNumber(who) + 1 >= gui.getPageAmount(who))
|| (pageAction == PageAction.PREVIOUS && gui.getPageNumber(who) == 0)) {
return gui.getFiller() != null ? gui.getFiller().getItem(who, slot) : null;
}
if (pageAction == PageAction.PREVIOUS) {
setNumber(gui.getPageNumber(who));
} else if (pageAction == PageAction.NEXT) {
setNumber(gui.getPageNumber(who) + 2);
} else if (pageAction == PageAction.LAST) {
setNumber(gui.getPageAmount(who));
}
return super.getItem(who, slot).clone();
}
public enum PageAction {
NEXT,
PREVIOUS,
FIRST,
LAST;
}
}

View File

@@ -1,280 +0,0 @@
package net.momirealms.customfishing.libraries.inventorygui;
/*
* Copyright 2017 Max Lee (https://github.com/Phoenix616)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import org.bukkit.entity.HumanEntity;
import org.bukkit.inventory.ItemStack;
import java.util.function.Supplier;
/**
* An element that can switch between certain states. It automatically handles the switching
* of the item in the slot that corresponds to the state that the element is in.
*/
public class GuiStateElement extends GuiElement {
private Supplier<Integer> queryState = null;
private boolean silent = false;
private int currentState;
private final State[] states;
/**
* An element that can switch between certain states.
* @param slotChar The character to replace in the gui setup string.
* @param defaultState The index of the default state.
* @param states The list of different {@link State}s that this element can have.
*/
public GuiStateElement(char slotChar, int defaultState, State... states) {
super(slotChar, null);
if (states.length == 0) {
throw new IllegalArgumentException("You need to add at least one State!");
}
this.currentState = defaultState;
this.states = states;
setAction(click -> {
State next = nextState();
next.change.onChange(click);
if (!isSilent()) {
click.getGui().playClickSound();
}
gui.draw(click.getWhoClicked(), false);
return true;
});
}
/**
* An element that can switch between certain states.
* @param slotChar The character to replace in the gui setup string.
* @param defaultState The key of the default state.
* @param states The list of different {@link State}s that this element can have.
*/
public GuiStateElement(char slotChar, String defaultState, State... states) {
this(slotChar, getStateIndex(defaultState, states), states);
}
/**
* An element that can switch between certain states.
* @param slotChar The character to replace in the gui setup string.
* @param queryState Supplier for the current state.
* @param states The list of different {@link State}s that this element can have.
*/
public GuiStateElement(char slotChar, Supplier<String> queryState, State... states) {
this(slotChar, queryState.get(), states);
this.queryState = () -> getStateIndex(queryState.get(), states);
}
/**
* An element that can switch between certain states. The first state will be the default one.
* @param slotChar The character to replace in the gui setup string.
* @param states The list of different {@link State}s that this element can have.
*/
public GuiStateElement(char slotChar, State... states) {
this(slotChar, 0, states);
}
/**
* Loop through the states of this element
* @return The new state (next one to the old)
*/
public State nextState() {
queryCurrentState();
currentState = states.length > currentState + 1 ? currentState + 1 : 0;
return states[currentState];
}
/**
* Loop through the states of this element backwards
* @return The new state (previous one to the old)
*/
public State previousState() {
queryCurrentState();
currentState = currentState > 0 ? currentState - 1 : states.length - 1;
return states[currentState];
}
@Override
public ItemStack getItem(HumanEntity who, int slot) {
return getState().getItem(who);
}
@Override
public void setGui(InventoryGui gui) {
super.setGui(gui);
for (State state : states) {
state.setGui(gui);
}
}
/**
* Get the current state of this element
* @return The current state of this element
*/
public State getState() {
queryCurrentState();
return states[currentState];
}
/**
* Get whether or not this element should make a sound when interacted with
* @return Whether or not to make a sound when interacted with
*/
public boolean isSilent() {
return silent;
}
/**
* Set whether or not this element should make a sound when interacted with
* @param silent Whether or not to make a sound when interacted with
*/
public void setSilent(boolean silent) {
this.silent = silent;
}
/**
* Try to query the current state if there is a query
*/
private void queryCurrentState() {
if (queryState != null) {
currentState = queryState.get();
}
}
/**
* Set the current state with the state's key. Does not trigger the state's change.
* @param key The key to search for.
* @throws IllegalArgumentException Thrown if there is no state with the provided key.
*/
public void setState(String key) throws IllegalArgumentException {
currentState = getStateIndex(key, states);
}
/**
* Get the index of a state from a key
* @param key The key to search for.
* @param states The states to search in.
* @return The index of that key in the state array.
* @throws IllegalArgumentException Thrown if there is no state with the provided key.
*/
private static int getStateIndex(String key, State[] states) throws IllegalArgumentException {
for (int i = 0; i < states.length; i++) {
if (states[i].getKey().equals(key)) {
return i;
}
}
throw new IllegalArgumentException("This element does not have the state " + key);
}
/**
* A state that the {@link GuiStateElement} can have.
*/
public static class State {
private final Change change;
private final String key;
private final ItemStack item;
private String[] text;
private InventoryGui gui;
/**
* A state that the {@link GuiStateElement} can have.
* @param change What to do when the state changes
* @param key The state's string key
* @param item The {@link ItemStack} to represent this state
* @param text The text to display on this element, placeholders are automatically
* replaced, see {@link InventoryGui#replaceVars} for a list of the
* placeholder variables. Empty text strings are also filter out, use
* a single space if you want to add an empty line!<br>
* If it's not set/empty the item's default name will be used
*/
public State(Change change, String key, ItemStack item, String... text) {
this.change = change;
this.key = key;
this.item = item;
this.text = text;
}
/**
* Set this element's display text. If this is an empty array the item's name will be displayed
* @param text The text to display on this element, placeholders are automatically
* replaced, see {@link InventoryGui#replaceVars} for a list of the
* placeholder variables. Empty text strings are also filter out, use
* a single space if you want to add an empty line!<br>
* If it's not set/empty the item's default name will be used
*/
public void setText(String... text) {
this.text = text;
}
/**
* Get the {@link ItemStack} that represents this state.
* @return The {@link ItemStack} that represents this state
* @deprecated Use {@link #getItem(HumanEntity)}
*/
@Deprecated
public ItemStack getItem() {
return getItem(null);
}
/**
* Get the {@link ItemStack} that represents this state.
* @param who The player viewing the GUI
* @return The {@link ItemStack} that represents this state
*/
public ItemStack getItem(HumanEntity who) {
ItemStack clone = item.clone();
gui.setItemText(who, clone, getText());
return clone;
}
/**
* Get the string key of the state.
* @return The state's string key
*/
public String getKey() {
return key;
}
/**
* Get the text lines that describe this state.
* @return The text lines for this state
*/
public String[] getText() {
return text;
}
private void setGui(InventoryGui gui) {
this.gui = gui;
}
/**
* Define what should happen when the state of the element' state changes to this state
*/
public interface Change {
/**
* What should happen when the element's state changes to this state
* @param click The click that triggered this change
*/
void onChange(Click click);
}
}
}

View File

@@ -1,368 +0,0 @@
package net.momirealms.customfishing.libraries.inventorygui;
/*
* Copyright 2017 Max Lee (https://github.com/Phoenix616)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.entity.HumanEntity;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import java.util.function.Function;
/**
* This element is used to access an {@link Inventory}. The slots in the inventory are selected
* by searching through the whole gui the element is in and getting the number of the spot
* in the character group that this element is in. <br>
* E.g. if you have five characters called "s" in the gui setup and the second element is
* accessed by the player then it will translate to the second slot in the inventory.
*/
public class GuiStorageElement extends GuiElement {
private final Inventory storage;
private final int invSlot;
private Runnable applyStorage;
private Function<ValidatorInfo, Boolean> itemValidator;
/**
* An element used to access an {@link Inventory}.
* @param slotChar The character to replace in the gui setup string.
* @param storage The {@link Inventory} that this element is linked to.
*/
public GuiStorageElement(char slotChar, Inventory storage) {
this(slotChar, storage, -1);
}
/**
* An element used to access a specific slot in an {@link Inventory}.
* @param slotChar The character to replace in the gui setup string.
* @param storage The {@link Inventory} that this element is linked to.
* @param invSlot The index of the slot to access in the {@link Inventory}.
*/
public GuiStorageElement(char slotChar, Inventory storage, int invSlot) {
this(slotChar, storage, invSlot, null, null);
}
/**
* An element used to access a specific slot in an {@link Inventory}.
* @param slotChar The character to replace in the gui setup string.
* @param storage The {@link Inventory} that this element is linked to.
* @param invSlot The index of the slot to access in the {@link Inventory}.
* @param applyStorage Apply the storage that this element represents.
* @param itemValidator Should return <code>false</code> for items that should not work in that slot
* Can be null if the storage is directly linked.
*/
public GuiStorageElement(char slotChar, Inventory storage, int invSlot, Runnable applyStorage, Function<ValidatorInfo, Boolean> itemValidator) {
super(slotChar, null);
this.invSlot = invSlot;
this.applyStorage = applyStorage;
this.itemValidator = itemValidator;
setAction(click -> {
if (getStorageSlot(click.getWhoClicked(), click.getSlot()) < 0) {
return true;
}
ItemStack storageItem = getStorageItem(click.getWhoClicked(), click.getSlot());
ItemStack slotItem = click.getRawEvent().getView().getTopInventory().getItem(click.getSlot());
if (slotItem == null && storageItem != null && storageItem.getType() != Material.AIR
|| storageItem == null && slotItem != null && slotItem.getType() != Material.AIR
|| storageItem != null && !storageItem.equals(slotItem)) {
gui.draw(click.getWhoClicked(), false);
return true;
}
if (!(click.getRawEvent() instanceof InventoryClickEvent)) {
// Only the click event will be handled here, drag event is handled separately
return true;
}
InventoryClickEvent event = (InventoryClickEvent) click.getRawEvent();
ItemStack movedItem = null;
switch (event.getAction()) {
case NOTHING:
case CLONE_STACK:
return false;
case MOVE_TO_OTHER_INVENTORY:
if (event.getRawSlot() < click.getRawEvent().getView().getTopInventory().getSize()) {
// Moved from storage
// Check if there is actually space (more advanced checks can unfortunately not be supported right now)
if (click.getRawEvent().getView().getBottomInventory().firstEmpty() == -1) {
// No empty slot, cancel
return true;
}
movedItem = null;
} else {
// Moved to storage
// Check if there is actually space (more advanced checks can unfortunately not be supported right now)
if (click.getRawEvent().getView().getTopInventory().firstEmpty() == -1) {
// No empty slot, cancel
return true;
}
movedItem = event.getCurrentItem();
}
// Update GUI to avoid display glitches
gui.runTask(gui::draw);
break;
case HOTBAR_MOVE_AND_READD:
case HOTBAR_SWAP:
int button = event.getHotbarButton();
if (button < 0) {
return true;
}
ItemStack hotbarItem = click.getRawEvent().getView().getBottomInventory().getItem(button);
if (hotbarItem != null) {
movedItem = hotbarItem.clone();
}
break;
case PICKUP_ONE:
case DROP_ONE_SLOT:
if (event.getCurrentItem() != null) {
movedItem = event.getCurrentItem().clone();
movedItem.setAmount(movedItem.getAmount() - 1);
}
break;
case DROP_ALL_SLOT:
movedItem = null;
break;
case PICKUP_HALF:
if (event.getCurrentItem() != null) {
movedItem = event.getCurrentItem().clone();
movedItem.setAmount(movedItem.getAmount() / 2);
}
break;
case PLACE_SOME:
if (event.getCurrentItem() == null) {
if (event.getCursor() != null) {
movedItem = event.getCursor().clone();
}
} else {
movedItem = event.getCurrentItem().clone();
int newAmount = movedItem.getAmount() + (event.getCursor() != null ? event.getCursor().getAmount() : 0);
if (newAmount < movedItem.getMaxStackSize()) {
movedItem.setAmount(newAmount);
} else {
movedItem.setAmount(movedItem.getMaxStackSize());
}
}
break;
case PLACE_ONE:
if (event.getCursor() != null) {
if (event.getCurrentItem() == null) {
movedItem = event.getCursor().clone();
movedItem.setAmount(1);
} else {
movedItem = event.getCursor().clone();
movedItem.setAmount(event.getCurrentItem().getAmount() + 1);
}
}
break;
case PLACE_ALL:
if (event.getCursor() != null) {
movedItem = event.getCursor().clone();
if (event.getCurrentItem() != null && event.getCurrentItem().getAmount() > 0) {
movedItem.setAmount(event.getCurrentItem().getAmount() + movedItem.getAmount());
}
}
break;
case PICKUP_ALL:
case SWAP_WITH_CURSOR:
if (event.getCursor() != null) {
movedItem = event.getCursor().clone();
};
break;
case COLLECT_TO_CURSOR:
if (event.getCursor() == null
|| event.getCurrentItem() != null && event.getCurrentItem().getType() != Material.AIR) {
return true;
}
gui.simulateCollectToCursor(click);
return false;
default:
click.getRawEvent().getWhoClicked().sendMessage(ChatColor.RED + "The action " + event.getAction() + " is not supported! Sorry about that :(");
return true;
}
return !setStorageItem(click.getWhoClicked(), click.getSlot(), movedItem);
});
this.storage = storage;
}
@Override
public ItemStack getItem(HumanEntity who, int slot) {
int index = getStorageSlot(who, slot);
if (index > -1 && index < storage.getSize()) {
return storage.getItem(index);
}
return null;
}
/**
* Get the {@link Inventory} that this element is linked to.
* @return The {@link Inventory} that this element is linked to.
*/
public Inventory getStorage() {
return storage;
}
/**
* Get the storage slot index that corresponds to the InventoryGui slot
* @param player The player which is using the GUI view
* @param slot The slot in the GUI
* @return The index of the storage slot or <code>-1</code> if it's outside the storage
*/
private int getStorageSlot(HumanEntity player, int slot) {
int index = invSlot != -1 ? invSlot : getSlotIndex(slot, gui.getPageNumber(player));
if (index < 0 || index >= storage.getSize()) {
return -1;
}
return index;
}
/**
* Get the item in the storage that corresponds to the InventoryGui slot
* @param slot The slot in the GUI
* @return The {@link ItemStack} or <code>null</code> if the slot is outside of the item's size
* @deprecated Use {@link #getStorageItem(HumanEntity, int)}
*/
@Deprecated
public ItemStack getStorageItem(int slot) {
return getStorageItem(null, slot);
}
/**
* Get the item in the storage that corresponds to the InventoryGui slot
* @param player The player which is using the GUI view
* @param slot The slot in the GUI
* @return The {@link ItemStack} or <code>null</code> if the slot is outside of the item's size
*/
public ItemStack getStorageItem(HumanEntity player, int slot) {
int index = getStorageSlot(player, slot);
if (index == -1) {
return null;
}
return storage.getItem(index);
}
/**
* Set the item in the storage that corresponds to the InventoryGui slot.
* @param slot The slot in the GUI
* @param item The {@link ItemStack} to set
* @return <code>true</code> if the item was set; <code>false</code> if the slot was outside of this storage
* @deprecated Use {@link #setStorageItem(HumanEntity, int, ItemStack)}
*/
@Deprecated
public boolean setStorageItem(int slot, ItemStack item) {
return setStorageItem(null, slot, item);
}
/**
* Set the item in the storage that corresponds to the InventoryGui slot.
* @param player The player using the GUI view
* @param slot The slot in the GUI
* @param item The {@link ItemStack} to set
* @return <code>true</code> if the item was set; <code>false</code> if the slot was outside of this storage
*/
public boolean setStorageItem(HumanEntity player, int slot, ItemStack item) {
int index = getStorageSlot(player, slot);
if (index == -1) {
return false;
}
if (!validateItem(slot, item)) {
return false;
}
storage.setItem(index, item);
if (applyStorage != null) {
applyStorage.run();
}
return true;
}
/**
* Get the runnable that applies the storage
* @return The storage applying runnable; might be null
*/
public Runnable getApplyStorage() {
return applyStorage;
}
/**
* Set what should be done to apply the storage.
* Not necessary if the storage is directly backed by a real inventory.
* @param applyStorage How to apply the storage; can be null if nothing should be done
*/
public void setApplyStorage(Runnable applyStorage) {
this.applyStorage = applyStorage;
}
/**
* Get the item validator
* @return The item validator
*/
public Function<ValidatorInfo, Boolean> getItemValidator() {
return itemValidator;
}
/**
* Set a function that can validate whether or not an item can fit in the slot
* @param itemValidator The item validator that takes a {@link ValidatorInfo} and returns <code>true</code> for items that
* should and <code>false</code> for items that should not work in that slot
*/
public void setItemValidator(Function<ValidatorInfo, Boolean> itemValidator) {
this.itemValidator = itemValidator;
}
/**
* Validate whether or not an item can be put in a slot with the item validator set in {@link #setItemValidator(Function)}
* @param slot The slot the item should be tested for
* @param item The item to test
* @return <code>true</code> for items that should and <code>false</code> for items that should not work in that slot
*/
public boolean validateItem(int slot, ItemStack item) {
return itemValidator == null || itemValidator.apply(new ValidatorInfo(this, slot, item));
}
public static class ValidatorInfo {
private final GuiElement element;
private final int slot;
private final ItemStack item;
public ValidatorInfo(GuiElement element, int slot, ItemStack item) {
this.item = item;
this.slot = slot;
this.element = element;
}
public GuiElement getElement() {
return element;
}
public int getSlot() {
return slot;
}
public ItemStack getItem() {
return item;
}
}
}

View File

@@ -1,159 +0,0 @@
package net.momirealms.customfishing.libraries.inventorygui;
/*
* Copyright 2017 Max Lee (https://github.com/Phoenix616)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import org.bukkit.entity.HumanEntity;
import org.bukkit.inventory.ItemStack;
/**
* Represents a simple element in a gui to which an action can be assigned.
* If you want the item to change on click you have to do that yourself.
*/
public class StaticGuiElement extends GuiElement {
private ItemStack item;
private int number;
private String[] text;
/**
* Represents an element in a gui
* @param slotChar The character to replace in the gui setup string
* @param item The item this element displays
* @param number The number, 1 will not display the number
* @param action The action to run when the player clicks on this element
* @param text The text to display on this element, placeholders are automatically
* replaced, see for a list of the
* placeholder variables. Empty text strings are also filter out, use
* a single space if you want to add an empty line!<br>
* If it's not set/empty the item's default name will be used
* @throws IllegalArgumentException If the number is below 1 or above the max stack count (currently 64)
*/
public StaticGuiElement(char slotChar, ItemStack item, int number, Action action, String... text) throws IllegalArgumentException {
super(slotChar, action);
this.item = item;
this.text = text;
setNumber(number);
}
/**
* Represents an element in a gui
* @param slotChar The character to replace in the gui setup string
* @param item The item this element displays
* @param action The action to run when the player clicks on this element
* @param text The text to display on this element, placeholders are automatically
* replaced, see {@link InventoryGui#replaceVars} for a list of the
* placeholder variables. Empty text strings are also filter out, use
* a single space if you want to add an empty line!<br>
* If it's not set/empty the item's default name will be used
*/
public StaticGuiElement(char slotChar, ItemStack item, Action action, String... text) {
this(slotChar, item, item != null ? item.getAmount() : 1, action, text);
}
/**
* Represents an element in a gui that doesn't have any action when clicked
* @param slotChar The character to replace in the gui setup string
* @param item The item this element displays
* @param text The text to display on this element, placeholders are automatically
* replaced, see {@link InventoryGui#replaceVars} for a list of the
* placeholder variables. Empty text strings are also filter out, use
* a single space if you want to add an empty line!<br>
* If it's not set/empty the item's default name will be used
*/
public StaticGuiElement(char slotChar, ItemStack item, String... text) {
this(slotChar, item, item != null ? item.getAmount() : 1, null, text);
}
/**
* Set the item that is displayed by this element
* @param item The item that should be displayed by this element
*/
public void setItem(ItemStack item) {
this.item = item;
}
/**
* Get the raw item displayed by this element which was passed to the constructor or set with {@link #setItem(ItemStack)}.
* This item will not have the amount or text applied! Use {@link #getItem(HumanEntity, int)} for that!
* @return The raw item
*/
public ItemStack getRawItem() {
return item;
}
@Override
public ItemStack getItem(HumanEntity who, int slot) {
if (item == null) {
return null;
}
ItemStack clone = item.clone();
gui.setItemText(who, clone, getText());
if (number > 0 && number <= 64) {
clone.setAmount(number);
}
return clone;
}
/**
* Set this element's display text. If this is an empty array the item's name will be displayed
* @param text The text to display on this element, placeholders are automatically
* replaced, see {@link InventoryGui#replaceVars} for a list of the
* placeholder variables. Empty text strings are also filter out, use
* a single space if you want to add an empty line!<br>
* If it's not set/empty the item's default name will be used
*/
public void setText(String... text) {
this.text = text;
}
/**
* Get the text that this element displays
* @return The text that is displayed on this element
*/
public String[] getText() {
return text;
}
/**
* Set the number that this element should display (via the Item's amount)
* @param number The number, 1 will not display the number
* @return <code>true</code> if the number was set; <code>false</code> if it was below 1 or above 64
*/
public boolean setNumber(int number) {
if (number < 1 || number > 64) {
this.number = 1;
return false;
}
this.number = number;
return true;
}
/**
* Get the number that this element should display
* @return The number (item amount) that this element currently has
*/
public int getNumber() {
return number;
}
}

View File

@@ -20,6 +20,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
public class ActionManagerImpl implements ActionManager {
@@ -43,6 +44,8 @@ public class ActionManagerImpl implements ActionManager {
this.registerPluginExpAction();
this.registerTitleAction();
this.registerActionBarAction();
this.registerCloseInvAction();
this.registerDelayedAction();
}
@Override
@@ -153,6 +156,13 @@ public class ActionManagerImpl implements ActionManager {
});
}
private void registerCloseInvAction() {
registerAction("close-inv", (args, chance) -> condition -> {
if (Math.random() > chance) return;
condition.getPlayer().closeInventory();
});
}
private void registerActionBarAction() {
registerAction("actionbar", (args, chance) -> {
String text = (String) args;
@@ -217,6 +227,34 @@ public class ActionManagerImpl implements ActionManager {
});
}
private void registerDelayedAction() {
registerAction("delay", (args, chance) -> {
List<Action> actions = new ArrayList<>();
int delay;
if (args instanceof ConfigurationSection section) {
delay = section.getInt("delay", 1);
ConfigurationSection actionSection = section.getConfigurationSection("action");
if (actionSection != null) {
for (Map.Entry<String, Object> entry : actionSection.getValues(false).entrySet()) {
if (entry.getValue() instanceof ConfigurationSection innerSection) {
actions.add(getAction(innerSection));
}
}
}
} else {
delay = 1;
}
return condition -> {
if (Math.random() > chance) return;
plugin.getScheduler().runTaskSyncLater(() -> {
for (Action action : actions) {
action.trigger(condition);
}
}, condition.getLocation(), delay * 50L, TimeUnit.MILLISECONDS);
};
});
}
private void registerTitleAction() {
registerAction("title", (args, chance) -> {
if (args instanceof ConfigurationSection section) {

View File

@@ -2,6 +2,7 @@ package net.momirealms.customfishing.mechanic.fishing;
import com.destroystokyo.paper.event.player.PlayerJumpEvent;
import de.tr7zw.changeme.nbtapi.NBTItem;
import io.papermc.paper.event.player.AsyncChatEvent;
import net.momirealms.customfishing.CustomFishingPluginImpl;
import net.momirealms.customfishing.api.common.Pair;
import net.momirealms.customfishing.api.event.LavaFishingEvent;
@@ -33,16 +34,14 @@ import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryPickupItemEvent;
import org.bukkit.event.player.PlayerAttemptPickupItemEvent;
import org.bukkit.event.player.PlayerFishEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.player.PlayerSwapHandItemsEvent;
import org.bukkit.event.player.*;
import org.bukkit.inventory.ItemStack;
import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
@@ -174,6 +173,16 @@ public class FishingManagerImpl implements Listener, FishingManager {
}
}
@EventHandler
public void onChat(AsyncPlayerChatEvent event) {
if (event.isCancelled()) return;
GamingPlayer gamingPlayer = gamingPlayerMap.get(event.getPlayer().getUniqueId());
if (gamingPlayer != null) {
if (gamingPlayer.onChat(event.getMessage()))
event.setCancelled(true);
}
}
@Override
public boolean removeHook(UUID uuid) {
FishHook hook = hookCacheMap.remove(uuid);
@@ -185,6 +194,11 @@ public class FishingManagerImpl implements Listener, FishingManager {
}
}
@Override
public Optional<FishHook> getHook(UUID uuid) {
return Optional.ofNullable(hookCacheMap.get(uuid));
}
public void selectState(PlayerFishEvent event) {
if (event.isCancelled()) return;
switch (event.getState()) {

View File

@@ -341,11 +341,9 @@ public class GameManagerImpl implements GameManager {
+ FontUtils.surroundWithFont(fishImage, font)
+ OffsetUtils.getOffsetChars((int) (barEffectiveWidth - fish_position - fishIconWidth + 1))
;
AdventureManagerImpl.getInstance().sendTitle(
player,
tip != null && !played ? tip :
title.replace("{progress}", progress[(int) ((hold_time / time_requirement) * progress.length)])
tip != null && !played ? tip : title.replace("{progress}", progress[(int) ((hold_time / time_requirement) * progress.length)])
,
bar,
0,

View File

@@ -0,0 +1,14 @@
package net.momirealms.customfishing.mechanic.market;
import org.bukkit.inventory.ItemStack;
public class MarketDynamicGUIElement extends MarketGUIElement {
public MarketDynamicGUIElement(char symbol, ItemStack itemStack) {
super(symbol, itemStack);
}
public void setItemStack(ItemStack itemStack) {
super.itemStack = itemStack;
}
}

View File

@@ -0,0 +1,140 @@
package net.momirealms.customfishing.mechanic.market;
import net.momirealms.customfishing.adventure.AdventureManagerImpl;
import net.momirealms.customfishing.api.mechanic.market.MarketGUIHolder;
import net.momirealms.customfishing.api.util.InventoryUtils;
import net.momirealms.customfishing.api.util.LogUtils;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
public class MarketGUI {
private final HashMap<Character, MarketGUIElement> itemsCharMap;
private final HashMap<Integer, MarketGUIElement> itemsSlotMap;
private final Inventory inventory;
private final MarketManagerImpl manager;
private final Player owner;
public MarketGUI(MarketManagerImpl manager, Player player) {
this.manager = manager;
this.owner = player;
this.itemsCharMap = new HashMap<>();
this.itemsSlotMap = new HashMap<>();
var holder = new MarketGUIHolder();
this.inventory = InventoryUtils.createInventory(
holder,
manager.getLayout().length * 9,
AdventureManagerImpl.getInstance().getComponentFromMiniMessage(manager.getTitle())
);
holder.setInventory(this.inventory);
}
private void init() {
int line = 0;
for (String content : manager.getLayout()) {
if (content.length() != 9) {
LogUtils.warn("Please make sure that GUI layout has 9 elements in each row");
return;
}
for (int index = 0; index < 9; index++) {
char symbol = content.charAt(index);
MarketGUIElement element = itemsCharMap.get(symbol);
element.addSlot(index + line * 9);
itemsSlotMap.put(index + line * 9, element);
}
line++;
}
for (Map.Entry<Integer, MarketGUIElement> entry : itemsSlotMap.entrySet()) {
this.inventory.setItem(entry.getKey(), entry.getValue().getItemStack().clone());
}
}
public MarketGUI addElement(MarketGUIElement... elements) {
for (MarketGUIElement element : elements) {
itemsCharMap.put(element.getSymbol(), element);
}
return this;
}
public MarketGUI build() {
init();
return this;
}
public void show(Player player) {
if (player != owner) return;
player.openInventory(inventory);
}
@Nullable
public MarketGUIElement getElement(int slot) {
return itemsSlotMap.get(slot);
}
@Nullable
public MarketGUIElement getElement(char slot) {
return itemsCharMap.get(slot);
}
public void refresh() {
double totalWorth = getTotalWorth();
if (totalWorth <= 0) {
addElement(new MarketDynamicGUIElement(
manager.getFunctionSlot(),
manager.getFunctionIconDenyBuilder().build(owner,
Map.of("{worth}", String.format("%.2f", totalWorth)
,"{player}", owner.getName())
)
));
} else {
addElement(new MarketDynamicGUIElement(
manager.getFunctionSlot(),
manager.getFunctionIconAllowBuilder().build(owner,
Map.of("{worth}", String.format("%.2f", totalWorth)
,"{player}", owner.getName())
)
));
}
for (Map.Entry<Integer, MarketGUIElement> entry : itemsSlotMap.entrySet()) {
if (entry.getValue() instanceof MarketDynamicGUIElement dynamicGUIElement) {
this.inventory.setItem(entry.getKey(), dynamicGUIElement.getItemStack().clone());
}
}
}
public double getTotalWorth() {
double money = 0d;
MarketGUIElement itemElement = getElement(manager.getItemSlot());
if (itemElement == null) {
LogUtils.warn("No item slot available. Please check if GUI layout contains the item slot symbol.");
return money;
}
for (int slot : itemElement.getSlots()) {
money += manager.getItemPrice(this.inventory.getItem(slot));
}
return money;
}
public Inventory getInventory() {
return inventory;
}
public void clearWorthyItems() {
MarketGUIElement itemElement = getElement(manager.getItemSlot());
if (itemElement == null) {
return;
}
for (int slot : itemElement.getSlots()) {
double money = manager.getItemPrice(inventory.getItem(slot));
if (money != 0) {
inventory.setItem(slot, new ItemStack(Material.AIR));
}
}
}
}

View File

@@ -0,0 +1,35 @@
package net.momirealms.customfishing.mechanic.market;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.List;
public class MarketGUIElement {
private final char symbol;
private final List<Integer> slots;
protected ItemStack itemStack;
public MarketGUIElement(char symbol, ItemStack itemStack) {
this.symbol = symbol;
this.itemStack = itemStack;
this.slots = new ArrayList<>();
}
public void addSlot(int slot) {
slots.add(slot);
}
public char getSymbol() {
return symbol;
}
public ItemStack getItemStack() {
return itemStack;
}
public List<Integer> getSlots() {
return slots;
}
}

View File

@@ -1,29 +1,33 @@
package net.momirealms.customfishing.mechanic.market;
import de.tr7zw.changeme.nbtapi.NBTItem;
import net.momirealms.customfishing.adventure.AdventureManagerImpl;
import net.momirealms.customfishing.api.CustomFishingPlugin;
import net.momirealms.customfishing.api.data.user.OnlineUser;
import net.momirealms.customfishing.api.manager.MarketManager;
import net.momirealms.customfishing.api.mechanic.item.BuildableItem;
import net.momirealms.customfishing.api.mechanic.item.ItemBuilder;
import net.momirealms.customfishing.api.mechanic.market.MarketGUI;
import net.momirealms.customfishing.libraries.inventorygui.InventoryGui;
import net.momirealms.customfishing.libraries.inventorygui.StaticGuiElement;
import net.momirealms.customfishing.mechanic.item.ItemManagerImpl;
import net.momirealms.customfishing.api.mechanic.market.MarketGUIHolder;
import net.momirealms.customfishing.util.ConfigUtils;
import net.objecthunter.exp4j.Expression;
import net.objecthunter.exp4j.ExpressionBuilder;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
public class MarketManagerImpl implements MarketManager {
public class MarketManagerImpl implements MarketManager, Listener {
private final CustomFishingPlugin plugin;
private final HashMap<String, Double> priceMap;
@@ -32,14 +36,36 @@ public class MarketManagerImpl implements MarketManager {
private String formula;
private final HashMap<Character, ItemBuilder> decorativeIcons;
private char itemSlot;
private char functionSlot;
private BuildableItem functionIconAllowBuilder;
private BuildableItem functionIconDenyBuilder;
private double earningLimit;
private ConcurrentHashMap<UUID, MarketGUI> marketGUIMap;
public MarketManagerImpl(CustomFishingPlugin plugin) {
this.plugin = plugin;
this.priceMap = new HashMap<>();
this.decorativeIcons = new HashMap<>();
this.marketGUIMap = new ConcurrentHashMap<>();
}
public void load() {
this.loadConfig();
Bukkit.getPluginManager().registerEvents(this, plugin);
}
public void unload() {
HandlerList.unregisterAll(this);
this.priceMap.clear();
this.decorativeIcons.clear();
}
public void disable() {
unload();
}
private void loadConfig() {
YamlConfiguration config = plugin.getConfig("market.yml");
this.layout = config.getStringList("layout").toArray(new String[0]);
this.title = config.getString("title", "market.title");
@@ -62,38 +88,74 @@ public class MarketManagerImpl implements MarketManager {
}
}
public void unload() {
this.priceMap.clear();
this.decorativeIcons.clear();
}
public void disable() {
unload();
}
public void openMarketGUI(Player player) {
player.closeInventory();
MarketGUI gui = new MarketGUI(this, player);
InventoryGui gui = new InventoryGui(
plugin,
new MarketGUI(),
AdventureManagerImpl.getInstance().getComponentFromMiniMessage(title),
layout
);
}
gui.setCloseAction(close -> {
var elements = gui.getElement(itemSlot);
@EventHandler
public void onClickInv(InventoryClickEvent event) {
if (event.isCancelled())
return;
Inventory clickedInv = event.getClickedInventory();
if (clickedInv == null)
return;
HumanEntity human = event.getWhoClicked();
if (!(clickedInv.getHolder() instanceof MarketGUIHolder holder))
return;
return false;
});
for (Map.Entry<Character, ItemBuilder> entry : decorativeIcons.entrySet()) {
gui.addElement(new StaticGuiElement(
entry.getKey(),
((ItemManagerImpl.CFBuilder) entry.getValue()).build()
));
MarketGUI gui = marketGUIMap.get(human.getUniqueId());
if (gui == null) {
event.setCancelled(true);
human.closeInventory();
return;
}
int slot = event.getSlot();
MarketGUIElement element = gui.getElement(slot);
if (element == null) {
event.setCancelled(true);
return;
}
if (element.getSymbol() == itemSlot) {
plugin.getScheduler().runTaskSyncLater(gui::refresh, human.getLocation(), 50, TimeUnit.MILLISECONDS);
return;
}
if (element.getSymbol() == functionSlot) {
event.setCancelled(true);
double worth = gui.getTotalWorth();
if (worth > 0) {
double remainingToEarn = getRemainingMoneyToEarn(human.getUniqueId());
if (remainingToEarn < worth) {
} else {
gui.clearWorthyItems();
this.setRemainMoneyToEarn(human.getUniqueId(), remainingToEarn + worth);
}
}
plugin.getScheduler().runTaskSyncLater(gui::refresh, human.getLocation(), 50, TimeUnit.MILLISECONDS);
return;
}
event.setCancelled(true);
}
public double getRemainingMoneyToEarn(UUID uuid) {
OnlineUser user = plugin.getStorageManager().getOnlineUser(uuid);
if (user == null) {
return -1;
}
return earningLimit - user.getEarningData().earnings;
}
public void setRemainMoneyToEarn(UUID uuid, double remaining) {
OnlineUser user = plugin.getStorageManager().getOnlineUser(uuid);
if (user == null) {
return;
}
user.getEarningData().earnings = remaining;
}
@Override
@@ -133,4 +195,28 @@ public class MarketManagerImpl implements MarketManager {
.setVariable("size", size);
return expression.evaluate();
}
public char getItemSlot() {
return itemSlot;
}
public char getFunctionSlot() {
return functionSlot;
}
public String[] getLayout() {
return layout;
}
public String getTitle() {
return title;
}
public BuildableItem getFunctionIconAllowBuilder() {
return functionIconAllowBuilder;
}
public BuildableItem getFunctionIconDenyBuilder() {
return functionIconDenyBuilder;
}
}

View File

@@ -9,10 +9,10 @@ layout:
- 'AIIIIIIIA'
- 'AAAABAAAA'
# Price formula (For customfishing loots)
# Price formula (For CustomFishing loots)
price-formula: '{base} + {bonus} * {size}'
# Item price (For vanilla items & other plugin items)
# Item price (For vanilla items & other plugin items that have CustomModelData)
item-price:
# Vanilla Items
COD: 10
@@ -22,30 +22,39 @@ item-price:
# PAPER (CustomModelData: 999)
PAPER:999: 5
# Functional icons
# Slots to put items in
item-slot:
symbol: 'I'
# Functional icon
functional-icons:
symbol: 'B'
sell-icon:
symbol: 'B'
material: IRON_BLOCK
display:
name: '<#00CED1><bold>● <bold:false>Sell the fish'
name: '<#00CED1><b>● <!b>Ship the fish'
lore:
- '<font:uniform><gradient:#E6E6FA:#48D1CC:#E6E6FA>You will gain {money}$</gradient></font>'
- '<font:uniform><gradient:#E6E6FA:#48D1CC:#E6E6FA>You will get <green>{money}$</green> by selling the fish</gradient></font>'
action:
message:
sound_action:
type: sound
message_action:
type: message
text: 'You earned {money}$ from selling the fish! You can still gain {remains}$ from selling fish today'
chance: 1.0
value: 'You earned {money}$ by selling the fish! You can still get {remains}$ from market today'
command_action:
type: command
value: 'money give {player} {money}'
deny-icon:
symbol: 'B'
material: REDSTONE_BLOCK
display:
name: '<red><bold>● <bold:false>Denied'
name: '<red><b>● <!b>Denied trade'
lore:
- '<font:uniform><gradient:#E6E6FA:red:#E6E6FA>Nothing to sell!</gradient></font>'
item-slot:
symbol: 'I'
action:
sound_action:
type: sound
# Decorative icons
decorative-icons:
glass-pane:
symbol: 'A'