diff --git a/.github/workflows/java.yml b/.github/workflows/java.yml
index b5ec63d..3ea9a48 100644
--- a/.github/workflows/java.yml
+++ b/.github/workflows/java.yml
@@ -22,10 +22,10 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v2
- - name: Set up JDK 1.8
+ - name: Set up JDK 16
uses: actions/setup-java@v2
with:
- java-version: 8
+ java-version: 16
distribution: adopt
- name: Build with Maven
run: mvn package --file pom.xml
diff --git a/.gitignore b/.gitignore
index cf6c107..c1e3877 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,4 @@
*.sh
dependency-reduced-pom.xml
/dependency-reduced-pom.xml
+*.DS_Store
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 984af2f..2570be0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -108,7 +108,7 @@
com.github.thebusybiscuit
Slimefun4
- 2c4f886fe4
+ RC-35
provided
diff --git a/src/main/java/dev/j3fftw/headlimiter/HeadLimiter.java b/src/main/java/dev/j3fftw/headlimiter/HeadLimiter.java
index 50cf15d..3d7600e 100644
--- a/src/main/java/dev/j3fftw/headlimiter/HeadLimiter.java
+++ b/src/main/java/dev/j3fftw/headlimiter/HeadLimiter.java
@@ -1,10 +1,11 @@
package dev.j3fftw.headlimiter;
-import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
-import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
-import io.github.thebusybiscuit.slimefun4.libraries.dough.updater.GitHubBuildsUpdater;
+import java.io.File;
+
+import dev.j3fftw.headlimiter.blocklimiter.Group;
import org.bukkit.Material;
import org.bukkit.block.Block;
+import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
@@ -12,17 +13,24 @@
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.plugin.java.JavaPlugin;
-import java.io.File;
+import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
+import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
+import io.github.thebusybiscuit.slimefun4.libraries.dough.updater.GitHubBuildsUpdater;
+
+import dev.j3fftw.headlimiter.blocklimiter.BlockLimiter;
public final class HeadLimiter extends JavaPlugin implements Listener {
private static HeadLimiter instance;
+ private BlockLimiter blockLimiter;
+
@Override
public void onEnable() {
instance = this;
- if (!new File(getDataFolder(), "config.yml").exists())
+ if (!new File(getDataFolder(), "config.yml").exists()) {
saveDefaultConfig();
+ }
Utils.loadPermissions();
@@ -35,6 +43,9 @@ public void onEnable() {
if (getConfig().getBoolean("auto-update", true) && getDescription().getVersion().startsWith("DEV - ")) {
new GitHubBuildsUpdater(this, getFile(), "J3fftw1/HeadLimiter/master").start();
}
+
+ this.blockLimiter = new BlockLimiter(this);
+ loadConfig();
}
@Override
@@ -64,13 +75,29 @@ public void onPlace(BlockPlaceEvent e) {
&& isCargo(sfItem)
) {
final int maxAmount = Utils.getMaxHeads(player);
- Utils.count(block.getChunk(),
- result -> Utils.onCheck(player, block, maxAmount, result.getTotal(), sfItem));
+ Utils.count(
+ block.getChunk(),
+ result -> Utils.onCheck(player, block, maxAmount, result.getTotal(), sfItem)
+ );
}
}
}
+ public BlockLimiter getBlockLimiter() {
+ return blockLimiter;
+ }
+
public static HeadLimiter getInstance() {
return instance;
}
+
+ public void loadConfig() {
+ ConfigurationSection configurationSection = instance.getConfig().getConfigurationSection("block-limits");
+ if (configurationSection == null) {
+ throw new IllegalStateException("No configuration for groups is available.");
+ }
+ for (String key : configurationSection.getKeys(false)) {
+ BlockLimiter.getInstance().getGroups().add(new Group(configurationSection.getConfigurationSection(key)));
+ }
+ }
}
diff --git a/src/main/java/dev/j3fftw/headlimiter/blocklimiter/BlockLimiter.java b/src/main/java/dev/j3fftw/headlimiter/blocklimiter/BlockLimiter.java
new file mode 100644
index 0000000..09b5c96
--- /dev/null
+++ b/src/main/java/dev/j3fftw/headlimiter/blocklimiter/BlockLimiter.java
@@ -0,0 +1,107 @@
+package dev.j3fftw.headlimiter.blocklimiter;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.World;
+import org.bukkit.entity.Player;
+
+import com.google.common.base.Preconditions;
+
+import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
+import io.github.thebusybiscuit.slimefun4.libraries.dough.blocks.ChunkPosition;
+
+import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
+import me.mrCookieSlime.Slimefun.api.BlockStorage;
+
+import dev.j3fftw.headlimiter.HeadLimiter;
+
+public final class BlockLimiter {
+
+ private static BlockLimiter instance;
+ private final HashSet groups = new HashSet<>();
+ private final Map contentMap = new HashMap<>();
+
+ public BlockLimiter(@Nonnull HeadLimiter headLimiter) {
+ Preconditions.checkArgument(instance == null, "Cannot create a new instance of the BlockLimiter");
+ instance = this;
+ new BlockListener(headLimiter);
+ headLimiter.getServer().getScheduler().runTaskLater(headLimiter, this::loadBlockStorage, 1);
+ }
+
+ private void loadBlockStorage() {
+ for (World world : Bukkit.getWorlds()) {
+ BlockStorage worldStorage = BlockStorage.getStorage(world);
+ if (worldStorage == null) {
+ return;
+ } else {
+ for (Map.Entry entry : worldStorage.getRawStorage().entrySet()) {
+ Location location = entry.getKey();
+ String id = entry.getValue().getString("id");
+ ChunkPosition chunkPosition = new ChunkPosition(location.getChunk());
+ ChunkContent content = contentMap.get(chunkPosition);
+ if (content == null) {
+ content = new ChunkContent();
+ content.incrementAmount(id);
+ contentMap.put(chunkPosition, content);
+ } else {
+ content.incrementAmount(id);
+ }
+ }
+ }
+
+ }
+ }
+
+ @Nullable
+ public ChunkContent getChunkContent(@Nonnull ChunkPosition chunkPosition) {
+ return contentMap.get(chunkPosition);
+ }
+
+ public Group getGroupByItem(@Nonnull SlimefunItem slimefunItem) {
+ return getGroupByItem(slimefunItem.getId());
+ }
+
+ @Nullable
+ public Group getGroupByItem(@Nonnull String itemId) {
+ for (Group group : this.groups) {
+ if (group.contains(itemId)) {
+ return group;
+ }
+ }
+ return null;
+ }
+
+ public int getPlayerLimitByItem(@Nonnull Player player, @Nonnull SlimefunItem slimefunItem) {
+ return getPlayerLimitByItem(player, slimefunItem.getId());
+ }
+
+ public int getPlayerLimitByItem(@Nonnull Player player, @Nonnull String itemId) {
+ Group group = getGroupByItem(itemId);
+ if (group == null) {
+ return -1;
+ } else {
+ return group.getPermissibleAmount(player);
+ }
+ }
+
+ public Set getGroups() {
+ return groups;
+ }
+
+ public void setChunkContent(@Nonnull ChunkPosition chunkPosition, @Nonnull ChunkContent content) {
+ contentMap.put(chunkPosition, content);
+ }
+
+ @Nonnull
+ public static BlockLimiter getInstance() {
+ return instance;
+ }
+}
diff --git a/src/main/java/dev/j3fftw/headlimiter/blocklimiter/BlockListener.java b/src/main/java/dev/j3fftw/headlimiter/blocklimiter/BlockListener.java
new file mode 100644
index 0000000..698220f
--- /dev/null
+++ b/src/main/java/dev/j3fftw/headlimiter/blocklimiter/BlockListener.java
@@ -0,0 +1,74 @@
+package dev.j3fftw.headlimiter.blocklimiter;
+
+import javax.annotation.Nonnull;
+
+import org.bukkit.ChatColor;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+
+import io.github.thebusybiscuit.slimefun4.api.events.SlimefunBlockBreakEvent;
+import io.github.thebusybiscuit.slimefun4.api.events.SlimefunBlockPlaceEvent;
+import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
+import io.github.thebusybiscuit.slimefun4.libraries.dough.blocks.ChunkPosition;
+
+import dev.j3fftw.headlimiter.HeadLimiter;
+
+public class BlockListener implements Listener {
+
+ public BlockListener(@Nonnull HeadLimiter headLimiter) {
+ headLimiter.getServer().getPluginManager().registerEvents(this, headLimiter);
+ }
+
+ @EventHandler
+ public void onSlimefunItemPlaced(@Nonnull SlimefunBlockPlaceEvent event) {
+ SlimefunItem slimefunItem = event.getSlimefunItem();
+ String slimefunItemId = slimefunItem.getId();
+ int definedLimit = BlockLimiter.getInstance().getPlayerLimitByItem(event.getPlayer(), slimefunItem);
+
+ if (definedLimit == -1) {
+ // No limit has been set, nothing required for HeadLimiter
+ return;
+ }
+
+ ChunkPosition chunkPosition = new ChunkPosition(event.getBlockPlaced().getChunk());
+ ChunkContent content = BlockLimiter.getInstance().getChunkContent(chunkPosition);
+
+ if (content == null) {
+ // Content is null so no blocks are currently in this chunk, lets set one up - event can continue
+ content = new ChunkContent();
+ content.incrementAmount(slimefunItemId);
+ BlockLimiter.getInstance().setChunkContent(chunkPosition, content);
+ } else if (content.getGroupTotal(slimefunItemId) < definedLimit) {
+ // This chunk can take more of the specified item type
+ content.incrementAmount(slimefunItemId);
+ } else {
+ // Chunk has hit its limit for this type, time to deny the placement
+ event.setCancelled(true);
+ event.getPlayer().sendMessage(ChatColor.RED + "You cannot place any more of this item within this chunk.");
+ }
+ }
+
+ @EventHandler
+ public void onSlimefunItemBroken(@Nonnull SlimefunBlockBreakEvent event) {
+ SlimefunItem slimefunItem = event.getSlimefunItem();
+ String slimefunItemId = slimefunItem.getId();
+ int definedLimit = BlockLimiter.getInstance().getPlayerLimitByItem(event.getPlayer(), slimefunItem);
+ if (definedLimit == -1) {
+ // No limit has been set, nothing required for HeadLimiter
+ return;
+ }
+
+ ChunkPosition chunkPosition = new ChunkPosition(event.getBlockBroken().getChunk());
+ ChunkContent content = BlockLimiter.getInstance().getChunkContent(chunkPosition);
+
+ if (content == null) {
+ // Content is null so no blocks are currently in this chunk, shouldn't be possible, but never mind
+ return;
+ }
+
+ // This chunk can take more of the specified item type
+ content.decrementAmount(slimefunItemId);
+
+ }
+
+}
diff --git a/src/main/java/dev/j3fftw/headlimiter/blocklimiter/ChunkContent.java b/src/main/java/dev/j3fftw/headlimiter/blocklimiter/ChunkContent.java
new file mode 100644
index 0000000..30adb45
--- /dev/null
+++ b/src/main/java/dev/j3fftw/headlimiter/blocklimiter/ChunkContent.java
@@ -0,0 +1,68 @@
+package dev.j3fftw.headlimiter.blocklimiter;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.Nonnull;
+
+import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
+
+public class ChunkContent {
+
+ private final Map contentMap = new HashMap<>();
+
+ public int getCurrentAmount(@Nonnull SlimefunItem slimefunItem) {
+ return getCurrentAmount(slimefunItem.getId());
+ }
+
+ public int getCurrentAmount(@Nonnull String itemId) {
+ return this.contentMap.getOrDefault(itemId, 0);
+ }
+
+ public int getGroupTotal(@Nonnull SlimefunItem slimefunItem) {
+ return getGroupTotal(slimefunItem.getId());
+ }
+
+ public int getGroupTotal(@Nonnull String itemId) {
+ Set groupSet = BlockLimiter.getInstance().getGroups();
+
+ for (Group group : groupSet) {
+ if (group.contains(itemId)) {
+ int amount = 0;
+ for (String item : group.getItems()) {
+ amount += this.contentMap.get(item);
+ }
+ return amount;
+ }
+ }
+
+ return -1;
+ }
+
+ public void incrementAmount(@Nonnull SlimefunItem slimefunItem) {
+ incrementAmount(slimefunItem.getId());
+ }
+
+ public void incrementAmount(@Nonnull String itemId) {
+ int amount = getCurrentAmount(itemId);
+ setAmount(itemId, amount + 1);
+ }
+
+ public void decrementAmount(@Nonnull SlimefunItem slimefunItem) {
+ incrementAmount(slimefunItem.getId());
+ }
+
+ public void decrementAmount(@Nonnull String itemId) {
+ int amount = getCurrentAmount(itemId);
+ setAmount(itemId, Math.max(0, amount - 1));
+ }
+
+ public void setAmount(@Nonnull SlimefunItem slimefunItem, int amount) {
+ setAmount(slimefunItem.getId(), amount);
+ }
+
+ public void setAmount(@Nonnull String itemId, int amount) {
+ contentMap.put(itemId, amount);
+ }
+}
diff --git a/src/main/java/dev/j3fftw/headlimiter/blocklimiter/Group.java b/src/main/java/dev/j3fftw/headlimiter/blocklimiter/Group.java
new file mode 100644
index 0000000..fb12500
--- /dev/null
+++ b/src/main/java/dev/j3fftw/headlimiter/blocklimiter/Group.java
@@ -0,0 +1,98 @@
+package dev.j3fftw.headlimiter.blocklimiter;
+
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.entity.Player;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.Nonnull;
+
+import com.google.common.base.Objects;
+
+import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
+
+public class Group {
+
+ private final String groupName;
+ private final int defaultAmount;
+ private final HashSet items;
+ private final HashMap permissionAmounts;
+
+ public Group(ConfigurationSection configurationSection) {
+ this.groupName = configurationSection.getName();
+ this.defaultAmount = configurationSection.getInt("items-amount", 0);
+ this.items = new HashSet<>(configurationSection.getStringList("items"));
+ this.permissionAmounts = new HashMap<>();
+
+ ConfigurationSection permissionSection = configurationSection.getConfigurationSection("permission-amount");
+
+ if (permissionSection != null) {
+ for (String key : permissionSection.getKeys(false)) {
+ permissionAmounts.put(key, permissionSection.getInt(key, 0));
+ }
+ }
+ }
+
+ public String getGroupName() {
+ return groupName;
+ }
+
+ public int getDefaultAmount() {
+ return defaultAmount;
+ }
+
+ public Set getItems() {
+ return items;
+ }
+
+ public Map getPermissionAmounts() {
+ return permissionAmounts;
+ }
+
+ public boolean contains(@Nonnull SlimefunItem slimefunItem) {
+ return contains(slimefunItem.getId());
+ }
+
+ public boolean contains(@Nonnull String itemId) {
+ return this.items.contains(itemId);
+ }
+
+ public int getPermissibleAmount(@Nonnull Player player) {
+ int allowable = defaultAmount;
+ if (!this.permissionAmounts.isEmpty()) {
+ for (Map.Entry entry : this.permissionAmounts.entrySet()) {
+ String permission = entry.getKey();
+ if (player.hasPermission(permission)) {
+ allowable = Math.max(entry.getValue(), allowable);
+ }
+ }
+ }
+ return allowable;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Group group = (Group) o;
+ return defaultAmount == group.defaultAmount && Objects.equal(
+ groupName,
+ group.groupName
+ ) && Objects.equal(items, group.items) && Objects.equal(
+ permissionAmounts,
+ group.permissionAmounts
+ );
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(groupName, defaultAmount, items, permissionAmounts);
+ }
+}
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
index 157fe55..475946a 100644
--- a/src/main/resources/config.yml
+++ b/src/main/resources/config.yml
@@ -1,28 +1,36 @@
-## Amount of Cargo machines per chunk (25 by default)
-amount: 25
-
-## Auto updater (true by default)
-auto-update: true
-
-## Size of the thread pool (4 by default)
-## Only touch this setting when you know what you are doing!
-thread-pool-size: 4
-
-## If a claiming plugin is enabled, this setting prevents players from placing cargo outside of claimed areas
-## This makes it impossible to "extend" existing networks from just outside the border in order to steal from claims
-block-wilderness-cargo: false
-
-## Permissions (false by default)
-## Permission node: headlimiter.permission.
-## Example: headlimiter.permission.noob
+## Block Limits
+## You can limit all Slimefun Blocks including all addons.
+## You will have to make a group per item or item set.
##
-## When permissions have been set to true, you can use the values here to set the amount of heads checked.
-## You can add as many entries as you want.
-## Order has to be reversed or breaky breaky
-permissions: false
-permission:
- ## sefi: 25
- ## walshy: 20
- ## alessio: 15
- ## jeff: 10
- noob: 5
\ No newline at end of file
+## Down here you have an example for Cargo.
+## cargo: is the group name
+## items-amount: is the default amount the group is limited to
+## items: will have a list of items you want to block. These are all Slimefun Items IDs (Addons included)
+## permission-amount: this will have a list of permissions. This is completely optional and doesn't have to be there,
+## If you do not want permissions you can just remove it or not add it to the group.
+## cargo:
+## items-amount: 25
+## items:
+## - CARGO_NODE_INPUT
+## - CARGO_NODE_OUTPUT
+## - CARGO_NODE_OUTPUT_ADVANCED
+## - CARGO_NODE
+## - CARGO_MANAGER
+## permission-amount:
+## example_1: 50
+## example_2: 100
+## example_3: 150
+
+block-limits:
+ cargo:
+ items-amount: 25
+ items:
+ - CARGO_NODE_INPUT
+ - CARGO_NODE_OUTPUT
+ - CARGO_NODE_OUTPUT_ADVANCED
+ - CARGO_NODE
+ - CARGO_MANAGER
+ permission-amount:
+ example_1: 50
+ example_2: 100
+ example_3: 150
\ No newline at end of file