├── src └── main │ ├── resources │ ├── config.yml │ └── plugin.yml │ └── java │ └── io │ └── ncbpfluffybear │ └── fluffymachines │ ├── utils │ ├── CancelPlace.java │ ├── McMMOEvents.java │ ├── Constants.java │ ├── Utils.java │ └── Events.java │ ├── items │ ├── tools │ │ ├── AlternateBreakEvent.java │ │ ├── UpgradedExplosivePickaxe.java │ │ ├── UpgradedExplosiveShovel.java │ │ ├── ACBUpgradeCard.java │ │ ├── Scythe.java │ │ ├── Paxel.java │ │ ├── UpgradedLumberAxe.java │ │ ├── FluffyWrench.java │ │ ├── WarpPadConfigurator.java │ │ ├── UpgradedExplosiveTool.java │ │ ├── PortableCharger.java │ │ ├── CargoManipulator.java │ │ └── Dolly.java │ ├── HelicopterHat.java │ ├── MiniBarrel.java │ ├── FireproofRune.java │ ├── EnderChestInsertionNode.java │ └── EnderChestExtractionNode.java │ ├── machines │ ├── AutoArmorForge.java │ ├── AutoEnhancedCraftingTable.java │ ├── AutoMagicWorkbench.java │ ├── WarpPad.java │ ├── ElectricDustRecycler.java │ ├── AdvancedChargingBench.java │ ├── ElectricDustFabricator.java │ ├── WaterSprinkler.java │ ├── BackpackUnloader.java │ ├── AlternateElevatorPlate.java │ ├── BackpackLoader.java │ └── AutoTableSaw.java │ ├── objects │ ├── NonHopperableBlock.java │ └── DoubleHologramOwner.java │ ├── multiblocks │ ├── components │ │ └── GeneratorCore.java │ ├── CrankGenerator.java │ ├── ExpDispenser.java │ └── Foundry.java │ ├── listeners │ └── KeyedCrafterListener.java │ └── FluffyMachines.java ├── .gitignore ├── .github ├── workflows │ ├── maven.yml │ └── blob-builds.yml ├── ISSUE_TEMPLATE │ └── bug-report.md └── PULL_REQUEST_TEMPLATE.md ├── README.md └── pom.xml /src/main/resources/config.yml: -------------------------------------------------------------------------------- 1 | options: 2 | auto-update: true 3 | ignore-outdated-warning: false -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /bin/ 2 | /.settings/ 3 | /target/ 4 | /.idea/ 5 | *.iml 6 | .project 7 | .classpath 8 | dependency-reduced-pom.xml 9 | .DS_Store 10 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/utils/CancelPlace.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.utils; 2 | 3 | public interface CancelPlace { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/items/tools/AlternateBreakEvent.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.items.tools; 2 | 3 | import org.bukkit.block.Block; 4 | import org.bukkit.entity.Player; 5 | import org.bukkit.event.block.BlockBreakEvent; 6 | 7 | public class AlternateBreakEvent extends BlockBreakEvent { 8 | 9 | public AlternateBreakEvent(Block b, Player p) { 10 | super(b, p); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /.github/workflows/maven.yml: -------------------------------------------------------------------------------- 1 | name: Java CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | build: 13 | 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v1 18 | - name: Set up JDK 16 19 | uses: actions/setup-java@v1 20 | with: 21 | java-version: 16 22 | - name: Build with Maven 23 | run: mvn package --file pom.xml 24 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/items/HelicopterHat.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.items; 2 | 3 | import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; 4 | import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; 5 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; 6 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; 7 | import org.bukkit.inventory.ItemStack; 8 | 9 | public class HelicopterHat extends SlimefunItem { 10 | 11 | public HelicopterHat(ItemGroup category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { 12 | super(category, item, recipeType, recipe); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/machines/AutoArmorForge.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.machines; 2 | 3 | import io.ncbpfluffybear.fluffymachines.objects.AutoCrafter; 4 | import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; 5 | import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; 6 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; 7 | import org.bukkit.Material; 8 | import org.bukkit.inventory.ItemStack; 9 | 10 | public class AutoArmorForge extends AutoCrafter { 11 | 12 | public AutoArmorForge(ItemGroup category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { 13 | super(category, item, recipeType, recipe, "&7Auto Armor Forge", Material.ANVIL, "&7Armor Forge", RecipeType.ARMOR_FORGE); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/utils/McMMOEvents.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.utils; 2 | 3 | import com.gmail.nossr50.events.skills.abilities.McMMOPlayerAbilityActivateEvent; 4 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; 5 | import org.bukkit.entity.Player; 6 | import org.bukkit.event.EventHandler; 7 | import org.bukkit.event.Listener; 8 | 9 | public class McMMOEvents implements Listener { 10 | 11 | @EventHandler 12 | private void onAbility(McMMOPlayerAbilityActivateEvent e) { 13 | Player p = e.getPlayer(); 14 | SlimefunItem sfItem = SlimefunItem.getByItem(p.getInventory().getItemInMainHand()); 15 | if (sfItem != null && sfItem.getId().equals(FluffyItems.PAXEL.getItemId())) { 16 | e.setCancelled(true); 17 | } 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /.github/workflows/blob-builds.yml: -------------------------------------------------------------------------------- 1 | name: Publish build 2 | 3 | on: 4 | push: 5 | branches: 6 | - master # Only publish when pushing to "main" 7 | 8 | jobs: 9 | publish: 10 | name: Upload build 11 | runs-on: ubuntu-latest 12 | if: contains(github.event.head_commit.message, '[ci skip]') == false 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | 17 | - name: Set up JDK 16 18 | uses: actions/setup-java@v1 19 | with: 20 | java-version: 16 21 | 22 | - name: Build with Maven 23 | run: mvn -B package 24 | 25 | - name: Upload to Blob Builds 26 | uses: WalshyDev/blob-builds/gh-action@main 27 | with: 28 | project: FluffyMachines 29 | apiToken: ${{ secrets.BLOB_BUILDS_API_TOKEN }} 30 | releaseNotes: ${{ github.event.head_commit.message }} 31 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/machines/AutoEnhancedCraftingTable.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.machines; 2 | 3 | import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; 4 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; 5 | import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; 6 | import io.ncbpfluffybear.fluffymachines.objects.AutoCrafter; 7 | import org.bukkit.Material; 8 | import org.bukkit.inventory.ItemStack; 9 | 10 | public class AutoEnhancedCraftingTable extends AutoCrafter { 11 | public AutoEnhancedCraftingTable(ItemGroup category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { 12 | super(category, item, recipeType, recipe, "&6Auto Enhanced Crafting Table", 13 | Material.CRAFTING_TABLE, "&6Enhanced Crafting Table", RecipeType.ENHANCED_CRAFTING_TABLE 14 | ); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/resources/plugin.yml: -------------------------------------------------------------------------------- 1 | ## CHANGE this to the name of your plugin. 2 | name: FluffyMachines 3 | 4 | ## CHANGE this to your username. 5 | author: NCBPFluffyBear 6 | 7 | ## CHANGE this to a meaninful but short description of your plugin. 8 | description: A fun addon 9 | 10 | ## CHANGE this to the path of the class that extends JavaPlugin. 11 | main: io.ncbpfluffybear.fluffymachines.FluffyMachines 12 | 13 | ## This is required and marks Slimefun as a plugin dependency. 14 | depend: [Slimefun] 15 | softdepend: [mcMMO, NoCheatPlus] 16 | 17 | ## This value is automatically replaced by the version specified in your pom.xml file, do not change this. 18 | version: ${project.version} 19 | 20 | ## This is the minimum minecraft version required to run your plugin. 21 | api-version: 1.14 22 | 23 | commands: 24 | fluffymachines: 25 | description: FluffyMachines Command 26 | usage: / 27 | aliases: [fm] 28 | 29 | permissions: 30 | fluffymachines.admin: 31 | description: Allows you to use FluffyMachines admin commands -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/items/tools/UpgradedExplosivePickaxe.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.items.tools; 2 | 3 | import io.github.thebusybiscuit.slimefun4.implementation.items.tools.ExplosiveShovel; 4 | import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; 5 | import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; 6 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; 7 | import org.bukkit.block.Block; 8 | import org.bukkit.inventory.ItemStack; 9 | 10 | /** 11 | * The {@link UpgradedExplosivePickaxe} is a pickaxe which can destroy {@link Block}s 12 | * in a size of 3 by 3. It also creates a explosion animation. 13 | * 14 | * @author TheBusyBiscuit, NCBPFluffyBear 15 | * @see ExplosiveShovel 16 | * @see UpgradedExplosiveTool 17 | */ 18 | public class UpgradedExplosivePickaxe extends UpgradedExplosiveTool { 19 | 20 | public UpgradedExplosivePickaxe(ItemGroup category, SlimefunItemStack item, 21 | RecipeType recipeType, ItemStack[] recipe) { 22 | super(category, item, recipeType, recipe); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug Report 3 | about: Report a Bug or an Issue with this Plugin. 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Description (Required) 11 | 12 | 13 | 14 | 15 | ## Steps to reproduce the Issue (Required) 16 | 17 | 18 | ## Expected behavior (Required) 19 | 20 | 21 | ## Server Log / Error Report 22 | 23 | 24 | 25 | ## Environment (Required) 26 | 27 | 28 | 29 | 30 | - Minecraft Version: 31 | - CS-CoreLib Version: 32 | - Slimefun Version: 33 | - FluffyMachines Version: 34 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Short Description 2 | 3 | 4 | ## Additions/Changes/Removals 5 | 6 | 7 | ## Related Issues 8 | 9 | 10 | 11 | ## Video Proof 12 | 13 | 14 | 15 | ## Checklist 16 | 17 | 18 | - [ ] I have fully tested the proposed changes and promise that they will not break everything into chaos. 19 | - [ ] I have tested every variant of every item or config setting that I have added. 20 | - [ ] I have also tested the proposed changes in combination with base Slimefun and made sure nothing breaks/unexpected happens. 21 | - [ ] I followed the existing code standards and didn't mess up the formatting. 22 | - [ ] I did my best to add documentation to any public classes or methods I added which may not be obvious to maintainers. 23 | - [ ] I have added `Nonnull` and `Nullable` annotations to my methods to indicate their behaviour for null values 24 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/utils/Constants.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.utils; 2 | 3 | import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems; 4 | import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; 5 | import io.ncbpfluffybear.fluffymachines.FluffyMachines; 6 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; 7 | import org.bukkit.Bukkit; 8 | import org.bukkit.NamespacedKey; 9 | 10 | import java.util.ArrayList; 11 | import java.util.Arrays; 12 | import java.util.List; 13 | import java.util.regex.Pattern; 14 | 15 | public final class Constants { 16 | 17 | public static final int SERVER_VERSION = Integer.parseInt(Bukkit.getVersion().replaceFirst(".*MC: ", "").replace( 18 | ")", "").replace(".", "")); 19 | 20 | public static final Pattern VERSION_PATTERN = Pattern.compile("(DEV - )([0-9]+)"); 21 | 22 | public static final boolean isSoulJarsInstalled = Bukkit.getPluginManager().isPluginEnabled("SoulJars"); 23 | 24 | public static final List dusts = new ArrayList<>(Arrays.asList( 25 | SlimefunItems.COPPER_DUST, SlimefunItems.GOLD_DUST, SlimefunItems.IRON_DUST, 26 | SlimefunItems.LEAD_DUST, SlimefunItems.ALUMINUM_DUST, SlimefunItems.ZINC_DUST, 27 | SlimefunItems.TIN_DUST, SlimefunItems.MAGNESIUM_DUST, SlimefunItems.SILVER_DUST 28 | )); 29 | 30 | public static final int MAX_STACK_SIZE = 64; 31 | 32 | private Constants() {} 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/objects/NonHopperableBlock.java: -------------------------------------------------------------------------------- 1 | // 2 | // Source code recreated from a .class file by IntelliJ IDEA 3 | // (powered by FernFlower decompiler) 4 | // 5 | 6 | package io.ncbpfluffybear.fluffymachines.objects; 7 | 8 | import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; 9 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; 10 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; 11 | import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; 12 | import me.mrCookieSlime.Slimefun.api.BlockStorage; 13 | import org.bukkit.event.EventHandler; 14 | import org.bukkit.event.inventory.InventoryMoveItemEvent; 15 | import org.bukkit.event.inventory.InventoryType; 16 | import org.bukkit.inventory.ItemStack; 17 | 18 | public class NonHopperableBlock extends SlimefunItem { 19 | public NonHopperableBlock(ItemGroup category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { 20 | super(category, item, recipeType, recipe); 21 | } 22 | 23 | @EventHandler 24 | public void onHopper(InventoryMoveItemEvent e) { 25 | if (e.getSource().getType() == InventoryType.HOPPER && e.getDestination().getLocation() != null 26 | && BlockStorage.hasBlockInfo(e.getDestination().getLocation()) 27 | && BlockStorage.check(e.getDestination().getLocation()) instanceof NonHopperableBlock 28 | ) { 29 | e.setCancelled(true); 30 | } 31 | 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/multiblocks/components/GeneratorCore.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.multiblocks.components; 2 | 3 | import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; 4 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; 5 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; 6 | import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; 7 | import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetProvider; 8 | import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNetComponentType; 9 | import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config; 10 | import org.bukkit.Location; 11 | import org.bukkit.inventory.ItemStack; 12 | 13 | import javax.annotation.Nonnull; 14 | 15 | public class GeneratorCore extends SlimefunItem implements EnergyNetProvider { 16 | 17 | public GeneratorCore(ItemGroup category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { 18 | super(category, item, recipeType, recipe); 19 | } 20 | 21 | @Nonnull 22 | @Override 23 | public EnergyNetComponentType getEnergyComponentType() { 24 | return EnergyNetComponentType.GENERATOR; 25 | } 26 | 27 | // Making this block an EnergyNetProvider instead of an EnergyNetComponent causes it to tick. However, this block will not actively 28 | // push out energy unless made a generator. 29 | @Override 30 | public int getGeneratedOutput(@Nonnull Location l, @Nonnull Config data) { 31 | return 0; 32 | } 33 | 34 | @Override 35 | public int getCapacity() { 36 | return 64; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/items/tools/UpgradedExplosiveShovel.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.items.tools; 2 | 3 | import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; 4 | import io.github.thebusybiscuit.slimefun4.implementation.items.tools.ExplosivePickaxe; 5 | import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag; 6 | import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; 7 | import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; 8 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; 9 | import io.github.thebusybiscuit.slimefun4.libraries.dough.protection.Interaction; 10 | import org.bukkit.block.Block; 11 | import org.bukkit.entity.Player; 12 | import org.bukkit.inventory.ItemStack; 13 | 14 | /** 15 | * The {@link UpgradedExplosiveShovel} works similar to the 16 | * {@link io.github.thebusybiscuit.slimefun4.implementation.items.tools.ExplosivePickaxe}. 17 | * However it can only break blocks that a shovel can break. 18 | * 19 | * @author Linox, NCBPFluffyBear 20 | * @see ExplosivePickaxe 21 | * @see UpgradedExplosiveTool 22 | */ 23 | public class UpgradedExplosiveShovel extends UpgradedExplosiveTool { 24 | 25 | public UpgradedExplosiveShovel(ItemGroup category, SlimefunItemStack item, RecipeType recipeType, 26 | ItemStack[] recipe) { 27 | super(category, item, recipeType, recipe); 28 | } 29 | 30 | @Override 31 | protected boolean canBreak(Player p, Block b) { 32 | return SlimefunTag.EXPLOSIVE_SHOVEL_BLOCKS.isTagged(b.getType()) 33 | && Slimefun.getProtectionManager().hasPermission(p, b.getLocation(), Interaction.BREAK_BLOCK); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/machines/AutoMagicWorkbench.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.machines; 2 | 3 | import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; 4 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; 5 | import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; 6 | import io.ncbpfluffybear.fluffymachines.objects.AutoCrafter; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | import me.mrCookieSlime.Slimefun.api.inventory.DirtyChestMenu; 10 | import me.mrCookieSlime.Slimefun.api.item_transport.ItemTransportFlow; 11 | import org.bukkit.Material; 12 | import org.bukkit.inventory.ItemStack; 13 | 14 | public class AutoMagicWorkbench extends AutoCrafter { 15 | 16 | public AutoMagicWorkbench(ItemGroup category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { 17 | super(category, item, recipeType, recipe, "&6Auto Magic Workbench", Material.BOOKSHELF, "&6Magic Workbench", RecipeType.MAGIC_WORKBENCH); 18 | } 19 | 20 | /** 21 | * Modified to accept non-stackable items 22 | */ 23 | @Override 24 | public int[] getCustomItemTransport(DirtyChestMenu menu, ItemTransportFlow flow, ItemStack item) { 25 | if (flow == ItemTransportFlow.WITHDRAW) { 26 | return getOutputSlots(); 27 | } 28 | 29 | if (item.getType().getMaxStackSize() == 1) { 30 | return getInputSlots(); 31 | } 32 | 33 | List slots = new ArrayList<>(); 34 | for (int slot : getInputSlots()) { 35 | if (menu.getItemInSlot(slot) != null) { 36 | slots.add(slot); 37 | } 38 | } 39 | 40 | slots.sort(compareSlots(menu)); 41 | 42 | int[] array = new int[slots.size()]; 43 | 44 | for (int i = 0; i < slots.size(); i++) { 45 | array[i] = slots.get(i); 46 | } 47 | 48 | return array; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/multiblocks/CrankGenerator.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.multiblocks; 2 | 3 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; 4 | import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetProvider; 5 | import io.github.thebusybiscuit.slimefun4.core.multiblocks.MultiBlockMachine; 6 | import io.ncbpfluffybear.fluffymachines.multiblocks.components.GeneratorCore; 7 | import io.ncbpfluffybear.fluffymachines.utils.Utils; 8 | import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config; 9 | import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; 10 | import me.mrCookieSlime.Slimefun.api.BlockStorage; 11 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; 12 | import io.ncbpfluffybear.fluffymachines.utils.FluffyItems; 13 | import org.bukkit.Bukkit; 14 | import org.bukkit.Location; 15 | import org.bukkit.Material; 16 | import org.bukkit.Sound; 17 | import org.bukkit.block.Block; 18 | import org.bukkit.block.BlockFace; 19 | import org.bukkit.entity.Player; 20 | import org.bukkit.inventory.ItemStack; 21 | 22 | import javax.annotation.Nonnull; 23 | 24 | public class CrankGenerator extends MultiBlockMachine { 25 | 26 | public static final int RATE = 16; 27 | public static final int CAPACITY = 64; 28 | 29 | public CrankGenerator(ItemGroup category, SlimefunItemStack item) { 30 | super(category, item, new ItemStack[] {null, null, null, null, new ItemStack(Material.LEVER), null, null, 31 | FluffyItems.GENERATOR_CORE, null}, BlockFace.SELF); 32 | } 33 | 34 | public void onInteract(Player p, Block b) { 35 | Block coreBlock = b.getRelative(BlockFace.DOWN); 36 | if (BlockStorage.hasBlockInfo(coreBlock)) { 37 | SlimefunItem core = BlockStorage.check(coreBlock.getLocation()); 38 | 39 | if (core instanceof GeneratorCore) { 40 | ((GeneratorCore) core).addCharge(coreBlock.getLocation(), RATE); 41 | p.playSound(p.getLocation(), Sound.BLOCK_PISTON_EXTEND, 0.5F, 0.5F); 42 | 43 | } else { 44 | Utils.send(p, "&cMissing generator core"); 45 | } 46 | } else { 47 | Utils.send(p, "&cMissing generator core"); 48 | } 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/machines/WarpPad.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.machines; 2 | 3 | import io.github.thebusybiscuit.slimefun4.api.events.PlayerRightClickEvent; 4 | import io.github.thebusybiscuit.slimefun4.core.attributes.HologramOwner; 5 | import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler; 6 | import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler; 7 | import io.github.thebusybiscuit.slimefun4.core.handlers.BlockUseHandler; 8 | import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; 9 | import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; 10 | import io.github.thebusybiscuit.slimefun4.api.items.ItemHandler; 11 | import io.ncbpfluffybear.fluffymachines.objects.NonHopperableBlock; 12 | import me.mrCookieSlime.Slimefun.api.BlockStorage; 13 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; 14 | import org.bukkit.block.Block; 15 | import org.bukkit.event.block.BlockBreakEvent; 16 | import org.bukkit.event.block.BlockPlaceEvent; 17 | import org.bukkit.inventory.ItemStack; 18 | 19 | import javax.annotation.Nonnull; 20 | import java.util.List; 21 | 22 | public class WarpPad extends NonHopperableBlock implements HologramOwner { 23 | 24 | 25 | public WarpPad(ItemGroup category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { 26 | super(category, item, recipeType, recipe); 27 | 28 | addItemHandler(onPlace(), onUse(), onBreak()); 29 | 30 | } 31 | 32 | private BlockBreakHandler onBreak() { 33 | return new BlockBreakHandler(false, false) { 34 | @Override 35 | public void onPlayerBreak(@Nonnull BlockBreakEvent e, @Nonnull ItemStack item, @Nonnull List drops) { 36 | Block b = e.getBlock(); 37 | removeHologram(b); 38 | } 39 | }; 40 | } 41 | 42 | private BlockPlaceHandler onPlace() { 43 | return new BlockPlaceHandler(true) { 44 | @Override 45 | public void onPlayerPlace(@Nonnull BlockPlaceEvent e) { 46 | BlockStorage.addBlockInfo(e.getBlockPlaced(), "type", "none"); 47 | updateHologram(e.getBlockPlaced(), "&4&lX"); 48 | } 49 | }; 50 | } 51 | 52 | private ItemHandler onUse() { 53 | return (BlockUseHandler) PlayerRightClickEvent::cancel; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/objects/DoubleHologramOwner.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.objects; 2 | 3 | 4 | import io.github.thebusybiscuit.slimefun4.core.attributes.ItemAttribute; 5 | import io.github.thebusybiscuit.slimefun4.core.services.holograms.HologramsService; 6 | import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; 7 | import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.HologramProjector; 8 | import io.ncbpfluffybear.fluffymachines.utils.Utils; 9 | import javax.annotation.Nonnull; 10 | import javax.annotation.Nullable; 11 | import org.bukkit.Location; 12 | import org.bukkit.block.Block; 13 | import org.bukkit.util.Vector; 14 | 15 | /** 16 | * This {@link ItemAttribute} manages holograms. 17 | * Modified version of {@link io.github.thebusybiscuit.slimefun4.core.attributes.HologramOwner} 18 | * Didn't extend because all methods are being modified 19 | * 20 | * @author TheBusyBiscuit 21 | * @author NCBPFluffyBear 22 | * 23 | * @see HologramProjector 24 | * @see HologramsService 25 | * 26 | */ 27 | public interface DoubleHologramOwner extends ItemAttribute { 28 | 29 | default void updateHologram(@Nonnull Block b, @Nullable String topText, @Nonnull String bottomText) { 30 | Location locTop = b.getLocation().add(getTopHologramOffset(b)); 31 | Location locBot = b.getLocation().add(getBottomHologramOffset(b)); 32 | Slimefun.getHologramsService().setHologramLabel(locTop, Utils.color(topText)); 33 | Slimefun.getHologramsService().setHologramLabel(locBot, Utils.color(bottomText)); 34 | } 35 | 36 | default void removeHologram(@Nonnull Block b) { 37 | Location locTop = b.getLocation().add(getTopHologramOffset(b)); 38 | Location locBot = b.getLocation().add(getBottomHologramOffset(b)); 39 | Slimefun.getHologramsService().removeHologram(locTop); 40 | Slimefun.getHologramsService().removeHologram(locBot); 41 | } 42 | 43 | @Nonnull 44 | default Vector getHologramOffset(@Nonnull Block block) { 45 | return Slimefun.getHologramsService().getDefaultOffset(); 46 | } 47 | 48 | @Nonnull 49 | default double getHologramSpacing() { 50 | return 0.2; 51 | } 52 | 53 | @Nonnull 54 | default Vector getTopHologramOffset(@Nonnull Block block) { 55 | return getHologramOffset(block).add(new Vector(0.0, getHologramSpacing(), 0.0)); 56 | } 57 | 58 | @Nonnull 59 | default Vector getBottomHologramOffset(@Nonnull Block block) { 60 | return getHologramOffset(block); 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/multiblocks/ExpDispenser.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.multiblocks; 2 | 3 | import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; 4 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; 5 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; 6 | import io.github.thebusybiscuit.slimefun4.core.multiblocks.MultiBlockMachine; 7 | import io.ncbpfluffybear.fluffymachines.items.Barrel; 8 | import io.ncbpfluffybear.fluffymachines.utils.Utils; 9 | import me.mrCookieSlime.Slimefun.api.BlockStorage; 10 | import org.bukkit.Material; 11 | import org.bukkit.block.Block; 12 | import org.bukkit.block.BlockFace; 13 | import org.bukkit.block.Container; 14 | import org.bukkit.block.data.Directional; 15 | import org.bukkit.entity.Player; 16 | import org.bukkit.inventory.ItemStack; 17 | 18 | /** 19 | * Dispenses multiple bottles of exp at once 20 | */ 21 | public class ExpDispenser extends MultiBlockMachine { 22 | 23 | private static final int EXP_PER_BOTTLE = 7; // Average exp per bottle 24 | 25 | public ExpDispenser(ItemGroup itemGroup, SlimefunItemStack item, ItemStack[] recipe) { 26 | super(itemGroup, item, recipe, BlockFace.SELF); 27 | } 28 | 29 | @Override 30 | public void onInteract(Player p, Block b) { 31 | Block dispenser = b.getRelative(0, -1, 0); 32 | Container container = (Container) dispenser.getState(); 33 | int experience = 0; 34 | 35 | for (ItemStack bottle : container.getInventory().getContents()) { 36 | if (bottle != null && bottle.getType() == Material.EXPERIENCE_BOTTLE) { // Search for xp bottles 37 | experience += EXP_PER_BOTTLE * bottle.getAmount(); // Collect experience from bottle 38 | bottle.setAmount(0); // Delete bottle 39 | } 40 | } 41 | 42 | Block barrel = dispenser.getRelative(((Directional) dispenser.getBlockData()).getFacing()); 43 | SlimefunItem sfItem = BlockStorage.check(barrel); 44 | 45 | if (sfItem instanceof Barrel) { 46 | Barrel sfBarrel = (Barrel) sfItem; 47 | if (sfBarrel.getStoredItem(barrel).getType() == Material.EXPERIENCE_BOTTLE) { 48 | experience += sfBarrel.getStored(barrel) * EXP_PER_BOTTLE; 49 | sfBarrel.setStored(barrel, 0); 50 | sfBarrel.updateMenu(barrel, BlockStorage.getInventory(barrel), true, sfBarrel.getCapacity(b)); 51 | } 52 | } 53 | 54 | if (experience == 0) { 55 | Utils.send(p, "&cThere were no experience bottles in the dispenser!"); 56 | } else { 57 | p.giveExp(experience); 58 | Utils.send(p, "&a+" + experience + " XP"); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/items/tools/ACBUpgradeCard.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.items.tools; 2 | 3 | import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler; 4 | import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem; 5 | import io.ncbpfluffybear.fluffymachines.utils.FluffyItems; 6 | import io.ncbpfluffybear.fluffymachines.utils.Utils; 7 | import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; 8 | import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; 9 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; 10 | import io.github.thebusybiscuit.slimefun4.api.items.ItemHandler; 11 | import me.mrCookieSlime.Slimefun.api.BlockStorage; 12 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; 13 | import org.bukkit.block.Block; 14 | import org.bukkit.entity.Player; 15 | import org.bukkit.inventory.EquipmentSlot; 16 | import org.bukkit.inventory.ItemStack; 17 | 18 | import javax.annotation.Nonnull; 19 | import java.util.Optional; 20 | 21 | public class ACBUpgradeCard extends SimpleSlimefunItem { 22 | 23 | public ACBUpgradeCard(ItemGroup category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { 24 | super(category, item, recipeType, recipe); 25 | } 26 | 27 | @Nonnull 28 | @Override 29 | public ItemHandler getItemHandler() { 30 | return (ItemUseHandler) e -> { 31 | // Prevent offhand right clicks 32 | if (e.getHand() != EquipmentSlot.HAND) { 33 | return; 34 | } 35 | 36 | // Block exists 37 | Optional optB = e.getClickedBlock(); 38 | 39 | if (!optB.isPresent()) { 40 | return; 41 | } 42 | 43 | // Prevent menu opening and interactions 44 | e.cancel(); 45 | 46 | Block b = optB.get(); 47 | SlimefunItem sfItem = BlockStorage.check(b); 48 | Player p = e.getPlayer(); 49 | ItemStack card = p.getInventory().getItemInMainHand(); 50 | 51 | // Make sure the block is an ACB 52 | if (sfItem == null || sfItem != FluffyItems.ADVANCED_CHARGING_BENCH.getItem()) { 53 | Utils.send(e.getPlayer(), "&cYou can only use this card on an Advanced Charging Bench"); 54 | return; 55 | } 56 | 57 | // Increment the tier by 1 58 | int tier = Integer.parseInt(BlockStorage.getLocationInfo(b.getLocation(), "tier")); 59 | if (tier == 100) { 60 | Utils.send(e.getPlayer(), "&cThis Advanced Charging Bench is maxed (Tier 100)"); 61 | return; 62 | } 63 | tier++; 64 | BlockStorage.addBlockInfo(b.getLocation(), "tier", String.valueOf(tier)); 65 | 66 | // Remove a card 67 | card.setAmount(card.getAmount() - 1); 68 | 69 | Utils.send(e.getPlayer(), "&aThis Advanced Charging Bench has been upgraded! &eTier: " + tier); 70 | }; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/items/tools/Scythe.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.items.tools; 2 | 3 | import io.github.thebusybiscuit.slimefun4.core.attributes.NotPlaceable; 4 | import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler; 5 | import io.github.thebusybiscuit.slimefun4.core.handlers.ToolUseHandler; 6 | import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; 7 | import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem; 8 | import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; 9 | import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; 10 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; 11 | import io.github.thebusybiscuit.slimefun4.libraries.dough.blocks.Vein; 12 | import io.github.thebusybiscuit.slimefun4.libraries.dough.protection.Interaction; 13 | import org.bukkit.Bukkit; 14 | import org.bukkit.GameMode; 15 | import org.bukkit.Material; 16 | import org.bukkit.Tag; 17 | import org.bukkit.block.Block; 18 | import org.bukkit.block.data.Ageable; 19 | import org.bukkit.event.Event; 20 | import org.bukkit.inventory.ItemStack; 21 | 22 | import javax.annotation.Nonnull; 23 | import java.util.List; 24 | 25 | public class Scythe extends SimpleSlimefunItem implements NotPlaceable { 26 | 27 | private static final int MAX_BROKEN = 5; 28 | 29 | public Scythe(ItemGroup category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { 30 | super(category, item, recipeType, recipe); 31 | } 32 | 33 | @Override 34 | public void preRegister() { 35 | super.preRegister(); 36 | 37 | addItemHandler(onBlockBreak()); 38 | } 39 | 40 | @Nonnull 41 | @Override 42 | public ItemUseHandler getItemHandler() { 43 | return e -> e.setUseBlock(Event.Result.DENY); 44 | } 45 | 46 | public ToolUseHandler onBlockBreak() { 47 | return (e, tool, fortune, drops) -> { 48 | 49 | if (e instanceof AlternateBreakEvent) { 50 | return; 51 | } 52 | 53 | if (e.getBlock().getBlockData() instanceof Ageable 54 | && ((Ageable) e.getBlock().getBlockData()).getAge() 55 | == ((Ageable) e.getBlock().getBlockData()).getMaximumAge()) { 56 | List crops = Vein.find(e.getBlock(), MAX_BROKEN, b -> Tag.CROPS.isTagged(b.getType())); 57 | 58 | crops.remove(e.getBlock()); 59 | 60 | boolean creative = e.getPlayer().getGameMode() == GameMode.CREATIVE; 61 | 62 | for (Block b : crops) { 63 | if (Slimefun.getProtectionManager().hasPermission(e.getPlayer(), b, Interaction.BREAK_BLOCK)) { 64 | AlternateBreakEvent breakEvent = new AlternateBreakEvent(b, e.getPlayer()); 65 | Bukkit.getPluginManager().callEvent(breakEvent); 66 | if (creative) { 67 | b.setType(Material.AIR); 68 | } else { 69 | b.breakNaturally(tool); 70 | } 71 | } 72 | } 73 | } 74 | }; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FluffyMachines 2 | 3 | These are some thrown together machines made by me for fun :) 4 | I pretty much add whatever comes to mind, is suggested by me, or other addons don't want to add. 5 | 6 | Custom item settings can be changed in `plugins/Slimefun/Items.yml` 7 | 8 | ## Machines 9 | **Auto Crafting Table**: Automatically crafts vanilla recipes 10 | 11 | **Auto Armor Forge**: Automatically crafts Armor Forge recipes 12 | 13 | **Auto Magic Workbench**: Automatically crafts Magic Workbench recipes 14 | 15 | **Auto Ancient Altar**: Automatically crafts Ancient Altar recipes 16 | 17 | **Auto Table Saw**: Automatically crafts Table Saw recipes 18 | 19 | **Water Sprinkler**: Electric sprinkler that grows crops in a 2 block radius 20 | 21 | **Backpack Loader**: Moves items from inventory to backpack 22 | 23 | **Backpack Unloader**: Empties backpack into inventory 24 | 25 | **Advanced Auto Disenchanter & Ancient Book**: Allows players to disenchant specific enchants from items. Requires an Ancient Book to operate. 26 | 27 | **Electric Dust Fabricator**: Turns cobblestone into sifted ore 28 | 29 | **Electric Dust Recycler**: Turns eight of the same dust into one sifted ore 30 | 31 | **Advanced Charging Bench & ACB Upgrade Card**: A charging bench which can be upgraded using upgrade cards. 32 | 33 | ## Generators 34 | **Crank Generator**: Multiblock machine that generates power when clicked 35 | 36 | ## Items 37 | **Watering Can**: Waters plants and trees to speed up their growth 38 | 39 | **Helicopter Hat**: Allows you to float upwards when sneaking 40 | 41 | **Fireproof Rune**: Drop this on your items to prevent them from burning 42 | 43 | **Dolly**: Allows players to pick up chests and place them back down elsewhere, while retaining their inventories. 44 | 45 | ## Tools 46 | **Upgraded Explosive Pickaxe & Upgraded Explosive Shovel**: 5x5 variants of the default explosive tools, and break 5 blocks in front of the player instead of 2 blocks all around. By default, these tools trigger other plugins that listen to block breaks, i.e. McMMO (Players get xp for every block broken). These features can be toggled in Items.yml. 47 | 48 | **Upgraded Lumber Axe**: Breaks all logs within 2 blocks of each other, as opposed to adjacent blocks that the default lumber axe targets. Intended to be used for strange trees like acacia and jungle, and even custom trees. 49 | 50 | **Scythe**: Breaks 5 crops per swing 51 | 52 | **Wrench**: Quickly breaks Slimefun cargo and energy components. 53 | 54 | **Paxel**: A pickaxe, axe, and shovel all in one. 55 | 56 | ## Misc 57 | **Ender Chest Extraction Node**: Moves items from ender chest to a chest 58 | 59 | **Ender Chest Insertion Node**: Moves items from a chest to an ender chest 60 | 61 | *The extraction and insertion nodes do no stack items in inventories, that costs more performance and can be handled by cargo. 62 | 63 | **Foundry & Superheated Furnace**: Allows the storage of dusts, and can be instantly converted to and from their ingot form. 64 | 65 | **Barrels**: Storage containers that store one type of item each 66 | 67 | **Warp Pad & Warp Pad Configurator**: Short distance teleportation pads 68 | 69 | **Alternate Elevator Plate**: Functions the same as Slimefun's Elevator Plates, but it uses a Chest GUI. Can be used for cosmetic effect, of if your server does not support elevators when a player is muted, this will work. 70 | 71 | **Portable Charger**: Multiple tiered handheld charders that allow players to charge items anywhere 72 | 73 | ## FAQ 74 | **Can cargo be used on the Foundry?** 75 | *Yes, but you can not place it directly on the Superheated Furnace. Place down a chest in its place, put the cargo on the chest, and then replace the chest wth the Superheated Furnace.* 76 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/machines/ElectricDustRecycler.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.machines; 2 | 3 | import io.github.thebusybiscuit.slimefun4.core.attributes.RecipeDisplayItem; 4 | import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler; 5 | import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems; 6 | import io.ncbpfluffybear.fluffymachines.utils.Constants; 7 | import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; 8 | import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; 9 | import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AContainer; 10 | import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineRecipe; 11 | import me.mrCookieSlime.Slimefun.api.BlockStorage; 12 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; 13 | import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu; 14 | import io.github.thebusybiscuit.slimefun4.libraries.dough.items.CustomItemStack; 15 | import org.bukkit.Material; 16 | import org.bukkit.block.Block; 17 | import org.bukkit.event.block.BlockBreakEvent; 18 | import org.bukkit.inventory.ItemStack; 19 | 20 | import javax.annotation.Nonnull; 21 | import java.util.ArrayList; 22 | import java.util.List; 23 | 24 | public class ElectricDustRecycler extends AContainer implements RecipeDisplayItem { 25 | 26 | public static final int ENERGY_CONSUMPTION = 32; 27 | public static final int CAPACITY = ENERGY_CONSUMPTION * 3; 28 | 29 | public ElectricDustRecycler(ItemGroup category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { 30 | super(category, item, recipeType, recipe); 31 | 32 | addItemHandler(onBreak()); 33 | 34 | } 35 | 36 | private BlockBreakHandler onBreak() { 37 | return new BlockBreakHandler(false, false) { 38 | @Override 39 | public void onPlayerBreak(@Nonnull BlockBreakEvent e, @Nonnull ItemStack item, @Nonnull List drops) { 40 | Block b = e.getBlock(); 41 | BlockMenu inv = BlockStorage.getInventory(b); 42 | 43 | if (inv != null) { 44 | inv.dropItems(b.getLocation(), getInputSlots()); 45 | inv.dropItems(b.getLocation(), getOutputSlots()); 46 | } 47 | } 48 | }; 49 | } 50 | 51 | @Override 52 | protected void registerDefaultRecipes() { 53 | 54 | for (SlimefunItemStack dust : Constants.dusts) { 55 | registerRecipe(1, new CustomItemStack(dust, 8), SlimefunItems.SIFTED_ORE); 56 | } 57 | } 58 | 59 | @Nonnull 60 | @Override 61 | public List getDisplayRecipes() { 62 | List displayRecipes = new ArrayList<>(recipes.size() * 2); 63 | 64 | for (MachineRecipe recipe : recipes) { 65 | displayRecipes.add(recipe.getInput()[0]); 66 | displayRecipes.add(recipe.getOutput()[recipe.getOutput().length - 1]); 67 | } 68 | 69 | return displayRecipes; 70 | } 71 | 72 | @Override 73 | public ItemStack getProgressBar() { 74 | return new ItemStack(Material.PISTON); 75 | } 76 | 77 | @Override 78 | public int getEnergyConsumption() { 79 | return ENERGY_CONSUMPTION; 80 | } 81 | 82 | @Override 83 | public int getCapacity() { 84 | return CAPACITY; 85 | } 86 | 87 | @Override 88 | public int getSpeed() { 89 | return 1; 90 | } 91 | 92 | @Nonnull 93 | @Override 94 | public String getInventoryTitle() { 95 | return "&fElectric Dust Recycler"; 96 | } 97 | 98 | @Nonnull 99 | @Override 100 | public String getMachineIdentifier() { 101 | return "ELECTRIC_DUST_RECYCLER"; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/machines/AdvancedChargingBench.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.machines; 2 | 3 | import io.github.thebusybiscuit.slimefun4.core.attributes.Rechargeable; 4 | import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler; 5 | import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; 6 | import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; 7 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; 8 | import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AContainer; 9 | import me.mrCookieSlime.Slimefun.api.BlockStorage; 10 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; 11 | import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu; 12 | import org.bukkit.block.Block; 13 | import org.bukkit.event.block.BlockPlaceEvent; 14 | import org.bukkit.inventory.ItemStack; 15 | 16 | import javax.annotation.Nonnull; 17 | 18 | public class AdvancedChargingBench extends AContainer { 19 | 20 | public static final int CAPACITY = 128; 21 | public static final int ENERGY_CONSUMPTION = 10; 22 | public static final int CHARGE = 5; 23 | private int tier = 0; 24 | 25 | public AdvancedChargingBench(ItemGroup category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { 26 | super(category, item, recipeType, recipe); 27 | addItemHandler(onPlace()); 28 | } 29 | 30 | private BlockPlaceHandler onPlace() { 31 | return new BlockPlaceHandler(true) { 32 | @Override 33 | public void onPlayerPlace(@Nonnull BlockPlaceEvent e) { 34 | Block b = e.getBlockPlaced(); 35 | BlockStorage.addBlockInfo(b.getLocation(), "tier", "0"); 36 | } 37 | }; 38 | } 39 | 40 | @Override 41 | protected void tick(Block b) { 42 | if (getCharge(b.getLocation()) < getEnergyConsumption()) { 43 | return; 44 | } 45 | 46 | BlockMenu inv = BlockStorage.getInventory(b); 47 | tier = Integer.parseInt(BlockStorage.getLocationInfo(b.getLocation(), "tier")); 48 | 49 | for (int slot : getInputSlots()) { 50 | ItemStack item = inv.getItemInSlot(slot); 51 | 52 | if (charge(b, inv, slot, item, tier)) { 53 | return; 54 | } 55 | } 56 | } 57 | 58 | private boolean charge(Block b, BlockMenu inv, int slot, ItemStack item, int tier) { 59 | SlimefunItem sfItem = SlimefunItem.getByItem(item); 60 | 61 | if (sfItem instanceof Rechargeable) { 62 | float charge = CHARGE + CHARGE * tier; 63 | 64 | if (((Rechargeable) sfItem).addItemCharge(item, charge)) { 65 | removeCharge(b.getLocation(), getEnergyConsumption()); 66 | } else if (inv.fits(item, getOutputSlots())) { 67 | inv.pushItem(item, getOutputSlots()); 68 | inv.replaceExistingItem(slot, null); 69 | } 70 | 71 | return true; 72 | } else if (sfItem != null && inv.fits(item, getOutputSlots())) { 73 | inv.pushItem(item, getOutputSlots()); 74 | inv.replaceExistingItem(slot, null); 75 | } 76 | 77 | return false; 78 | } 79 | 80 | @Override 81 | public ItemStack getProgressBar() { 82 | return null; 83 | } 84 | 85 | @Override 86 | public int getCapacity() { 87 | return CAPACITY + CAPACITY * tier; 88 | } 89 | 90 | @Override 91 | public int getEnergyConsumption() { 92 | return ENERGY_CONSUMPTION + ENERGY_CONSUMPTION * tier; 93 | } 94 | 95 | @Override 96 | public int getSpeed() { 97 | return 1; 98 | } 99 | 100 | @Nonnull 101 | @Override 102 | public String getMachineIdentifier() { 103 | return "ADVANCED_CHARGING_BENCH"; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/multiblocks/Foundry.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.multiblocks; 2 | 3 | import io.github.thebusybiscuit.slimefun4.core.multiblocks.MultiBlockMachine; 4 | import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; 5 | import io.ncbpfluffybear.fluffymachines.multiblocks.components.SuperheatedFurnace; 6 | import io.ncbpfluffybear.fluffymachines.utils.FluffyItems; 7 | import io.ncbpfluffybear.fluffymachines.utils.Utils; 8 | import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; 9 | import java.util.Objects; 10 | import me.mrCookieSlime.Slimefun.api.BlockStorage; 11 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; 12 | import io.github.thebusybiscuit.slimefun4.libraries.dough.items.CustomItemStack; 13 | import org.bukkit.Material; 14 | import org.bukkit.block.Block; 15 | import org.bukkit.block.BlockFace; 16 | import org.bukkit.block.Furnace; 17 | import org.bukkit.entity.ArmorStand; 18 | import org.bukkit.entity.EntityType; 19 | import org.bukkit.entity.Player; 20 | import org.bukkit.inventory.ItemStack; 21 | 22 | /** 23 | * The shell of the {@link SuperheatedFurnace} 24 | * 25 | * @author NCBPFluffyBear 26 | */ 27 | public class Foundry extends MultiBlockMachine { 28 | 29 | public Foundry(ItemGroup category, SlimefunItemStack item) { 30 | super(category, item, new ItemStack[] { 31 | new ItemStack(Material.NETHERITE_BLOCK), FluffyItems.SUPERHEATED_FURNACE, new ItemStack(Material.NETHERITE_BLOCK), 32 | new ItemStack(Material.NETHERITE_BLOCK), new ItemStack(Material.GLASS), new ItemStack(Material.NETHERITE_BLOCK), 33 | new ItemStack(Material.NETHERITE_BLOCK), new ItemStack(Material.CAULDRON), new ItemStack(Material.NETHERITE_BLOCK) 34 | }, BlockFace.DOWN); 35 | } 36 | 37 | @Override 38 | public void onInteract(Player p, Block b) { 39 | // Verify a vanilla blast furnace is not being used 40 | if (BlockStorage.checkID(b) == null || !BlockStorage.checkID(b).equals("SUPERHEATED_FURNACE")) { 41 | return; 42 | } 43 | 44 | if (BlockStorage.getLocationInfo(b.getLocation(), "accessible") == null) { 45 | BlockStorage.addBlockInfo(b, "accessible", "true"); 46 | Utils.send(p, "&eFoundry has been registered. Right click the furnace with a lava bucket to heat."); 47 | } else if (BlockStorage.getLocationInfo(b.getLocation(), "ignited") == null) { 48 | if (p.getInventory().getItemInMainHand().getType() == Material.LAVA_BUCKET) { 49 | 50 | p.getInventory().getItemInMainHand().setType(Material.BUCKET); 51 | ArmorStand lavaStand = (ArmorStand) p.getWorld().spawnEntity(b.getLocation().add(0.5, -3, 0.5), 52 | EntityType.ARMOR_STAND); 53 | lavaStand.getEquipment().setHelmet(new CustomItemStack( 54 | SlimefunUtils.getCustomHead("b6965e6a58684c277d18717cec959f2833a72dfa95661019dbcdf3dbf66b048"))); 55 | lavaStand.setCanPickupItems(false); 56 | lavaStand.setGravity(false); 57 | lavaStand.setVisible(false); 58 | lavaStand.setCustomName("hehexdfluff"); 59 | lavaStand.setCustomNameVisible(false); 60 | Furnace furnace = (Furnace) b.getState(); 61 | furnace.setBurnTime((short)1000000); 62 | furnace.update(true); 63 | 64 | BlockStorage.addBlockInfo(b, "stand", String.valueOf(lavaStand.getUniqueId())); 65 | BlockStorage.addBlockInfo(b, "ignited", "true"); 66 | } else { 67 | Utils.send(p, "&cThis foundry still needs to be filled with lava!"); 68 | } 69 | } else if (BlockStorage.getLocationInfo(b.getLocation(), "ignited") != null) { 70 | // Reheat furnace (Cosmetic) 71 | Furnace furnace = (Furnace) b.getState(); 72 | furnace.setBurnTime((short)1000000); 73 | furnace.update(true); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/listeners/KeyedCrafterListener.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.listeners; 2 | 3 | import io.github.thebusybiscuit.slimefun4.api.events.PlayerRightClickEvent; 4 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; 5 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; 6 | import io.github.thebusybiscuit.slimefun4.core.attributes.RecipeDisplayItem; 7 | import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems; 8 | import io.ncbpfluffybear.fluffymachines.machines.AutoCraftingTable; 9 | import io.ncbpfluffybear.fluffymachines.machines.SmartFactory; 10 | import io.ncbpfluffybear.fluffymachines.utils.Utils; 11 | import java.util.Optional; 12 | import javax.annotation.Nullable; 13 | import me.mrCookieSlime.Slimefun.api.BlockStorage; 14 | import org.apache.commons.lang.WordUtils; 15 | import org.bukkit.Material; 16 | import org.bukkit.block.Block; 17 | import org.bukkit.entity.Player; 18 | import org.bukkit.event.Event; 19 | import org.bukkit.event.EventHandler; 20 | import org.bukkit.event.Listener; 21 | import org.bukkit.inventory.EquipmentSlot; 22 | import org.bukkit.inventory.ItemStack; 23 | 24 | public class KeyedCrafterListener implements Listener { 25 | 26 | public KeyedCrafterListener() { 27 | } 28 | 29 | @EventHandler 30 | private void onSmartFactoryInteract(PlayerRightClickEvent e) { 31 | Optional clickedBlock = e.getClickedBlock(); 32 | 33 | if (e.getHand() == EquipmentSlot.HAND && e.useBlock() != Event.Result.DENY && clickedBlock.isPresent() && e.getPlayer().isSneaking()) { 34 | Optional slimefunBlock = e.getSlimefunBlock(); 35 | 36 | if (!slimefunBlock.isPresent()) { 37 | return; 38 | } 39 | 40 | SlimefunItem sfBlock = slimefunBlock.get(); 41 | ItemStack item = e.getItem(); 42 | Player p = e.getPlayer(); 43 | SlimefunItem key = SlimefunItem.getByItem(item); 44 | Block b = clickedBlock.get(); 45 | 46 | // Handle SmartFactory recipe setting 47 | if (sfBlock instanceof SmartFactory) { 48 | 49 | if (isCargoNode(key)) { 50 | return; 51 | } 52 | e.cancel(); 53 | 54 | if (key == null) { 55 | Utils.send(p, "&cYou can not use vanilla items with this machine!"); 56 | return; 57 | } 58 | 59 | if (SmartFactory.getAcceptedItems().contains((SlimefunItemStack) key.getItem())) { 60 | 61 | BlockStorage.addBlockInfo(b, "recipe", key.getId()); 62 | BlockStorage.getInventory(b).replaceExistingItem(SmartFactory.RECIPE_SLOT, 63 | SmartFactory.getDisplayItem(key, ((RecipeDisplayItem) sfBlock).getDisplayRecipes()) 64 | ); 65 | Utils.send(p, "&aTarget recipe set to " + key.getItemName()); 66 | } else { 67 | Utils.send(p, "&cThis item is not supported!"); 68 | } 69 | 70 | } else if (sfBlock instanceof AutoCraftingTable) { 71 | 72 | if (isCargoNode(key)) { 73 | return; 74 | } 75 | e.cancel(); 76 | 77 | if (item.getType() == Material.AIR) { 78 | Utils.send(p, "&cRight click the machine with an item to set the vanilla recipe"); 79 | return; 80 | } 81 | 82 | BlockStorage.getInventory(b).replaceExistingItem(AutoCraftingTable.KEY_SLOT, 83 | AutoCraftingTable.createKeyItem(item.getType()) 84 | ); 85 | 86 | Utils.send(p, "&aTarget recipe set to " 87 | + WordUtils.capitalizeFully(item.getType().name().replace("_", " ")) 88 | ); 89 | } 90 | } 91 | } 92 | 93 | private boolean isCargoNode(@Nullable SlimefunItem recipe) { 94 | return recipe != null && (recipe.getItem() == SlimefunItems.CARGO_INPUT_NODE 95 | || recipe.getItem() == SlimefunItems.CARGO_OUTPUT_NODE || recipe.getItem() == SlimefunItems.CARGO_OUTPUT_NODE_2); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/items/MiniBarrel.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.items; 2 | 3 | import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; 4 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; 5 | import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; 6 | import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler; 7 | import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; 8 | import io.github.thebusybiscuit.slimefun4.libraries.dough.items.CustomItemStack; 9 | import io.github.thebusybiscuit.slimefun4.utils.ChatUtils; 10 | import io.github.thebusybiscuit.slimefun4.utils.NumberUtils; 11 | import io.ncbpfluffybear.fluffymachines.utils.Utils; 12 | import javax.annotation.Nonnull; 13 | import me.mrCookieSlime.Slimefun.api.BlockStorage; 14 | import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu; 15 | import org.bukkit.Material; 16 | import org.bukkit.block.Block; 17 | import org.bukkit.event.block.BlockPlaceEvent; 18 | import org.bukkit.inventory.ItemStack; 19 | 20 | public class MiniBarrel extends Barrel { 21 | private static final int MAX_STORAGE = 172800; 22 | 23 | public MiniBarrel(ItemGroup category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { 24 | super(category, item, recipeType, recipe, MAX_STORAGE); 25 | addItemHandler(onPlace()); 26 | } 27 | 28 | private BlockPlaceHandler onPlace() { 29 | return new BlockPlaceHandler(false) { 30 | @Override 31 | public void onPlayerPlace(@Nonnull BlockPlaceEvent e) { 32 | BlockStorage.addBlockInfo(e.getBlock(), "max-size", String.valueOf(barrelCapacity.getValue())); 33 | } 34 | }; 35 | } 36 | 37 | @Override 38 | protected void buildMenu(BlockMenu menu, Block b) { 39 | super.buildMenu(menu, b); 40 | menu.replaceExistingItem(13, new CustomItemStack(Material.YELLOW_STAINED_GLASS_PANE, 41 | "&eChange barrel size", "&7> Click to change max size", "&eCurrent size: " + getCapacity(b), 42 | "&eSize limit: " + barrelCapacity.getValue() 43 | )); 44 | menu.addMenuClickHandler(13, (p, slot, item, action) -> { 45 | p.closeInventory(); 46 | Utils.send(p, "&eType the new size of the barrel. Max size: " + barrelCapacity.getValue()); 47 | ChatUtils.awaitInput(p, message -> { 48 | String cleanMsg = message.replaceAll("[^0-9]", ""); 49 | int renameSize = NumberUtils.getInt(cleanMsg, 0); 50 | 51 | if (renameSize == 0 || renameSize > barrelCapacity.getValue()) { 52 | Utils.send(p, "&cThe new size must be between 0 and " + barrelCapacity.getValue()); 53 | return; 54 | } 55 | 56 | if (renameSize < getStored(b)) { 57 | Utils.send(p, "&cRemove items from the barrel before changing it to this size!"); 58 | return; 59 | } 60 | 61 | BlockStorage.addBlockInfo(b, "max-size", String.valueOf(renameSize)); 62 | menu.replaceExistingItem(13, new CustomItemStack(Material.YELLOW_STAINED_GLASS_PANE, 63 | "&eChange barrel size", "&7> Click to change max size", "&eCurrent size: " + renameSize, 64 | "&eSize limit: " + barrelCapacity.getValue() 65 | )); 66 | Utils.send(p, "&aMax size has been changed to " + renameSize); 67 | updateMenu(b, menu, true, renameSize); 68 | }); 69 | return false; 70 | }); 71 | } 72 | 73 | @Override 74 | public int getCapacity(Block b) { 75 | String capacity = BlockStorage.getLocationInfo(b.getLocation(), "max-size"); 76 | if (capacity == null) { 77 | BlockStorage.addBlockInfo(b, "max-size", String.valueOf(barrelCapacity.getValue())); 78 | return barrelCapacity.getValue(); 79 | } 80 | return Integer.parseInt(capacity); 81 | } 82 | 83 | public static int getDisplayCapacity() { 84 | int capacity = Slimefun.getItemCfg().getInt("MINI_FLUFFY_BARREL.capacity"); 85 | if (capacity == 0) { 86 | capacity = MAX_STORAGE; 87 | } 88 | 89 | return capacity; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/machines/ElectricDustFabricator.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.machines; 2 | 3 | import io.github.thebusybiscuit.slimefun4.core.attributes.RecipeDisplayItem; 4 | import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems; 5 | import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.ElectricDustWasher; 6 | import io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks.OreWasher; 7 | import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; 8 | import io.ncbpfluffybear.fluffymachines.utils.Constants; 9 | import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; 10 | import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; 11 | import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AContainer; 12 | import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineRecipe; 13 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; 14 | import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu; 15 | import io.github.thebusybiscuit.slimefun4.libraries.dough.items.CustomItemStack; 16 | import org.bukkit.Material; 17 | import org.bukkit.inventory.ItemStack; 18 | 19 | import javax.annotation.Nonnull; 20 | import java.util.ArrayList; 21 | import java.util.Arrays; 22 | import java.util.List; 23 | 24 | /** 25 | * The electric dust washer but accepts cobblestone 26 | * Low iq low effort machine 27 | * 28 | * @see ElectricDustWasher 29 | */ 30 | 31 | public class ElectricDustFabricator extends AContainer implements RecipeDisplayItem { 32 | 33 | public static final int ENERGY_CONSUMPTION = 256; 34 | public static final int CAPACITY = ENERGY_CONSUMPTION * 3; 35 | private OreWasher oreWasher; 36 | private final List acceptableInputs = new ArrayList<>(Arrays.asList( 37 | new ItemStack(Material.COBBLESTONE), new ItemStack(Material.ANDESITE), 38 | new ItemStack(Material.DIORITE), new ItemStack(Material.GRANITE) 39 | )); 40 | 41 | public ElectricDustFabricator(ItemGroup category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { 42 | super(category, item, recipeType, recipe); 43 | } 44 | 45 | @Override 46 | public void preRegister() { 47 | super.preRegister(); 48 | 49 | oreWasher = (OreWasher) SlimefunItems.ORE_WASHER.getItem(); 50 | } 51 | 52 | @Nonnull 53 | @Override 54 | public List getDisplayRecipes() { 55 | List displayRecipes = new ArrayList<>(); 56 | 57 | for (SlimefunItemStack dust : Constants.dusts) { 58 | displayRecipes.add(new CustomItemStack(Material.COBBLESTONE, 59 | "&fAny Cobblestone Variant", "&7Cobblestone", "&7Andesite", "&7Diorite", "&7Granite" 60 | )); 61 | displayRecipes.add(dust); 62 | } 63 | 64 | return displayRecipes; 65 | } 66 | 67 | @Override 68 | protected MachineRecipe findNextRecipe(BlockMenu menu) { 69 | for (int slot : getInputSlots()) { 70 | for (ItemStack acceptableInput : acceptableInputs) { 71 | if (SlimefunUtils.isItemSimilar(menu.getItemInSlot(slot), acceptableInput, true, false)) { 72 | if (!hasFreeSlot(menu)) { 73 | return null; 74 | } 75 | 76 | ItemStack dust = oreWasher.getRandomDust(); 77 | MachineRecipe recipe = new MachineRecipe(4 / getSpeed(), new ItemStack[] {acceptableInput}, 78 | new ItemStack[] {dust}); 79 | 80 | if (menu.fits(recipe.getOutput()[0], getOutputSlots())) { 81 | menu.consumeItem(slot); 82 | return recipe; 83 | } 84 | } 85 | } 86 | } 87 | 88 | return null; 89 | } 90 | 91 | private boolean hasFreeSlot(BlockMenu menu) { 92 | for (int slot : getOutputSlots()) { 93 | ItemStack item = menu.getItemInSlot(slot); 94 | 95 | if (item == null || item.getType() == Material.AIR) { 96 | return true; 97 | } 98 | } 99 | 100 | return false; 101 | } 102 | 103 | @Override 104 | public ItemStack getProgressBar() { 105 | return new ItemStack(Material.CAULDRON); 106 | } 107 | 108 | @Nonnull 109 | @Override 110 | public String getMachineIdentifier() { 111 | return "DUST_FABRICATOR"; 112 | } 113 | 114 | @Override 115 | public int getCapacity() { 116 | return CAPACITY; 117 | } 118 | 119 | @Override 120 | public int getEnergyConsumption() { 121 | return ENERGY_CONSUMPTION; 122 | } 123 | 124 | @Override 125 | public int getSpeed() { 126 | return 10; 127 | } 128 | 129 | } 130 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/items/tools/Paxel.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.items.tools; 2 | 3 | import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; 4 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; 5 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; 6 | import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; 7 | import io.github.thebusybiscuit.slimefun4.core.attributes.NotPlaceable; 8 | import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag; 9 | import io.ncbpfluffybear.fluffymachines.FluffyMachines; 10 | import io.ncbpfluffybear.fluffymachines.utils.FluffyItems; 11 | import java.util.Arrays; 12 | import java.util.HashSet; 13 | import java.util.Set; 14 | import java.util.stream.Collectors; 15 | import java.util.stream.Stream; 16 | import org.bukkit.Bukkit; 17 | import org.bukkit.Material; 18 | import org.bukkit.Tag; 19 | import org.bukkit.block.Block; 20 | import org.bukkit.entity.Player; 21 | import org.bukkit.event.EventHandler; 22 | import org.bukkit.event.Listener; 23 | import org.bukkit.event.block.BlockDamageEvent; 24 | import org.bukkit.event.entity.EntityDamageByEntityEvent; 25 | import org.bukkit.inventory.ItemStack; 26 | 27 | public class Paxel extends SlimefunItem implements Listener, NotPlaceable { 28 | 29 | public final Set axeBlocks = Stream.of( 30 | Tag.LOGS.getValues(), 31 | Tag.PLANKS.getValues(), 32 | Tag.WOODEN_STAIRS.getValues(), 33 | Tag.SIGNS.getValues(), 34 | Tag.WOODEN_FENCES.getValues(), 35 | Tag.FENCE_GATES.getValues(), 36 | Tag.WOODEN_TRAPDOORS.getValues(), 37 | Tag.WOODEN_PRESSURE_PLATES.getValues(), 38 | Tag.WOODEN_DOORS.getValues(), 39 | Tag.WOODEN_SLABS.getValues(), 40 | Tag.WOODEN_BUTTONS.getValues(), 41 | Tag.BANNERS.getValues(), 42 | Tag.LEAVES.getValues(), 43 | new HashSet<>(Arrays.asList(Material.CHEST, Material.TRAPPED_CHEST, Material.CRAFTING_TABLE, Material.SMITHING_TABLE, 44 | Material.LOOM, Material.CARTOGRAPHY_TABLE, Material.FLETCHING_TABLE, Material.BARREL, Material.JUKEBOX, 45 | Material.CAMPFIRE, Material.BOOKSHELF, Material.JACK_O_LANTERN, Material.CARVED_PUMPKIN, 46 | Material.PUMPKIN, Material.MELON, Material.COMPOSTER, Material.BEEHIVE, Material.BEE_NEST, 47 | Material.NOTE_BLOCK, Material.LADDER, Material.COCOA_BEANS, Material.DAYLIGHT_DETECTOR, Material.MUSHROOM_STEM, 48 | Material.BROWN_MUSHROOM_BLOCK, Material.RED_MUSHROOM_BLOCK, Material.BAMBOO, Material.VINE, Material.LECTERN)) 49 | ).flatMap(Set::stream).collect(Collectors.toSet()); 50 | 51 | public Paxel(ItemGroup category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { 52 | super(category, item, recipeType, recipe); 53 | 54 | Bukkit.getPluginManager().registerEvents(this, FluffyMachines.getInstance()); 55 | } 56 | 57 | @EventHandler(ignoreCancelled = true) 58 | private void onMine(BlockDamageEvent e) { 59 | Player p = e.getPlayer(); 60 | SlimefunItem sfItem = SlimefunItem.getByItem(p.getInventory().getItemInMainHand()); 61 | 62 | if (sfItem != null && sfItem == FluffyItems.PAXEL.getItem()) { 63 | boolean netherite = false; 64 | Block b = e.getBlock(); 65 | ItemStack item = p.getInventory().getItemInMainHand(); 66 | 67 | Material blockType = b.getType(); 68 | 69 | if (item.getType() == Material.NETHERITE_PICKAXE 70 | || item.getType() == Material.NETHERITE_AXE 71 | || item.getType() == Material.NETHERITE_SHOVEL 72 | ) { 73 | netherite = true; 74 | } 75 | 76 | if (SlimefunTag.EXPLOSIVE_SHOVEL_BLOCKS.isTagged(blockType)) { 77 | if (netherite) { 78 | item.setType(Material.NETHERITE_SHOVEL); 79 | } else { 80 | item.setType(Material.DIAMOND_SHOVEL); 81 | } 82 | } else if (axeBlocks.contains(blockType)) { 83 | if (netherite) { 84 | item.setType(Material.NETHERITE_AXE); 85 | } else { 86 | item.setType(Material.DIAMOND_AXE); 87 | } 88 | } else { 89 | if (netherite) { 90 | item.setType(Material.NETHERITE_PICKAXE); 91 | } else { 92 | item.setType(Material.DIAMOND_PICKAXE); 93 | } 94 | } 95 | } 96 | } 97 | 98 | @EventHandler(ignoreCancelled = true) 99 | private void onEntityHit(EntityDamageByEntityEvent e) { 100 | if (!(e.getDamager() instanceof Player)) { 101 | return; 102 | } 103 | 104 | Player p = (Player) e.getDamager(); 105 | ItemStack item = p.getInventory().getItemInMainHand(); 106 | SlimefunItem sfItem = SlimefunItem.getByItem(item); 107 | 108 | if (sfItem instanceof Paxel) { 109 | 110 | boolean netherite = item.getType() == Material.NETHERITE_PICKAXE 111 | || item.getType() == Material.NETHERITE_AXE 112 | || item.getType() == Material.NETHERITE_SHOVEL; 113 | 114 | if (netherite) { 115 | item.setType(Material.NETHERITE_AXE); 116 | } else { 117 | item.setType(Material.DIAMOND_AXE); 118 | } 119 | } 120 | 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/items/tools/UpgradedLumberAxe.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.items.tools; 2 | 3 | import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting; 4 | import io.github.thebusybiscuit.slimefun4.core.attributes.NotPlaceable; 5 | import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler; 6 | import io.github.thebusybiscuit.slimefun4.core.handlers.ToolUseHandler; 7 | import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; 8 | import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem; 9 | import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; 10 | import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; 11 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; 12 | import io.github.thebusybiscuit.slimefun4.libraries.dough.protection.Interaction; 13 | import me.mrCookieSlime.Slimefun.api.BlockStorage; 14 | import org.bukkit.Axis; 15 | import org.bukkit.Bukkit; 16 | import org.bukkit.Material; 17 | import org.bukkit.Sound; 18 | import org.bukkit.Tag; 19 | import org.bukkit.block.Block; 20 | import org.bukkit.block.data.Orientable; 21 | import org.bukkit.inventory.ItemStack; 22 | 23 | import javax.annotation.Nonnull; 24 | import java.util.LinkedList; 25 | import java.util.List; 26 | import java.util.function.Predicate; 27 | 28 | public class UpgradedLumberAxe extends SimpleSlimefunItem implements NotPlaceable { 29 | 30 | private static final int MAX_BROKEN = 200; 31 | private static final int MAX_STRIPPED = 200; 32 | private static final int RANGE = 2; 33 | 34 | private final ItemSetting triggerOtherPlugins = new ItemSetting<>(this, "trigger-other-plugins", true); 35 | 36 | public UpgradedLumberAxe(ItemGroup category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { 37 | super(category, item, recipeType, recipe); 38 | } 39 | 40 | @Override 41 | public void preRegister() { 42 | super.preRegister(); 43 | 44 | addItemHandler(onBlockBreak()); 45 | addItemSetting(triggerOtherPlugins); 46 | } 47 | 48 | private ToolUseHandler onBlockBreak() { 49 | return (e, tool, fortune, drops) -> { 50 | if (Tag.LOGS.getValues().contains(e.getBlock().getType())) { 51 | 52 | // Prevent use on Slimefun blocks 53 | if (BlockStorage.checkID(e.getBlock()) != null) { 54 | return; 55 | } 56 | 57 | if (e instanceof AlternateBreakEvent) { 58 | return; 59 | } 60 | 61 | List logs = find(e.getBlock(), MAX_BROKEN, b -> Tag.LOGS.isTagged(b.getType())); 62 | 63 | logs.remove(e.getBlock()); 64 | 65 | for (Block b : logs) { 66 | if (Slimefun.getProtectionManager().hasPermission(e.getPlayer(), b, 67 | Interaction.BREAK_BLOCK) && BlockStorage.checkID(b) == null) { 68 | if (triggerOtherPlugins.getValue()) { 69 | Bukkit.getPluginManager().callEvent(new AlternateBreakEvent(b, e.getPlayer())); 70 | } 71 | b.breakNaturally(tool); 72 | } 73 | } 74 | } 75 | }; 76 | } 77 | 78 | @Nonnull 79 | @Override 80 | public ItemUseHandler getItemHandler() { 81 | return e -> { 82 | if (e.getClickedBlock().isPresent()) { 83 | Block block = e.getClickedBlock().get(); 84 | 85 | if (isUnstrippedLog(block)) { 86 | List logs = find(block, MAX_STRIPPED, this::isUnstrippedLog); 87 | 88 | logs.remove(block); 89 | 90 | for (Block b : logs) { 91 | if (Slimefun.getProtectionManager().hasPermission(e.getPlayer(), b, 92 | Interaction.BREAK_BLOCK) && BlockStorage.checkID(b) == null) { 93 | stripLog(b); 94 | } 95 | } 96 | } 97 | } 98 | }; 99 | } 100 | 101 | private boolean isUnstrippedLog(Block block) { 102 | return Tag.LOGS.isTagged(block.getType()) && !block.getType().name().startsWith("STRIPPED_"); 103 | } 104 | 105 | private void stripLog(Block b) { 106 | b.getWorld().playSound(b.getLocation(), Sound.ITEM_AXE_STRIP, 1, 1); 107 | Axis axis = ((Orientable) b.getBlockData()).getAxis(); 108 | b.setType(Material.valueOf("STRIPPED_" + b.getType().name())); 109 | 110 | Orientable orientable = (Orientable) b.getBlockData(); 111 | orientable.setAxis(axis); 112 | b.setBlockData(orientable); 113 | } 114 | 115 | public static List find(Block b, int limit, Predicate predicate) { 116 | List list = new LinkedList<>(); 117 | expand(b, list, limit, predicate); 118 | return list; 119 | } 120 | 121 | private static void expand(Block anchor, List list, int limit, Predicate predicate) { 122 | 123 | if (list.size() < limit) { 124 | list.add(anchor); 125 | for (int x = -RANGE; x <= RANGE; x++) { 126 | for (int z = -RANGE; z <= RANGE; z++) { 127 | for (int y = -RANGE; y <= RANGE; y++) { 128 | Block next = anchor.getRelative(x, y, z); 129 | if (!list.contains(next) && predicate.test(next)) { 130 | expand(next, list, limit, predicate); 131 | } 132 | } 133 | } 134 | } 135 | 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/items/FireproofRune.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.items; 2 | 3 | import io.github.thebusybiscuit.slimefun4.core.handlers.ItemDropHandler; 4 | import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem; 5 | import io.ncbpfluffybear.fluffymachines.FluffyMachines; 6 | import io.ncbpfluffybear.fluffymachines.utils.Utils; 7 | import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; 8 | import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; 9 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; 10 | import org.bukkit.ChatColor; 11 | import org.bukkit.Location; 12 | import org.bukkit.Material; 13 | import org.bukkit.NamespacedKey; 14 | import org.bukkit.Sound; 15 | import org.bukkit.entity.Entity; 16 | import org.bukkit.entity.Item; 17 | import org.bukkit.entity.Player; 18 | import org.bukkit.inventory.ItemStack; 19 | import org.bukkit.inventory.meta.ItemMeta; 20 | import org.bukkit.persistence.PersistentDataContainer; 21 | import org.bukkit.persistence.PersistentDataType; 22 | 23 | import javax.annotation.Nonnull; 24 | import javax.annotation.Nullable; 25 | import java.util.ArrayList; 26 | import java.util.Collection; 27 | import java.util.List; 28 | import java.util.Optional; 29 | 30 | /** 31 | * The Fireproof Rune prevents items from 32 | * burning in lava or fire 33 | * Heavily based off of the Soulbound Rune 34 | * 35 | * @author NCBPFluffyBear 36 | *

37 | * Worked on Soulbound Rune: 38 | * @author Linox 39 | * @author Walshy 40 | * @author TheBusyBiscuit 41 | */ 42 | 43 | public class FireproofRune extends SimpleSlimefunItem { 44 | 45 | private static final double RANGE = 1.5; 46 | private static final NamespacedKey FIREPROOF_KEY = new NamespacedKey(FluffyMachines.getInstance(), "fireproof"); 47 | private static final String FIREPROOF_LORE = ChatColor.RED + "Fireproof"; 48 | 49 | 50 | public FireproofRune(ItemGroup category, SlimefunItemStack item, RecipeType type, ItemStack[] recipe) { 51 | super(category, item, type, recipe); 52 | } 53 | 54 | @Nonnull 55 | @Override 56 | public ItemDropHandler getItemHandler() { 57 | return (e, p, item) -> { 58 | if (isItem(item.getItemStack())) { 59 | 60 | if (!this.canUse(p, true)) { 61 | return true; 62 | } 63 | 64 | Utils.runSync(() -> activate(p, item), 20L); 65 | 66 | return true; 67 | } 68 | return false; 69 | }; 70 | } 71 | 72 | private void activate(Player p, Item rune) { 73 | if (!rune.isValid()) { 74 | return; 75 | } 76 | 77 | Location l = rune.getLocation(); 78 | Collection entities = l.getWorld().getNearbyEntities(l, RANGE, RANGE, RANGE, this::findCompatibleItem); 79 | Optional optional = entities.stream().findFirst(); 80 | 81 | if (optional.isPresent()) { 82 | Item item = (Item) optional.get(); 83 | ItemStack itemStack = item.getItemStack(); 84 | 85 | if (itemStack.getAmount() == 1) { 86 | // This lightning is just an effect, it deals no damage. 87 | l.getWorld().strikeLightningEffect(l); 88 | 89 | Utils.runSync(() -> { 90 | // Being sure entities are still valid and not picked up or whatsoever. 91 | if (rune.isValid() && item.isValid() && itemStack.getAmount() == 1) { 92 | 93 | l.getWorld().createExplosion(l, 0); 94 | l.getWorld().playSound(l, Sound.ENTITY_GENERIC_EXPLODE, 0.3F, 1); 95 | 96 | item.remove(); 97 | rune.remove(); 98 | 99 | setFireproof(itemStack); 100 | l.getWorld().dropItemNaturally(l, itemStack); 101 | 102 | Utils.send(p, "&aYour item is now fireproof"); 103 | } else { 104 | Utils.send(p, "&cYour item could not be made fireproof"); 105 | } 106 | }, 10L); 107 | } else { 108 | Utils.send(p, "&cYour item could not be made fireproof"); 109 | } 110 | } 111 | } 112 | 113 | private boolean findCompatibleItem(Entity entity) { 114 | if (entity instanceof Item) { 115 | Item item = (Item) entity; 116 | 117 | return !isFireproof(item.getItemStack()) && !isItem(item.getItemStack()); 118 | } 119 | 120 | return false; 121 | } 122 | 123 | public static void setFireproof(@Nullable ItemStack item) { 124 | if (item != null && item.getType() != Material.AIR) { 125 | boolean isFireproof = isFireproof(item); 126 | ItemMeta meta = item.getItemMeta(); 127 | PersistentDataContainer container = meta.getPersistentDataContainer(); 128 | if (!isFireproof) { 129 | container.set(FIREPROOF_KEY, PersistentDataType.BYTE, (byte) 1); 130 | List lore = meta.hasLore() ? meta.getLore() : new ArrayList<>(); 131 | lore.add(FIREPROOF_LORE); 132 | meta.setLore(lore); 133 | item.setItemMeta(meta); 134 | } 135 | } 136 | } 137 | 138 | public static boolean isFireproof(@Nullable ItemStack item) { 139 | if (item != null && item.getType() != Material.AIR) { 140 | ItemMeta meta = item.hasItemMeta() ? item.getItemMeta() : null; 141 | return hasFireproofFlag(meta); 142 | } else { 143 | return false; 144 | } 145 | } 146 | 147 | private static boolean hasFireproofFlag(@Nullable ItemMeta meta) { 148 | if (meta != null) { 149 | PersistentDataContainer container = meta.getPersistentDataContainer(); 150 | return container.has(FIREPROOF_KEY, PersistentDataType.BYTE); 151 | } 152 | return false; 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/items/EnderChestInsertionNode.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.items; 2 | 3 | import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler; 4 | import io.github.thebusybiscuit.slimefun4.core.handlers.BlockUseHandler; 5 | import io.github.thebusybiscuit.slimefun4.libraries.paperlib.PaperLib; 6 | import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config; 7 | import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; 8 | import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; 9 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; 10 | import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker; 11 | import me.mrCookieSlime.Slimefun.api.BlockStorage; 12 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; 13 | import io.ncbpfluffybear.fluffymachines.utils.Utils; 14 | import org.bukkit.Bukkit; 15 | import org.bukkit.Material; 16 | import org.bukkit.block.Block; 17 | import org.bukkit.block.BlockFace; 18 | import org.bukkit.block.BlockState; 19 | import org.bukkit.block.Container; 20 | import org.bukkit.block.EnderChest; 21 | import org.bukkit.entity.Player; 22 | import org.bukkit.event.block.BlockPlaceEvent; 23 | import org.bukkit.inventory.Inventory; 24 | import org.bukkit.inventory.InventoryHolder; 25 | import org.bukkit.inventory.ItemStack; 26 | 27 | import javax.annotation.Nonnull; 28 | import java.util.UUID; 29 | 30 | /** 31 | * This {@link SlimefunItem} transfers items to the facing 32 | * {@link EnderChest} from the {@link Container} behind it 33 | * 34 | * @author NCBPFluffyBear 35 | */ 36 | public class EnderChestInsertionNode extends SlimefunItem { 37 | 38 | private static final Material material = Material.ENDER_CHEST; 39 | 40 | public EnderChestInsertionNode(ItemGroup category, SlimefunItemStack item, RecipeType recipeType, 41 | ItemStack[] recipe) { 42 | super(category, item, recipeType, recipe); 43 | 44 | addItemHandler(onPlace()); 45 | addItemHandler(onInteract()); 46 | } 47 | 48 | @Override 49 | public void preRegister() { 50 | this.addItemHandler(new BlockTicker() { 51 | public void tick(Block b, SlimefunItem sf, Config data) { 52 | EnderChestInsertionNode.this.tick(b); 53 | } 54 | 55 | public boolean isSynchronized() { 56 | return true; 57 | } 58 | }); 59 | } 60 | 61 | private void tick(@Nonnull Block b) { 62 | ItemStack transferItemStack; 63 | BlockFace face; 64 | 65 | if (b.getRelative(BlockFace.NORTH).getType() == material) { 66 | face = BlockFace.SOUTH; 67 | 68 | } else if (b.getRelative(BlockFace.SOUTH).getType() == material) { 69 | face = BlockFace.NORTH; 70 | 71 | 72 | } else if (b.getRelative(BlockFace.EAST).getType() == material) { 73 | face = BlockFace.WEST; 74 | 75 | 76 | } else if (b.getRelative(BlockFace.WEST).getType() == material) { 77 | face = BlockFace.EAST; 78 | 79 | } else { 80 | return; 81 | } 82 | 83 | BlockState state = PaperLib.getBlockState(b.getRelative(face), false).getState(); 84 | 85 | if (b.getRelative(face).getState() instanceof InventoryHolder) { 86 | Player p = Bukkit.getOfflinePlayer(UUID.fromString(BlockStorage.getLocationInfo(b.getLocation(), "owner"))).getPlayer(); 87 | 88 | // Ender chest null check necessary because Bukkit yes. 89 | if (p != null) { 90 | 91 | boolean enderValid = false; 92 | boolean containerValid = false; 93 | int enderIndex = -1; 94 | int containerIndex = -1; 95 | 96 | Inventory containerInv = ((InventoryHolder) state).getInventory(); 97 | 98 | for (int i = 0; i < containerInv.getSize(); i++) { 99 | 100 | if (containerInv.getItem(i) != null) { 101 | containerIndex = i; 102 | containerValid = true; 103 | break; 104 | } 105 | } 106 | 107 | Inventory enderInv = p.getEnderChest(); 108 | 109 | for (int i = 0; i < enderInv.getSize(); i++) { 110 | 111 | if (enderInv.getItem(i) == null) { 112 | enderIndex = i; 113 | enderValid = true; 114 | break; 115 | } 116 | } 117 | 118 | if (enderValid && containerValid) { 119 | transferItemStack = containerInv.getItem(containerIndex); 120 | containerInv.setItem(containerIndex, null); 121 | 122 | enderInv.setItem(enderIndex, transferItemStack); 123 | } 124 | } 125 | } 126 | } 127 | 128 | private BlockPlaceHandler onPlace() { 129 | return new BlockPlaceHandler(false) { 130 | @Override 131 | public void onPlayerPlace(@Nonnull BlockPlaceEvent e) { 132 | Player p = e.getPlayer(); 133 | Block b = e.getBlock(); 134 | 135 | if (!e.isCancelled()) { 136 | BlockStorage.addBlockInfo(b, "owner", p.getUniqueId().toString()); 137 | BlockStorage.addBlockInfo(b, "playername", p.getDisplayName()); 138 | Utils.send(p, "&aEnder Chest Insertion Node registered to " + p.getDisplayName() 139 | + " &7(UUID: " + p.getUniqueId() + ")"); 140 | } 141 | } 142 | }; 143 | } 144 | 145 | private BlockUseHandler onInteract() { 146 | return e -> { 147 | Player p = e.getPlayer(); 148 | Block b = e.getClickedBlock().get(); 149 | Utils.send(p, "&eThis Ender Chest Insertion Node belongs to " + 150 | BlockStorage.getLocationInfo(b.getLocation(), "playername") 151 | + " &7(UUID: " + BlockStorage.getLocationInfo(b.getLocation(), "owner") + ")"); 152 | }; 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/machines/WaterSprinkler.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.machines; 2 | 3 | import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting; 4 | import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.accelerators.AbstractGrowthAccelerator; 5 | import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.accelerators.CropGrowthAccelerator; 6 | import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils; 7 | import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; 8 | import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; 9 | import me.mrCookieSlime.Slimefun.api.BlockStorage; 10 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; 11 | import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu; 12 | import io.github.thebusybiscuit.slimefun4.libraries.dough.items.CustomItemStack; 13 | import org.bukkit.Material; 14 | import org.bukkit.Particle; 15 | import org.bukkit.block.Block; 16 | import org.bukkit.block.BlockFace; 17 | import org.bukkit.block.data.Ageable; 18 | import org.bukkit.block.data.BlockData; 19 | import org.bukkit.inventory.ItemStack; 20 | 21 | import javax.annotation.Nonnull; 22 | import java.util.concurrent.ThreadLocalRandom; 23 | 24 | /** 25 | * The {@link WaterSprinkler} speeds up the growth of nearby crops 26 | * when water is under the machine 27 | * Essentially a modified {@link CropGrowthAccelerator} 28 | * 29 | * @author FluffyBear 30 | */ 31 | public class WaterSprinkler extends AbstractGrowthAccelerator { 32 | 33 | public final ItemSetting successChance = new ItemSetting<>(this, "success-chance", 0.5); 34 | public static final int ENERGY_CONSUMPTION = 16; 35 | public static final int CAPACITY = 128; 36 | private static final int RADIUS = 2; 37 | private static final int PROGRESS_SLOT = 4; 38 | private static final CustomItemStack noWaterItem = new CustomItemStack(Material.BUCKET, 39 | "&cNo water found", 40 | "", 41 | "&cPlease place water under the sprinkler!" 42 | ); 43 | private static final CustomItemStack waterFoundItem = new CustomItemStack(Material.WATER_BUCKET, 44 | "&bWater detected" 45 | ); 46 | private final ItemSetting particles = new ItemSetting<>(this, "particles", true); 47 | 48 | public WaterSprinkler(ItemGroup category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { 49 | super(category, item, recipeType, recipe); 50 | 51 | createPreset(this, "&bWater Sprinkler", 52 | blockMenuPreset -> { 53 | for (int i = 0; i < 9; i++) 54 | blockMenuPreset.addItem(i, ChestMenuUtils.getBackground(), ChestMenuUtils.getEmptyClickHandler()); 55 | 56 | blockMenuPreset.addItem(PROGRESS_SLOT, noWaterItem); 57 | }); 58 | 59 | addItemSetting(successChance, particles); 60 | } 61 | 62 | public int getEnergyConsumption() { 63 | return ENERGY_CONSUMPTION; 64 | } 65 | 66 | @Override 67 | public int getCapacity() { 68 | return CAPACITY; 69 | } 70 | 71 | public int getRadius() { 72 | return RADIUS; 73 | } 74 | 75 | @Override 76 | public int[] getInputSlots() { 77 | return new int[0]; 78 | } 79 | 80 | @Override 81 | public int[] getOutputSlots() { 82 | return new int[0]; 83 | } 84 | 85 | @Override 86 | protected void tick(@Nonnull Block b) { 87 | if (this.isDisabled()) { 88 | return; 89 | } 90 | 91 | final BlockMenu inv = BlockStorage.getInventory(b); 92 | boolean open = inv.hasViewer(); 93 | 94 | if (b.getRelative(BlockFace.DOWN).getType() == Material.WATER) { 95 | if (open) { 96 | inv.replaceExistingItem(PROGRESS_SLOT, waterFoundItem); 97 | } 98 | } else { 99 | if (open) { 100 | inv.replaceExistingItem(PROGRESS_SLOT, noWaterItem); 101 | } 102 | return; 103 | } 104 | 105 | if (getCharge(b.getLocation()) >= getEnergyConsumption()) { 106 | for (int x = -getRadius(); x <= getRadius(); x++) { 107 | for (int z = -getRadius(); z <= getRadius(); z++) { 108 | final Block block = b.getRelative(x, 0, z); 109 | 110 | if (particles.getValue()) { 111 | block.getWorld().spawnParticle(Particle.WATER_SPLASH, block.getLocation().add(0.5D, 0.5D, 112 | 0.5D), 4, 0.1F, 0.1F, 0.1F); 113 | } 114 | 115 | BlockData blockData = block.getBlockData(); 116 | 117 | if (blockData instanceof Ageable) { 118 | grow(block); 119 | removeCharge(b.getLocation(), getEnergyConsumption()); 120 | } 121 | } 122 | } 123 | } 124 | } 125 | 126 | private void grow(@Nonnull Block crop) { 127 | 128 | final double random = ThreadLocalRandom.current().nextDouble(); 129 | if (successChance.getValue() >= random) { 130 | if (crop.getType() == Material.SUGAR_CANE) { 131 | for (int i = 1; i < 3; i++) { 132 | final Block above = crop.getRelative(BlockFace.UP, i); 133 | if (above.getType().isAir()) { 134 | above.setType(Material.SUGAR_CANE); 135 | break; 136 | } else if (above.getType() != Material.SUGAR_CANE) { 137 | return; 138 | } 139 | } 140 | } else { 141 | final Ageable ageable = (Ageable) crop.getBlockData(); 142 | if (ageable.getAge() < ageable.getMaximumAge()) { 143 | 144 | ageable.setAge(ageable.getAge() + 1); 145 | crop.setBlockData(ageable); 146 | 147 | crop.getWorld().spawnParticle(Particle.VILLAGER_HAPPY, crop.getLocation().add(0.5D, 0.5D, 0.5D), 148 | 4, 0.1F, 0.1F, 0.1F); 149 | } 150 | } 151 | } 152 | } 153 | 154 | } 155 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 4.0.0 6 | io.ncbpfluffybear 7 | FluffyMachines 8 | 1.0.0 9 | 10 | 11 | 16 12 | 16 13 | UTF-8 14 | 15 | 16 | 17 | 18 | paper-repo 19 | https://repo.destroystokyo.com/repository/maven-public/ 20 | 21 | 22 | 23 | spigot-repo 24 | https://hub.spigotmc.org/nexus/content/repositories/snapshots/ 25 | 26 | 27 | 28 | jitpack.io 29 | https://jitpack.io 30 | 31 | 32 | 33 | CodeMC 34 | https://repo.codemc.org/repository/maven-public 35 | 36 | 37 | 38 | 39 | ${project.name} v${project.version} 40 | clean package 41 | ${basedir}/src/main/java 42 | 43 | 44 | 45 | ${basedir}/src/main/resources 46 | true 47 | 48 | * 49 | 50 | 51 | 52 | 53 | 54 | 55 | org.apache.maven.plugins 56 | maven-compiler-plugin 57 | 3.9.0 58 | 59 | 60 | 61 | org.apache.maven.plugins 62 | maven-shade-plugin 63 | 3.5.1 64 | 65 | 66 | 67 | org.bstats 68 | io.ncbpfluffybear.shaded.bstats 69 | 70 | 71 | com.github.Slimefun-Addon-Community.extrautils 72 | io.ncbpfluffybear.shaded.extrautils 73 | 74 | 75 | 76 | 77 | 78 | 79 | *:* 80 | 81 | META-INF/*.MF 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | package 90 | 91 | shade 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | org.spigotmc 102 | spigot-api 103 | 1.16.3-R0.1-SNAPSHOT 104 | provided 105 | 106 | 107 | 108 | io.github.TheBusyBiscuit 109 | Slimefun4 110 | RC-37 111 | provided 112 | 113 | 114 | 115 | com.gmail.nossr50.mcMMO 116 | mcMMO 117 | 2.1.149 118 | provided 119 | 120 | 121 | org.jetbrains 122 | annotations 123 | 124 | 125 | com.sk89q.worldguard 126 | worldguard-core 127 | 128 | 129 | com.sk89q.worldguard 130 | worldguard-legacy 131 | 132 | 133 | 134 | 135 | 136 | com.google.code.findbugs 137 | jsr305 138 | 3.0.2 139 | provided 140 | 141 | 142 | org.projectlombok 143 | lombok 144 | 1.18.20 145 | provided 146 | 147 | 148 | 149 | org.bstats 150 | bstats-bukkit 151 | 2.2.1 152 | compile 153 | 154 | 155 | 156 | com.github.Slimefun-Addon-Community 157 | extrautils 158 | 73e76ac06c 159 | 160 | 161 | 162 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/items/tools/FluffyWrench.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.items.tools; 2 | 3 | import io.github.thebusybiscuit.slimefun4.core.attributes.DamageableItem; 4 | import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent; 5 | import io.github.thebusybiscuit.slimefun4.core.attributes.Rechargeable; 6 | import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler; 7 | import io.github.thebusybiscuit.slimefun4.core.networks.cargo.CargoNet; 8 | import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems; 9 | import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; 10 | import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem; 11 | import io.github.thebusybiscuit.slimefun4.implementation.items.cargo.TrashCan; 12 | import io.ncbpfluffybear.fluffymachines.FluffyMachines; 13 | import io.ncbpfluffybear.fluffymachines.utils.Constants; 14 | import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; 15 | import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; 16 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; 17 | import me.mrCookieSlime.Slimefun.api.BlockStorage; 18 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; 19 | import io.github.thebusybiscuit.slimefun4.libraries.dough.protection.Interaction; 20 | import org.bukkit.Bukkit; 21 | import org.bukkit.Material; 22 | import org.bukkit.block.Block; 23 | import org.bukkit.entity.Player; 24 | import org.bukkit.event.Event; 25 | import org.bukkit.event.EventHandler; 26 | import org.bukkit.event.Listener; 27 | import org.bukkit.event.block.BlockBreakEvent; 28 | import org.bukkit.event.player.PlayerInteractEvent; 29 | import org.bukkit.inventory.ItemStack; 30 | 31 | import javax.annotation.Nonnull; 32 | import java.util.HashMap; 33 | import java.util.UUID; 34 | 35 | /** 36 | * This {@link SimpleSlimefunItem} allows players to 37 | * instantly break any {@link EnergyNetComponent} block 38 | * or {@link CargoNet} block. 39 | * 40 | * @author NCBPFluffyBear 41 | */ 42 | public class FluffyWrench extends SimpleSlimefunItem implements Listener, DamageableItem, Rechargeable { 43 | 44 | private final Wrench type; 45 | 46 | private final HashMap cooldowns = new HashMap<>(); 47 | private static final int WRENCH_DELAY = 250; // Not an itemsetting, too low causes dupes and no reason to increase 48 | 49 | public FluffyWrench(ItemGroup category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, Wrench type) { 50 | super(category, item, recipeType, recipe); 51 | this.type = type; 52 | 53 | Bukkit.getPluginManager().registerEvents(this, FluffyMachines.getInstance()); 54 | } 55 | 56 | @Nonnull 57 | @Override 58 | public ItemUseHandler getItemHandler() { 59 | return e -> e.setUseBlock(Event.Result.DENY); 60 | } 61 | 62 | @EventHandler 63 | public void onWrenchInteract(PlayerInteractEvent e) { 64 | Player p = e.getPlayer(); 65 | ItemStack wrenchItem = e.getItem(); 66 | 67 | Long cooldown = cooldowns.get(p.getUniqueId()); 68 | if (isItem(wrenchItem) && cooldown != null 69 | ) { 70 | if ((System.currentTimeMillis() - cooldown) < WRENCH_DELAY) { 71 | return; 72 | } 73 | } 74 | cooldowns.put(p.getUniqueId(), System.currentTimeMillis()); 75 | 76 | Block block = e.getClickedBlock(); 77 | // Check if player has wrench and is left clicking block 78 | // Can't use offhand because a player can offhand the wrench to escape the event 79 | if (isItem(e.getItem()) && !isItem(p.getInventory().getItemInOffHand()) 80 | && e.getAction().toString().endsWith("_BLOCK") 81 | && Slimefun.getProtectionManager().hasPermission(e.getPlayer(), 82 | block.getLocation(), Interaction.BREAK_BLOCK) 83 | ) { 84 | e.setCancelled(true); 85 | SlimefunItem slimefunBlock = BlockStorage.check(block); 86 | 87 | // Check if slimefunBlock is not a machine or a cargo component 88 | if (slimefunBlock == null 89 | || (!(slimefunBlock instanceof EnergyNetComponent) 90 | && !slimefunBlock.getId().startsWith("CARGO_NODE") 91 | && !slimefunBlock.getId().equals(SlimefunItems.CARGO_MANAGER.getItemId()) 92 | && !(slimefunBlock instanceof TrashCan)) 93 | ) { 94 | return; 95 | } 96 | 97 | if (!type.isElectric) { 98 | damageItem(p, wrenchItem); 99 | breakBlock(block, p); 100 | } else if (removeItemCharge(wrenchItem, 1)) { 101 | breakBlock(block, p); 102 | } 103 | } 104 | } 105 | 106 | public static void breakBlock(Block block, Player p) { 107 | BlockBreakEvent breakEvent = new BlockBreakEvent(block, p); 108 | Bukkit.getPluginManager().callEvent(breakEvent); 109 | if (!breakEvent.isCancelled()) { 110 | BlockStorage.clearBlockInfo(block); 111 | block.setType(Material.AIR); 112 | } 113 | } 114 | 115 | @Override 116 | public boolean isDamageable() { 117 | return true; 118 | } 119 | 120 | @Override 121 | public float getMaxItemCharge(ItemStack item) { 122 | if (!type.isElectric) { 123 | return 0; 124 | } else { 125 | return type.getMaxCharge(); 126 | } 127 | } 128 | 129 | public enum Wrench { 130 | DEFAULT(Material.GOLDEN_AXE, false, 0), 131 | REINFORCED(Material.DIAMOND_AXE, false, 0), 132 | CARBONADO(Material.NETHERITE_AXE, true, 5000); 133 | 134 | private final Material material; 135 | private final boolean isElectric; 136 | private final int maxCharge; 137 | 138 | Wrench(Material material, boolean isElectric, int maxCharge) { 139 | this.material = material; 140 | this.isElectric = isElectric; 141 | this.maxCharge = maxCharge; 142 | } 143 | 144 | public Material getMaterial() { 145 | return material; 146 | } 147 | 148 | public boolean isElectric() { 149 | return isElectric; 150 | } 151 | 152 | public int getMaxCharge() { 153 | return maxCharge; 154 | } 155 | } 156 | } -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/items/tools/WarpPadConfigurator.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.items.tools; 2 | 3 | import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; 4 | import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting; 5 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; 6 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; 7 | import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; 8 | import io.github.thebusybiscuit.slimefun4.core.attributes.HologramOwner; 9 | import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; 10 | import io.github.thebusybiscuit.slimefun4.libraries.dough.protection.Interaction; 11 | import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; 12 | import io.ncbpfluffybear.fluffymachines.FluffyMachines; 13 | import io.ncbpfluffybear.fluffymachines.utils.FluffyItems; 14 | import io.ncbpfluffybear.fluffymachines.utils.Utils; 15 | import me.mrCookieSlime.Slimefun.api.BlockStorage; 16 | import org.bukkit.Bukkit; 17 | import org.bukkit.ChatColor; 18 | import org.bukkit.NamespacedKey; 19 | import org.bukkit.block.Block; 20 | import org.bukkit.entity.Player; 21 | import org.bukkit.event.EventHandler; 22 | import org.bukkit.event.Listener; 23 | import org.bukkit.event.block.Action; 24 | import org.bukkit.event.player.PlayerInteractEvent; 25 | import org.bukkit.inventory.EquipmentSlot; 26 | import org.bukkit.inventory.ItemStack; 27 | import org.bukkit.inventory.meta.ItemMeta; 28 | import org.bukkit.persistence.PersistentDataContainer; 29 | import org.bukkit.persistence.PersistentDataType; 30 | 31 | import java.util.List; 32 | 33 | public class WarpPadConfigurator extends SlimefunItem implements HologramOwner, Listener { 34 | 35 | private final NamespacedKey xCoord = new NamespacedKey(FluffyMachines.getInstance(), "xCoordinate"); 36 | private final NamespacedKey yCoord = new NamespacedKey(FluffyMachines.getInstance(), "yCoordinate"); 37 | private final NamespacedKey zCoord = new NamespacedKey(FluffyMachines.getInstance(), "zCoordinate"); 38 | private final NamespacedKey world = new NamespacedKey(FluffyMachines.getInstance(), "world"); 39 | 40 | private static final int LORE_COORDINATE_INDEX = 4; 41 | private final ItemSetting MAX_DISTANCE = new ItemSetting<>(this, "max-distance", 100); 42 | 43 | public WarpPadConfigurator(ItemGroup category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { 44 | super(category, item, recipeType, recipe); 45 | 46 | Bukkit.getPluginManager().registerEvents(this, FluffyMachines.getInstance()); 47 | 48 | addItemSetting(MAX_DISTANCE); 49 | 50 | } 51 | 52 | @EventHandler 53 | private void onInteract(PlayerInteractEvent e) { 54 | 55 | if (e.getClickedBlock() == null || e.getHand() != EquipmentSlot.HAND) { 56 | return; 57 | } 58 | 59 | Block b = e.getClickedBlock(); 60 | Player p = e.getPlayer(); 61 | 62 | if (BlockStorage.hasBlockInfo(b) && BlockStorage.check(b) == FluffyItems.WARP_PAD.getItem() 63 | && Slimefun.getProtectionManager().hasPermission(p, b.getLocation(), Interaction.PLACE_BLOCK)) { 64 | if (SlimefunUtils.isItemSimilar(p.getInventory().getItemInMainHand(), FluffyItems.WARP_PAD_CONFIGURATOR, 65 | false)) { 66 | 67 | ItemStack item = p.getInventory().getItemInMainHand(); 68 | ItemMeta meta = item.getItemMeta(); 69 | List lore = meta.getLore(); 70 | PersistentDataContainer pdc = meta.getPersistentDataContainer(); 71 | 72 | if (e.getAction() == Action.RIGHT_CLICK_BLOCK) { 73 | 74 | // Destination 75 | if (p.isSneaking()) { 76 | pdc.set(world, PersistentDataType.STRING, b.getWorld().getName()); 77 | 78 | pdc.set(xCoord, PersistentDataType.INTEGER, b.getX()); 79 | pdc.set(yCoord, PersistentDataType.INTEGER, b.getY()); 80 | pdc.set(zCoord, PersistentDataType.INTEGER, b.getZ()); 81 | lore.set(LORE_COORDINATE_INDEX, ChatColor.translateAlternateColorCodes( 82 | '&', "&eLinked Coordinates: &7" + b.getX() + ", " + b.getY() + ", " + b.getZ())); 83 | 84 | meta.setLore(lore); 85 | item.setItemMeta(meta); 86 | 87 | updateHologram(b, "&a&lDestination"); 88 | BlockStorage.addBlockInfo(b, "type", "destination"); 89 | Utils.send(p, "&3This pad has been marked as a &aDestination &3and bound to your configurator"); 90 | 91 | // Origin 92 | } else if (pdc.has(world, PersistentDataType.STRING) && b.getWorld().getName().equals( 93 | pdc.get(world, PersistentDataType.STRING))) { 94 | int x = pdc.getOrDefault(xCoord, PersistentDataType.INTEGER, 0); 95 | int y = pdc.getOrDefault(yCoord, PersistentDataType.INTEGER, 0); 96 | int z = pdc.getOrDefault(zCoord, PersistentDataType.INTEGER, 0); 97 | 98 | if (Math.abs(x - b.getX()) > MAX_DISTANCE.getValue() 99 | || Math.abs(z - b.getZ()) > MAX_DISTANCE.getValue()) { 100 | 101 | Utils.send(p, "&cYou can not link blocks more than " 102 | + MAX_DISTANCE.getValue() + " blocks apart!"); 103 | 104 | return; 105 | } 106 | 107 | registerOrigin(b, x, y, z); 108 | 109 | Utils.send(p, "&3This pad has been marked as an &aOrigin &3and your configurator's settings " + 110 | "have been pasted onto this pad"); 111 | 112 | } else { 113 | 114 | Utils.send(p, "&cSneak and right click on a Warp Pad to set the destination, then right click" + 115 | " " + "another Warp Pad tp set the origin!"); 116 | } 117 | 118 | } 119 | 120 | } else { 121 | Utils.send(p, "&cConfigure this Warp Pad using a Warp Pad Configurator"); 122 | } 123 | } 124 | } 125 | 126 | private void registerOrigin(Block b, int x, int y, int z) { 127 | BlockStorage.addBlockInfo(b, "type", "origin"); 128 | 129 | BlockStorage.addBlockInfo(b, "x", String.valueOf(x)); 130 | BlockStorage.addBlockInfo(b, "y", String.valueOf(y)); 131 | BlockStorage.addBlockInfo(b, "z", String.valueOf(z)); 132 | 133 | updateHologram(b, "&a&lOrigin"); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/items/EnderChestExtractionNode.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.items; 2 | 3 | import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler; 4 | import io.github.thebusybiscuit.slimefun4.core.handlers.BlockUseHandler; 5 | import io.github.thebusybiscuit.slimefun4.implementation.items.magical.talismans.Talisman; 6 | import io.github.thebusybiscuit.slimefun4.libraries.paperlib.PaperLib; 7 | import io.ncbpfluffybear.fluffymachines.utils.Utils; 8 | import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config; 9 | import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; 10 | import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; 11 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; 12 | import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker; 13 | import me.mrCookieSlime.Slimefun.api.BlockStorage; 14 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; 15 | import org.bukkit.Bukkit; 16 | import org.bukkit.Material; 17 | import org.bukkit.Tag; 18 | import org.bukkit.block.Block; 19 | import org.bukkit.block.BlockFace; 20 | import org.bukkit.block.BlockState; 21 | import org.bukkit.block.Container; 22 | import org.bukkit.block.EnderChest; 23 | import org.bukkit.block.ShulkerBox; 24 | import org.bukkit.entity.Player; 25 | import org.bukkit.event.block.BlockPlaceEvent; 26 | import org.bukkit.inventory.Inventory; 27 | import org.bukkit.inventory.InventoryHolder; 28 | import org.bukkit.inventory.ItemStack; 29 | 30 | import javax.annotation.Nonnull; 31 | import java.util.UUID; 32 | 33 | /** 34 | * This {@link SlimefunItem} transfers items from the facing 35 | * {@link EnderChest} to the {@link Container} behind it 36 | * 37 | * @author NCBPFluffyBear 38 | */ 39 | public class EnderChestExtractionNode extends SlimefunItem { 40 | 41 | private static final Material material = Material.ENDER_CHEST; 42 | 43 | public EnderChestExtractionNode(ItemGroup category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { 44 | super(category, item, recipeType, recipe); 45 | 46 | addItemHandler(onPlace()); 47 | addItemHandler(onInteract()); 48 | } 49 | 50 | @Override 51 | public void preRegister() { 52 | this.addItemHandler(new BlockTicker() { 53 | public void tick(Block b, SlimefunItem sf, Config data) { 54 | EnderChestExtractionNode.this.tick(b); 55 | } 56 | 57 | public boolean isSynchronized() { 58 | return true; 59 | } 60 | }); 61 | } 62 | 63 | private void tick(@Nonnull Block b) { 64 | ItemStack transferItemStack; 65 | BlockFace face; 66 | 67 | if (b.getRelative(BlockFace.NORTH).getType() == material) { 68 | face = BlockFace.SOUTH; 69 | 70 | } else if (b.getRelative(BlockFace.SOUTH).getType() == material) { 71 | face = BlockFace.NORTH; 72 | 73 | 74 | } else if (b.getRelative(BlockFace.EAST).getType() == material) { 75 | face = BlockFace.WEST; 76 | 77 | 78 | } else if (b.getRelative(BlockFace.WEST).getType() == material) { 79 | face = BlockFace.EAST; 80 | 81 | } else { 82 | return; 83 | } 84 | 85 | BlockState state = PaperLib.getBlockState(b.getRelative(face), false).getState(); 86 | 87 | if (state instanceof InventoryHolder) { 88 | Player p = Bukkit.getOfflinePlayer(UUID.fromString(BlockStorage.getLocationInfo(b.getLocation(), "owner"))).getPlayer(); 89 | 90 | // Ender chest null check necessary because Bukkit yes. 91 | if (p != null) { 92 | 93 | boolean enderValid = false; 94 | boolean containerValid = false; 95 | int enderIndex = -1; 96 | int containerIndex = -1; 97 | 98 | Inventory enderInv = p.getEnderChest(); 99 | 100 | for (int i = 0; i < enderInv.getSize(); i++) { 101 | 102 | ItemStack enderItem = enderInv.getItem(i); 103 | 104 | // Ignore null items 105 | if (enderItem == null) { 106 | continue; 107 | } 108 | 109 | // Prevent putting shulkers in shulkers 110 | if (state instanceof ShulkerBox && !Tag.SHULKER_BOXES.isTagged(enderItem.getType())) { 111 | continue; 112 | } 113 | 114 | SlimefunItem sfEnderItem = SlimefunItem.getByItem(enderItem); 115 | 116 | // Ignore Talismen 117 | if (sfEnderItem instanceof Talisman) { 118 | continue; 119 | } 120 | 121 | enderIndex = i; 122 | enderValid = true; 123 | break; 124 | } 125 | 126 | Inventory containerInv = ((InventoryHolder) state).getInventory(); 127 | 128 | for (int i = 0; i < containerInv.getSize(); i++) { 129 | 130 | if (containerInv.getItem(i) == null) { 131 | containerIndex = i; 132 | containerValid = true; 133 | break; 134 | } 135 | } 136 | 137 | if (enderValid && containerValid) { 138 | transferItemStack = enderInv.getItem(enderIndex); 139 | enderInv.setItem(enderIndex, null); 140 | 141 | containerInv.setItem(containerIndex, transferItemStack); 142 | } 143 | } 144 | } 145 | } 146 | 147 | private BlockPlaceHandler onPlace() { 148 | return new BlockPlaceHandler(false) { 149 | @Override 150 | public void onPlayerPlace(@Nonnull BlockPlaceEvent e) { 151 | Player p = e.getPlayer(); 152 | Block b = e.getBlock(); 153 | 154 | if (!e.isCancelled()) { 155 | BlockStorage.addBlockInfo(b, "owner", p.getUniqueId().toString()); 156 | BlockStorage.addBlockInfo(b, "playername", p.getDisplayName()); 157 | Utils.send(p, "&aEnder Chest Extraction Node registered to " + p.getDisplayName() 158 | + " &7(UUID: " + p.getUniqueId() + ")"); 159 | } 160 | } 161 | }; 162 | } 163 | 164 | private BlockUseHandler onInteract() { 165 | return e -> { 166 | Player p = e.getPlayer(); 167 | Block b = e.getClickedBlock().get(); 168 | Utils.send(p, "&eThis Ender Chest Extraction Node belongs to " + 169 | BlockStorage.getLocationInfo(b.getLocation(), "playername") 170 | + " &7(UUID: " + BlockStorage.getLocationInfo(b.getLocation(), "owner") + ")"); 171 | }; 172 | } 173 | } -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/utils/Utils.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.utils; 2 | 3 | import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler; 4 | import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; 5 | import io.github.thebusybiscuit.slimefun4.implementation.handlers.SimpleBlockBreakHandler; 6 | import io.github.thebusybiscuit.slimefun4.libraries.dough.common.ChatColors; 7 | import io.github.thebusybiscuit.slimefun4.libraries.dough.protection.Interaction; 8 | import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils; 9 | import io.ncbpfluffybear.fluffymachines.FluffyMachines; 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | import java.util.TreeMap; 13 | import javax.annotation.Nonnull; 14 | import javax.annotation.Nullable; 15 | import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu; 16 | import me.mrCookieSlime.Slimefun.api.BlockStorage; 17 | import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu; 18 | import org.apache.commons.lang.WordUtils; 19 | import org.bukkit.Bukkit; 20 | import org.bukkit.ChatColor; 21 | import org.bukkit.Material; 22 | import org.bukkit.NamespacedKey; 23 | import org.bukkit.block.Block; 24 | import org.bukkit.command.CommandSender; 25 | import org.bukkit.entity.Player; 26 | import org.bukkit.inventory.ItemStack; 27 | import org.bukkit.inventory.meta.ItemMeta; 28 | import org.bukkit.persistence.PersistentDataType; 29 | import org.bukkit.scheduler.BukkitTask; 30 | 31 | public final class Utils { 32 | 33 | private static final NamespacedKey fluffykey = new NamespacedKey(FluffyMachines.getInstance(), "fluffykey"); 34 | private static final NamespacedKey nonClickable = new NamespacedKey(FluffyMachines.getInstance(), "nonclickable"); 35 | 36 | private final static TreeMap map = new TreeMap<>(); 37 | 38 | static { 39 | 40 | map.put(1000, "M"); 41 | map.put(900, "CM"); 42 | map.put(500, "D"); 43 | map.put(400, "CD"); 44 | map.put(100, "C"); 45 | map.put(90, "XC"); 46 | map.put(50, "L"); 47 | map.put(40, "XL"); 48 | map.put(10, "X"); 49 | map.put(9, "IX"); 50 | map.put(5, "V"); 51 | map.put(4, "IV"); 52 | map.put(1, "I"); 53 | 54 | } 55 | 56 | private Utils() { 57 | } 58 | 59 | public static String color(String str) { 60 | if (str == null) { 61 | return null; 62 | } 63 | 64 | return ChatColor.translateAlternateColorCodes('&', str); 65 | } 66 | 67 | public static void send(CommandSender p, String message) { 68 | p.sendMessage(color("&7[&6FluffyMachines&7] &r" + message)); 69 | } 70 | 71 | public static String multiBlockWarning() { 72 | return "&cThis is a Multiblock machine!"; 73 | } 74 | 75 | // TODO: Deprecate custom model data method of detecting non interactables 76 | public static ItemStack buildNonInteractable(Material material, @Nullable String name, @Nullable String... lore) { 77 | ItemStack nonClickableItem = new ItemStack(material); 78 | ItemMeta NCMeta = nonClickableItem.getItemMeta(); 79 | if (name != null) { 80 | NCMeta.setDisplayName(ChatColors.color(name)); 81 | } else { 82 | NCMeta.setDisplayName(" "); 83 | } 84 | 85 | if (lore.length > 0) { 86 | List lines = new ArrayList<>(); 87 | 88 | for (String line : lore) { 89 | lines.add(ChatColor.translateAlternateColorCodes('&', line)); 90 | } 91 | NCMeta.setLore(lines); 92 | } 93 | 94 | NCMeta.getPersistentDataContainer().set(nonClickable, PersistentDataType.BYTE, (byte) 1); 95 | nonClickableItem.setItemMeta(NCMeta); 96 | return nonClickableItem; 97 | } 98 | 99 | // TODO: Deprecate custom model data method of detecting non interactables 100 | public static boolean checkNonInteractable(ItemStack item) { 101 | if (item == null || item.getItemMeta() == null) { 102 | return false; 103 | } 104 | 105 | return item.getItemMeta().getPersistentDataContainer().getOrDefault(nonClickable, PersistentDataType.BYTE, (byte) 0) == 1; 106 | } 107 | 108 | public static void createBorder(ChestMenu menu, ItemStack backgroundItem, int[] slots) { 109 | for (int slot : slots) { 110 | menu.addItem(slot, backgroundItem, ChestMenuUtils.getEmptyClickHandler()); 111 | } 112 | } 113 | 114 | public static BlockBreakHandler getDefaultBreakHandler(int[] inputs, int[] outputs) { 115 | return new SimpleBlockBreakHandler() { 116 | 117 | @Override 118 | public void onBlockBreak(@Nonnull Block b) { 119 | BlockMenu inv = BlockStorage.getInventory(b); 120 | 121 | if (inv != null) { 122 | inv.dropItems(b.getLocation(), inputs); 123 | inv.dropItems(b.getLocation(), outputs); 124 | } 125 | } 126 | 127 | }; 128 | } 129 | 130 | public static void giveOrDropItem(Player p, ItemStack toGive) { 131 | for (ItemStack leftover : p.getInventory().addItem(toGive).values()) { 132 | p.getWorld().dropItemNaturally(p.getLocation(), leftover); 133 | } 134 | } 135 | 136 | public static String getViewableName(ItemStack item) { 137 | if (item.getItemMeta().hasDisplayName()) { 138 | return item.getItemMeta().getDisplayName(); 139 | } else { 140 | return WordUtils.capitalizeFully(item.getType().name().replace("_", " ")); 141 | } 142 | } 143 | 144 | public static String toRoman(int number) { 145 | int l = map.floorKey(number); 146 | if (number == l) { 147 | return map.get(number); 148 | } 149 | return map.get(l) + toRoman(number - l); 150 | } 151 | 152 | public static ItemStack keyItem(ItemStack item) { 153 | ItemStack clone = item.clone(); 154 | ItemMeta meta = clone.getItemMeta(); 155 | meta.getPersistentDataContainer().set(fluffykey, PersistentDataType.INTEGER, 1); 156 | clone.setItemMeta(meta); 157 | return clone; 158 | } 159 | 160 | public static ItemStack unKeyItem(ItemStack item) { 161 | ItemStack clone = item.clone(); 162 | ItemMeta meta = clone.getItemMeta(); 163 | meta.getPersistentDataContainer().remove(fluffykey); 164 | clone.setItemMeta(meta); 165 | return clone; 166 | } 167 | 168 | public static boolean canOpen(@Nonnull Block b, @Nonnull Player p) { 169 | return (p.hasPermission("slimefun.inventory.bypass") 170 | || Slimefun.getProtectionManager().hasPermission( 171 | p, b.getLocation(), Interaction.INTERACT_BLOCK)); 172 | } 173 | 174 | // Don't use Slimefun's runsync 175 | public static BukkitTask runSync(Runnable r) { 176 | return FluffyMachines.getInstance() != null && FluffyMachines.getInstance().isEnabled() ? 177 | Bukkit.getScheduler().runTask(FluffyMachines.getInstance(), r) : null; 178 | } 179 | 180 | public static BukkitTask runSync(Runnable r, long delay) { 181 | return FluffyMachines.getInstance() != null && FluffyMachines.getInstance().isEnabled() ? 182 | Bukkit.getScheduler().runTaskLater(FluffyMachines.getInstance(), r, delay) : null; 183 | } 184 | } 185 | 186 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/items/tools/UpgradedExplosiveTool.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.items.tools; 2 | 3 | import io.github.thebusybiscuit.slimefun4.api.events.ExplosiveToolBreakBlocksEvent; 4 | import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting; 5 | import io.github.thebusybiscuit.slimefun4.core.handlers.ToolUseHandler; 6 | import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; 7 | import io.github.thebusybiscuit.slimefun4.implementation.items.tools.ExplosiveTool; 8 | import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag; 9 | import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; 10 | import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; 11 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; 12 | import me.mrCookieSlime.Slimefun.api.BlockStorage; 13 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; 14 | import io.github.thebusybiscuit.slimefun4.libraries.dough.protection.Interaction; 15 | import org.bukkit.Bukkit; 16 | import org.bukkit.Effect; 17 | import org.bukkit.Material; 18 | import org.bukkit.Sound; 19 | import org.bukkit.block.Block; 20 | import org.bukkit.block.BlockFace; 21 | import org.bukkit.entity.Player; 22 | import org.bukkit.event.block.BlockExplodeEvent; 23 | import org.bukkit.inventory.ItemStack; 24 | 25 | import javax.annotation.Nonnull; 26 | import java.util.ArrayList; 27 | import java.util.List; 28 | 29 | /** 30 | * This {@link SlimefunItem} is a super class for items like the {@link UpgradedExplosivePickaxe} or {@link 31 | * UpgradedExplosiveShovel}. 32 | * 33 | * @author TheBusyBiscuit, NCBPFluffyBear 34 | * @see UpgradedExplosivePickaxe 35 | * @see UpgradedExplosiveShovel 36 | */ 37 | class UpgradedExplosiveTool extends ExplosiveTool { 38 | 39 | private final ItemSetting damageOnUse; 40 | private final ItemSetting callExplosionEvent; 41 | private final ItemSetting breakFromCenter = new ItemSetting<>(this, "break-from-center", false); 42 | private final ItemSetting triggerOtherPlugins = new ItemSetting<>(this, "trigger-other-plugins", true); 43 | 44 | public UpgradedExplosiveTool(ItemGroup category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { 45 | super(category, item, recipeType, recipe); 46 | 47 | addItemSetting(breakFromCenter, triggerOtherPlugins); 48 | 49 | damageOnUse = getItemSetting("damage-on-use", Boolean.class).get(); 50 | callExplosionEvent = getItemSetting("call-explosion-event", Boolean.class).get(); 51 | } 52 | 53 | @Nonnull 54 | @Override 55 | public ToolUseHandler getItemHandler() { 56 | return (e, tool, fortune, drops) -> { 57 | 58 | if (e instanceof AlternateBreakEvent) { 59 | return; 60 | } 61 | 62 | Player p = e.getPlayer(); 63 | Block b = e.getBlock(); 64 | 65 | b.getWorld().createExplosion(b.getLocation(), 0.0F); 66 | b.getWorld().playSound(b.getLocation(), Sound.ENTITY_GENERIC_EXPLODE, 0.2F, 1F); 67 | 68 | BlockFace face = p.getFacing(); 69 | if (p.getLocation().getPitch() > 67.5) { 70 | face = BlockFace.DOWN; 71 | } else if (p.getLocation().getPitch() < -67.5) { 72 | face = BlockFace.UP; 73 | } 74 | List blocks = findBlocks(b, face); 75 | breakBlocks(p, tool, b, blocks, drops); 76 | }; 77 | } 78 | 79 | private void breakBlocks(Player p, ItemStack item, Block b, List blocks, List drops) { 80 | List blocksToDestroy = new ArrayList<>(); 81 | 82 | if (callExplosionEvent.getValue()) { 83 | BlockExplodeEvent blockExplodeEvent = new BlockExplodeEvent(b, blocks, 0); 84 | Bukkit.getServer().getPluginManager().callEvent(blockExplodeEvent); 85 | 86 | if (!blockExplodeEvent.isCancelled()) { 87 | for (Block block : blockExplodeEvent.blockList()) { 88 | if (canBreak(p, block)) { 89 | blocksToDestroy.add(block); 90 | } 91 | } 92 | } 93 | } else { 94 | for (Block block : blocks) { 95 | if (canBreak(p, block)) { 96 | blocksToDestroy.add(block); 97 | } 98 | } 99 | } 100 | 101 | ExplosiveToolBreakBlocksEvent event = new ExplosiveToolBreakBlocksEvent(p, b, blocksToDestroy, item, this); 102 | Bukkit.getServer().getPluginManager().callEvent(event); 103 | 104 | if (!event.isCancelled()) { 105 | for (Block block : blocksToDestroy) { 106 | breakBlock(p, item, block, drops); 107 | } 108 | } 109 | } 110 | 111 | private List findBlocks(Block b, BlockFace face) { 112 | List blocks = new ArrayList<>(26); 113 | Block center = b; 114 | 115 | // Shift center block 116 | if (!breakFromCenter.getValue()) { 117 | center = b.getRelative(face, 2); 118 | } 119 | for (int x = -2; x <= 2; x++) { 120 | for (int y = -2; y <= 2; y++) { 121 | for (int z = -2; z <= 2; z++) { 122 | 123 | Block relative = center.getRelative(x, y, z); 124 | 125 | // Skip the hit block 126 | if (relative.getLocation().equals(b.getLocation())) { 127 | continue; 128 | } 129 | 130 | // Small check to reduce lag 131 | if (relative.getType() != Material.AIR) { 132 | blocks.add(relative); 133 | } 134 | } 135 | } 136 | } 137 | return blocks; 138 | } 139 | 140 | @Override 141 | public boolean isDamageable() { 142 | return damageOnUse.getValue(); 143 | } 144 | 145 | protected boolean canBreak(@Nonnull Player p, @Nonnull Block b) { 146 | if (b.isEmpty() || b.isLiquid()) { 147 | return false; 148 | } else if (SlimefunTag.UNBREAKABLE_MATERIALS.isTagged(b.getType())) { 149 | return false; 150 | } else if (!b.getWorld().getWorldBorder().isInside(b.getLocation())) { 151 | return false; 152 | } else if (Slimefun.getIntegrations().isCustomBlock(b)) { 153 | return false; 154 | } else { 155 | return Slimefun.getProtectionManager().hasPermission(p, b.getLocation(), Interaction.BREAK_BLOCK); 156 | } 157 | } 158 | 159 | private void breakBlock(Player p, ItemStack item, Block b, List drops) { 160 | Slimefun.getProtectionManager().logAction(p, b, Interaction.BREAK_BLOCK); 161 | Material material = b.getType(); 162 | 163 | b.getWorld().playEffect(b.getLocation(), Effect.STEP_SOUND, material); 164 | SlimefunItem sfItem = BlockStorage.check(b); 165 | 166 | // Don't break SF blocks 167 | if (sfItem != null) { 168 | return; 169 | } 170 | 171 | if (triggerOtherPlugins.getValue()) { 172 | AlternateBreakEvent breakEvent = new AlternateBreakEvent(b, p); 173 | Bukkit.getServer().getPluginManager().callEvent(breakEvent); 174 | } 175 | 176 | b.breakNaturally(item); 177 | 178 | damageItem(p, item); 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/machines/BackpackUnloader.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.machines; 2 | 3 | import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile; 4 | import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent; 5 | import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler; 6 | import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNetComponentType; 7 | import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; 8 | import io.github.thebusybiscuit.slimefun4.implementation.items.backpacks.SlimefunBackpack; 9 | import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config; 10 | import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; 11 | import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; 12 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; 13 | import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker; 14 | import me.mrCookieSlime.Slimefun.api.BlockStorage; 15 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; 16 | import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu; 17 | import me.mrCookieSlime.Slimefun.api.inventory.BlockMenuPreset; 18 | import me.mrCookieSlime.Slimefun.api.inventory.DirtyChestMenu; 19 | import me.mrCookieSlime.Slimefun.api.item_transport.ItemTransportFlow; 20 | import io.github.thebusybiscuit.slimefun4.libraries.dough.protection.Interaction; 21 | import org.bukkit.ChatColor; 22 | import org.bukkit.block.Block; 23 | import org.bukkit.entity.Player; 24 | import org.bukkit.event.block.BlockBreakEvent; 25 | import org.bukkit.inventory.Inventory; 26 | import org.bukkit.inventory.ItemStack; 27 | 28 | import javax.annotation.Nonnull; 29 | import java.util.List; 30 | 31 | public class BackpackUnloader extends SlimefunItem implements EnergyNetComponent { 32 | 33 | public static final int ENERGY_CONSUMPTION = 16; 34 | public static final int CAPACITY = ENERGY_CONSUMPTION * 3; 35 | 36 | private static final int[] PLAIN_BORDER = {2, 3, 4, 5, 6, 7, 8, 11, 12, 13, 14, 15, 16, 17}; 37 | private static final int[] INPUT_BORDER = {1, 9, 10}; 38 | private static final int[] OUTPUT_BORDER = {18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 35, 36, 44, 45, 46, 47, 48, 39 | 49, 50, 51, 52, 53}; 40 | private static final int[] INPUT_SLOTS = {0}; 41 | private static final int[] OUTPUT_SLOTS = {28, 29, 30, 31, 32, 33, 34, 37, 38, 39, 40, 41, 42, 43}; 42 | 43 | public BackpackUnloader(ItemGroup category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { 44 | super(category, item, recipeType, recipe 45 | ); 46 | 47 | addItemHandler(onBreak()); 48 | 49 | new BlockMenuPreset(getId(), "&eBackpack Unloader") { 50 | 51 | @Override 52 | public void init() { 53 | BackpackLoader.buildBorder(this, PLAIN_BORDER, INPUT_BORDER, OUTPUT_BORDER); 54 | } 55 | 56 | @Override 57 | public boolean canOpen(@Nonnull Block b, @Nonnull Player p) { 58 | return p.hasPermission("slimefun.inventory.bypass") 59 | || Slimefun.getProtectionManager().hasPermission(p, b.getLocation(), 60 | Interaction.INTERACT_BLOCK); 61 | } 62 | 63 | @Override 64 | public int[] getSlotsAccessedByItemTransport(ItemTransportFlow flow) { 65 | return new int[0]; 66 | } 67 | 68 | @Override 69 | public int[] getSlotsAccessedByItemTransport(DirtyChestMenu menu, ItemTransportFlow flow, ItemStack item) { 70 | if (flow == ItemTransportFlow.WITHDRAW) { 71 | return getOutputSlots(); 72 | } else { 73 | return getInputSlots(); 74 | } 75 | } 76 | }; 77 | 78 | } 79 | 80 | private BlockBreakHandler onBreak() { 81 | return new BlockBreakHandler(false, false) { 82 | @Override 83 | public void onPlayerBreak(@Nonnull BlockBreakEvent e, @Nonnull ItemStack item, @Nonnull List drops) { 84 | Block b = e.getBlock(); 85 | BlockMenu inv = BlockStorage.getInventory(b); 86 | 87 | if (inv != null) { 88 | inv.dropItems(b.getLocation(), getInputSlots()); 89 | inv.dropItems(b.getLocation(), getOutputSlots()); 90 | } 91 | } 92 | }; 93 | } 94 | 95 | @Override 96 | public void preRegister() { 97 | this.addItemHandler(new BlockTicker() { 98 | public void tick(Block b, SlimefunItem sf, Config data) { 99 | BackpackUnloader.this.tick(b); 100 | } 101 | 102 | public boolean isSynchronized() { 103 | return false; 104 | } 105 | }); 106 | } 107 | 108 | private void tick(@Nonnull Block b) { 109 | 110 | if (getCharge(b.getLocation()) < ENERGY_CONSUMPTION) { 111 | return; 112 | } 113 | 114 | final BlockMenu inv = BlockStorage.getInventory(b); 115 | 116 | for (int outputSlot : getOutputSlots()) { 117 | if (inv.getItemInSlot(outputSlot) == null) { 118 | break; 119 | } else if (outputSlot == getOutputSlots()[13]) { 120 | return; 121 | } 122 | } 123 | 124 | ItemStack inputItem = inv.getItemInSlot(getInputSlots()[0]); 125 | if (inputItem != null) { 126 | SlimefunItem sfItem = SlimefunItem.getByItem(inputItem); 127 | if (sfItem instanceof SlimefunBackpack) { 128 | 129 | // No ID 130 | List lore = inputItem.getItemMeta().getLore(); 131 | for (String s : lore) { 132 | if (s.equals(ChatColor.GRAY + "ID: ")) { 133 | rejectInput(inv); 134 | return; 135 | } 136 | } 137 | 138 | PlayerProfile.getBackpack(inputItem, backpack -> { 139 | Inventory bpinv = backpack.getInventory(); 140 | for (int slot = 0; slot < bpinv.getSize(); slot++) { 141 | if (bpinv.getItem(slot) != null) { 142 | ItemStack transferItem = bpinv.getItem(slot); 143 | bpinv.setItem(slot, null); 144 | inv.pushItem(transferItem, getOutputSlots()); 145 | removeCharge(b.getLocation(), ENERGY_CONSUMPTION); 146 | return; 147 | } 148 | // Backpack is empty, move it to the output 149 | if (slot == bpinv.getSize() - 1) { 150 | rejectInput(inv); 151 | return; 152 | } 153 | } 154 | }); 155 | } else { 156 | // Not a backpack 157 | rejectInput(inv); 158 | } 159 | } 160 | } 161 | 162 | private void rejectInput(BlockMenu inv) { 163 | ItemStack transferItem = inv.getItemInSlot(getInputSlots()[0]); 164 | inv.replaceExistingItem(getInputSlots()[0], null); 165 | inv.pushItem(transferItem, getOutputSlots()); 166 | } 167 | 168 | @Nonnull 169 | @Override 170 | public EnergyNetComponentType getEnergyComponentType() { 171 | return EnergyNetComponentType.CONSUMER; 172 | } 173 | 174 | @Override 175 | public int getCapacity() { 176 | return CAPACITY; 177 | } 178 | 179 | public int[] getInputSlots() { 180 | return INPUT_SLOTS; 181 | } 182 | 183 | public int[] getOutputSlots() { 184 | return OUTPUT_SLOTS; 185 | } 186 | } 187 | 188 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/FluffyMachines.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines; 2 | 3 | import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon; 4 | import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile; 5 | import io.github.thebusybiscuit.slimefun4.libraries.dough.collections.Pair; 6 | import io.github.thebusybiscuit.slimefun4.libraries.dough.config.Config; 7 | import io.github.thebusybiscuit.slimefun4.libraries.dough.updater.BlobBuildUpdater; 8 | import io.github.thebusybiscuit.slimefun4.libraries.dough.updater.GitHubBuildsUpdater; 9 | import io.ncbpfluffybear.fluffymachines.listeners.KeyedCrafterListener; 10 | import io.ncbpfluffybear.fluffymachines.utils.Constants; 11 | import io.ncbpfluffybear.fluffymachines.utils.Events; 12 | import io.ncbpfluffybear.fluffymachines.utils.McMMOEvents; 13 | import io.ncbpfluffybear.fluffymachines.utils.Utils; 14 | import java.lang.reflect.Field; 15 | import java.util.ArrayList; 16 | import java.util.Collections; 17 | import java.util.HashMap; 18 | import java.util.Iterator; 19 | import java.util.List; 20 | import java.util.Map; 21 | import java.util.logging.Level; 22 | import javax.annotation.Nonnull; 23 | import lombok.SneakyThrows; 24 | import me.mrCookieSlime.Slimefun.api.BlockStorage; 25 | import org.bstats.bukkit.Metrics; 26 | import org.bukkit.Bukkit; 27 | import org.bukkit.ChatColor; 28 | import org.bukkit.Registry; 29 | import org.bukkit.command.Command; 30 | import org.bukkit.command.CommandSender; 31 | import org.bukkit.enchantments.Enchantment; 32 | import org.bukkit.enchantments.EnchantmentWrapper; 33 | import org.bukkit.entity.Player; 34 | import org.bukkit.inventory.ItemStack; 35 | import org.bukkit.inventory.Recipe; 36 | import org.bukkit.inventory.RecipeChoice; 37 | import org.bukkit.inventory.ShapedRecipe; 38 | import org.bukkit.inventory.ShapelessRecipe; 39 | import org.bukkit.plugin.java.JavaPlugin; 40 | import org.bukkit.util.RayTraceResult; 41 | 42 | public class FluffyMachines extends JavaPlugin implements SlimefunAddon { 43 | 44 | private static FluffyMachines instance; 45 | public static final HashMap>>> shapedVanillaRecipes = new HashMap<>(); 46 | public static final HashMap>>> shapelessVanillaRecipes = 47 | new HashMap<>(); 48 | 49 | @SneakyThrows 50 | @Override 51 | public void onEnable() { 52 | instance = this; 53 | // Read something from your config.yml 54 | Config cfg = new Config(this); 55 | 56 | if (cfg.getBoolean("options.auto-update") && getDescription().getVersion().startsWith("Dev - ")) { 57 | new BlobBuildUpdater(this, getFile(), "FluffyMachines", "Dev").start(); 58 | } 59 | 60 | // Register ACT Recipes 61 | Iterator recipeIterator = Bukkit.recipeIterator(); 62 | while (recipeIterator.hasNext()) { 63 | Recipe r = recipeIterator.next(); 64 | 65 | if (r instanceof ShapedRecipe) { 66 | ShapedRecipe sr = (ShapedRecipe) r; 67 | List rc = new ArrayList<>(); 68 | ItemStack key = new ItemStack(sr.getResult().getType(), 1); 69 | 70 | // Convert the recipe to a list 71 | for (Map.Entry choice : sr.getChoiceMap().entrySet()) { 72 | if (choice.getValue() != null) { 73 | rc.add(choice.getValue()); 74 | } 75 | } 76 | 77 | if (!shapedVanillaRecipes.containsKey(key)) { 78 | shapedVanillaRecipes.put(key, 79 | new ArrayList<>(Collections.singletonList(new Pair<>(sr.getResult(), rc)))); 80 | } else { 81 | shapedVanillaRecipes.get(key).add(new Pair<>(sr.getResult(), rc)); 82 | } 83 | 84 | } else if (r instanceof ShapelessRecipe) { 85 | ShapelessRecipe slr = (ShapelessRecipe) r; 86 | ItemStack key = new ItemStack(slr.getResult().getType(), 1); 87 | 88 | // Key has a list of recipe options 89 | if (!shapelessVanillaRecipes.containsKey(key)) { 90 | shapelessVanillaRecipes.put(key, 91 | new ArrayList<>(Collections.singletonList(new Pair<>(slr.getResult(), slr.getChoiceList())))); 92 | } else { 93 | shapelessVanillaRecipes.get(key).add(new Pair<>(slr.getResult(), slr.getChoiceList())); 94 | } 95 | } 96 | } 97 | 98 | // Register McMMO Events 99 | if (getServer().getPluginManager().isPluginEnabled("McMMO")) { 100 | Bukkit.getLogger().log(Level.INFO, "McMMO found!"); 101 | getServer().getPluginManager().registerEvents(new McMMOEvents(), this); 102 | } 103 | 104 | // Registering Items 105 | FluffyItemSetup.setup(this); 106 | FluffyItemSetup.setupBarrels(this); 107 | 108 | // Register Events Class 109 | getServer().getPluginManager().registerEvents(new Events(), this); 110 | getServer().getPluginManager().registerEvents(new KeyedCrafterListener(), this); 111 | 112 | final Metrics metrics = new Metrics(this, 8927); 113 | } 114 | 115 | @Override 116 | public void onDisable() { 117 | // Logic for disabling the plugin... 118 | } 119 | 120 | @Override 121 | public boolean onCommand(@Nonnull CommandSender sender, @Nonnull Command cmd, @Nonnull String label, String[] args) { 122 | 123 | if (args.length == 0) { 124 | Utils.send(sender, "&cInvalid command"); 125 | return true; 126 | } 127 | 128 | if (!(sender instanceof Player)) { 129 | Utils.send(sender, "&cThere are no console commands available"); 130 | return true; 131 | } 132 | 133 | Player p = (Player) sender; 134 | 135 | switch (args[0].toUpperCase()) { 136 | case "META": 137 | Utils.send(p, String.valueOf(p.getInventory().getItemInMainHand().getItemMeta())); 138 | return true; 139 | case "RAWMETA": 140 | p.sendMessage(String.valueOf(p.getInventory().getItemInMainHand().getItemMeta()).replace("§", "&")); 141 | return true; 142 | case "VERSION": 143 | case "V": 144 | Utils.send(p, "&eThe current version is " + this.getPluginVersion()); 145 | return true; 146 | } 147 | 148 | if (p.hasPermission("fluffymachines.admin")) { 149 | switch (args[0].toUpperCase()) { 150 | case "ADDINFO": 151 | 152 | if (args.length != 3) { 153 | Utils.send(p, "&cPlease specify the key and the data"); 154 | 155 | } else { 156 | RayTraceResult rayResult = p.rayTraceBlocks(5d); 157 | if (rayResult != null && rayResult.getHitBlock() != null 158 | && BlockStorage.hasBlockInfo(rayResult.getHitBlock())) { 159 | 160 | BlockStorage.addBlockInfo(rayResult.getHitBlock(), args[1], args[2]); 161 | Utils.send(p, "&aInfo has been added."); 162 | 163 | } else { 164 | Utils.send(p, "&cYou must be looking at a Slimefun block"); 165 | } 166 | } 167 | return true; 168 | case "SAVEPLAYERS": 169 | saveAllPlayers(); 170 | return true; 171 | } 172 | } 173 | 174 | Utils.send(p, "&cCommand not found"); 175 | 176 | return false; 177 | } 178 | 179 | private void saveAllPlayers() { 180 | Iterator iterator = PlayerProfile.iterator(); 181 | int players = 0; 182 | 183 | while (iterator.hasNext()) { 184 | PlayerProfile profile = iterator.next(); 185 | 186 | profile.save(); 187 | players++; 188 | } 189 | 190 | if (players > 0) { 191 | Bukkit.getLogger().log(Level.INFO, "Auto-saved all player data for {0} player(s)!", players); 192 | } 193 | } 194 | 195 | @Override 196 | public String getBugTrackerURL() { 197 | return "https://github.com/NCBPFluffyBear/FluffyMachines/issues"; 198 | } 199 | 200 | @Nonnull 201 | @Override 202 | public JavaPlugin getJavaPlugin() { 203 | return this; 204 | } 205 | 206 | public static FluffyMachines getInstance() { 207 | return instance; 208 | } 209 | 210 | } 211 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/machines/AlternateElevatorPlate.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.machines; 2 | 3 | import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler; 4 | import io.github.thebusybiscuit.slimefun4.core.handlers.BlockUseHandler; 5 | import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; 6 | import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem; 7 | import io.github.thebusybiscuit.slimefun4.libraries.dough.common.ChatColors; 8 | import io.github.thebusybiscuit.slimefun4.libraries.paperlib.PaperLib; 9 | import io.github.thebusybiscuit.slimefun4.utils.ChatUtils; 10 | import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils; 11 | import io.ncbpfluffybear.fluffymachines.utils.Utils; 12 | import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu; 13 | import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; 14 | import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; 15 | import me.mrCookieSlime.Slimefun.api.BlockStorage; 16 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; 17 | import io.github.thebusybiscuit.slimefun4.libraries.dough.items.CustomItemStack; 18 | import org.bukkit.ChatColor; 19 | import org.bukkit.Location; 20 | import org.bukkit.Material; 21 | import org.bukkit.block.Block; 22 | import org.bukkit.entity.Player; 23 | import org.bukkit.event.block.BlockPlaceEvent; 24 | import org.bukkit.inventory.ItemStack; 25 | 26 | import javax.annotation.Nonnull; 27 | import javax.annotation.ParametersAreNonnullByDefault; 28 | import java.util.HashSet; 29 | import java.util.LinkedList; 30 | import java.util.List; 31 | import java.util.Set; 32 | import java.util.UUID; 33 | 34 | /** 35 | * Alternative elevators that use a Chest GUI instead of 36 | * a Book GUI. Avoids issues with chat plugins. 37 | * Based off of the ElevatorPlate 38 | * 39 | * @author NCBPFluffyBear 40 | * @author TheBusyBiscuit 41 | */ 42 | public class AlternateElevatorPlate extends SimpleSlimefunItem { 43 | 44 | private static final String DATA_KEY = "floor"; 45 | private final Set users = new HashSet<>(); 46 | private static final int MAX_CHEST_INDEX = 53; 47 | 48 | public AlternateElevatorPlate(ItemGroup category, SlimefunItemStack item, RecipeType recipeType, 49 | ItemStack[] recipe, ItemStack recipeOutput) { 50 | super(category, item, recipeType, recipe, recipeOutput); 51 | 52 | addItemHandler(onPlace()); 53 | } 54 | 55 | private BlockPlaceHandler onPlace() { 56 | return new BlockPlaceHandler(false) { 57 | 58 | @Override 59 | public void onPlayerPlace(@Nonnull BlockPlaceEvent e) { 60 | Block b = e.getBlock(); 61 | BlockStorage.addBlockInfo(b, DATA_KEY, "&fFloor #0"); 62 | BlockStorage.addBlockInfo(b, "owner", e.getPlayer().getUniqueId().toString()); 63 | } 64 | }; 65 | } 66 | 67 | @Nonnull 68 | public Set getUsers() { 69 | return users; 70 | } 71 | 72 | @Nonnull 73 | @Override 74 | public BlockUseHandler getItemHandler() { 75 | return e -> { 76 | Block b = e.getClickedBlock().get(); 77 | 78 | if (BlockStorage.getLocationInfo(b.getLocation(), "owner").equals(e.getPlayer().getUniqueId().toString())) { 79 | openEditor(e.getPlayer(), b); 80 | } 81 | }; 82 | } 83 | 84 | @Nonnull 85 | public List getFloors(@Nonnull Block b) { 86 | List floors = new LinkedList<>(); 87 | 88 | for (int y = b.getWorld().getMaxHeight(); y > -64; y--) { 89 | if (y == b.getY()) { 90 | floors.add(b); 91 | continue; 92 | } 93 | 94 | Block block = b.getWorld().getBlockAt(b.getX(), y, b.getZ()); 95 | 96 | if (block.getType() == getItem().getType() && BlockStorage.check(block, getId())) { 97 | floors.add(block); 98 | } 99 | } 100 | 101 | return floors; 102 | } 103 | 104 | @ParametersAreNonnullByDefault 105 | public void openInterface(Player p, Block b) { 106 | if (users.remove(p.getUniqueId())) { 107 | return; 108 | } 109 | 110 | List floors = getFloors(b); 111 | 112 | if (floors.size() < 2) { 113 | Slimefun.getLocalization().sendMessage(p, "machines.ELEVATOR.no-destinations", true); 114 | } else { 115 | openFloorSelector(b, floors, p); 116 | } 117 | } 118 | 119 | @ParametersAreNonnullByDefault 120 | private void openFloorSelector(Block b, List floors, Player p) { 121 | ChestMenu elevatorMenu = new ChestMenu("Elevator"); 122 | for (int i = 0; i < floors.size(); i++) { 123 | 124 | if (i > MAX_CHEST_INDEX) { 125 | break; 126 | } 127 | 128 | Block destination = floors.get(i); 129 | String floor = ChatColors.color(BlockStorage.getLocationInfo(destination.getLocation(), DATA_KEY)); 130 | 131 | addFloor(elevatorMenu, i, p, floor, b, destination); 132 | } 133 | 134 | if (floors.size() < MAX_CHEST_INDEX) { 135 | for (int i = floors.size(); i <= MAX_CHEST_INDEX; i++) { 136 | elevatorMenu.addItem(i, new CustomItemStack(Material.LIGHT_GRAY_STAINED_GLASS_PANE, "")); 137 | elevatorMenu.addMenuClickHandler(i, ChestMenuUtils.getEmptyClickHandler()); 138 | } 139 | } 140 | 141 | elevatorMenu.open(p); 142 | } 143 | 144 | @ParametersAreNonnullByDefault 145 | private void teleport(Player player, String floorName, Block target) { 146 | Utils.runSync(() -> { 147 | users.add(player.getUniqueId()); 148 | 149 | float yaw = player.getEyeLocation().getYaw() + 180; 150 | 151 | if (yaw > 180) { 152 | yaw = -180 + (yaw - 180); 153 | } 154 | 155 | Location destination = new Location(player.getWorld(), target.getX() + 0.5, target.getY() + 0.4, 156 | target.getZ() + 0.5, yaw, player.getEyeLocation().getPitch()); 157 | 158 | PaperLib.teleportAsync(player, destination).thenAccept(teleported -> { 159 | if (teleported) { 160 | player.sendTitle(ChatColor.WHITE + ChatColors.color(floorName), null, 20, 60, 20); 161 | } 162 | }); 163 | }); 164 | } 165 | 166 | @ParametersAreNonnullByDefault 167 | public void openEditor(Player p, Block b) { 168 | ChestMenu menu = new ChestMenu("Elevator Settings"); 169 | 170 | menu.addItem(4, new CustomItemStack(Material.NAME_TAG, "&7Floor Name &e(Click to edit)", "", 171 | "&f" + ChatColors.color(BlockStorage.getLocationInfo(b.getLocation(), DATA_KEY)))); 172 | menu.addMenuClickHandler(4, (pl, slot, item, action) -> { 173 | pl.closeInventory(); 174 | pl.sendMessage(""); 175 | Slimefun.getLocalization().sendMessage(p, "machines.ELEVATOR.enter-name"); 176 | pl.sendMessage(""); 177 | 178 | ChatUtils.awaitInput(pl, message -> { 179 | BlockStorage.addBlockInfo(b, DATA_KEY, message.replace(ChatColor.COLOR_CHAR, '&')); 180 | 181 | pl.sendMessage(""); 182 | Slimefun.getLocalization().sendMessage(p, "machines.ELEVATOR.named", msg -> msg.replace("%floor" + 183 | "%", message)); 184 | pl.sendMessage(""); 185 | 186 | openEditor(pl, b); 187 | }); 188 | 189 | return false; 190 | }); 191 | 192 | menu.open(p); 193 | } 194 | 195 | private void addFloor(ChestMenu menu, int slot, Player p, String floor, Block b, Block destination) { 196 | if (destination.getY() == b.getY()) { 197 | menu.addItem(slot, new CustomItemStack(Material.LIME_STAINED_GLASS_PANE, 198 | ChatColors.color(Slimefun.getLocalization().getMessage(p, "machines.ELEVATOR.current-floor")), 199 | "", ChatColor.WHITE + floor, "")); 200 | menu.addMenuClickHandler(slot, ChestMenuUtils.getEmptyClickHandler()); 201 | 202 | } else { 203 | menu.addItem(slot, new CustomItemStack(Material.GRAY_STAINED_GLASS_PANE, 204 | ChatColors.color(Slimefun.getLocalization().getMessage(p, 205 | "machines.ELEVATOR.click-to-teleport")), "", ChatColor.WHITE + floor, "")); 206 | menu.addMenuClickHandler(slot, (player, clickSlot, item, action) -> { 207 | teleport(p, floor, destination); 208 | return false; 209 | }); 210 | } 211 | } 212 | 213 | } 214 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/items/tools/PortableCharger.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.items.tools; 2 | 3 | 4 | import io.github.thebusybiscuit.slimefun4.core.attributes.Rechargeable; 5 | import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler; 6 | import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem; 7 | import io.github.thebusybiscuit.slimefun4.libraries.dough.common.ChatColors; 8 | import io.ncbpfluffybear.fluffymachines.FluffyMachines; 9 | import io.ncbpfluffybear.fluffymachines.utils.Utils; 10 | import lombok.AccessLevel; 11 | import lombok.AllArgsConstructor; 12 | import lombok.Getter; 13 | import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; 14 | import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; 15 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; 16 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; 17 | import org.bukkit.Bukkit; 18 | import org.bukkit.ChatColor; 19 | import org.bukkit.GameMode; 20 | import org.bukkit.Material; 21 | import org.bukkit.entity.Player; 22 | import org.bukkit.event.EventHandler; 23 | import org.bukkit.event.Listener; 24 | import org.bukkit.event.inventory.InventoryClickEvent; 25 | import org.bukkit.inventory.Inventory; 26 | import org.bukkit.inventory.ItemStack; 27 | import org.bukkit.inventory.meta.ItemMeta; 28 | import org.bukkit.plugin.Plugin; 29 | import org.bukkit.scheduler.BukkitRunnable; 30 | 31 | import javax.annotation.Nonnull; 32 | import java.util.ArrayList; 33 | import java.util.List; 34 | 35 | /** 36 | * The {@link PortableCharger} is an item that opens 37 | * a portable charging GUI that charges any 38 | * {@link Rechargeable} item. 39 | * 40 | * @author NCBPFluffyBear 41 | */ 42 | public class PortableCharger extends SimpleSlimefunItem implements Listener, Rechargeable { 43 | 44 | private final int[] BORDER = {5, 6, 7, 14, 16, 23, 24, 25}; 45 | private final int POWER_SLOT = 11; 46 | private final int CHARGE_SLOT = 15; 47 | private final int INV_SIZE = 27; 48 | private final float CHARGE_CAPACITY; 49 | private final float CHARGE_SPEED; 50 | private final Plugin plugin = FluffyMachines.getInstance(); 51 | 52 | public PortableCharger(ItemGroup category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, 53 | int chargeCapacity, int chargeSpeed) { 54 | super(category, item, recipeType, recipe); 55 | 56 | this.CHARGE_CAPACITY = chargeCapacity; 57 | this.CHARGE_SPEED = chargeSpeed; 58 | 59 | Bukkit.getPluginManager().registerEvents(this, FluffyMachines.getInstance()); 60 | } 61 | 62 | @Nonnull 63 | @Override 64 | public ItemUseHandler getItemHandler() { 65 | return e -> { 66 | e.cancel(); 67 | 68 | // Get variables 69 | final Player p = e.getPlayer(); 70 | final ItemStack chargerItem = e.getItem(); 71 | final Rechargeable charger = (Rechargeable) SlimefunItem.getByItem(chargerItem); 72 | 73 | // Create GUI Items 74 | Inventory inventory = Bukkit.createInventory(null, INV_SIZE, ChatColor.GOLD + "Portable Charger"); 75 | 76 | ItemStack backgroundItem = Utils.buildNonInteractable(Material.GRAY_STAINED_GLASS_PANE, null); 77 | ItemStack borderItem = Utils.buildNonInteractable(Material.YELLOW_STAINED_GLASS_PANE, null); 78 | ItemStack powerItem = Utils.buildNonInteractable(Material.GLOWSTONE, "&4Power"); 79 | 80 | // Build and open GUI 81 | for (int i = 0; i < INV_SIZE; i++) 82 | inventory.setItem(i, backgroundItem); 83 | 84 | for (int slot : BORDER) 85 | inventory.setItem(slot, borderItem); 86 | 87 | inventory.setItem(POWER_SLOT, powerItem); 88 | updateSlot(inventory, POWER_SLOT, "&6&lPower Remaining", 89 | "&e" + charger.getItemCharge(chargerItem) + "J"); 90 | inventory.clear(CHARGE_SLOT); 91 | p.openInventory(inventory); 92 | 93 | // Task that triggers every second 94 | new BukkitRunnable() { 95 | public void run() { 96 | 97 | ItemStack deviceItem = inventory.getItem(CHARGE_SLOT); 98 | SlimefunItem sfItem = SlimefunItem.getByItem(deviceItem); 99 | 100 | if (sfItem instanceof PortableCharger) { 101 | p.closeInventory(); 102 | Utils.send(p, "&cYou can not charge a portable charger"); 103 | } 104 | 105 | if (sfItem instanceof Rechargeable) { 106 | 107 | Rechargeable device = (Rechargeable) sfItem; 108 | float neededCharge = device.getMaxItemCharge(deviceItem) 109 | - device.getItemCharge(deviceItem); 110 | float availableCharge = charger.getItemCharge(chargerItem); 111 | 112 | // Three different scenarios 113 | if (p.getGameMode() == GameMode.CREATIVE && neededCharge > 0) { 114 | device.setItemCharge(deviceItem, device.getMaxItemCharge(deviceItem)); 115 | 116 | } else if (neededCharge > 0 && availableCharge > 0) { 117 | 118 | if (neededCharge >= CHARGE_SPEED && availableCharge >= CHARGE_SPEED) { 119 | transferCharge(charger, chargerItem, device, deviceItem, CHARGE_SPEED); 120 | 121 | } else { 122 | transferCharge(charger, chargerItem, device, deviceItem, Math.min(neededCharge, 123 | availableCharge)); 124 | } 125 | 126 | } else if (neededCharge == 0) { 127 | Utils.send(p, "&cThis item is already full!"); 128 | 129 | } else { 130 | Utils.send(p, "&cYour charger does not have enough power!"); 131 | } 132 | 133 | // The name of the powerItem NEEDS to be "Portable Charger" to cancel event 134 | updateSlot(inventory, POWER_SLOT, "&6&lPower Remaining", 135 | "&e" + charger.getItemCharge(chargerItem) + "J"); 136 | } 137 | 138 | // Check if GUI is no longer open 139 | if (!inventory.getViewers().contains(p)) { 140 | cancel(); 141 | 142 | ItemStack forgottenItem = inventory.getItem(CHARGE_SLOT); 143 | 144 | // Check if player left an item inside 145 | if (forgottenItem != null) { 146 | Utils.send(p, "&cHey! You left something in the charger! Dropping it now..."); 147 | Utils.giveOrDropItem(p, forgottenItem); 148 | } 149 | } 150 | } 151 | }.runTaskTimer(plugin, 0, 20); 152 | }; 153 | } 154 | 155 | @EventHandler 156 | public void onChargerItemClick(InventoryClickEvent e) { 157 | SlimefunItem sfItem1 = SlimefunItem.getByItem(e.getCurrentItem()); 158 | SlimefunItem sfItem2 = SlimefunItem.getByItem(e.getCursor()); 159 | if ((sfItem1 instanceof PortableCharger || sfItem2 instanceof PortableCharger) 160 | && e.getWhoClicked().getOpenInventory().getTitle().contains("Portable Charger")) { 161 | e.setCancelled(true); 162 | } 163 | } 164 | 165 | public void updateSlot(Inventory inventory, int slot, String name, String... lore) { 166 | ItemStack item = inventory.getItem(slot); 167 | ItemMeta slotMeta = item.getItemMeta(); 168 | if (name != null) { 169 | slotMeta.setDisplayName(ChatColors.color(name)); 170 | } else { 171 | slotMeta.setDisplayName(" "); 172 | } 173 | 174 | if (lore.length > 0) { 175 | List lines = new ArrayList<>(); 176 | 177 | for (String line : lore) { 178 | lines.add(ChatColor.translateAlternateColorCodes('&', line)); 179 | } 180 | slotMeta.setLore(lines); 181 | } 182 | item.setItemMeta(slotMeta); 183 | inventory.setItem(slot, item); 184 | } 185 | 186 | public void transferCharge(Rechargeable charger, ItemStack chargerItem, Rechargeable device, ItemStack deviceItem 187 | , float charge) { 188 | charger.removeItemCharge(chargerItem, charge); 189 | device.addItemCharge(deviceItem, charge); 190 | } 191 | 192 | @Override 193 | public float getMaxItemCharge(ItemStack itemStack) { 194 | return CHARGE_CAPACITY; 195 | } 196 | 197 | @Override 198 | public boolean isDisenchantable() { 199 | return false; 200 | } 201 | 202 | @Getter 203 | @AllArgsConstructor(access = AccessLevel.PRIVATE) 204 | public enum Type { 205 | 206 | SMALL(128, 8), 207 | MEDIUM(512, 32), 208 | BIG(1024, 64), 209 | LARGE(8192, 512), 210 | CARBONADO(65526, 4096); 211 | 212 | public final int chargeCapacity; 213 | public final int chargeSpeed; 214 | 215 | } 216 | } -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/utils/Events.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.utils; 2 | 3 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; 4 | import io.ncbpfluffybear.fluffymachines.items.Barrel; 5 | import io.ncbpfluffybear.fluffymachines.items.FireproofRune; 6 | import io.ncbpfluffybear.fluffymachines.items.HelicopterHat; 7 | import io.ncbpfluffybear.fluffymachines.items.tools.WateringCan; 8 | import io.ncbpfluffybear.fluffymachines.machines.AlternateElevatorPlate; 9 | import javax.annotation.Nonnull; 10 | import me.mrCookieSlime.Slimefun.api.BlockStorage; 11 | import org.bukkit.Location; 12 | import org.bukkit.Material; 13 | import org.bukkit.Particle; 14 | import org.bukkit.Sound; 15 | import org.bukkit.block.Block; 16 | import org.bukkit.block.BlockFace; 17 | import org.bukkit.entity.Entity; 18 | import org.bukkit.entity.Item; 19 | import org.bukkit.entity.Player; 20 | import org.bukkit.event.EventHandler; 21 | import org.bukkit.event.EventPriority; 22 | import org.bukkit.event.Listener; 23 | import org.bukkit.event.block.Action; 24 | import org.bukkit.event.block.BlockBurnEvent; 25 | import org.bukkit.event.block.BlockDispenseEvent; 26 | import org.bukkit.event.block.BlockPlaceEvent; 27 | import org.bukkit.event.entity.EntityDamageEvent; 28 | import org.bukkit.event.inventory.InventoryClickEvent; 29 | import org.bukkit.event.player.PlayerArmorStandManipulateEvent; 30 | import org.bukkit.event.player.PlayerInteractEntityEvent; 31 | import org.bukkit.event.player.PlayerInteractEvent; 32 | import org.bukkit.event.player.PlayerToggleSneakEvent; 33 | import org.bukkit.inventory.ItemStack; 34 | import org.bukkit.potion.PotionEffect; 35 | import org.bukkit.potion.PotionEffectType; 36 | 37 | public class Events implements Listener { 38 | 39 | final HelicopterHat helicopterHat = (HelicopterHat) FluffyItems.HELICOPTER_HAT.getItem(); 40 | final WateringCan wateringCan = (WateringCan) FluffyItems.WATERING_CAN.getItem(); 41 | 42 | @EventHandler(ignoreCancelled = true) 43 | public void onHelicopterHatUse(PlayerToggleSneakEvent e) { 44 | Player p = e.getPlayer(); 45 | if (helicopterHat.isItem(p.getEquipment().getHelmet())) { 46 | if (e.isSneaking()) { 47 | p.addPotionEffect(new PotionEffect(PotionEffectType.LEVITATION, 1000000, 4)); 48 | } else { 49 | p.removePotionEffect(PotionEffectType.LEVITATION); 50 | } 51 | } 52 | } 53 | 54 | @EventHandler(ignoreCancelled = true) 55 | public void onWateringCanSplash(PlayerInteractEntityEvent e) { 56 | Player p = e.getPlayer(); 57 | ItemStack item = p.getInventory().getItemInMainHand(); 58 | 59 | // For some reason player interact events trigger twice, probably after a method returns false 60 | if (wateringCan.isItem(item)) { 61 | e.setCancelled(true); 62 | Entity target = e.getRightClicked(); 63 | if (target instanceof Player && WateringCan.updateUses(wateringCan, p, item, 3)) { 64 | Utils.send(p, "&bSplash!"); 65 | Utils.send((Player) target, "&bYou were splashed by " + p.getDisplayName() + "!"); 66 | ((Player) target).addPotionEffect(new PotionEffect(PotionEffectType.SLOW, 60, 1)); 67 | } 68 | } 69 | } 70 | 71 | @EventHandler(ignoreCancelled = true) 72 | public void onPlayerDamage(EntityDamageEvent e) { 73 | if (e.getEntity() instanceof Player && ((Player) e.getEntity()).getEquipment() != null 74 | && e.getCause() == EntityDamageEvent.DamageCause.FALL 75 | ) { 76 | Player p = (Player) e.getEntity(); 77 | ItemStack helmet = p.getEquipment().getHelmet(); 78 | if (helmet != null && helicopterHat.isItem(helmet) 79 | ) { 80 | e.setCancelled(true); 81 | } 82 | } 83 | } 84 | 85 | // This is used to make the non clickable GUI items non clickable 86 | @EventHandler(ignoreCancelled = true) 87 | public void onNonClickableClick(InventoryClickEvent e) { 88 | ItemStack item = e.getCurrentItem(); 89 | if (item != null && item.getType() != Material.AIR && (item.getItemMeta().hasCustomModelData() 90 | && item.getItemMeta().getCustomModelData() == 6969) || Utils.checkNonInteractable(item)) { 91 | e.setCancelled(true); 92 | } 93 | } 94 | 95 | @EventHandler(ignoreCancelled = true) 96 | public void onHeadRemove(PlayerArmorStandManipulateEvent e) { 97 | if (e.getRightClicked().getCustomName() != null 98 | && e.getRightClicked().getCustomName().equals("hehexdfluff")) 99 | e.setCancelled(true); 100 | } 101 | 102 | @EventHandler(ignoreCancelled = true) 103 | public void onItemDamage(EntityDamageEvent e) { 104 | Entity en = e.getEntity(); 105 | if (en instanceof Item) { 106 | ItemStack item = ((Item) en).getItemStack(); 107 | if (FireproofRune.isFireproof(item) 108 | && (e.getCause() == EntityDamageEvent.DamageCause.FIRE 109 | || e.getCause() == EntityDamageEvent.DamageCause.FIRE_TICK 110 | || e.getCause() == EntityDamageEvent.DamageCause.LAVA 111 | || e.getCause() == EntityDamageEvent.DamageCause.LIGHTNING) 112 | && !en.isDead() 113 | ) { 114 | en.remove(); 115 | en.getLocation().getWorld().dropItem(en.getLocation(), item); 116 | 117 | } 118 | } 119 | } 120 | 121 | @EventHandler(ignoreCancelled = true) 122 | public void onPlayerWarp(PlayerToggleSneakEvent e) { 123 | if (e.isSneaking()) { 124 | Player p = e.getPlayer(); 125 | Block b = p.getLocation().subtract(0, 1, 0).getBlock(); 126 | 127 | if (BlockStorage.hasBlockInfo(b) && BlockStorage.check(b) == FluffyItems.WARP_PAD.getItem() 128 | && BlockStorage.getLocationInfo(b.getLocation(), "type").equals("origin")) { 129 | 130 | Location l = b.getLocation(); 131 | Location destination = new Location(b.getWorld(), 132 | Integer.parseInt(BlockStorage.getLocationInfo(l, "x")), 133 | Integer.parseInt(BlockStorage.getLocationInfo(l, "y")), 134 | Integer.parseInt(BlockStorage.getLocationInfo(l, "z"))); 135 | 136 | float yaw = p.getLocation().getYaw(); 137 | float pitch = p.getLocation().getPitch(); 138 | 139 | if (BlockStorage.hasBlockInfo(destination) && BlockStorage.getLocationInfo(destination, "type") != null 140 | && BlockStorage.getLocationInfo(destination, "type").equals("destination") 141 | && destination.getBlock().getRelative(BlockFace.UP).getType() == Material.AIR 142 | && destination.getBlock().getRelative(BlockFace.UP, 2).getType() == Material.AIR) { 143 | 144 | destination.setPitch(pitch); 145 | destination.setYaw(yaw); 146 | p.teleport(destination.add(0.5, 1, 0.5)); 147 | 148 | p.playSound(p.getLocation(), Sound.ITEM_CHORUS_FRUIT_TELEPORT, 0.5F, 0.5F); 149 | p.spawnParticle(Particle.DRAGON_BREATH, p.getLocation(), 10); 150 | 151 | } else { 152 | Utils.send(p, "&cMissing destination Warp Pad!"); 153 | 154 | } 155 | } 156 | } 157 | } 158 | 159 | @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) 160 | public void onPressurePlateEnter(PlayerInteractEvent e) { 161 | if (e.getAction() != Action.PHYSICAL || e.getClickedBlock() == null) { 162 | return; 163 | } 164 | 165 | String id = BlockStorage.checkID(e.getClickedBlock()); 166 | if (id != null && id.equals(FluffyItems.ALTERNATE_ELEVATOR_PLATE.getItemId())) { 167 | AlternateElevatorPlate elevator = ((AlternateElevatorPlate) FluffyItems.ALTERNATE_ELEVATOR_PLATE.getItem()); 168 | elevator.openInterface(e.getPlayer(), e.getClickedBlock()); 169 | } 170 | } 171 | 172 | @EventHandler(ignoreCancelled = true) 173 | public void onExtractionNodePlace(BlockPlaceEvent e) { 174 | if ((e.getBlock().getY() != e.getBlockAgainst().getY() || e.getBlockAgainst().getType() != Material.ENDER_CHEST) 175 | && isExtractionNode(e.getItemInHand())) { 176 | Utils.send(e.getPlayer(), "&cYou can only place this on an Ender Chest!"); 177 | e.setCancelled(true); 178 | } 179 | } 180 | 181 | @EventHandler(ignoreCancelled = true) 182 | public void onDollyDispense(BlockDispenseEvent e) { 183 | SlimefunItem sfItem = SlimefunItem.getByItem(e.getItem()); 184 | if (sfItem != null && sfItem.getId().equals(FluffyItems.DOLLY.getItemId())) { 185 | e.setCancelled(true); 186 | } 187 | } 188 | 189 | @EventHandler(ignoreCancelled = true) 190 | public void onBarrelBurn(BlockBurnEvent e) { 191 | if (BlockStorage.check(e.getBlock()) instanceof Barrel) { 192 | e.setCancelled(true); 193 | } 194 | } 195 | 196 | private boolean isExtractionNode(@Nonnull ItemStack item) { 197 | SlimefunItem sfItem = SlimefunItem.getByItem(item); 198 | 199 | if (sfItem == null) { 200 | return false; 201 | } 202 | return sfItem.getId().equals(FluffyItems.ENDER_CHEST_EXTRACTION_NODE.getItemId()) || sfItem.getId().equals(FluffyItems.ENDER_CHEST_INSERTION_NODE.getItemId()); 203 | } 204 | 205 | @EventHandler(ignoreCancelled = true) 206 | private void onCancelPlace(BlockPlaceEvent e) { 207 | ItemStack item = e.getItemInHand(); 208 | SlimefunItem sfItem = SlimefunItem.getByItem(item); 209 | if (sfItem instanceof CancelPlace) { 210 | e.setCancelled(true); 211 | } 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/machines/BackpackLoader.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.machines; 2 | 3 | import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile; 4 | import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent; 5 | import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler; 6 | import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNetComponentType; 7 | import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; 8 | import io.github.thebusybiscuit.slimefun4.implementation.items.backpacks.SlimefunBackpack; 9 | import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config; 10 | import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; 11 | import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; 12 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; 13 | import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker; 14 | import me.mrCookieSlime.Slimefun.api.BlockStorage; 15 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; 16 | import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu; 17 | import me.mrCookieSlime.Slimefun.api.inventory.BlockMenuPreset; 18 | import me.mrCookieSlime.Slimefun.api.inventory.DirtyChestMenu; 19 | import me.mrCookieSlime.Slimefun.api.item_transport.ItemTransportFlow; 20 | import io.github.thebusybiscuit.slimefun4.libraries.dough.items.CustomItemStack; 21 | import io.github.thebusybiscuit.slimefun4.libraries.dough.protection.Interaction; 22 | import org.bukkit.ChatColor; 23 | import org.bukkit.Material; 24 | import org.bukkit.Tag; 25 | import org.bukkit.block.Block; 26 | import org.bukkit.entity.Player; 27 | import org.bukkit.event.block.BlockBreakEvent; 28 | import org.bukkit.inventory.Inventory; 29 | import org.bukkit.inventory.ItemStack; 30 | 31 | import javax.annotation.Nonnull; 32 | import java.util.List; 33 | 34 | public class BackpackLoader extends SlimefunItem implements EnergyNetComponent { 35 | 36 | public static final int ENERGY_CONSUMPTION = 16; 37 | public static final int CAPACITY = ENERGY_CONSUMPTION * 3; 38 | 39 | private static final int[] PLAIN_BORDER = {38, 39, 40, 41, 42, 47, 48, 49, 50, 51}; 40 | private static final int[] INPUT_BORDER = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 17, 18, 26, 27, 28, 29, 30, 31, 32, 33, 41 | 34, 35}; 42 | private static final int[] OUTPUT_BORDER = {43, 44, 52}; 43 | private static final int[] BACKPACK_BORDER = {36, 37, 46}; 44 | private static final int[] INPUT_SLOTS = {10, 11, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 24, 25}; 45 | private static final int[] OUTPUT_SLOTS = {53}; 46 | private static final int BACKPACK_SLOT = 45; 47 | 48 | 49 | public BackpackLoader(ItemGroup category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { 50 | super(category, item, recipeType, recipe); 51 | 52 | addItemHandler(onBreak()); 53 | 54 | new BlockMenuPreset(getId(), "&eBackpack Loader") { 55 | 56 | @Override 57 | public void init() { 58 | buildBorder(this, PLAIN_BORDER, INPUT_BORDER, OUTPUT_BORDER); 59 | 60 | for (int i : BACKPACK_BORDER) { 61 | this.addItem(i, new CustomItemStack(new ItemStack(Material.YELLOW_STAINED_GLASS_PANE), " "), 62 | (p, slot, item, action) -> false 63 | ); 64 | } 65 | } 66 | 67 | @Override 68 | public boolean canOpen(@Nonnull Block b, @Nonnull Player p) { 69 | return p.hasPermission("slimefun.inventory.bypass") 70 | || Slimefun.getProtectionManager().hasPermission(p, b.getLocation(), 71 | Interaction.INTERACT_BLOCK); 72 | } 73 | 74 | @Override 75 | public int[] getSlotsAccessedByItemTransport(ItemTransportFlow flow) { 76 | return new int[0]; 77 | } 78 | 79 | @Override 80 | public int[] getSlotsAccessedByItemTransport(DirtyChestMenu menu, ItemTransportFlow flow, ItemStack item) { 81 | if (flow == ItemTransportFlow.WITHDRAW) { 82 | return getOutputSlots(); 83 | } else { 84 | return getInputSlots(); 85 | } 86 | } 87 | }; 88 | 89 | } 90 | 91 | private BlockBreakHandler onBreak() { 92 | return new BlockBreakHandler(false, false) { 93 | @Override 94 | public void onPlayerBreak(@Nonnull BlockBreakEvent e, @Nonnull ItemStack item, @Nonnull List drops) { 95 | Block b = e.getBlock(); 96 | BlockMenu inv = BlockStorage.getInventory(b); 97 | 98 | if (inv != null) { 99 | inv.dropItems(b.getLocation(), getInputSlots()); 100 | inv.dropItems(b.getLocation(), getOutputSlots()); 101 | inv.dropItems(b.getLocation(), BACKPACK_SLOT); 102 | } 103 | } 104 | }; 105 | } 106 | 107 | @Override 108 | public void preRegister() { 109 | this.addItemHandler(new BlockTicker() { 110 | public void tick(Block b, SlimefunItem sf, Config data) { 111 | BackpackLoader.this.tick(b); 112 | } 113 | 114 | public boolean isSynchronized() { 115 | return false; 116 | } 117 | }); 118 | } 119 | 120 | private void tick(@Nonnull Block b) { 121 | 122 | if (getCharge(b.getLocation()) < ENERGY_CONSUMPTION) { 123 | return; 124 | } 125 | 126 | final BlockMenu inv = BlockStorage.getInventory(b); 127 | boolean invalidItem = false; 128 | 129 | // If no backpack in backpack slot, search for one and if found move to BACKPACK_SLOT 130 | if (inv.getItemInSlot(BACKPACK_SLOT) == null) { 131 | for (int inputSlot : getInputSlots()) { 132 | ItemStack backpackItem = inv.getItemInSlot(inputSlot); 133 | if (backpackItem != null && SlimefunItem.getByItem(backpackItem) instanceof SlimefunBackpack) { 134 | 135 | // Make sure it has an ID 136 | List lore = backpackItem.getItemMeta().getLore(); 137 | for (String s : lore) { 138 | if (s.equals(ChatColor.GRAY + "ID: ")) { 139 | invalidItem = true; 140 | break; 141 | } 142 | } 143 | if (!invalidItem) { 144 | moveItem(inv, inputSlot, BACKPACK_SLOT); 145 | 146 | } else if (inv.getItemInSlot(getOutputSlots()[0]) == null) { 147 | moveItem(inv, inputSlot, getOutputSlots()[0]); 148 | } 149 | return; 150 | } 151 | } 152 | } 153 | 154 | int occupiedInputSlot = 0; 155 | 156 | // Are there any items in the input? 157 | for (int inputSlot : getInputSlots()) { 158 | if (inv.getItemInSlot(inputSlot) != null 159 | && !(SlimefunItem.getByItem(inv.getItemInSlot(inputSlot)) instanceof SlimefunBackpack) 160 | && !Tag.SHULKER_BOXES.isTagged(inv.getItemInSlot(inputSlot).getType())) { 161 | occupiedInputSlot = inputSlot; 162 | break; 163 | } else if (inputSlot == getInputSlots()[13]) { 164 | return; 165 | } 166 | } 167 | 168 | // Loading the backpack 169 | ItemStack bpItem = inv.getItemInSlot(BACKPACK_SLOT); 170 | SlimefunItem sfItem = SlimefunItem.getByItem(bpItem); 171 | if (sfItem instanceof SlimefunBackpack) { 172 | 173 | ItemStack transferItem = inv.getItemInSlot(occupiedInputSlot); 174 | 175 | int finalOccupiedInputSlot = occupiedInputSlot; 176 | PlayerProfile.getBackpack(bpItem, backpack -> { 177 | 178 | Inventory bpinv = backpack.getInventory(); 179 | 180 | int bpSlot = bpinv.firstEmpty(); 181 | 182 | // Backpack is full 183 | if (bpSlot == -1) { 184 | if (inv.getItemInSlot(OUTPUT_SLOTS[0]) == null) { 185 | moveItem(inv, BACKPACK_SLOT, OUTPUT_SLOTS[0]); 186 | } 187 | return; 188 | } 189 | 190 | if (bpinv.getItem(bpSlot) == null) { 191 | 192 | // IntelliJ wanted me to put it as a separate variable so here we are 193 | inv.replaceExistingItem(finalOccupiedInputSlot, null); 194 | bpinv.setItem(bpSlot, transferItem); 195 | 196 | removeCharge(b.getLocation(), ENERGY_CONSUMPTION); 197 | } 198 | }); 199 | } 200 | } 201 | 202 | private void moveItem(BlockMenu inv, int slot1, int slot2) { 203 | ItemStack transferItem = inv.getItemInSlot(slot1); 204 | inv.replaceExistingItem(slot1, null); 205 | inv.pushItem(transferItem, slot2); 206 | } 207 | 208 | @Nonnull 209 | @Override 210 | public EnergyNetComponentType getEnergyComponentType() { 211 | return EnergyNetComponentType.CONSUMER; 212 | } 213 | 214 | @Override 215 | public int getCapacity() { 216 | return CAPACITY; 217 | } 218 | 219 | public int[] getInputSlots() { 220 | return INPUT_SLOTS; 221 | } 222 | 223 | public int[] getOutputSlots() { 224 | return OUTPUT_SLOTS; 225 | } 226 | 227 | static void buildBorder(BlockMenuPreset preset, int[] plainBorder, int[] inputBorder, int[] outputBorder) { 228 | for (int i : plainBorder) { 229 | preset.addItem(i, new CustomItemStack(new ItemStack(Material.GRAY_STAINED_GLASS_PANE), " "), 230 | (p, slot, item, action) -> false 231 | ); 232 | } 233 | 234 | for (int i : inputBorder) { 235 | preset.addItem(i, new CustomItemStack(new ItemStack(Material.CYAN_STAINED_GLASS_PANE), " "), 236 | (p, slot, item, action) -> false 237 | ); 238 | } 239 | 240 | for (int i : outputBorder) { 241 | preset.addItem(i, new CustomItemStack(new ItemStack(Material.ORANGE_STAINED_GLASS_PANE), " "), 242 | (p, slot, item, action) -> false 243 | ); 244 | } 245 | } 246 | } 247 | 248 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/machines/AutoTableSaw.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.machines; 2 | 3 | import io.github.thebusybiscuit.slimefun4.api.events.BlockPlacerPlaceEvent; 4 | import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent; 5 | import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler; 6 | import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler; 7 | import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNetComponentType; 8 | import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; 9 | import io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks.TableSaw; 10 | import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils; 11 | import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; 12 | import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config; 13 | import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; 14 | import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; 15 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; 16 | import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker; 17 | import me.mrCookieSlime.Slimefun.api.BlockStorage; 18 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; 19 | import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu; 20 | import me.mrCookieSlime.Slimefun.api.inventory.BlockMenuPreset; 21 | import me.mrCookieSlime.Slimefun.api.inventory.DirtyChestMenu; 22 | import me.mrCookieSlime.Slimefun.api.item_transport.ItemTransportFlow; 23 | import io.github.thebusybiscuit.slimefun4.libraries.dough.items.CustomItemStack; 24 | import io.github.thebusybiscuit.slimefun4.libraries.dough.protection.Interaction; 25 | import org.bukkit.Location; 26 | import org.bukkit.Material; 27 | import org.bukkit.Tag; 28 | import org.bukkit.block.Block; 29 | import org.bukkit.entity.Player; 30 | import org.bukkit.event.block.BlockBreakEvent; 31 | import org.bukkit.event.block.BlockPlaceEvent; 32 | import org.bukkit.inventory.ItemStack; 33 | 34 | import javax.annotation.Nonnull; 35 | import java.util.HashMap; 36 | import java.util.List; 37 | import java.util.Map; 38 | import java.util.Optional; 39 | 40 | /** 41 | * This {@link SlimefunItem} is an electric version 42 | * of the {@link TableSaw} 43 | * 44 | * @author NCBPFluffyBear 45 | */ 46 | public class AutoTableSaw extends SlimefunItem implements EnergyNetComponent { 47 | 48 | public static final int ENERGY_CONSUMPTION = 128; 49 | public static final int CAPACITY = ENERGY_CONSUMPTION * 3; 50 | private final int[] border = {0, 1, 3, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 22, 27, 31, 36, 40, 45, 51 | 46, 47, 48, 49, 50, 51, 52, 53}; 52 | private final int[] inputBorder = {19, 20, 21, 28, 30, 37, 38, 39,}; 53 | private final int[] outputBorder = {23, 24, 25, 26, 32, 35, 41, 42, 43, 44}; 54 | private final int[] inputSlots = {29}; 55 | private final int[] outputSlots = {33, 34}; 56 | 57 | private final Map tableSawRecipes = new HashMap<>(); 58 | 59 | public AutoTableSaw(ItemGroup category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { 60 | super(category, item, recipeType, recipe); 61 | 62 | for (Material log : Tag.LOGS.getValues()) { 63 | Optional planks = getPlanks(log); 64 | 65 | planks.ifPresent(material -> tableSawRecipes.put(new ItemStack(log), new ItemStack(material, 8))); 66 | } 67 | 68 | for (Material plank : Tag.PLANKS.getValues()) { 69 | tableSawRecipes.put(new ItemStack(plank), new ItemStack(Material.STICK, 4)); 70 | } 71 | 72 | new BlockMenuPreset(getId(), "&6Auto Table Saw") { 73 | 74 | @Override 75 | public void init() { 76 | constructMenu(this); 77 | } 78 | 79 | @Override 80 | public void newInstance(@Nonnull BlockMenu menu, @Nonnull Block b) { 81 | if (!BlockStorage.hasBlockInfo(b) 82 | || BlockStorage.getLocationInfo(b.getLocation(), "enabled") == null 83 | || BlockStorage.getLocationInfo(b.getLocation(), "enabled").equals(String.valueOf(false))) { 84 | menu.replaceExistingItem(6, new CustomItemStack(Material.GUNPOWDER, "&7Enabled: &4\u2718", 85 | "", "&e> Click to enable this Machine") 86 | ); 87 | menu.addMenuClickHandler(6, (p, slot, item, action) -> { 88 | BlockStorage.addBlockInfo(b, "enabled", String.valueOf(true)); 89 | newInstance(menu, b); 90 | return false; 91 | }); 92 | } else { 93 | menu.replaceExistingItem(6, new CustomItemStack(Material.REDSTONE, "&7Enabled: &2\u2714", 94 | "", "&e> Click to disable this Machine")); 95 | menu.addMenuClickHandler(6, (p, slot, item, action) -> { 96 | BlockStorage.addBlockInfo(b, "enabled", String.valueOf(false)); 97 | newInstance(menu, b); 98 | return false; 99 | }); 100 | } 101 | } 102 | 103 | @Override 104 | public boolean canOpen(@Nonnull Block b, @Nonnull Player p) { 105 | return p.hasPermission("slimefun.inventory.bypass") 106 | || Slimefun.getProtectionManager().hasPermission(p, b.getLocation(), 107 | Interaction.INTERACT_BLOCK 108 | ); 109 | } 110 | 111 | @Override 112 | public int[] getSlotsAccessedByItemTransport(ItemTransportFlow flow) { 113 | return new int[0]; 114 | } 115 | 116 | @Override 117 | public int[] getSlotsAccessedByItemTransport(DirtyChestMenu menu, ItemTransportFlow flow, ItemStack item) { 118 | if (flow == ItemTransportFlow.WITHDRAW) { 119 | return outputSlots; 120 | } else { 121 | return inputSlots; 122 | } 123 | } 124 | }; 125 | 126 | addItemHandler(onPlace()); 127 | addItemHandler(onBreak()); 128 | 129 | } 130 | 131 | private BlockBreakHandler onBreak() { 132 | return new BlockBreakHandler(false, false) { 133 | @Override 134 | public void onPlayerBreak(@Nonnull BlockBreakEvent e, @Nonnull ItemStack item, @Nonnull List drops) { 135 | Block b = e.getBlock(); 136 | BlockMenu inv = BlockStorage.getInventory(b); 137 | Location location = b.getLocation(); 138 | 139 | if (inv != null) { 140 | inv.dropItems(location, inputSlots); 141 | inv.dropItems(location, outputSlots); 142 | } 143 | } 144 | }; 145 | } 146 | 147 | private BlockPlaceHandler onPlace() { 148 | return new BlockPlaceHandler(true) { 149 | 150 | @Override 151 | public void onPlayerPlace(@Nonnull BlockPlaceEvent e) { 152 | BlockStorage.addBlockInfo(e.getBlock(), "enabled", String.valueOf(false)); 153 | } 154 | 155 | @Override 156 | public void onBlockPlacerPlace(@Nonnull BlockPlacerPlaceEvent e) { 157 | BlockStorage.addBlockInfo(e.getBlock(), "enabled", String.valueOf(false)); 158 | } 159 | }; 160 | } 161 | 162 | protected void constructMenu(BlockMenuPreset preset) { 163 | 164 | borders(preset, border, inputBorder, outputBorder); 165 | preset.addItem(2, new CustomItemStack(new ItemStack(Material.STONECUTTER), "&eRecipe", "", 166 | "&bPut in the Recipe you want to craft", 167 | "&4Table Saw Recipes ONLY" 168 | ), 169 | ChestMenuUtils.getEmptyClickHandler()); 170 | } 171 | 172 | @Nonnull 173 | @Override 174 | public EnergyNetComponentType getEnergyComponentType() { 175 | return EnergyNetComponentType.CONSUMER; 176 | } 177 | 178 | @Override 179 | public int getCapacity() { 180 | return CAPACITY; 181 | } 182 | 183 | public int getEnergyConsumption() { 184 | return ENERGY_CONSUMPTION; 185 | } 186 | 187 | @Override 188 | public void preRegister() { 189 | addItemHandler(new BlockTicker() { 190 | 191 | @Override 192 | public void tick(Block b, SlimefunItem sf, Config data) { 193 | AutoTableSaw.this.tick(b); 194 | } 195 | 196 | @Override 197 | public boolean isSynchronized() { 198 | return false; 199 | } 200 | }); 201 | } 202 | 203 | protected void tick(Block block) { 204 | if (BlockStorage.getLocationInfo(block.getLocation(), "enabled").equals(String.valueOf(false))) { 205 | return; 206 | } 207 | 208 | if (getCharge(block.getLocation()) < getEnergyConsumption()) { 209 | return; 210 | } 211 | 212 | BlockMenu menu = BlockStorage.getInventory(block); 213 | tableSawRecipes.forEach((input, output) -> { 214 | if (menu.getItemInSlot(inputSlots[0]) != null 215 | && SlimefunUtils.isItemSimilar(menu.getItemInSlot(inputSlots[0]), input, true, false) 216 | && menu.fits(output, outputSlots)) { 217 | 218 | menu.consumeItem(inputSlots[0]); 219 | menu.pushItem(output.clone(), outputSlots); 220 | } 221 | }); 222 | } 223 | 224 | /** 225 | * Method that finds planks associated with a log 226 | * @author TheBusyBiscuit 227 | */ 228 | private @Nonnull Optional getPlanks(@Nonnull Material log) { 229 | String materialName = log.name().replace("STRIPPED_", ""); 230 | materialName = materialName.substring(0, materialName.lastIndexOf('_')) + "_PLANKS"; 231 | return Optional.ofNullable(Material.getMaterial(materialName)); 232 | } 233 | 234 | static void borders(BlockMenuPreset preset, int[] border, int[] inputBorder, int[] outputBorder) { 235 | for (int i : border) { 236 | preset.addItem(i, new CustomItemStack(new ItemStack(Material.GRAY_STAINED_GLASS_PANE), " "), 237 | (p, slot, item, action) -> false); 238 | } 239 | 240 | for (int i : inputBorder) { 241 | preset.addItem(i, new CustomItemStack(new ItemStack(Material.CYAN_STAINED_GLASS_PANE), " "), 242 | (p, slot, item, action) -> false); 243 | } 244 | 245 | for (int i : outputBorder) { 246 | preset.addItem(i, new CustomItemStack(new ItemStack(Material.ORANGE_STAINED_GLASS_PANE), " "), 247 | (p, slot, item, action) -> false); 248 | } 249 | } 250 | 251 | } 252 | 253 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/items/tools/CargoManipulator.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.items.tools; 2 | 3 | import com.google.gson.JsonObject; 4 | import com.google.gson.JsonParser; 5 | import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; 6 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; 7 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; 8 | import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; 9 | import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler; 10 | import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; 11 | import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems; 12 | import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem; 13 | import io.github.thebusybiscuit.slimefun4.libraries.dough.collections.Pair; 14 | import io.github.thebusybiscuit.slimefun4.libraries.dough.items.CustomItemStack; 15 | import io.github.thebusybiscuit.slimefun4.libraries.dough.protection.Interaction; 16 | import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; 17 | import io.ncbpfluffybear.fluffymachines.FluffyMachines; 18 | import io.ncbpfluffybear.fluffymachines.utils.Utils; 19 | import me.mrCookieSlime.Slimefun.api.BlockStorage; 20 | import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu; 21 | import org.bukkit.Bukkit; 22 | import org.bukkit.Color; 23 | import org.bukkit.Particle; 24 | import org.bukkit.block.Block; 25 | import org.bukkit.entity.Player; 26 | import org.bukkit.event.Event; 27 | import org.bukkit.event.EventHandler; 28 | import org.bukkit.event.Listener; 29 | import org.bukkit.event.block.Action; 30 | import org.bukkit.event.player.PlayerInteractEvent; 31 | import org.bukkit.inventory.Inventory; 32 | import org.bukkit.inventory.ItemStack; 33 | 34 | import javax.annotation.Nonnull; 35 | import java.util.HashMap; 36 | import java.util.Map; 37 | 38 | /** 39 | * used to quickly manipulate cargo nodes 40 | * 41 | * @author NCBPFluffyBear 42 | */ 43 | public class CargoManipulator extends SimpleSlimefunItem implements Listener { 44 | 45 | private static final int[] CARGO_SLOTS = {19, 20, 21, 28, 29, 30, 37, 38, 39}; 46 | private final Map> storedFilters = new HashMap<>(); 47 | 48 | public CargoManipulator(ItemGroup category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { 49 | super(category, item, recipeType, recipe); 50 | 51 | Bukkit.getPluginManager().registerEvents(this, FluffyMachines.getInstance()); 52 | } 53 | 54 | @Nonnull 55 | @Override 56 | public ItemUseHandler getItemHandler() { 57 | return e -> e.setUseBlock(Event.Result.DENY); // Prevent opening inventories 58 | } 59 | 60 | @EventHandler 61 | private void onCargoManipulatorUse(PlayerInteractEvent e) { 62 | 63 | ItemStack manipulator = e.getItem(); 64 | 65 | // Check item is cargo manipulator 66 | if (manipulator == null || !this.isItem(manipulator)) { 67 | return; 68 | } 69 | 70 | e.setCancelled(true); 71 | 72 | Action act = e.getAction(); 73 | Player p = e.getPlayer(); 74 | Block b = e.getClickedBlock(); 75 | 76 | // Check if targeted block is cargo node 77 | SlimefunItemStack nodeType = getCargoNodeType(b); 78 | if (nodeType == null || ( 79 | nodeType != SlimefunItems.CARGO_OUTPUT_NODE && 80 | nodeType != SlimefunItems.CARGO_OUTPUT_NODE_2 && 81 | nodeType != SlimefunItems.CARGO_INPUT_NODE 82 | )) { 83 | return; 84 | } 85 | 86 | if (!Slimefun.getProtectionManager().hasPermission(e.getPlayer(), b.getLocation(), Interaction.INTERACT_BLOCK)) { 87 | return; 88 | } 89 | 90 | if (act == Action.RIGHT_CLICK_BLOCK) { 91 | if (p.isSneaking()) { 92 | clearNode(b, p, getCargoNodeType(b)); 93 | } else { 94 | copyNode(b, p, getCargoNodeType(b)); 95 | } 96 | } else { 97 | pasteNode(b, p, getCargoNodeType(b)); 98 | } 99 | } 100 | 101 | /** 102 | * Copy's a node's data into the manipulator. Cargo inventories stored in map. 103 | * Action: Right Click Block 104 | */ 105 | private void copyNode(Block parent, Player p, SlimefunItemStack nodeType) { 106 | // Copy BlockStorage data 107 | JsonObject nodeData = (JsonObject) new JsonParser().parse(BlockStorage.getBlockInfoAsJson(parent)); 108 | 109 | ItemStack[] filterItems = new ItemStack[9]; 110 | if (nodeType != SlimefunItems.CARGO_OUTPUT_NODE) { // No inventory 111 | // Copy inventory into map 112 | BlockMenu parentInventory = BlockStorage.getInventory(parent); 113 | for (int i = 0; i < 9; i++) { // Iterate through all slots in cargo filter 114 | ItemStack menuItem = parentInventory.getItemInSlot(CARGO_SLOTS[i]); 115 | if (menuItem != null) { 116 | filterItems[i] = new CustomItemStack(menuItem, 1); 117 | } else { 118 | filterItems[i] = null; 119 | } 120 | } 121 | } 122 | 123 | storedFilters.put(p, new Pair<>(nodeData, filterItems)); // Save cargo slots into map 124 | 125 | Utils.send(p, "&aYour " + SlimefunItem.getById(nodeData.get("id").getAsString()).getItemName() + " &ahas been copied."); 126 | createParticle(parent, Color.fromRGB(255, 252, 51)); // Bright Yellow 127 | } 128 | 129 | /** 130 | * Pastes stored node contents 131 | * Action: Left Click 132 | */ 133 | private void pasteNode(Block child, Player p, SlimefunItemStack nodeType) { 134 | Pair nodeSettings = storedFilters.getOrDefault(p, null); 135 | 136 | // No data saved yet 137 | if (nodeSettings == null) { 138 | Utils.send(p, "&cYou have not copied a cargo node yet."); 139 | return; 140 | } 141 | 142 | // Get saved data 143 | JsonObject jsonData = nodeSettings.getFirstValue(); 144 | 145 | SlimefunItemStack savedNodeType = (SlimefunItemStack) SlimefunItem.getById(jsonData.get("id").getAsString()).getItem(); 146 | if (savedNodeType != nodeType) { 147 | Utils.send(p, "&cYou copied a " + savedNodeType.getDisplayName() + 148 | " &cbut you are trying to modify a " + nodeType.getDisplayName() + "&c!"); 149 | createParticle(child, Color.RED); 150 | return; 151 | } 152 | 153 | // Set the data 154 | BlockStorage.setBlockInfo(child, jsonData.toString(), false); 155 | 156 | if (nodeType != SlimefunItems.CARGO_OUTPUT_NODE) { 157 | // Set the filter 158 | BlockMenu nodeMenu = BlockStorage.getInventory(child); 159 | ItemStack[] filterItems = nodeSettings.getSecondValue(); 160 | Inventory playerInventory = p.getInventory(); 161 | 162 | for (int i = 0; i < 9; i++) { 163 | 164 | // Check if item already exists in slot 165 | if (SlimefunUtils.isItemSimilar(filterItems[i], nodeMenu.getItemInSlot(CARGO_SLOTS[i]), true, false)) { 166 | continue; 167 | } 168 | 169 | // Drop item in filter slot 170 | clearFilterSlot(nodeMenu, CARGO_SLOTS[i], p); 171 | 172 | // No need to insert new items in 173 | if (filterItems[i] == null) { 174 | continue; 175 | } 176 | 177 | // Check if item not in inventory 178 | if (!SlimefunUtils.containsSimilarItem(playerInventory, filterItems[i], true)) { 179 | createParticle(child, Color.AQUA); 180 | Utils.send(p, "&cYou do not have " + Utils.getViewableName(filterItems[i]) + "&c. Skipping this item."); 181 | continue; 182 | } 183 | 184 | // Consume item in player inventory 185 | for (ItemStack playerItem : playerInventory) { 186 | if (SlimefunUtils.isItemSimilar(playerItem, filterItems[i], false, false)) { 187 | playerItem.setAmount(playerItem.getAmount() - 1); 188 | 189 | // Insert item into node menu 190 | nodeMenu.replaceExistingItem(CARGO_SLOTS[i], new CustomItemStack(playerItem, 1)); 191 | break; 192 | } 193 | } 194 | } 195 | } 196 | 197 | // Force menu update 198 | BlockStorage.getStorage(child.getWorld()).reloadInventory(child.getLocation()); 199 | Utils.send(p, "&aYour " + savedNodeType.getDisplayName() + " &ahas been pasted."); 200 | createParticle(child, Color.LIME); 201 | 202 | } 203 | 204 | /** 205 | * Clears the data of a targeted node 206 | * Action: Sneak + Right Click Block 207 | */ 208 | private void clearNode(Block node, Player p, SlimefunItemStack nodeType) { 209 | // Clear node settings 210 | BlockStorage.addBlockInfo(node, "owner", p.getUniqueId().toString()); 211 | BlockStorage.addBlockInfo(node, "frequency", "0"); 212 | 213 | // These settings are only for Input and Advanced Output nodes 214 | if (nodeType != SlimefunItems.CARGO_OUTPUT_NODE) { 215 | // AbstractFilterNode settings 216 | BlockStorage.addBlockInfo(node, "index", "0"); 217 | BlockStorage.addBlockInfo(node, "filter-type", "whitelist"); 218 | BlockStorage.addBlockInfo(node, "filter-lore", String.valueOf(true)); 219 | BlockStorage.addBlockInfo(node, "filter-durability", String.valueOf(false)); 220 | 221 | if (nodeType == SlimefunItems.CARGO_INPUT_NODE) { 222 | // CargoInputNode settings 223 | BlockStorage.addBlockInfo(node, "round-robin", String.valueOf(false)); 224 | BlockStorage.addBlockInfo(node, "smart-fill", String.valueOf(false)); 225 | } 226 | 227 | clearNodeFilter(node, p); 228 | 229 | // Force update 230 | BlockStorage.getStorage(node.getWorld()).reloadInventory(node.getLocation()); 231 | 232 | Utils.send(p, "&aThe selected Cargo Node has been cleared"); 233 | createParticle(node, Color.fromRGB(255, 152, 56)); // Light orange 234 | } 235 | } 236 | 237 | private void clearNodeFilter(Block node, Player p) { 238 | // Empty filter contents 239 | BlockMenu nodeMenu = BlockStorage.getInventory(node); 240 | for (int i = 0; i < 9; i++) { 241 | clearFilterSlot(nodeMenu, CARGO_SLOTS[i], p); 242 | } 243 | } 244 | 245 | private void clearFilterSlot(BlockMenu nodeMenu, int slot, Player p) { 246 | ItemStack filterItem = nodeMenu.getItemInSlot(slot); 247 | if (filterItem != null) { 248 | Utils.giveOrDropItem(p, filterItem); // Give player item in filter 249 | nodeMenu.replaceExistingItem(slot, null); // Clear item in filter 250 | } 251 | } 252 | 253 | /** 254 | * Get the SlimefunItemStack of the cargo node 255 | */ 256 | private SlimefunItemStack getCargoNodeType(Block b) { 257 | if (b == null) { 258 | return null; 259 | } 260 | 261 | String blockId = BlockStorage.checkID(b); 262 | 263 | if (blockId == null) { 264 | return null; 265 | } 266 | 267 | return (SlimefunItemStack) SlimefunItem.getById(blockId).getItem(); 268 | } 269 | 270 | private void createParticle(Block b, Color color) { 271 | Particle.DustOptions dustOption = new Particle.DustOptions(color, 1); 272 | b.getLocation().getWorld().spawnParticle(Particle.REDSTONE, b.getLocation().add(0.5, 0.5, 0.5), 1, dustOption); 273 | } 274 | } 275 | -------------------------------------------------------------------------------- /src/main/java/io/ncbpfluffybear/fluffymachines/items/tools/Dolly.java: -------------------------------------------------------------------------------- 1 | package io.ncbpfluffybear.fluffymachines.items.tools; 2 | 3 | import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; 4 | import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; 5 | import io.github.thebusybiscuit.slimefun4.api.player.PlayerBackpack; 6 | import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile; 7 | import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; 8 | import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler; 9 | import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; 10 | import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem; 11 | import io.github.thebusybiscuit.slimefun4.libraries.dough.protection.Interaction; 12 | import io.ncbpfluffybear.fluffymachines.utils.Utils; 13 | import me.mrCookieSlime.Slimefun.api.BlockStorage; 14 | import org.bukkit.Material; 15 | import org.bukkit.block.Block; 16 | import org.bukkit.block.BlockFace; 17 | import org.bukkit.block.DoubleChest; 18 | import org.bukkit.block.data.Directional; 19 | import org.bukkit.block.data.type.Chest; 20 | import org.bukkit.entity.Player; 21 | import org.bukkit.inventory.Inventory; 22 | import org.bukkit.inventory.InventoryHolder; 23 | import org.bukkit.inventory.ItemStack; 24 | import org.bukkit.inventory.meta.ItemMeta; 25 | import org.bukkit.scheduler.BukkitRunnable; 26 | 27 | import javax.annotation.Nonnull; 28 | import javax.annotation.Nullable; 29 | import java.util.Arrays; 30 | import java.util.HashMap; 31 | import java.util.Map; 32 | import java.util.concurrent.atomic.AtomicBoolean; 33 | 34 | public class Dolly extends SimpleSlimefunItem { 35 | 36 | private static final ItemStack LOCK_ITEM = Utils.buildNonInteractable( 37 | Material.DIRT, "&4&lDolly empty", "&cHow did you get in here?" 38 | ); 39 | 40 | private static final int DELAY = 500; // 500ms 41 | private final Map timeouts; 42 | 43 | public Dolly(ItemGroup category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { 44 | super(category, item, recipeType, recipe); 45 | this.timeouts = new HashMap<>(); 46 | } 47 | 48 | @Nonnull 49 | @Override 50 | public ItemUseHandler getItemHandler() { 51 | return e -> { 52 | e.cancel(); 53 | 54 | Player p = e.getPlayer(); 55 | 56 | if (timeouts.containsKey(p) && timeouts.get(p) + DELAY > System.currentTimeMillis()) { 57 | Utils.send(p, "&cPlease wait before using the dolly again!"); 58 | return; 59 | } 60 | 61 | timeouts.put(p, System.currentTimeMillis()); 62 | 63 | ItemStack dolly = e.getItem(); 64 | 65 | if (!e.getClickedBlock().isPresent()) { 66 | return; 67 | } 68 | 69 | Block b = e.getClickedBlock().get(); 70 | 71 | // Block usage on Slimefun Blocks 72 | if (BlockStorage.hasBlockInfo(b)) { 73 | return; 74 | } 75 | 76 | if (b.getType() == Material.CHEST && Slimefun.getProtectionManager().hasPermission( 77 | e.getPlayer(), b.getLocation(), Interaction.BREAK_BLOCK) 78 | ) { 79 | 80 | // Create dolly if not already one 81 | buildDolly(dolly, p); 82 | 83 | // Pick up the chest 84 | pickupChest(dolly, b, p); 85 | 86 | 87 | } else if (Slimefun.getProtectionManager().hasPermission( 88 | e.getPlayer(), b.getLocation(), Interaction.PLACE_BLOCK) 89 | ) { 90 | 91 | // Place new chest 92 | placeChest(dolly, b.getRelative(e.getClickedFace()), p); 93 | } 94 | 95 | }; 96 | } 97 | 98 | private void buildDolly(ItemStack dolly, Player p) { 99 | // Build backpack if new 100 | ItemMeta dollyMeta = dolly.getItemMeta(); 101 | for (String line : dollyMeta.getLore()) { 102 | if (line.contains("ID: ")) { 103 | PlayerProfile.get(p, profile -> { 104 | int backpackId = profile.createBackpack(54).getId(); 105 | Slimefun.getBackpackListener().setBackpackId(p, dolly, 3, backpackId); 106 | PlayerProfile.getBackpack(dolly, backpack -> backpack.getInventory().setItem(0, LOCK_ITEM)); 107 | }); 108 | } 109 | } 110 | } 111 | 112 | private void pickupChest(ItemStack dolly, Block chest, Player p) { 113 | Inventory chestInventory = ((InventoryHolder) chest.getState()).getInventory(); 114 | AtomicBoolean validOperation = new AtomicBoolean(false); // Used to deal with async block replacement 115 | AtomicBoolean isDoubleChest = new AtomicBoolean(false); 116 | 117 | PlayerProfile.getBackpack(dolly, backpack -> { 118 | 119 | if (backpack == null) { 120 | return; 121 | } 122 | 123 | // Dolly full/empty status determined by lock item in first slot 124 | // Make sure the dolly is empty 125 | if (!isLockItem(backpack.getInventory().getItem(0))) { 126 | Utils.send(p, "&cThis dolly is already carrying a chest!"); 127 | return; 128 | } 129 | 130 | // Update old dollies to be able to store double chests 131 | if (backpack.getSize() < 54) { 132 | backpack.setSize(54); 133 | } 134 | 135 | backpack.getInventory().setStorageContents(chestInventory.getContents()); 136 | 137 | // Add marker for single chests 138 | if (chestInventory.getSize() == 54) { // Double chest (Avoid instanceof because of weird chest class setup) 139 | isDoubleChest.set(true); 140 | } else { 141 | backpack.getInventory().setItem(27, LOCK_ITEM); 142 | } 143 | 144 | // Clear chest 145 | chestInventory.clear(); 146 | PlayerProfile.getBackpack(dolly, PlayerBackpack::markDirty); 147 | validOperation.set(true); 148 | dolly.setType(Material.CHEST_MINECART); 149 | }); 150 | 151 | // Deals with async problems 152 | if (validOperation.get()) { 153 | if (isDoubleChest.get()) { 154 | 155 | DoubleChest doubleChest = (DoubleChest) ((org.bukkit.block.Chest) chest.getState()).getInventory().getHolder(); 156 | 157 | // Set other side of chest to air 158 | if (((org.bukkit.block.Chest) doubleChest.getLeftSide()).getLocation().equals(chest.getLocation()) 159 | ) { 160 | ((org.bukkit.block.Chest) doubleChest.getRightSide()).getLocation().getBlock().setType(Material.AIR); 161 | } else { 162 | ((org.bukkit.block.Chest) doubleChest.getLeftSide()).getLocation().getBlock().setType(Material.AIR); 163 | } 164 | 165 | } 166 | 167 | chest.setType(Material.AIR); 168 | 169 | Utils.send(p, "&aYou have picked up this chest"); 170 | } 171 | } 172 | 173 | private void placeChest(ItemStack dolly, Block chestBlock, Player p) { 174 | PlayerProfile.getBackpack(dolly, backpack -> { 175 | 176 | if (backpack == null) { 177 | return; 178 | } 179 | 180 | // Update backpack size to fit doublechests 181 | if (backpack.getSize() == 27) { 182 | backpack.setSize(54); 183 | backpack.getInventory().setItem(27, LOCK_ITEM); // Mark as single chest 184 | } 185 | 186 | final ItemStack[][] bpContents = {backpack.getInventory().getContents()}; 187 | 188 | if (isLockItem(bpContents[0][0])) { 189 | Utils.send(p, "&cYou must pick up a chest first!"); 190 | return; 191 | } 192 | 193 | boolean singleChest = isLockItem(bpContents[0][27]); 194 | if (!canChestFit(chestBlock, p, singleChest)) { 195 | Utils.send(p, "&cYou can't fit your chest there!"); 196 | return; 197 | } 198 | 199 | Utils.runSync(new BukkitRunnable() { 200 | @Override 201 | public void run() { 202 | createChest(chestBlock, p, singleChest); 203 | backpack.getInventory().clear(); 204 | backpack.getInventory().setItem(0, LOCK_ITEM); 205 | 206 | // Shrink contents size if single chest 207 | if (singleChest) { 208 | bpContents[0] = Arrays.copyOf(bpContents[0], 27); 209 | } 210 | 211 | ((InventoryHolder) chestBlock.getState()).getInventory().setStorageContents(bpContents[0]); 212 | dolly.setType(Material.MINECART); 213 | Utils.send(p, "&aChest has been placed"); 214 | } 215 | }); 216 | }); 217 | } 218 | 219 | private boolean canChestFit(Block singleChestBlock, Player p, boolean singleChest) { 220 | 221 | boolean fits = singleChestBlock.getType() == Material.AIR; 222 | 223 | if (!singleChest) { 224 | fits = fits && getRightBlock(singleChestBlock, p.getFacing().getOppositeFace()).getType() == Material.AIR; 225 | } 226 | 227 | return fits; 228 | } 229 | 230 | private void createChest(Block firstChest, Player p, boolean singleChest) { 231 | BlockFace chestFace = p.getFacing().getOppositeFace(); 232 | 233 | // Place chest and rotate 234 | firstChest.setType(Material.CHEST); 235 | Directional firstDirectional = ((Directional) firstChest.getBlockData()); 236 | firstDirectional.setFacing(chestFace); 237 | firstChest.setBlockData(firstDirectional); 238 | 239 | if (!singleChest) { 240 | // Get block on right (Previous cardinal) 241 | Block secondChest = getRightBlock(firstChest, chestFace); 242 | 243 | // Place chest and rotate 244 | secondChest.setType(Material.CHEST); 245 | Directional secondDirectional = ((Directional) secondChest.getBlockData()); 246 | secondDirectional.setFacing(chestFace); 247 | secondChest.setBlockData(secondDirectional); 248 | 249 | // Connect chests 250 | Chest firstChestType = ((Chest) firstChest.getBlockData()); 251 | Chest secondChestType = ((Chest) secondChest.getBlockData()); 252 | 253 | firstChestType.setType(Chest.Type.RIGHT); // Don't know why these are flipped 254 | secondChestType.setType(Chest.Type.LEFT); 255 | 256 | firstChest.setBlockData(firstChestType); 257 | secondChest.setBlockData(secondChestType); 258 | } 259 | } 260 | 261 | @Nonnull 262 | private Block getRightBlock(Block b, BlockFace face) { 263 | 264 | BlockFace rightFace; 265 | 266 | switch (face) { 267 | case NORTH: 268 | rightFace = BlockFace.WEST; 269 | break; 270 | case EAST: 271 | rightFace = BlockFace.NORTH; 272 | break; 273 | case SOUTH: 274 | rightFace = BlockFace.EAST; 275 | break; 276 | case WEST: 277 | rightFace = BlockFace.SOUTH; 278 | break; 279 | default: 280 | throw new IllegalStateException("Unexpected value: " + face); 281 | } 282 | 283 | return b.getRelative(rightFace); 284 | 285 | } 286 | 287 | private boolean isLockItem(@Nullable ItemStack lockItem) { 288 | return lockItem != null && (Utils.checkNonInteractable(lockItem) 289 | || lockItem.getItemMeta().hasCustomModelData() // Remnants of when I didn't know what PDC was 290 | && lockItem.getItemMeta().getCustomModelData() == 6969); // Leave in to maintain compatibility 291 | } 292 | 293 | } 294 | --------------------------------------------------------------------------------