1
mirror of https://github.com/StarWishsama/Slimefun4.git synced 2024-09-19 19:25:48 +00:00

Lots of refactoring

This commit is contained in:
TheBusyBiscuit 2020-06-10 23:33:51 +02:00
parent 22650f53dd
commit 7acee959ce
17 changed files with 897 additions and 812 deletions

View File

@ -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

View File

@ -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 <Player> <Slimefun Item> [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 <Player> <Slimefun Item> [Amount]"));
}
else SlimefunPlugin.getLocal().sendMessage(sender, "messages.no-permission", true);
}
private int parseAmount(String[] args) {

View File

@ -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);

View File

@ -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<String, String> 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<String, String> skins, Contributor contributor) throws TooManyRequestsException, IOException {
private int requestTexture(Contributor contributor, Map<String, String> 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<String, String> skins, Contributor contributor) throws TooManyRequestsException, IOException {
Optional<UUID> uuid = contributor.getUniqueId();
if (!uuid.isPresent()) {

View File

@ -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<Entity> 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<Config> 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<String> 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<String> 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<String>());
script.setValue("rating.negative", new ArrayList<String>());
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<Config> getUploadedScripts() {
List<Config> 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<ScriptAction> getAccessibleScriptParts() {
List<ScriptAction> 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);
}
}

View File

@ -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);
}

View File

@ -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<BlockFace> 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<BlockFace> directions = Arrays.asList(BlockFace.NORTH, BlockFace.EAST, BlockFace.SOUTH, BlockFace.WEST);
protected final Set<MachineFuel> recipes = new HashSet<>();
protected final Set<MachineFuel> 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<Config> 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<String> 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<String> 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<String>());
script.setValue("rating.negative", new ArrayList<String>());
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<Config> getUploadedScripts() {
List<Config> 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<ScriptAction> getAccessibleScriptParts() {
List<ScriptAction> 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<ItemStack> getDisplayRecipes() {
List<ItemStack> list = new ArrayList<>();
for (MachineFuel fuel : recipes) {
for (MachineFuel fuel : fuelTypes) {
ItemStack item = fuel.getInput().clone();
ItemMeta im = item.getItemMeta();
List<String> 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<Entity> 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!");
}
}

View File

@ -190,68 +190,18 @@ public class WitherAssembler extends SimpleSlimefunItem<BlockTicker> 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<BlockTicker> 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);
}
}
}
}
}

View File

@ -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.
*

View File

@ -57,19 +57,7 @@ class ExplosiveTool extends SimpleSlimefunItem<BlockBreakHandler> 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<Block> 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<Block> blocks = findBlocks(e.getBlock());
if (callExplosionEvent.getValue().booleanValue()) {
BlockExplodeEvent blockExplodeEvent = new BlockExplodeEvent(e.getBlock(), blocks, 0);
@ -95,6 +83,25 @@ class ExplosiveTool extends SimpleSlimefunItem<BlockBreakHandler> implements Not
};
}
private List<Block> findBlocks(Block b) {
List<Block> 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();

View File

@ -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<BlockBreakHandler> {
public PickaxeOfContainment(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
@ -47,25 +57,9 @@ public class PickaxeOfContainment extends SimpleSlimefunItem<BlockBreakHandler>
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<String> lore = im.getLore();
for (int i = 0; i < lore.size(); i++) {
if (lore.get(i).contains("<Type>")) {
lore.set(i, lore.get(i).replace("<Type>", 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<BlockBreakHandler>
};
}
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<String> lore = im.getLore();
for (int i = 0; i < lore.size(); i++) {
if (lore.get(i).contains("<Type>")) {
lore.set(i, lore.get(i).replace("<Type>", ChatUtils.humanize(((CreatureSpawner) b.getState()).getSpawnedType().toString())));
}
}
im.setLore(lore);
spawner.setItemMeta(im);
return spawner;
}
}

View File

@ -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<BlockBreakHandler> {
private final ItemSetting<Integer> maxBlocks = new ItemSetting<Integer>("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<BlockBreakHandler> {
@Override
public boolean onBlockBreak(BlockBreakEvent e, ItemStack item, int fortune, List<ItemStack> drops) {
if (MaterialCollections.getAllOres().contains(e.getBlock().getType()) && isItem(item)) {
List<Block> 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<Block> 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<Block> 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);
}
}
}
}

View File

@ -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<BlockBreakHandler> imple
@Override
public boolean onBlockBreak(BlockBreakEvent e, ItemStack item, int fortune, List<ItemStack> 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<ItemStack> blockDrops = e.getBlock().getDrops(getItem());
for (ItemStack drop : blockDrops) {
if (drop != null) {
ItemStack output = drop;
output.setAmount(fortune);
Optional<ItemStack> 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<BlockBreakHandler> imple
};
}
private void smelt(Block b, ItemStack drop, int fortune) {
Optional<ItemStack> 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;

View File

@ -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<ItemUseHandler> 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<ItemUseHandler> implements No
public ItemUseHandler getItemHandler() {
return e -> {
Player p = e.getPlayer();
List<Block> blocks = p.getLineOfSight(null, 10);
List<Block> 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<ItemUseHandler> 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;

View File

@ -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();
}
}

View File

@ -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<ItemStack> 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<ItemStack> 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");

View File

@ -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);
}
/**