From 7acee959ceb7a8d8c3cf5341560af1d6d148b4d1 Mon Sep 17 00:00:00 2001 From: TheBusyBiscuit Date: Wed, 10 Jun 2020 23:33:51 +0200 Subject: [PATCH] Lots of refactoring --- CHANGELOG.md | 2 + .../commands/subcommands/GiveCommand.java | 50 +- .../services/github/GitHubIssuesTracker.java | 8 +- .../core/services/github/GitHubTask.java | 86 +-- .../items/androids/Android.java | 490 ---------------- .../items/androids/FarmerAndroid.java | 11 +- .../items/androids/ProgrammableAndroid.java | 553 ++++++++++++++++-- .../electric/machines/WitherAssembler.java | 117 ++-- .../items/multiblocks/OreWasher.java | 61 +- .../items/tools/ExplosiveTool.java | 33 +- .../items/tools/PickaxeOfContainment.java | 53 +- .../items/tools/PickaxeOfVeinMining.java | 63 +- .../items/tools/SmeltersPickaxe.java | 35 +- .../items/weapons/SeismicAxe.java | 82 ++- .../listeners/SeismicAxeListener.java | 1 + .../implementation/setup/PostSetup.java | 48 +- .../utils/itemstack/ItemStackWrapper.java | 16 +- 17 files changed, 897 insertions(+), 812 deletions(-) delete mode 100644 src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/Android.java diff --git a/CHANGELOG.md b/CHANGELOG.md index b1421cd66..1b1e24a26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ * Added Advanced Industrial Miner * Added Cocoa Organic Food * Added Cocoa Fertilizer +* Added a configurable limit to the Pickaxe of Vein Mining #### Changes * Fixed a few memory leaks @@ -36,6 +37,7 @@ * Dried Kelp Blocks can now be used in the Coal Generator * Crafting Organic Food/Fertilizer yields more output now * Organic Food (Melon) now uses Melon Slices instead of Melon blocks +* The Seismic Axe now skips the first two blocks to clear your field of view #### Fixes * Fixed Ore Washer recipes showing up twice diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/GiveCommand.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/GiveCommand.java index 25f742ed0..6b7f2e91d 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/GiveCommand.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/GiveCommand.java @@ -47,29 +47,41 @@ class GiveCommand extends SubCommand { SlimefunItem sfItem = SlimefunItem.getByID(args[2].toUpperCase(Locale.ROOT)); if (sfItem != null) { - if (sfItem instanceof MultiBlockMachine) { - SlimefunPlugin.getLocal().sendMessage(sender, "guide.cheat.no-multiblocks"); - } - else { - int amount = parseAmount(args); - - if (amount > 0) { - SlimefunPlugin.getLocal().sendMessage(p, "messages.given-item", true, msg -> msg.replace(PLACEHOLDER_ITEM, sfItem.getItemName()).replace(PLACEHOLDER_AMOUNT, String.valueOf(amount))); - p.getInventory().addItem(new CustomItem(sfItem.getItem(), amount)); - SlimefunPlugin.getLocal().sendMessage(sender, "messages.give-item", true, msg -> msg.replace(PLACEHOLDER_PLAYER, args[1]).replace(PLACEHOLDER_ITEM, sfItem.getItemName()).replace(PLACEHOLDER_AMOUNT, String.valueOf(amount))); - } - else { - SlimefunPlugin.getLocal().sendMessage(sender, "messages.not-valid-amount", true, msg -> msg.replace(PLACEHOLDER_AMOUNT, args[3])); - } - } + giveItem(sender, p, sfItem, args); + } + else { + SlimefunPlugin.getLocal().sendMessage(sender, "messages.not-valid-item", true, msg -> msg.replace(PLACEHOLDER_ITEM, args[2])); } - else SlimefunPlugin.getLocal().sendMessage(sender, "messages.not-valid-item", true, msg -> msg.replace(PLACEHOLDER_ITEM, args[2])); } - else SlimefunPlugin.getLocal().sendMessage(sender, "messages.not-online", true, msg -> msg.replace(PLACEHOLDER_PLAYER, args[1])); + else { + SlimefunPlugin.getLocal().sendMessage(sender, "messages.not-online", true, msg -> msg.replace(PLACEHOLDER_PLAYER, args[1])); + } + } + else { + SlimefunPlugin.getLocal().sendMessage(sender, "messages.usage", true, msg -> msg.replace("%usage%", "/sf give [Amount]")); + } + } + else { + SlimefunPlugin.getLocal().sendMessage(sender, "messages.no-permission", true); + } + } + + private void giveItem(CommandSender sender, Player p, SlimefunItem sfItem, String[] args) { + if (sfItem instanceof MultiBlockMachine) { + SlimefunPlugin.getLocal().sendMessage(sender, "guide.cheat.no-multiblocks"); + } + else { + int amount = parseAmount(args); + + if (amount > 0) { + SlimefunPlugin.getLocal().sendMessage(p, "messages.given-item", true, msg -> msg.replace(PLACEHOLDER_ITEM, sfItem.getItemName()).replace(PLACEHOLDER_AMOUNT, String.valueOf(amount))); + p.getInventory().addItem(new CustomItem(sfItem.getItem(), amount)); + SlimefunPlugin.getLocal().sendMessage(sender, "messages.give-item", true, msg -> msg.replace(PLACEHOLDER_PLAYER, args[1]).replace(PLACEHOLDER_ITEM, sfItem.getItemName()).replace(PLACEHOLDER_AMOUNT, String.valueOf(amount))); + } + else { + SlimefunPlugin.getLocal().sendMessage(sender, "messages.not-valid-amount", true, msg -> msg.replace(PLACEHOLDER_AMOUNT, args[3])); } - else SlimefunPlugin.getLocal().sendMessage(sender, "messages.usage", true, msg -> msg.replace("%usage%", "/sf give [Amount]")); } - else SlimefunPlugin.getLocal().sendMessage(sender, "messages.no-permission", true); } private int parseAmount(String[] args) { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubIssuesTracker.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubIssuesTracker.java index 04394e768..9686d4e92 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubIssuesTracker.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubIssuesTracker.java @@ -35,8 +35,12 @@ class GitHubIssuesTracker extends GitHubConnector { for (JsonElement elem : array) { JsonObject obj = elem.getAsJsonObject(); - if (obj.has("pull_request")) pullRequests++; - else issues++; + if (obj.has("pull_request")) { + pullRequests++; + } + else { + issues++; + } } callback.update(issues, pullRequests); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubTask.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubTask.java index 80434f687..338360409 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubTask.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/github/GitHubTask.java @@ -45,52 +45,18 @@ class GitHubTask implements Runnable { // Store all queried usernames to prevent 429 responses for pinging the // same URL twice in one run. Map skins = new HashMap<>(); - int count = 0; + int requests = 0; for (Contributor contributor : gitHubService.getContributors().values()) { - if (!contributor.hasTexture()) { - try { - if (skins.containsKey(contributor.getMinecraftName())) { - contributor.setTexture(skins.get(contributor.getMinecraftName())); - } - else { - contributor.setTexture(grabTexture(skins, contributor)); + int newRequests = requestTexture(contributor, skins); + requests += newRequests; - count += contributor.getUniqueId().isPresent() ? 1 : 2; - - if (count >= MAX_REQUESTS_PER_MINUTE) { - break; - } - } - } - catch (IllegalArgumentException x) { - // There cannot be a texture found because it is not a valid MC username - contributor.setTexture(null); - } - catch (IOException x) { - // Too many requests - Slimefun.getLogger().log(Level.WARNING, "Attempted to connect to mojang.com, got this response: {0}: {1}", new Object[] { x.getClass().getSimpleName(), x.getMessage() }); - Slimefun.getLogger().log(Level.WARNING, "This usually means mojang.com is down or started to rate-limit this connection, this is not an error message!"); - - // Retry after 5 minutes if it was rate-limiting - if (x.getMessage().contains("429")) { - Bukkit.getScheduler().runTaskLaterAsynchronously(SlimefunPlugin.instance, this::grabTextures, 5 * 60 * 20L); - } - - count = 0; - break; - } - catch (TooManyRequestsException x) { - Slimefun.getLogger().log(Level.WARNING, "Received a rate-limit from mojang.com, retrying in 4 minutes"); - Bukkit.getScheduler().runTaskLaterAsynchronously(SlimefunPlugin.instance, this::grabTextures, 4 * 60 * 20L); - - count = 0; - break; - } + if (newRequests < 0 || requests >= MAX_REQUESTS_PER_MINUTE) { + break; } } - if (count >= MAX_REQUESTS_PER_MINUTE) { + if (requests >= MAX_REQUESTS_PER_MINUTE) { // Slow down API requests and wait a minute after more than x requests were made Bukkit.getScheduler().runTaskLaterAsynchronously(SlimefunPlugin.instance, this::grabTextures, 2 * 60 * 20L); } @@ -106,7 +72,45 @@ class GitHubTask implements Runnable { gitHubService.saveUUIDCache(); } - private String grabTexture(Map skins, Contributor contributor) throws TooManyRequestsException, IOException { + private int requestTexture(Contributor contributor, Map skins) { + if (!contributor.hasTexture()) { + try { + if (skins.containsKey(contributor.getMinecraftName())) { + contributor.setTexture(skins.get(contributor.getMinecraftName())); + } + else { + contributor.setTexture(pullTexture(skins, contributor)); + return contributor.getUniqueId().isPresent() ? 1 : 2; + } + } + catch (IllegalArgumentException x) { + // There cannot be a texture found because it is not a valid MC username + contributor.setTexture(null); + } + catch (IOException x) { + // Too many requests + Slimefun.getLogger().log(Level.WARNING, "Attempted to connect to mojang.com, got this response: {0}: {1}", new Object[] { x.getClass().getSimpleName(), x.getMessage() }); + Slimefun.getLogger().log(Level.WARNING, "This usually means mojang.com is down or started to rate-limit this connection, this is not an error message!"); + + // Retry after 5 minutes if it was rate-limiting + if (x.getMessage().contains("429")) { + Bukkit.getScheduler().runTaskLaterAsynchronously(SlimefunPlugin.instance, this::grabTextures, 5 * 60 * 20L); + } + + return -1; + } + catch (TooManyRequestsException x) { + Slimefun.getLogger().log(Level.WARNING, "Received a rate-limit from mojang.com, retrying in 4 minutes"); + Bukkit.getScheduler().runTaskLaterAsynchronously(SlimefunPlugin.instance, this::grabTextures, 4 * 60 * 20L); + + return -1; + } + } + + return 0; + } + + private String pullTexture(Map skins, Contributor contributor) throws TooManyRequestsException, IOException { Optional uuid = contributor.getUniqueId(); if (!uuid.isPresent()) { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/Android.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/Android.java deleted file mode 100644 index 0e21a58bc..000000000 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/Android.java +++ /dev/null @@ -1,490 +0,0 @@ -package io.github.thebusybiscuit.slimefun4.implementation.items.androids; - -import java.io.File; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.function.Predicate; - -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.OfflinePlayer; -import org.bukkit.Sound; -import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; - -import io.github.thebusybiscuit.cscorelib2.chat.ChatInput; -import io.github.thebusybiscuit.cscorelib2.config.Config; -import io.github.thebusybiscuit.cscorelib2.item.CustomItem; -import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils; -import io.github.thebusybiscuit.slimefun4.utils.PatternUtils; -import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; -import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu; -import me.mrCookieSlime.Slimefun.SlimefunPlugin; -import me.mrCookieSlime.Slimefun.Lists.RecipeType; -import me.mrCookieSlime.Slimefun.Objects.Category; -import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; -import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker; -import me.mrCookieSlime.Slimefun.api.BlockStorage; -import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; -import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu; - -abstract class Android extends SlimefunItem { - - public Android(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { - super(category, item, recipeType, recipe); - } - - /** - * This returns the {@link AndroidType} that is associated with this {@link ProgrammableAndroid}. - * - * @return The type of this {@link ProgrammableAndroid} - */ - public abstract AndroidType getAndroidType(); - - protected abstract void tick(Block b); - - @Override - public void preRegister() { - super.preRegister(); - - addItemHandler(new BlockTicker() { - - @Override - public void tick(Block b, SlimefunItem sf, me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config data) { - if (b != null) { - Android.this.tick(b); - } - } - - @Override - public boolean isSynchronized() { - return true; - } - }); - } - - protected void killEntities(Block b, double damage, Predicate predicate) { - throw new UnsupportedOperationException("Non-butcher Android tried to butcher!"); - } - - protected void fish(Block b, BlockMenu menu) { - throw new UnsupportedOperationException("Non-fishing Android tried to fish!"); - } - - protected void mine(Block b, BlockMenu menu, Block block) { - throw new UnsupportedOperationException("Non-mining Android tried to mine!"); - } - - protected void movedig(Block b, BlockMenu menu, BlockFace face, Block block) { - throw new UnsupportedOperationException("Non-mining Android tried to mine!"); - } - - protected boolean chopTree(Block b, BlockMenu menu, BlockFace face) { - throw new UnsupportedOperationException("Non-woodcutter Android tried to chop a Tree!"); - } - - protected void farm(BlockMenu menu, Block block) { - throw new UnsupportedOperationException("Non-farming Android tried to farm!"); - } - - protected void exoticFarm(BlockMenu menu, Block block) { - throw new UnsupportedOperationException("Non-farming Android tried to farm!"); - } - - public void openScript(Player p, Block b, String script) { - ChestMenu menu = new ChestMenu(ChatColor.DARK_AQUA + SlimefunPlugin.getLocal().getMessage(p, "android.scripts.editor")); - - menu.addItem(0, new CustomItem(ScriptAction.START.getItem(), SlimefunPlugin.getLocal().getMessage(p, "android.scripts.instructions.START"), "", "&7\u21E8 &eLeft Click &7to return to the Android's interface")); - menu.addMenuClickHandler(0, (pl, slot, item, action) -> { - BlockStorage.getInventory(b).open(pl); - return false; - }); - - String[] commands = PatternUtils.DASH.split(script); - - for (int i = 1; i < commands.length; i++) { - int index = i; - - if (i == commands.length - 1) { - int additional = commands.length == 54 ? 0 : 1; - - if (additional == 1) { - menu.addItem(i, new CustomItem(SlimefunUtils.getCustomHead("171d8979c1878a05987a7faf21b56d1b744f9d068c74cffcde1ea1edad5852"), "&7> Add new Command")); - menu.addMenuClickHandler(i, (pl, slot, item, action) -> { - openScriptComponentEditor(pl, b, script, index); - return false; - }); - } - - menu.addItem(i + additional, new CustomItem(ScriptAction.REPEAT.getItem(), SlimefunPlugin.getLocal().getMessage(p, "android.scripts.instructions.REPEAT"), "", "&7\u21E8 &eLeft Click &7to return to the Android's interface")); - menu.addMenuClickHandler(i + additional, (pl, slot, item, action) -> { - BlockStorage.getInventory(b).open(pl); - return false; - }); - } - else { - ItemStack stack = ScriptAction.valueOf(commands[i]).getItem(); - menu.addItem(i, new CustomItem(stack, SlimefunPlugin.getLocal().getMessage(p, "android.scripts.instructions." + ScriptAction.valueOf(commands[i]).name()), "", "&7\u21E8 &eLeft Click &7to edit", "&7\u21E8 &eRight Click &7to delete", "&7\u21E8 &eShift + Right Click &7to duplicate")); - menu.addMenuClickHandler(i, (pl, slot, item, action) -> { - if (action.isRightClicked() && action.isShiftClicked()) { - if (commands.length == 54) return false; - - int j = 0; - StringBuilder builder = new StringBuilder(ScriptAction.START + "-"); - - for (String command : commands) { - if (j > 0) { - if (j == index) { - builder.append(commands[j]).append('-').append(commands[j]).append('-'); - } - else if (j < commands.length - 1) builder.append(command).append('-'); - } - j++; - } - builder.append(ScriptAction.REPEAT); - setScript(b.getLocation(), builder.toString()); - openScript(pl, b, builder.toString()); - } - else if (action.isRightClicked()) { - int j = 0; - StringBuilder builder = new StringBuilder(ScriptAction.START + "-"); - - for (String command : commands) { - if (j != index && j > 0 && j < commands.length - 1) builder.append(command).append('-'); - j++; - } - - builder.append(ScriptAction.REPEAT); - setScript(b.getLocation(), builder.toString()); - - openScript(pl, b, builder.toString()); - } - else { - openScriptComponentEditor(pl, b, script, index); - } - return false; - }); - } - } - - menu.open(p); - } - - protected void openScriptDownloader(Player p, Block b, int page) { - ChestMenu menu = new ChestMenu("Android Scripts"); - menu.addMenuOpeningHandler(pl -> pl.playSound(pl.getLocation(), Sound.BLOCK_NOTE_BLOCK_HAT, 0.7F, 0.7F)); - - List scripts = getUploadedScripts(); - - int pages = (scripts.size() / 45) + 1; - - for (int i = 45; i < 54; i++) { - menu.addItem(i, new CustomItem(new ItemStack(Material.GRAY_STAINED_GLASS_PANE), " ")); - menu.addMenuClickHandler(i, (pl, slot, item, action) -> false); - } - - menu.addItem(46, new CustomItem(new ItemStack(Material.LIME_STAINED_GLASS_PANE), "&r\u21E6 Previous Page", "", "&7(" + page + " / " + pages + ")")); - menu.addMenuClickHandler(46, (pl, slot, item, action) -> { - int next = page - 1; - if (next < 1) next = pages; - if (next != page) { - openScriptDownloader(pl, b, next); - } - return false; - }); - - menu.addItem(48, new CustomItem(SlimefunUtils.getCustomHead("105a2cab8b68ea57e3af992a36e47c8ff9aa87cc8776281966f8c3cf31a38"), "&eUpload a Script", "", "&6Click &7to upload your Android's Script", "&7to the Database")); - menu.addMenuClickHandler(48, (pl, slot, item, action) -> { - uploadScript(pl, b, page); - return false; - }); - - menu.addItem(50, new CustomItem(new ItemStack(Material.LIME_STAINED_GLASS_PANE), "&rNext Page \u21E8", "", "&7(" + page + " / " + pages + ")")); - menu.addMenuClickHandler(50, (pl, slot, item, action) -> { - int next = page + 1; - if (next > pages) next = 1; - if (next != page) { - openScriptDownloader(pl, b, next); - } - return false; - }); - - menu.addItem(53, new CustomItem(SlimefunUtils.getCustomHead("185c97dbb8353de652698d24b64327b793a3f32a98be67b719fbedab35e"), "&6> Back", "", "&7Return to the Android's interface")); - menu.addMenuClickHandler(53, (pl, slot, item, action) -> { - openScriptEditor(pl, b); - return false; - }); - - int index = 0; - int categoryIndex = 45 * (page - 1); - - for (int i = 0; i < 45; i++) { - int target = categoryIndex + i; - - if (target >= scripts.size()) { - break; - } - else { - Config script = scripts.get(target); - - OfflinePlayer op = Bukkit.getOfflinePlayer(script.getUUID("author")); - String author = (op != null && op.getName() != null) ? op.getName() : script.getString("author_name"); - - if (script.getString("author").equals(p.getUniqueId().toString())) { - menu.addItem(index, new CustomItem(this.getItem(), "&b" + script.getString("name"), "&7by &r" + author, "", "&7Downloads: &r" + script.getInt("downloads"), "&7Rating: " + getScriptRatingPercentage(script), "&a" + getScriptRating(script, true) + " \u263A &7| &4\u2639 " + getScriptRating(script, false), "", "&eLeft Click &rto download this Script", "&4(This will override your current Script)")); - } - else { - menu.addItem(index, new CustomItem(this.getItem(), "&b" + script.getString("name"), "&7by &r" + author, "", "&7Downloads: &r" + script.getInt("downloads"), "&7Rating: " + getScriptRatingPercentage(script), "&a" + getScriptRating(script, true) + " \u263A &7| &4\u2639 " + getScriptRating(script, false), "", "&eLeft Click &rto download this Script", "&4(This will override your current Script)", "&eShift + Left Click &rto leave a positive Rating", "&eShift + Right Click &rto leave a negative Rating")); - } - - menu.addMenuClickHandler(index, (pl, slot, item, action) -> { - Config script2 = new Config(script.getFile()); - - if (action.isShiftClicked()) { - if (script2.getString("author").equals(pl.getUniqueId().toString())) { - SlimefunPlugin.getLocal().sendMessage(pl, "android.scripts.rating.own", true); - } - else if (action.isRightClicked()) { - if (!script2.getStringList("rating.negative").contains(pl.getUniqueId().toString()) && !script2.getStringList("rating.positive").contains(pl.getUniqueId().toString())) { - List list = script2.getStringList("rating.negative"); - list.add(p.getUniqueId().toString()); - - script2.setValue("rating.negative", list); - script2.save(); - - openScriptDownloader(pl, b, page); - } - else { - SlimefunPlugin.getLocal().sendMessage(pl, "android.scripts.rating.already", true); - } - } - else { - if (!script2.getStringList("rating.negative").contains(pl.getUniqueId().toString()) && !script2.getStringList("rating.positive").contains(pl.getUniqueId().toString())) { - List list = script2.getStringList("rating.positive"); - list.add(pl.getUniqueId().toString()); - - script2.setValue("rating.positive", list); - script2.save(); - - openScriptDownloader(pl, b, page); - } - else { - SlimefunPlugin.getLocal().sendMessage(pl, "android.scripts.rating.already", true); - } - } - } - else if (!action.isRightClicked()) { - script2.setValue("downloads", script2.getInt("downloads") + 1); - script2.save(); - - setScript(b.getLocation(), script2.getString("code")); - openScriptEditor(pl, b); - } - return false; - }); - - index++; - } - } - - menu.open(p); - } - - private void uploadScript(Player p, Block b, int page) { - String code = getScript(b.getLocation()); - int num = 1; - - for (Config script : getUploadedScripts()) { - if (script.getString("author").equals(p.getUniqueId().toString())) { - num++; - } - - if (script.getString("code").equals(code)) { - SlimefunPlugin.getLocal().sendMessage(p, "android.scripts.already-uploaded", true); - return; - } - } - - int id = num; - - p.closeInventory(); - SlimefunPlugin.getLocal().sendMessages(p, "android.scripts.enter-name"); - - ChatInput.waitForPlayer(SlimefunPlugin.instance, p, msg -> { - Config script = new Config("plugins/Slimefun/scripts/" + getAndroidType().toString() + '/' + p.getName() + ' ' + id + ".sfs"); - - script.setValue("author", p.getUniqueId().toString()); - script.setValue("author_name", p.getName()); - script.setValue("name", ChatColor.stripColor(ChatColor.translateAlternateColorCodes('&', msg))); - script.setValue("code", code); - script.setValue("downloads", 0); - script.setValue("android", getAndroidType().toString()); - script.setValue("rating.positive", new ArrayList()); - script.setValue("rating.negative", new ArrayList()); - script.save(); - - SlimefunPlugin.getLocal().sendMessages(p, "android.scripts.uploaded"); - openScriptDownloader(p, b, page); - }); - } - - public void openScriptEditor(Player p, Block b) { - ChestMenu menu = new ChestMenu(ChatColor.DARK_AQUA + SlimefunPlugin.getLocal().getMessage(p, "android.scripts.editor")); - - menu.addItem(1, new CustomItem(SlimefunUtils.getCustomHead("d9bf6db4aeda9d8822b9f736538e8c18b9a4844f84eb45504adfbfee87eb"), "&2> Edit Script", "", "&aEdits your current Script")); - menu.addMenuClickHandler(1, (pl, slot, item, action) -> { - openScript(pl, b, getScript(b.getLocation())); - return false; - }); - - menu.addItem(3, new CustomItem(SlimefunUtils.getCustomHead("171d8979c1878a05987a7faf21b56d1b744f9d068c74cffcde1ea1edad5852"), "&4> Create new Script", "", "&cDeletes your current Script", "&cand creates a blank one")); - menu.addMenuClickHandler(3, (pl, slot, item, action) -> { - openScript(pl, b, "START-TURN_LEFT-REPEAT"); - return false; - }); - - menu.addItem(5, new CustomItem(SlimefunUtils.getCustomHead("c01586e39f6ffa63b4fb301b65ca7da8a92f7353aaab89d3886579125dfbaf9"), "&6> Download a Script", "", "&eDownload a Script from the Server", "&eYou can edit or simply use it")); - menu.addMenuClickHandler(5, (pl, slot, item, action) -> { - openScriptDownloader(pl, b, 1); - return false; - }); - - menu.addItem(8, new CustomItem(SlimefunUtils.getCustomHead("a185c97dbb8353de652698d24b64327b793a3f32a98be67b719fbedab35e"), "&6> Back", "", "&7Return to the Android's interface")); - menu.addMenuClickHandler(8, (pl, slot, item, action) -> { - BlockStorage.getInventory(b).open(p); - return false; - }); - - menu.open(p); - } - - protected List getUploadedScripts() { - List scripts = new ArrayList<>(); - - File directory = new File("plugins/Slimefun/scripts/" + getAndroidType().toString()); - if (!directory.exists()) directory.mkdirs(); - - for (File script : directory.listFiles()) { - if (script.getName().endsWith("sfs")) { - scripts.add(new Config(script)); - } - } - - if (getAndroidType() != AndroidType.NONE) { - File mainDirectory = new File("plugins/Slimefun/scripts/NONE"); - if (!mainDirectory.exists()) mainDirectory.mkdirs(); - - for (File script : mainDirectory.listFiles()) { - if (script.getName().endsWith("sfs")) { - scripts.add(new Config(script)); - } - } - } - - Collections.sort(scripts, Comparator.comparingInt(script -> -(getScriptRating(script, true) + 1 - getScriptRating(script, false)))); - - return scripts; - } - - protected List getAccessibleScriptParts() { - List list = new ArrayList<>(); - - for (ScriptAction part : ScriptAction.values()) { - if (part != ScriptAction.START && part != ScriptAction.REPEAT && getAndroidType().isType(part.getRequiredType())) { - list.add(part); - } - } - - return list; - } - - protected float getScriptRating(Config script) { - int positive = getScriptRating(script, true) + 1; - int negative = getScriptRating(script, false); - return Math.round((positive / (double) (positive + negative)) * 100.0F) / 100.0F; - } - - protected int getScriptRating(Config script, boolean positive) { - if (positive) return script.getStringList("rating.positive").size(); - else return script.getStringList("rating.negative").size(); - } - - protected String getScriptRatingPercentage(Config script) { - String progress = String.valueOf(getScriptRating(script)); - if (Float.parseFloat(progress) < 16.0F) progress = "&4" + progress + "&r% "; - else if (Float.parseFloat(progress) < 32.0F) progress = "&c" + progress + "&r% "; - else if (Float.parseFloat(progress) < 48.0F) progress = "&6" + progress + "&r% "; - else if (Float.parseFloat(progress) < 64.0F) progress = "&e" + progress + "&r% "; - else if (Float.parseFloat(progress) < 80.0F) progress = "&2" + progress + "&r% "; - else progress = "&a" + progress + "&r% "; - - return progress; - } - - protected void openScriptComponentEditor(Player p, Block b, String script, int index) { - ChestMenu menu = new ChestMenu(ChatColor.DARK_AQUA + SlimefunPlugin.getLocal().getMessage(p, "android.scripts.editor")); - String[] commands = PatternUtils.DASH.split(script); - - ChestMenuUtils.drawBackground(menu, 0, 1, 2, 3, 4, 5, 6, 7, 8); - - menu.addItem(9, new CustomItem(SlimefunUtils.getCustomHead("16139fd1c5654e56e9e4e2c8be7eb2bd5b499d633616663feee99b74352ad64"), "&rDo nothing"), (pl, slot, item, action) -> { - int i = 0; - StringBuilder builder = new StringBuilder("START-"); - - for (String command : commands) { - if (i != index && i > 0 && i < commands.length - 1) builder.append(command).append('-'); - i++; - } - - builder.append("REPEAT"); - setScript(b.getLocation(), builder.toString()); - - openScript(p, b, builder.toString()); - return false; - }); - - int i = 10; - for (ScriptAction part : getAccessibleScriptParts()) { - menu.addItem(i, new CustomItem(part.getItem(), SlimefunPlugin.getLocal().getMessage(p, "android.scripts.instructions." + part.name())), (pl, slot, item, action) -> { - addInstruction(pl, b, index, part, commands); - return false; - }); - i++; - } - - menu.open(p); - } - - private void addInstruction(Player p, Block b, int index, ScriptAction part, String[] commands) { - int j = 0; - StringBuilder builder = new StringBuilder("START-"); - - for (String command : commands) { - if (j > 0) { - if (j == index) builder.append(part).append('-'); - else if (j < commands.length - 1) builder.append(command).append('-'); - } - j++; - } - - builder.append("REPEAT"); - setScript(b.getLocation(), builder.toString()); - - openScript(p, b, builder.toString()); - } - - protected String getScript(Location l) { - return BlockStorage.getLocationInfo(l, "script"); - } - - protected void setScript(Location l, String script) { - BlockStorage.addBlockInfo(l, "script", script); - } -} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/FarmerAndroid.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/FarmerAndroid.java index a66907c37..4b32d5239 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/FarmerAndroid.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/FarmerAndroid.java @@ -7,6 +7,7 @@ import org.bukkit.Effect; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.data.Ageable; +import org.bukkit.block.data.BlockData; import org.bukkit.inventory.ItemStack; import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion; @@ -28,9 +29,13 @@ public abstract class FarmerAndroid extends ProgrammableAndroid { } private boolean isFullGrown(Block block) { - if (!(block.getBlockData() instanceof Ageable)) return false; + BlockData data = block.getBlockData(); - Ageable ageable = ((Ageable) block.getBlockData()); + if (!(data instanceof Ageable)) { + return false; + } + + Ageable ageable = (Ageable) data; return ageable.getAge() >= ageable.getMaximumAge(); } @@ -51,7 +56,7 @@ public abstract class FarmerAndroid extends ProgrammableAndroid { private ItemStack getDropFromCrop(Material crop) { Random random = ThreadLocalRandom.current(); - + if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_14) && crop == Material.SWEET_BERRY_BUSH) { return new ItemStack(Material.SWEET_BERRIES, random.nextInt(3) + 1); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/ProgrammableAndroid.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/ProgrammableAndroid.java index a9c520293..04808c82d 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/ProgrammableAndroid.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/ProgrammableAndroid.java @@ -1,19 +1,29 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.androids; +import java.io.File; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.function.Predicate; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.OfflinePlayer; +import org.bukkit.Sound; import org.bukkit.Tag; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.Dispenser; import org.bukkit.block.data.Rotatable; import org.bukkit.entity.Animals; +import org.bukkit.entity.Entity; import org.bukkit.entity.Monster; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryClickEvent; @@ -22,6 +32,8 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import io.github.thebusybiscuit.cscorelib2.chat.ChatColors; +import io.github.thebusybiscuit.cscorelib2.chat.ChatInput; +import io.github.thebusybiscuit.cscorelib2.config.Config; import io.github.thebusybiscuit.cscorelib2.inventory.ItemUtils; import io.github.thebusybiscuit.cscorelib2.item.CustomItem; import io.github.thebusybiscuit.cscorelib2.skull.SkullBlock; @@ -30,6 +42,7 @@ import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils; import io.github.thebusybiscuit.slimefun4.utils.NumberUtils; import io.github.thebusybiscuit.slimefun4.utils.PatternUtils; import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; +import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu; import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu.AdvancedMenuClickHandler; import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ClickAction; import me.mrCookieSlime.Slimefun.SlimefunPlugin; @@ -41,25 +54,26 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.UnregisterReason; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineFuel; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.interfaces.InventoryBlock; +import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker; import me.mrCookieSlime.Slimefun.api.BlockStorage; import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu; import me.mrCookieSlime.Slimefun.api.inventory.BlockMenuPreset; import me.mrCookieSlime.Slimefun.api.item_transport.ItemTransportFlow; -public abstract class ProgrammableAndroid extends Android implements InventoryBlock, RecipeDisplayItem { +public abstract class ProgrammableAndroid extends SlimefunItem implements InventoryBlock, RecipeDisplayItem { - private static final int[] border = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 18, 24, 25, 26, 27, 33, 35, 36, 42, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53 }; - private static final int[] border_out = { 10, 11, 12, 13, 14, 19, 23, 28, 32, 37, 38, 39, 40, 41 }; + private static final List POSSIBLE_ROTATIONS = Arrays.asList(BlockFace.NORTH, BlockFace.EAST, BlockFace.SOUTH, BlockFace.WEST); + private static final int[] BORDER = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 18, 24, 25, 26, 27, 33, 35, 36, 42, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53 }; + private static final int[] OUTPUT_BORDER = { 10, 11, 12, 13, 14, 19, 23, 28, 32, 37, 38, 39, 40, 41 }; - protected final List directions = Arrays.asList(BlockFace.NORTH, BlockFace.EAST, BlockFace.SOUTH, BlockFace.WEST); - protected final Set recipes = new HashSet<>(); + protected final Set fuelTypes = new HashSet<>(); protected final String texture; public ProgrammableAndroid(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { super(category, item, recipeType, recipe); - this.texture = item.getSkullTexture().orElse(null); + texture = item.getSkullTexture().orElse(null); registerDefaultFuelTypes(); new BlockMenuPreset(getID(), "Programmable Android") { @@ -156,34 +170,451 @@ public abstract class ProgrammableAndroid extends Android implements InventoryBl }); } + /** + * This returns the {@link AndroidType} that is associated with this {@link ProgrammableAndroid}. + * + * @return The type of this {@link ProgrammableAndroid} + */ + public abstract AndroidType getAndroidType(); + + @Override + public void preRegister() { + super.preRegister(); + + addItemHandler(new BlockTicker() { + + @Override + public void tick(Block b, SlimefunItem item, me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config data) { + if (b != null) { + ProgrammableAndroid.this.tick(b); + } + } + + @Override + public boolean isSynchronized() { + return true; + } + }); + } + + public void openScript(Player p, Block b, String script) { + ChestMenu menu = new ChestMenu(ChatColor.DARK_AQUA + SlimefunPlugin.getLocal().getMessage(p, "android.scripts.editor")); + + menu.addItem(0, new CustomItem(ScriptAction.START.getItem(), SlimefunPlugin.getLocal().getMessage(p, "android.scripts.instructions.START"), "", "&7\u21E8 &eLeft Click &7to return to the Android's interface")); + menu.addMenuClickHandler(0, (pl, slot, item, action) -> { + BlockStorage.getInventory(b).open(pl); + return false; + }); + + String[] commands = PatternUtils.DASH.split(script); + + for (int i = 1; i < commands.length; i++) { + int index = i; + + if (i == commands.length - 1) { + int additional = commands.length == 54 ? 0 : 1; + + if (additional == 1) { + menu.addItem(i, new CustomItem(SlimefunUtils.getCustomHead("171d8979c1878a05987a7faf21b56d1b744f9d068c74cffcde1ea1edad5852"), "&7> Add new Command")); + menu.addMenuClickHandler(i, (pl, slot, item, action) -> { + openScriptComponentEditor(pl, b, script, index); + return false; + }); + } + + menu.addItem(i + additional, new CustomItem(ScriptAction.REPEAT.getItem(), SlimefunPlugin.getLocal().getMessage(p, "android.scripts.instructions.REPEAT"), "", "&7\u21E8 &eLeft Click &7to return to the Android's interface")); + menu.addMenuClickHandler(i + additional, (pl, slot, item, action) -> { + BlockStorage.getInventory(b).open(pl); + return false; + }); + } + else { + ItemStack stack = ScriptAction.valueOf(commands[i]).getItem(); + menu.addItem(i, new CustomItem(stack, SlimefunPlugin.getLocal().getMessage(p, "android.scripts.instructions." + ScriptAction.valueOf(commands[i]).name()), "", "&7\u21E8 &eLeft Click &7to edit", "&7\u21E8 &eRight Click &7to delete", "&7\u21E8 &eShift + Right Click &7to duplicate")); + menu.addMenuClickHandler(i, (pl, slot, item, action) -> { + if (action.isRightClicked() && action.isShiftClicked()) { + if (commands.length == 54) return false; + + int j = 0; + StringBuilder builder = new StringBuilder(ScriptAction.START + "-"); + + for (String command : commands) { + if (j > 0) { + if (j == index) { + builder.append(commands[j]).append('-').append(commands[j]).append('-'); + } + else if (j < commands.length - 1) builder.append(command).append('-'); + } + j++; + } + builder.append(ScriptAction.REPEAT); + setScript(b.getLocation(), builder.toString()); + openScript(pl, b, builder.toString()); + } + else if (action.isRightClicked()) { + int j = 0; + StringBuilder builder = new StringBuilder(ScriptAction.START + "-"); + + for (String command : commands) { + if (j != index && j > 0 && j < commands.length - 1) builder.append(command).append('-'); + j++; + } + + builder.append(ScriptAction.REPEAT); + setScript(b.getLocation(), builder.toString()); + + openScript(pl, b, builder.toString()); + } + else { + openScriptComponentEditor(pl, b, script, index); + } + return false; + }); + } + } + + menu.open(p); + } + + protected void openScriptDownloader(Player p, Block b, int page) { + ChestMenu menu = new ChestMenu("Android Scripts"); + menu.addMenuOpeningHandler(pl -> pl.playSound(pl.getLocation(), Sound.BLOCK_NOTE_BLOCK_HAT, 0.7F, 0.7F)); + + List scripts = getUploadedScripts(); + + int pages = (scripts.size() / 45) + 1; + + for (int i = 45; i < 54; i++) { + menu.addItem(i, new CustomItem(new ItemStack(Material.GRAY_STAINED_GLASS_PANE), " ")); + menu.addMenuClickHandler(i, (pl, slot, item, action) -> false); + } + + menu.addItem(46, new CustomItem(new ItemStack(Material.LIME_STAINED_GLASS_PANE), "&r\u21E6 Previous Page", "", "&7(" + page + " / " + pages + ")")); + menu.addMenuClickHandler(46, (pl, slot, item, action) -> { + int next = page - 1; + if (next < 1) next = pages; + if (next != page) { + openScriptDownloader(pl, b, next); + } + return false; + }); + + menu.addItem(48, new CustomItem(SlimefunUtils.getCustomHead("105a2cab8b68ea57e3af992a36e47c8ff9aa87cc8776281966f8c3cf31a38"), "&eUpload a Script", "", "&6Click &7to upload your Android's Script", "&7to the Database")); + menu.addMenuClickHandler(48, (pl, slot, item, action) -> { + uploadScript(pl, b, page); + return false; + }); + + menu.addItem(50, new CustomItem(new ItemStack(Material.LIME_STAINED_GLASS_PANE), "&rNext Page \u21E8", "", "&7(" + page + " / " + pages + ")")); + menu.addMenuClickHandler(50, (pl, slot, item, action) -> { + int next = page + 1; + if (next > pages) next = 1; + if (next != page) { + openScriptDownloader(pl, b, next); + } + return false; + }); + + menu.addItem(53, new CustomItem(SlimefunUtils.getCustomHead("185c97dbb8353de652698d24b64327b793a3f32a98be67b719fbedab35e"), "&6> Back", "", "&7Return to the Android's interface")); + menu.addMenuClickHandler(53, (pl, slot, item, action) -> { + openScriptEditor(pl, b); + return false; + }); + + int index = 0; + int categoryIndex = 45 * (page - 1); + + for (int i = 0; i < 45; i++) { + int target = categoryIndex + i; + + if (target >= scripts.size()) { + break; + } + else { + Config script = scripts.get(target); + + OfflinePlayer op = Bukkit.getOfflinePlayer(script.getUUID("author")); + String author = (op != null && op.getName() != null) ? op.getName() : script.getString("author_name"); + + if (script.getString("author").equals(p.getUniqueId().toString())) { + menu.addItem(index, new CustomItem(this.getItem(), "&b" + script.getString("name"), "&7by &r" + author, "", "&7Downloads: &r" + script.getInt("downloads"), "&7Rating: " + getScriptRatingPercentage(script), "&a" + getScriptRating(script, true) + " \u263A &7| &4\u2639 " + getScriptRating(script, false), "", "&eLeft Click &rto download this Script", "&4(This will override your current Script)")); + } + else { + menu.addItem(index, new CustomItem(this.getItem(), "&b" + script.getString("name"), "&7by &r" + author, "", "&7Downloads: &r" + script.getInt("downloads"), "&7Rating: " + getScriptRatingPercentage(script), "&a" + getScriptRating(script, true) + " \u263A &7| &4\u2639 " + getScriptRating(script, false), "", "&eLeft Click &rto download this Script", "&4(This will override your current Script)", "&eShift + Left Click &rto leave a positive Rating", "&eShift + Right Click &rto leave a negative Rating")); + } + + menu.addMenuClickHandler(index, (pl, slot, item, action) -> { + Config script2 = new Config(script.getFile()); + + if (action.isShiftClicked()) { + if (script2.getString("author").equals(pl.getUniqueId().toString())) { + SlimefunPlugin.getLocal().sendMessage(pl, "android.scripts.rating.own", true); + } + else if (action.isRightClicked()) { + if (!script2.getStringList("rating.negative").contains(pl.getUniqueId().toString()) && !script2.getStringList("rating.positive").contains(pl.getUniqueId().toString())) { + List list = script2.getStringList("rating.negative"); + list.add(p.getUniqueId().toString()); + + script2.setValue("rating.negative", list); + script2.save(); + + openScriptDownloader(pl, b, page); + } + else { + SlimefunPlugin.getLocal().sendMessage(pl, "android.scripts.rating.already", true); + } + } + else { + if (!script2.getStringList("rating.negative").contains(pl.getUniqueId().toString()) && !script2.getStringList("rating.positive").contains(pl.getUniqueId().toString())) { + List list = script2.getStringList("rating.positive"); + list.add(pl.getUniqueId().toString()); + + script2.setValue("rating.positive", list); + script2.save(); + + openScriptDownloader(pl, b, page); + } + else { + SlimefunPlugin.getLocal().sendMessage(pl, "android.scripts.rating.already", true); + } + } + } + else if (!action.isRightClicked()) { + script2.setValue("downloads", script2.getInt("downloads") + 1); + script2.save(); + + setScript(b.getLocation(), script2.getString("code")); + openScriptEditor(pl, b); + } + return false; + }); + + index++; + } + } + + menu.open(p); + } + + private void uploadScript(Player p, Block b, int page) { + String code = getScript(b.getLocation()); + int num = 1; + + for (Config script : getUploadedScripts()) { + if (script.getString("author").equals(p.getUniqueId().toString())) { + num++; + } + + if (script.getString("code").equals(code)) { + SlimefunPlugin.getLocal().sendMessage(p, "android.scripts.already-uploaded", true); + return; + } + } + + int id = num; + + p.closeInventory(); + SlimefunPlugin.getLocal().sendMessages(p, "android.scripts.enter-name"); + + ChatInput.waitForPlayer(SlimefunPlugin.instance, p, msg -> { + Config script = new Config("plugins/Slimefun/scripts/" + getAndroidType().toString() + '/' + p.getName() + ' ' + id + ".sfs"); + + script.setValue("author", p.getUniqueId().toString()); + script.setValue("author_name", p.getName()); + script.setValue("name", ChatColor.stripColor(ChatColor.translateAlternateColorCodes('&', msg))); + script.setValue("code", code); + script.setValue("downloads", 0); + script.setValue("android", getAndroidType().toString()); + script.setValue("rating.positive", new ArrayList()); + script.setValue("rating.negative", new ArrayList()); + script.save(); + + SlimefunPlugin.getLocal().sendMessages(p, "android.scripts.uploaded"); + openScriptDownloader(p, b, page); + }); + } + + public void openScriptEditor(Player p, Block b) { + ChestMenu menu = new ChestMenu(ChatColor.DARK_AQUA + SlimefunPlugin.getLocal().getMessage(p, "android.scripts.editor")); + + menu.addItem(1, new CustomItem(SlimefunUtils.getCustomHead("d9bf6db4aeda9d8822b9f736538e8c18b9a4844f84eb45504adfbfee87eb"), "&2> Edit Script", "", "&aEdits your current Script")); + menu.addMenuClickHandler(1, (pl, slot, item, action) -> { + openScript(pl, b, getScript(b.getLocation())); + return false; + }); + + menu.addItem(3, new CustomItem(SlimefunUtils.getCustomHead("171d8979c1878a05987a7faf21b56d1b744f9d068c74cffcde1ea1edad5852"), "&4> Create new Script", "", "&cDeletes your current Script", "&cand creates a blank one")); + menu.addMenuClickHandler(3, (pl, slot, item, action) -> { + openScript(pl, b, "START-TURN_LEFT-REPEAT"); + return false; + }); + + menu.addItem(5, new CustomItem(SlimefunUtils.getCustomHead("c01586e39f6ffa63b4fb301b65ca7da8a92f7353aaab89d3886579125dfbaf9"), "&6> Download a Script", "", "&eDownload a Script from the Server", "&eYou can edit or simply use it")); + menu.addMenuClickHandler(5, (pl, slot, item, action) -> { + openScriptDownloader(pl, b, 1); + return false; + }); + + menu.addItem(8, new CustomItem(SlimefunUtils.getCustomHead("a185c97dbb8353de652698d24b64327b793a3f32a98be67b719fbedab35e"), "&6> Back", "", "&7Return to the Android's interface")); + menu.addMenuClickHandler(8, (pl, slot, item, action) -> { + BlockStorage.getInventory(b).open(p); + return false; + }); + + menu.open(p); + } + + protected List getUploadedScripts() { + List scripts = new ArrayList<>(); + + File directory = new File("plugins/Slimefun/scripts/" + getAndroidType().toString()); + if (!directory.exists()) directory.mkdirs(); + + for (File script : directory.listFiles()) { + if (script.getName().endsWith("sfs")) { + scripts.add(new Config(script)); + } + } + + if (getAndroidType() != AndroidType.NONE) { + File mainDirectory = new File("plugins/Slimefun/scripts/NONE"); + if (!mainDirectory.exists()) mainDirectory.mkdirs(); + + for (File script : mainDirectory.listFiles()) { + if (script.getName().endsWith("sfs")) { + scripts.add(new Config(script)); + } + } + } + + Collections.sort(scripts, Comparator.comparingInt(script -> -(getScriptRating(script, true) + 1 - getScriptRating(script, false)))); + + return scripts; + } + + protected List getAccessibleScriptParts() { + List list = new ArrayList<>(); + + for (ScriptAction part : ScriptAction.values()) { + if (part != ScriptAction.START && part != ScriptAction.REPEAT && getAndroidType().isType(part.getRequiredType())) { + list.add(part); + } + } + + return list; + } + + protected float getScriptRating(Config script) { + int positive = getScriptRating(script, true) + 1; + int negative = getScriptRating(script, false); + return Math.round((positive / (double) (positive + negative)) * 100.0F) / 100.0F; + } + + protected int getScriptRating(Config script, boolean positive) { + if (positive) return script.getStringList("rating.positive").size(); + else return script.getStringList("rating.negative").size(); + } + + protected String getScriptRatingPercentage(Config script) { + String progress = String.valueOf(getScriptRating(script)); + if (Float.parseFloat(progress) < 16.0F) progress = "&4" + progress + "&r% "; + else if (Float.parseFloat(progress) < 32.0F) progress = "&c" + progress + "&r% "; + else if (Float.parseFloat(progress) < 48.0F) progress = "&6" + progress + "&r% "; + else if (Float.parseFloat(progress) < 64.0F) progress = "&e" + progress + "&r% "; + else if (Float.parseFloat(progress) < 80.0F) progress = "&2" + progress + "&r% "; + else progress = "&a" + progress + "&r% "; + + return progress; + } + + protected void openScriptComponentEditor(Player p, Block b, String script, int index) { + ChestMenu menu = new ChestMenu(ChatColor.DARK_AQUA + SlimefunPlugin.getLocal().getMessage(p, "android.scripts.editor")); + String[] commands = PatternUtils.DASH.split(script); + + ChestMenuUtils.drawBackground(menu, 0, 1, 2, 3, 4, 5, 6, 7, 8); + + menu.addItem(9, new CustomItem(SlimefunUtils.getCustomHead("16139fd1c5654e56e9e4e2c8be7eb2bd5b499d633616663feee99b74352ad64"), "&rDo nothing"), (pl, slot, item, action) -> { + int i = 0; + StringBuilder builder = new StringBuilder("START-"); + + for (String command : commands) { + if (i != index && i > 0 && i < commands.length - 1) builder.append(command).append('-'); + i++; + } + + builder.append("REPEAT"); + setScript(b.getLocation(), builder.toString()); + + openScript(p, b, builder.toString()); + return false; + }); + + int i = 10; + for (ScriptAction part : getAccessibleScriptParts()) { + menu.addItem(i, new CustomItem(part.getItem(), SlimefunPlugin.getLocal().getMessage(p, "android.scripts.instructions." + part.name())), (pl, slot, item, action) -> { + addInstruction(pl, b, index, part, commands); + return false; + }); + i++; + } + + menu.open(p); + } + + private void addInstruction(Player p, Block b, int index, ScriptAction part, String[] commands) { + int j = 0; + StringBuilder builder = new StringBuilder("START-"); + + for (String command : commands) { + if (j > 0) { + if (j == index) builder.append(part).append('-'); + else if (j < commands.length - 1) builder.append(command).append('-'); + } + j++; + } + + builder.append("REPEAT"); + setScript(b.getLocation(), builder.toString()); + + openScript(p, b, builder.toString()); + } + + protected String getScript(Location l) { + return BlockStorage.getLocationInfo(l, "script"); + } + + protected void setScript(Location l, String script) { + BlockStorage.addBlockInfo(l, "script", script); + } + private void registerDefaultFuelTypes() { if (getTier() == 1) { - registerFuel(new MachineFuel(800, new ItemStack(Material.COAL_BLOCK))); - registerFuel(new MachineFuel(45, new ItemStack(Material.BLAZE_ROD))); + registerFuelType(new MachineFuel(800, new ItemStack(Material.COAL_BLOCK))); + registerFuelType(new MachineFuel(45, new ItemStack(Material.BLAZE_ROD))); // Coal & Charcoal - registerFuel(new MachineFuel(8, new ItemStack(Material.COAL))); - registerFuel(new MachineFuel(8, new ItemStack(Material.CHARCOAL))); + registerFuelType(new MachineFuel(8, new ItemStack(Material.COAL))); + registerFuelType(new MachineFuel(8, new ItemStack(Material.CHARCOAL))); // Logs for (Material mat : Tag.LOGS.getValues()) { - registerFuel(new MachineFuel(2, new ItemStack(mat))); + registerFuelType(new MachineFuel(2, new ItemStack(mat))); } // Wooden Planks for (Material mat : Tag.PLANKS.getValues()) { - registerFuel(new MachineFuel(1, new ItemStack(mat))); + registerFuelType(new MachineFuel(1, new ItemStack(mat))); } } else if (getTier() == 2) { - registerFuel(new MachineFuel(100, new ItemStack(Material.LAVA_BUCKET))); - registerFuel(new MachineFuel(200, SlimefunItems.BUCKET_OF_OIL)); - registerFuel(new MachineFuel(500, SlimefunItems.BUCKET_OF_FUEL)); + registerFuelType(new MachineFuel(100, new ItemStack(Material.LAVA_BUCKET))); + registerFuelType(new MachineFuel(200, SlimefunItems.BUCKET_OF_OIL)); + registerFuelType(new MachineFuel(500, SlimefunItems.BUCKET_OF_FUEL)); } else { - registerFuel(new MachineFuel(2500, SlimefunItems.URANIUM)); - registerFuel(new MachineFuel(1200, SlimefunItems.NEPTUNIUM)); - registerFuel(new MachineFuel(3000, SlimefunItems.BOOSTED_URANIUM)); + registerFuelType(new MachineFuel(2500, SlimefunItems.URANIUM)); + registerFuelType(new MachineFuel(1200, SlimefunItems.NEPTUNIUM)); + registerFuelType(new MachineFuel(3000, SlimefunItems.BOOSTED_URANIUM)); } } @@ -196,7 +627,7 @@ public abstract class ProgrammableAndroid extends Android implements InventoryBl public List getDisplayRecipes() { List list = new ArrayList<>(); - for (MachineFuel fuel : recipes) { + for (MachineFuel fuel : fuelTypes) { ItemStack item = fuel.getInput().clone(); ItemMeta im = item.getItemMeta(); List lore = new ArrayList<>(); @@ -219,8 +650,6 @@ public abstract class ProgrammableAndroid extends Android implements InventoryBl return new int[] { 20, 21, 22, 29, 30, 31 }; } - public abstract AndroidType getAndroidType(); - public abstract float getFuelEfficiency(); public abstract int getTier(); @@ -266,23 +695,23 @@ public abstract class ProgrammableAndroid extends Android implements InventoryBl BlockStorage.addBlockInfo(b, "index", String.valueOf(0)); break; case TURN_LEFT: - int indexLeft = directions.indexOf(BlockFace.valueOf(BlockStorage.getLocationInfo(b.getLocation(), "rotation"))) - 1; - if (indexLeft < 0) indexLeft = directions.size() - 1; + int indexLeft = POSSIBLE_ROTATIONS.indexOf(BlockFace.valueOf(BlockStorage.getLocationInfo(b.getLocation(), "rotation"))) - 1; + if (indexLeft < 0) indexLeft = POSSIBLE_ROTATIONS.size() - 1; Rotatable rotatableLeft = (Rotatable) b.getBlockData(); - rotatableLeft.setRotation(directions.get(indexLeft)); + rotatableLeft.setRotation(POSSIBLE_ROTATIONS.get(indexLeft)); b.setBlockData(rotatableLeft); - BlockStorage.addBlockInfo(b, "rotation", directions.get(indexLeft).toString()); + BlockStorage.addBlockInfo(b, "rotation", POSSIBLE_ROTATIONS.get(indexLeft).toString()); break; case TURN_RIGHT: - int indexRight = directions.indexOf(BlockFace.valueOf(BlockStorage.getLocationInfo(b.getLocation(), "rotation"))) + 1; - if (indexRight == directions.size()) indexRight = 0; + int indexRight = POSSIBLE_ROTATIONS.indexOf(BlockFace.valueOf(BlockStorage.getLocationInfo(b.getLocation(), "rotation"))) + 1; + if (indexRight == POSSIBLE_ROTATIONS.size()) indexRight = 0; Rotatable rotatableRight = (Rotatable) b.getBlockData(); - rotatableRight.setRotation(directions.get(indexRight)); + rotatableRight.setRotation(POSSIBLE_ROTATIONS.get(indexRight)); b.setBlockData(rotatableRight); - BlockStorage.addBlockInfo(b, "rotation", directions.get(indexRight).toString()); + BlockStorage.addBlockInfo(b, "rotation", POSSIBLE_ROTATIONS.get(indexRight).toString()); break; case DIG_FORWARD: @@ -375,7 +804,7 @@ public abstract class ProgrammableAndroid extends Android implements InventoryBl ItemStack item = menu.getItemInSlot(43); if (item != null) { - for (MachineFuel fuel : recipes) { + for (MachineFuel fuel : fuelTypes) { if (fuel.test(item)) { menu.consumeItem(43); @@ -425,25 +854,11 @@ public abstract class ProgrammableAndroid extends Android implements InventoryBl return false; } - protected void move(Block b, BlockFace face, Block block) { - if (block.getY() > 0 && block.getY() < block.getWorld().getMaxHeight() && (block.getType() == Material.AIR || block.getType() == Material.CAVE_AIR)) { - block.setType(Material.PLAYER_HEAD); - Rotatable blockData = (Rotatable) block.getBlockData(); - blockData.setRotation(face.getOppositeFace()); - block.setBlockData(blockData); - - SkullBlock.setFromBase64(block, texture); - - b.setType(Material.AIR); - BlockStorage.moveBlockInfo(b.getLocation(), block.getLocation()); - } - } - private void constructMenu(BlockMenuPreset preset) { - for (int i : border) { + for (int i : BORDER) { preset.addItem(i, new CustomItem(new ItemStack(Material.GRAY_STAINED_GLASS_PANE), " "), ChestMenuUtils.getEmptyClickHandler()); } - for (int i : border_out) { + for (int i : OUTPUT_BORDER) { preset.addItem(i, new CustomItem(new ItemStack(Material.ORANGE_STAINED_GLASS_PANE), " "), ChestMenuUtils.getEmptyClickHandler()); } @@ -483,8 +898,50 @@ public abstract class ProgrammableAndroid extends Android implements InventoryBl } } - public void registerFuel(MachineFuel fuel) { - this.recipes.add(fuel); + public void registerFuelType(MachineFuel fuel) { + fuelTypes.add(fuel); + } + + protected void move(Block b, BlockFace face, Block block) { + if (block.getY() > 0 && block.getY() < block.getWorld().getMaxHeight() && (block.getType() == Material.AIR || block.getType() == Material.CAVE_AIR)) { + block.setType(Material.PLAYER_HEAD); + Rotatable blockData = (Rotatable) block.getBlockData(); + blockData.setRotation(face.getOppositeFace()); + block.setBlockData(blockData); + + SkullBlock.setFromBase64(block, texture); + + b.setType(Material.AIR); + BlockStorage.moveBlockInfo(b.getLocation(), block.getLocation()); + } + } + + protected void killEntities(Block b, double damage, Predicate predicate) { + throw new UnsupportedOperationException("Non-butcher Android tried to butcher!"); + } + + protected void fish(Block b, BlockMenu menu) { + throw new UnsupportedOperationException("Non-fishing Android tried to fish!"); + } + + protected void mine(Block b, BlockMenu menu, Block block) { + throw new UnsupportedOperationException("Non-mining Android tried to mine!"); + } + + protected void movedig(Block b, BlockMenu menu, BlockFace face, Block block) { + throw new UnsupportedOperationException("Non-mining Android tried to mine!"); + } + + protected boolean chopTree(Block b, BlockMenu menu, BlockFace face) { + throw new UnsupportedOperationException("Non-woodcutter Android tried to chop a Tree!"); + } + + protected void farm(BlockMenu menu, Block block) { + throw new UnsupportedOperationException("Non-farming Android tried to farm!"); + } + + protected void exoticFarm(BlockMenu menu, Block block) { + throw new UnsupportedOperationException("Non-farming Android tried to farm!"); } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/WitherAssembler.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/WitherAssembler.java index a4ed4a4ed..72175f602 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/WitherAssembler.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/WitherAssembler.java @@ -190,68 +190,18 @@ public class WitherAssembler extends SimpleSlimefunItem implements @Override public void tick(Block b, SlimefunItem sf, Config data) { - if (BlockStorage.getLocationInfo(b.getLocation(), "enabled").equals("false")) return; - - if (lifetime % 60 == 0) { - if (ChargableBlock.getCharge(b) < ENERGY_CONSUMPTION) return; - - int soulsand = 0; - int skulls = 0; + if ("false".equals(BlockStorage.getLocationInfo(b.getLocation(), "enabled"))) { + return; + } + if (lifetime % 60 == 0 && ChargableBlock.getCharge(b) >= ENERGY_CONSUMPTION) { BlockMenu menu = BlockStorage.getInventory(b); - for (int slot : getSoulSandSlots()) { - if (SlimefunUtils.isItemSimilar(menu.getItemInSlot(slot), new ItemStack(Material.SOUL_SAND), true)) { - soulsand = soulsand + menu.getItemInSlot(slot).getAmount(); + boolean soulsand = findResource(menu, Material.SOUL_SAND, 4, getSoulSandSlots()); + boolean skulls = findResource(menu, Material.WITHER_SKELETON_SKULL, 3, getWitherSkullSlots()); - if (soulsand > 3) { - soulsand = 4; - break; - } - } - } - - for (int slot : getWitherSkullSlots()) { - if (SlimefunUtils.isItemSimilar(menu.getItemInSlot(slot), new ItemStack(Material.WITHER_SKELETON_SKULL), true)) { - skulls = skulls + menu.getItemInSlot(slot).getAmount(); - - if (skulls > 2) { - skulls = 3; - break; - } - } - } - - if (soulsand > 3 && skulls > 2) { - for (int slot : getSoulSandSlots()) { - if (SlimefunUtils.isItemSimilar(menu.getItemInSlot(slot), new ItemStack(Material.SOUL_SAND), true)) { - int amount = menu.getItemInSlot(slot).getAmount(); - - if (amount >= soulsand) { - menu.consumeItem(slot, soulsand); - break; - } - else { - soulsand = soulsand - amount; - menu.replaceExistingItem(slot, null); - } - } - } - - for (int slot : getWitherSkullSlots()) { - if (SlimefunUtils.isItemSimilar(menu.getItemInSlot(slot), new ItemStack(Material.WITHER_SKELETON_SKULL), true)) { - int amount = menu.getItemInSlot(slot).getAmount(); - - if (amount >= skulls) { - menu.consumeItem(slot, skulls); - break; - } - else { - skulls = skulls - amount; - menu.replaceExistingItem(slot, null); - } - } - } + if (soulsand && skulls) { + consumeResources(menu); ChargableBlock.addCharge(b, -ENERGY_CONSUMPTION); double offset = Double.parseDouble(BlockStorage.getLocationInfo(b.getLocation(), "offset")); @@ -273,4 +223,55 @@ public class WitherAssembler extends SimpleSlimefunItem implements }; } + private boolean findResource(BlockMenu menu, Material resource, int required, int[] slots) { + int found = 0; + + for (int slot : slots) { + if (SlimefunUtils.isItemSimilar(menu.getItemInSlot(slot), new ItemStack(resource), true)) { + found += menu.getItemInSlot(slot).getAmount(); + + if (found > required) { + return true; + } + } + } + + return false; + } + + private void consumeResources(BlockMenu inv) { + int soulsand = 4; + int skulls = 3; + + for (int slot : getSoulSandSlots()) { + if (SlimefunUtils.isItemSimilar(inv.getItemInSlot(slot), new ItemStack(Material.SOUL_SAND), true)) { + int amount = inv.getItemInSlot(slot).getAmount(); + + if (amount >= soulsand) { + inv.consumeItem(slot, soulsand); + break; + } + else { + soulsand -= amount; + inv.replaceExistingItem(slot, null); + } + } + } + + for (int slot : getWitherSkullSlots()) { + if (SlimefunUtils.isItemSimilar(inv.getItemInSlot(slot), new ItemStack(Material.WITHER_SKELETON_SKULL), true)) { + int amount = inv.getItemInSlot(slot).getAmount(); + + if (amount >= skulls) { + inv.consumeItem(slot, skulls); + break; + } + else { + skulls -= amount; + inv.replaceExistingItem(slot, null); + } + } + } + } + } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/OreWasher.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/OreWasher.java index 7375691bd..8a1ce2c20 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/OreWasher.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/OreWasher.java @@ -14,7 +14,6 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; -import io.github.thebusybiscuit.cscorelib2.inventory.InvUtils; import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; import me.mrCookieSlime.Slimefun.SlimefunPlugin; import me.mrCookieSlime.Slimefun.Lists.SlimefunItems; @@ -45,9 +44,9 @@ public class OreWasher extends MultiBlockMachine { Dispenser disp = (Dispenser) dispBlock.getState(); Inventory inv = disp.getInventory(); - for (ItemStack current : inv.getContents()) { - if (current != null) { - if (SlimefunUtils.isItemSimilar(current, SlimefunItems.SIFTED_ORE, true)) { + for (ItemStack input : inv.getContents()) { + if (input != null) { + if (SlimefunUtils.isItemSimilar(input, SlimefunItems.SIFTED_ORE, true)) { ItemStack output = getRandomDust(); Inventory outputInv = null; @@ -62,50 +61,31 @@ public class OreWasher extends MultiBlockMachine { ItemStack dummyAdding = SlimefunItems.DEBUG_FISH; outputInv = findOutputInventory(dummyAdding, dispBlock, inv); } - else outputInv = findOutputInventory(output, dispBlock, inv); + else { + outputInv = findOutputInventory(output, dispBlock, inv); + } + + removeItem(p, b, inv, outputInv, input, output, 1); if (outputInv != null) { - ItemStack removing = current.clone(); - removing.setAmount(1); - inv.removeItem(removing); - outputInv.addItem(output); - p.getWorld().playSound(b.getLocation(), Sound.ENTITY_PLAYER_SPLASH, 1, 1); - p.getWorld().playEffect(b.getLocation(), Effect.STEP_SOUND, Material.WATER); - if (InvUtils.fits(outputInv, SlimefunItems.STONE_CHUNK)) outputInv.addItem(SlimefunItems.STONE_CHUNK); + outputInv.addItem(SlimefunItems.STONE_CHUNK); } - else SlimefunPlugin.getLocal().sendMessage(p, "machines.full-inventory", true); return; } - else if (SlimefunUtils.isItemSimilar(current, new ItemStack(Material.SAND, 2), false)) { + else if (SlimefunUtils.isItemSimilar(input, new ItemStack(Material.SAND, 2), false)) { ItemStack output = SlimefunItems.SALT; Inventory outputInv = findOutputInventory(output, dispBlock, inv); - if (outputInv != null) { - ItemStack removing = current.clone(); - removing.setAmount(2); - inv.removeItem(removing); - outputInv.addItem(output.clone()); - p.getWorld().playEffect(b.getLocation(), Effect.STEP_SOUND, Material.WATER); - p.getWorld().playSound(b.getLocation(), Sound.ENTITY_PLAYER_SPLASH, 1, 1); - } - else SlimefunPlugin.getLocal().sendMessage(p, "machines.full-inventory", true); + removeItem(p, b, inv, outputInv, input, output, 2); return; } - else if (SlimefunUtils.isItemSimilar(current, SlimefunItems.PULVERIZED_ORE, true)) { + else if (SlimefunUtils.isItemSimilar(input, SlimefunItems.PULVERIZED_ORE, true)) { ItemStack output = SlimefunItems.PURE_ORE_CLUSTER; Inventory outputInv = findOutputInventory(output, dispBlock, inv); - if (outputInv != null) { - ItemStack removing = current.clone(); - removing.setAmount(1); - inv.removeItem(removing); - outputInv.addItem(output.clone()); - p.getWorld().playEffect(b.getLocation(), Effect.STEP_SOUND, Material.WATER); - p.getWorld().playSound(b.getLocation(), Sound.ENTITY_PLAYER_SPLASH, 1, 1); - } - else SlimefunPlugin.getLocal().sendMessage(p, "machines.full-inventory", true); + removeItem(p, b, inv, outputInv, input, output, 1); return; } @@ -114,6 +94,21 @@ public class OreWasher extends MultiBlockMachine { SlimefunPlugin.getLocal().sendMessage(p, "machines.unknown-material", true); } + private void removeItem(Player p, Block b, Inventory inputInv, Inventory outputInv, ItemStack input, ItemStack output, int amount) { + if (outputInv != null) { + ItemStack removing = input.clone(); + removing.setAmount(amount); + inputInv.removeItem(removing); + outputInv.addItem(output.clone()); + + b.getWorld().playEffect(b.getLocation(), Effect.STEP_SOUND, Material.WATER); + b.getWorld().playSound(b.getLocation(), Sound.ENTITY_PLAYER_SPLASH, 1, 1); + } + else { + SlimefunPlugin.getLocal().sendMessage(p, "machines.full-inventory", true); + } + } + /** * This returns a random dust item from Slimefun. * diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/ExplosiveTool.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/ExplosiveTool.java index a122b7fa9..549445851 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/ExplosiveTool.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/ExplosiveTool.java @@ -57,19 +57,7 @@ class ExplosiveTool extends SimpleSlimefunItem implements Not e.getBlock().getWorld().createExplosion(e.getBlock().getLocation(), 0.0F); e.getBlock().getWorld().playSound(e.getBlock().getLocation(), Sound.ENTITY_GENERIC_EXPLODE, 0.2F, 1F); - List blocks = new ArrayList<>(); - for (int x = -1; x <= 1; x++) { - for (int y = -1; y <= 1; y++) { - for (int z = -1; z <= 1; z++) { - // We can skip the center block since that will break as usual - if (x == 0 && y == 0 && z == 0) { - continue; - } - - blocks.add(e.getBlock().getRelative(x, y, z)); - } - } - } + List blocks = findBlocks(e.getBlock()); if (callExplosionEvent.getValue().booleanValue()) { BlockExplodeEvent blockExplodeEvent = new BlockExplodeEvent(e.getBlock(), blocks, 0); @@ -95,6 +83,25 @@ class ExplosiveTool extends SimpleSlimefunItem implements Not }; } + private List findBlocks(Block b) { + List blocks = new ArrayList<>(26); + + for (int x = -1; x <= 1; x++) { + for (int y = -1; y <= 1; y++) { + for (int z = -1; z <= 1; z++) { + // We can skip the center block since that will break as usual + if (x == 0 && y == 0 && z == 0) { + continue; + } + + blocks.add(b.getRelative(x, y, z)); + } + } + } + + return blocks; + } + @Override public boolean isDamageable() { return damageOnUse.getValue(); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/PickaxeOfContainment.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/PickaxeOfContainment.java index 5e6169f60..42701c6e9 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/PickaxeOfContainment.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/PickaxeOfContainment.java @@ -9,6 +9,8 @@ import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; +import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.BrokenSpawner; +import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.RepairedSpawner; import io.github.thebusybiscuit.slimefun4.utils.ChatUtils; import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Lists.SlimefunItems; @@ -19,6 +21,14 @@ import me.mrCookieSlime.Slimefun.api.BlockStorage; import me.mrCookieSlime.Slimefun.api.Slimefun; import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; +/** + * The {@link PickaxeOfContainment} is a Pickaxe that allows you to break Spawners. + * Upon breaking a Spawner, a {@link BrokenSpawner} will be dropped. + * But it also allows you to break a {@link RepairedSpawner}. + * + * @author Admin + * + */ public class PickaxeOfContainment extends SimpleSlimefunItem { public PickaxeOfContainment(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { @@ -47,25 +57,9 @@ public class PickaxeOfContainment extends SimpleSlimefunItem return true; } - // If the spawner's BlockStorage has BlockInfo, then it's not a vanilla spawner and - // should not give a broken spawner. - ItemStack spawner = SlimefunItems.BROKEN_SPAWNER.clone(); - if (BlockStorage.hasBlockInfo(b)) { - spawner = SlimefunItems.REPAIRED_SPAWNER.clone(); - } - - ItemMeta im = spawner.getItemMeta(); - List lore = im.getLore(); - - for (int i = 0; i < lore.size(); i++) { - if (lore.get(i).contains("")) { - lore.set(i, lore.get(i).replace("", ChatUtils.humanize(((CreatureSpawner) b.getState()).getSpawnedType().toString()))); - } - } - - im.setLore(lore); - spawner.setItemMeta(im); + ItemStack spawner = breakSpawner(b); b.getLocation().getWorld().dropItemNaturally(b.getLocation(), spawner); + e.setExpToDrop(0); e.setDropItems(false); return true; @@ -78,4 +72,27 @@ public class PickaxeOfContainment extends SimpleSlimefunItem }; } + private ItemStack breakSpawner(Block b) { + // If the spawner's BlockStorage has BlockInfo, then it's not a vanilla spawner and + // should not give a broken spawner. + ItemStack spawner = SlimefunItems.BROKEN_SPAWNER.clone(); + + if (BlockStorage.hasBlockInfo(b)) { + spawner = SlimefunItems.REPAIRED_SPAWNER.clone(); + } + + ItemMeta im = spawner.getItemMeta(); + List lore = im.getLore(); + + for (int i = 0; i < lore.size(); i++) { + if (lore.get(i).contains("")) { + lore.set(i, lore.get(i).replace("", ChatUtils.humanize(((CreatureSpawner) b.getState()).getSpawnedType().toString()))); + } + } + + im.setLore(lore); + spawner.setItemMeta(im); + return spawner; + } + } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/PickaxeOfVeinMining.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/PickaxeOfVeinMining.java index adf8dbb15..ee293b2a9 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/PickaxeOfVeinMining.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/PickaxeOfVeinMining.java @@ -5,6 +5,8 @@ import java.util.List; import org.bukkit.Effect; import org.bukkit.Material; import org.bukkit.block.Block; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Player; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.inventory.ItemStack; @@ -12,17 +14,38 @@ import io.github.thebusybiscuit.cscorelib2.blocks.Vein; import io.github.thebusybiscuit.cscorelib2.item.CustomItem; import io.github.thebusybiscuit.cscorelib2.materials.MaterialCollections; import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction; +import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting; import me.mrCookieSlime.Slimefun.SlimefunPlugin; import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Objects.Category; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SimpleSlimefunItem; import me.mrCookieSlime.Slimefun.Objects.handlers.BlockBreakHandler; +import me.mrCookieSlime.Slimefun.api.Slimefun; import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; +/** + * The {@link PickaxeOfVeinMining} is a powerful tool which allows you to mine an entire vein of ores + * at once. It even works with the fortune {@link Enchantment}. + * + * @author TheBusyBiscuit + * + */ public class PickaxeOfVeinMining extends SimpleSlimefunItem { + private final ItemSetting maxBlocks = new ItemSetting("max-blocks", 16) { + + @Override + public boolean validateInput(Integer input) { + // We do not wanna allow any negative values here + return super.validateInput(input) && input.intValue() > 0; + } + + }; + public PickaxeOfVeinMining(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { super(category, item, recipeType, recipe); + + addItemSetting(maxBlocks); } @Override @@ -36,26 +59,34 @@ public class PickaxeOfVeinMining extends SimpleSlimefunItem { @Override public boolean onBlockBreak(BlockBreakEvent e, ItemStack item, int fortune, List drops) { - if (MaterialCollections.getAllOres().contains(e.getBlock().getType()) && isItem(item)) { - List blocks = Vein.find(e.getBlock(), 16, MaterialCollections.getAllOres()); - - for (Block b : blocks) { - if (SlimefunPlugin.getProtectionManager().hasPermission(e.getPlayer(), b.getLocation(), ProtectableAction.BREAK_BLOCK)) { - b.getWorld().playEffect(b.getLocation(), Effect.STEP_SOUND, b.getType()); - - for (ItemStack drop : b.getDrops(getItem())) { - b.getWorld().dropItemNaturally(b.getLocation(), drop.getType().isBlock() ? drop : new CustomItem(drop, fortune)); - } - - b.setType(Material.AIR); - } - } - + if (!Slimefun.hasUnlocked(e.getPlayer(), PickaxeOfVeinMining.this, true)) { return true; } - else return false; + + if (MaterialCollections.getAllOres().contains(e.getBlock().getType()) && isItem(item)) { + List blocks = Vein.find(e.getBlock(), maxBlocks.getValue(), MaterialCollections.getAllOres()); + breakBlocks(e.getPlayer(), blocks, fortune); + return true; + } + else { + return false; + } } }; } + private void breakBlocks(Player p, List blocks, int fortune) { + for (Block b : blocks) { + if (SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.BREAK_BLOCK)) { + b.getWorld().playEffect(b.getLocation(), Effect.STEP_SOUND, b.getType()); + + for (ItemStack drop : b.getDrops(getItem())) { + b.getWorld().dropItemNaturally(b.getLocation(), drop.getType().isBlock() ? drop : new CustomItem(drop, fortune)); + } + + b.setType(Material.AIR); + } + } + } + } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/SmeltersPickaxe.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/SmeltersPickaxe.java index dbdfc52ea..46433a9bf 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/SmeltersPickaxe.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/SmeltersPickaxe.java @@ -5,6 +5,8 @@ import java.util.List; import java.util.Optional; import org.bukkit.Effect; +import org.bukkit.Material; +import org.bukkit.block.Block; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.inventory.ItemStack; @@ -36,24 +38,21 @@ public class SmeltersPickaxe extends SimpleSlimefunItem imple @Override public boolean onBlockBreak(BlockBreakEvent e, ItemStack item, int fortune, List drops) { + if (!Slimefun.hasUnlocked(e.getPlayer(), SmeltersPickaxe.this, true)) { + return true; + } + if (MaterialCollections.getAllOres().contains(e.getBlock().getType()) && isItem(item)) { - if (BlockStorage.hasBlockInfo(e.getBlock())) return true; - if (!Slimefun.hasUnlocked(e.getPlayer(), SmeltersPickaxe.this, true)) return true; + if (BlockStorage.hasBlockInfo(e.getBlock())) { + return true; + } Collection blockDrops = e.getBlock().getDrops(getItem()); for (ItemStack drop : blockDrops) { - if (drop != null) { - ItemStack output = drop; - output.setAmount(fortune); - - Optional furnaceOutput = SlimefunPlugin.getMinecraftRecipes().getFurnaceOutput(drop); - if (furnaceOutput.isPresent()) { - e.getBlock().getWorld().playEffect(e.getBlock().getLocation(), Effect.MOBSPAWNER_FLAMES, 1); - output.setType(furnaceOutput.get().getType()); - } - - drops.add(output); + if (drop != null && drop.getType() != Material.AIR) { + smelt(e.getBlock(), drop, fortune); + drops.add(drop); } } @@ -66,6 +65,16 @@ public class SmeltersPickaxe extends SimpleSlimefunItem imple }; } + private void smelt(Block b, ItemStack drop, int fortune) { + Optional furnaceOutput = SlimefunPlugin.getMinecraftRecipes().getFurnaceOutput(drop); + + if (furnaceOutput.isPresent()) { + b.getWorld().playEffect(b.getLocation(), Effect.MOBSPAWNER_FLAMES, 1); + drop.setType(furnaceOutput.get().getType()); + drop.setAmount(fortune); + } + } + @Override public boolean isDamageable() { return true; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/SeismicAxe.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/SeismicAxe.java index f6ea9be80..cc8437b01 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/SeismicAxe.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/weapons/SeismicAxe.java @@ -28,8 +28,20 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SimpleSlimefunItem; import me.mrCookieSlime.Slimefun.Objects.handlers.ItemUseHandler; import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; +/** + * The {@link SeismicAxe} is an interesting weapon. It spawns ghostly block entities in a straight line + * when right-clicked. These blocks launch up from the ground and damage any {@link LivingEntity} in its way. + * It is quite similar to a shockwave. + * + * @author TheBusyBiscuit + * + */ public class SeismicAxe extends SimpleSlimefunItem implements NotPlaceable, DamageableItem { + private static final float STRENGTH = 1.2F; + private static final float DAMAGE = 6; + private static final int RANGE = 10; + public SeismicAxe(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { super(category, item, recipeType, recipe); } @@ -38,45 +50,25 @@ public class SeismicAxe extends SimpleSlimefunItem implements No public ItemUseHandler getItemHandler() { return e -> { Player p = e.getPlayer(); - List blocks = p.getLineOfSight(null, 10); + List blocks = p.getLineOfSight(null, RANGE); - for (int i = 0; i < blocks.size(); i++) { - Block b = blocks.get(i); - Location ground = b.getLocation(); + for (int i = 2; i < blocks.size(); i++) { + Block ground = findGround(blocks.get(i)); + Location groundLocation = ground.getLocation(); - if (b.getType() == null || b.getType() == Material.AIR) { - for (int y = ground.getBlockY(); y > 0; y--) { - if (b.getWorld().getBlockAt(b.getX(), y, b.getZ()) != null && b.getWorld().getBlockAt(b.getX(), y, b.getZ()).getType() != null && b.getWorld().getBlockAt(b.getX(), y, b.getZ()).getType() != Material.AIR) { - ground = new Location(b.getWorld(), b.getX(), y, b.getZ()); - break; - } - } - } + ground.getWorld().playEffect(groundLocation, Effect.STEP_SOUND, ground.getType()); - b.getWorld().playEffect(ground, Effect.STEP_SOUND, ground.getBlock().getType()); - - if (ground.getBlock().getRelative(BlockFace.UP).getType() == null || ground.getBlock().getRelative(BlockFace.UP).getType() == Material.AIR) { - Location loc = ground.getBlock().getRelative(BlockFace.UP).getLocation().add(0.5, 0.0, 0.5); - FallingBlock block = ground.getWorld().spawnFallingBlock(loc, ground.getBlock().getBlockData()); + if (ground.getRelative(BlockFace.UP).getType() == Material.AIR) { + Location loc = ground.getRelative(BlockFace.UP).getLocation().add(0.5, 0.0, 0.5); + FallingBlock block = ground.getWorld().spawnFallingBlock(loc, ground.getBlockData()); block.setDropItem(false); block.setVelocity(new Vector(0, 0.4 + i * 0.01, 0)); block.setMetadata("seismic_axe", new FixedMetadataValue(SlimefunPlugin.instance, "fake_block")); } for (Entity n : ground.getChunk().getEntities()) { - if (n instanceof LivingEntity && n.getType() != EntityType.ARMOR_STAND && n.getLocation().distance(ground) <= 2.0D && !n.getUniqueId().equals(p.getUniqueId())) { - Vector vector = n.getLocation().toVector().subtract(p.getLocation().toVector()).normalize().multiply(1.4); - vector.setY(0.9); - n.setVelocity(vector); - - if (n.getType() != EntityType.PLAYER || p.getWorld().getPVP()) { - EntityDamageByEntityEvent event = new EntityDamageByEntityEvent(p, n, DamageCause.ENTITY_ATTACK, 6D); - Bukkit.getPluginManager().callEvent(event); - - if (!event.isCancelled()) { - ((LivingEntity) n).damage(6D); - } - } + if (n instanceof LivingEntity && n.getType() != EntityType.ARMOR_STAND && n.getLocation().distance(groundLocation) <= 2.0D && !n.getUniqueId().equals(p.getUniqueId())) { + pushEntity(p, n); } } } @@ -87,6 +79,36 @@ public class SeismicAxe extends SimpleSlimefunItem implements No }; } + private void pushEntity(Player p, Entity entity) { + Vector vector = entity.getLocation().toVector().subtract(p.getLocation().toVector()).normalize(); + vector.multiply(STRENGTH); + vector.setY(0.9); + entity.setVelocity(vector); + + if (entity.getType() != EntityType.PLAYER || p.getWorld().getPVP()) { + EntityDamageByEntityEvent event = new EntityDamageByEntityEvent(p, entity, DamageCause.ENTITY_ATTACK, 6D); + Bukkit.getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + ((LivingEntity) entity).damage(DAMAGE); + } + } + } + + private Block findGround(Block b) { + if (b.getType() == Material.AIR) { + for (int y = 0; y < b.getY(); y++) { + Block block = b.getRelative(0, -y, 0); + + if (block.getType() != Material.AIR) { + return block; + } + } + } + + return b; + } + @Override public boolean isDamageable() { return true; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SeismicAxeListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SeismicAxeListener.java index 38dc3e5a5..aae928ebf 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SeismicAxeListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SeismicAxeListener.java @@ -35,6 +35,7 @@ public class SeismicAxeListener implements Listener { if (e.getEntity().getType() == EntityType.FALLING_BLOCK && e.getEntity().hasMetadata("seismic_axe")) { e.setCancelled(true); + e.getEntity().removeMetadata("seismic_axe", SlimefunPlugin.instance); e.getEntity().remove(); } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/setup/PostSetup.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/setup/PostSetup.java index 98ed5def8..d326c831e 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/setup/PostSetup.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/setup/PostSetup.java @@ -199,32 +199,16 @@ public final class PostSetup { Smeltery smeltery = (Smeltery) SlimefunItems.SMELTERY.getItem(); if (smeltery != null && !smeltery.isDisabled()) { + MakeshiftSmeltery makeshiftSmeltery = ((MakeshiftSmeltery) SlimefunItems.MAKESHIFT_SMELTERY.getItem()); ItemStack[] input = null; - for (ItemStack[] recipe : smeltery.getRecipes()) { + for (ItemStack[] output : smeltery.getRecipes()) { if (input == null) { - input = recipe; + input = output; } else { - if (input[0] != null && recipe[0] != null) { - List inputs = new ArrayList<>(); - - for (ItemStack item : input) { - if (item != null) { - inputs.add(item); - } - } - - // We want to exclude Dust to Ingot Recipes - if (inputs.size() == 1 && isDust(inputs.get(0))) { - ((MakeshiftSmeltery) SlimefunItems.MAKESHIFT_SMELTERY.getItem()).addRecipe(new ItemStack[] { inputs.get(0) }, recipe[0]); - - registerMachineRecipe("ELECTRIC_INGOT_FACTORY", 8, new ItemStack[] { inputs.get(0) }, new ItemStack[] { recipe[0] }); - registerMachineRecipe("ELECTRIC_INGOT_PULVERIZER", 3, new ItemStack[] { recipe[0] }, new ItemStack[] { inputs.get(0) }); - } - else { - registerMachineRecipe("ELECTRIC_SMELTERY", 12, inputs.toArray(new ItemStack[0]), new ItemStack[] { recipe[0] }); - } + if (input[0] != null && output[0] != null) { + addSmelteryRecipe(input, output, makeshiftSmeltery); } input = null; @@ -240,6 +224,28 @@ public final class PostSetup { } } + private static void addSmelteryRecipe(ItemStack[] input, ItemStack[] output, MakeshiftSmeltery makeshiftSmeltery) { + List ingredients = new ArrayList<>(); + + // Filter out 'null' items + for (ItemStack item : input) { + if (item != null) { + ingredients.add(item); + } + } + + // We want to redirect Dust to Ingot Recipes + if (ingredients.size() == 1 && isDust(ingredients.get(0))) { + makeshiftSmeltery.addRecipe(new ItemStack[] { ingredients.get(0) }, output[0]); + + registerMachineRecipe("ELECTRIC_INGOT_FACTORY", 8, new ItemStack[] { ingredients.get(0) }, new ItemStack[] { output[0] }); + registerMachineRecipe("ELECTRIC_INGOT_PULVERIZER", 3, new ItemStack[] { output[0] }, new ItemStack[] { ingredients.get(0) }); + } + else { + registerMachineRecipe("ELECTRIC_SMELTERY", 12, ingredients.toArray(new ItemStack[0]), new ItemStack[] { output[0] }); + } + } + private static boolean isDust(ItemStack item) { SlimefunItem sfItem = SlimefunItem.getByItem(item); return sfItem != null && sfItem.getID().endsWith("_DUST"); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/itemstack/ItemStackWrapper.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/itemstack/ItemStackWrapper.java index 95d8fa522..70f6a85ff 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/itemstack/ItemStackWrapper.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/itemstack/ItemStackWrapper.java @@ -19,6 +19,8 @@ import org.bukkit.inventory.meta.ItemMeta; */ public final class ItemStackWrapper extends ItemStack { + private static final String ERROR_MESSAGE = "ItemStackWrappers are immutable and not indended for actual usage."; + private final ItemMeta meta; private final boolean hasItemMeta; @@ -49,37 +51,37 @@ public final class ItemStackWrapper extends ItemStack { @Override public boolean equals(Object obj) { - throw new UnsupportedOperationException("ItemStackWrappers do not allow .equals()"); + throw new UnsupportedOperationException(ERROR_MESSAGE); } @Override public int hashCode() { - throw new UnsupportedOperationException("You cannot hash an ItemStackWrapper"); + throw new UnsupportedOperationException(ERROR_MESSAGE); } @Override public ItemStack clone() { - throw new UnsupportedOperationException("You cannot clone an ItemStackWrapper"); + throw new UnsupportedOperationException(ERROR_MESSAGE); } @Override public void setType(Material type) { - throw new UnsupportedOperationException("ItemStackWrappers are immutable and not indended for actual usage."); + throw new UnsupportedOperationException(ERROR_MESSAGE); } @Override public void setAmount(int amount) { - throw new UnsupportedOperationException("ItemStackWrappers are immutable and not indended for actual usage."); + throw new UnsupportedOperationException(ERROR_MESSAGE); } @Override public boolean setItemMeta(ItemMeta itemMeta) { - throw new UnsupportedOperationException("ItemStackWrappers are immutable and not indended for actual usage."); + throw new UnsupportedOperationException(ERROR_MESSAGE); } @Override public void addUnsafeEnchantment(Enchantment ench, int level) { - throw new UnsupportedOperationException("ItemStackWrappers are immutable and not indended for actual usage."); + throw new UnsupportedOperationException(ERROR_MESSAGE); } /**