Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
00ea3506ca | ||
|
|
521659cfec | ||
|
|
bbe5f1eba4 | ||
|
|
eae5d29f8d | ||
|
|
c878d6fd12 | ||
|
|
2b97c0072f | ||
|
|
63079df745 | ||
|
|
079b41e877 | ||
|
|
1aaab459d8 | ||
|
|
db78c2eb4c | ||
|
|
02fd07b3c8 | ||
|
|
3de2e53031 | ||
|
|
cb088bb70b | ||
|
|
36fca7016f | ||
|
|
7e1137da06 | ||
|
|
0da104d614 | ||
|
|
9095de7d19 | ||
|
|
7a8abac1a2 | ||
|
|
1ddcb6e964 | ||
|
|
4d0858ad84 | ||
|
|
3d05695a36 | ||
|
|
d676be15ce | ||
|
|
16848caec1 | ||
|
|
ef26fe4629 | ||
|
|
29fbd785d7 | ||
|
|
8c73676ee0 | ||
|
|
ebf27d28d9 | ||
|
|
317bc13f65 | ||
|
|
b8ec0ee6fc | ||
|
|
307e57c902 | ||
|
|
db0d55659f | ||
|
|
548529feb3 | ||
|
|
fb56baf452 | ||
|
|
5d18b424d7 | ||
|
|
7be9a1bd10 | ||
|
|
97c39b56dd | ||
|
|
3a9f5bc139 | ||
|
|
1e5955f249 | ||
|
|
bad076bbe9 | ||
|
|
e219b2f33c | ||
|
|
2f7603409e | ||
|
|
28cdb65176 | ||
|
|
03ae9e89b3 |
@@ -35,7 +35,7 @@ allprojects {
|
||||
// NMS (for jitpack compilation)
|
||||
maven("https://repo.codemc.org/repository/nms/")
|
||||
|
||||
// bStats, mcMMO, BentoBox
|
||||
// mcMMO, BentoBox
|
||||
maven("https://repo.codemc.org/repository/maven-public/")
|
||||
|
||||
// Spigot API, Bungee API
|
||||
|
||||
@@ -524,6 +524,25 @@ public interface Config extends Cloneable {
|
||||
@Nullable
|
||||
List<Double> getDoublesOrNull(@NotNull String path);
|
||||
|
||||
/**
|
||||
* Get a list of subsections from config.
|
||||
*
|
||||
* @param path The key to fetch the value from.
|
||||
* @return The found value, or a blank {@link java.util.ArrayList} if not found.
|
||||
*/
|
||||
@NotNull
|
||||
List<? extends Config> getSubsections(@NotNull String path);
|
||||
|
||||
/**
|
||||
* Get a list of subsections from config.
|
||||
*
|
||||
* @param path The key to fetch the value from.
|
||||
* @return The found value, or null if not found.
|
||||
*/
|
||||
@Nullable
|
||||
List<? extends Config> getSubsectionsOrNull(@NotNull String path);
|
||||
|
||||
|
||||
/**
|
||||
* Clone the config.
|
||||
*
|
||||
|
||||
@@ -173,6 +173,16 @@ public abstract class ConfigWrapper<T extends Config> implements Config {
|
||||
return handle.getDoublesOrNull(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull List<? extends Config> getSubsections(@NotNull final String path) {
|
||||
return handle.getSubsections(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable List<? extends Config> getSubsectionsOrNull(@NotNull final String path) {
|
||||
return handle.getSubsectionsOrNull(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Config clone() {
|
||||
return handle.clone();
|
||||
|
||||
@@ -14,16 +14,23 @@ import java.io.StringReader;
|
||||
*/
|
||||
public class YamlTransientConfig extends YamlConfigWrapper {
|
||||
/**
|
||||
* @param config The YamlConfiguration handle.
|
||||
* @param config The YamlConfiguration handle.
|
||||
*/
|
||||
public YamlTransientConfig(@NotNull final YamlConfiguration config) {
|
||||
super(Eco.getHandler().getConfigFactory().createYamlConfig(config));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param contents The contents of the config.
|
||||
* @param contents The contents of the config.
|
||||
*/
|
||||
public YamlTransientConfig(@NotNull final String contents) {
|
||||
super(Eco.getHandler().getConfigFactory().createYamlConfig(YamlConfiguration.loadConfiguration(new StringReader(contents))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new empty transient config.
|
||||
*/
|
||||
public YamlTransientConfig() {
|
||||
super(Eco.getHandler().getConfigFactory().createYamlConfig(YamlConfiguration.loadConfiguration(new StringReader(""))));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
package com.willfp.eco.core.events;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.player.PlayerEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Called on DropQueue push.
|
||||
*/
|
||||
public class DropQueuePushEvent extends PlayerEvent implements Cancellable {
|
||||
/**
|
||||
* Cancel state.
|
||||
*/
|
||||
private boolean cancelled;
|
||||
|
||||
/**
|
||||
* If telekinetic.
|
||||
*/
|
||||
private final boolean isTelekinetic;
|
||||
|
||||
/**
|
||||
* The items.
|
||||
*/
|
||||
private final Collection<? extends ItemStack> items;
|
||||
|
||||
/**
|
||||
* The xp.
|
||||
*/
|
||||
private final int xp;
|
||||
|
||||
/**
|
||||
* The location.
|
||||
*/
|
||||
private final Location location;
|
||||
|
||||
/**
|
||||
* Bukkit parity.
|
||||
*/
|
||||
private static final HandlerList HANDLERS = new HandlerList();
|
||||
|
||||
/**
|
||||
* Create a new DropQueuePushEvent.
|
||||
*
|
||||
* @param player The player.
|
||||
* @param items The items.
|
||||
* @param location The location.
|
||||
* @param xp The xp.
|
||||
* @param isTelekinetic If the event is telekinetic.
|
||||
*/
|
||||
public DropQueuePushEvent(@NotNull final Player player,
|
||||
@NotNull final Collection<? extends ItemStack> items,
|
||||
@NotNull final Location location,
|
||||
final int xp,
|
||||
final boolean isTelekinetic) {
|
||||
super(player);
|
||||
this.items = items;
|
||||
this.location = location;
|
||||
this.xp = xp;
|
||||
this.isTelekinetic = isTelekinetic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of handlers handling this event.
|
||||
*
|
||||
* @return A list of handlers handling this event.
|
||||
*/
|
||||
@Override
|
||||
@NotNull
|
||||
public HandlerList getHandlers() {
|
||||
return HANDLERS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bukkit parity.
|
||||
*
|
||||
* @return The handler list.
|
||||
*/
|
||||
public static HandlerList getHandlerList() {
|
||||
return HANDLERS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cancel state.
|
||||
*
|
||||
* @return The cancel state.
|
||||
*/
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return this.cancelled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set cancel state.
|
||||
*
|
||||
* @param cancelled If cancelled.
|
||||
*/
|
||||
@Override
|
||||
public void setCancelled(final boolean cancelled) {
|
||||
this.cancelled = cancelled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the items to be dropped.
|
||||
*
|
||||
* @return The items.
|
||||
*/
|
||||
public Collection<? extends ItemStack> getItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the xp to be dropped.
|
||||
*
|
||||
* @return The xp.
|
||||
*/
|
||||
public int getXp() {
|
||||
return xp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the location.
|
||||
*
|
||||
* @return The location.
|
||||
*/
|
||||
public Location getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get force telekinesis state.
|
||||
*
|
||||
* @return The force telekinesis state.
|
||||
*/
|
||||
public boolean isTelekinetic() {
|
||||
return this.isTelekinetic;
|
||||
}
|
||||
}
|
||||
@@ -37,6 +37,17 @@ public final class AntigriefManager {
|
||||
REGISTERED.remove(antigrief);
|
||||
}
|
||||
|
||||
/**
|
||||
* Can player pickup item.
|
||||
*
|
||||
* @param player The player.
|
||||
* @param location The location.
|
||||
* @return If player can pick up item.
|
||||
*/
|
||||
public static boolean canPickupItem(@NotNull final Player player, @NotNull final Location location) {
|
||||
return REGISTERED.stream().allMatch(antigriefWrapper -> antigriefWrapper.canPickupItem(player, location));
|
||||
}
|
||||
|
||||
/**
|
||||
* Can player break block.
|
||||
*
|
||||
@@ -45,7 +56,7 @@ public final class AntigriefManager {
|
||||
* @return If player can break block.
|
||||
*/
|
||||
public static boolean canBreakBlock(@NotNull final Player player,
|
||||
@NotNull final Block block) {
|
||||
@NotNull final Block block) {
|
||||
return REGISTERED.stream().allMatch(antigriefWrapper -> antigriefWrapper.canBreakBlock(player, block));
|
||||
}
|
||||
|
||||
@@ -57,7 +68,7 @@ public final class AntigriefManager {
|
||||
* @return If player can create explosion.
|
||||
*/
|
||||
public static boolean canCreateExplosion(@NotNull final Player player,
|
||||
@NotNull final Location location) {
|
||||
@NotNull final Location location) {
|
||||
return REGISTERED.stream().allMatch(antigriefWrapper -> antigriefWrapper.canCreateExplosion(player, location));
|
||||
}
|
||||
|
||||
@@ -69,7 +80,7 @@ public final class AntigriefManager {
|
||||
* @return If player can place block.
|
||||
*/
|
||||
public static boolean canPlaceBlock(@NotNull final Player player,
|
||||
@NotNull final Block block) {
|
||||
@NotNull final Block block) {
|
||||
return REGISTERED.stream().allMatch(antigriefWrapper -> antigriefWrapper.canPlaceBlock(player, block));
|
||||
}
|
||||
|
||||
@@ -81,7 +92,7 @@ public final class AntigriefManager {
|
||||
* @return If player can injure.
|
||||
*/
|
||||
public static boolean canInjure(@NotNull final Player player,
|
||||
@NotNull final LivingEntity victim) {
|
||||
@NotNull final LivingEntity victim) {
|
||||
return REGISTERED.stream().allMatch(antigriefWrapper -> antigriefWrapper.canInjure(player, victim));
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import org.bukkit.Location;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Wrapper class for antigrief integrations.
|
||||
@@ -17,7 +18,7 @@ public interface AntigriefWrapper extends Integration {
|
||||
* @param block The block.
|
||||
* @return If player can break block.
|
||||
*/
|
||||
boolean canBreakBlock(Player player, Block block);
|
||||
boolean canBreakBlock(@NotNull Player player, @NotNull Block block);
|
||||
|
||||
/**
|
||||
* Can player create explosion at location.
|
||||
@@ -26,7 +27,7 @@ public interface AntigriefWrapper extends Integration {
|
||||
* @param location The location.
|
||||
* @return If player can create explosion.
|
||||
*/
|
||||
boolean canCreateExplosion(Player player, Location location);
|
||||
boolean canCreateExplosion(@NotNull Player player, @NotNull Location location);
|
||||
|
||||
/**
|
||||
* Can player place block.
|
||||
@@ -35,7 +36,7 @@ public interface AntigriefWrapper extends Integration {
|
||||
* @param block The block.
|
||||
* @return If player can place block.
|
||||
*/
|
||||
boolean canPlaceBlock(Player player, Block block);
|
||||
boolean canPlaceBlock(@NotNull Player player, @NotNull Block block);
|
||||
|
||||
/**
|
||||
* Can player injure living entity.
|
||||
@@ -44,5 +45,15 @@ public interface AntigriefWrapper extends Integration {
|
||||
* @param victim The victim.
|
||||
* @return If player can injure.
|
||||
*/
|
||||
boolean canInjure(Player player, LivingEntity victim);
|
||||
boolean canInjure(@NotNull Player player, @NotNull LivingEntity victim);
|
||||
|
||||
/**
|
||||
* Can player pick up item.
|
||||
*
|
||||
* @param player The player.
|
||||
* @param location The location.
|
||||
* @return If player can pick up item.
|
||||
*/
|
||||
boolean canPickupItem(@NotNull Player player, @NotNull Location location);
|
||||
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ public final class Items {
|
||||
* @param item The item.
|
||||
*/
|
||||
public static void registerCustomItem(@NotNull final NamespacedKey key,
|
||||
@NotNull final TestableItem item) {
|
||||
@NotNull final TestableItem item) {
|
||||
REGISTRY.put(key, item);
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ public final class Items {
|
||||
/**
|
||||
* This is the backbone of the entire eco item system.
|
||||
* <p>
|
||||
* You can lookup a TestableItem for any material, custom item,
|
||||
* You can look up a TestableItem for any material, custom item,
|
||||
* or item in general, and it will return it with any modifiers
|
||||
* passed as parameters. This includes stack size (item amount)
|
||||
* and enchantments that should be present on the item.
|
||||
@@ -94,8 +94,8 @@ public final class Items {
|
||||
* <p>
|
||||
* The advantages of the testable item system are that there is the inbuilt
|
||||
* {@link TestableItem#matches(ItemStack)} - this allows to check if any item
|
||||
* is that testable item; which may sound negligible but actually it allows for
|
||||
* much more power an flexibility. For example, you can have an item with an
|
||||
* is that testable item; which may sound negligible, but actually it allows for
|
||||
* much more power and flexibility. For example, you can have an item with an
|
||||
* extra metadata tag, extra lore lines, different display name - and it
|
||||
* will still work as long as the test passes. This is very important
|
||||
* for custom crafting recipes where other plugins may add metadata
|
||||
@@ -104,6 +104,7 @@ public final class Items {
|
||||
* @param key The lookup string.
|
||||
* @return The testable item, or an {@link EmptyTestableItem}.
|
||||
*/
|
||||
@NotNull
|
||||
public static TestableItem lookup(@NotNull final String key) {
|
||||
if (key.contains("?")) {
|
||||
String[] options = key.split("\\?");
|
||||
@@ -235,6 +236,37 @@ public final class Items {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a Testable Item from an ItemStack.
|
||||
* <p>
|
||||
* Will search for registered items first. If there are no matches in the registry,
|
||||
* then it will return a {@link MaterialTestableItem} matching the item type.
|
||||
* <p>
|
||||
* Does not account for modifiers (arg parser data).
|
||||
*
|
||||
* @param item The ItemStack.
|
||||
* @return The found Testable Item.
|
||||
*/
|
||||
@NotNull
|
||||
public static TestableItem getItem(@Nullable final ItemStack item) {
|
||||
if (item == null || item.getType().isAir()) {
|
||||
return new EmptyTestableItem();
|
||||
}
|
||||
|
||||
CustomItem customItem = getCustomItem(item);
|
||||
|
||||
if (customItem != null) {
|
||||
return customItem;
|
||||
}
|
||||
|
||||
for (TestableItem known : REGISTRY.values()) {
|
||||
if (known.matches(item)) {
|
||||
return known;
|
||||
}
|
||||
}
|
||||
return new MaterialTestableItem(item.getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get if itemStack is a custom item.
|
||||
*
|
||||
@@ -284,6 +316,7 @@ public final class Items {
|
||||
* @param item The item.
|
||||
* @return The CustomItem.
|
||||
*/
|
||||
@NotNull
|
||||
public static CustomItem getOrWrap(@NotNull final TestableItem item) {
|
||||
if (item instanceof CustomItem) {
|
||||
return (CustomItem) item;
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.willfp.eco.core.items.args;
|
||||
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Parse leather armor colors.
|
||||
*
|
||||
* @deprecated Moved to internals.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public class ColorArgParser implements LookupArgParser {
|
||||
@Override
|
||||
public @Nullable Predicate<ItemStack> parseArguments(@NotNull final String[] args,
|
||||
@NotNull final ItemMeta meta) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -9,49 +9,14 @@ import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Parse custom model data.
|
||||
*
|
||||
* @deprecated Moved to internals.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public class CustomModelDataArgParser implements LookupArgParser {
|
||||
@Override
|
||||
public @Nullable Predicate<ItemStack> parseArguments(@NotNull final String[] args,
|
||||
@NotNull final ItemMeta meta) {
|
||||
Integer modelData = null;
|
||||
|
||||
for (String arg : args) {
|
||||
String[] argSplit = arg.split(":");
|
||||
if (!argSplit[0].equalsIgnoreCase("custom-model-data")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argSplit.length < 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String asString = argSplit[1];
|
||||
|
||||
try {
|
||||
modelData = Integer.parseInt(asString);
|
||||
} catch (NumberFormatException e) {
|
||||
modelData = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (modelData == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
meta.setCustomModelData(modelData);
|
||||
|
||||
int finalModelData = modelData;
|
||||
return test -> {
|
||||
if (!test.hasItemMeta()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ItemMeta testMeta = test.getItemMeta();
|
||||
|
||||
assert testMeta != null;
|
||||
|
||||
return testMeta.getCustomModelData() == finalModelData;
|
||||
};
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,83 +1,22 @@
|
||||
package com.willfp.eco.core.items.args;
|
||||
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Parses enchantment arguments.
|
||||
*
|
||||
* @deprecated Moved to internals.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public class EnchantmentArgParser implements LookupArgParser {
|
||||
@Override
|
||||
public @Nullable Predicate<ItemStack> parseArguments(@NotNull final String[] args,
|
||||
@NotNull final ItemMeta meta) {
|
||||
Map<Enchantment, Integer> requiredEnchantments = new HashMap<>();
|
||||
|
||||
for (String enchantArg : args) {
|
||||
String[] enchantArgSplit = enchantArg.split(":");
|
||||
|
||||
Enchantment enchantment = Enchantment.getByKey(NamespacedKey.minecraft(enchantArgSplit[0].toLowerCase()));
|
||||
if (enchantment == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (enchantArgSplit.length < 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int level = Integer.parseInt(enchantArgSplit[1]);
|
||||
|
||||
requiredEnchantments.put(enchantment, level);
|
||||
}
|
||||
|
||||
if (requiredEnchantments.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (meta instanceof EnchantmentStorageMeta storageMeta) {
|
||||
requiredEnchantments.forEach((enchantment, integer) -> storageMeta.addStoredEnchant(enchantment, integer, true));
|
||||
} else {
|
||||
requiredEnchantments.forEach((enchantment, integer) -> meta.addEnchant(enchantment, integer, true));
|
||||
}
|
||||
|
||||
return test -> {
|
||||
if (!test.hasItemMeta()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ItemMeta testMeta = test.getItemMeta();
|
||||
|
||||
assert testMeta != null;
|
||||
|
||||
if (testMeta instanceof EnchantmentStorageMeta storageMeta) {
|
||||
for (Map.Entry<Enchantment, Integer> entry : requiredEnchantments.entrySet()) {
|
||||
if (!storageMeta.hasStoredEnchant(entry.getKey())) {
|
||||
return false;
|
||||
}
|
||||
if (storageMeta.getStoredEnchantLevel(entry.getKey()) < entry.getValue()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (Map.Entry<Enchantment, Integer> entry : requiredEnchantments.entrySet()) {
|
||||
if (!testMeta.hasEnchant(entry.getKey())) {
|
||||
return false;
|
||||
}
|
||||
if (testMeta.getEnchantLevel(entry.getKey()) < entry.getValue()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package com.willfp.eco.core.items.args;
|
||||
|
||||
import com.willfp.eco.util.SkullUtils;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.inventory.meta.SkullMeta;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -11,49 +9,14 @@ import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Parse skull textures.
|
||||
*
|
||||
* @deprecated Moved to internals.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public class TextureArgParser implements LookupArgParser {
|
||||
@Override
|
||||
public @Nullable Predicate<ItemStack> parseArguments(@NotNull final String[] args,
|
||||
@NotNull final ItemMeta meta) {
|
||||
String skullTexture = null;
|
||||
|
||||
for (String arg : args) {
|
||||
String[] argSplit = arg.split(":");
|
||||
if (!argSplit[0].equalsIgnoreCase("texture")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (argSplit.length < 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
skullTexture = argSplit[1];
|
||||
}
|
||||
|
||||
if (meta instanceof SkullMeta skullMeta && skullTexture != null) {
|
||||
SkullUtils.setSkullTexture(skullMeta, skullTexture);
|
||||
}
|
||||
|
||||
if (skullTexture == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String finalSkullTexture = skullTexture;
|
||||
return test -> {
|
||||
if (!test.hasItemMeta()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ItemMeta testMeta = test.getItemMeta();
|
||||
|
||||
assert testMeta != null;
|
||||
|
||||
if (testMeta instanceof SkullMeta skullMeta) {
|
||||
return finalSkullTexture.equalsIgnoreCase(SkullUtils.getSkullTexture(skullMeta));
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.willfp.eco.util;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -21,8 +20,8 @@ public final class ListUtils {
|
||||
* @return The list, filled will null objects.
|
||||
*/
|
||||
@NotNull
|
||||
public static <@Nullable T> List<List<T>> create2DList(final int rows,
|
||||
final int columns) {
|
||||
public static <T> List<List<T>> create2DList(final int rows,
|
||||
final int columns) {
|
||||
List<List<T>> list = new ArrayList<>(rows);
|
||||
while (list.size() < rows) {
|
||||
List<T> row = new ArrayList<>(columns);
|
||||
|
||||
@@ -14,7 +14,7 @@ import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.Color;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@@ -30,7 +30,7 @@ open class EcoLoadableJSONConfig(
|
||||
}
|
||||
}
|
||||
|
||||
override fun createFile() {
|
||||
final override fun createFile() {
|
||||
val inputStream = source.getResourceAsStream(resourcePath)!!
|
||||
val outFile = File(this.plugin.dataFolder, resourcePath)
|
||||
val lastIndex = resourcePath.lastIndexOf('/')
|
||||
@@ -40,7 +40,7 @@ open class EcoLoadableJSONConfig(
|
||||
}
|
||||
if (!outFile.exists()) {
|
||||
val out: OutputStream = FileOutputStream(outFile)
|
||||
inputStream.copyTo(out, 1024)
|
||||
inputStream.copyTo(out)
|
||||
out.close()
|
||||
inputStream.close()
|
||||
}
|
||||
|
||||
@@ -40,11 +40,10 @@ open class EcoLoadableYamlConfig(
|
||||
}
|
||||
if (!outFile.exists()) {
|
||||
val out: OutputStream = FileOutputStream(outFile)
|
||||
inputStream.copyTo(out, 1024)
|
||||
inputStream.copyTo(out)
|
||||
out.close()
|
||||
inputStream.close()
|
||||
}
|
||||
plugin.configHandler.addConfig(this)
|
||||
}
|
||||
|
||||
override fun getResourcePath(): String {
|
||||
|
||||
@@ -5,12 +5,11 @@ import com.willfp.eco.util.StringUtils
|
||||
import org.bukkit.configuration.ConfigurationSection
|
||||
import org.bukkit.configuration.file.YamlConfiguration
|
||||
import java.io.StringReader
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
open class EcoYamlConfigWrapper<T : ConfigurationSection> : Config {
|
||||
lateinit var handle: T
|
||||
private val cache = ConcurrentHashMap<String, Any?>()
|
||||
private val cache = mutableMapOf<String, Any?>()
|
||||
|
||||
protected fun init(config: T): Config {
|
||||
handle = config
|
||||
@@ -70,9 +69,9 @@ open class EcoYamlConfigWrapper<T : ConfigurationSection> : Config {
|
||||
|
||||
override fun getInt(path: String): Int {
|
||||
return if (cache.containsKey(path)) {
|
||||
cache[path] as Int
|
||||
(cache[path] as Number).toInt()
|
||||
} else {
|
||||
cache[path] = handle.getInt(path, 0)
|
||||
cache[path] = handle.getDouble(path, 0.0).toInt()
|
||||
getInt(path)
|
||||
}
|
||||
}
|
||||
@@ -90,9 +89,9 @@ open class EcoYamlConfigWrapper<T : ConfigurationSection> : Config {
|
||||
def: Int
|
||||
): Int {
|
||||
return if (cache.containsKey(path)) {
|
||||
cache[path] as Int
|
||||
(cache[path] as Number).toInt()
|
||||
} else {
|
||||
cache[path] = handle.getInt(path, def)
|
||||
cache[path] = handle.getDouble(path, def.toDouble()).toInt()
|
||||
getInt(path)
|
||||
}
|
||||
}
|
||||
@@ -262,6 +261,31 @@ open class EcoYamlConfigWrapper<T : ConfigurationSection> : Config {
|
||||
}
|
||||
}
|
||||
|
||||
override fun getSubsections(path: String): MutableList<out Config> {
|
||||
return if (cache.containsKey(path)) {
|
||||
(cache[path] as Collection<Config>).toMutableList()
|
||||
} else {
|
||||
val mapList = ArrayList(handle.getMapList(path)) as List<Map<String, Any?>>
|
||||
val configList = mutableListOf<Config>()
|
||||
for (map in mapList) {
|
||||
val temp = YamlConfiguration.loadConfiguration(StringReader(""))
|
||||
temp.createSection("a", map)
|
||||
configList.add(EcoYamlConfigSection(temp.getConfigurationSection("a")!!))
|
||||
}
|
||||
|
||||
cache[path] = if (has(path)) configList else emptyList()
|
||||
getSubsections(path)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getSubsectionsOrNull(path: String): MutableList<out Config>? {
|
||||
return if (has(path)) {
|
||||
getSubsections(path)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
override fun clone(): Config {
|
||||
return EcoYamlConfigSection(
|
||||
YamlConfiguration.loadConfiguration(
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.willfp.eco.internal.drops.impl
|
||||
|
||||
import com.willfp.eco.core.drops.InternalDropQueue
|
||||
import com.willfp.eco.core.events.DropQueuePushEvent
|
||||
import com.willfp.eco.core.integrations.antigrief.AntigriefManager
|
||||
import com.willfp.eco.util.TelekinesisUtils
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.Location
|
||||
@@ -15,7 +17,7 @@ import org.bukkit.util.Vector
|
||||
open class EcoDropQueue(val player: Player) : InternalDropQueue {
|
||||
val items = mutableListOf<ItemStack>()
|
||||
var xp: Int = 0
|
||||
var loc: Location
|
||||
var location: Location
|
||||
var hasTelekinesis = false
|
||||
|
||||
override fun addItem(item: ItemStack): InternalDropQueue {
|
||||
@@ -34,7 +36,7 @@ open class EcoDropQueue(val player: Player) : InternalDropQueue {
|
||||
}
|
||||
|
||||
override fun setLocation(location: Location): InternalDropQueue {
|
||||
loc = location
|
||||
this.location = location
|
||||
return this
|
||||
}
|
||||
|
||||
@@ -47,8 +49,20 @@ open class EcoDropQueue(val player: Player) : InternalDropQueue {
|
||||
if (!hasTelekinesis) {
|
||||
hasTelekinesis = TelekinesisUtils.testPlayer(player)
|
||||
}
|
||||
val world = loc.world!!
|
||||
loc = loc.add(0.5, 0.5, 0.5)
|
||||
|
||||
if (hasTelekinesis && !AntigriefManager.canPickupItem(player, location)) {
|
||||
hasTelekinesis = false
|
||||
}
|
||||
|
||||
val pushEvent = DropQueuePushEvent(player, items, location, xp, hasTelekinesis)
|
||||
Bukkit.getServer().pluginManager.callEvent(pushEvent)
|
||||
|
||||
if (pushEvent.isCancelled) {
|
||||
return
|
||||
}
|
||||
|
||||
val world = location.world!!
|
||||
location = location.add(0.5, 0.5, 0.5)
|
||||
items.removeIf { itemStack: ItemStack -> itemStack.type == Material.AIR }
|
||||
if (items.isEmpty()) {
|
||||
return
|
||||
@@ -56,7 +70,7 @@ open class EcoDropQueue(val player: Player) : InternalDropQueue {
|
||||
if (hasTelekinesis) {
|
||||
val leftover = player.inventory.addItem(*items.toTypedArray())
|
||||
for (drop in leftover.values) {
|
||||
world.dropItem(loc, drop!!).velocity = Vector()
|
||||
world.dropItem(location, drop!!).velocity = Vector()
|
||||
}
|
||||
if (xp > 0) {
|
||||
val event = PlayerExpChangeEvent(player, xp)
|
||||
@@ -68,16 +82,16 @@ open class EcoDropQueue(val player: Player) : InternalDropQueue {
|
||||
}
|
||||
} else {
|
||||
for (drop in items) {
|
||||
world.dropItem(loc, drop).velocity = Vector()
|
||||
world.dropItem(location, drop).velocity = Vector()
|
||||
}
|
||||
if (xp > 0) {
|
||||
val orb = world.spawnEntity(loc, EntityType.EXPERIENCE_ORB) as ExperienceOrb
|
||||
val orb = world.spawnEntity(location, EntityType.EXPERIENCE_ORB) as ExperienceOrb
|
||||
orb.experience = xp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
loc = player.location
|
||||
location = player.location
|
||||
}
|
||||
}
|
||||
@@ -10,10 +10,10 @@ class EcoFastCollatedDropQueue(player: Player) : EcoDropQueue(player) {
|
||||
val fetched = COLLATED_MAP[player]
|
||||
|
||||
if (fetched == null) {
|
||||
COLLATED_MAP[player] = CollatedDrops(items, loc, xp, hasTelekinesis)
|
||||
COLLATED_MAP[player] = CollatedDrops(items, location, xp, hasTelekinesis)
|
||||
} else {
|
||||
fetched.addDrops(items)
|
||||
fetched.location = loc
|
||||
fetched.location = location
|
||||
fetched.addXp(xp)
|
||||
if (this.hasTelekinesis) {
|
||||
fetched.forceTelekinesis()
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.willfp.eco.internal.gui.menu
|
||||
|
||||
import com.willfp.eco.internal.gui.slot.EcoCaptivatorSlot
|
||||
import com.willfp.eco.util.MenuUtils
|
||||
import com.willfp.eco.util.StringUtils
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.NamespacedKey
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.inventory.Inventory
|
||||
@@ -20,12 +20,14 @@ class ExtendedInventory(
|
||||
for (i in 0 until inventory.size) {
|
||||
val (row, column) = MenuUtils.convertSlotToRowColumn(i)
|
||||
val slot = menu.getSlot(row, column)
|
||||
if (slot is EcoCaptivatorSlot) {
|
||||
if (slot.isCaptive) {
|
||||
val defaultItem = slot.getItemStack(player)
|
||||
val item = inventory.getItem(i) ?: continue
|
||||
if (item != defaultItem) {
|
||||
captiveItems.add(item)
|
||||
if (item == defaultItem && item.type == Material.AIR) {
|
||||
continue
|
||||
}
|
||||
|
||||
captiveItems.add(item)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
package com.willfp.eco.internal.gui.slot
|
||||
|
||||
import com.willfp.eco.core.Eco
|
||||
import com.willfp.eco.core.gui.slot.functional.SlotHandler
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.inventory.ItemStack
|
||||
|
||||
class EcoCaptivatorSlot : EcoSlot(
|
||||
{ _, _ -> ItemStack(Material.AIR) },
|
||||
allowMovingItem,
|
||||
allowMovingItem,
|
||||
allowMovingItem,
|
||||
allowMovingItem,
|
||||
allowMovingItem,
|
||||
{ _, _, _ -> }
|
||||
) {
|
||||
companion object {
|
||||
val plugin = Eco.getHandler().ecoPlugin
|
||||
|
||||
val allowMovingItem = SlotHandler { event, _, _ ->
|
||||
event.isCancelled = false
|
||||
}
|
||||
}
|
||||
|
||||
override fun isCaptive(): Boolean {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.willfp.eco.internal.gui.slot
|
||||
|
||||
import com.willfp.eco.core.gui.slot.functional.SlotHandler
|
||||
import com.willfp.eco.core.gui.slot.functional.SlotProvider
|
||||
|
||||
class EcoCaptiveSlot(
|
||||
provider: SlotProvider
|
||||
) : EcoSlot(
|
||||
provider,
|
||||
allowMovingItem,
|
||||
allowMovingItem,
|
||||
allowMovingItem,
|
||||
allowMovingItem,
|
||||
allowMovingItem,
|
||||
{ _, _, _ -> }
|
||||
) {
|
||||
override fun isCaptive(): Boolean {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
private val allowMovingItem = SlotHandler { event, _, _ ->
|
||||
event.isCancelled = false
|
||||
}
|
||||
@@ -31,8 +31,7 @@ open class EcoSlot(
|
||||
ClickType.SHIFT_LEFT -> this.onShiftLeftClick.handle(event, this, menu)
|
||||
ClickType.SHIFT_RIGHT -> this.onShiftRightClick.handle(event, this, menu)
|
||||
ClickType.MIDDLE -> this.onMiddleClick.handle(event, this, menu)
|
||||
else -> {
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ class EcoSlotBuilder(private val provider: SlotProvider) : SlotBuilder {
|
||||
|
||||
override fun build(): Slot {
|
||||
return if (captive) {
|
||||
EcoCaptivatorSlot()
|
||||
EcoCaptiveSlot(provider)
|
||||
} else {
|
||||
EcoSlot(provider, onLeftClick, onRightClick, onShiftLeftClick, onShiftRightClick, onMiddleClick, modifier)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.willfp.eco.internal.items
|
||||
|
||||
import com.willfp.eco.core.items.args.LookupArgParser
|
||||
import org.bukkit.Color
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import org.bukkit.inventory.meta.ItemMeta
|
||||
import org.bukkit.inventory.meta.LeatherArmorMeta
|
||||
import java.util.function.Predicate
|
||||
|
||||
class ArgParserColor : LookupArgParser {
|
||||
override fun parseArguments(args: Array<out String>, meta: ItemMeta): Predicate<ItemStack>? {
|
||||
if (meta !is LeatherArmorMeta) {
|
||||
return null
|
||||
}
|
||||
|
||||
var color: String? = null
|
||||
|
||||
for (arg in args) {
|
||||
val argSplit = arg.split(":")
|
||||
if (!argSplit[0].equals("color", ignoreCase = true)) {
|
||||
continue
|
||||
}
|
||||
if (argSplit.size < 2) {
|
||||
continue
|
||||
}
|
||||
color = argSplit[1].replace("#","")
|
||||
}
|
||||
|
||||
color ?: return null
|
||||
|
||||
meta.setColor(Color.fromRGB(Integer.parseInt(color, 16)))
|
||||
|
||||
return Predicate {
|
||||
val testMeta = it.itemMeta as? LeatherArmorMeta ?: return@Predicate false
|
||||
|
||||
color.equals(
|
||||
Integer.toHexString(testMeta.color.red)
|
||||
+ Integer.toHexString(testMeta.color.green)
|
||||
+ Integer.toHexString(testMeta.color.blue),
|
||||
ignoreCase = true
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.willfp.eco.internal.items
|
||||
|
||||
import com.willfp.eco.core.items.args.LookupArgParser
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import org.bukkit.inventory.meta.ItemMeta
|
||||
import java.util.function.Predicate
|
||||
|
||||
class ArgParserCustomModelData : LookupArgParser {
|
||||
override fun parseArguments(args: Array<out String>, meta: ItemMeta): Predicate<ItemStack>? {
|
||||
var modelData: Int? = null
|
||||
|
||||
for (arg in args) {
|
||||
val argSplit = arg.split(":")
|
||||
if (!argSplit[0].equals("custom-model-data", ignoreCase = true)) {
|
||||
continue
|
||||
}
|
||||
if (argSplit.size < 2) {
|
||||
continue
|
||||
}
|
||||
modelData = argSplit[1].toIntOrNull()
|
||||
}
|
||||
|
||||
modelData ?: return null
|
||||
|
||||
meta.setCustomModelData(modelData)
|
||||
|
||||
return Predicate {
|
||||
val testMeta = it.itemMeta ?: return@Predicate false
|
||||
|
||||
testMeta.customModelData == modelData
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.willfp.eco.internal.items
|
||||
|
||||
import com.willfp.eco.core.fast.FastItemStack
|
||||
import com.willfp.eco.core.items.args.LookupArgParser
|
||||
import org.bukkit.NamespacedKey
|
||||
import org.bukkit.enchantments.Enchantment
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import org.bukkit.inventory.meta.EnchantmentStorageMeta
|
||||
import org.bukkit.inventory.meta.ItemMeta
|
||||
import java.util.function.Predicate
|
||||
|
||||
class ArgParserEnchantment : LookupArgParser {
|
||||
override fun parseArguments(args: Array<out String>, meta: ItemMeta): Predicate<ItemStack>? {
|
||||
val enchants = mutableMapOf<Enchantment, Int>()
|
||||
|
||||
for (arg in args) {
|
||||
val argSplit = arg.split(":")
|
||||
|
||||
if (argSplit.size < 2) {
|
||||
continue
|
||||
}
|
||||
|
||||
val enchant = Enchantment.getByKey(NamespacedKey.minecraft(argSplit[0].lowercase()))
|
||||
val level = argSplit[1].toIntOrNull()
|
||||
|
||||
if (enchant != null && level != null) {
|
||||
enchants[enchant] = level
|
||||
}
|
||||
}
|
||||
|
||||
if (enchants.isEmpty()) {
|
||||
return null
|
||||
}
|
||||
|
||||
for ((enchant, level) in enchants) {
|
||||
if (meta is EnchantmentStorageMeta) {
|
||||
meta.addStoredEnchant(enchant, level, true)
|
||||
} else {
|
||||
meta.addEnchant(enchant, level, true)
|
||||
}
|
||||
}
|
||||
|
||||
return Predicate {
|
||||
val onItem = FastItemStack.wrap(it).getEnchantmentsOnItem(true)
|
||||
|
||||
for ((enchant, level) in enchants) {
|
||||
if ((onItem[enchant] ?: 0) < level) {
|
||||
return@Predicate false
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.willfp.eco.internal.items
|
||||
|
||||
import com.willfp.eco.core.items.args.LookupArgParser
|
||||
import org.bukkit.inventory.ItemFlag
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import org.bukkit.inventory.meta.ItemMeta
|
||||
import java.util.function.Predicate
|
||||
|
||||
class ArgParserFlag : LookupArgParser {
|
||||
override fun parseArguments(args: Array<out String>, meta: ItemMeta): Predicate<ItemStack>? {
|
||||
val flags = mutableSetOf<ItemFlag>()
|
||||
|
||||
for (arg in args) {
|
||||
val flag = try {
|
||||
ItemFlag.valueOf(arg.uppercase())
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
} ?: continue
|
||||
|
||||
flags.add(flag)
|
||||
}
|
||||
|
||||
if (flags.isEmpty()) {
|
||||
return null
|
||||
}
|
||||
|
||||
meta.addItemFlags(*flags.toTypedArray())
|
||||
|
||||
return Predicate {
|
||||
val testMeta = it.itemMeta ?: return@Predicate false
|
||||
|
||||
testMeta.itemFlags.containsAll(flags)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.willfp.eco.internal.items
|
||||
|
||||
import com.willfp.eco.core.items.args.LookupArgParser
|
||||
import com.willfp.eco.util.StringUtils
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import org.bukkit.inventory.meta.ItemMeta
|
||||
import java.util.function.Predicate
|
||||
|
||||
class ArgParserName : LookupArgParser {
|
||||
override fun parseArguments(args: Array<out String>, meta: ItemMeta): Predicate<ItemStack>? {
|
||||
var name: String? = null
|
||||
|
||||
for (arg in args) {
|
||||
val argSplit = arg.split(":")
|
||||
if (!argSplit[0].equals("name", ignoreCase = true)) {
|
||||
continue
|
||||
}
|
||||
if (argSplit.size < 2) {
|
||||
continue
|
||||
}
|
||||
name = argSplit[1].replace("_", "")
|
||||
}
|
||||
|
||||
name ?: return null
|
||||
|
||||
val formatted = StringUtils.format(name)
|
||||
|
||||
meta.setDisplayName(formatted)
|
||||
|
||||
return Predicate {
|
||||
val testMeta = it.itemMeta ?: return@Predicate false
|
||||
|
||||
testMeta.displayName == formatted
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.willfp.eco.internal.items
|
||||
|
||||
import com.willfp.eco.core.items.args.LookupArgParser
|
||||
import com.willfp.eco.util.SkullUtils
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import org.bukkit.inventory.meta.ItemMeta
|
||||
import org.bukkit.inventory.meta.SkullMeta
|
||||
import java.util.function.Predicate
|
||||
|
||||
class ArgParserTexture : LookupArgParser {
|
||||
override fun parseArguments(args: Array<out String>, meta: ItemMeta): Predicate<ItemStack>? {
|
||||
if (meta !is SkullMeta) {
|
||||
return null
|
||||
}
|
||||
|
||||
var texture: String? = null
|
||||
|
||||
for (arg in args) {
|
||||
val argSplit = arg.split(":")
|
||||
if (!argSplit[0].equals("texture", ignoreCase = true)) {
|
||||
continue
|
||||
}
|
||||
if (argSplit.size < 2) {
|
||||
continue
|
||||
}
|
||||
texture = argSplit[1]
|
||||
}
|
||||
|
||||
texture ?: return null
|
||||
|
||||
SkullUtils.setSkullTexture(meta, texture)
|
||||
|
||||
return Predicate {
|
||||
val testMeta = it.itemMeta as? SkullMeta ?: return@Predicate false
|
||||
|
||||
texture == SkullUtils.getSkullTexture(testMeta)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.willfp.eco.internal.items
|
||||
|
||||
import com.willfp.eco.core.items.args.LookupArgParser
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import org.bukkit.inventory.meta.ItemMeta
|
||||
import java.util.function.Predicate
|
||||
|
||||
class ArgParserUnbreakable : LookupArgParser {
|
||||
override fun parseArguments(args: Array<out String>, meta: ItemMeta): Predicate<ItemStack>? {
|
||||
var unbreakable = false
|
||||
|
||||
for (arg in args) {
|
||||
if (arg.equals("unbreakable", true)) {
|
||||
unbreakable = true
|
||||
}
|
||||
}
|
||||
|
||||
if (!unbreakable) {
|
||||
return null
|
||||
}
|
||||
|
||||
meta.isUnbreakable = true
|
||||
|
||||
return Predicate {
|
||||
val testMeta = it.itemMeta ?: return@Predicate false
|
||||
|
||||
testMeta.isUnbreakable
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,6 @@ class RequirementPlaceholderGreaterThan : Requirement() {
|
||||
|
||||
val placeholder = args[0]
|
||||
val equals = args[1].toDoubleOrNull() ?: return false
|
||||
return PlaceholderManager.translatePlaceholders(placeholder, player).toDoubleOrNull() ?: 0.0 >= equals
|
||||
return (PlaceholderManager.translatePlaceholders(placeholder, player).toDoubleOrNull() ?: 0.0) >= equals
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,6 @@ class RequirementPlaceholderLessThan : Requirement() {
|
||||
|
||||
val placeholder = args[0]
|
||||
val equals = args[1].toDoubleOrNull() ?: return false
|
||||
return PlaceholderManager.translatePlaceholders(placeholder, player).toDoubleOrNull() ?: 0.0 < equals
|
||||
return (PlaceholderManager.translatePlaceholders(placeholder, player).toDoubleOrNull() ?: 0.0) < equals
|
||||
}
|
||||
}
|
||||
@@ -165,7 +165,7 @@ class NMSFastItemStack(itemStack: org.bukkit.inventory.ItemStack) : EcoFastItemS
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return handle.tag?.hashCode() ?: 0b00010101 * 31 + Item.getId(handle.item)
|
||||
return handle.tag?.hashCode() ?: (0b00010101 * 31 + Item.getId(handle.item))
|
||||
}
|
||||
|
||||
private fun apply() {
|
||||
|
||||
@@ -180,7 +180,7 @@ class NMSFastItemStack(itemStack: org.bukkit.inventory.ItemStack) : EcoFastItemS
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return handle.tag?.hashCode() ?: 0b00010101 * 31 + Item.getId(handle.item)
|
||||
return handle.tag?.hashCode() ?: (0b00010101 * 31 + Item.getId(handle.item))
|
||||
}
|
||||
|
||||
private fun apply() {
|
||||
|
||||
@@ -2,7 +2,6 @@ group 'com.willfp'
|
||||
version rootProject.version
|
||||
|
||||
dependencies {
|
||||
implementation 'org.bstats:bstats-bukkit:1.7'
|
||||
implementation('net.kyori:adventure-text-minimessage:4.1.0-SNAPSHOT') {
|
||||
exclude group: 'net.kyori', module: 'adventure-api'
|
||||
}
|
||||
@@ -40,6 +39,7 @@ dependencies {
|
||||
compileOnly 'com.iridium:IridiumSkyblock:3.1.2'
|
||||
compileOnly 'com.github.WillFP:CrashClaim:1.0.19'
|
||||
compileOnly 'com.wolfyscript.wolfyutilities:wolfyutilities:1.7.8.1'
|
||||
compileOnly 'com.github.decentsoftware-eu:decentholograms:2.1.2'
|
||||
|
||||
// CombatLogX V10 + NewbieHelper Expansion
|
||||
compileOnly 'com.SirBlobman.combatlogx:CombatLogX-API:10.0.0.0-SNAPSHOT'
|
||||
|
||||
@@ -118,7 +118,7 @@ class EcoHandler : com.willfp.eco.internal.spigot.EcoSpigotPlugin(), Handler {
|
||||
}
|
||||
|
||||
override fun registerBStats(plugin: EcoPlugin) {
|
||||
MetricHandler.createMetrics(plugin, this.ecoPlugin)
|
||||
MetricHandler.createMetrics(plugin)
|
||||
}
|
||||
|
||||
override fun getRequirementFactory(): EcoRequirementFactory {
|
||||
|
||||
@@ -15,11 +15,15 @@ import com.willfp.eco.core.integrations.hologram.HologramManager
|
||||
import com.willfp.eco.core.integrations.mcmmo.McmmoManager
|
||||
import com.willfp.eco.core.integrations.shop.ShopManager
|
||||
import com.willfp.eco.core.items.Items
|
||||
import com.willfp.eco.core.items.args.CustomModelDataArgParser
|
||||
import com.willfp.eco.core.items.args.EnchantmentArgParser
|
||||
import com.willfp.eco.core.items.args.TextureArgParser
|
||||
import com.willfp.eco.internal.display.EcoDisplayHandler
|
||||
import com.willfp.eco.internal.drops.DropManager
|
||||
import com.willfp.eco.internal.items.ArgParserColor
|
||||
import com.willfp.eco.internal.items.ArgParserCustomModelData
|
||||
import com.willfp.eco.internal.items.ArgParserEnchantment
|
||||
import com.willfp.eco.internal.items.ArgParserFlag
|
||||
import com.willfp.eco.internal.items.ArgParserName
|
||||
import com.willfp.eco.internal.items.ArgParserTexture
|
||||
import com.willfp.eco.internal.items.ArgParserUnbreakable
|
||||
import com.willfp.eco.internal.spigot.arrows.ArrowDataListener
|
||||
import com.willfp.eco.internal.spigot.data.DataListener
|
||||
import com.willfp.eco.internal.spigot.data.PlayerBlockListener
|
||||
@@ -65,6 +69,7 @@ import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsItemsA
|
||||
import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsOraxen
|
||||
import com.willfp.eco.internal.spigot.integrations.economy.EconomyVault
|
||||
import com.willfp.eco.internal.spigot.integrations.hologram.HologramCMI
|
||||
import com.willfp.eco.internal.spigot.integrations.hologram.HologramDecentHolograms
|
||||
import com.willfp.eco.internal.spigot.integrations.hologram.HologramHolographicDisplays
|
||||
import com.willfp.eco.internal.spigot.integrations.mcmmo.McmmoIntegrationImpl
|
||||
import com.willfp.eco.internal.spigot.integrations.multiverseinventories.MultiverseInventoriesIntegration
|
||||
@@ -91,9 +96,13 @@ abstract class EcoSpigotPlugin : EcoPlugin(
|
||||
"&a"
|
||||
) {
|
||||
init {
|
||||
Items.registerArgParser(EnchantmentArgParser())
|
||||
Items.registerArgParser(TextureArgParser())
|
||||
Items.registerArgParser(CustomModelDataArgParser())
|
||||
Items.registerArgParser(ArgParserEnchantment())
|
||||
Items.registerArgParser(ArgParserColor())
|
||||
Items.registerArgParser(ArgParserTexture())
|
||||
Items.registerArgParser(ArgParserCustomModelData())
|
||||
Items.registerArgParser(ArgParserFlag())
|
||||
Items.registerArgParser(ArgParserUnbreakable())
|
||||
Items.registerArgParser(ArgParserName())
|
||||
|
||||
val skullProxy = getProxy(SkullProxy::class.java)
|
||||
SkullUtils.initialize(
|
||||
@@ -210,6 +219,7 @@ abstract class EcoSpigotPlugin : EcoPlugin(
|
||||
// Hologram
|
||||
IntegrationLoader("HolographicDisplays") { HologramManager.register(HologramHolographicDisplays(this)) },
|
||||
IntegrationLoader("CMI") { HologramManager.register(HologramCMI()) },
|
||||
IntegrationLoader("DecentHolograms") { HologramManager.register(HologramDecentHolograms()) },
|
||||
//IntegrationLoader("GHolo") { HologramManager.register(HologramGHolo()) },
|
||||
|
||||
// AFK
|
||||
|
||||
@@ -7,8 +7,6 @@ import com.willfp.eco.core.AbstractPacketAdapter
|
||||
import com.willfp.eco.core.EcoPlugin
|
||||
import com.willfp.eco.core.Prerequisite
|
||||
import com.willfp.eco.core.display.Display
|
||||
import com.willfp.eco.internal.spigot.display.frame.DisplayFrame
|
||||
import com.willfp.eco.internal.spigot.display.frame.lastDisplayFrame
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.inventory.ItemStack
|
||||
|
||||
@@ -27,7 +25,5 @@ class PacketHeldWindowItems(plugin: EcoPlugin) : AbstractPacketAdapter(plugin, P
|
||||
item!!, player
|
||||
)
|
||||
}
|
||||
|
||||
player.lastDisplayFrame = DisplayFrame.EMPTY
|
||||
}
|
||||
}
|
||||
@@ -57,6 +57,11 @@ class AntigriefBentoBox : AntigriefWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
override fun canPickupItem(player: Player, location: Location): Boolean {
|
||||
val island = BentoBox.getInstance().islandsManager.getIslandAt(location).orElse(null) ?: return true
|
||||
return island.isAllowed(User.getInstance(player), Flags.ITEM_PICKUP)
|
||||
}
|
||||
|
||||
override fun getPluginName(): String {
|
||||
return "BentoBox"
|
||||
}
|
||||
|
||||
@@ -55,6 +55,10 @@ class AntigriefCombatLogXV10 : AntigriefWrapper {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun canPickupItem(player: Player, location: Location): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getPluginName(): String {
|
||||
return "CombatLogX"
|
||||
}
|
||||
|
||||
@@ -58,6 +58,10 @@ class AntigriefCombatLogXV11 : AntigriefWrapper {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun canPickupItem(player: Player, location: Location): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getPluginName(): String {
|
||||
return "CombatLogX"
|
||||
}
|
||||
|
||||
@@ -48,6 +48,10 @@ class AntigriefCrashClaim : AntigriefWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
override fun canPickupItem(player: Player, location: Location): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getPluginName(): String {
|
||||
return "CrashClaim"
|
||||
}
|
||||
|
||||
@@ -31,4 +31,8 @@ class AntigriefDeluxeCombat: AntigriefWrapper {
|
||||
else -> true
|
||||
}
|
||||
}
|
||||
|
||||
override fun canPickupItem(player: Player, location: Location): Boolean {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -65,6 +65,10 @@ class AntigriefFactionsUUID : AntigriefWrapper {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun canPickupItem(player: Player, location: Location): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getPluginName(): String {
|
||||
return "FactionsUUID"
|
||||
}
|
||||
|
||||
@@ -51,6 +51,10 @@ class AntigriefGriefPrevention : AntigriefWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
override fun canPickupItem(player: Player, location: Location): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getPluginName(): String {
|
||||
return "GriefPrevention"
|
||||
}
|
||||
|
||||
@@ -48,6 +48,11 @@ class AntigriefIridiumSkyblock : AntigriefWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
override fun canPickupItem(player: Player, location: Location): Boolean {
|
||||
val api = IridiumSkyblockAPI.getInstance() ?: return true
|
||||
return api.getIslandPermission(api.getIslandViaLocation(location).orElse(null) ?: return true, api.getUser(player), PermissionType.PICKUP_ITEMS)
|
||||
}
|
||||
|
||||
override fun getPluginName(): String {
|
||||
return "IridiumSkyblock"
|
||||
}
|
||||
|
||||
@@ -65,6 +65,10 @@ class AntigriefKingdoms : AntigriefWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
override fun canPickupItem(player: Player, location: Location): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getPluginName(): String {
|
||||
return "Kingdoms"
|
||||
}
|
||||
|
||||
@@ -52,6 +52,11 @@ class AntigriefLands(private val plugin: EcoPlugin) : AntigriefWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
override fun canPickupItem(player: Player, location: Location): Boolean {
|
||||
val area = landsIntegration.getAreaByLoc(location) ?: return true
|
||||
return area.hasFlag(player, Flags.ITEM_PICKUP, false)
|
||||
}
|
||||
|
||||
override fun getPluginName(): String {
|
||||
return "Lands"
|
||||
}
|
||||
|
||||
@@ -4,13 +4,13 @@ import com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI
|
||||
import com.bgsoftware.superiorskyblock.api.enums.HitActionResult
|
||||
import com.bgsoftware.superiorskyblock.api.island.Island
|
||||
import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege
|
||||
import com.bgsoftware.superiorskyblock.api.key.Key
|
||||
import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer
|
||||
import com.willfp.eco.core.integrations.antigrief.AntigriefWrapper
|
||||
import org.bukkit.Location
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.block.Block
|
||||
import org.bukkit.entity.*
|
||||
import org.bukkit.entity.LivingEntity
|
||||
import org.bukkit.entity.Monster
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
class AntigriefSuperiorSkyblock2 : AntigriefWrapper {
|
||||
override fun getPluginName(): String {
|
||||
@@ -18,34 +18,19 @@ class AntigriefSuperiorSkyblock2 : AntigriefWrapper {
|
||||
}
|
||||
|
||||
override fun canBreakBlock(player: Player, block: Block): Boolean {
|
||||
val island: Island? =
|
||||
SuperiorSkyblockAPI.getIslandAt(block.location)
|
||||
|
||||
val superiorPlayer: SuperiorPlayer =
|
||||
SuperiorSkyblockAPI.getPlayer(player)
|
||||
val island = SuperiorSkyblockAPI.getIslandAt(block.location)
|
||||
val superiorPlayer = SuperiorSkyblockAPI.getPlayer(player)
|
||||
|
||||
if (island == null) {
|
||||
if (!superiorPlayer.hasBypassModeEnabled() && SuperiorSkyblockAPI.getSuperiorSkyblock().grid
|
||||
.isIslandsWorld(player.world)
|
||||
.isIslandsWorld(superiorPlayer.world)
|
||||
) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
val blockType = block.type
|
||||
|
||||
val islandPermission: IslandPrivilege =
|
||||
if (blockType == Material.SPAWNER) IslandPrivilege.getByName("SPAWNER_BREAK") else IslandPrivilege.getByName("BREAK")
|
||||
|
||||
if (!island.hasPermission(superiorPlayer, islandPermission)) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (SuperiorSkyblockAPI.getSuperiorSkyblock().settings.valuableBlocks
|
||||
.contains(Key.of(block)) &&
|
||||
!island.hasPermission(superiorPlayer, IslandPrivilege.getByName("VALUABLE_BREAK"))
|
||||
) {
|
||||
if (!island.hasPermission(superiorPlayer, IslandPrivilege.getByName("BREAK"))) {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -64,14 +49,12 @@ class AntigriefSuperiorSkyblock2 : AntigriefWrapper {
|
||||
}
|
||||
|
||||
override fun canPlaceBlock(player: Player, block: Block): Boolean {
|
||||
val island: Island? =
|
||||
SuperiorSkyblockAPI.getIslandAt(block.location)
|
||||
|
||||
val superiorPlayer: SuperiorPlayer =
|
||||
SuperiorSkyblockAPI.getPlayer(player)
|
||||
val island = SuperiorSkyblockAPI.getIslandAt(block.location)
|
||||
val superiorPlayer: SuperiorPlayer = SuperiorSkyblockAPI.getPlayer(player)
|
||||
|
||||
if (island == null) {
|
||||
if (!superiorPlayer.hasBypassModeEnabled() && SuperiorSkyblockAPI.getSuperiorSkyblock().grid.isIslandsWorld(superiorPlayer.world)
|
||||
if (!superiorPlayer.hasBypassModeEnabled() && SuperiorSkyblockAPI.getSuperiorSkyblock().grid
|
||||
.isIslandsWorld(superiorPlayer.world)
|
||||
) {
|
||||
return false
|
||||
}
|
||||
@@ -90,19 +73,28 @@ class AntigriefSuperiorSkyblock2 : AntigriefWrapper {
|
||||
}
|
||||
|
||||
override fun canInjure(player: Player, victim: LivingEntity): Boolean {
|
||||
if (SuperiorSkyblockAPI.getPlayer(player).hasBypassModeEnabled()) {
|
||||
return true
|
||||
|
||||
val island: Island? = SuperiorSkyblockAPI.getSuperiorSkyblock().grid.getIslandAt(victim.location)
|
||||
|
||||
if (victim is Player) return SuperiorSkyblockAPI.getPlayer(player).canHit(SuperiorSkyblockAPI.getPlayer(victim))
|
||||
.equals(HitActionResult.SUCCESS)
|
||||
|
||||
val islandPermission = when (victim) {
|
||||
is Monster -> IslandPrivilege.getByName("MONSTER_DAMAGE")
|
||||
else -> IslandPrivilege.getByName("ANIMAL_DAMAGE")
|
||||
}
|
||||
return when (victim) {
|
||||
is Player -> SuperiorSkyblockAPI.getPlayer(player).canHit(SuperiorSkyblockAPI.getPlayer(victim)).equals(HitActionResult.SUCCESS)
|
||||
else -> {
|
||||
val island: Island? = SuperiorSkyblockAPI.getSuperiorSkyblock().grid.getIslandAt(victim.location)
|
||||
val islandPermission = if (victim is Monster) IslandPrivilege.getByName("MONSTER_DAMAGE") else IslandPrivilege.getByName("ANIMAL_DAMAGE")
|
||||
if (island != null ) {
|
||||
return island.hasPermission(player, islandPermission)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
if (island != null && !island.hasPermission(player, islandPermission)) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun canPickupItem(player: Player, location: Location): Boolean {
|
||||
val superiorPlayer: SuperiorPlayer =
|
||||
SuperiorSkyblockAPI.getPlayer(player)
|
||||
val island = SuperiorSkyblockAPI.getSuperiorSkyblock().grid.getIslandAt(location) ?: return true
|
||||
return island.hasPermission(superiorPlayer, IslandPrivilege.getByName("PICKUP_DROPS"))
|
||||
}
|
||||
}
|
||||
@@ -69,6 +69,10 @@ class AntigriefTowny : AntigriefWrapper {
|
||||
return townBlock.permissions.pvp
|
||||
}
|
||||
|
||||
override fun canPickupItem(player: Player, location: Location): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getPluginName(): String {
|
||||
return "Towny"
|
||||
}
|
||||
|
||||
@@ -98,6 +98,20 @@ class AntigriefWorldGuard : AntigriefWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
override fun canPickupItem(player: Player, location: Location): Boolean {
|
||||
val localPlayer: LocalPlayer = WorldGuardPlugin.inst().wrapPlayer(player)
|
||||
val container: RegionContainer = WorldGuard.getInstance().platform.regionContainer
|
||||
val query: RegionQuery = container.createQuery()
|
||||
val world = location.world
|
||||
Validate.notNull(world, "World cannot be null!")
|
||||
return if (!query.testBuild(BukkitAdapter.adapt(location), localPlayer, Flags.ITEM_PICKUP)) {
|
||||
WorldGuard.getInstance().platform.sessionManager.hasBypass(
|
||||
localPlayer,
|
||||
BukkitAdapter.adapt(world)
|
||||
)
|
||||
} else true
|
||||
}
|
||||
|
||||
override fun getPluginName(): String {
|
||||
return "WorldGuard"
|
||||
}
|
||||
|
||||
@@ -1,21 +1,9 @@
|
||||
package com.willfp.eco.internal.spigot.integrations.bstats
|
||||
|
||||
import com.willfp.eco.core.EcoPlugin
|
||||
import org.bstats.bukkit.Metrics
|
||||
import org.bukkit.configuration.file.YamlConfiguration
|
||||
import java.io.File
|
||||
|
||||
object MetricHandler {
|
||||
fun createMetrics(plugin: EcoPlugin, ecoPlugin: EcoPlugin) {
|
||||
val bStatsFolder = File(plugin.dataFolder.parentFile, "bStats")
|
||||
val configFile = File(bStatsFolder, "config.yml")
|
||||
val config = YamlConfiguration.loadConfiguration(configFile)
|
||||
|
||||
if (config.isSet("serverUuid")) {
|
||||
config.set("enabled", ecoPlugin.configYml.getBool("enable-bstats"))
|
||||
config.save(configFile)
|
||||
}
|
||||
|
||||
Metrics(plugin, plugin.bStatsId)
|
||||
fun createMetrics(plugin: EcoPlugin) {
|
||||
Metrics(plugin)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,339 @@
|
||||
package com.willfp.eco.internal.spigot.integrations.bstats
|
||||
|
||||
import com.willfp.eco.core.EcoPlugin
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.configuration.file.YamlConfiguration
|
||||
import java.io.BufferedReader
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.DataOutputStream
|
||||
import java.io.File
|
||||
import java.io.InputStreamReader
|
||||
import java.net.URL
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.util.Arrays
|
||||
import java.util.Objects
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.function.BiConsumer
|
||||
import java.util.function.Consumer
|
||||
import java.util.function.Supplier
|
||||
import java.util.logging.Level
|
||||
import java.util.stream.Collectors
|
||||
import java.util.zip.GZIPOutputStream
|
||||
import javax.net.ssl.HttpsURLConnection
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
class Metrics(private val plugin: EcoPlugin) {
|
||||
private val metricsBase: MetricsBase
|
||||
|
||||
private fun appendPlatformData(builder: JsonObjectBuilder) {
|
||||
builder.appendField("playerAmount", playerAmount)
|
||||
builder.appendField("onlineMode", if (Bukkit.getOnlineMode()) 1 else 0)
|
||||
builder.appendField("bukkitVersion", Bukkit.getVersion())
|
||||
builder.appendField("bukkitName", Bukkit.getName())
|
||||
builder.appendField("javaVersion", System.getProperty("java.version"))
|
||||
builder.appendField("osName", System.getProperty("os.name"))
|
||||
builder.appendField("osArch", System.getProperty("os.arch"))
|
||||
builder.appendField("osVersion", System.getProperty("os.version"))
|
||||
builder.appendField("coreCount", Runtime.getRuntime().availableProcessors())
|
||||
}
|
||||
|
||||
private fun appendServiceData(builder: JsonObjectBuilder) {
|
||||
builder.appendField("pluginVersion", plugin.description.version)
|
||||
}
|
||||
|
||||
private val playerAmount: Int
|
||||
get() = Bukkit.getOnlinePlayers().size
|
||||
|
||||
class MetricsBase(
|
||||
private val platform: String,
|
||||
private val serverUuid: String,
|
||||
private val serviceId: Int,
|
||||
private val appendPlatformDataConsumer: Consumer<JsonObjectBuilder>,
|
||||
private val appendServiceDataConsumer: Consumer<JsonObjectBuilder>,
|
||||
private val submitTaskConsumer: Consumer<Runnable>?,
|
||||
private val checkServiceEnabledSupplier: Supplier<Boolean>,
|
||||
private val errorLogger: BiConsumer<String?, Throwable?>,
|
||||
private val infoLogger: Consumer<String>,
|
||||
private val logErrors: Boolean,
|
||||
private val logSentData: Boolean,
|
||||
private val logResponseStatusText: Boolean
|
||||
) {
|
||||
private val customCharts: MutableSet<CustomChart> = HashSet()
|
||||
|
||||
private fun startSubmitting() {
|
||||
val submitTask = Runnable {
|
||||
if (!checkServiceEnabledSupplier.get()) {
|
||||
// Submitting data or service is disabled
|
||||
scheduler.shutdown()
|
||||
return@Runnable
|
||||
}
|
||||
if (submitTaskConsumer != null) {
|
||||
submitTaskConsumer.accept { submitData() }
|
||||
} else {
|
||||
submitData()
|
||||
}
|
||||
}
|
||||
// Many servers tend to restart at a fixed time at xx:00 which causes an uneven distribution
|
||||
// of requests on the
|
||||
// bStats backend. To circumvent this problem, we introduce some randomness into the initial
|
||||
// and second delay.
|
||||
// WARNING: You must not modify and part of this Metrics class, including the submit delay or
|
||||
// frequency!
|
||||
// WARNING: Modifying this code will get your plugin banned on bStats. Just don't do it!
|
||||
val initialDelay = (1000 * 60 * (3 + Math.random() * 3)).toLong()
|
||||
val secondDelay = (1000 * 60 * (Math.random() * 30)).toLong()
|
||||
runIgnoring {
|
||||
scheduler.schedule(submitTask, initialDelay, TimeUnit.MILLISECONDS)
|
||||
scheduler.scheduleAtFixedRate(
|
||||
submitTask, initialDelay + secondDelay, (1000 * 60 * 30).toLong(), TimeUnit.MILLISECONDS
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun submitData() {
|
||||
val baseJsonBuilder = JsonObjectBuilder()
|
||||
appendPlatformDataConsumer.accept(baseJsonBuilder)
|
||||
val serviceJsonBuilder = JsonObjectBuilder()
|
||||
appendServiceDataConsumer.accept(serviceJsonBuilder)
|
||||
val chartData = customCharts.stream()
|
||||
.map { customChart: CustomChart ->
|
||||
customChart.getRequestJsonObject(
|
||||
errorLogger, logErrors
|
||||
)
|
||||
}
|
||||
.filter { obj: JsonObjectBuilder.JsonObject? -> Objects.nonNull(obj) }
|
||||
.toArray()
|
||||
|
||||
serviceJsonBuilder.appendField("id", serviceId)
|
||||
serviceJsonBuilder.appendField(
|
||||
"customCharts",
|
||||
chartData as Array<JsonObjectBuilder.JsonObject>
|
||||
)
|
||||
baseJsonBuilder.appendField("service", serviceJsonBuilder.build())
|
||||
baseJsonBuilder.appendField("serverUUID", serverUuid)
|
||||
baseJsonBuilder.appendField("metricsVersion", METRICS_VERSION)
|
||||
val data = baseJsonBuilder.build()
|
||||
runIgnoring {
|
||||
scheduler.execute {
|
||||
runIgnoring { sendData(data) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
private fun sendData(data: JsonObjectBuilder.JsonObject) {
|
||||
if (logSentData) {
|
||||
infoLogger.accept("Sent bStats metrics data: $data")
|
||||
}
|
||||
val url = String.format(REPORT_URL, platform)
|
||||
val connection = URL(url).openConnection() as HttpsURLConnection
|
||||
// Compress the data to save bandwidth
|
||||
val compressedData = compress(data.toString())
|
||||
connection.requestMethod = "POST"
|
||||
connection.addRequestProperty("Accept", "application/json")
|
||||
connection.addRequestProperty("Connection", "close")
|
||||
connection.addRequestProperty("Content-Encoding", "gzip")
|
||||
connection.addRequestProperty("Content-Length", compressedData!!.size.toString())
|
||||
connection.setRequestProperty("Content-Type", "application/json")
|
||||
connection.setRequestProperty("User-Agent", "Metrics-Service/1")
|
||||
connection.doOutput = true
|
||||
DataOutputStream(connection.outputStream).use { outputStream -> outputStream.write(compressedData) }
|
||||
val builder = StringBuilder()
|
||||
BufferedReader(InputStreamReader(connection.inputStream)).use { bufferedReader ->
|
||||
var line: String?
|
||||
while (bufferedReader.readLine().also { line = it } != null) {
|
||||
builder.append(line)
|
||||
}
|
||||
}
|
||||
if (logResponseStatusText) {
|
||||
infoLogger.accept("Sent data to bStats and received response: $builder")
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val METRICS_VERSION = "2.2.1"
|
||||
private val scheduler =
|
||||
Executors.newScheduledThreadPool(1) { task: Runnable? -> Thread(task, "bStats-Metrics") }
|
||||
private const val REPORT_URL = "https://bStats.org/api/v2/data/%s"
|
||||
|
||||
private fun compress(str: String?): ByteArray? {
|
||||
if (str == null) {
|
||||
return null
|
||||
}
|
||||
val outputStream = ByteArrayOutputStream()
|
||||
GZIPOutputStream(outputStream).use { gzip -> gzip.write(str.toByteArray(StandardCharsets.UTF_8)) }
|
||||
return outputStream.toByteArray()
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
startSubmitting()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
abstract class CustomChart protected constructor(chartId: String?) {
|
||||
private val chartId: String
|
||||
fun getRequestJsonObject(
|
||||
errorLogger: BiConsumer<String?, Throwable?>, logErrors: Boolean
|
||||
): JsonObjectBuilder.JsonObject? {
|
||||
val builder = JsonObjectBuilder()
|
||||
builder.appendField("chartId", chartId)
|
||||
try {
|
||||
val data = chartData
|
||||
?: // If the data is null we don't send the chart.
|
||||
return null
|
||||
builder.appendField("data", data)
|
||||
} catch (t: Throwable) {
|
||||
if (logErrors) {
|
||||
errorLogger.accept("Failed to get data for custom chart with id $chartId", t)
|
||||
}
|
||||
return null
|
||||
}
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
protected abstract val chartData: JsonObjectBuilder.JsonObject?
|
||||
|
||||
init {
|
||||
requireNotNull(chartId) { "chartId must not be null" }
|
||||
this.chartId = chartId
|
||||
}
|
||||
}
|
||||
|
||||
class JsonObjectBuilder {
|
||||
private var builder: StringBuilder? = StringBuilder()
|
||||
private var hasAtLeastOneField = false
|
||||
|
||||
fun appendField(key: String?, value: String?): JsonObjectBuilder {
|
||||
requireNotNull(value) { "JSON value must not be null" }
|
||||
appendFieldUnescaped(key, "\"" + escape(value) + "\"")
|
||||
return this
|
||||
}
|
||||
|
||||
fun appendField(key: String?, value: Int): JsonObjectBuilder {
|
||||
appendFieldUnescaped(key, value.toString())
|
||||
return this
|
||||
}
|
||||
|
||||
fun appendField(key: String?, `object`: JsonObject?): JsonObjectBuilder {
|
||||
requireNotNull(`object`) { "JSON object must not be null" }
|
||||
appendFieldUnescaped(key, `object`.toString())
|
||||
return this
|
||||
}
|
||||
|
||||
fun appendField(key: String?, values: Array<JsonObject>?): JsonObjectBuilder {
|
||||
requireNotNull(values) { "JSON values must not be null" }
|
||||
val escapedValues = Arrays.stream(values).map { obj: JsonObject -> obj.toString() }
|
||||
.collect(Collectors.joining(","))
|
||||
appendFieldUnescaped(key, "[$escapedValues]")
|
||||
return this
|
||||
}
|
||||
|
||||
private fun appendFieldUnescaped(key: String?, escapedValue: String) {
|
||||
checkNotNull(builder) { "JSON has already been built" }
|
||||
requireNotNull(key) { "JSON key must not be null" }
|
||||
if (hasAtLeastOneField) {
|
||||
builder!!.append(",")
|
||||
}
|
||||
builder!!.append("\"").append(escape(key)).append("\":").append(escapedValue)
|
||||
hasAtLeastOneField = true
|
||||
}
|
||||
|
||||
fun build(): JsonObject {
|
||||
checkNotNull(builder) { "JSON has already been built" }
|
||||
val obj = JsonObject(
|
||||
builder!!.append("}").toString()
|
||||
)
|
||||
builder = null
|
||||
return obj
|
||||
}
|
||||
|
||||
class JsonObject(private val value: String) {
|
||||
override fun toString(): String {
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private fun escape(value: String): String {
|
||||
val builder = StringBuilder()
|
||||
for (element in value) {
|
||||
if (element == '"') {
|
||||
builder.append("\\\"")
|
||||
} else if (element == '\\') {
|
||||
builder.append("\\\\")
|
||||
} else if (element <= '\u000F') {
|
||||
builder.append("\\u000").append(Integer.toHexString(element.code))
|
||||
} else if (element <= '\u001F') {
|
||||
builder.append("\\u00").append(Integer.toHexString(element.code))
|
||||
} else {
|
||||
builder.append(element)
|
||||
}
|
||||
}
|
||||
return builder.toString()
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
builder!!.append("{")
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
// Get the config file
|
||||
val bStatsFolder = File(plugin.dataFolder.parentFile, "bStats")
|
||||
val configFile = File(bStatsFolder, "config.yml")
|
||||
val config = YamlConfiguration.loadConfiguration(configFile)
|
||||
if (!config.isSet("serverUuid")) {
|
||||
config.addDefault("enabled", true)
|
||||
config.addDefault("serverUuid", UUID.randomUUID().toString())
|
||||
config.addDefault("logFailedRequests", false)
|
||||
config.addDefault("logSentData", false)
|
||||
config.addDefault("logResponseStatusText", false)
|
||||
// Inform the server owners about bStats
|
||||
config
|
||||
.options()
|
||||
.header(
|
||||
"""
|
||||
bStats (https://bStats.org) collects some basic information for plugin authors, like how
|
||||
many people use their plugin and their total player count. It's recommended to keep bStats
|
||||
enabled, but if you're not comfortable with this, you can turn this setting off. There is no
|
||||
performance penalty associated with having metrics enabled, and data sent to bStats is fully
|
||||
anonymous.
|
||||
""".trimIndent()
|
||||
)
|
||||
.copyDefaults(true)
|
||||
config.save(configFile)
|
||||
}
|
||||
// Load the data
|
||||
val serverUUID = config.getString("serverUuid")!!
|
||||
val logErrors = config.getBoolean("logFailedRequests", false)
|
||||
val logSentData = config.getBoolean("logSentData", false)
|
||||
val logResponseStatusText = config.getBoolean("logResponseStatusText", false)
|
||||
metricsBase = MetricsBase(
|
||||
"bukkit",
|
||||
serverUUID,
|
||||
plugin.bStatsId,
|
||||
{ builder: JsonObjectBuilder -> appendPlatformData(builder) },
|
||||
{ builder: JsonObjectBuilder -> appendServiceData(builder) },
|
||||
{ submitDataTask: Runnable? -> Bukkit.getScheduler().runTask(plugin, submitDataTask!!) },
|
||||
{ plugin.isEnabled },
|
||||
{ message: String?, error: Throwable? -> this.plugin.logger.log(Level.WARNING, message, error) },
|
||||
{ message: String? -> this.plugin.logger.log(Level.INFO, message) },
|
||||
logErrors,
|
||||
logSentData,
|
||||
logResponseStatusText
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun runIgnoring(func: () -> Unit) {
|
||||
try {
|
||||
func()
|
||||
} catch (e: Exception) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.willfp.eco.internal.spigot.integrations.hologram
|
||||
|
||||
import com.willfp.eco.core.integrations.hologram.Hologram
|
||||
import com.willfp.eco.core.integrations.hologram.HologramWrapper
|
||||
import eu.decentsoftware.holograms.api.DHAPI
|
||||
import org.bukkit.Location
|
||||
import java.util.UUID
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
class HologramDecentHolograms : HologramWrapper {
|
||||
override fun createHologram(location: Location, contents: MutableList<String>): Hologram {
|
||||
val id = UUID.randomUUID().toString()
|
||||
|
||||
DHAPI.createHologram(id, location, contents)
|
||||
|
||||
return HologramImplDecentHolograms(id)
|
||||
}
|
||||
|
||||
override fun getPluginName(): String {
|
||||
return "DecentHolograms"
|
||||
}
|
||||
|
||||
class HologramImplDecentHolograms(
|
||||
private val id: String,
|
||||
) : Hologram {
|
||||
override fun remove() {
|
||||
DHAPI.getHologram(id)?.destroy()
|
||||
}
|
||||
|
||||
override fun setContents(contents: MutableList<String>) {
|
||||
DHAPI.setHologramLines(DHAPI.getHologram(id), contents)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@ class ShopShopGuiPlus : ShopWrapper {
|
||||
|
||||
override fun loadItem(configurationSection: ConfigurationSection): ItemStack? {
|
||||
val id = configurationSection.getString("eco")
|
||||
return if (id == null) null else Items.lookup(id)?.item
|
||||
return if (id == null) null else Items.lookup(id).item
|
||||
}
|
||||
|
||||
override fun compare(itemStack1: ItemStack, itemStack2: ItemStack): Boolean {
|
||||
|
||||
@@ -25,10 +25,6 @@ villager-display-fix: false
|
||||
# Disable it if it changes drop mechanics too much for you.
|
||||
use-fast-collated-drops: true
|
||||
|
||||
# bStats is important and you should keep it enabled.
|
||||
# This option is only here because of compliance with data protection laws.
|
||||
enable-bstats: true
|
||||
|
||||
# Some plugins use their own item display systems (eg Triton)
|
||||
# And must be run after eco. Don't enable this unless you run a conflicting plugin
|
||||
# and have been told to enable it.
|
||||
|
||||
@@ -38,6 +38,7 @@ softdepend:
|
||||
- IridiumSkyblock
|
||||
- SuperiorSkyblock2
|
||||
- CrashClaim
|
||||
- DecentHolograms
|
||||
libraries:
|
||||
- 'org.reflections:reflections:0.9.12'
|
||||
- 'org.apache.maven:maven-artifact:3.0.3'
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
version = 6.14.1
|
||||
plugin-name = eco
|
||||
version = 6.16.0
|
||||
plugin-name = eco
|
||||
kotlin.code.style = official
|
||||
Reference in New Issue
Block a user