Compare commits

..

43 Commits

Author SHA1 Message Date
Auxilor
00ea3506ca config.yml changes 2021-12-08 20:32:55 +00:00
Auxilor
521659cfec bStats changes 2021-12-08 20:32:31 +00:00
Auxilor
bbe5f1eba4 Merge remote-tracking branch 'origin/develop' into develop
# Conflicts:
#	eco-core/core-plugin/build.gradle
2021-12-08 20:24:07 +00:00
Auxilor
eae5d29f8d Downgraded bStats 2021-12-08 20:16:59 +00:00
Auxilor
c878d6fd12 Implemented stipped-down bStats directly (recoded in kotlin) 2021-12-08 16:08:03 +00:00
Auxilor
2b97c0072f Downgraded bStats 2021-12-08 14:18:24 +00:00
Auxilor
63079df745 Removed explicit buffer size 2021-12-08 12:41:24 +00:00
Auxilor
079b41e877 Switched to old config behavior 2021-12-08 12:40:13 +00:00
Auxilor
1aaab459d8 Updated bStats to 2.2.1 2021-12-08 12:34:38 +00:00
Auxilor
db78c2eb4c Fixed javadoc + codestyle 2021-12-08 12:22:51 +00:00
Auxilor
02fd07b3c8 Fixed shadowed name 2021-12-08 12:17:22 +00:00
Auxilor
3de2e53031 Fixed default captive items bug 2021-12-08 11:27:33 +00:00
Auxilor
cb088bb70b Allowed specifiying default captive items 2021-12-08 11:23:23 +00:00
Auxilor
36fca7016f Fixed ArgParserEnchantment never returning null 2021-12-08 11:11:59 +00:00
Auxilor
7e1137da06 Cleaned up SS2 integration 2021-12-08 10:53:16 +00:00
Auxilor
0da104d614 Added color:#fffff support x 2021-12-08 10:51:25 +00:00
Auxilor
9095de7d19 Updated to 6.16.0 2021-12-08 10:50:36 +00:00
Auxilor
7a8abac1a2 Pull Request Fixes / Changes, config changes 2021-12-08 10:50:12 +00:00
0ft3n
1ddcb6e964 Merge branch 'master' into master 2021-12-07 14:11:40 +03:00
_OfTeN_
4d0858ad84 Added AntigriefManager#canPickupItem and created and implemented DropQueuePushEvent event 2021-12-07 14:08:04 +03:00
_OfTeN_
3d05695a36 Added Items#getItem 2021-12-07 13:30:36 +03:00
Auxilor
d676be15ce Grammar 2021-12-06 13:46:27 +00:00
Auxilor
16848caec1 Fixed grammar errors 2021-12-06 13:08:45 +00:00
Auxilor
ef26fe4629 Removed legacy arg parser method bodies 2021-12-06 13:06:22 +00:00
Auxilor
29fbd785d7 Added ArgParserName 2021-12-06 12:54:28 +00:00
Auxilor
8c73676ee0 Added ArgParserUnbreakable 2021-12-06 12:50:26 +00:00
Auxilor
ebf27d28d9 Updated to 6.15.2 2021-12-06 12:49:10 +00:00
Auxilor
317bc13f65 Moved arg parsers to internals and added ArgParserFlag 2021-12-06 12:49:00 +00:00
Auxilor
b8ec0ee6fc Updated to 6.15.1 2021-12-06 10:14:14 +00:00
Auxilor
307e57c902 Display frame changes with PacketHeldWindowItems 2021-12-06 10:13:29 +00:00
Auxilor
db0d55659f Empty transient config 2021-12-06 10:10:35 +00:00
Auxilor
548529feb3 Javadoc formatting 2021-12-06 10:09:52 +00:00
Auxilor
fb56baf452 Fixed class-cast error 2021-12-06 10:02:24 +00:00
Auxilor
5d18b424d7 Added ColorArgParser 2021-12-04 15:37:29 +00:00
Auxilor
7be9a1bd10 Fixed EcoYamlConfigWrapper cast issues 2021-12-03 20:59:07 +00:00
Auxilor
97c39b56dd Updated to 6.15.0 2021-12-03 20:23:25 +00:00
_OfTeN_
3a9f5bc139 Added support for DecentHolograms 2021-12-03 21:10:40 +03:00
Auxilor
1e5955f249 Codestyle fixes 2021-12-03 16:21:47 +00:00
Auxilor
bad076bbe9 Added kotlin.code.style = official 2021-12-03 16:18:53 +00:00
Auxilor
e219b2f33c Config additions 2021-12-03 16:13:37 +00:00
Auxilor
2f7603409e Generic variance 2021-12-03 15:58:41 +00:00
Auxilor
28cdb65176 Added Config#getSubsections 2021-12-03 15:49:00 +00:00
_OfTeN_
03ae9e89b3 Added color:#FFFFFF, color:FFFFFF or color:red,green,blue parser for leather armor color 2021-12-02 23:26:38 +03:00
59 changed files with 1142 additions and 296 deletions

View File

@@ -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

View File

@@ -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.
*

View File

@@ -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();

View File

@@ -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(""))));
}
}

View File

@@ -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;
}
}

View File

@@ -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));
}

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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()
}

View File

@@ -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 {

View File

@@ -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(

View File

@@ -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
}
}

View File

@@ -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()

View File

@@ -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)
}
}

View File

@@ -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
}
}

View File

@@ -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
}

View File

@@ -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 -> {}
}
}

View File

@@ -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)
}

View File

@@ -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
)
}
}
}

View File

@@ -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
}
}
}

View File

@@ -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
}
}
}

View File

@@ -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)
}
}
}

View File

@@ -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
}
}
}

View File

@@ -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)
}
}
}

View File

@@ -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
}
}
}

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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() {

View File

@@ -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() {

View File

@@ -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'

View File

@@ -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 {

View File

@@ -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

View File

@@ -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
}
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -48,6 +48,10 @@ class AntigriefCrashClaim : AntigriefWrapper {
}
}
override fun canPickupItem(player: Player, location: Location): Boolean {
return true
}
override fun getPluginName(): String {
return "CrashClaim"
}

View File

@@ -31,4 +31,8 @@ class AntigriefDeluxeCombat: AntigriefWrapper {
else -> true
}
}
override fun canPickupItem(player: Player, location: Location): Boolean {
return true
}
}

View File

@@ -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"
}

View File

@@ -51,6 +51,10 @@ class AntigriefGriefPrevention : AntigriefWrapper {
}
}
override fun canPickupItem(player: Player, location: Location): Boolean {
return true
}
override fun getPluginName(): String {
return "GriefPrevention"
}

View File

@@ -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"
}

View File

@@ -65,6 +65,10 @@ class AntigriefKingdoms : AntigriefWrapper {
}
}
override fun canPickupItem(player: Player, location: Location): Boolean {
return true
}
override fun getPluginName(): String {
return "Kingdoms"
}

View File

@@ -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"
}

View File

@@ -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"))
}
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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)
}
}

View File

@@ -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
}
}

View File

@@ -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)
}
}
}

View File

@@ -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 {

View File

@@ -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.

View File

@@ -38,6 +38,7 @@ softdepend:
- IridiumSkyblock
- SuperiorSkyblock2
- CrashClaim
- DecentHolograms
libraries:
- 'org.reflections:reflections:0.9.12'
- 'org.apache.maven:maven-artifact:3.0.3'

View File

@@ -1,2 +1,3 @@
version = 6.14.1
plugin-name = eco
version = 6.16.0
plugin-name = eco
kotlin.code.style = official