diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..f7c773b
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,26 @@
+root = true
+
+
+[*]
+charset = utf-8
+end_of_line = lf
+indent_size = 4
+indent_style = space
+insert_final_newline = true
+# max_line_length = 120
+tab_width = 4
+trim_trailing_whitespace = true
+ij_continuation_indent_size = 8
+ij_formatter_off_tag = @formatter:off
+ij_formatter_on_tag = @formatter:on
+ij_formatter_tags_enabled = true
+
+
+[{*.yaml,*.yml,*.json,*.graphqlconfig,*.har,*.jsb2,*.jsb3,*.webmanifest,.babelrc,.eslintrc,.prettierrc,.stylelintrc,bowerrc,jest.config}]
+indent_size = 2
+tab_width = 2
+
+
+[{*.markdown,*.md,*.html,*.htm,*.ng,*.sht,*.shtm,*.shtml,*.ts,*.ats,*.js,*.cjs,*.bash,*.sh,*.zsh}]
+indent_size = 2
+tab_width = 2
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 0000000..1ef9dcf
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1 @@
+custom: [ 'https://craftaro.to/+' ]
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..fec9b26
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,16 @@
+# Please see the documentation for all configuration options:
+# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
+
+version: 2
+updates:
+ - package-ecosystem: maven
+ directory: /
+ target-branch: development
+ schedule:
+ interval: monthly
+
+ - package-ecosystem: github-actions
+ directory: /
+ target-branch: development
+ schedule:
+ interval: monthly
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000..24fc045
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,95 @@
+name: Build
+
+on:
+ push:
+ branches: [ master, development ]
+ tags:
+ - 'v*'
+ pull_request:
+ types: [ opened, synchronize, reopened ]
+
+permissions: read-all
+
+env:
+ DEPLOYMENT_POM_PATH: ./EpicHoppers-API/pom.xml
+ DEPLOYMENT_ARTIFACT_DIR: ./EpicHoppers-API/target
+ DEPLOYMENT_ARTIFACT_SELECTOR: EpicHoppers-API-*.jar
+ PLUGIN_ARTIFACT_DIR: ./EpicHoppers-Plugin/target
+ PLUGIN_ARTIFACT_SELECTOR: EpicHoppers-*.jar
+
+jobs:
+ Build:
+ name: Build + Deploy
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+ - name: Prepare Workspace
+ uses: craftaro/GH-Commons/.github/actions/setup_workspace@master
+ with:
+ maven_username: ${{ secrets.PLUGINS_MAVEN_REPO_USERNAME }}
+ maven_password: ${{ secrets.PLUGINS_MAVEN_REPO_PASSWORD }}
+
+ - name: Set project version
+ uses: craftaro/GH-Commons/.github/actions/maven_set_project_version@master
+ with:
+ append_snapshot: ${{ github.ref_type == 'tag' && 'false' || 'true' }}
+ version: ${{ github.ref_type == 'tag' && github.ref_name || '' }}
+ increment_version: ${{ github.ref_type != 'tag' && 'patch' || '' }}
+ increment_version_only_if_not_snapshot_version: ${{ github.ref == 'refs/heads/development' && 'true' || 'false' }}
+
+ - name: Build with Maven
+ run: mvn -B -Duser.name="GitHub Actions on $GITHUB_REPOSITORY (id=$GITHUB_RUN_ID)" clean package
+
+ - name: Sign jar archives
+ uses: craftaro/GH-Commons/.github/actions/sign_jars@master
+ with:
+ jar_file_selector: ${{ env.DEPLOYMENT_ARTIFACT_DIR }}/${{ env.DEPLOYMENT_ARTIFACT_SELECTOR }}
+ keystore_gpg_encrypted: ${{ secrets.PLUGINS_JARSIGNER_KEYSTORE_GPG }}
+ keystore_gpg_password: ${{ secrets.PLUGINS_JARSIGNER_KEYSTORE_GPG_PASSWORD }}
+ keystore_password: ${{ secrets.PLUGINS_JARSIGNER_KEYSTORE_PASSWORD }}
+
+ - name: Upload Build Artifacts [API]
+ uses: actions/upload-artifact@v4
+ with:
+ name: ${{ github.event.repository.name }}-API
+ path: ${{ env.DEPLOYMENT_ARTIFACT_DIR }}/${{ env.DEPLOYMENT_ARTIFACT_SELECTOR }}
+
+ - name: Upload Build Artifacts [Plugin]
+ uses: actions/upload-artifact@v4
+ with:
+ name: ${{ github.event.repository.name }}
+ path: ${{ env.PLUGIN_ARTIFACT_DIR }}/${{ env.PLUGIN_ARTIFACT_SELECTOR }}
+
+ - name: Deploy to Maven repo
+ if: ${{ github.event_name == 'push' }}
+ uses: craftaro/GH-Commons/.github/actions/maven_deploy@master
+ with:
+ repository_url: ${{ vars.PLUGINS_MAVEN_REPO_URL_RELEASE }}
+ repository_url_snapshots: ${{ vars.PLUGINS_MAVEN_REPO_URL_SNAPSHOT }}
+ maven_pom_path: ${{ env.DEPLOYMENT_POM_PATH }}
+ maven_out_dir: ${{ env.DEPLOYMENT_ARTIFACT_DIR }}
+
+ - name: Deploy parent pom.xml to Maven repo
+ if: ${{ github.event_name == 'push' }}
+ uses: craftaro/GH-Commons/.github/actions/maven_deploy@master
+ with:
+ repository_url: ${{ vars.PLUGINS_MAVEN_REPO_URL_RELEASE }}
+ repository_url_snapshots: ${{ vars.PLUGINS_MAVEN_REPO_URL_SNAPSHOT }}
+ only_deploy_pom: true
+ maven_out_dir: ${{ env.DEPLOYMENT_ARTIFACT_DIR }}
+
+ discord_webhook:
+ name: Send Discord Webhook
+ runs-on: ubuntu-latest
+
+ needs: [ Build ]
+ if: ${{ always() && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/development' || github.ref_type == 'tag') }}
+
+ steps:
+ - uses: actions/checkout@v4
+ - name: Notify Webhook
+ uses: craftaro/GH-Commons/.github/actions/discord_send_job_results@master
+ with:
+ github_token: ${{ secrets.GITHUB_TOKEN }}
+ webhook_url: ${{ secrets.DISCORD_BUILD_STATUS_WEBHOOK }}
diff --git a/.gitignore b/.gitignore
index 1d6910d..8b3e126 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,14 +1,10 @@
-
-out/
-
-\.idea/
-/src/main/resources/META-INF/MANIFEST.MF
-/EpicHoppers.iml
-
-target/
-
-EpicHoppers-API/EpicHoppers-API\.iml
-
-EpicHoppers-Plugin/EpicHoppers-Plugin\.iml
-
-*.iml
+## JetBrains IDEs
+/.idea/
+*.iml
+
+## Maven
+/**/target/
+/**/dependency-reduced-pom.xml
+
+## Misc.
+.DS_Store
diff --git a/EpicHoppers-API/pom.xml b/EpicHoppers-API/pom.xml
new file mode 100644
index 0000000..1c28af0
--- /dev/null
+++ b/EpicHoppers-API/pom.xml
@@ -0,0 +1,70 @@
+
+
+ 4.0.0
+
+
+ com.craftaro
+ EpicHoppers-Parent
+ 5.0.1
+ ../pom.xml
+
+ EpicHoppers-API
+ 1.0.0-SNAPSHOT
+
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+ 3.5.0
+
+
+
+
+ jar
+
+
+
+
+
+
+ https://hub.spigotmc.org/javadocs/spigot/
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+ 3.3.0
+
+
+
+
+ jar
+
+
+
+
+
+
+
+
+
+ com.craftaro
+ CraftaroCore
+ ${craftaro.coreVersion}
+ provided
+
+
+
+
+ org.spigotmc
+ spigot-api
+ 1.18-R0.1-SNAPSHOT
+ provided
+
+
+
diff --git a/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/EpicHoppersApi.java b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/EpicHoppersApi.java
new file mode 100644
index 0000000..e133db7
--- /dev/null
+++ b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/EpicHoppersApi.java
@@ -0,0 +1,61 @@
+package com.craftaro.epichoppers;
+
+import com.craftaro.core.database.DataManager;
+import com.craftaro.epichoppers.boost.BoostManager;
+import com.craftaro.epichoppers.containers.ContainerManager;
+import com.craftaro.epichoppers.hopper.teleport.TeleportHandler;
+import com.craftaro.epichoppers.player.PlayerDataManager;
+import com.craftaro.epichoppers.hopper.levels.LevelManager;
+import org.jetbrains.annotations.ApiStatus;
+
+public class EpicHoppersApi {
+ private static EpicHoppersApi instance;
+
+ private final LevelManager levelManager;
+ private final BoostManager boostManager;
+ private final ContainerManager containerManager;
+ private final TeleportHandler teleportHandler;
+ private final PlayerDataManager playerDataManager;
+ private EpicHoppersApi(LevelManager levelManager,
+ BoostManager boostManager,
+ ContainerManager containerManager,
+ TeleportHandler teleportHandler,
+ PlayerDataManager playerDataManager) {
+ this.levelManager = levelManager;
+ this.boostManager = boostManager;
+ this.containerManager = containerManager;
+ this.teleportHandler = teleportHandler;
+ this.playerDataManager = playerDataManager;
+ }
+
+ public LevelManager getLevelManager() {
+ return this.levelManager;
+ }
+
+ public BoostManager getBoostManager() {
+ return this.boostManager;
+ }
+
+ public ContainerManager getContainerManager() {
+ return this.containerManager;
+ }
+
+ public TeleportHandler getTeleportHandler() {
+ return this.teleportHandler;
+ }
+
+ public PlayerDataManager getPlayerDataManager() {
+ return this.playerDataManager;
+ }
+
+ public static EpicHoppersApi getApi() {
+ return instance;
+ }
+
+ static void initApi(LevelManager levelManager, BoostManager boostManager, ContainerManager containerManager, TeleportHandler teleportHandler, PlayerDataManager playerDataManager) {
+ if (instance != null) {
+ throw new IllegalStateException(EpicHoppersApi.class.getSimpleName() + " already initialized");
+ }
+ instance = new EpicHoppersApi(levelManager, boostManager, containerManager, teleportHandler, playerDataManager);
+ }
+}
diff --git a/src/main/java/com/songoda/epichoppers/api/events/HopperAccessEvent.java b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/api/events/HopperAccessEvent.java
similarity index 67%
rename from src/main/java/com/songoda/epichoppers/api/events/HopperAccessEvent.java
rename to EpicHoppers-API/src/main/java/com/craftaro/epichoppers/api/events/HopperAccessEvent.java
index bf3c2a0..0e1cc5d 100644
--- a/src/main/java/com/songoda/epichoppers/api/events/HopperAccessEvent.java
+++ b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/api/events/HopperAccessEvent.java
@@ -1,6 +1,6 @@
-package com.songoda.epichoppers.api.events;
+package com.craftaro.epichoppers.api.events;
-import com.songoda.epichoppers.hopper.Hopper;
+import com.craftaro.epichoppers.hopper.Hopper;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
@@ -9,13 +9,22 @@ import org.bukkit.event.HandlerList;
* Called when a hopper is accessed by a player.
*/
public class HopperAccessEvent extends HopperEvent implements Cancellable {
-
private static final HandlerList HANDLERS = new HandlerList();
private boolean canceled = false;
- public HopperAccessEvent(Player player, Hopper hopper) {
- super(player, hopper);
+ public HopperAccessEvent(Player who, Hopper hopper) {
+ super(who, hopper);
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return this.canceled;
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ this.canceled = cancel;
}
@Override
@@ -26,15 +35,4 @@ public class HopperAccessEvent extends HopperEvent implements Cancellable {
public static HandlerList getHandlerList() {
return HANDLERS;
}
-
- @Override
- public boolean isCancelled() {
- return canceled;
- }
-
- @Override
- public void setCancelled(boolean canceled) {
- this.canceled = canceled;
- }
-
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/songoda/epichoppers/api/events/HopperBreakEvent.java b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/api/events/HopperBreakEvent.java
similarity index 66%
rename from src/main/java/com/songoda/epichoppers/api/events/HopperBreakEvent.java
rename to EpicHoppers-API/src/main/java/com/craftaro/epichoppers/api/events/HopperBreakEvent.java
index 87e207f..625616e 100644
--- a/src/main/java/com/songoda/epichoppers/api/events/HopperBreakEvent.java
+++ b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/api/events/HopperBreakEvent.java
@@ -1,15 +1,14 @@
-package com.songoda.epichoppers.api.events;
+package com.craftaro.epichoppers.api.events;
-import com.songoda.epichoppers.hopper.Hopper;
+import com.craftaro.epichoppers.hopper.Hopper;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
public class HopperBreakEvent extends HopperEvent {
-
private static final HandlerList HANDLERS = new HandlerList();
- public HopperBreakEvent(Player player, Hopper hopper) {
- super(player, hopper);
+ public HopperBreakEvent(Player who, Hopper hopper) {
+ super(who, hopper);
}
@Override
@@ -20,5 +19,4 @@ public class HopperBreakEvent extends HopperEvent {
public static HandlerList getHandlerList() {
return HANDLERS;
}
-
}
diff --git a/src/main/java/com/songoda/epichoppers/api/events/HopperEvent.java b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/api/events/HopperEvent.java
similarity index 82%
rename from src/main/java/com/songoda/epichoppers/api/events/HopperEvent.java
rename to EpicHoppers-API/src/main/java/com/craftaro/epichoppers/api/events/HopperEvent.java
index 64fb566..3fb803f 100644
--- a/src/main/java/com/songoda/epichoppers/api/events/HopperEvent.java
+++ b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/api/events/HopperEvent.java
@@ -1,6 +1,6 @@
-package com.songoda.epichoppers.api.events;
+package com.craftaro.epichoppers.api.events;
-import com.songoda.epichoppers.hopper.Hopper;
+import com.craftaro.epichoppers.hopper.Hopper;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.player.PlayerEvent;
@@ -9,7 +9,6 @@ import org.bukkit.event.player.PlayerEvent;
* Represents an abstract {@link Event} given a {@link Player} and {@link Hopper} instance
*/
public abstract class HopperEvent extends PlayerEvent {
-
protected final Hopper hopper;
public HopperEvent(Player who, Hopper hopper) {
@@ -23,7 +22,6 @@ public abstract class HopperEvent extends PlayerEvent {
* @return the broken spawner
*/
public Hopper getHopper() {
- return hopper;
+ return this.hopper;
}
-
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/songoda/epichoppers/api/events/HopperPlaceEvent.java b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/api/events/HopperPlaceEvent.java
similarity index 66%
rename from src/main/java/com/songoda/epichoppers/api/events/HopperPlaceEvent.java
rename to EpicHoppers-API/src/main/java/com/craftaro/epichoppers/api/events/HopperPlaceEvent.java
index c7e1c5f..6683e20 100644
--- a/src/main/java/com/songoda/epichoppers/api/events/HopperPlaceEvent.java
+++ b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/api/events/HopperPlaceEvent.java
@@ -1,15 +1,14 @@
-package com.songoda.epichoppers.api.events;
+package com.craftaro.epichoppers.api.events;
-import com.songoda.epichoppers.hopper.Hopper;
+import com.craftaro.epichoppers.hopper.Hopper;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
public class HopperPlaceEvent extends HopperEvent {
-
private static final HandlerList HANDLERS = new HandlerList();
- public HopperPlaceEvent(Player player, Hopper hopper) {
- super(player, hopper);
+ public HopperPlaceEvent(Player who, Hopper hopper) {
+ super(who, hopper);
}
@Override
@@ -20,5 +19,4 @@ public class HopperPlaceEvent extends HopperEvent {
public static HandlerList getHandlerList() {
return HANDLERS;
}
-
-}
\ No newline at end of file
+}
diff --git a/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/boost/BoostData.java b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/boost/BoostData.java
new file mode 100644
index 0000000..f472a6a
--- /dev/null
+++ b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/boost/BoostData.java
@@ -0,0 +1,25 @@
+package com.craftaro.epichoppers.boost;
+
+import java.util.Objects;
+import java.util.UUID;
+
+public interface BoostData {
+
+ /**
+ * Gets the multiplier of the boost
+ * @return The multiplier
+ */
+ int getMultiplier();
+
+ /**
+ * Gets the player's uuid who has the boost
+ * @return The player's uuid
+ */
+ public UUID getPlayer();
+
+ /**
+ * Gets the end time of the boost
+ * @return The end time
+ */
+ public long getEndTime();
+}
diff --git a/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/boost/BoostManager.java b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/boost/BoostManager.java
new file mode 100644
index 0000000..13a394e
--- /dev/null
+++ b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/boost/BoostManager.java
@@ -0,0 +1,17 @@
+package com.craftaro.epichoppers.boost;
+
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+
+public interface BoostManager {
+ void addBoostToPlayer(BoostData data);
+
+ void removeBoostFromPlayer(BoostData data);
+
+ void addBoosts(List boosts);
+
+ Set getBoosts();
+
+ BoostData getBoost(UUID player);
+}
diff --git a/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/containers/ContainerManager.java b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/containers/ContainerManager.java
new file mode 100644
index 0000000..0208cb6
--- /dev/null
+++ b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/containers/ContainerManager.java
@@ -0,0 +1,15 @@
+package com.craftaro.epichoppers.containers;
+
+import org.bukkit.block.Block;
+
+import java.util.Set;
+
+public interface ContainerManager {
+ Set getCustomContainerImplementations();
+
+ void registerCustomContainerImplementation(String requiredPlugin, IContainer container);
+
+ void registerCustomContainerImplementation(IContainer container);
+
+ CustomContainer getCustomContainer(Block block);
+}
diff --git a/src/main/java/com/songoda/epichoppers/containers/CustomContainer.java b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/containers/CustomContainer.java
similarity index 64%
rename from src/main/java/com/songoda/epichoppers/containers/CustomContainer.java
rename to EpicHoppers-API/src/main/java/com/craftaro/epichoppers/containers/CustomContainer.java
index 7f517dc..6716611 100644
--- a/src/main/java/com/songoda/epichoppers/containers/CustomContainer.java
+++ b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/containers/CustomContainer.java
@@ -1,17 +1,13 @@
-package com.songoda.epichoppers.containers;
+package com.craftaro.epichoppers.containers;
-import org.bukkit.block.Block;
import org.bukkit.inventory.ItemStack;
public abstract class CustomContainer {
-
- private final Block block;
- public CustomContainer(Block block) {
- this.block = block;
- }
-
public abstract boolean addToContainer(ItemStack itemToMove);
+
public abstract ItemStack[] getItems();
+
public abstract void removeFromContainer(ItemStack itemToMove, int amountToMove);
+
public abstract boolean isContainer();
}
diff --git a/src/main/java/com/songoda/epichoppers/containers/IContainer.java b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/containers/IContainer.java
similarity index 72%
rename from src/main/java/com/songoda/epichoppers/containers/IContainer.java
rename to EpicHoppers-API/src/main/java/com/craftaro/epichoppers/containers/IContainer.java
index 5a02d9a..c5bbe45 100644
--- a/src/main/java/com/songoda/epichoppers/containers/IContainer.java
+++ b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/containers/IContainer.java
@@ -1,8 +1,7 @@
-package com.songoda.epichoppers.containers;
+package com.craftaro.epichoppers.containers;
import org.bukkit.block.Block;
public interface IContainer {
-
CustomContainer getCustomContainer(Block block);
}
diff --git a/src/main/java/com/songoda/epichoppers/hopper/Filter.java b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/hopper/Filter.java
similarity index 71%
rename from src/main/java/com/songoda/epichoppers/hopper/Filter.java
rename to EpicHoppers-API/src/main/java/com/craftaro/epichoppers/hopper/Filter.java
index c740da0..b3c009f 100644
--- a/src/main/java/com/songoda/epichoppers/hopper/Filter.java
+++ b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/hopper/Filter.java
@@ -1,4 +1,4 @@
-package com.songoda.epichoppers.hopper;
+package com.craftaro.epichoppers.hopper;
import org.bukkit.Location;
import org.bukkit.inventory.ItemStack;
@@ -8,7 +8,6 @@ import java.util.Collections;
import java.util.List;
public class Filter {
-
private List whiteList = new ArrayList<>();
private List blackList = new ArrayList<>();
private List voidList = new ArrayList<>();
@@ -16,65 +15,52 @@ public class Filter {
private List autoSellWhiteList = new ArrayList<>();
private List autoSellBlackList = new ArrayList<>();
-
private Location endPoint;
-
public List getWhiteList() {
- return whiteList != null ? whiteList : Collections.emptyList();
+ return this.whiteList != null ? this.whiteList : Collections.emptyList();
}
-
public void setWhiteList(List whiteList) {
this.whiteList = whiteList;
}
-
public List getBlackList() {
- return blackList != null ? blackList : Collections.emptyList();
+ return this.blackList != null ? this.blackList : Collections.emptyList();
}
-
public void setBlackList(List blackList) {
this.blackList = blackList;
}
-
public List getVoidList() {
- return voidList != null ? voidList : Collections.emptyList();
+ return this.voidList != null ? this.voidList : Collections.emptyList();
}
-
public void setVoidList(List voidList) {
this.voidList = voidList;
}
-
public List getAutoSellWhiteList() {
- return autoSellWhiteList != null ? autoSellWhiteList : Collections.emptyList();
+ return this.autoSellWhiteList != null ? this.autoSellWhiteList : Collections.emptyList();
}
-
public void setAutoSellWhiteList(List autoSellWhiteList) {
this.autoSellWhiteList = autoSellWhiteList;
}
-
public List getAutoSellBlackList() {
- return autoSellBlackList != null ? autoSellBlackList : Collections.emptyList();
+ return this.autoSellBlackList != null ? this.autoSellBlackList : Collections.emptyList();
}
-
public void setAutoSellBlackList(List autoSellBlackList) {
this.autoSellBlackList = autoSellBlackList;
}
-
public Location getEndPoint() {
- return endPoint;
+ return this.endPoint;
}
-
public void setEndPoint(Location endPoint) {
this.endPoint = endPoint;
}
@@ -82,19 +68,23 @@ public class Filter {
public void addItem(ItemStack item, ItemType type) {
switch (type) {
case WHITELIST:
- whiteList.add(item);
+ this.whiteList.add(item);
break;
+
case BLACKLIST:
- blackList.add(item);
+ this.blackList.add(item);
break;
+
case VOID:
- voidList.add(item);
+ this.voidList.add(item);
break;
+
case AUTO_SELL_WHITELIST:
- autoSellWhiteList.add(item);
+ this.autoSellWhiteList.add(item);
break;
+
case AUTO_SELL_BLACKLIST:
- autoSellBlackList.add(item);
+ this.autoSellBlackList.add(item);
break;
}
}
diff --git a/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/hopper/Hopper.java b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/hopper/Hopper.java
new file mode 100644
index 0000000..4c09834
--- /dev/null
+++ b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/hopper/Hopper.java
@@ -0,0 +1,58 @@
+package com.craftaro.epichoppers.hopper;
+
+import com.craftaro.core.database.Data;
+import com.craftaro.epichoppers.hopper.levels.Level;
+import com.craftaro.epichoppers.hopper.teleport.TeleportTrigger;
+import org.bukkit.Location;
+import org.bukkit.block.Block;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+import java.util.UUID;
+
+public interface Hopper extends Data {
+
+ Location getLocation();
+
+ Block getBlock();
+
+ Level getLevel();
+
+ void setLevel(Level level);
+
+ @Nullable UUID getLastPlayerOpened();
+
+ @NotNull UUID getPlacedBy();
+
+ void setPlacedBy(UUID placedBy);
+
+ void setLastPlayerOpened(UUID lastPlayerOpened);
+
+ TeleportTrigger getTeleportTrigger();
+
+ void setTeleportTrigger(TeleportTrigger teleportTrigger);
+
+ List getLinkedBlocks();
+
+ void addLinkedBlock(Location location, LinkType type);
+
+ void removeLinkedBlock(Location location);
+
+ void clearLinkedBlocks();
+
+ Filter getFilter();
+
+ void setActivePlayer(Player activePlayer);
+
+ void timeout(Player player);
+
+ void addDataToModuleCache(String s, Object value);
+
+ boolean isDataCachedInModuleCache(String cacheStr);
+
+ Object getDataFromModuleCache(String cacheStr);
+
+ void clearModuleCache();
+}
diff --git a/src/main/java/com/songoda/epichoppers/hopper/ItemType.java b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/hopper/ItemType.java
similarity index 70%
rename from src/main/java/com/songoda/epichoppers/hopper/ItemType.java
rename to EpicHoppers-API/src/main/java/com/craftaro/epichoppers/hopper/ItemType.java
index 9a54d96..16b0ef2 100644
--- a/src/main/java/com/songoda/epichoppers/hopper/ItemType.java
+++ b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/hopper/ItemType.java
@@ -1,7 +1,5 @@
-package com.songoda.epichoppers.hopper;
+package com.craftaro.epichoppers.hopper;
public enum ItemType {
-
WHITELIST, BLACKLIST, VOID, AUTO_SELL_WHITELIST, AUTO_SELL_BLACKLIST
-
}
diff --git a/src/main/java/com/songoda/epichoppers/hopper/LinkType.java b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/hopper/LinkType.java
similarity index 52%
rename from src/main/java/com/songoda/epichoppers/hopper/LinkType.java
rename to EpicHoppers-API/src/main/java/com/craftaro/epichoppers/hopper/LinkType.java
index df6e31e..ca067e7 100644
--- a/src/main/java/com/songoda/epichoppers/hopper/LinkType.java
+++ b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/hopper/LinkType.java
@@ -1,6 +1,5 @@
-package com.songoda.epichoppers.hopper;
+package com.craftaro.epichoppers.hopper;
public enum LinkType {
-
REGULAR, REJECT
}
diff --git a/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/hopper/levels/Level.java b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/hopper/levels/Level.java
new file mode 100644
index 0000000..728d625
--- /dev/null
+++ b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/hopper/levels/Level.java
@@ -0,0 +1,142 @@
+package com.craftaro.epichoppers.hopper.levels;
+
+import com.craftaro.core.SongodaPlugin;
+import com.craftaro.epichoppers.hopper.levels.modules.Module;
+import org.bukkit.Bukkit;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Level {
+ private final ArrayList registeredModules;
+ private final List description = new ArrayList<>();
+ private final int level, costExperience, costEconomy, range, amount, linkAmount;
+ private final boolean filter, teleport;
+
+ public Level(int level, int costExperience, int costEconomy, int range, int amount, boolean filter, boolean teleport, int linkAmount, ArrayList registeredModules) {
+ this.level = level;
+ this.costExperience = costExperience;
+ this.costEconomy = costEconomy;
+ this.range = range;
+ this.amount = amount;
+ this.filter = filter;
+ this.teleport = teleport;
+ this.linkAmount = linkAmount;
+ this.registeredModules = registeredModules;
+
+ buildDescription();
+ }
+
+ public void buildDescription() {
+ this.description.clear();
+
+ this.description.add(getPlugin().getLocale().getMessage("interface.hopper.range")
+ .processPlaceholder("range", this.range).getMessage());
+ this.description.add(getPlugin().getLocale().getMessage("interface.hopper.amount")
+ .processPlaceholder("amount", this.amount).getMessage());
+ if (this.linkAmount != 1) {
+ this.description.add(getPlugin().getLocale().getMessage("interface.hopper.linkamount")
+ .processPlaceholder("amount", this.linkAmount).getMessage());
+ }
+ if (this.filter) {
+ this.description.add(getPlugin().getLocale().getMessage("interface.hopper.filter")
+ .processPlaceholder("enabled", getPlugin().getLocale()
+ .getMessage("general.word.enabled").getMessage()).getMessage());
+ }
+ if (this.teleport) {
+ this.description.add(getPlugin()
+ .getLocale()
+ .getMessage("interface.hopper.teleport")
+ .processPlaceholder(
+ "enabled",
+ getPlugin()
+ .getLocale()
+ .getMessage("general.word.enabled")
+ .getMessage())
+ .getMessage());
+ }
+
+ for (Module module : this.registeredModules) {
+ this.description.add(module.getDescription());
+ }
+ }
+
+
+ public int getLevel() {
+ return this.level;
+ }
+
+
+ public int getRange() {
+ return this.range;
+ }
+
+
+ public int getAmount() {
+ return this.amount;
+ }
+
+
+ public boolean isFilter() {
+ return this.filter;
+ }
+
+
+ public boolean isTeleport() {
+ return this.teleport;
+ }
+
+
+ public int getLinkAmount() {
+ return this.linkAmount;
+ }
+
+
+ public int getCostExperience() {
+ return this.costExperience;
+ }
+
+
+ public int getCostEconomy() {
+ return this.costEconomy;
+ }
+
+
+ public List getDescription() {
+ return new ArrayList<>(this.description);
+ }
+
+
+ public ArrayList getRegisteredModules() {
+ return new ArrayList<>(this.registeredModules);
+ }
+
+
+ public void addModule(Module module) {
+ this.registeredModules.add(module);
+ buildDescription();
+ }
+
+
+ public Module getModule(String name) {
+ if (this.registeredModules == null) {
+ return null;
+ }
+
+ for (Module module : this.registeredModules) {
+ if (module.getName().equals(name)) {
+ return module;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @deprecated The class needs refactoring to not even need the plugin.
+ * This is just a temporary workaround to get a Minecraft 1.20-beta build ready
+ */
+ @Deprecated
+ private SongodaPlugin getPlugin() {
+ return (SongodaPlugin) Bukkit.getPluginManager().getPlugin("EpicHoppers");
+ }
+}
diff --git a/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/hopper/levels/LevelManager.java b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/hopper/levels/LevelManager.java
new file mode 100644
index 0000000..80dcbcc
--- /dev/null
+++ b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/hopper/levels/LevelManager.java
@@ -0,0 +1,27 @@
+package com.craftaro.epichoppers.hopper.levels;
+
+import com.craftaro.epichoppers.hopper.levels.modules.Module;
+import org.bukkit.inventory.ItemStack;
+
+import java.util.ArrayList;
+import java.util.Map;
+
+public interface LevelManager {
+ void addLevel(int level, int costExperience, int costEconomy, int range, int amount, boolean filter, boolean teleport, int linkAmount, ArrayList modules);
+
+ Level getLevel(int level);
+
+ Level getLevel(ItemStack item);
+
+ boolean isEpicHopper(ItemStack item);
+
+ Level getLowestLevel();
+
+ Level getHighestLevel();
+
+ boolean isLevel(int level);
+
+ Map getLevels();
+
+ void clear();
+}
diff --git a/src/main/java/com/songoda/epichoppers/hopper/levels/modules/Module.java b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/hopper/levels/modules/Module.java
similarity index 52%
rename from src/main/java/com/songoda/epichoppers/hopper/levels/modules/Module.java
rename to EpicHoppers-API/src/main/java/com/craftaro/epichoppers/hopper/levels/modules/Module.java
index 09e0211..a25b52b 100644
--- a/src/main/java/com/songoda/epichoppers/hopper/levels/modules/Module.java
+++ b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/hopper/levels/modules/Module.java
@@ -1,10 +1,11 @@
-package com.songoda.epichoppers.hopper.levels.modules;
+package com.craftaro.epichoppers.hopper.levels.modules;
-import com.songoda.core.configuration.Config;
-import com.songoda.epichoppers.EpicHoppers;
-import com.songoda.epichoppers.hopper.Hopper;
-import com.songoda.epichoppers.utils.Methods;
-import com.songoda.epichoppers.utils.StorageContainerCache;
+import com.craftaro.core.SongodaPlugin;
+import com.craftaro.core.configuration.Config;
+import com.craftaro.core.gui.GuiManager;
+import com.craftaro.epichoppers.utils.StorageContainerCache;
+import com.craftaro.epichoppers.hopper.Hopper;
+import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
@@ -16,21 +17,23 @@ import java.util.List;
import java.util.Map;
public abstract class Module {
+ private static final Map CONFIGS = new HashMap<>();
- private static final Map configs = new HashMap<>();
-
- protected final EpicHoppers plugin;
+ protected final SongodaPlugin plugin;
+ protected final GuiManager guiManager;
private final Config config;
- public Module(EpicHoppers plugin) {
+ public Module(SongodaPlugin plugin, GuiManager guiManager) {
this.plugin = plugin;
- if (!configs.containsKey(getName())) {
+ this.guiManager = guiManager;
+
+ if (!CONFIGS.containsKey(getName())) {
Config config = new Config(plugin, File.separator + "modules", getName() + ".yml");
- configs.put(getName(), config);
+ CONFIGS.put(getName(), config);
config.load();
}
- this.config = configs.get(getName());
+ this.config = CONFIGS.get(getName());
}
public abstract String getName();
@@ -50,7 +53,7 @@ public abstract class Module {
}
public void saveData(Hopper hopper, String setting, Object value, Object toCache) {
- config.set("data." + Methods.serializeLocation(hopper.getLocation()) + "." + setting, value);
+ this.config.set("data." + serializeLocation(hopper.getLocation()) + "." + setting, value);
modifyDataCache(hopper, setting, toCache);
}
@@ -60,20 +63,34 @@ public abstract class Module {
protected Object getData(Hopper hopper, String setting) {
String cacheStr = getName() + "." + setting;
- if (hopper.isDataCachedInModuleCache(cacheStr))
+ if (hopper.isDataCachedInModuleCache(cacheStr)) {
return hopper.getDataFromModuleCache(cacheStr);
+ }
- Object data = config.get("data." + Methods.serializeLocation(hopper.getLocation()) + "." + setting);
+ Object data = this.config.get("data." + serializeLocation(hopper.getLocation()) + "." + setting);
modifyDataCache(hopper, setting, data);
return data;
}
public void clearData(Hopper hopper) {
- config.set("data." + Methods.serializeLocation(hopper.getLocation()), null);
+ this.config.set("data." + serializeLocation(hopper.getLocation()), null);
hopper.clearModuleCache();
}
public void saveDataToFile() {
- config.save();
+ this.config.save();
+ }
+
+ private static String serializeLocation(Location location) {
+ if (location == null || location.getWorld() == null) {
+ return "";
+ }
+ String w = location.getWorld().getName();
+ double x = location.getX();
+ double y = location.getY();
+ double z = location.getZ();
+ String str = w + ":" + x + ":" + y + ":" + z;
+ str = str.replace(".0", "").replace(".", "/");
+ return str;
}
}
diff --git a/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/hopper/teleport/TeleportHandler.java b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/hopper/teleport/TeleportHandler.java
new file mode 100644
index 0000000..6f32c55
--- /dev/null
+++ b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/hopper/teleport/TeleportHandler.java
@@ -0,0 +1,8 @@
+package com.craftaro.epichoppers.hopper.teleport;
+
+import com.craftaro.epichoppers.hopper.Hopper;
+import org.bukkit.entity.Entity;
+
+public interface TeleportHandler {
+ void tpEntity(Entity entity, Hopper hopper);
+}
diff --git a/src/main/java/com/songoda/epichoppers/hopper/teleport/TeleportTrigger.java b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/hopper/teleport/TeleportTrigger.java
similarity index 54%
rename from src/main/java/com/songoda/epichoppers/hopper/teleport/TeleportTrigger.java
rename to EpicHoppers-API/src/main/java/com/craftaro/epichoppers/hopper/teleport/TeleportTrigger.java
index 2aecdd5..6f91f6e 100644
--- a/src/main/java/com/songoda/epichoppers/hopper/teleport/TeleportTrigger.java
+++ b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/hopper/teleport/TeleportTrigger.java
@@ -1,7 +1,5 @@
-package com.songoda.epichoppers.hopper.teleport;
+package com.craftaro.epichoppers.hopper.teleport;
public enum TeleportTrigger {
-
DISABLED, WALK_ON, SNEAK
-
}
diff --git a/src/main/java/com/songoda/epichoppers/player/PlayerData.java b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/player/PlayerData.java
similarity index 72%
rename from src/main/java/com/songoda/epichoppers/player/PlayerData.java
rename to EpicHoppers-API/src/main/java/com/craftaro/epichoppers/player/PlayerData.java
index 28e51f0..9574acf 100644
--- a/src/main/java/com/songoda/epichoppers/player/PlayerData.java
+++ b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/player/PlayerData.java
@@ -1,15 +1,14 @@
-package com.songoda.epichoppers.player;
+package com.craftaro.epichoppers.player;
-import com.songoda.epichoppers.hopper.Hopper;
+
+import com.craftaro.epichoppers.hopper.Hopper;
public class PlayerData {
-
private Hopper lastHopper = null;
-
private SyncType syncType = null; // Null means off.
public Hopper getLastHopper() {
- return lastHopper;
+ return this.lastHopper;
}
public void setLastHopper(Hopper lastHopper) {
@@ -17,7 +16,7 @@ public class PlayerData {
}
public SyncType getSyncType() {
- return syncType;
+ return this.syncType;
}
public void setSyncType(SyncType syncType) {
diff --git a/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/player/PlayerDataManager.java b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/player/PlayerDataManager.java
new file mode 100644
index 0000000..8ad001e
--- /dev/null
+++ b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/player/PlayerDataManager.java
@@ -0,0 +1,11 @@
+package com.craftaro.epichoppers.player;
+
+import org.bukkit.entity.Player;
+
+import java.util.Collection;
+
+public interface PlayerDataManager {
+ PlayerData getPlayerData(Player player);
+
+ Collection getRegisteredPlayers();
+}
diff --git a/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/player/SyncType.java b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/player/SyncType.java
new file mode 100644
index 0000000..16e8cbf
--- /dev/null
+++ b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/player/SyncType.java
@@ -0,0 +1,5 @@
+package com.craftaro.epichoppers.player;
+
+public enum SyncType {
+ REGULAR, FILTERED
+}
diff --git a/src/main/java/com/songoda/epichoppers/utils/CostType.java b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/utils/CostType.java
similarity index 53%
rename from src/main/java/com/songoda/epichoppers/utils/CostType.java
rename to EpicHoppers-API/src/main/java/com/craftaro/epichoppers/utils/CostType.java
index 0b0627c..b2fcd44 100644
--- a/src/main/java/com/songoda/epichoppers/utils/CostType.java
+++ b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/utils/CostType.java
@@ -1,7 +1,5 @@
-package com.songoda.epichoppers.utils;
+package com.craftaro.epichoppers.utils;
public enum CostType {
-
ECONOMY, EXPERIENCE
-
-}
\ No newline at end of file
+}
diff --git a/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/utils/Methods.java b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/utils/Methods.java
new file mode 100644
index 0000000..b097cf8
--- /dev/null
+++ b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/utils/Methods.java
@@ -0,0 +1,104 @@
+package com.craftaro.epichoppers.utils;
+
+import com.craftaro.core.SongodaPlugin;
+import com.craftaro.core.compatibility.ServerVersion;
+import com.craftaro.core.utils.TextUtils;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.entity.Entity;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.jetbrains.annotations.ApiStatus;
+
+@ApiStatus.Internal
+public class Methods {
+ public static boolean isSimilarMaterial(ItemStack is1, ItemStack is2) {
+ if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13) ||
+ is1.getDurability() == Short.MAX_VALUE || is2.getDurability() == Short.MAX_VALUE) {
+ // Durability of Short.MAX_VALUE is used in recipes if the durability should be ignored
+ return is1.getType() == is2.getType();
+ } else {
+ return is1.getType() == is2.getType() && (is1.getDurability() == -1 || is2.getDurability() == -1 || is1.getDurability() == is2.getDurability());
+ }
+ }
+
+ public static boolean canMove(Inventory inventory, ItemStack item) {
+ if (inventory.firstEmpty() != -1) {
+ return true;
+ }
+
+ final ItemMeta itemMeta = item.getItemMeta();
+ for (ItemStack stack : inventory) {
+ final ItemMeta stackMeta;
+ if (isSimilarMaterial(stack, item) && (stack.getAmount() + item.getAmount()) < stack.getMaxStackSize()
+ && ((itemMeta == null) == ((stackMeta = stack.getItemMeta()) == null))
+ && (itemMeta == null || Bukkit.getItemFactory().equals(itemMeta, stackMeta))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static boolean canMoveReserved(Inventory inventory, ItemStack item) {
+ if (inventory.firstEmpty() != inventory.getSize() - 1) {
+ return true;
+ }
+
+ final ItemMeta itemMeta = item.getItemMeta();
+ final ItemStack[] contents = inventory.getContents();
+ for (int i = 0; i < 4; i++) {
+ final ItemStack stack = contents[i];
+ final ItemMeta stackMeta;
+ if (isSimilarMaterial(stack, item) && (stack.getAmount() + item.getAmount()) < stack.getMaxStackSize()
+ && ((itemMeta == null) == ((stackMeta = stack.getItemMeta()) == null))
+ && (itemMeta == null || Bukkit.getItemFactory().equals(itemMeta, stackMeta))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static boolean canMoveReserved(ItemStack[] contents, ItemStack item) {
+ final ItemMeta itemMeta = item.getItemMeta();
+ for (int i = 0; i < contents.length - 2; i++) {
+ final ItemStack stack = contents[i];
+ if (stack == null || stack.getAmount() == 0) {
+ return true;
+ }
+ final ItemMeta stackMeta;
+ if (isSimilarMaterial(stack, item) && (stack.getAmount() + item.getAmount()) < stack.getMaxStackSize()
+ && ((itemMeta == null) == ((stackMeta = stack.getItemMeta()) == null))
+ && (itemMeta == null || Bukkit.getItemFactory().equals(itemMeta, stackMeta))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static String formatName(int level) {
+ String name = getPlugin().getLocale()
+ .getMessage("general.nametag.nameformat")
+ .processPlaceholder("level", level)
+ .getMessage();
+
+
+ return TextUtils.formatText(name);
+ }
+
+ public static void doParticles(Entity entity, Location location) {
+ location.setX(location.getX() + .5);
+ location.setY(location.getY() + .5);
+ location.setZ(location.getZ() + .5);
+ entity.getWorld().spawnParticle(org.bukkit.Particle.valueOf(getPlugin().getConfig().getString("Main.Upgrade Particle Type")), location, 200, .5, .5, .5);
+ }
+
+ /**
+ * @deprecated The class needs refactoring to not even need the plugin.
+ * This is just a temporary workaround to get a Minecraft 1.20-beta build ready
+ */
+ @Deprecated
+ private static SongodaPlugin getPlugin() {
+ return (SongodaPlugin) Bukkit.getPluginManager().getPlugin("EpicHoppers");
+ }
+}
diff --git a/src/main/java/com/songoda/epichoppers/utils/StorageContainerCache.java b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/utils/StorageContainerCache.java
similarity index 61%
rename from src/main/java/com/songoda/epichoppers/utils/StorageContainerCache.java
rename to EpicHoppers-API/src/main/java/com/craftaro/epichoppers/utils/StorageContainerCache.java
index 8bc38e8..3255e6e 100644
--- a/src/main/java/com/songoda/epichoppers/utils/StorageContainerCache.java
+++ b/EpicHoppers-API/src/main/java/com/craftaro/epichoppers/utils/StorageContainerCache.java
@@ -1,358 +1,362 @@
-package com.songoda.epichoppers.utils;
-
-import com.songoda.core.compatibility.CompatibleMaterial;
-import com.songoda.core.compatibility.ServerVersion;
-import com.songoda.core.nms.NmsManager;
-import org.bukkit.Material;
-import org.bukkit.block.Block;
-import org.bukkit.block.BlockFace;
-import org.bukkit.block.BlockState;
-import org.bukkit.block.data.BlockData;
-import org.bukkit.block.data.type.Chest;
-import org.bukkit.inventory.Inventory;
-import org.bukkit.inventory.InventoryHolder;
-import org.bukkit.inventory.ItemStack;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Persistent storage intended for streamlining read/write for storage
- * containers in large batches
- */
-public class StorageContainerCache {
-
- private static final Map inventoryCache = new HashMap<>();
-
- // need to get the topmost inventory for a double chest, and save as that block
- public static Cache getCachedInventory(Block b) {
- Cache cache = inventoryCache.get(b);
- if (cache == null) {
- Material type = b.getType();
- if (type == Material.CHEST || type == Material.TRAPPED_CHEST) {
- Block b2 = findAdjacentDoubleChest(b);
- //System.out.println("Adjacent to " + b + " = " + b2);
- if (b2 != null && (cache = inventoryCache.get(b2)) != null) {
- return cache;
- }
- }
- BlockState blockState = b.getState();
- if (blockState instanceof InventoryHolder) {
- //System.out.println("Load " + b.getLocation());
- inventoryCache.put(b, cache = new Cache(b, ((InventoryHolder) blockState).getInventory().getContents()));
- }
- }
- return cache;
- }
-
- /**
- * Look for a double chest adjacent to a chest
- *
- * @param block
- * @return
- */
- public static Block findAdjacentDoubleChest(Block block) {
- if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13)) {
- final BlockData d = block.getBlockData();
- if (d instanceof Chest) {
- final Chest c = (Chest) d;
- if (c.getType() != Chest.Type.SINGLE) {
- // this is a double chest - check the other chest for registration data
- Block other = null;
- switch (c.getFacing()) {
- case SOUTH:
- other = block.getRelative(c.getType() != Chest.Type.RIGHT ? BlockFace.WEST : BlockFace.EAST);
- break;
- case NORTH:
- other = block.getRelative(c.getType() != Chest.Type.RIGHT ? BlockFace.EAST : BlockFace.WEST);
- break;
- case EAST:
- other = block.getRelative(c.getType() != Chest.Type.RIGHT ? BlockFace.SOUTH : BlockFace.NORTH);
- break;
- case WEST:
- other = block.getRelative(c.getType() != Chest.Type.RIGHT ? BlockFace.NORTH : BlockFace.SOUTH);
- break;
- default:
- break;
- }
- // double-check
- if (other != null && other.getType() == block.getType()) {
- return other;
- }
- }
- }
- } else {
- // legacy check
- Material material = block.getType();
- BlockFace[] faces = new BlockFace[] {BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST};
- for (BlockFace face : faces) {
- Block adjacentBlock = block.getRelative(face);
-
- if (adjacentBlock.getType() == material) {
- return adjacentBlock;
- }
- }
- }
- return null;
- }
-
- public static void update() {
- inventoryCache.entrySet().stream()
- .filter(e -> e.getValue().dirty)
- .forEach(e -> {
- //System.out.println("Update " + e.getKey().getLocation());
- // setContents makes a copy of every item whether it's needed or not
- //((InventoryHolder) e.getKey().getState()).getInventory().setContents(e.getValue().cachedInventory);
- // so let's only update what needs to be updated.
- final ItemStack[] cachedInventory = e.getValue().cachedInventory;
- final boolean[] cacheChanged = e.getValue().cacheChanged;
- Inventory inventory = ((InventoryHolder) e.getKey().getState()).getInventory();//.setContents();
- for (int i = 0; i < cachedInventory.length; i++) {
- if (cacheChanged[i]) {
- inventory.setItem(i, cachedInventory[i]);
- }
- }
-
- NmsManager.getWorld().updateAdjacentComparators(e.getKey());
- });
- inventoryCache.clear();
- }
-
- public static class Cache {
-
- public final Material type;
- public final Block block;
- public ItemStack[] cachedInventory;
- public boolean[] cacheChanged;
- public int[] cacheAdded;
- public boolean dirty;
-
- public Cache(Material type, ItemStack[] cachedInventory) {
- this.block = null;
- this.type = type;
- this.cachedInventory = cachedInventory;
- this.cacheChanged = new boolean[cachedInventory.length];
- this.cacheAdded = new int[cachedInventory.length];
- }
-
- public Cache(Block b, ItemStack[] cachedInventory) {
- this.block = b;
- this.type = b.getType();
- this.cachedInventory = cachedInventory;
- this.cacheChanged = new boolean[cachedInventory.length];
- this.cacheAdded = new int[cachedInventory.length];
- }
-
- public void setDirty(boolean dirty) {
- this.dirty = dirty;
- }
-
- public boolean isDirty() {
- return this.dirty;
- }
-
- public void setContents(ItemStack[] items) {
- if (cachedInventory == null || items.length == cachedInventory.length) {
- cachedInventory = items;
- for (int i = 0; i < cachedInventory.length; i++) {
- cacheChanged[i] = true;
- }
- dirty = true;
- }
- }
-
- public void setItem(int item, ItemStack itemStack) {
- if (cachedInventory != null) {
- cachedInventory[item] = itemStack;
- cacheChanged[item] = true;
- dirty = true;
- }
- }
-
- public void removeItem(int item) {
- if (cachedInventory != null) {
- cachedInventory[item] = null;
- cacheChanged[item] = true;
- dirty = true;
- }
- }
-
- public void removeItems(ItemStack item) {
- if (cachedInventory != null && item != null) {
- int toRemove = item.getAmount();
- for (int i = 0; toRemove > 0 && i < cachedInventory.length; i++) {
- final ItemStack cacheItem = cachedInventory[i];
- if (cacheItem != null && cacheItem.getAmount() != 0 && item.isSimilar(cacheItem)) {
- int have = cacheItem.getAmount();
- if (have > toRemove) {
- cachedInventory[i].setAmount(have - toRemove);
- cacheChanged[i] = true;
- toRemove = 0;
- } else {
- cachedInventory[i] = null;
- cacheChanged[i] = true;
- toRemove -= have;
- }
- }
- }
- dirty = dirty | (toRemove != item.getAmount());
- }
- }
-
- /**
- * Add a number of items to this container's inventory later.
- *
- * @param item item to add
- * @param amountToAdd how many of this item to attempt to add
- * @return how many items were added
- */
- public int addAny(ItemStack item, int amountToAdd) {
-
- // Don't transfer shulker boxes into other shulker boxes, that's a bad idea.
- if (type.name().contains("SHULKER_BOX") && item.getType().name().contains("SHULKER_BOX"))
- return 0;
-
- int totalAdded = 0;
- if (cachedInventory != null && item != null) {
- final int maxStack = item.getMaxStackSize();
- for (int i = 0; amountToAdd > 0 && i < cachedInventory.length; i++) {
- final ItemStack cacheItem = cachedInventory[i];
- if (cacheItem == null || cacheItem.getAmount() == 0) {
- // free slot!
- int toAdd = Math.min(maxStack, amountToAdd);
- cachedInventory[i] = item.clone();
- cachedInventory[i].setAmount(toAdd);
- cacheChanged[i] = true;
- cacheAdded[i] = toAdd;
- totalAdded += toAdd;
- amountToAdd -= toAdd;
- } else if (maxStack > cacheItem.getAmount() && item.isSimilar(cacheItem)) {
- // free space!
- int toAdd = Math.min(maxStack - cacheItem.getAmount(), amountToAdd);
- cachedInventory[i].setAmount(toAdd + cacheItem.getAmount());
- cacheChanged[i] = true;
- cacheAdded[i] += toAdd;
- totalAdded += toAdd;
- amountToAdd -= toAdd;
- }
- }
- if (totalAdded != 0) {
- dirty = true;
- }
- }
- return totalAdded;
- }
-
- /**
- * Add an item to this container's inventory later.
- *
- * @param item item to add
- * @return true if the item was added
- */
- public boolean addItem(ItemStack item) {
- if (cachedInventory == null || item == null || item.getAmount() <= 0)
- return false;
-
- // Don't transfer shulker boxes into other shulker boxes, that's a bad idea.
- if (type.name().contains("SHULKER_BOX") && item.getType().name().contains("SHULKER_BOX"))
- return false;
-
- // grab the amount to move and the max item stack size
- int toAdd = item.getAmount();
- final int maxStack = item.getMaxStackSize();
- boolean[] check = null;
-
- // some destination containers have special conditions
- switch (type.name()) {
- case "BREWING_STAND": {
-
- // first compile a list of what slots to check
- check = new boolean[5];
- String typeStr = item.getType().name().toUpperCase();
- if (typeStr.contains("POTION") || typeStr.contains("BOTTLE")) {
- // potion bottles are the first three slots
- check[0] = check[1] = check[2] = true;
- }
- // fuel in 5th position, input in 4th
- if (item.getType() == Material.BLAZE_POWDER)
- check[4] = true;
- else if (CompatibleMaterial.getMaterial(item).isBrewingStandIngredient())
- check[3] = true;
-
- break;
- }
- case "SMOKER":
- case "BLAST_FURNACE":
- case "BURNING_FURNACE":
- case "FURNACE": {
-
- check = new boolean[3];
-
- boolean isFuel = !item.getType().name().contains("LOG") && CompatibleMaterial.getMaterial(item.getType()).isFuel();
- // fuel is 2nd slot, input is first
- if (isFuel)
- check[1] = true;
- else
- check[0] = true;
-
- break;
- }
- default:
- break;
- }
-
- // we can reduce calls to ItemStack.isSimilar() by caching what cells to look at
- if (check == null) {
- check = new boolean[cachedInventory.length];
- for (int i = 0; toAdd > 0 && i < check.length; i++)
- check[i] = true;
- }
-
- // first verify that we can add this item
- for (int i = 0; toAdd > 0 && i < cachedInventory.length; i++) {
- if (check[i]) {
- final ItemStack cacheItem = cachedInventory[i];
- if (cacheItem == null || cacheItem.getAmount() == 0) {
- // free slot!
- toAdd -= Math.min(maxStack, toAdd);
- check[i] = true;
- } else if (maxStack > cacheItem.getAmount() && item.isSimilar(cacheItem)) {
- // free space!
- toAdd -= Math.min(maxStack - cacheItem.getAmount(), toAdd);
- check[i] = true;
- } else
- check[i] = false;
- }
- }
- if (toAdd <= 0) {
- // all good to add!
- toAdd = item.getAmount();
- for (int i = 0; toAdd > 0 && i < cachedInventory.length; i++) {
- if (!check[i])
- continue;
- final ItemStack cacheItem = cachedInventory[i];
- if (cacheItem == null || cacheItem.getAmount() == 0) {
- // free slot!
- int adding = Math.min(maxStack, toAdd);
- cachedInventory[i] = item.clone();
- cachedInventory[i].setAmount(adding);
- cacheChanged[i] = true;
- cacheAdded[i] = adding;
- toAdd -= adding;
- } else if (maxStack > cacheItem.getAmount()) {
- // free space!
- // (no need to check item.isSimilar(cacheItem), since we have that cached in check[])
- int adding = Math.min(maxStack - cacheItem.getAmount(), toAdd);
- cachedInventory[i].setAmount(adding + cacheItem.getAmount());
- cacheChanged[i] = true;
- cacheAdded[i] += adding;
- toAdd -= adding;
- }
- }
- dirty = true;
- return true;
- }
- return false;
- }
- }
-}
+package com.craftaro.epichoppers.utils;
+
+import com.craftaro.core.compatibility.CompatibleMaterial;
+import com.craftaro.core.compatibility.ServerVersion;
+import com.craftaro.core.nms.Nms;
+import com.craftaro.third_party.com.cryptomorin.xseries.XMaterial;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.block.BlockFace;
+import org.bukkit.block.BlockState;
+import org.bukkit.block.data.BlockData;
+import org.bukkit.block.data.type.Chest;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.InventoryHolder;
+import org.bukkit.inventory.ItemStack;
+import org.jetbrains.annotations.ApiStatus;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Persistent storage intended for streamlining read/write for storage
+ * containers in large batches
+ */
+@ApiStatus.Internal
+public class StorageContainerCache {
+ private static final Map INVENTORY_CACHE = new HashMap<>();
+
+ // need to get the topmost inventory for a double chest, and save as that block
+ public static Cache getCachedInventory(Block block) {
+ Cache cache = INVENTORY_CACHE.get(block);
+ if (cache == null) {
+ Material type = block.getType();
+ if (type == Material.CHEST || type == Material.TRAPPED_CHEST) {
+ Block b2 = findAdjacentDoubleChest(block);
+ //System.out.println("Adjacent to " + block + " = " + b2);
+ if (b2 != null && (cache = INVENTORY_CACHE.get(b2)) != null) {
+ return cache;
+ }
+ }
+ BlockState blockState = block.getState();
+ if (blockState instanceof InventoryHolder) {
+ //System.out.println("Load " + block.getLocation());
+ INVENTORY_CACHE.put(block, cache = new Cache(block, ((InventoryHolder) blockState).getInventory().getContents()));
+ }
+ }
+ return cache;
+ }
+
+ /**
+ * Look for a double chest adjacent to a chest
+ */
+ public static Block findAdjacentDoubleChest(Block block) {
+ if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13)) {
+ final BlockData blockData = block.getBlockData();
+ if (blockData instanceof Chest) {
+ final Chest chest = (Chest) blockData;
+ if (chest.getType() != Chest.Type.SINGLE) {
+ // this is a double chest - check the other chest for registration data
+ Block other = null;
+ switch (chest.getFacing()) {
+ case SOUTH:
+ other = block.getRelative(chest.getType() != Chest.Type.RIGHT ? BlockFace.WEST : BlockFace.EAST);
+ break;
+ case NORTH:
+ other = block.getRelative(chest.getType() != Chest.Type.RIGHT ? BlockFace.EAST : BlockFace.WEST);
+ break;
+ case EAST:
+ other = block.getRelative(chest.getType() != Chest.Type.RIGHT ? BlockFace.SOUTH : BlockFace.NORTH);
+ break;
+ case WEST:
+ other = block.getRelative(chest.getType() != Chest.Type.RIGHT ? BlockFace.NORTH : BlockFace.SOUTH);
+ break;
+ default:
+ break;
+ }
+ // double-check
+ if (other != null && other.getType() == block.getType()) {
+ return other;
+ }
+ }
+ }
+ } else {
+ // legacy check
+ Material material = block.getType();
+ BlockFace[] faces = new BlockFace[]{BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST};
+ for (BlockFace face : faces) {
+ Block adjacentBlock = block.getRelative(face);
+
+ if (adjacentBlock.getType() == material) {
+ return adjacentBlock;
+ }
+ }
+ }
+ return null;
+ }
+
+ public static void update() {
+ INVENTORY_CACHE.entrySet().stream()
+ .filter(e -> e.getValue().dirty)
+ .forEach(e -> {
+ //System.out.println("Update " + e.getKey().getLocation());
+ // setContents makes a copy of every item whether it's needed or not
+ //((InventoryHolder) e.getKey().getState()).getInventory().setContents(e.getValue().cachedInventory);
+ // so let's only update what needs to be updated.
+ final ItemStack[] cachedInventory = e.getValue().cachedInventory;
+ final boolean[] cacheChanged = e.getValue().cacheChanged;
+ Inventory inventory = ((InventoryHolder) e.getKey().getState()).getInventory();//.setContents();
+ for (int i = 0; i < cachedInventory.length; i++) {
+ if (cacheChanged[i]) {
+ inventory.setItem(i, cachedInventory[i]);
+ }
+ }
+
+ Nms.getImplementations().getWorld().updateAdjacentComparators(e.getKey());
+ });
+ INVENTORY_CACHE.clear();
+ }
+
+ public static class Cache {
+ public final Material type;
+ public final Block block;
+ public ItemStack[] cachedInventory;
+ public boolean[] cacheChanged;
+ public int[] cacheAdded;
+ public boolean dirty;
+
+ public Cache(Material type, ItemStack[] cachedInventory) {
+ this.block = null;
+ this.type = type;
+ this.cachedInventory = cachedInventory;
+ this.cacheChanged = new boolean[cachedInventory.length];
+ this.cacheAdded = new int[cachedInventory.length];
+ }
+
+ public Cache(Block block, ItemStack[] cachedInventory) {
+ this.block = block;
+ this.type = block.getType();
+ this.cachedInventory = cachedInventory;
+ this.cacheChanged = new boolean[cachedInventory.length];
+ this.cacheAdded = new int[cachedInventory.length];
+ }
+
+ public void setDirty(boolean dirty) {
+ this.dirty = dirty;
+ }
+
+ public boolean isDirty() {
+ return this.dirty;
+ }
+
+ public void setContents(ItemStack[] items) {
+ if (this.cachedInventory == null || items.length == this.cachedInventory.length) {
+ this.cachedInventory = items;
+ for (int i = 0; i < this.cachedInventory.length; i++) {
+ this.cacheChanged[i] = true;
+ }
+ this.dirty = true;
+ }
+ }
+
+ public void setItem(int item, ItemStack itemStack) {
+ if (this.cachedInventory != null) {
+ this.cachedInventory[item] = itemStack;
+ this.cacheChanged[item] = true;
+ this.dirty = true;
+ }
+ }
+
+ public void removeItem(int item) {
+ if (this.cachedInventory != null) {
+ this.cachedInventory[item] = null;
+ this.cacheChanged[item] = true;
+ this.dirty = true;
+ }
+ }
+
+ public void removeItems(ItemStack item) {
+ if (this.cachedInventory != null && item != null) {
+ int toRemove = item.getAmount();
+ for (int i = 0; toRemove > 0 && i < this.cachedInventory.length; i++) {
+ final ItemStack cacheItem = this.cachedInventory[i];
+ if (cacheItem != null && cacheItem.getAmount() != 0 && item.isSimilar(cacheItem)) {
+ int have = cacheItem.getAmount();
+ if (have > toRemove) {
+ this.cachedInventory[i].setAmount(have - toRemove);
+ this.cacheChanged[i] = true;
+ toRemove = 0;
+ } else {
+ this.cachedInventory[i] = null;
+ this.cacheChanged[i] = true;
+ toRemove -= have;
+ }
+ }
+ }
+ this.dirty = this.dirty | (toRemove != item.getAmount());
+ }
+ }
+
+ /**
+ * Add a number of items to this container's inventory later.
+ *
+ * @param item item to add
+ * @param amountToAdd how many of this item to attempt to add
+ * @return how many items were added
+ */
+ public int addAny(ItemStack item, int amountToAdd) {
+ // Don't transfer shulker boxes into other shulker boxes, that's a bad idea.
+ if (this.type.name().contains("SHULKER_BOX") && item.getType().name().contains("SHULKER_BOX")) {
+ return 0;
+ }
+
+ int totalAdded = 0;
+ if (this.cachedInventory != null && item != null) {
+ final int maxStack = item.getMaxStackSize();
+ for (int i = 0; amountToAdd > 0 && i < this.cachedInventory.length; i++) {
+ final ItemStack cacheItem = this.cachedInventory[i];
+ if (cacheItem == null || cacheItem.getAmount() == 0) {
+ // free slot!
+ int toAdd = Math.min(maxStack, amountToAdd);
+ this.cachedInventory[i] = item.clone();
+ this.cachedInventory[i].setAmount(toAdd);
+ this.cacheChanged[i] = true;
+ this.cacheAdded[i] = toAdd;
+ totalAdded += toAdd;
+ amountToAdd -= toAdd;
+ } else if (maxStack > cacheItem.getAmount() && item.isSimilar(cacheItem)) {
+ // free space!
+ int toAdd = Math.min(maxStack - cacheItem.getAmount(), amountToAdd);
+ this.cachedInventory[i].setAmount(toAdd + cacheItem.getAmount());
+ this.cacheChanged[i] = true;
+ this.cacheAdded[i] += toAdd;
+ totalAdded += toAdd;
+ amountToAdd -= toAdd;
+ }
+ }
+ if (totalAdded != 0) {
+ this.dirty = true;
+ }
+ }
+ return totalAdded;
+ }
+
+ /**
+ * Add an item to this container's inventory later.
+ *
+ * @param item item to add
+ * @return true if the item was added
+ */
+ public boolean addItem(ItemStack item) {
+ if (this.cachedInventory == null || item == null || item.getAmount() <= 0) {
+ return false;
+ }
+
+ // Don't transfer shulker boxes into other shulker boxes, that's a bad idea.
+ if (this.type.name().contains("SHULKER_BOX") && item.getType().name().contains("SHULKER_BOX")) {
+ return false;
+ }
+
+ // grab the amount to move and the max item stack size
+ int toAdd = item.getAmount();
+ final int maxStack = item.getMaxStackSize();
+ boolean[] check = null;
+
+ // some destination containers have special conditions
+ switch (CompatibleMaterial.getMaterial(this.type).orElse(XMaterial.AIR)) {
+ case BREWING_STAND: {
+ // first compile a list of what slots to check
+ check = new boolean[5];
+ String typeStr = item.getType().name().toUpperCase();
+ if (typeStr.contains("POTION") || typeStr.contains("BOTTLE")) {
+ // potion bottles are the first three slots
+ check[0] = check[1] = check[2] = true;
+ }
+ // fuel in 5th position, input in 4th
+ if (item.getType() == Material.BLAZE_POWDER) {
+ check[4] = true;
+ } else if (CompatibleMaterial.isBrewingStandIngredient(CompatibleMaterial.getMaterial(item.getType()).get())) {
+ check[3] = true;
+ }
+
+ break;
+ }
+
+ case SMOKER:
+ case BLAST_FURNACE:
+ case FURNACE: {
+ check = new boolean[3];
+
+ boolean isFuel = !item.getType().name().contains("LOG") && CompatibleMaterial.isFurnaceFuel(CompatibleMaterial.getMaterial(item.getType()).get());
+ // fuel is 2nd slot, input is first
+ if (isFuel) {
+ check[1] = true;
+ } else {
+ check[0] = true;
+ }
+
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ // we can reduce calls to ItemStack.isSimilar() by caching what cells to look at
+ if (check == null) {
+ check = new boolean[this.cachedInventory.length];
+ for (int i = 0; toAdd > 0 && i < check.length; i++) {
+ check[i] = true;
+ }
+ }
+
+ // first verify that we can add this item
+ for (int i = 0; toAdd > 0 && i < this.cachedInventory.length; i++) {
+ if (check[i]) {
+ final ItemStack cacheItem = this.cachedInventory[i];
+ if (cacheItem == null || cacheItem.getAmount() == 0) {
+ // free slot!
+ toAdd -= Math.min(maxStack, toAdd);
+ check[i] = true;
+ } else if (maxStack > cacheItem.getAmount() && item.isSimilar(cacheItem)) {
+ // free space!
+ toAdd -= Math.min(maxStack - cacheItem.getAmount(), toAdd);
+ check[i] = true;
+ } else {
+ check[i] = false;
+ }
+ }
+ }
+ if (toAdd <= 0) {
+ // all good to add!
+ toAdd = item.getAmount();
+ for (int i = 0; toAdd > 0 && i < this.cachedInventory.length; i++) {
+ if (!check[i]) {
+ continue;
+ }
+ final ItemStack cacheItem = this.cachedInventory[i];
+ if (cacheItem == null || cacheItem.getAmount() == 0) {
+ // free slot!
+ int adding = Math.min(maxStack, toAdd);
+ this.cachedInventory[i] = item.clone();
+ this.cachedInventory[i].setAmount(adding);
+ this.cacheChanged[i] = true;
+ this.cacheAdded[i] = adding;
+ toAdd -= adding;
+ } else if (maxStack > cacheItem.getAmount()) {
+ // free space!
+ // (no need to check item.isSimilar(cacheItem), since we have that cached in check[])
+ int adding = Math.min(maxStack - cacheItem.getAmount(), toAdd);
+ this.cachedInventory[i].setAmount(adding + cacheItem.getAmount());
+ this.cacheChanged[i] = true;
+ this.cacheAdded[i] += adding;
+ toAdd -= adding;
+ }
+ }
+ this.dirty = true;
+ return true;
+ }
+ return false;
+ }
+ }
+}
diff --git a/EpicHoppers-Plugin/pom.xml b/EpicHoppers-Plugin/pom.xml
new file mode 100644
index 0000000..56ad744
--- /dev/null
+++ b/EpicHoppers-Plugin/pom.xml
@@ -0,0 +1,182 @@
+
+
+ 4.0.0
+
+
+ com.craftaro
+ EpicHoppers-Parent
+ 5.0.1
+ ../pom.xml
+
+ EpicHoppers-Plugin
+
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 3.4.1
+
+
+
+ package
+
+ shade
+
+
+
+ ${project.parent.name}-${project.version}
+
+ false
+ true
+ true
+
+
+
+ com.craftaro.core
+ com.craftaro.epichoppers.core
+
+
+
+
+
+ *:*
+
+
+ META-INF/**
+ LICENSE
+ LICENSE.**
+
+
+
+
+ com.craftaro:CraftaroCore
+ false
+
+ **/nms/v*/**
+
+
+ **/third_party/org/apache/**
+ **/third_party/net/kyori/**
+ **/third_party/com/zaxxer/**
+ **/third_party/org/jooq/**
+ **/third_party/org/mariadb/**
+ **/third_party/com/h2database/**
+ **/third_party/org/h2/**
+ **/third_party/com/cryptomorin/**
+ **/third_party/org/reactivestreams/**
+
+
+
+
+
+
+
+
+
+
+
+ src/main/resources
+ true
+
+
+
+
+
+
+ rosewood-repo
+ https://repo.rosewooddev.io/repository/public/
+
+
+
+ public
+ https://repo.songoda.com/repository/public/
+
+
+
+ jitpack.io
+ https://jitpack.io/
+
+
+
+
+
+ com.craftaro
+ EpicHoppers-API
+ 1.0.0-SNAPSHOT
+ compile
+
+
+
+ com.craftaro
+ CraftaroCore
+ ${craftaro.coreVersion}
+ compile
+
+
+
+ org.spigotmc
+ spigot-api
+ 1.19.4-R0.1-SNAPSHOT
+ provided
+
+
+
+ com.craftaro
+ FabledSkyBlock
+ 3.0.4
+ provided
+
+
+
+ com.craftaro
+ EpicFarming
+ 4.1.1
+ provided
+
+
+
+ com.github.brcdev-minecraft
+ shopgui-api
+ 2.2.0
+ provided
+
+
+
+ com.github.Gypopo
+ EconomyShopGUI-API
+ 1.4.0
+ provided
+
+
+
+ com.craftaro
+ UltimateStacker-API
+ 1.0.0-SNAPSHOT
+ provided
+
+
+
+ com.bgsoftware
+ wildstacker
+ 3.5.1
+ provided
+
+
+
+ dev.rosewood
+ rosestacker
+ 1.5.11
+ provided
+
+
+
+ com.github.DeadSilenceIV
+ AdvancedChestsAPI
+ 2.2
+ provided
+
+
+
diff --git a/EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/EpicHoppers.java b/EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/EpicHoppers.java
new file mode 100644
index 0000000..406af72
--- /dev/null
+++ b/EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/EpicHoppers.java
@@ -0,0 +1,289 @@
+package com.craftaro.epichoppers;
+
+import com.craftaro.core.SongodaCore;
+import com.craftaro.core.SongodaPlugin;
+import com.craftaro.core.commands.CommandManager;
+import com.craftaro.core.configuration.Config;
+import com.craftaro.core.database.DatabaseConnector;
+import com.craftaro.core.gui.GuiManager;
+import com.craftaro.core.hooks.EconomyManager;
+import com.craftaro.core.hooks.ProtectionManager;
+import com.craftaro.third_party.com.cryptomorin.xseries.XMaterial;
+import com.craftaro.core.third_party.de.tr7zw.nbtapi.NBTItem;
+import com.craftaro.core.utils.TextUtils;
+import com.craftaro.epichoppers.boost.BoostDataImpl;
+import com.craftaro.epichoppers.boost.BoostManager;
+import com.craftaro.epichoppers.boost.BoostManagerImpl;
+import com.craftaro.epichoppers.commands.CommandBoost;
+import com.craftaro.epichoppers.commands.CommandGive;
+import com.craftaro.epichoppers.commands.CommandReload;
+import com.craftaro.epichoppers.commands.CommandSettings;
+import com.craftaro.epichoppers.containers.ContainerManager;
+import com.craftaro.epichoppers.containers.ContainerManagerImpl;
+import com.craftaro.epichoppers.database.migrations._1_InitialMigration;
+import com.craftaro.epichoppers.hopper.HopperImpl;
+import com.craftaro.epichoppers.hopper.HopperManager;
+import com.craftaro.epichoppers.hopper.levels.Level;
+import com.craftaro.epichoppers.hopper.levels.LevelManager;
+import com.craftaro.epichoppers.hopper.levels.LevelManagerImpl;
+import com.craftaro.epichoppers.hopper.levels.modules.Module;
+import com.craftaro.epichoppers.hopper.levels.modules.ModuleAutoCrafting;
+import com.craftaro.epichoppers.hopper.levels.modules.ModuleAutoSell;
+import com.craftaro.epichoppers.hopper.levels.modules.ModuleAutoSmelter;
+import com.craftaro.epichoppers.hopper.levels.modules.ModuleBlockBreak;
+import com.craftaro.epichoppers.hopper.levels.modules.ModuleMobHopper;
+import com.craftaro.epichoppers.hopper.levels.modules.ModuleSuction;
+import com.craftaro.epichoppers.hopper.teleport.TeleportHandler;
+import com.craftaro.epichoppers.listeners.BlockListeners;
+import com.craftaro.epichoppers.listeners.EntityListeners;
+import com.craftaro.epichoppers.listeners.HopperListeners;
+import com.craftaro.epichoppers.listeners.InteractListeners;
+import com.craftaro.epichoppers.listeners.InventoryListeners;
+import com.craftaro.epichoppers.player.PlayerDataManager;
+import com.craftaro.epichoppers.player.PlayerDataManagerImpl;
+import com.craftaro.epichoppers.settings.Settings;
+import com.craftaro.epichoppers.tasks.HopTask;
+import com.craftaro.epichoppers.utils.Methods;
+import com.craftaro.epichoppers.hopper.teleport.TeleportHandlerImpl;
+import com.craftaro.skyblock.SkyBlock;
+import com.craftaro.skyblock.permission.BasicPermission;
+import org.bukkit.Bukkit;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.bukkit.plugin.PluginManager;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public class EpicHoppers extends SongodaPlugin {
+ private final GuiManager guiManager = new GuiManager(this);
+ private final Config levelsConfig = new Config(this, "levels.yml");
+ private HopperManager hopperManager;
+ private CommandManager commandManager;
+ private LevelManager levelManager;
+ private BoostManagerImpl boostManager;
+ private PlayerDataManager playerDataManager;
+ private ContainerManager containerManager;
+
+ private TeleportHandler teleportHandler;
+
+ @Override
+ public void onPluginLoad() {
+ }
+
+ @Override
+ public void onPluginDisable() {
+ getDataManager().shutdown();
+ saveModules();
+ }
+
+ @Override
+ public void onPluginEnable() {
+ SongodaCore.registerPlugin(this, 15, XMaterial.HOPPER);
+
+ // Load Economy
+ EconomyManager.load();
+
+ // Load protection hook
+ ProtectionManager.load(this);
+
+ // Setup Config
+ Settings.setupConfig();
+ this.setLocale(Settings.LANGUGE_MODE.getString(), false);
+
+ // Set Economy & Hologram preference
+ EconomyManager.getManager().setPreferredHook(Settings.ECONOMY_PLUGIN.getString());
+
+ // Register commands
+ this.commandManager = new CommandManager(this);
+ this.commandManager.addMainCommand("eh")
+ .addSubCommands(
+ new CommandBoost(this),
+ new CommandGive(this),
+ new CommandReload(this),
+ new CommandSettings(this)
+ );
+
+ this.hopperManager = new HopperManager(this);
+ this.playerDataManager = new PlayerDataManagerImpl();
+ this.containerManager = new ContainerManagerImpl();
+ this.boostManager = new BoostManagerImpl();
+
+
+ initDatabase(Collections.singletonList(new _1_InitialMigration(this)));
+
+ this.loadLevelManager();
+
+ new HopTask(this);
+ this.teleportHandler = new TeleportHandlerImpl(this);
+
+ // Register Listeners
+ this.guiManager.init();
+ PluginManager pluginManager = Bukkit.getPluginManager();
+ pluginManager.registerEvents(new HopperListeners(this), this);
+ pluginManager.registerEvents(new EntityListeners(), this);
+ pluginManager.registerEvents(new BlockListeners(this), this);
+ pluginManager.registerEvents(new InteractListeners(this), this);
+ pluginManager.registerEvents(new InventoryListeners(), this);
+
+ EpicHoppersApi.initApi(this.levelManager, this.boostManager, this.containerManager, this.teleportHandler, this.playerDataManager);
+
+ // Start auto save
+ int saveInterval = Settings.AUTOSAVE.getInt() * 60 * 20;
+ Bukkit.getScheduler().runTaskTimerAsynchronously(this, this::saveModules, saveInterval, saveInterval);
+
+ // Hotfix for EH loading before FSB
+ Bukkit.getScheduler().runTask(this, () -> {
+ if (pluginManager.isPluginEnabled("FabledSkyBlock")) {
+ try {
+ SkyBlock.getInstance().getPermissionManager().registerPermission(
+ (BasicPermission) Class.forName("com.craftaro.epichoppers.compatibility.EpicHoppersPermission").getDeclaredConstructor().newInstance());
+ } catch (ReflectiveOperationException ex) {
+ ex.printStackTrace();
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onDataLoad() {
+ // Load data from DB
+ this.dataManager.getAsyncPool().execute(() -> {
+ getLogger().info("loading data...");
+ long start = System.currentTimeMillis();
+ this.hopperManager.addHoppers(this.dataManager.loadBatch(HopperImpl.class, "placed_hoppers"));
+ this.boostManager.loadBoosts(this.dataManager.loadBatch(BoostDataImpl.class, "boosted_players"));
+ getLogger().info("Loaded " + hopperManager.getHoppers().size() + " hoppers in " + (System.currentTimeMillis() - start) + "ms");
+ this.hopperManager.setReady();
+ });
+ }
+
+ @Override
+ public void onConfigReload() {
+ this.setLocale(getConfig().getString("System.Language Mode"), true);
+ this.locale.reloadMessages();
+ loadLevelManager();
+ }
+
+ @Override
+ public List getExtraConfig() {
+ return Collections.singletonList(this.levelsConfig);
+ }
+
+ private void loadLevelManager() {
+ if (!new File(this.getDataFolder(), "levels.yml").exists()) {
+ this.saveResource("levels.yml", false);
+ }
+ this.levelsConfig.load();
+
+ // Load an instance of LevelManager
+ this.levelManager = new LevelManagerImpl();
+ /*
+ * Register Levels into LevelManager from configuration.
+ */
+ this.levelManager.clear();
+ for (String levelName : this.levelsConfig.getKeys(false)) {
+ int level = Integer.parseInt(levelName.split("-")[1]);
+
+ ConfigurationSection levels = this.levelsConfig.getConfigurationSection(levelName);
+
+ int radius = levels.getInt("Range");
+ int amount = levels.getInt("Amount");
+ int linkAmount = levels.getInt("Link-amount", 1);
+ boolean filter = levels.getBoolean("Filter");
+ boolean teleport = levels.getBoolean("Teleport");
+ int costExperience = levels.getInt("Cost-xp", -1);
+ int costEconomy = levels.getInt("Cost-eco", -1);
+ int autoSell = levels.getInt("AutoSell");
+
+ ArrayList modules = new ArrayList<>();
+
+ for (String key : levels.getKeys(false)) {
+ if (key.equals("Suction") && levels.getInt("Suction") != 0) {
+ modules.add(new ModuleSuction(this, getGuiManager(), levels.getInt("Suction")));
+ } else if (key.equals("BlockBreak") && levels.getInt("BlockBreak") != 0) {
+ modules.add(new ModuleBlockBreak(this, getGuiManager(), levels.getInt("BlockBreak")));
+ } else if (key.equals("AutoCrafting")) {
+ modules.add(new ModuleAutoCrafting(this, getGuiManager()));
+ } else if (key.equals("AutoSell")) {
+ modules.add(new ModuleAutoSell(this, getGuiManager(), autoSell));
+ } else if (key.equals("MobHopper")) {
+ modules.add(new ModuleMobHopper(this, getGuiManager(), levels.getInt("MobHopper")));
+ } else if (key.equals("AutoSmelting")) {
+ modules.add(new ModuleAutoSmelter(this, getGuiManager(), levels.getInt("AutoSmelting")));
+ }
+ }
+ this.levelManager.addLevel(level, costExperience, costEconomy, radius, amount, filter, teleport, linkAmount, modules);
+ }
+ }
+
+ private void saveModules() {
+ if (this.levelManager != null) {
+ for (Level level : this.levelManager.getLevels().values()) {
+ for (Module module : level.getRegisteredModules()) {
+ module.saveDataToFile();
+ }
+ }
+ }
+ }
+
+ public ItemStack newHopperItem(Level level) {
+ ItemStack item = XMaterial.HOPPER.parseItem();
+ ItemMeta itemmeta = item.getItemMeta();
+ itemmeta.setDisplayName(TextUtils.formatText(Methods.formatName(level.getLevel())));
+ String line = getLocale().getMessage("general.nametag.lore").getMessage();
+ if (!line.isEmpty()) {
+ itemmeta.setLore(Arrays.asList(line.split("\n")));
+ }
+ item.setItemMeta(itemmeta);
+
+ NBTItem nbtItem = new NBTItem(item);
+ nbtItem.setInteger("level", level.getLevel());
+ return nbtItem.getItem();
+ }
+
+ public TeleportHandler getTeleportHandler() {
+ return this.teleportHandler;
+ }
+
+ public BoostManager getBoostManager() {
+ return this.boostManager;
+ }
+
+ public CommandManager getCommandManager() {
+ return this.commandManager;
+ }
+
+ public LevelManager getLevelManager() {
+ return this.levelManager;
+ }
+
+ public HopperManager getHopperManager() {
+ return this.hopperManager;
+ }
+
+ public PlayerDataManager getPlayerDataManager() {
+ return this.playerDataManager;
+ }
+
+ public GuiManager getGuiManager() {
+ return this.guiManager;
+ }
+
+ public ContainerManager getContainerManager() {
+ return this.containerManager;
+ }
+
+
+ /**
+ * @deprecated Use {@link #getPlugin(Class)} instead
+ */
+ @Deprecated
+ public static EpicHoppers getInstance() {
+ return EpicHoppers.getPlugin(EpicHoppers.class);
+ }
+}
diff --git a/EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/boost/BoostDataImpl.java b/EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/boost/BoostDataImpl.java
new file mode 100644
index 0000000..8c2f202
--- /dev/null
+++ b/EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/boost/BoostDataImpl.java
@@ -0,0 +1,92 @@
+package com.craftaro.epichoppers.boost;
+
+import com.craftaro.core.database.Data;
+
+import java.util.Map;
+import java.util.Objects;
+import java.util.UUID;
+
+public class BoostDataImpl implements BoostData, Data {
+ private final int multiplier;
+ private final long endTime;
+ private final UUID player;
+
+ public BoostDataImpl() {
+ this.multiplier = 0;
+ this.endTime = 0;
+ this.player = null;
+ }
+
+ public BoostDataImpl(Map map) {
+ this.multiplier = (int) map.get("multiplier");
+ this.endTime = (long) map.get("end_time");
+ this.player = UUID.fromString((String) map.get("player"));
+ }
+
+ public BoostDataImpl(int multiplier, long endTime, UUID player) {
+ this.multiplier = multiplier;
+ this.endTime = endTime;
+ this.player = player;
+ }
+
+ public int getMultiplier() {
+ return this.multiplier;
+ }
+
+ public UUID getPlayer() {
+ return this.player;
+ }
+
+ public long getEndTime() {
+ return this.endTime;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 31 * this.multiplier;
+
+ result = 31 * result + (this.player == null ? 0 : this.player.hashCode());
+ result = 31 * result + (int) (this.endTime ^ (this.endTime >>> 32));
+
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof BoostDataImpl)) {
+ return false;
+ }
+
+ BoostDataImpl other = (BoostDataImpl) obj;
+ return this.multiplier == other.multiplier &&
+ this.endTime == other.endTime &&
+ Objects.equals(this.player, other.player);
+ }
+
+ @Override
+ public UUID getUniqueId() {
+ return player;
+ }
+
+ @Override
+ public Map serialize() {
+ Map map = new java.util.HashMap<>();
+ map.put("player", player.toString());
+ map.put("multiplier", multiplier);
+ map.put("end_time", endTime);
+ return map;
+ }
+
+ @Override
+ public Data deserialize(Map map) {
+ return new BoostDataImpl(map);
+ }
+
+ @Override
+ public String getTableName() {
+ return "player_boosts";
+ }
+}
diff --git a/src/main/java/com/songoda/epichoppers/boost/BoostManager.java b/EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/boost/BoostManagerImpl.java
similarity index 59%
rename from src/main/java/com/songoda/epichoppers/boost/BoostManager.java
rename to EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/boost/BoostManagerImpl.java
index 63951d5..f39e565 100644
--- a/src/main/java/com/songoda/epichoppers/boost/BoostManager.java
+++ b/EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/boost/BoostManagerImpl.java
@@ -1,34 +1,48 @@
-package com.songoda.epichoppers.boost;
+package com.craftaro.epichoppers.boost;
+import com.craftaro.core.database.Data;
+
+import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
-public class BoostManager {
-
+public class BoostManagerImpl implements BoostManager {
private final Set registeredBoosts = new HashSet<>();
+ @Override
public void addBoostToPlayer(BoostData data) {
this.registeredBoosts.add(data);
}
+ @Override
public void removeBoostFromPlayer(BoostData data) {
this.registeredBoosts.remove(data);
}
+ @Override
public void addBoosts(List boosts) {
- registeredBoosts.addAll(boosts);
+ this.registeredBoosts.addAll(boosts);
}
+ public void loadBoosts(Collection boosts) {
+ this.registeredBoosts.addAll(boosts);
+ }
+
+ @Override
public Set getBoosts() {
- return Collections.unmodifiableSet(registeredBoosts);
+ return Collections.unmodifiableSet(this.registeredBoosts);
}
+ @Override
public BoostData getBoost(UUID player) {
- if (player == null) return null;
- for (BoostData boostData : registeredBoosts) {
+ if (player == null) {
+ return null;
+ }
+
+ for (BoostData boostData : this.registeredBoosts) {
if (boostData.getPlayer().toString().equals(player.toString())) {
if (System.currentTimeMillis() >= boostData.getEndTime()) {
removeBoostFromPlayer(boostData);
diff --git a/src/main/java/com/songoda/epichoppers/commands/CommandBoost.java b/EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/commands/CommandBoost.java
similarity index 60%
rename from src/main/java/com/songoda/epichoppers/commands/CommandBoost.java
rename to EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/commands/CommandBoost.java
index 9fdc059..829d784 100644
--- a/src/main/java/com/songoda/epichoppers/commands/CommandBoost.java
+++ b/EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/commands/CommandBoost.java
@@ -1,19 +1,20 @@
-package com.songoda.epichoppers.commands;
+package com.craftaro.epichoppers.commands;
-import com.songoda.core.commands.AbstractCommand;
-import com.songoda.epichoppers.EpicHoppers;
-import com.songoda.epichoppers.boost.BoostData;
-import com.songoda.epichoppers.utils.Methods;
+import com.craftaro.core.commands.AbstractCommand;
+import com.craftaro.core.utils.NumberUtils;
+import com.craftaro.core.utils.TimeUtils;
+import com.craftaro.epichoppers.boost.BoostDataImpl;
+import com.craftaro.epichoppers.EpicHoppers;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
public class CommandBoost extends AbstractCommand {
-
private final EpicHoppers plugin;
public CommandBoost(EpicHoppers plugin) {
@@ -24,11 +25,11 @@ public class CommandBoost extends AbstractCommand {
@Override
protected ReturnType runCommand(CommandSender sender, String... args) {
if (args.length < 2) {
- plugin.getLocale().newMessage("&7Syntax error...").sendPrefixedMessage(sender);
+ this.plugin.getLocale().newMessage("&7Syntax error...").sendPrefixedMessage(sender);
return ReturnType.SYNTAX_ERROR;
}
- if (!Methods.isInt(args[1])) {
- plugin.getLocale().newMessage("&6" + args[1] + " &7is not a number...").sendPrefixedMessage(sender);
+ if (!NumberUtils.isInt(args[1])) {
+ this.plugin.getLocale().newMessage("&6" + args[1] + " &7is not a number...").sendPrefixedMessage(sender);
return ReturnType.SYNTAX_ERROR;
}
@@ -36,7 +37,7 @@ public class CommandBoost extends AbstractCommand {
if (args.length > 2) {
for (String line : args) {
- long time = Methods.parseTime(line);
+ long time = TimeUtils.parseTime(line);
duration += time;
}
@@ -44,14 +45,14 @@ public class CommandBoost extends AbstractCommand {
Player player = Bukkit.getPlayer(args[0]);
if (player == null) {
- plugin.getLocale().newMessage("&cThat player does not exist or is not online...").sendPrefixedMessage(sender);
+ this.plugin.getLocale().newMessage("&cThat player does not exist or is not online...").sendPrefixedMessage(sender);
return ReturnType.FAILURE;
}
- BoostData boostData = new BoostData(Integer.parseInt(args[1]), duration == 0L ? Long.MAX_VALUE : System.currentTimeMillis() + duration, player.getUniqueId());
- plugin.getBoostManager().addBoostToPlayer(boostData);
- plugin.getLocale().newMessage("&7Successfully boosted &6" + Bukkit.getPlayer(args[0]).getName()
- + "'s &7hopper transfer rates by &6" + args[1] + "x" + (duration == 0L ? "" : (" for " + Methods.makeReadable(duration))) + "&7.").sendPrefixedMessage(sender);
+ BoostDataImpl boostData = new BoostDataImpl(Integer.parseInt(args[1]), duration == 0L ? Long.MAX_VALUE : System.currentTimeMillis() + duration, player.getUniqueId());
+ this.plugin.getBoostManager().addBoostToPlayer(boostData);
+ this.plugin.getLocale().newMessage("&7Successfully boosted &6" + Bukkit.getPlayer(args[0]).getName()
+ + "'s &7hopper transfer rates by &6" + args[1] + "x" + (duration == 0L ? "" : (" for " + TimeUtils.makeReadable(duration))) + "&7.").sendPrefixedMessage(sender);
return ReturnType.SUCCESS;
}
@@ -68,7 +69,8 @@ public class CommandBoost extends AbstractCommand {
} else if (args.length == 3) {
return Arrays.asList("1m", "1h", "1d");
}
- return null;
+
+ return Collections.emptyList();
}
@Override
diff --git a/src/main/java/com/songoda/epichoppers/commands/CommandGive.java b/EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/commands/CommandGive.java
similarity index 61%
rename from src/main/java/com/songoda/epichoppers/commands/CommandGive.java
rename to EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/commands/CommandGive.java
index b16d91a..3f71613 100644
--- a/src/main/java/com/songoda/epichoppers/commands/CommandGive.java
+++ b/EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/commands/CommandGive.java
@@ -1,8 +1,8 @@
-package com.songoda.epichoppers.commands;
+package com.craftaro.epichoppers.commands;
-import com.songoda.core.commands.AbstractCommand;
-import com.songoda.epichoppers.EpicHoppers;
-import com.songoda.epichoppers.hopper.levels.Level;
+import com.craftaro.core.commands.AbstractCommand;
+import com.craftaro.epichoppers.EpicHoppers;
+import com.craftaro.epichoppers.hopper.levels.Level;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@@ -12,7 +12,6 @@ import java.util.Arrays;
import java.util.List;
public class CommandGive extends AbstractCommand {
-
private final EpicHoppers plugin;
public CommandGive(EpicHoppers plugin) {
@@ -26,29 +25,29 @@ public class CommandGive extends AbstractCommand {
return ReturnType.SYNTAX_ERROR;
}
if (Bukkit.getPlayerExact(args[0]) == null) {
- plugin.getLocale().newMessage("&cThat username does not exist, or the user is not online!").sendPrefixedMessage(sender);
+ this.plugin.getLocale().newMessage("&cThat username does not exist, or the user is not online!").sendPrefixedMessage(sender);
return ReturnType.FAILURE;
}
- Level level = plugin.getLevelManager().getLowestLevel();
+ Level level = this.plugin.getLevelManager().getLowestLevel();
Player player;
if (Bukkit.getPlayer(args[0]) == null) {
- plugin.getLocale().newMessage("&cThat player does not exist or is currently offline.").sendPrefixedMessage(sender);
+ this.plugin.getLocale().newMessage("&cThat player does not exist or is currently offline.").sendPrefixedMessage(sender);
return ReturnType.FAILURE;
} else {
player = Bukkit.getPlayer(args[0]);
}
- if (!plugin.getLevelManager().isLevel(Integer.parseInt(args[1]))) {
- plugin.getLocale().newMessage("&cNot a valid level... The current valid levels are: &4" + level.getLevel() + "-" + plugin.getLevelManager().getHighestLevel().getLevel() + "&c.")
+ if (!this.plugin.getLevelManager().isLevel(Integer.parseInt(args[1]))) {
+ this.plugin.getLocale().newMessage("&cNot a valid level... The current valid levels are: &4" + level.getLevel() + "-" + this.plugin.getLevelManager().getHighestLevel().getLevel() + "&c.")
.sendPrefixedMessage(sender);
return ReturnType.FAILURE;
} else {
- level = plugin.getLevelManager().getLevel(Integer.parseInt(args[1]));
+ level = this.plugin.getLevelManager().getLevel(Integer.parseInt(args[1]));
}
- player.getInventory().addItem(plugin.newHopperItem(level));
- plugin.getLocale().getMessage("command.give.success").processPlaceholder("level", level.getLevel()).sendPrefixedMessage(player);
+ player.getInventory().addItem(this.plugin.newHopperItem(level));
+ this.plugin.getLocale().getMessage("command.give.success").processPlaceholder("level", level.getLevel()).sendPrefixedMessage(player);
return ReturnType.SUCCESS;
}
diff --git a/src/main/java/com/songoda/epichoppers/commands/CommandReload.java b/EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/commands/CommandReload.java
similarity index 73%
rename from src/main/java/com/songoda/epichoppers/commands/CommandReload.java
rename to EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/commands/CommandReload.java
index 2a30d9d..91af4f7 100644
--- a/src/main/java/com/songoda/epichoppers/commands/CommandReload.java
+++ b/EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/commands/CommandReload.java
@@ -1,13 +1,12 @@
-package com.songoda.epichoppers.commands;
+package com.craftaro.epichoppers.commands;
-import com.songoda.core.commands.AbstractCommand;
-import com.songoda.epichoppers.EpicHoppers;
+import com.craftaro.core.commands.AbstractCommand;
+import com.craftaro.epichoppers.EpicHoppers;
import org.bukkit.command.CommandSender;
import java.util.List;
public class CommandReload extends AbstractCommand {
-
private final EpicHoppers plugin;
public CommandReload(EpicHoppers plugin) {
@@ -17,8 +16,8 @@ public class CommandReload extends AbstractCommand {
@Override
protected ReturnType runCommand(CommandSender sender, String... args) {
- plugin.reloadConfig();
- plugin.getLocale().getMessage("&7Configuration and Language files reloaded.").sendPrefixedMessage(sender);
+ this.plugin.reloadConfig();
+ this.plugin.getLocale().getMessage("&7Configuration and Language files reloaded.").sendPrefixedMessage(sender);
return ReturnType.SUCCESS;
}
diff --git a/src/main/java/com/songoda/epichoppers/commands/CommandSettings.java b/EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/commands/CommandSettings.java
similarity index 74%
rename from src/main/java/com/songoda/epichoppers/commands/CommandSettings.java
rename to EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/commands/CommandSettings.java
index de4c3b3..b9eeffe 100644
--- a/src/main/java/com/songoda/epichoppers/commands/CommandSettings.java
+++ b/EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/commands/CommandSettings.java
@@ -1,15 +1,14 @@
-package com.songoda.epichoppers.commands;
+package com.craftaro.epichoppers.commands;
-import com.songoda.core.commands.AbstractCommand;
-import com.songoda.core.configuration.editor.PluginConfigGui;
-import com.songoda.epichoppers.EpicHoppers;
+import com.craftaro.core.commands.AbstractCommand;
+import com.craftaro.core.configuration.editor.PluginConfigGui;
+import com.craftaro.epichoppers.EpicHoppers;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.List;
public class CommandSettings extends AbstractCommand {
-
private final EpicHoppers plugin;
public CommandSettings(EpicHoppers plugin) {
@@ -19,7 +18,7 @@ public class CommandSettings extends AbstractCommand {
@Override
protected ReturnType runCommand(CommandSender sender, String... args) {
- plugin.getGuiManager().showGUI((Player) sender, new PluginConfigGui(plugin));
+ this.plugin.getGuiManager().showGUI((Player) sender, new PluginConfigGui(this.plugin));
return ReturnType.SUCCESS;
}
diff --git a/EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/compatibility/EpicHoppersPermission.java b/EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/compatibility/EpicHoppersPermission.java
new file mode 100644
index 0000000..8aeda18
--- /dev/null
+++ b/EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/compatibility/EpicHoppersPermission.java
@@ -0,0 +1,11 @@
+package com.craftaro.epichoppers.compatibility;
+
+import com.craftaro.skyblock.permission.BasicPermission;
+import com.craftaro.skyblock.permission.PermissionType;
+import com.craftaro.third_party.com.cryptomorin.xseries.XMaterial;
+
+public class EpicHoppersPermission extends BasicPermission {
+ public EpicHoppersPermission() {
+ super("EpicHoppers", XMaterial.HOPPER, PermissionType.GENERIC);
+ }
+}
diff --git a/src/main/java/com/songoda/epichoppers/containers/ContainerManager.java b/EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/containers/ContainerManagerImpl.java
similarity index 63%
rename from src/main/java/com/songoda/epichoppers/containers/ContainerManager.java
rename to EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/containers/ContainerManagerImpl.java
index 96ed170..04c4655 100644
--- a/src/main/java/com/songoda/epichoppers/containers/ContainerManager.java
+++ b/EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/containers/ContainerManagerImpl.java
@@ -1,9 +1,8 @@
-package com.songoda.epichoppers.containers;
+package com.craftaro.epichoppers.containers;
-import com.songoda.epichoppers.EpicHoppers;
-import com.songoda.epichoppers.containers.impl.AdvancedChestImplementation;
-import com.songoda.epichoppers.containers.impl.EpicFarmingImplementation;
-import com.songoda.epichoppers.containers.impl.FabledSkyBlockImplementation;
+import com.craftaro.epichoppers.containers.impl.AdvancedChestImpl;
+import com.craftaro.epichoppers.containers.impl.EpicFarmingImpl;
+import com.craftaro.epichoppers.containers.impl.FabledSkyBlockImpl;
import org.bukkit.Bukkit;
import org.bukkit.block.Block;
import org.bukkit.plugin.PluginManager;
@@ -12,37 +11,38 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
-public class ContainerManager {
-
- private final EpicHoppers plugin;
+public class ContainerManagerImpl implements ContainerManager {
private final Set customContainers;
- public ContainerManager(EpicHoppers plugin) {
- this.plugin = plugin;
+ public ContainerManagerImpl() {
this.customContainers = new HashSet<>();
- registerCustomContainerImplementation("AdvancedChests", new AdvancedChestImplementation());
- registerCustomContainerImplementation("EpicFarming", new EpicFarmingImplementation());
- registerCustomContainerImplementation("FabledSkyBlock", new FabledSkyBlockImplementation());
+ registerCustomContainerImplementation("AdvancedChests", new AdvancedChestImpl());
+ registerCustomContainerImplementation("EpicFarming", new EpicFarmingImpl());
+ registerCustomContainerImplementation("FabledSkyBlock", new FabledSkyBlockImpl());
}
+ @Override
public Set getCustomContainerImplementations() {
- return Collections.unmodifiableSet(customContainers);
+ return Collections.unmodifiableSet(this.customContainers);
}
+ @Override
public void registerCustomContainerImplementation(String requiredPlugin, IContainer container) {
PluginManager pluginManager = Bukkit.getPluginManager();
if (requiredPlugin != null && pluginManager.isPluginEnabled(requiredPlugin)) {
- customContainers.add(container);
+ this.customContainers.add(container);
}
}
+ @Override
public void registerCustomContainerImplementation(IContainer container) {
registerCustomContainerImplementation(null, container);
}
+ @Override
public CustomContainer getCustomContainer(Block block) {
- for (IContainer container : customContainers) {
+ for (IContainer container : this.customContainers) {
CustomContainer customContainer = container.getCustomContainer(block);
if (customContainer.isContainer()) {
return customContainer;
diff --git a/src/main/java/com/songoda/epichoppers/containers/impl/AdvancedChestImplementation.java b/EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/containers/impl/AdvancedChestImpl.java
similarity index 58%
rename from src/main/java/com/songoda/epichoppers/containers/impl/AdvancedChestImplementation.java
rename to EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/containers/impl/AdvancedChestImpl.java
index 869b7e6..487531c 100644
--- a/src/main/java/com/songoda/epichoppers/containers/impl/AdvancedChestImplementation.java
+++ b/EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/containers/impl/AdvancedChestImpl.java
@@ -1,46 +1,48 @@
-package com.songoda.epichoppers.containers.impl;
+package com.craftaro.epichoppers.containers.impl;
-import com.songoda.epichoppers.containers.CustomContainer;
-import com.songoda.epichoppers.containers.IContainer;
+import com.craftaro.epichoppers.containers.CustomContainer;
+import com.craftaro.epichoppers.containers.IContainer;
import org.bukkit.block.Block;
import org.bukkit.inventory.ItemStack;
import us.lynuxcraft.deadsilenceiv.advancedchests.AdvancedChestsAPI;
import us.lynuxcraft.deadsilenceiv.advancedchests.chest.AdvancedChest;
-public class AdvancedChestImplementation implements IContainer {
-
+public class AdvancedChestImpl implements IContainer {
@Override
public CustomContainer getCustomContainer(Block block) {
return new Container(block);
}
- class Container extends CustomContainer {
+ static class Container extends CustomContainer {
private final AdvancedChest advancedChest;
public Container(Block block) {
- super(block);
this.advancedChest = AdvancedChestsAPI.getChestManager().getAdvancedChest(block.getLocation());
}
@Override
public boolean addToContainer(ItemStack itemToMove) {
- return AdvancedChestsAPI.addItemToChest(advancedChest, itemToMove);
+ return AdvancedChestsAPI.addItemToChest(this.advancedChest, itemToMove);
}
@Override
public ItemStack[] getItems() {
- return advancedChest.getAllItems().toArray(new ItemStack[0]);
+ return this.advancedChest.getAllItems().toArray(new ItemStack[0]);
}
@Override
public void removeFromContainer(ItemStack itemToMove, int amountToMove) {
- for (ItemStack item : advancedChest.getAllItems()) {
- if (item == null) return;
+ for (ItemStack item : this.advancedChest.getAllItems()) {
+ if (item == null) {
+ return;
+ }
+
if (itemToMove.getType() == item.getType()) {
item.setAmount(item.getAmount() - amountToMove);
- if (item.getAmount() <= 0)
- advancedChest.getAllItems().remove(item);
+ if (item.getAmount() <= 0) {
+ this.advancedChest.getAllItems().remove(item);
+ }
return;
}
}
@@ -48,7 +50,7 @@ public class AdvancedChestImplementation implements IContainer {
@Override
public boolean isContainer() {
- return advancedChest != null;
+ return this.advancedChest != null;
}
}
}
diff --git a/EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/containers/impl/EpicFarmingImpl.java b/EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/containers/impl/EpicFarmingImpl.java
new file mode 100644
index 0000000..0721280
--- /dev/null
+++ b/EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/containers/impl/EpicFarmingImpl.java
@@ -0,0 +1,51 @@
+package com.craftaro.epichoppers.containers.impl;
+
+import com.craftaro.third_party.com.cryptomorin.xseries.XMaterial;
+import com.craftaro.epicfarming.EpicFarming;
+import com.craftaro.epicfarming.core.compatibility.CompatibleMaterial;
+import com.craftaro.epicfarming.farming.Farm;
+import com.craftaro.epichoppers.containers.CustomContainer;
+import com.craftaro.epichoppers.containers.IContainer;
+import org.bukkit.block.Block;
+import org.bukkit.inventory.ItemStack;
+
+public class EpicFarmingImpl implements IContainer {
+ @Override
+ public CustomContainer getCustomContainer(Block block) {
+ return new Container(block);
+ }
+
+ static class Container extends CustomContainer {
+ private final Farm farm;
+
+ public Container(Block block) {
+ this.farm = EpicFarming.getInstance().getFarmManager().getFarm(block);
+ }
+
+ @Override
+ public boolean addToContainer(ItemStack itemToMove) {
+ if (!this.farm.willFit(itemToMove)) {
+ return false;
+ }
+ this.farm.addItem(itemToMove);
+ return true;
+ }
+
+ @Override
+ public ItemStack[] getItems() {
+ return this.farm.getItems()
+ .stream().filter(item -> XMaterial.matchXMaterial(item) != XMaterial.BONE_MEAL)
+ .toArray(ItemStack[]::new);
+ }
+
+ @Override
+ public void removeFromContainer(ItemStack itemToMove, int amountToMove) {
+ this.farm.removeMaterial(itemToMove.getType(), amountToMove);
+ }
+
+ @Override
+ public boolean isContainer() {
+ return this.farm != null;
+ }
+ }
+}
diff --git a/EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/containers/impl/FabledSkyBlockImpl.java b/EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/containers/impl/FabledSkyBlockImpl.java
new file mode 100644
index 0000000..ba46b4b
--- /dev/null
+++ b/EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/containers/impl/FabledSkyBlockImpl.java
@@ -0,0 +1,65 @@
+package com.craftaro.epichoppers.containers.impl;
+
+import com.craftaro.epichoppers.containers.CustomContainer;
+import com.craftaro.epichoppers.containers.IContainer;
+import com.craftaro.skyblock.SkyBlock;
+import com.craftaro.skyblock.core.compatibility.CompatibleMaterial;
+import com.craftaro.skyblock.stackable.Stackable;
+import com.craftaro.skyblock.stackable.StackableManager;
+import com.craftaro.third_party.com.cryptomorin.xseries.XMaterial;
+import org.bukkit.block.Block;
+import org.bukkit.inventory.ItemStack;
+
+public class FabledSkyBlockImpl implements IContainer {
+ @Override
+ public CustomContainer getCustomContainer(Block block) {
+ return new Container(block);
+ }
+
+ static class Container extends CustomContainer {
+ private final Stackable stackable;
+
+ public Container(Block block) {
+ super();
+
+ StackableManager stackableManager = SkyBlock.getInstance().getStackableManager();
+ XMaterial xMaterial = XMaterial.matchXMaterial(block.getType());
+
+ this.stackable = stackableManager.getStack(block.getLocation(), xMaterial);
+ }
+
+ @Override
+ public boolean addToContainer(ItemStack itemToMove) {
+ if (XMaterial.matchXMaterial(itemToMove) != this.stackable.getMaterial()) {
+ return false;
+ }
+
+ this.stackable.addOne();
+ if (this.stackable.getMaxSize() > 0 && this.stackable.isMaxSize()) {
+ this.stackable.setSize(this.stackable.getMaxSize());
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public ItemStack[] getItems() {
+ return new ItemStack[]{new ItemStack(this.stackable.getMaterial().parseMaterial(), this.stackable.getSize())};
+ }
+
+ @Override
+ public void removeFromContainer(ItemStack itemToMove, int amountToMove) {
+ if (XMaterial.matchXMaterial(itemToMove) != this.stackable.getMaterial()) {
+ return;
+ }
+
+ this.stackable.setSize(this.stackable.getSize() - amountToMove);
+ }
+
+ @Override
+ public boolean isContainer() {
+ return this.stackable != null;
+ }
+ }
+}
diff --git a/EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/database/DataManagerImpl.java b/EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/database/DataManagerImpl.java
new file mode 100644
index 0000000..53d222b
--- /dev/null
+++ b/EpicHoppers-Plugin/src/main/java/com/craftaro/epichoppers/database/DataManagerImpl.java
@@ -0,0 +1,378 @@
+package com.craftaro.epichoppers.database;
+
+import com.craftaro.core.database.DatabaseConnector;
+import com.craftaro.epichoppers.boost.BoostData;
+import com.craftaro.epichoppers.boost.BoostDataImpl;
+import com.craftaro.epichoppers.EpicHoppers;
+import com.craftaro.epichoppers.hopper.Filter;
+import com.craftaro.epichoppers.hopper.HopperImpl;
+import com.craftaro.epichoppers.hopper.HopperBuilder;
+import com.craftaro.epichoppers.hopper.ItemType;
+import com.craftaro.epichoppers.hopper.LinkType;
+import com.craftaro.epichoppers.hopper.teleport.TeleportTrigger;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.World;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.plugin.Plugin;
+import org.bukkit.util.io.BukkitObjectInputStream;
+import org.bukkit.util.io.BukkitObjectOutputStream;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.function.Consumer;
+
+public class DataManagerImpl {
+// public DataManagerImpl(DatabaseConnector databaseConnector, Plugin plugin) {
+// super(databaseConnector, plugin);
+// }
+//
+// @Override
+// public void createBoost(BoostDataImpl boostData) {
+// this.runAsync(() -> {
+// try (Connection connection = this.databaseConnector.getConnection()) {
+// String createBoostedPlayer = "INSERT INTO " + this.getTablePrefix() + "boosted_players (player, multiplier, end_time) VALUES (?, ?, ?)";
+// PreparedStatement statement = connection.prepareStatement(createBoostedPlayer);
+// statement.setString(1, boostData.getPlayer().toString());
+// statement.setInt(2, boostData.getMultiplier());
+// statement.setLong(3, boostData.getEndTime());
+// statement.executeUpdate();
+// } catch (Exception ex) {
+// ex.printStackTrace();
+// }
+// });
+// }
+//
+// @Override
+// public void getBoosts(Consumer> callback) {
+// List boosts = new ArrayList<>();
+// this.runAsync(() -> {
+// try (Connection connection = this.databaseConnector.getConnection()) {
+// Statement statement = connection.createStatement();
+// String selectBoostedPlayers = "SELECT * FROM " + this.getTablePrefix() + "boosted_players";
+// ResultSet result = statement.executeQuery(selectBoostedPlayers);
+// while (result.next()) {
+// UUID player = UUID.fromString(result.getString("player"));
+// int multiplier = result.getInt("multiplier");
+// long endTime = result.getLong("end_time");
+// boosts.add(new BoostDataImpl(multiplier, endTime, player));
+// }
+//
+// this.sync(() -> callback.accept(boosts));
+// } catch (Exception ex) {
+// ex.printStackTrace();
+// }
+// });
+// }
+//
+// @Override
+// public void deleteBoost(BoostDataImpl boostData) {
+// this.runAsync(() -> {
+// try (Connection connection = this.databaseConnector.getConnection()) {
+// String deleteBoost = "DELETE FROM " + this.getTablePrefix() + "boosted_players WHERE end_time = ?";
+// PreparedStatement statement = connection.prepareStatement(deleteBoost);
+// statement.setLong(1, boostData.getEndTime());
+// statement.executeUpdate();
+// } catch (Exception ex) {
+// ex.printStackTrace();
+// }
+// });
+// }
+//
+// @Override
+// public void deleteLink(HopperImpl hopper, Location location) {
+// this.runAsync(() -> {
+// try (Connection connection = this.databaseConnector.getConnection()) {
+// String deleteLink = "DELETE FROM " + this.getTablePrefix() + "links WHERE hopper_id = ? AND world = ? AND x = ? AND y = ? AND z = ?";
+// PreparedStatement statement = connection.prepareStatement(deleteLink);
+// statement.setInt(1, hopper.getId());
+// statement.setString(2, location.getWorld().getName());
+// statement.setInt(3, location.getBlockX());
+// statement.setInt(4, location.getBlockY());
+// statement.setInt(5, location.getBlockZ());
+// statement.executeUpdate();
+// } catch (Exception ex) {
+// ex.printStackTrace();
+// }
+// });
+// }
+//
+// @Override
+// public void deleteLinks(HopperImpl hopper) {
+// this.runAsync(() -> {
+// try (Connection connection = this.databaseConnector.getConnection()) {
+// String deleteHopperLinks = "DELETE FROM " + this.getTablePrefix() + "links WHERE hopper_id = ?";
+// PreparedStatement statement = connection.prepareStatement(deleteHopperLinks);
+// statement.setInt(1, hopper.getId());
+// statement.executeUpdate();
+// } catch (Exception ex) {
+// ex.printStackTrace();
+// }
+// });
+// }
+//
+// @Override
+// public void createHoppers(List hoppers) {
+// for (HopperImpl hopper : hoppers) {
+// createHopper(hopper);
+// }
+// }
+//
+// @Override
+// public void createHopper(HopperImpl hopper) {
+// this.runAsync(() -> {
+// try (Connection connection = this.databaseConnector.getConnection()) {
+// String createHopper = "INSERT INTO " + this.getTablePrefix() + "placed_hoppers (level, placed_by, last_opened_by, teleport_trigger, world, x, y, z) VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
+// try (PreparedStatement statement = connection.prepareStatement(createHopper)) {
+// statement.setInt(1, hopper.getLevel().getLevel());
+//
+// statement.setString(2,
+// hopper.getPlacedBy() == null ? null : hopper.getPlacedBy().toString());
+//
+// statement.setString(3,
+// hopper.getLastPlayerOpened() == null ? null : hopper.getLastPlayerOpened().toString());
+//
+// statement.setString(4, hopper.getTeleportTrigger().name());
+//
+// statement.setString(5, hopper.getWorld().getName());
+// statement.setInt(6, hopper.getX());
+// statement.setInt(7, hopper.getY());
+// statement.setInt(8, hopper.getZ());
+// statement.executeUpdate();
+// }
+//
+// int hopperId = this.lastInsertedId(connection, "placed_hoppers");
+// hopper.setId(hopperId);
+//
+// Map items = new HashMap<>();
+// Filter filter = hopper.getFilter();
+//
+// for (ItemStack item : filter.getWhiteList()) {
+// items.put(item, ItemType.WHITELIST);
+// }
+//
+// for (ItemStack item : filter.getBlackList()) {
+// items.put(item, ItemType.BLACKLIST);
+// }
+//
+// for (ItemStack item : filter.getVoidList()) {
+// items.put(item, ItemType.VOID);
+// }
+//
+// for (ItemStack item : filter.getAutoSellWhiteList()) {
+// items.put(item, ItemType.AUTO_SELL_WHITELIST);
+// }
+//
+// for (ItemStack item : filter.getAutoSellBlackList()) {
+// items.put(item, ItemType.AUTO_SELL_BLACKLIST);
+// }
+//
+// String createItem = "INSERT INTO " + this.getTablePrefix() + "items (hopper_id, item_type, item) VALUES (?, ?, ?)";
+// try (PreparedStatement statement = connection.prepareStatement(createItem)) {
+// for (Map.Entry entry : items.entrySet()) {
+// statement.setInt(1, hopper.getId());
+// statement.setString(2, entry.getValue().name());
+//
+// try (ByteArrayOutputStream stream = new ByteArrayOutputStream(); BukkitObjectOutputStream bukkitStream = new BukkitObjectOutputStream(stream)) {
+// bukkitStream.writeObject(entry.getKey());
+// statement.setString(3, Base64.getEncoder().encodeToString(stream.toByteArray()));
+// } catch (IOException e) {
+// e.printStackTrace();
+// continue;
+// }
+// statement.addBatch();
+// }
+// statement.executeBatch();
+// }
+//
+// Map links = new HashMap<>();
+//
+// for (Location location : hopper.getLinkedBlocks()) {
+// links.put(location, LinkType.REGULAR);
+// }
+//
+// if (filter.getEndPoint() != null) {
+// links.put(filter.getEndPoint(), LinkType.REJECT);
+// }
+//
+// String createLink = "INSERT INTO " + this.getTablePrefix() + "links (hopper_id, link_type, world, x, y, z) VALUES (?, ?, ?, ?, ?, ?)";
+// try (PreparedStatement statement = connection.prepareStatement(createLink)) {
+// for (Map.Entry entry : links.entrySet()) {
+// statement.setInt(1, hopper.getId());
+//
+// statement.setString(2, entry.getValue().name());
+//
+// Location location = entry.getKey();
+// statement.setString(3, location.getWorld().getName());
+// statement.setInt(4, location.getBlockX());
+// statement.setInt(5, location.getBlockY());
+// statement.setInt(6, location.getBlockZ());
+// statement.addBatch();
+// }
+// statement.executeBatch();
+// }
+// } catch (Exception ex) {
+// ex.printStackTrace();
+// }
+// });
+// }
+//
+// @Override
+// public void updateHopper(HopperImpl hopper) {
+// this.runAsync(() -> {
+// try (Connection connection = this.databaseConnector.getConnection()) {
+// String updateHopper = "UPDATE " + this.getTablePrefix() + "placed_hoppers SET level = ?, placed_by = ?, last_opened_by = ?, teleport_trigger = ? WHERE id = ?";
+// PreparedStatement statement = connection.prepareStatement(updateHopper);
+// statement.setInt(1, hopper.getLevel().getLevel());
+// statement.setString(2, hopper.getPlacedBy().toString());
+// statement.setString(3, hopper.getLastPlayerOpened().toString());
+// statement.setString(4, hopper.getTeleportTrigger().name());
+// statement.setInt(5, hopper.getId());
+// statement.executeUpdate();
+// } catch (Exception ex) {
+// ex.printStackTrace();
+// }
+// });
+// }
+//
+// @Override
+// public void deleteHopper(HopperImpl hopper) {
+// this.runAsync(() -> {
+// try (Connection connection = this.databaseConnector.getConnection()) {
+// String deleteHopper = "DELETE FROM " + this.getTablePrefix() + "placed_hoppers WHERE id = ?";
+// try (PreparedStatement statement = connection.prepareStatement(deleteHopper)) {
+// statement.setInt(1, hopper.getId());
+// statement.executeUpdate();
+// }
+//
+// String deleteHopperLinks = "DELETE FROM " + this.getTablePrefix() + "links WHERE hopper_id = ?";
+// try (PreparedStatement statement = connection.prepareStatement(deleteHopperLinks)) {
+// statement.setInt(1, hopper.getId());
+// statement.executeUpdate();
+// }
+//
+// String deleteItems = "DELETE FROM " + this.getTablePrefix() + "items WHERE hopper_id = ?";
+// try (PreparedStatement statement = connection.prepareStatement(deleteItems)) {
+// statement.setInt(1, hopper.getId());
+// statement.executeUpdate();
+// }
+// } catch (Exception ex) {
+// ex.printStackTrace();
+// }
+// });
+// }
+//
+// @Override
+// public void getHoppers(Consumer