Compare commits

..

56 Commits
3.3.2 ... 4.0.0

Author SHA1 Message Date
Auxilor
bb42505d66 Hopeful fix 2021-02-17 16:07:08 +00:00
Auxilor
b4d59077e3 Fixed load order again 2021-02-17 15:55:39 +00:00
Auxilor
104d55c11b Changed load order again 2021-02-17 15:49:51 +00:00
Auxilor
b5af17cf08 Changed load order 2021-02-17 15:45:33 +00:00
Auxilor
78ae662ced Fixed RecipeParts 2021-02-17 15:20:39 +00:00
Auxilor
32e48db3ce Removed @Nullable because it's annoying 2021-02-17 15:02:52 +00:00
Auxilor
8a27e75c02 Fixed EcoPlugin 2021-02-17 14:55:34 +00:00
Auxilor
bf55e9b189 Constructor change 2021-02-17 14:54:28 +00:00
Auxilor
bfbaa3d033 Removed redundant check 2021-02-17 14:42:03 +00:00
Auxilor
64f87d5741 Cleaned up recipes 2021-02-17 13:54:02 +00:00
Auxilor
cb3441286c Removed redundant Registerable interface 2021-02-17 13:39:32 +00:00
Auxilor
5e97a0f894 Refactored ArrowDataListener 2021-02-17 13:35:32 +00:00
Auxilor
de2166dfdb Reworked tuples 2021-02-17 13:33:57 +00:00
Auxilor
abd361f4b5 Refactored config internals 2021-02-17 13:30:06 +00:00
Auxilor
422f8ead23 Removed RecipeListener from api 2021-02-17 13:27:28 +00:00
Auxilor
7c05dd7457 Reworked recipes 2021-02-17 13:20:34 +00:00
Auxilor
3ef7622c6f Updated to 4.0.0 2021-02-17 12:50:16 +00:00
Auxilor
8207d62b1f Reworked display system. 2021-02-17 12:50:01 +00:00
Auxilor
75a0b1dd0d Added @Internal annotations 2021-02-17 12:05:14 +00:00
Auxilor
d1307e35db Minor code issues 2021-02-16 19:48:20 +00:00
Auxilor
0a6b197a97 Cleaned various internals 2021-02-16 19:44:34 +00:00
Auxilor
8d6512886c Removed redundant PluginDependentFactory.java 2021-02-16 19:37:55 +00:00
Auxilor
5c0c0f3e2a Refactored Scheduler.java 2021-02-16 19:35:55 +00:00
Auxilor
e2c2fc776a Moved break blocks into block utils 2021-02-16 19:34:26 +00:00
Auxilor
576050b31e Updated to 3.8.0 2021-02-16 19:22:20 +00:00
Auxilor
f9a43bd336 Added trident util initializatoin 2021-02-16 19:17:59 +00:00
Auxilor
203f2f599a Added trident utils 2021-02-16 19:16:48 +00:00
Auxilor
baa5d37744 Added PlayerUtils 2021-02-16 19:11:02 +00:00
Auxilor
17f6af2a70 Added Skull texture setter 2021-02-16 18:07:47 +00:00
Auxilor
eae213f58e More refactoring, splitting api and internal 2021-02-14 16:31:16 +00:00
Auxilor
3a6a133560 Added caching to AbstractConfig 2021-02-14 15:32:10 +00:00
Auxilor
57cf144c57 Refactoring to remove internal components from API 2021-02-14 15:23:42 +00:00
Auxilor
5c29859d49 Updated to 3.7.0 2021-02-10 10:50:46 +00:00
Auxilor
02510127d1 Added getParts to EcoShapedRecipe 2021-02-10 10:50:31 +00:00
Auxilor
f6b5c8f7e0 Updated to eco 3.6.1 2021-02-09 09:30:29 +00:00
Auxilor
dbfef3094b Fixed villager trade being finalized 2021-02-09 09:30:08 +00:00
Auxilor
b5c3af752c Fixed bugs with new config system 2021-02-07 20:18:00 +00:00
Auxilor
d0366b39e2 Updated to 3.6.0 2021-02-07 20:03:46 +00:00
Auxilor
ed5390d2b5 Reworked config system (again) 2021-02-07 20:03:31 +00:00
Auxilor
e31857a15d Merge remote-tracking branch 'origin/master' into master
# Conflicts:
#	gradle.properties
2021-02-07 19:29:52 +00:00
Auxilor
32e119d187 Updated to 3.5.0 2021-02-07 19:29:32 +00:00
Auxilor
5690eccd14 Refactored config system and added update blacklist 2021-02-07 19:29:05 +00:00
Auxilor
2faf3732df Updated to 3.4.4 2021-02-07 15:00:52 +00:00
Auxilor
8670fb36e0 Changed ItemStats to StatTrackers 2021-02-07 15:00:36 +00:00
Auxilor
7c001c4809 Updated to 3.4.3 2021-02-03 09:14:20 +00:00
Auxilor
bce1dd9fee Fixed finalize issues 2021-02-03 09:13:45 +00:00
Auxilor
412c2e1e3c Updated to 3.4.2 2021-02-01 16:04:28 +00:00
Auxilor
dd7ffac974 Cleaned up DurabilityUtils and added edge case 2021-02-01 16:04:17 +00:00
Auxilor
7ad59e0166 Updated to 3.4.1 2021-02-01 08:54:30 +00:00
Auxilor
2f2bdbb9f5 Prevented dropping empty dropqueue or air 2021-02-01 08:54:17 +00:00
Auxilor
d23dc10bc5 Improved finalization (again) 2021-01-30 14:48:14 +00:00
Auxilor
46c2e3f90a Updated to 3.4.0 2021-01-30 14:31:51 +00:00
Auxilor
1776b668a4 Improved Display system 2021-01-30 14:31:31 +00:00
Auxilor
10dccd0f38 Updated to 3.3.3 2021-01-28 13:13:21 +00:00
Auxilor
f1918eb1ec Stopped removing final modifier on villager trades 2021-01-28 13:13:02 +00:00
Auxilor
436b33fde2 Fixed lands 2021-01-27 10:33:08 +00:00
84 changed files with 2016 additions and 1029 deletions

View File

@@ -0,0 +1,16 @@
package com.willfp.eco.proxy.v1_15_R1;
import com.willfp.eco.proxy.proxies.BlockBreakProxy;
import net.minecraft.server.v1_15_R1.BlockPosition;
import org.bukkit.block.Block;
import org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public final class BlockBreak implements BlockBreakProxy {
@Override
public void breakBlock(@NotNull final Player player,
@NotNull final Block block) {
((CraftPlayer) player).getHandle().playerInteractManager.breakBlock(new BlockPosition(block.getX(), block.getY(), block.getZ()));
}
}

View File

@@ -0,0 +1,15 @@
package com.willfp.eco.proxy.v1_15_R1;
import com.willfp.eco.proxy.proxies.CooldownProxy;
import net.minecraft.server.v1_15_R1.EntityHuman;
import org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public final class Cooldown implements CooldownProxy {
@Override
public double getAttackCooldown(@NotNull final Player player) {
EntityHuman entityHuman = ((CraftPlayer) player).getHandle();
return entityHuman.s(0);
}
}

View File

@@ -0,0 +1,41 @@
package com.willfp.eco.proxy.v1_15_R1;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.Property;
import com.willfp.eco.proxy.proxies.SkullProxy;
import org.bukkit.inventory.meta.SkullMeta;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.UUID;
public final class Skull implements SkullProxy {
/**
* Cached method to set the gameProfile.
*/
private Method setProfile = null;
@Override
public void setSkullTexture(@NotNull final SkullMeta meta,
@NotNull final String base64) {
try {
if (setProfile == null) {
setProfile = meta.getClass().getDeclaredMethod("setProfile", GameProfile.class);
setProfile.setAccessible(true);
}
UUID uuid = new UUID(
base64.substring(base64.length() - 20).hashCode(),
base64.substring(base64.length() - 10).hashCode()
);
GameProfile profile = new GameProfile(uuid, "talismans");
profile.getProperties().put("textures", new Property("textures", base64));
setProfile.invoke(meta, profile);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,17 @@
package com.willfp.eco.proxy.v1_15_R1;
import com.willfp.eco.proxy.proxies.TridentStackProxy;
import net.minecraft.server.v1_15_R1.EntityThrownTrident;
import org.bukkit.craftbukkit.v1_15_R1.entity.CraftTrident;
import org.bukkit.craftbukkit.v1_15_R1.inventory.CraftItemStack;
import org.bukkit.entity.Trident;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
public final class TridentStack implements TridentStackProxy {
@Override
public ItemStack getTridentStack(@NotNull final Trident trident) {
EntityThrownTrident t = ((CraftTrident) trident).getHandle();
return CraftItemStack.asBukkitCopy(t.trident);
}
}

View File

@@ -9,36 +9,29 @@ import org.bukkit.inventory.MerchantRecipe;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public final class VillagerTrade implements VillagerTradeProxy {
@Override
public void displayTrade(@NotNull final MerchantRecipe merchantRecipe) {
try {
// Enables removing final modifier
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
// Bukkit MerchantRecipe result
Field fResult = MerchantRecipe.class.getDeclaredField("result");
fResult.setAccessible(true);
ItemStack result = merchantRecipe.getResult();
Display.displayAndFinalize(result);
Display.display(result);
fResult.set(merchantRecipe, result);
// Get NMS MerchantRecipe from CraftMerchantRecipe
Field fHandle = CraftMerchantRecipe.class.getDeclaredField("handle");
fHandle.setAccessible(true);
net.minecraft.server.v1_15_R1.MerchantRecipe handle = (net.minecraft.server.v1_15_R1.MerchantRecipe) fHandle.get(merchantRecipe); // NMS Recipe
modifiersField.setInt(fHandle, fHandle.getModifiers() & ~Modifier.FINAL); // Remove final
Field fSelling = net.minecraft.server.v1_15_R1.MerchantRecipe.class.getDeclaredField("sellingItem");
fSelling.setAccessible(true);
modifiersField.setInt(fSelling, fSelling.getModifiers() & ~Modifier.FINAL);
ItemStack selling = CraftItemStack.asBukkitCopy(handle.sellingItem);
Display.displayAndFinalize(selling);
Display.display(selling);
fSelling.set(handle, CraftItemStack.asNMSCopy(selling));
} catch (IllegalAccessException | NoSuchFieldException e) {
e.printStackTrace();

View File

@@ -0,0 +1,16 @@
package com.willfp.eco.proxy.v1_16_R1;
import com.willfp.eco.proxy.proxies.BlockBreakProxy;
import net.minecraft.server.v1_16_R1.BlockPosition;
import org.bukkit.block.Block;
import org.bukkit.craftbukkit.v1_16_R1.entity.CraftPlayer;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public final class BlockBreak implements BlockBreakProxy {
@Override
public void breakBlock(@NotNull final Player player,
@NotNull final Block block) {
((CraftPlayer) player).getHandle().playerInteractManager.breakBlock(new BlockPosition(block.getX(), block.getY(), block.getZ()));
}
}

View File

@@ -0,0 +1,41 @@
package com.willfp.eco.proxy.v1_16_R1;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.Property;
import com.willfp.eco.proxy.proxies.SkullProxy;
import org.bukkit.inventory.meta.SkullMeta;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.UUID;
public final class Skull implements SkullProxy {
/**
* Cached method to set the gameProfile.
*/
private Method setProfile = null;
@Override
public void setSkullTexture(@NotNull final SkullMeta meta,
@NotNull final String base64) {
try {
if (setProfile == null) {
setProfile = meta.getClass().getDeclaredMethod("setProfile", GameProfile.class);
setProfile.setAccessible(true);
}
UUID uuid = new UUID(
base64.substring(base64.length() - 20).hashCode(),
base64.substring(base64.length() - 10).hashCode()
);
GameProfile profile = new GameProfile(uuid, "talismans");
profile.getProperties().put("textures", new Property("textures", base64));
setProfile.invoke(meta, profile);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,17 @@
package com.willfp.eco.proxy.v1_16_R1;
import com.willfp.eco.proxy.proxies.TridentStackProxy;
import net.minecraft.server.v1_16_R1.EntityThrownTrident;
import org.bukkit.craftbukkit.v1_16_R1.entity.CraftTrident;
import org.bukkit.craftbukkit.v1_16_R1.inventory.CraftItemStack;
import org.bukkit.entity.Trident;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
public final class TridentStack implements TridentStackProxy {
@Override
public ItemStack getTridentStack(@NotNull final Trident trident) {
EntityThrownTrident t = ((CraftTrident) trident).getHandle();
return CraftItemStack.asBukkitCopy(t.trident);
}
}

View File

@@ -9,35 +9,28 @@ import org.bukkit.inventory.MerchantRecipe;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public final class VillagerTrade implements VillagerTradeProxy {
@Override
public void displayTrade(@NotNull final MerchantRecipe merchantRecipe) {
try {
// Enables removing final modifier
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
// Bukkit MerchantRecipe result
Field fResult = MerchantRecipe.class.getDeclaredField("result");
fResult.setAccessible(true);
ItemStack result = merchantRecipe.getResult();
Display.displayAndFinalize(result);
Display.display(result);
fResult.set(merchantRecipe, result);
// Get NMS MerchantRecipe from CraftMerchantRecipe
Field fHandle = CraftMerchantRecipe.class.getDeclaredField("handle");
fHandle.setAccessible(true);
net.minecraft.server.v1_16_R1.MerchantRecipe handle = (net.minecraft.server.v1_16_R1.MerchantRecipe) fHandle.get(merchantRecipe); // NMS Recipe
modifiersField.setInt(fHandle, fHandle.getModifiers() & ~Modifier.FINAL); // Remove final
Field fSelling = net.minecraft.server.v1_16_R1.MerchantRecipe.class.getDeclaredField("sellingItem");
fSelling.setAccessible(true);
modifiersField.setInt(fSelling, fSelling.getModifiers() & ~Modifier.FINAL);
ItemStack selling = CraftItemStack.asBukkitCopy(handle.sellingItem);
Display.displayAndFinalize(selling);
Display.display(selling);
fSelling.set(handle, CraftItemStack.asNMSCopy(selling));
} catch (IllegalAccessException | NoSuchFieldException e) {

View File

@@ -0,0 +1,16 @@
package com.willfp.eco.proxy.v1_16_R2;
import com.willfp.eco.proxy.proxies.BlockBreakProxy;
import net.minecraft.server.v1_16_R2.BlockPosition;
import org.bukkit.block.Block;
import org.bukkit.craftbukkit.v1_16_R2.entity.CraftPlayer;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public final class BlockBreak implements BlockBreakProxy {
@Override
public void breakBlock(@NotNull final Player player,
@NotNull final Block block) {
((CraftPlayer) player).getHandle().playerInteractManager.breakBlock(new BlockPosition(block.getX(), block.getY(), block.getZ()));
}
}

View File

@@ -0,0 +1,41 @@
package com.willfp.eco.proxy.v1_16_R2;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.Property;
import com.willfp.eco.proxy.proxies.SkullProxy;
import org.bukkit.inventory.meta.SkullMeta;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.UUID;
public final class Skull implements SkullProxy {
/**
* Cached method to set the gameProfile.
*/
private Method setProfile = null;
@Override
public void setSkullTexture(@NotNull final SkullMeta meta,
@NotNull final String base64) {
try {
if (setProfile == null) {
setProfile = meta.getClass().getDeclaredMethod("setProfile", GameProfile.class);
setProfile.setAccessible(true);
}
UUID uuid = new UUID(
base64.substring(base64.length() - 20).hashCode(),
base64.substring(base64.length() - 10).hashCode()
);
GameProfile profile = new GameProfile(uuid, "talismans");
profile.getProperties().put("textures", new Property("textures", base64));
setProfile.invoke(meta, profile);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,17 @@
package com.willfp.eco.proxy.v1_16_R2;
import com.willfp.eco.proxy.proxies.TridentStackProxy;
import net.minecraft.server.v1_16_R2.EntityThrownTrident;
import org.bukkit.craftbukkit.v1_16_R2.entity.CraftTrident;
import org.bukkit.craftbukkit.v1_16_R2.inventory.CraftItemStack;
import org.bukkit.entity.Trident;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
public final class TridentStack implements TridentStackProxy {
@Override
public ItemStack getTridentStack(@NotNull final Trident trident) {
EntityThrownTrident t = ((CraftTrident) trident).getHandle();
return CraftItemStack.asBukkitCopy(t.trident);
}
}

View File

@@ -9,35 +9,28 @@ import org.bukkit.inventory.MerchantRecipe;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public final class VillagerTrade implements VillagerTradeProxy {
@Override
public void displayTrade(@NotNull final MerchantRecipe merchantRecipe) {
try {
// Enables removing final modifier
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
// Bukkit MerchantRecipe result
Field fResult = MerchantRecipe.class.getDeclaredField("result");
fResult.setAccessible(true);
ItemStack result = merchantRecipe.getResult();
Display.displayAndFinalize(result);
Display.display(result);
fResult.set(merchantRecipe, result);
// Get NMS MerchantRecipe from CraftMerchantRecipe
Field fHandle = CraftMerchantRecipe.class.getDeclaredField("handle");
fHandle.setAccessible(true);
net.minecraft.server.v1_16_R2.MerchantRecipe handle = (net.minecraft.server.v1_16_R2.MerchantRecipe) fHandle.get(merchantRecipe); // NMS Recipe
modifiersField.setInt(fHandle, fHandle.getModifiers() & ~Modifier.FINAL); // Remove final
Field fSelling = net.minecraft.server.v1_16_R2.MerchantRecipe.class.getDeclaredField("sellingItem");
fSelling.setAccessible(true);
modifiersField.setInt(fSelling, fSelling.getModifiers() & ~Modifier.FINAL);
ItemStack selling = CraftItemStack.asBukkitCopy(handle.sellingItem);
Display.displayAndFinalize(selling);
Display.display(selling);
fSelling.set(handle, CraftItemStack.asNMSCopy(selling));
} catch (IllegalAccessException | NoSuchFieldException e) {

View File

@@ -0,0 +1,16 @@
package com.willfp.eco.proxy.v1_16_R3;
import com.willfp.eco.proxy.proxies.BlockBreakProxy;
import net.minecraft.server.v1_16_R3.BlockPosition;
import org.bukkit.block.Block;
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public final class BlockBreak implements BlockBreakProxy {
@Override
public void breakBlock(@NotNull final Player player,
@NotNull final Block block) {
((CraftPlayer) player).getHandle().playerInteractManager.breakBlock(new BlockPosition(block.getX(), block.getY(), block.getZ()));
}
}

View File

@@ -0,0 +1,41 @@
package com.willfp.eco.proxy.v1_16_R3;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.Property;
import com.willfp.eco.proxy.proxies.SkullProxy;
import org.bukkit.inventory.meta.SkullMeta;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.UUID;
public final class Skull implements SkullProxy {
/**
* Cached method to set the gameProfile.
*/
private Method setProfile = null;
@Override
public void setSkullTexture(@NotNull final SkullMeta meta,
@NotNull final String base64) {
try {
if (setProfile == null) {
setProfile = meta.getClass().getDeclaredMethod("setProfile", GameProfile.class);
setProfile.setAccessible(true);
}
UUID uuid = new UUID(
base64.substring(base64.length() - 20).hashCode(),
base64.substring(base64.length() - 10).hashCode()
);
GameProfile profile = new GameProfile(uuid, "talismans");
profile.getProperties().put("textures", new Property("textures", base64));
setProfile.invoke(meta, profile);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,17 @@
package com.willfp.eco.proxy.v1_16_R3;
import com.willfp.eco.proxy.proxies.TridentStackProxy;
import net.minecraft.server.v1_16_R3.EntityThrownTrident;
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftTrident;
import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftItemStack;
import org.bukkit.entity.Trident;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
public final class TridentStack implements TridentStackProxy {
@Override
public ItemStack getTridentStack(@NotNull final Trident trident) {
EntityThrownTrident t = ((CraftTrident) trident).getHandle();
return CraftItemStack.asBukkitCopy(t.trident);
}
}

View File

@@ -9,35 +9,28 @@ import org.bukkit.inventory.MerchantRecipe;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public final class VillagerTrade implements VillagerTradeProxy {
@Override
public void displayTrade(@NotNull final MerchantRecipe merchantRecipe) {
try {
// Enables removing final modifier
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
// Bukkit MerchantRecipe result
Field fResult = MerchantRecipe.class.getDeclaredField("result");
fResult.setAccessible(true);
ItemStack result = merchantRecipe.getResult();
Display.displayAndFinalize(result);
Display.display(result);
fResult.set(merchantRecipe, result);
// Get NMS MerchantRecipe from CraftMerchantRecipe
Field fHandle = CraftMerchantRecipe.class.getDeclaredField("handle");
fHandle.setAccessible(true);
net.minecraft.server.v1_16_R3.MerchantRecipe handle = (net.minecraft.server.v1_16_R3.MerchantRecipe) fHandle.get(merchantRecipe); // NMS Recipe
modifiersField.setInt(fHandle, fHandle.getModifiers() & ~Modifier.FINAL); // Remove final
net.minecraft.server.v1_16_R3.MerchantRecipe handle = (net.minecraft.server.v1_16_R3.MerchantRecipe) fHandle.get(merchantRecipe); // NMS RecipeR
Field fSelling = net.minecraft.server.v1_16_R3.MerchantRecipe.class.getDeclaredField("sellingItem");
fSelling.setAccessible(true);
modifiersField.setInt(fSelling, fSelling.getModifiers() & ~Modifier.FINAL);
ItemStack selling = CraftItemStack.asBukkitCopy(handle.sellingItem);
Display.displayAndFinalize(selling);
Display.display(selling);
fSelling.set(handle, CraftItemStack.asNMSCopy(selling));
} catch (IllegalAccessException | NoSuchFieldException e) {

View File

@@ -1,11 +1,18 @@
package com.willfp.eco.spigot;
import com.willfp.eco.spigot.display.packets.PacketAutoRecipe;
import com.willfp.eco.spigot.display.packets.PacketChat;
import com.willfp.eco.spigot.display.packets.PacketOpenWindowMerchant;
import com.willfp.eco.spigot.display.packets.PacketSetCreativeSlot;
import com.willfp.eco.spigot.display.packets.PacketSetSlot;
import com.willfp.eco.spigot.display.packets.PacketWindowItems;
import com.willfp.eco.proxy.proxies.BlockBreakProxy;
import com.willfp.eco.proxy.proxies.CooldownProxy;
import com.willfp.eco.proxy.proxies.SkullProxy;
import com.willfp.eco.proxy.proxies.TridentStackProxy;
import com.willfp.eco.spigot.display.PacketAutoRecipe;
import com.willfp.eco.spigot.display.PacketChat;
import com.willfp.eco.spigot.display.PacketOpenWindowMerchant;
import com.willfp.eco.spigot.display.PacketSetCreativeSlot;
import com.willfp.eco.spigot.display.PacketSetSlot;
import com.willfp.eco.spigot.display.PacketWindowItems;
import com.willfp.eco.spigot.drops.CollatedRunnable;
import com.willfp.eco.spigot.eventlisteners.EntityDeathByEntityListeners;
import com.willfp.eco.spigot.eventlisteners.NaturalExpGainListeners;
import com.willfp.eco.spigot.integrations.anticheat.AnticheatAAC;
import com.willfp.eco.spigot.integrations.anticheat.AnticheatMatrix;
import com.willfp.eco.spigot.integrations.anticheat.AnticheatNCP;
@@ -16,12 +23,16 @@ import com.willfp.eco.spigot.integrations.antigrief.AntigriefLands;
import com.willfp.eco.spigot.integrations.antigrief.AntigriefTowny;
import com.willfp.eco.spigot.integrations.antigrief.AntigriefWorldGuard;
import com.willfp.eco.spigot.integrations.mcmmo.McmmoIntegrationImpl;
import com.willfp.eco.spigot.recipes.RecipeListener;
import com.willfp.eco.util.BlockUtils;
import com.willfp.eco.util.PlayerUtils;
import com.willfp.eco.util.SkullUtils;
import com.willfp.eco.util.TridentUtils;
import com.willfp.eco.util.command.AbstractCommand;
import com.willfp.eco.util.drops.internal.FastCollatedDropQueue;
import com.willfp.eco.util.display.Display;
import com.willfp.eco.util.display.DisplayModule;
import com.willfp.eco.util.events.armorequip.ArmorListener;
import com.willfp.eco.util.events.armorequip.DispenserArmorListener;
import com.willfp.eco.util.events.entitydeathbyentity.EntityDeathByEntityListeners;
import com.willfp.eco.util.events.naturalexpgainevent.NaturalExpGainListeners;
import com.willfp.eco.util.integrations.IntegrationLoader;
import com.willfp.eco.util.integrations.anticheat.AnticheatManager;
import com.willfp.eco.util.integrations.antigrief.AntigriefManager;
@@ -30,6 +41,7 @@ import com.willfp.eco.util.plugin.AbstractEcoPlugin;
import com.willfp.eco.util.protocollib.AbstractPacketAdapter;
import lombok.Getter;
import org.bukkit.event.Listener;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
@@ -48,15 +60,21 @@ public class EcoPlugin extends AbstractEcoPlugin {
public EcoPlugin() {
super("eco", 87955, 10043, "com.willfp.eco.proxy", "&a");
instance = this;
Display.setFinalizeKey(this.getNamespacedKeyFactory().create("finalized"));
SkullUtils.initialize((skullMeta, base64) -> InternalProxyUtils.getProxy(SkullProxy.class).setSkullTexture(skullMeta, base64));
BlockUtils.initialize(((player, block) -> InternalProxyUtils.getProxy(BlockBreakProxy.class).breakBlock(player, block)));
PlayerUtils.initialize(((player) -> InternalProxyUtils.getProxy(CooldownProxy.class).getAttackCooldown(player)));
TridentUtils.initialize(((trident) -> InternalProxyUtils.getProxy(TridentStackProxy.class).getTridentStack(trident)));
}
@Override
public void enable() {
new FastCollatedDropQueue.CollatedRunnable(this);
new CollatedRunnable(this);
this.getEventManager().registerListener(new NaturalExpGainListeners());
this.getEventManager().registerListener(new ArmorListener());
this.getEventManager().registerListener(new DispenserArmorListener());
this.getEventManager().registerListener(new EntityDeathByEntityListeners(this));
this.getEventManager().registerListener(new RecipeListener());
}
@Override
@@ -71,7 +89,7 @@ public class EcoPlugin extends AbstractEcoPlugin {
@Override
public void onReload() {
new FastCollatedDropQueue.CollatedRunnable(this);
new CollatedRunnable(this);
}
@Override
@@ -126,4 +144,10 @@ public class EcoPlugin extends AbstractEcoPlugin {
public List<Class<?>> getUpdatableClasses() {
return new ArrayList<>();
}
@Override
@Nullable
protected DisplayModule createDisplayModule() {
return null;
}
}

View File

@@ -1,4 +1,4 @@
package com.willfp.eco.spigot.display.packets;
package com.willfp.eco.spigot.display;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;

View File

@@ -1,4 +1,4 @@
package com.willfp.eco.spigot.display.packets;
package com.willfp.eco.spigot.display;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.ListenerPriority;

View File

@@ -1,4 +1,4 @@
package com.willfp.eco.spigot.display.packets;
package com.willfp.eco.spigot.display;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketContainer;

View File

@@ -1,4 +1,4 @@
package com.willfp.eco.spigot.display.packets;
package com.willfp.eco.spigot.display;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketContainer;

View File

@@ -1,4 +1,4 @@
package com.willfp.eco.spigot.display.packets;
package com.willfp.eco.spigot.display;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketContainer;

View File

@@ -1,4 +1,4 @@
package com.willfp.eco.spigot.display.packets;
package com.willfp.eco.spigot.display;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketContainer;

View File

@@ -0,0 +1,39 @@
package com.willfp.eco.spigot.drops;
import com.willfp.eco.internal.drops.impl.FastCollatedDropQueue;
import com.willfp.eco.internal.drops.impl.InternalDropQueue;
import com.willfp.eco.util.plugin.AbstractEcoPlugin;
import lombok.Getter;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitTask;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
public class CollatedRunnable {
/**
* The {@link BukkitTask} that the runnable represents.
*/
@Getter
private final BukkitTask runnableTask;
/**
* Create and run a new runnable to process collated drops.
*
* @param plugin The {@link AbstractEcoPlugin} that manages the processing.
*/
public CollatedRunnable(@NotNull final AbstractEcoPlugin plugin) {
runnableTask = plugin.getScheduler().runTimer(() -> {
for (Map.Entry<Player, FastCollatedDropQueue.CollatedDrops> entry : FastCollatedDropQueue.COLLATED_MAP.entrySet()) {
new InternalDropQueue(entry.getKey())
.setLocation(entry.getValue().getLocation())
.addItems(entry.getValue().getDrops())
.addXP(entry.getValue().getXp())
.push();
FastCollatedDropQueue.COLLATED_MAP.remove(entry.getKey());
}
FastCollatedDropQueue.COLLATED_MAP.clear();
}, 0, 1);
}
}

View File

@@ -1,5 +1,6 @@
package com.willfp.eco.util.events.entitydeathbyentity;
package com.willfp.eco.spigot.eventlisteners;
import com.willfp.eco.util.events.entitydeathbyentity.EntityDeathByEntityEvent;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang.Validate;

View File

@@ -1,4 +1,4 @@
package com.willfp.eco.util.events.entitydeathbyentity;
package com.willfp.eco.spigot.eventlisteners;
import com.willfp.eco.util.internal.PluginDependent;
import com.willfp.eco.util.plugin.AbstractEcoPlugin;

View File

@@ -1,5 +1,6 @@
package com.willfp.eco.util.events.naturalexpgainevent;
package com.willfp.eco.spigot.eventlisteners;
import com.willfp.eco.util.events.naturalexpgainevent.NaturalExpGainEvent;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang.Validate;

View File

@@ -1,4 +1,4 @@
package com.willfp.eco.util.events.naturalexpgainevent;
package com.willfp.eco.spigot.eventlisteners;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
@@ -7,6 +7,7 @@ import org.bukkit.event.player.PlayerExpChangeEvent;
import org.jetbrains.annotations.NotNull;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
public class NaturalExpGainListeners implements Listener {
@@ -28,9 +29,10 @@ public class NaturalExpGainListeners implements Listener {
NaturalExpGainBuilder toRemove = null;
for (NaturalExpGainBuilder searchBuilder : events) {
if (!searchBuilder.getLocation().getWorld().equals(event.getPlayer().getLocation().getWorld())) {
if (!Objects.equals(searchBuilder.getLocation().getWorld(), event.getPlayer().getLocation().getWorld())) {
continue;
}
if (searchBuilder.getReason().equals(NaturalExpGainBuilder.BuildReason.BOTTLE) && searchBuilder.getLocation().distanceSquared(event.getPlayer().getLocation()) > 52) {
toRemove = searchBuilder;
}

View File

@@ -29,6 +29,10 @@ public class AntigriefKingdoms implements AntigriefWrapper {
Land land = Land.getLand(block);
if (land == null) {
return true;
}
DefaultKingdomPermission permission = land.isNexusLand() ? DefaultKingdomPermission.NEXUS_BUILD : DefaultKingdomPermission.BUILD;
if (!kp.hasPermission(permission)) {
return false;

View File

@@ -0,0 +1,220 @@
package com.willfp.eco.spigot.recipes;
import com.willfp.eco.util.plugin.AbstractEcoPlugin;
import com.willfp.eco.util.recipe.RecipeParts;
import com.willfp.eco.util.recipe.Recipes;
import com.willfp.eco.util.recipe.parts.RecipePart;
import com.willfp.eco.util.recipe.parts.SimpleRecipePart;
import com.willfp.eco.util.recipe.recipes.EcoShapedRecipe;
import org.bukkit.Material;
import org.bukkit.event.Event;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.CraftItemEvent;
import org.bukkit.event.inventory.PrepareItemCraftEvent;
import org.bukkit.event.player.PlayerRecipeDiscoverEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.ShapedRecipe;
import org.jetbrains.annotations.NotNull;
public class RecipeListener implements Listener {
/**
* Called on item craft.
*
* @param event The event to listen for.
*/
@EventHandler
public void complexRecipeListener(@NotNull final PrepareItemCraftEvent event) {
if (!(event.getRecipe() instanceof ShapedRecipe)) {
return;
}
ShapedRecipe recipe = (ShapedRecipe) event.getRecipe();
if (!AbstractEcoPlugin.LOADED_ECO_PLUGINS.contains(recipe.getKey().getNamespace())) {
return;
}
ItemStack[] matrix = event.getInventory().getMatrix();
EcoShapedRecipe matched = Recipes.getMatch(matrix);
if (matched == null) {
event.getInventory().setResult(new ItemStack(Material.AIR));
return;
}
if (matched.test(matrix)) {
event.getInventory().setResult(matched.getOutput());
} else {
event.getInventory().setResult(new ItemStack(Material.AIR));
}
}
/**
* Called on item craft.
*
* @param event The event to listen for.
*/
@EventHandler
public void complexRecipeListener(@NotNull final CraftItemEvent event) {
if (!(event.getRecipe() instanceof ShapedRecipe)) {
return;
}
ShapedRecipe recipe = (ShapedRecipe) event.getRecipe();
if (!AbstractEcoPlugin.LOADED_ECO_PLUGINS.contains(recipe.getKey().getNamespace())) {
return;
}
ItemStack[] matrix = event.getInventory().getMatrix();
EcoShapedRecipe matched = Recipes.getMatch(matrix);
if (matched == null) {
event.getInventory().setResult(new ItemStack(Material.AIR));
event.setResult(Event.Result.DENY);
event.setCancelled(true);
return;
}
if (matched.test(matrix)) {
event.getInventory().setResult(matched.getOutput());
} else {
event.getInventory().setResult(new ItemStack(Material.AIR));
event.setResult(Event.Result.DENY);
event.setCancelled(true);
}
}
/**
* Called on item craft.
*
* @param event The event to listen for.
*/
@EventHandler
public void preventUsingComplexPartInEcoRecipe(@NotNull final PrepareItemCraftEvent event) {
if (!(event.getRecipe() instanceof ShapedRecipe)) {
return;
}
ShapedRecipe recipe = (ShapedRecipe) event.getRecipe();
EcoShapedRecipe ecoShapedRecipe = Recipes.getShapedRecipe(recipe.getKey());
if (ecoShapedRecipe == null) {
return;
}
for (int i = 0; i < 9; i++) {
ItemStack itemStack = event.getInventory().getMatrix()[i];
RecipePart part = ecoShapedRecipe.getParts()[i];
if (part instanceof SimpleRecipePart) {
if (RecipeParts.isRecipePart(itemStack)) {
event.getInventory().setResult(new ItemStack(Material.AIR));
return;
}
}
}
}
/**
* Called on item craft.
*
* @param event The event to listen for.
*/
@EventHandler
public void preventUsingComplexPartInEcoRecipe(@NotNull final CraftItemEvent event) {
if (!(event.getRecipe() instanceof ShapedRecipe)) {
return;
}
ShapedRecipe recipe = (ShapedRecipe) event.getRecipe();
EcoShapedRecipe ecoShapedRecipe = Recipes.getShapedRecipe(recipe.getKey());
if (ecoShapedRecipe == null) {
return;
}
for (int i = 0; i < 9; i++) {
ItemStack itemStack = event.getInventory().getMatrix()[i];
RecipePart part = ecoShapedRecipe.getParts()[i];
if (part instanceof SimpleRecipePart) {
if (RecipeParts.isRecipePart(itemStack)) {
event.getInventory().setResult(new ItemStack(Material.AIR));
event.setResult(Event.Result.DENY);
event.setCancelled(true);
return;
}
}
}
}
/**
* Prevents using talismans in recipes.
*
* @param event The event to listen for.
*/
@EventHandler
public void preventUsingComplexPartInVanillaRecipe(@NotNull final PrepareItemCraftEvent event) {
if (!(event.getRecipe() instanceof ShapedRecipe)) {
return;
}
ShapedRecipe recipe = (ShapedRecipe) event.getRecipe();
if (AbstractEcoPlugin.LOADED_ECO_PLUGINS.contains(recipe.getKey().getNamespace())) {
return;
}
for (ItemStack itemStack : event.getInventory().getMatrix()) {
if (RecipeParts.isRecipePart(itemStack)) {
event.getInventory().setResult(new ItemStack(Material.AIR));
return;
}
}
}
/**
* Prevents using talismans in recipes.
*
* @param event The event to listen for.
*/
@EventHandler
public void preventUsingComplexPartInVanillaRecipe(@NotNull final CraftItemEvent event) {
if (!(event.getRecipe() instanceof ShapedRecipe)) {
return;
}
ShapedRecipe recipe = (ShapedRecipe) event.getRecipe();
if (AbstractEcoPlugin.LOADED_ECO_PLUGINS.contains(recipe.getKey().getNamespace())) {
return;
}
for (ItemStack itemStack : event.getInventory().getMatrix()) {
if (RecipeParts.isRecipePart(itemStack)) {
event.getInventory().setResult(new ItemStack(Material.AIR));
event.setResult(Event.Result.DENY);
event.setCancelled(true);
return;
}
}
}
/**
* Prevents learning displayed recipes.
*
* @param event The event to listen for.
*/
@EventHandler
public void preventLearningDisplayedRecipes(@NotNull final PlayerRecipeDiscoverEvent event) {
if (!AbstractEcoPlugin.LOADED_ECO_PLUGINS.contains(event.getRecipe().getNamespace())) {
return;
}
if (event.getRecipe().getKey().contains("_displayed")) {
event.setCancelled(true);
}
}
}

View File

@@ -7,7 +7,7 @@ website: willfp.com
loadbefore:
- EcoEnchants
- Talismans
- ItemStats
- StatTrackers
- EcoArmor
- Illusioner
depend:

View File

@@ -0,0 +1,17 @@
package com.willfp.eco.proxy.proxies;
import com.willfp.eco.util.proxy.AbstractProxy;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public interface BlockBreakProxy extends AbstractProxy {
/**
* Break the block as if the player had done it manually.
*
* @param player The player to break the block as.
* @param block The block to break.
*/
void breakBlock(@NotNull Player player,
@NotNull Block block);
}

View File

@@ -0,0 +1,15 @@
package com.willfp.eco.proxy.proxies;
import com.willfp.eco.util.proxy.AbstractProxy;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public interface CooldownProxy extends AbstractProxy {
/**
* Get the attack cooldown for a player.
*
* @param player The player's attack cooldown.
* @return A value between 0 and 1, with 1 representing full power.
*/
double getAttackCooldown(@NotNull Player player);
}

View File

@@ -0,0 +1,16 @@
package com.willfp.eco.proxy.proxies;
import com.willfp.eco.util.proxy.AbstractProxy;
import org.bukkit.inventory.meta.SkullMeta;
import org.jetbrains.annotations.NotNull;
public interface SkullProxy extends AbstractProxy {
/**
* Set the texture of a skull from base64.
*
* @param meta The meta to modify.
* @param base64 The base64 texture.
*/
void setSkullTexture(@NotNull SkullMeta meta,
@NotNull String base64);
}

View File

@@ -0,0 +1,16 @@
package com.willfp.eco.proxy.proxies;
import com.willfp.eco.util.proxy.AbstractProxy;
import org.bukkit.entity.Trident;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
public interface TridentStackProxy extends AbstractProxy {
/**
* Get a trident's ItemStack.
*
* @param trident The trident to query.
* @return The trident's ItemStack.
*/
ItemStack getTridentStack(@NotNull Trident trident);
}

View File

@@ -1,4 +1,4 @@
package com.willfp.eco.util.arrows;
package com.willfp.eco.internal.arrows;
import com.willfp.eco.util.internal.PluginDependent;
import com.willfp.eco.util.plugin.AbstractEcoPlugin;

View File

@@ -1,5 +1,6 @@
package com.willfp.eco.util.bukkit.events;
package com.willfp.eco.internal.bukkit.events;
import com.willfp.eco.util.bukkit.events.EventManager;
import com.willfp.eco.util.internal.PluginDependent;
import com.willfp.eco.util.plugin.AbstractEcoPlugin;
import org.bukkit.Bukkit;

View File

@@ -1,6 +1,7 @@
package com.willfp.eco.util.bukkit.logging;
package com.willfp.eco.internal.bukkit.logging;
import com.willfp.eco.util.StringUtils;
import com.willfp.eco.util.bukkit.logging.Logger;
import com.willfp.eco.util.internal.PluginDependent;
import com.willfp.eco.util.plugin.AbstractEcoPlugin;
import org.jetbrains.annotations.NotNull;

View File

@@ -1,5 +1,6 @@
package com.willfp.eco.util.bukkit.scheduling;
package com.willfp.eco.internal.bukkit.scheduling;
import com.willfp.eco.util.bukkit.scheduling.Scheduler;
import com.willfp.eco.util.internal.PluginDependent;
import com.willfp.eco.util.plugin.AbstractEcoPlugin;
import org.bukkit.Bukkit;

View File

@@ -0,0 +1,472 @@
package com.willfp.eco.internal.config;
import com.willfp.eco.util.StringUtils;
import com.willfp.eco.util.internal.PluginDependent;
import com.willfp.eco.util.plugin.AbstractEcoPlugin;
import lombok.AccessLevel;
import lombok.Getter;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@SuppressWarnings("unchecked")
public abstract class AbstractConfig extends PluginDependent {
/**
* The linked {@link YamlConfiguration} where values are physically stored.
*/
@Getter(AccessLevel.PUBLIC)
protected final YamlConfiguration config;
/**
* The physical config file, as stored on disk.
*/
@Getter(AccessLevel.PROTECTED)
private final File configFile;
/**
* The full name of the config file (eg config.yml).
*/
@Getter(AccessLevel.PROTECTED)
private final String name;
/**
* The subdirectory path.
*/
@Getter(AccessLevel.PROTECTED)
private final String subDirectoryPath;
/**
* The provider of the config.
*/
@Getter(AccessLevel.PROTECTED)
private final Class<?> source;
/**
* Cached values for faster reading.
*/
private final Map<String, Object> cache = new HashMap<>();
/**
* Abstract config.
*
* @param configName The name of the config
* @param plugin The plugin.
* @param subDirectoryPath The subdirectory path.
* @param source The class that owns the resource.
*/
protected AbstractConfig(@NotNull final String configName,
@NotNull final AbstractEcoPlugin plugin,
@NotNull final String subDirectoryPath,
@NotNull final Class<?> source) {
super(plugin);
this.source = source;
this.subDirectoryPath = subDirectoryPath;
this.name = configName + ".yml";
File directory = new File(this.getPlugin().getDataFolder(), subDirectoryPath);
if (!directory.exists()) {
directory.mkdirs();
}
if (!new File(directory, this.name).exists()) {
createFile();
}
this.configFile = new File(directory, this.name);
this.config = YamlConfiguration.loadConfiguration(configFile);
}
private void createFile() {
String resourcePath = getResourcePath();
InputStream in = source.getResourceAsStream(resourcePath);
File outFile = new File(this.getPlugin().getDataFolder(), resourcePath);
int lastIndex = resourcePath.lastIndexOf('/');
File outDir = new File(this.getPlugin().getDataFolder(), resourcePath.substring(0, Math.max(lastIndex, 0)));
if (!outDir.exists()) {
outDir.mkdirs();
}
try {
if (!outFile.exists()) {
OutputStream out = new FileOutputStream(outFile);
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
out.close();
in.close();
}
} catch (IOException ignored) {
}
}
/**
* Get resource path as relative to base directory.
*
* @return The resource path.
*/
protected String getResourcePath() {
String resourcePath;
if (subDirectoryPath.isEmpty()) {
resourcePath = name;
} else {
resourcePath = subDirectoryPath + name;
}
return "/" + resourcePath;
}
/**
* Get YamlConfiguration as found in jar.
*
* @return The YamlConfiguration.
*/
protected YamlConfiguration getConfigInJar() {
InputStream newIn = source.getResourceAsStream(getResourcePath());
if (newIn == null) {
throw new NullPointerException(this.getName() + " is null?");
}
BufferedReader reader = new BufferedReader(new InputStreamReader(newIn, StandardCharsets.UTF_8));
YamlConfiguration newConfig = new YamlConfiguration();
try {
newConfig.load(reader);
} catch (IOException | InvalidConfigurationException e) {
e.printStackTrace();
}
return newConfig;
}
/**
* Clears cache.
*/
public final void clearCache() {
cache.clear();
}
/**
* Get if the config contains a key.
*
* @param path The key to check.
* @return If contained.
*/
public boolean has(@NotNull final String path) {
return config.contains(path);
}
/**
* Get configuration section from config.
*
* @param path The key to check.
* @return The configuration section. Throws NPE if not found.
*/
@NotNull
public ConfigurationSection getSection(@NotNull final String path) {
ConfigurationSection section = getSectionOrNull(path);
if (section == null) {
throw new NullPointerException("Section cannot be null!");
} else {
return section;
}
}
/**
* Get configuration section from config.
*
* @param path The key to check.
* @return The configuration section, or null if not found.
*/
@Nullable
public ConfigurationSection getSectionOrNull(@NotNull final String path) {
if (cache.containsKey(path)) {
return (ConfigurationSection) cache.get(path);
} else {
cache.put(path, config.getConfigurationSection(path));
return getSectionOrNull(path);
}
}
/**
* Get an integer from config.
*
* @param path The key to fetch the value from.
* @return The found value, or 0 if not found.
*/
public int getInt(@NotNull final String path) {
if (cache.containsKey(path)) {
return (int) cache.get(path);
} else {
cache.put(path, config.getInt(path, 0));
return getInt(path);
}
}
/**
* Get an integer from config.
*
* @param path The key to fetch the value from.
* @return The found value, or null if not found.
*/
@Nullable
public Integer getIntOrNull(@NotNull final String path) {
if (has(path)) {
return getInt(path);
} else {
return null;
}
}
/**
* Get an integer from config with a specified default (not found) value.
*
* @param path The key to fetch the value from.
* @param def The value to default to if not found.
* @return The found value, or the default.
*/
public int getInt(@NotNull final String path,
final int def) {
if (cache.containsKey(path)) {
return (int) cache.get(path);
} else {
cache.put(path, config.getInt(path, def));
return getInt(path);
}
}
/**
* Get a list of integers 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
public List<Integer> getInts(@NotNull final String path) {
if (cache.containsKey(path)) {
return (List<Integer>) cache.get(path);
} else {
cache.put(path, config.getIntegerList(path));
return getInts(path);
}
}
/**
* Get a list of integers from config.
*
* @param path The key to fetch the value from.
* @return The found value, or null if not found.
*/
@Nullable
public List<Integer> getIntsOrNull(@NotNull final String path) {
if (has(path)) {
return getInts(path);
} else {
return null;
}
}
/**
* Get a boolean from config.
*
* @param path The key to fetch the value from.
* @return The found value, or false if not found.
*/
public boolean getBool(@NotNull final String path) {
if (cache.containsKey(path)) {
return (boolean) cache.get(path);
} else {
cache.put(path, config.getBoolean(path));
return getBool(path);
}
}
/**
* Get a boolean from config.
*
* @param path The key to fetch the value from.
* @return The found value, or null if not found.
*/
@Nullable
public Boolean getBoolOrNull(@NotNull final String path) {
if (has(path)) {
return getBool(path);
} else {
return null;
}
}
/**
* Get a list of booleans 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
public List<Boolean> getBools(@NotNull final String path) {
if (cache.containsKey(path)) {
return (List<Boolean>) cache.get(path);
} else {
cache.put(path, config.getBooleanList(path));
return getBools(path);
}
}
/**
* Get a list of booleans from config.
*
* @param path The key to fetch the value from.
* @return The found value, or null if not found.
*/
@Nullable
public List<Boolean> getBoolsOrNull(@NotNull final String path) {
if (has(path)) {
return getBools(path);
} else {
return null;
}
}
/**
* Get a string from config.
*
* @param path The key to fetch the value from.
* @return The found value, or an empty string if not found.
*/
@NotNull
public String getString(@NotNull final String path) {
if (cache.containsKey(path)) {
return (String) cache.get(path);
} else {
cache.put(path, StringUtils.translate(Objects.requireNonNull(config.getString(path, ""))));
return getString(path);
}
}
/**
* Get a string from config.
*
* @param path The key to fetch the value from.
* @return The found value, or null if not found.
*/
@Nullable
public String getStringOrNull(@NotNull final String path) {
if (has(path)) {
return getString(path);
} else {
return null;
}
}
/**
* Get a list of strings 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
public List<String> getStrings(@NotNull final String path) {
if (cache.containsKey(path)) {
return (List<String>) cache.get(path);
} else {
cache.put(path, config.getStringList(path));
return getStrings(path);
}
}
/**
* Get a list of strings from config.
*
* @param path The key to fetch the value from.
* @return The found value, or null if not found.
*/
@Nullable
public List<String> getStringsOrNull(@NotNull final String path) {
if (has(path)) {
return getStrings(path);
} else {
return null;
}
}
/**
* Get a decimal from config.
*
* @param path The key to fetch the value from.
* @return The found value, or 0 if not found.
*/
public double getDouble(@NotNull final String path) {
if (cache.containsKey(path)) {
return (double) cache.get(path);
} else {
cache.put(path, config.getDouble(path));
return getDouble(path);
}
}
/**
* Get a decimal from config.
*
* @param path The key to fetch the value from.
* @return The found value, or null if not found.
*/
@Nullable
public Double getDoubleOrNull(@NotNull final String path) {
if (has(path)) {
return getDouble(path);
} else {
return null;
}
}
/**
* Get a list of decimals 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
public List<Double> getDoubles(@NotNull final String path) {
if (cache.containsKey(path)) {
return (List<Double>) cache.get(path);
} else {
cache.put(path, config.getDoubleList(path));
return getDoubles(path);
}
}
/**
* Get a list of decimals from config.
*
* @param path The key to fetch the value from.
* @return The found value, or null if not found.
*/
@Nullable
public List<Double> getDoublesOrNull(@NotNull final String path) {
if (has(path)) {
return getDoubles(path);
} else {
return null;
}
}
}

View File

@@ -0,0 +1,87 @@
package com.willfp.eco.internal.config;
import com.willfp.eco.util.plugin.AbstractEcoPlugin;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public abstract class AbstractUpdatableConfig extends AbstractConfig {
/**
* Whether keys not in the base config should be removed on update.
*/
private final boolean removeUnused;
/**
* List of blacklisted update keys.
*/
private final List<String> updateBlacklist;
/**
* Updatable config.
*
* @param configName The name of the config
* @param plugin The plugin.
* @param subDirectoryPath The subdirectory path.
* @param source The class that owns the resource.
* @param removeUnused Whether keys not present in the default config should be removed on update.
* @param updateBlacklist Substring of keys to not add/remove keys for.
*/
protected AbstractUpdatableConfig(@NotNull final String configName,
@NotNull final AbstractEcoPlugin plugin,
@NotNull final String subDirectoryPath,
@NotNull final Class<?> source,
final boolean removeUnused,
@NotNull final String... updateBlacklist) {
super(configName, plugin, subDirectoryPath, source);
this.removeUnused = removeUnused;
this.updateBlacklist = new ArrayList<>(Arrays.asList(updateBlacklist));
this.updateBlacklist.removeIf(String::isEmpty);
update();
}
/**
* Update the config.
* <p>
* Writes missing values, however removes comments due to how configs are stored internally in bukkit.
*/
public void update() {
super.clearCache();
try {
config.load(this.getConfigFile());
YamlConfiguration newConfig = this.getConfigInJar();
if (newConfig.getKeys(true).equals(config.getKeys(true))) {
return;
}
newConfig.getKeys(true).forEach((s -> {
if (!config.getKeys(true).contains(s)) {
if (updateBlacklist.stream().noneMatch(s::contains)) {
config.set(s, newConfig.get(s));
}
}
}));
if (this.removeUnused) {
config.getKeys(true).forEach((s -> {
if (!newConfig.getKeys(true).contains(s)) {
if (updateBlacklist.stream().noneMatch(s::contains)) {
config.set(s, null);
}
}
}));
}
config.save(this.getConfigFile());
} catch (IOException | InvalidConfigurationException e) {
e.printStackTrace();
}
}
}

View File

@@ -1,4 +1,4 @@
package com.willfp.eco.util.drops.internal;
package com.willfp.eco.internal.drops;
import org.bukkit.Location;
import org.bukkit.inventory.ItemStack;

View File

@@ -1,4 +1,4 @@
package com.willfp.eco.util.drops.internal;
package com.willfp.eco.internal.drops;
import lombok.Getter;
import lombok.experimental.UtilityClass;

View File

@@ -1,4 +1,4 @@
package com.willfp.eco.util.drops.internal;
package com.willfp.eco.internal.drops;
public enum DropQueueType {
/**

View File

@@ -1,6 +1,6 @@
package com.willfp.eco.util.drops.internal;
package com.willfp.eco.internal.drops.impl;
import com.willfp.eco.util.plugin.AbstractEcoPlugin;
import com.willfp.eco.internal.drops.AbstractDropQueue;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@@ -8,8 +8,6 @@ import lombok.experimental.Accessors;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.scheduler.BukkitTask;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import java.util.List;
@@ -22,7 +20,7 @@ public class FastCollatedDropQueue extends InternalDropQueue {
* <p>
* Cleared and updated every tick.
*/
private static final Map<Player, CollatedDrops> COLLATED_MAP = new ConcurrentHashMap<>();
public static final Map<Player, CollatedDrops> COLLATED_MAP = new ConcurrentHashMap<>();
/**
* Backend implementation of {@link AbstractDropQueue}
@@ -37,7 +35,7 @@ public class FastCollatedDropQueue extends InternalDropQueue {
}
/**
* Queues the drops to be managed by the {@link CollatedRunnable}.
* Queues the drops to be managed by the runnable.
*/
@Override
public void push() {
@@ -50,7 +48,7 @@ public class FastCollatedDropQueue extends InternalDropQueue {
* The items, location, and xp linked to a player's drops.
*/
@ToString
private static final class CollatedDrops {
public static final class CollatedDrops {
/**
* A collection of all ItemStacks to be dropped at the end of the tick.
*/
@@ -101,32 +99,4 @@ public class FastCollatedDropQueue extends InternalDropQueue {
return this;
}
}
public static class CollatedRunnable {
/**
* The {@link BukkitTask} that the runnable represents.
*/
@Getter
private final BukkitTask runnableTask;
/**
* Create and run a new runnable to process collated drops.
*
* @param plugin The {@link AbstractEcoPlugin} that manages the processing.
*/
@ApiStatus.Internal
public CollatedRunnable(@NotNull final AbstractEcoPlugin plugin) {
runnableTask = plugin.getScheduler().runTimer(() -> {
for (Map.Entry<Player, CollatedDrops> entry : COLLATED_MAP.entrySet()) {
new InternalDropQueue(entry.getKey())
.setLocation(entry.getValue().getLocation())
.addItems(entry.getValue().getDrops())
.addXP(entry.getValue().getXp())
.push();
COLLATED_MAP.remove(entry.getKey());
}
COLLATED_MAP.clear();
}, 0, 1);
}
}
}

View File

@@ -1,10 +1,12 @@
package com.willfp.eco.util.drops.internal;
package com.willfp.eco.internal.drops.impl;
import com.willfp.eco.internal.drops.AbstractDropQueue;
import com.willfp.eco.util.drops.telekinesis.TelekinesisUtils;
import lombok.AccessLevel;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.ExperienceOrb;
@@ -133,6 +135,11 @@ public class InternalDropQueue implements AbstractDropQueue {
assert world != null;
loc = loc.add(0.5, 0.5, 0.5);
items.removeIf(itemStack -> itemStack.getType() == Material.AIR);
if (items.isEmpty()) {
return;
}
if (hasTelekinesis) {
HashMap<Integer, ItemStack> leftover = player.getInventory().addItem(items.toArray(new ItemStack[0]));
for (ItemStack drop : leftover.values()) {

View File

@@ -1,10 +1,12 @@
package com.willfp.eco.util.extensions.loader;
package com.willfp.eco.internal.extensions;
import com.willfp.eco.util.extensions.Extension;
import com.willfp.eco.util.extensions.MalformedExtensionException;
import com.willfp.eco.util.extensions.loader.ExtensionLoader;
import com.willfp.eco.util.internal.PluginDependent;
import com.willfp.eco.util.plugin.AbstractEcoPlugin;
import org.apache.commons.lang.Validate;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;
@@ -94,6 +96,9 @@ public class EcoExtensionLoader extends PluginDependent implements ExtensionLoad
String mainClass = extensionYml.getString("main");
String name = extensionYml.getString("name");
String version = extensionYml.getString("version");
Validate.notNull(name, "Name is missing!");
Validate.notNull(version, "Version is missing!");
Extension.ExtensionMetadata metadata = new Extension.ExtensionMetadata(version, name);
Class<?> cls;

View File

@@ -1,20 +1,34 @@
package com.willfp.eco.util;
import lombok.experimental.UtilityClass;
import org.apache.commons.lang.Validate;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.BiConsumer;
@UtilityClass
public class BlockUtils {
public class BlockUtils {
/**
* If the meta set function has been set.
*/
private boolean initialized = false;
/**
* The block break function.
*/
private BiConsumer<Player, Block> blockBreakConsumer = null;
private Set<Block> getNearbyBlocks(@NotNull final Block start,
@NotNull final List<Material> allowedMaterials,
@NotNull final HashSet<Block> blocks,
@NotNull final Set<Block> blocks,
final int limit) {
for (BlockFace face : BlockFace.values()) {
Block block = start.getRelative(face);
@@ -29,7 +43,6 @@ public class BlockUtils {
return blocks;
}
/**
* Get a set of all blocks in contact with each other of a specific type.
*
@@ -44,4 +57,32 @@ public class BlockUtils {
final int limit) {
return getNearbyBlocks(start, allowedMaterials, new HashSet<>(), limit);
}
/**
* Break the block as if the player had done it manually.
*
* @param player The player to break the block as.
* @param block The block to break.
*/
public void breakBlock(@NotNull final Player player,
@NotNull final Block block) {
Validate.isTrue(initialized, "Must be initialized!");
Validate.notNull(blockBreakConsumer, "Must be initialized!");
blockBreakConsumer.accept(player, block);
}
/**
* Initialize the block break function.
*
* @param function The function.
*/
@ApiStatus.Internal
public void initialize(@NotNull final BiConsumer<Player, Block> function) {
Validate.isTrue(!initialized, "Already initialized!");
blockBreakConsumer = function;
initialized = true;
}
}

View File

@@ -2,6 +2,7 @@ package com.willfp.eco.util;
import lombok.experimental.UtilityClass;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.SoundCategory;
import org.bukkit.entity.Player;
@@ -37,25 +38,32 @@ public class DurabilityUtils {
return;
}
if (!(item.getItemMeta() instanceof Damageable)) {
return;
}
// Special edge case
if (item.getType() == Material.CARVED_PUMPKIN || item.getType() == Material.PLAYER_HEAD) {
return;
}
PlayerItemDamageEvent event3 = new PlayerItemDamageEvent(player, item, damage);
Bukkit.getPluginManager().callEvent(event3);
if (!event3.isCancelled()) {
int damage2 = event3.getDamage();
if (item.getItemMeta() instanceof Damageable) {
Damageable meta = (Damageable) item.getItemMeta();
meta.setDamage(meta.getDamage() + damage2);
Damageable meta = (Damageable) item.getItemMeta();
meta.setDamage(meta.getDamage() + damage2);
if (meta.getDamage() >= item.getType().getMaxDurability()) {
meta.setDamage(item.getType().getMaxDurability());
item.setItemMeta((ItemMeta) meta);
PlayerItemBreakEvent event = new PlayerItemBreakEvent(player, item);
Bukkit.getPluginManager().callEvent(event);
player.getInventory().clear(slot);
player.playSound(player.getLocation(), Sound.ENTITY_ITEM_BREAK, SoundCategory.BLOCKS, 1, 1);
} else {
item.setItemMeta((ItemMeta) meta);
}
if (meta.getDamage() >= item.getType().getMaxDurability()) {
meta.setDamage(item.getType().getMaxDurability());
item.setItemMeta((ItemMeta) meta);
PlayerItemBreakEvent event = new PlayerItemBreakEvent(player, item);
Bukkit.getPluginManager().callEvent(event);
player.getInventory().clear(slot);
player.playSound(player.getLocation(), Sound.ENTITY_ITEM_BREAK, SoundCategory.BLOCKS, 1, 1);
} else {
item.setItemMeta((ItemMeta) meta);
}
}
}
@@ -78,20 +86,22 @@ public class DurabilityUtils {
return;
}
if (!(item.getItemMeta() instanceof Damageable)) {
return;
}
PlayerItemDamageEvent event3 = new PlayerItemDamageEvent(player, item, damage);
Bukkit.getPluginManager().callEvent(event3);
if (!event3.isCancelled()) {
int damage2 = event3.getDamage();
if (item.getItemMeta() instanceof Damageable) {
Damageable meta = (Damageable) item.getItemMeta();
meta.setDamage(meta.getDamage() + damage2);
Damageable meta = (Damageable) item.getItemMeta();
meta.setDamage(meta.getDamage() + damage2);
if (meta.getDamage() >= item.getType().getMaxDurability()) {
meta.setDamage(item.getType().getMaxDurability() - 1);
}
item.setItemMeta((ItemMeta) meta);
if (meta.getDamage() >= item.getType().getMaxDurability()) {
meta.setDamage(item.getType().getMaxDurability() - 1);
}
item.setItemMeta((ItemMeta) meta);
}
}

View File

@@ -0,0 +1,54 @@
package com.willfp.eco.util;
import com.willfp.eco.util.optional.Prerequisite;
import lombok.experimental.UtilityClass;
import org.apache.commons.lang.Validate;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import java.util.function.Function;
@UtilityClass
public class PlayerUtils {
/**
* If the meta set function has been set.
*/
private boolean initialized = false;
/**
* The cooldown function.
*/
private Function<Player, Double> cooldownFunction = null;
/**
* Get the attack cooldown for a player.
*
* @param player The player's attack cooldown.
* @return A value between 0 and 1, with 1 representing full power.
*/
public double getAttackCooldown(@NotNull final Player player) {
Validate.isTrue(initialized, "Must be initialized!");
Validate.notNull(cooldownFunction, "Must be initialized!");
if (Prerequisite.MINIMUM_1_16.isMet()) {
return player.getAttackCooldown();
}
return cooldownFunction.apply(player);
}
/**
* Initialize the cooldown function.
*
* @param function The function.
*/
@ApiStatus.Internal
public void initialize(@NotNull final Function<Player, Double> function) {
Validate.isTrue(!initialized, "Already initialized!");
cooldownFunction = function;
initialized = true;
}
}

View File

@@ -0,0 +1,49 @@
package com.willfp.eco.util;
import lombok.experimental.UtilityClass;
import org.apache.commons.lang.Validate;
import org.bukkit.inventory.meta.SkullMeta;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import java.util.function.BiConsumer;
@UtilityClass
public class SkullUtils {
/**
* If the meta set function has been set.
*/
private boolean initialized = false;
/**
* The meta set function.
*/
private BiConsumer<SkullMeta, String> metaSetConsumer = null;
/**
* Set the texture of a skull from base64.
*
* @param meta The meta to modify.
* @param base64 The base64 texture.
*/
public void setSkullTexture(@NotNull final SkullMeta meta,
@NotNull final String base64) {
Validate.isTrue(initialized, "Must be initialized!");
Validate.notNull(metaSetConsumer, "Must be initialized!");
metaSetConsumer.accept(meta, base64);
}
/**
* Initialize the skull texture function.
*
* @param function The function.
*/
@ApiStatus.Internal
public void initialize(@NotNull final BiConsumer<SkullMeta, String> function) {
Validate.isTrue(!initialized, "Already initialized!");
metaSetConsumer = function;
initialized = true;
}
}

View File

@@ -0,0 +1,49 @@
package com.willfp.eco.util;
import lombok.experimental.UtilityClass;
import org.apache.commons.lang.Validate;
import org.bukkit.entity.Trident;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import java.util.function.Function;
@UtilityClass
public class TridentUtils {
/**
* If the meta set function has been set.
*/
private boolean initialized = false;
/**
* The meta set function.
*/
private Function<Trident, ItemStack> tridentFunction = null;
/**
* Get a trident's ItemStack.
*
* @param trident The trident to query.
* @return The trident's ItemStack.
*/
public ItemStack getItemStack(@NotNull final Trident trident) {
Validate.isTrue(initialized, "Must be initialized!");
Validate.notNull(tridentFunction, "Must be initialized!");
return tridentFunction.apply(trident);
}
/**
* Initialize the trident function.
*
* @param function The function.
*/
@ApiStatus.Internal
public void initialize(@NotNull final Function<Trident, ItemStack> function) {
Validate.isTrue(!initialized, "Already initialized!");
tridentFunction = function;
initialized = true;
}
}

View File

@@ -1,11 +1,11 @@
package com.willfp.eco.util.bukkit.keys;
import com.willfp.eco.util.internal.PluginDependentFactory;
import com.willfp.eco.util.internal.PluginDependent;
import com.willfp.eco.util.plugin.AbstractEcoPlugin;
import org.bukkit.NamespacedKey;
import org.jetbrains.annotations.NotNull;
public class NamespacedKeyFactory extends PluginDependentFactory {
public class NamespacedKeyFactory extends PluginDependent {
/**
* Factory class to produce {@link NamespacedKey}s associated with an {@link AbstractEcoPlugin}.
*

View File

@@ -1,11 +1,11 @@
package com.willfp.eco.util.bukkit.meta;
import com.willfp.eco.util.internal.PluginDependentFactory;
import com.willfp.eco.util.internal.PluginDependent;
import com.willfp.eco.util.plugin.AbstractEcoPlugin;
import org.bukkit.metadata.FixedMetadataValue;
import org.jetbrains.annotations.NotNull;
public class MetadataValueFactory extends PluginDependentFactory {
public class MetadataValueFactory extends PluginDependent {
/**
* Factory class to produce {@link FixedMetadataValue}s associated with an {@link AbstractEcoPlugin}.
*

View File

@@ -1,12 +1,12 @@
package com.willfp.eco.util.bukkit.scheduling;
import com.willfp.eco.util.internal.PluginDependentFactory;
import com.willfp.eco.util.internal.PluginDependent;
import com.willfp.eco.util.plugin.AbstractEcoPlugin;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
public class RunnableFactory extends PluginDependentFactory {
public class RunnableFactory extends PluginDependent {
/**
* Factory class to produce {@link EcoBukkitRunnable}s associated with an {@link AbstractEcoPlugin}.
*

View File

@@ -12,7 +12,8 @@ public interface Scheduler {
* @param ticksLater The amount of ticks to wait before execution.
* @return The created {@link BukkitTask}.
*/
BukkitTask runLater(@NotNull Runnable runnable, long ticksLater);
BukkitTask runLater(@NotNull Runnable runnable,
long ticksLater);
/**
* Run the task repeatedly on a timer.
@@ -22,7 +23,9 @@ public interface Scheduler {
* @param repeat The amount of ticks to wait between executions.
* @return The created {@link BukkitTask}.
*/
BukkitTask runTimer(@NotNull Runnable runnable, long delay, long repeat);
BukkitTask runTimer(@NotNull Runnable runnable,
long delay,
long repeat);
/**
* Run the task repeatedly and asynchronously on a timer.
@@ -32,7 +35,9 @@ public interface Scheduler {
* @param repeat The amount of ticks to wait between executions.
* @return The created {@link BukkitTask}.
*/
BukkitTask runAsyncTimer(@NotNull Runnable runnable, long delay, long repeat);
BukkitTask runAsyncTimer(@NotNull Runnable runnable,
long delay,
long repeat);
/**
* Run the task.
@@ -58,7 +63,9 @@ public interface Scheduler {
* @param repeat The amount of ticks to wait between executions.
* @return The id of the task.
*/
int syncRepeating(@NotNull Runnable runnable, long delay, long repeat);
int syncRepeating(@NotNull Runnable runnable,
long delay,
long repeat);
/**
* Cancel all running tasks from the linked {@link AbstractEcoPlugin}.

View File

@@ -0,0 +1,11 @@
package com.willfp.eco.util.bukkit.scheduling;
public interface TimedRunnable extends Runnable {
/**
* The TimedRunnable interface is generally used for repeating tasks.
* This method is to retrieve the ticks between repetitions.
*
* @return The ticks between repetitions.
*/
long getTime();
}

View File

@@ -1,7 +1,6 @@
package com.willfp.eco.util.command;
import com.willfp.eco.util.internal.PluginDependent;
import com.willfp.eco.util.interfaces.Registerable;
import com.willfp.eco.util.plugin.AbstractEcoPlugin;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
@@ -15,7 +14,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.List;
public abstract class AbstractCommand extends PluginDependent implements CommandExecutor, Registerable {
public abstract class AbstractCommand extends PluginDependent implements CommandExecutor {
/**
* The name of the command
* <p>
@@ -130,7 +129,6 @@ public abstract class AbstractCommand extends PluginDependent implements Command
* <p>
* Requires the command name to exist, defined in plugin.yml.
*/
@Override
public final void register() {
PluginCommand command = Bukkit.getPluginCommand(name);
assert command != null;

View File

@@ -1,221 +1,40 @@
package com.willfp.eco.util.config;
import com.willfp.eco.util.StringUtils;
import com.willfp.eco.util.internal.PluginDependent;
import com.willfp.eco.internal.config.AbstractUpdatableConfig;
import com.willfp.eco.util.plugin.AbstractEcoPlugin;
import lombok.AccessLevel;
import lombok.Getter;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Objects;
public abstract class BaseConfig extends PluginDependent implements ValueGetter {
/**
* The linked {@link YamlConfiguration} where values are physically stored.
*/
@Getter(AccessLevel.PUBLIC)
private final YamlConfiguration config;
/**
* The physical config file, as stored on disk.
*/
@Getter(AccessLevel.PROTECTED)
private final File configFile;
/**
* The full name of the config file (eg config.yml).
*/
private final String name;
/**
* Whether keys not in the base config should be removed on update.
*/
private final boolean removeUnused;
public abstract class BaseConfig extends AbstractUpdatableConfig {
/**
* Config implementation for configs present in the plugin's base directory (eg config.yml, lang.yml).
* <p>
* Automatically updates.
*
* @param configName The name of the config
* @param removeUnused Whether keys not present in the default config should be removed on update.
* @param plugin The plugin.
* @param configName The name of the config
* @param removeUnused Whether keys not present in the default config should be removed on update.
* @param plugin The plugin.
* @param updateBlacklist Substring of keys to not add/remove keys for.
*/
protected BaseConfig(@NotNull final String configName,
final boolean removeUnused,
@NotNull final AbstractEcoPlugin plugin,
@NotNull final String... updateBlacklist) {
super(configName, plugin, "", plugin.getClass(), removeUnused, updateBlacklist);
}
/**
* Config implementation for configs present in the plugin's base directory (eg config.yml, lang.yml).
* <p>
* Automatically updates.
*
* @param configName The name of the config
* @param removeUnused Whether keys not present in the default config should be removed on update.
* @param plugin The plugin.
*/
protected BaseConfig(@NotNull final String configName,
final boolean removeUnused,
@NotNull final AbstractEcoPlugin plugin) {
super(plugin);
this.name = configName + ".yml";
this.removeUnused = removeUnused;
if (!new File(this.getPlugin().getDataFolder(), this.name).exists()) {
createFile();
}
this.configFile = new File(this.getPlugin().getDataFolder(), this.name);
this.config = YamlConfiguration.loadConfiguration(configFile);
update();
}
private void createFile() {
this.getPlugin().saveResource(name, false);
}
/**
* Update the config.
* <p>
* Writes missing values, however removes comments due to how configs are stored internally in bukkit.
*/
public void update() {
try {
config.load(configFile);
InputStream newIn = this.getPlugin().getResource(name);
if (newIn == null) {
this.getPlugin().getLog().error(name + " is null?");
return;
}
BufferedReader reader = new BufferedReader(new InputStreamReader(newIn, StandardCharsets.UTF_8));
YamlConfiguration newConfig = new YamlConfiguration();
newConfig.load(reader);
if (newConfig.getKeys(true).equals(config.getKeys(true))) {
return;
}
newConfig.getKeys(true).forEach((s -> {
if (!config.getKeys(true).contains(s)) {
config.set(s, newConfig.get(s));
}
}));
if (this.removeUnused) {
config.getKeys(true).forEach((s -> {
if (!newConfig.getKeys(true).contains(s)) {
config.set(s, null);
}
}));
}
config.save(configFile);
} catch (IOException | InvalidConfigurationException e) {
e.printStackTrace();
}
}
/**
* Get an integer from config.
*
* @param path The key to fetch the value from.
* @return The found value, or 0 if not found.
*/
@Override
public int getInt(@NotNull final String path) {
return config.getInt(path, 0);
}
/**
* Get an integer from config with a specified default (not found) value.
*
* @param path The key to fetch the value from.
* @param def The value to default to if not found.
* @return The found value, or the default.
*/
@Override
public int getInt(@NotNull final String path,
final int def) {
return config.getInt(path, def);
}
/**
* Get a list of integers 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.
*/
@Override
@NotNull
public List<Integer> getInts(@NotNull final String path) {
return config.getIntegerList(path);
}
/**
* Get a boolean from config.
*
* @param path The key to fetch the value from.
* @return The found value, or false if not found.
*/
@Override
public boolean getBool(@NotNull final String path) {
return config.getBoolean(path, false);
}
/**
* Get a list of booleans 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.
*/
@Override
@NotNull
public List<Boolean> getBools(@NotNull final String path) {
return config.getBooleanList(path);
}
/**
* Get a string from config.
*
* @param path The key to fetch the value from.
* @return The found value, or an empty string if not found.
*/
@Override
@NotNull
public String getString(@NotNull final String path) {
return StringUtils.translate(Objects.requireNonNull(config.getString(path, "")));
}
/**
* Get a list of strings 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.
*/
@Override
@NotNull
public List<String> getStrings(@NotNull final String path) {
return config.getStringList(path);
}
/**
* Get a decimal from config.
*
* @param path The key to fetch the value from.
* @return The found value, or 0 if not found.
*/
@Override
public double getDouble(@NotNull final String path) {
return config.getDouble(path, 0);
}
/**
* Get a list of decimals 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.
*/
@Override
@NotNull
public List<Double> getDoubles(@NotNull final String path) {
return config.getDoubleList(path);
super(configName, plugin, "", plugin.getClass(), removeUnused, "");
}
}

View File

@@ -0,0 +1,28 @@
package com.willfp.eco.util.config;
import com.willfp.eco.internal.config.AbstractUpdatableConfig;
import com.willfp.eco.util.plugin.AbstractEcoPlugin;
import org.jetbrains.annotations.NotNull;
public abstract class ExtendableConfig extends AbstractUpdatableConfig {
/**
* Config implementation for configs present in the plugin's base directory (eg config.yml, lang.yml).
* <p>
* Automatically updates.
*
* @param configName The name of the config
* @param removeUnused Whether keys not present in the default config should be removed on update.
* @param plugin The plugin.
* @param updateBlacklist Substring of keys to not add/remove keys for.
* @param subDirectoryPath The subdirectory path.
* @param source The class that owns the resource.
*/
protected ExtendableConfig(@NotNull final String configName,
final boolean removeUnused,
@NotNull final AbstractEcoPlugin plugin,
@NotNull final Class<?> source,
@NotNull final String subDirectoryPath,
@NotNull final String... updateBlacklist) {
super(configName, plugin, subDirectoryPath, source, removeUnused, updateBlacklist);
}
}

View File

@@ -1,163 +1,20 @@
package com.willfp.eco.util.config;
import com.willfp.eco.util.StringUtils;
import com.willfp.eco.util.internal.PluginDependent;
import com.willfp.eco.internal.config.AbstractConfig;
import com.willfp.eco.util.plugin.AbstractEcoPlugin;
import lombok.AccessLevel;
import lombok.Getter;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.util.List;
import java.util.Objects;
public abstract class StaticBaseConfig extends PluginDependent implements ValueGetter {
/**
* The linked {@link YamlConfiguration} where values are physically stored.
*/
@Getter(AccessLevel.PUBLIC)
private final YamlConfiguration config;
/**
* The physical config file, as stored on disk.
*/
@Getter(AccessLevel.PROTECTED)
private final File configFile;
/**
* The full name of the config file (eg config.yml).
*/
private final String name;
public abstract class StaticBaseConfig extends AbstractConfig {
/**
* Config implementation for configs present in the plugin's base directory (eg config.yml, lang.yml).
* <p>
* Does not automatically update.
*
* @param configName The name of the config
* @param plugin The plugin.
* @param configName The name of the config
* @param plugin The plugin.
*/
protected StaticBaseConfig(@NotNull final String configName,
@NotNull final AbstractEcoPlugin plugin) {
super(plugin);
this.name = configName + ".yml";
if (!new File(this.getPlugin().getDataFolder(), this.name).exists()) {
createFile();
}
this.configFile = new File(this.getPlugin().getDataFolder(), this.name);
this.config = YamlConfiguration.loadConfiguration(configFile);
}
private void createFile() {
this.getPlugin().saveResource(name, false);
}
/**
* Get an integer from config.
*
* @param path The key to fetch the value from.
* @return The found value, or 0 if not found.
*/
@Override
public int getInt(@NotNull final String path) {
return config.getInt(path, 0);
}
/**
* Get an integer from config with a specified default (not found) value.
*
* @param path The key to fetch the value from.
* @param def The value to default to if not found.
* @return The found value, or the default.
*/
@Override
public int getInt(@NotNull final String path,
final int def) {
return config.getInt(path, def);
}
/**
* Get a list of integers 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.
*/
@Override
@NotNull
public List<Integer> getInts(@NotNull final String path) {
return config.getIntegerList(path);
}
/**
* Get a boolean from config.
*
* @param path The key to fetch the value from.
* @return The found value, or false if not found.
*/
@Override
public boolean getBool(@NotNull final String path) {
return config.getBoolean(path, false);
}
/**
* Get a list of booleans 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.
*/
@Override
@NotNull
public List<Boolean> getBools(@NotNull final String path) {
return config.getBooleanList(path);
}
/**
* Get a string from config.
*
* @param path The key to fetch the value from.
* @return The found value, or an empty string if not found.
*/
@Override
@NotNull
public String getString(@NotNull final String path) {
return StringUtils.translate(Objects.requireNonNull(config.getString(path, "")));
}
/**
* Get a list of strings 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.
*/
@Override
@NotNull
public List<String> getStrings(@NotNull final String path) {
return config.getStringList(path);
}
/**
* Get a decimal from config.
*
* @param path The key to fetch the value from.
* @return The found value, or 0 if not found.
*/
@Override
public double getDouble(@NotNull final String path) {
return config.getDouble(path, 0);
}
/**
* Get a list of decimals 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.
*/
@Override
@NotNull
public List<Double> getDoubles(@NotNull final String path) {
return config.getDoubleList(path);
super(configName, plugin, "", plugin.getClass());
}
}

View File

@@ -1,87 +0,0 @@
package com.willfp.eco.util.config;
import org.jetbrains.annotations.NotNull;
import java.util.List;
@SuppressWarnings("unused")
public interface ValueGetter {
/**
* Get an integer from config.
*
* @param path The key to fetch the value from.
* @return The found value, or 0 if not found.
*/
int getInt(@NotNull String path);
/**
* Get an integer from config with a specified default (not found) value.
*
* @param path The key to fetch the value from.
* @param def The value to default to if not found.
* @return The found value, or the default.
*/
int getInt(@NotNull String path,
int def);
/**
* Get a list of integers 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<Integer> getInts(@NotNull String path);
/**
* Get a boolean from config.
*
* @param path The key to fetch the value from.
* @return The found value, or false if not found.
*/
boolean getBool(@NotNull String path);
/**
* Get a list of booleans 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<Boolean> getBools(@NotNull String path);
/**
* Get a string from config.
*
* @param path The key to fetch the value from.
* @return The found value, or an empty string if not found.
*/
@NotNull
String getString(@NotNull String path);
/**
* Get a list of strings 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<String> getStrings(@NotNull String path);
/**
* Get a decimal from config.
*
* @param path The key to fetch the value from.
* @return The found value, or 0 if not found.
*/
double getDouble(@NotNull String path);
/**
* Get a list of decimals 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<Double> getDoubles(@NotNull String path);
}

View File

@@ -1,6 +1,5 @@
package com.willfp.eco.util.config.configs;
import com.willfp.eco.util.StringUtils;
import com.willfp.eco.util.config.BaseConfig;
import com.willfp.eco.util.plugin.AbstractEcoPlugin;
import org.jetbrains.annotations.NotNull;
@@ -21,7 +20,7 @@ public class Lang extends BaseConfig {
* @return The prefix.
*/
public String getPrefix() {
return StringUtils.translate(this.getConfig().getString("messages.prefix"));
return this.getString("messages.prefix");
}
/**
@@ -30,7 +29,7 @@ public class Lang extends BaseConfig {
* @return The message.
*/
public String getNoPermission() {
return getPrefix() + StringUtils.translate(this.getConfig().getString("messages.no-permission"));
return getPrefix() + this.getString("messages.no-permission");
}
/**
@@ -40,6 +39,6 @@ public class Lang extends BaseConfig {
* @return The message with a prefix appended.
*/
public String getMessage(@NotNull final String message) {
return getPrefix() + StringUtils.translate(this.getConfig().getString("messages." + message));
return getPrefix() + this.getString("messages." + message);
}
}

View File

@@ -1,38 +1,36 @@
package com.willfp.eco.util.display;
import lombok.experimental.UtilityClass;
import org.apache.commons.lang.Validate;
import org.bukkit.NamespacedKey;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Predicate;
@UtilityClass
public class Display {
/**
* Registered display functions.
* The prefix for lore lines.
*/
private static final List<Map<String, Function<ItemStack, ItemStack>>> DISPLAY_FUNCTIONS = new ArrayList<>(10000);
public static final String PREFIX = "§z";
/**
* Registered revert functions.
* All registered display modules.
*/
private static final List<Function<ItemStack, ItemStack>> REVERT_FUNCTIONS = new ArrayList<>();
private static final Map<DisplayPriority, List<DisplayModule>> MODULES = new HashMap<>();
/**
* Registered finalize functions.
* NamespacedKey for finalizing.
*/
public static final List<Function<ItemStack, ItemStack>> FINALIZE_FUNCTIONS = new ArrayList<>();
/**
* Registered finalize test functions.
*/
public static final List<Predicate<ItemStack>> FINALIZE_TEST_FUNCTIONS = new ArrayList<>();
private static NamespacedKey finalizeKey = null;
/**
* Register display module.
@@ -40,48 +38,11 @@ public class Display {
* @param module The module.
*/
public void registerDisplayModule(@NotNull final DisplayModule module) {
int priority = module.getPriority();
if (priority > 9999) {
priority = 9999;
}
Function<ItemStack, ItemStack> function = module.getFunction();
List<DisplayModule> modules = MODULES.get(module.getPriority());
Map<String, Function<ItemStack, ItemStack>> functions = DISPLAY_FUNCTIONS.get(priority);
if (functions == null) {
functions = new HashMap<>();
}
modules.add(module);
functions.remove(module.getId());
functions.put(module.getId(), function);
DISPLAY_FUNCTIONS.set(priority, functions);
}
/**
* Register revert function.
*
* @param function The function.
*/
public void registerRevertModule(@NotNull final Function<ItemStack, ItemStack> function) {
REVERT_FUNCTIONS.add(function);
}
/**
* Register finalize function.
*
* @param function The function.
*/
public void registerFinalizeModule(@NotNull final Function<ItemStack, ItemStack> function) {
FINALIZE_FUNCTIONS.add(function);
}
/**
* Register finalize test function.
*
* @param function The function.
*/
public void registerFinalizeTestModule(@NotNull final Predicate<ItemStack> function) {
FINALIZE_TEST_FUNCTIONS.add(function);
MODULES.put(module.getPriority(), modules);
}
/**
@@ -91,13 +52,27 @@ public class Display {
* @return The itemstack.
*/
public ItemStack display(@NotNull final ItemStack itemStack) {
for (Map<String, Function<ItemStack, ItemStack>> displayFunctions : DISPLAY_FUNCTIONS) {
if (displayFunctions == null) {
continue;
}
if (isFinalized(itemStack)) {
unfinalize(itemStack);
return itemStack;
}
for (Function<ItemStack, ItemStack> displayFunction : displayFunctions.values()) {
displayFunction.apply(itemStack);
revert(itemStack);
if (!itemStack.hasItemMeta()) {
return itemStack;
}
ItemMeta meta = itemStack.getItemMeta();
if (meta == null) {
return itemStack;
}
for (DisplayPriority priority : DisplayPriority.values()) {
List<DisplayModule> modules = MODULES.get(priority);
for (DisplayModule module : modules) {
module.display(itemStack);
}
}
@@ -121,9 +96,40 @@ public class Display {
* @return The itemstack.
*/
public ItemStack revert(@NotNull final ItemStack itemStack) {
for (Function<ItemStack, ItemStack> displayFunction : REVERT_FUNCTIONS) {
displayFunction.apply(itemStack);
if (isFinalized(itemStack)) {
unfinalize(itemStack);
return itemStack;
}
if (!itemStack.hasItemMeta()) {
return itemStack;
}
ItemMeta meta = itemStack.getItemMeta();
if (meta == null) {
return itemStack;
}
List<String> lore = meta.getLore();
if (lore == null) {
lore = new ArrayList<>();
}
lore.removeIf(line -> line.startsWith(Display.PREFIX));
meta.setLore(lore);
itemStack.setItemMeta(meta);
for (DisplayPriority priority : DisplayPriority.values()) {
List<DisplayModule> modules = MODULES.get(priority);
for (DisplayModule module : modules) {
module.revert(itemStack);
}
}
return itemStack;
}
@@ -134,31 +140,76 @@ public class Display {
* @return The itemstack.
*/
public ItemStack finalize(@NotNull final ItemStack itemStack) {
for (Function<ItemStack, ItemStack> function : FINALIZE_FUNCTIONS) {
function.apply(itemStack);
Validate.notNull(finalizeKey, "Key cannot be null!");
if (itemStack.getType().getMaxStackSize() > 1) {
return itemStack;
}
ItemMeta meta = itemStack.getItemMeta();
if (meta == null) {
return itemStack;
}
PersistentDataContainer container = meta.getPersistentDataContainer();
container.set(finalizeKey, PersistentDataType.INTEGER, 1);
itemStack.setItemMeta(meta);
return itemStack;
}
/**
* Finalize an ItemStacks.
* Unfinalize an ItemStacks.
*
* @param itemStack The item.
* @return The itemstack.
*/
public ItemStack unfinalize(@NotNull final ItemStack itemStack) {
Validate.notNull(finalizeKey, "Key cannot be null!");
ItemMeta meta = itemStack.getItemMeta();
if (meta == null) {
return itemStack;
}
PersistentDataContainer container = meta.getPersistentDataContainer();
container.remove(finalizeKey);
itemStack.setItemMeta(meta);
return itemStack;
}
/**
* If an item is finalized.
*
* @param itemStack The item.
* @return If finalized.
*/
public boolean isFinalized(@NotNull final ItemStack itemStack) {
for (Predicate<ItemStack> function : FINALIZE_TEST_FUNCTIONS) {
if (function.test(itemStack)) {
return true;
}
Validate.notNull(finalizeKey, "Key cannot be null!");
ItemMeta meta = itemStack.getItemMeta();
if (meta == null) {
return false;
}
return false;
PersistentDataContainer container = meta.getPersistentDataContainer();
return container.has(finalizeKey, PersistentDataType.INTEGER);
}
/**
* Set key to be used for finalization.
*
* @param finalizeKey The key.
*/
@ApiStatus.Internal
public static void setFinalizeKey(@NotNull final NamespacedKey finalizeKey) {
Display.finalizeKey = finalizeKey;
}
static {
for (int i = 0; i < 10000; i++) {
DISPLAY_FUNCTIONS.add(null);
for (DisplayPriority priority : DisplayPriority.values()) {
MODULES.put(priority, new ArrayList<>());
}
}
}

View File

@@ -1,42 +1,41 @@
package com.willfp.eco.util.display;
import com.willfp.eco.util.internal.PluginDependent;
import com.willfp.eco.util.plugin.AbstractEcoPlugin;
import lombok.Getter;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.function.Function;
public class DisplayModule {
public abstract class DisplayModule extends PluginDependent {
/**
* Priority of the display module, where lower numbers are executed sooner.
* The priority of the module.
*/
@Getter
private final int priority;
private final DisplayPriority priority;
/**
* The function executed on display.
*/
@Getter
private final Function<ItemStack, ItemStack> function;
/**
* Function id for unregistration.
*/
@Getter
private final String id;
/**
* Create new display module.
* Create a new display module.
*
* @param function The function.
* @param priority The priority.
* @param id The id.
* @param plugin The plugin that the display is for.
* @param priority The priority of the module.
*/
public DisplayModule(@NotNull final Function<ItemStack, ItemStack> function,
final int priority,
@NotNull final String id) {
this.function = function;
protected DisplayModule(@NotNull final AbstractEcoPlugin plugin,
@NotNull final DisplayPriority priority) {
super(plugin);
this.priority = priority;
this.id = id;
}
/**
* Display an item.
*
* @param itemStack The item.
*/
protected abstract void display(@NotNull ItemStack itemStack);
/**
* Revert an item.
*
* @param itemStack The item.
*/
protected abstract void revert(@NotNull ItemStack itemStack);
}

View File

@@ -0,0 +1,23 @@
package com.willfp.eco.util.display;
public enum DisplayPriority {
/**
* Ran first.
*/
LOWEST,
/**
* Ran second.
*/
LOW,
/**
* Ran third.
*/
HIGH,
/**
* Ran last.
*/
HIGHEST
}

View File

@@ -1,10 +1,10 @@
package com.willfp.eco.util.drops;
import com.willfp.eco.util.drops.internal.AbstractDropQueue;
import com.willfp.eco.util.drops.internal.DropManager;
import com.willfp.eco.util.drops.internal.DropQueueType;
import com.willfp.eco.util.drops.internal.FastCollatedDropQueue;
import com.willfp.eco.util.drops.internal.InternalDropQueue;
import com.willfp.eco.internal.drops.AbstractDropQueue;
import com.willfp.eco.internal.drops.DropManager;
import com.willfp.eco.internal.drops.DropQueueType;
import com.willfp.eco.internal.drops.impl.FastCollatedDropQueue;
import com.willfp.eco.internal.drops.impl.InternalDropQueue;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;

View File

@@ -122,6 +122,6 @@ public class ArmorEquipEvent extends PlayerEvent implements Cancellable {
/**
* When you die causing all armor to unequip
*/
DEATH;
DEATH
}
}

View File

@@ -1,11 +0,0 @@
package com.willfp.eco.util.interfaces;
public interface EcoRunnable extends Runnable {
/**
* The EcoRunnable interface is generally used for repeating tasks.
* This method is to retrieve the ticks between repetitions.
*
* @return The ticks between repetitions.
*/
long getTime();
}

View File

@@ -1,8 +0,0 @@
package com.willfp.eco.util.interfaces;
public interface Registerable {
/**
* Register an object with its respective registry.
*/
void register();
}

View File

@@ -1,12 +0,0 @@
package com.willfp.eco.util.internal;
import com.willfp.eco.util.plugin.AbstractEcoPlugin;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
@ApiStatus.Internal
public abstract class PluginDependentFactory extends PluginDependent {
protected PluginDependentFactory(@NotNull final AbstractEcoPlugin plugin) {
super(plugin);
}
}

View File

@@ -1,8 +1,8 @@
package com.willfp.eco.util.optional;
import com.willfp.eco.util.ClassUtils;
import com.willfp.eco.util.proxy.ProxyConstants;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
@@ -20,7 +20,7 @@ public class Prerequisite {
* Requires the server to be running minecraft version 1.16 or higher.
*/
public static final Prerequisite MINIMUM_1_16 = new Prerequisite(
() -> !Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3].contains("15"),
() -> !ProxyConstants.NMS_VERSION.contains("15"),
"Requires minimum server version of 1.16"
);

View File

@@ -1,29 +1,28 @@
package com.willfp.eco.util.plugin;
import com.willfp.eco.util.ClassUtils;
import com.willfp.eco.util.arrows.ArrowDataListener;
import com.willfp.eco.util.bukkit.events.EcoEventManager;
import com.willfp.eco.internal.arrows.ArrowDataListener;
import com.willfp.eco.internal.bukkit.events.EcoEventManager;
import com.willfp.eco.internal.bukkit.logging.EcoLogger;
import com.willfp.eco.internal.bukkit.scheduling.EcoScheduler;
import com.willfp.eco.internal.extensions.EcoExtensionLoader;
import com.willfp.eco.util.bukkit.events.EventManager;
import com.willfp.eco.util.bukkit.keys.NamespacedKeyFactory;
import com.willfp.eco.util.bukkit.logging.EcoLogger;
import com.willfp.eco.util.bukkit.logging.Logger;
import com.willfp.eco.util.bukkit.meta.MetadataValueFactory;
import com.willfp.eco.util.bukkit.scheduling.EcoScheduler;
import com.willfp.eco.util.bukkit.scheduling.RunnableFactory;
import com.willfp.eco.util.bukkit.scheduling.Scheduler;
import com.willfp.eco.util.command.AbstractCommand;
import com.willfp.eco.util.config.configs.Config;
import com.willfp.eco.util.config.configs.Lang;
import com.willfp.eco.util.config.updating.ConfigHandler;
import com.willfp.eco.util.extensions.loader.EcoExtensionLoader;
import com.willfp.eco.util.display.Display;
import com.willfp.eco.util.display.DisplayModule;
import com.willfp.eco.util.extensions.loader.ExtensionLoader;
import com.willfp.eco.util.integrations.IntegrationLoader;
import com.willfp.eco.util.integrations.placeholder.PlaceholderManager;
import com.willfp.eco.util.integrations.placeholder.plugins.PlaceholderIntegrationPAPI;
import com.willfp.eco.util.optional.Prerequisite;
import com.willfp.eco.util.protocollib.AbstractPacketAdapter;
import com.willfp.eco.util.recipe.RecipeListener;
import com.willfp.eco.util.recipe.RecipeManager;
import com.willfp.eco.util.updater.UpdateChecker;
import lombok.Getter;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
@@ -33,6 +32,7 @@ import org.bukkit.event.Listener;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
@@ -41,7 +41,6 @@ import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@SuppressWarnings("unchecked")
public abstract class AbstractEcoPlugin extends JavaPlugin {
/**
* Loaded eco plugins.
@@ -142,12 +141,6 @@ public abstract class AbstractEcoPlugin extends JavaPlugin {
@Getter
private final RunnableFactory runnableFactory;
/**
* Recipe handler for crafting recipes.
*/
@Getter
private final RecipeManager recipeManager;
/**
* The loader for all plugin extensions.
*
@@ -162,6 +155,12 @@ public abstract class AbstractEcoPlugin extends JavaPlugin {
@Getter
private final ConfigHandler configHandler;
/**
* The display module for the plugin.
*/
@Getter
private DisplayModule displayModule;
/**
* If the server is running an outdated version of the plugin.
*/
@@ -196,7 +195,6 @@ public abstract class AbstractEcoPlugin extends JavaPlugin {
this.runnableFactory = new RunnableFactory(this);
this.extensionLoader = new EcoExtensionLoader(this);
this.configHandler = new ConfigHandler(this);
this.recipeManager = new RecipeManager(this);
this.langYml = new Lang(this);
this.configYml = new Config(this);
@@ -215,7 +213,6 @@ public abstract class AbstractEcoPlugin extends JavaPlugin {
this.getLog().info("Loading " + this.color + this.pluginName);
this.getEventManager().registerListener(new ArrowDataListener(this));
this.getEventManager().registerListener(new RecipeListener(this));
new UpdateChecker(this).getVersion(version -> {
DefaultArtifactVersion currentVersion = new DefaultArtifactVersion(this.getDescription().getVersion());
@@ -298,14 +295,18 @@ public abstract class AbstractEcoPlugin extends JavaPlugin {
* Default code to be executed after the server is up.
*/
public final void afterLoad() {
if (ClassUtils.exists("com.comphenix.protocol.events.PacketAdapter")) {
this.getPacketAdapters().forEach(abstractPacketAdapter -> {
if (abstractPacketAdapter.isPostLoad()) {
abstractPacketAdapter.register();
}
});
this.displayModule = createDisplayModule();
if (this.getDisplayModule() != null) {
Display.registerDisplayModule(this.getDisplayModule());
}
this.getPacketAdapters().forEach(abstractPacketAdapter -> {
if (abstractPacketAdapter.isPostLoad()) {
abstractPacketAdapter.register();
}
});
if (!Prerequisite.HAS_PAPER.isMet()) {
this.getLog().error("");
this.getLog().error("----------------------------");
@@ -401,4 +402,12 @@ public abstract class AbstractEcoPlugin extends JavaPlugin {
* @return A list of all updatable classes.
*/
public abstract List<Class<?>> getUpdatableClasses();
/**
* Create the display module for the plugin.
*
* @return The display module, or null.
*/
@Nullable
protected abstract DisplayModule createDisplayModule();
}

View File

@@ -1,89 +0,0 @@
package com.willfp.eco.util.recipe;
import com.willfp.eco.util.internal.PluginDependent;
import com.willfp.eco.util.plugin.AbstractEcoPlugin;
import org.bukkit.Material;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.CraftItemEvent;
import org.bukkit.event.inventory.PrepareItemCraftEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.ShapedRecipe;
import org.jetbrains.annotations.NotNull;
public class RecipeListener extends PluginDependent implements Listener {
/**
* Pass an {@link AbstractEcoPlugin} in order to interface with it.
*
* @param plugin The plugin to manage.
*/
public RecipeListener(@NotNull final AbstractEcoPlugin plugin) {
super(plugin);
}
/**
* Called on item craft.
*
* @param event The event to listen for.
*/
@EventHandler
public void prepareCraftListener(@NotNull final PrepareItemCraftEvent event) {
if (!(event.getRecipe() instanceof ShapedRecipe)) {
return;
}
ShapedRecipe recipe = (ShapedRecipe) event.getRecipe();
if (!recipe.getKey().getNamespace().equals(this.getPlugin().getPluginName().toLowerCase())) {
return;
}
ItemStack[] matrix = event.getInventory().getMatrix();
EcoShapedRecipe matched = this.getPlugin().getRecipeManager().getMatch(matrix);
if (matched == null) {
event.getInventory().setResult(new ItemStack(Material.AIR));
return;
}
if (matched.test(matrix)) {
event.getInventory().setResult(matched.getOutput());
} else {
event.getInventory().setResult(new ItemStack(Material.AIR));
}
}
/**
* Called on item craft.
*
* @param event The event to listen for.
*/
@EventHandler
public void craftListener(@NotNull final CraftItemEvent event) {
if (!(event.getRecipe() instanceof ShapedRecipe)) {
return;
}
ShapedRecipe recipe = (ShapedRecipe) event.getRecipe();
if (!recipe.getKey().getNamespace().equals(this.getPlugin().getPluginName().toLowerCase())) {
return;
}
ItemStack[] matrix = event.getInventory().getMatrix();
EcoShapedRecipe matched = this.getPlugin().getRecipeManager().getMatch(matrix);
if (matched == null) {
event.getInventory().setResult(new ItemStack(Material.AIR));
event.setCancelled(true);
return;
}
if (matched.test(matrix)) {
event.getInventory().setResult(matched.getOutput());
} else {
event.getInventory().setResult(new ItemStack(Material.AIR));
event.setCancelled(true);
}
}
}

View File

@@ -0,0 +1,63 @@
package com.willfp.eco.util.recipe;
import com.willfp.eco.util.recipe.parts.EmptyRecipePart;
import com.willfp.eco.util.recipe.parts.RecipePart;
import com.willfp.eco.util.recipe.parts.SimpleRecipePart;
import lombok.experimental.UtilityClass;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
@UtilityClass
@SuppressWarnings("deprecation")
public final class RecipeParts {
/**
* All recipe parts.
*/
private static final Map<NamespacedKey, RecipePart> PARTS = new HashMap<>();
/**
* Register a new recipe part.
*
* @param key The key of the recipe part.
* @param part The recipe part.
*/
public void registerRecipePart(@NotNull final NamespacedKey key,
@NotNull final RecipePart part) {
PARTS.put(key, part);
}
/**
* Lookup recipe part from string.
*
* @param key The string to test.
* @return The found recipe part, or null if not found.
*/
public RecipePart lookup(@NotNull final String key) {
String[] split = key.toLowerCase().split(":");
if (split.length == 1) {
Material material = Material.getMaterial(key.toUpperCase());
if (material == null || material == Material.AIR) {
return new EmptyRecipePart();
}
return new SimpleRecipePart(material);
}
RecipePart part = PARTS.get(new NamespacedKey(split[0], split[1]));
return part == null ? new EmptyRecipePart() : part;
}
/**
* Get if itemStack is a recipe part (used to check for custom items).
*
* @param itemStack The itemStack to check.
* @return If is recipe.
*/
public boolean isRecipePart(@NotNull final ItemStack itemStack) {
return PARTS.values().stream().anyMatch(recipePart -> recipePart.matches(itemStack));
}
}

View File

@@ -2,8 +2,8 @@ package com.willfp.eco.util.recipe;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.willfp.eco.util.internal.PluginDependent;
import com.willfp.eco.util.plugin.AbstractEcoPlugin;
import com.willfp.eco.util.recipe.recipes.EcoShapedRecipe;
import lombok.experimental.UtilityClass;
import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey;
import org.bukkit.inventory.ItemStack;
@@ -12,40 +12,34 @@ import org.bukkit.inventory.ShapedRecipe;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@UtilityClass
@SuppressWarnings("deprecation")
public class RecipeManager extends PluginDependent {
public class Recipes {
/**
* Registry of all recipes.
*/
private final BiMap<String, EcoShapedRecipe> registry = HashBiMap.create();
private static final BiMap<NamespacedKey, EcoShapedRecipe> RECIPES = HashBiMap.create();
/**
* Pass an {@link AbstractEcoPlugin} in order to interface with it.
* Register a recipe.
*
* @param plugin The plugin to manage.
* @param recipe The recipe.
*/
public RecipeManager(@NotNull final AbstractEcoPlugin plugin) {
super(plugin);
}
public void register(@NotNull final EcoShapedRecipe recipe) {
RECIPES.forcePut(recipe.getKey(), recipe);
void register(@NotNull final EcoShapedRecipe recipe) {
String key = recipe.getKey();
registry.forcePut(key, recipe);
Bukkit.getServer().removeRecipe(recipe.getKey());
Bukkit.getServer().removeRecipe(recipe.getDisplayedKey());
NamespacedKey baseKey = this.getPlugin().getNamespacedKeyFactory().create(key);
Bukkit.getServer().removeRecipe(baseKey);
NamespacedKey displayedKey = this.getPlugin().getNamespacedKeyFactory().create(key + "_displayed");
Bukkit.getServer().removeRecipe(displayedKey);
ShapedRecipe shapedRecipe = new ShapedRecipe(baseKey, recipe.getOutput());
ShapedRecipe shapedRecipe = new ShapedRecipe(recipe.getKey(), recipe.getOutput());
shapedRecipe.shape("012", "345", "678");
for (int i = 0; i < 9; i++) {
char character = String.valueOf(i).toCharArray()[0];
shapedRecipe.setIngredient(character, recipe.getMaterialAtIndex(i));
}
ShapedRecipe displayedRecipe = new ShapedRecipe(displayedKey, recipe.getOutput());
ShapedRecipe displayedRecipe = new ShapedRecipe(recipe.getDisplayedKey(), recipe.getOutput());
displayedRecipe.shape("012", "345", "678");
for (int i = 0; i < 9; i++) {
char character = String.valueOf(i).toCharArray()[0];
@@ -64,7 +58,7 @@ public class RecipeManager extends PluginDependent {
*/
@Nullable
public EcoShapedRecipe getMatch(@NotNull final ItemStack[] matrix) {
return registry.values().stream().filter(recipe -> recipe.test(matrix)).findFirst().orElse(null);
return RECIPES.values().stream().filter(recipe -> recipe.test(matrix)).findFirst().orElse(null);
}
/**
@@ -74,7 +68,18 @@ public class RecipeManager extends PluginDependent {
* @return The shaped recipe, or null if not found.
*/
@Nullable
public EcoShapedRecipe getShapedRecipe(@NotNull final String key) {
return registry.get(key);
public EcoShapedRecipe getShapedRecipe(@NotNull final NamespacedKey key) {
EcoShapedRecipe recipe = RECIPES.get(key);
if (recipe != null) {
return recipe;
}
if (key.getKey().contains("_displayed")) {
NamespacedKey otherKey = new NamespacedKey(key.getNamespace(), key.getKey().replace("_displayed", ""));
return RECIPES.get(otherKey);
}
return null;
}
}

View File

@@ -1,51 +0,0 @@
package com.willfp.eco.util.recipe.lookup;
import com.willfp.eco.util.recipe.parts.EmptyRecipePart;
import com.willfp.eco.util.recipe.parts.RecipePart;
import com.willfp.eco.util.recipe.parts.SimpleRecipePart;
import lombok.experimental.UtilityClass;
import org.bukkit.Material;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
@UtilityClass
public final class RecipePartUtils {
/**
* Set of tests that return if the player is telekinetic.
*/
private static final Map<String, Function<String, RecipePart>> TESTS = new HashMap<>();
/**
* Register a new lookup.
*
* @param key The key of the lookup.
* @param lookupFunction The lookup to register, where the output is the recipe part generated.
*/
public void registerLookup(@NotNull final String key,
@NotNull final Function<String, RecipePart> lookupFunction) {
TESTS.put(key, lookupFunction);
}
/**
* Lookup recipe part from string.
*
* @param key The string to test.
* @return The generated recipe part, or null if invalid.
*/
public RecipePart lookup(@NotNull final String key) {
Function<String, RecipePart> lookup = TESTS.get(key);
if (lookup == null) {
Material material = Material.getMaterial(key.toUpperCase());
if (material == null || material == Material.AIR) {
return new EmptyRecipePart();
}
return new SimpleRecipePart(material);
}
return lookup.apply(key);
}
}

View File

@@ -1,28 +1,36 @@
package com.willfp.eco.util.recipe;
package com.willfp.eco.util.recipe.recipes;
import com.willfp.eco.util.interfaces.Registerable;
import com.willfp.eco.util.internal.PluginDependent;
import com.willfp.eco.util.plugin.AbstractEcoPlugin;
import com.willfp.eco.util.recipe.Recipes;
import com.willfp.eco.util.recipe.parts.EmptyRecipePart;
import com.willfp.eco.util.recipe.parts.RecipePart;
import lombok.Getter;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
public final class EcoShapedRecipe extends PluginDependent implements Registerable {
public final class EcoShapedRecipe extends PluginDependent {
/**
* Recipe parts.
*/
@Getter
private final RecipePart[] parts;
/**
* The key of the recipe.
*/
@Getter
private final String key;
private final NamespacedKey key;
/**
* The key of the displayed recipe.
*/
@Getter
private final NamespacedKey displayedKey;
/**
* The recipe's output.
@@ -37,7 +45,8 @@ public final class EcoShapedRecipe extends PluginDependent implements Registerab
super(plugin);
this.parts = parts;
this.key = key;
this.key = plugin.getNamespacedKeyFactory().create(key);
this.displayedKey = plugin.getNamespacedKeyFactory().create(key + "_displayed");
this.output = output;
}
@@ -81,9 +90,8 @@ public final class EcoShapedRecipe extends PluginDependent implements Registerab
/**
* Register the recipe.
*/
@Override
public void register() {
this.getPlugin().getRecipeManager().register(this);
Recipes.register(this);
}
@Override
@@ -192,66 +200,4 @@ public final class EcoShapedRecipe extends PluginDependent implements Registerab
return new EcoShapedRecipe(plugin, key.toLowerCase(), recipeParts, output);
}
}
public enum RecipePosition {
/**
* Top left of matrix.
*/
TOP_LEFT(0),
/**
* Top middle of matrix.
*/
TOP_MIDDLE(1),
/**
* Top right of matrix.
*/
TOP_RIGHT(2),
/**
* Middle left of matrix.
*/
MIDDLE_LEFT(3),
/**
* Middle of matrix.
*/
MIDDLE(4),
/**
* Middle right of matrix.
*/
MIDDLE_RIGHT(5),
/**
* Bottom left of matrix.
*/
BOTTOM_LEFT(6),
/**
* Bottom middle of matrix.
*/
BOTTOM_MIDDLE(7),
/**
* Bottom right of matrix.
*/
BOTTOM_RIGHT(8);
/**
* The index within a crafting table matrix.
*/
@Getter
private final int index;
/**
* Recipe position with crafting table index.
*
* @param index The index.
*/
RecipePosition(final int index) {
this.index = index;
}
}
}

View File

@@ -0,0 +1,65 @@
package com.willfp.eco.util.recipe.recipes;
import lombok.Getter;
public enum RecipePosition {
/**
* Top left of matrix.
*/
TOP_LEFT(0),
/**
* Top middle of matrix.
*/
TOP_MIDDLE(1),
/**
* Top right of matrix.
*/
TOP_RIGHT(2),
/**
* Middle left of matrix.
*/
MIDDLE_LEFT(3),
/**
* Middle of matrix.
*/
MIDDLE(4),
/**
* Middle right of matrix.
*/
MIDDLE_RIGHT(5),
/**
* Bottom left of matrix.
*/
BOTTOM_LEFT(6),
/**
* Bottom middle of matrix.
*/
BOTTOM_MIDDLE(7),
/**
* Bottom right of matrix.
*/
BOTTOM_RIGHT(8);
/**
* The index within a crafting table matrix.
*/
@Getter
private final int index;
/**
* Recipe position with crafting table index.
*
* @param index The index.
*/
RecipePosition(final int index) {
this.index = index;
}
}

View File

@@ -1,14 +1,12 @@
package com.willfp.eco.util.tuplets;
package com.willfp.eco.util.tuples;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.jetbrains.annotations.Nullable;
@ToString
public class Pair<A, B> {
/**
* The first value in the pair.
* The first item in the tuple.
*/
@Getter
@Setter
@@ -16,7 +14,7 @@ public class Pair<A, B> {
private A first;
/**
* The second value in the pair.
* The second item in the tuple.
*/
@Getter
@Setter

View File

@@ -0,0 +1,30 @@
package com.willfp.eco.util.tuples;
import lombok.Getter;
import lombok.Setter;
import org.jetbrains.annotations.Nullable;
public class Triplet<A, B, C> extends Pair<A, B> {
/**
* The third item in the tuple.
*/
@Getter
@Setter
@Nullable
private C third;
/**
* Create a triple of values.
*
* @param first The first item in the pair.
* @param second The second item in the pair.
* @param third The third item in the pair.
*/
public Triplet(@Nullable final A first,
@Nullable final B second,
@Nullable final C third) {
super(first, second);
this.third = third;
}
}

View File

@@ -1,48 +0,0 @@
package com.willfp.eco.util.tuplets;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.jetbrains.annotations.Nullable;
@ToString
public class Triplet<A, B, C> {
/**
* The first item in the triplet.
*/
@Getter
@Setter
@Nullable
private A first;
/**
* The second item in the triplet.
*/
@Getter
@Setter
@Nullable
private B second;
/**
* The third item in the triplet.
*/
@Getter
@Setter
@Nullable
private C third;
/**
* Create a triplet.
*
* @param first The first item in the triplet.
* @param second The second item in the triplet.
* @param third The third item in the triplet.
*/
public Triplet(@Nullable final A first,
@Nullable final B second,
@Nullable final C third) {
this.first = first;
this.second = second;
this.third = third;
}
}

View File

@@ -1,2 +1,2 @@
version = 3.3.2
version = 4.0.0
plugin-name = eco