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

Merge branch 'master' into performance/cobblestone

This commit is contained in:
TheBusyBiscuit 2021-01-06 20:24:54 +01:00 committed by GitHub
commit e773e68b4a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
90 changed files with 1549 additions and 617 deletions

14
.github/CODEOWNERS vendored
View File

@ -1,7 +1,13 @@
# Modifications to the source code should be handled by the review team
*.java @Slimefun/code-reviewers
*.java @Slimefun/code-reviewers
# Modifications to sensitive files should be reviewed by maintainers
/.github/ @Slimefun/slimefun4-maintainers
pom.xml @Slimefun/slimefun4-maintainers
CONTRIBUTING.md @Slimefun/slimefun4-maintainers
/.github/ @Slimefun/slimefun4-maintainers
pom.xml @Slimefun/slimefun4-maintainers
CONTRIBUTING.md @Slimefun/slimefun4-maintainers
# Changes to the Issue templates need to be checked by the triage team
/.github/ISSUE_TEMPLATE/ @Slimefun/bug-testers
# This file is handled by TheBusyBiscuit (admins have overwrite access anyway)
/.github/CODEOWNERS @TheBusyBiscuit

View File

@ -2,7 +2,7 @@
name: Bug Report
about: Report a Bug or an Issue with Slimefun 4.
title: ''
labels: '🐞 Bug Report'
labels: "\U0001F3AF Needs testing, \U0001F41E Bug Report"
assignees: ''
---
@ -19,7 +19,9 @@ assignees: ''
<!-- Tell us the exact steps to reproduce this issue, the more detailed the easier we can reproduce it. -->
<!-- Youtube Videos and Screenshots are recommended!!! -->
<!-- Start writing below this line -->
1.
2.
3.
## :bulb: Expected behavior (REQUIRED)
<!-- What were you expecting to happen? -->
@ -34,7 +36,7 @@ assignees: ''
## :open_file_folder: /error-reports/ Folder
<!-- Check the folder /plugins/Slimefun/error-reports/ and upload all files inside that folder. -->
<!-- Check the folder /plugins/Slimefun/error-reports/ and upload any files inside that folder. -->
<!-- You can also post these files via https://pastebin.com/ -->
<!-- Paste your link(s) below this line -->
@ -46,7 +48,7 @@ assignees: ''
<!-- Make sure that the screenshot covers the entire output of that command. -->
<!-- If your issue is related to other plugins, make sure to include the versions of these plugins too! -->
- Server Software (Spigot/Paper):
- Server Software:
- Minecraft Version:
- Slimefun Version:
- CS-CoreLib Version:

View File

@ -7,7 +7,7 @@ on:
jobs:
comment:
runs-on: ubuntu-latest
if: contains(github.event.issue.labels.*.name, 'Bug Report')
if: contains(github.event.issue.labels.*.name, '🐞 Bug Report')
steps:
- name: Query recent commits
uses: TheBusyBiscuit/recently-closed-issues@1.1.0
@ -21,7 +21,7 @@ jobs:
with:
token: ${{ secrets.ACCESS_TOKEN }}
issue_number: ${{ github.event.issue.number }}
labels: 'Resolved'
labels: 'Resolved'
- uses: maxkomarychev/octions/octions/issues/create-comment@master
id: comment
if: contains(steps.resolved.outputs.issues, github.event.issue.number) == false

View File

@ -26,12 +26,26 @@
## Release Candidate 19 (TBD)
#### Additions
* Added Bee Armor (1.15+ only)
#### Changes
* Performance optimizations for Cargo networks
* Removed an old version of bStats
* CraftBukkit is officially no longer supported, Slimefun will now be disabled on old builds of CraftBukkit
* Removed the deprecated ItemManipulationAPI for BlockMenus
* Performance Improvements and Optimizations for Cobblestone/Stone/Basalt generators and mining androids
* Androids operating on a Cobblestone/Stone/Basalt generator now work faster
#### Fixes
* Fixed a couple of compatibility issues with ItemsAdder
* Fixed #2575
* Fixed ghost blocks to some extent (ghost blocks will now drop and be replaced)
* Fixed #2636 (hotfix)
* Fixed #2647
* Fixed #2664
* Fixed #2655
## Release Candidate 18 (03 Dec 2020)
#### Additions

32
pom.xml
View File

@ -49,11 +49,11 @@
<repositories>
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots</url>
</repository>
<repository>
<id>paper-repo</id>
<url>https://papermc.io/repo/repository/maven-public/</url>
<url>https://papermc.io/repo/repository/maven-public</url>
</repository>
<repository>
<id>jitpack.io</id>
@ -61,7 +61,7 @@
</repository>
<repository>
<id>worldedit-repo</id>
<url>https://maven.sk89q.com/repo/</url>
<url>https://maven.sk89q.com/repo</url>
</repository>
<repository>
<id>codemc-repo</id>
@ -69,11 +69,11 @@
</repository>
<repository>
<id>placeholderapi-repo</id>
<url>https://repo.extendedclip.com/content/repositories/placeholderapi/</url>
<url>https://repo.extendedclip.com/content/repositories/placeholderapi</url>
</repository>
<repository>
<id>walshy-public</id>
<url>https://repo.walshy.dev/public/</url>
<url>https://repo.walshy.dev/public</url>
</repository>
</repositories>
@ -314,7 +314,7 @@
<dependency>
<groupId>com.github.seeseemelk</groupId>
<artifactId>MockBukkit-v1.16</artifactId>
<version>0.17.0</version>
<version>0.20.0</version>
<scope>test</scope>
<exclusions>
<exclusion>
@ -328,7 +328,7 @@
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.6.28</version>
<version>3.7.0</version>
<scope>test</scope>
</dependency>
@ -348,7 +348,7 @@
<dependency>
<groupId>com.konghq</groupId>
<artifactId>unirest-java</artifactId>
<version>3.11.05</version>
<version>3.11.09</version>
<scope>compile</scope>
<exclusions>
<exclusion>
@ -380,7 +380,7 @@
<dependency>
<groupId>com.gmail.nossr50.mcMMO</groupId>
<artifactId>mcMMO</artifactId>
<version>2.1.161</version>
<version>2.1.170</version>
<scope>provided</scope>
<exclusions>
<exclusion>
@ -419,5 +419,19 @@
<version>3.1.6</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.github.LoneDev6</groupId>
<artifactId>itemsadder-api</artifactId>
<version>0.1.2</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<!-- We use javax.annotation instead. Excluding this -->
<!-- prevents us from using inconsistent annotations -->
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>

View File

@ -1,5 +1,7 @@
package io.github.thebusybiscuit.slimefun4.api;
import javax.annotation.Nonnull;
import org.apache.commons.lang.Validate;
import org.bukkit.Server;
@ -59,7 +61,7 @@ public enum MinecraftVersion {
* @param name
* The display name of this {@link MinecraftVersion}
*/
MinecraftVersion(String name) {
MinecraftVersion(@Nonnull String name) {
this(name, false);
}
@ -73,7 +75,7 @@ public enum MinecraftVersion {
* @param virtual
* Whether this {@link MinecraftVersion} is virtual
*/
MinecraftVersion(String name, boolean virtual) {
MinecraftVersion(@Nonnull String name, boolean virtual) {
this.name = name;
this.virtual = virtual;
this.prefix = name().replace("MINECRAFT_", "v") + '_';
@ -84,6 +86,7 @@ public enum MinecraftVersion {
*
* @return The name of this {@link MinecraftVersion}
*/
@Nonnull
public String getName() {
return name;
}
@ -110,8 +113,9 @@ public enum MinecraftVersion {
*
* @return Whether the version matches with this one
*/
public boolean matches(String version) {
public boolean matches(@Nonnull String version) {
Validate.notNull(version, "The input version must not be null!");
return version.startsWith(prefix);
}
@ -126,7 +130,7 @@ public enum MinecraftVersion {
*
* @return Whether this {@link MinecraftVersion} is newer or equal to the given {@link MinecraftVersion}
*/
public boolean isAtLeast(MinecraftVersion version) {
public boolean isAtLeast(@Nonnull MinecraftVersion version) {
Validate.notNull(version, "A Minecraft version cannot be null!");
if (this == UNKNOWN) {
@ -146,7 +150,7 @@ public enum MinecraftVersion {
*
* @return Whether this {@link MinecraftVersion} is older than the given one
*/
public boolean isBefore(MinecraftVersion version) {
public boolean isBefore(@Nonnull MinecraftVersion version) {
Validate.notNull(version, "A Minecraft version cannot be null!");
if (this == UNKNOWN) {

View File

@ -3,7 +3,7 @@ package io.github.thebusybiscuit.slimefun4.core.attributes;
import org.bukkit.entity.Piglin;
import org.bukkit.event.entity.EntityDropItemEvent;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.PiglinListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.entity.PiglinListener;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;

View File

@ -5,7 +5,7 @@ import org.bukkit.entity.Player;
import org.bukkit.event.entity.EntityDeathEvent;
import io.github.thebusybiscuit.slimefun4.implementation.items.misc.BasicCircuitBoard;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.MobDropListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.entity.MobDropListener;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;

View File

@ -1,10 +1,16 @@
package io.github.thebusybiscuit.slimefun4.core.commands.subcommands;
import javax.annotation.Nonnull;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.entity.Player;
import io.github.thebusybiscuit.slimefun4.core.commands.SlimefunCommand;
import io.github.thebusybiscuit.slimefun4.core.commands.SubCommand;
import io.github.thebusybiscuit.slimefun4.core.services.profiler.PerformanceInspector;
import io.github.thebusybiscuit.slimefun4.core.services.profiler.inspectors.ConsolePerformanceInspector;
import io.github.thebusybiscuit.slimefun4.core.services.profiler.inspectors.PlayerPerformanceInspector;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
class TimingsCommand extends SubCommand {
@ -17,10 +23,20 @@ class TimingsCommand extends SubCommand {
public void onExecute(CommandSender sender, String[] args) {
if (sender.hasPermission("slimefun.command.timings") || sender instanceof ConsoleCommandSender) {
sender.sendMessage("Please wait a second... The results are coming in!");
SlimefunPlugin.getProfiler().requestSummary(sender);
PerformanceInspector inspector = inspectorOf(sender);
SlimefunPlugin.getProfiler().requestSummary(inspector);
} else {
SlimefunPlugin.getLocalization().sendMessage(sender, "messages.no-permission", true);
}
}
@Nonnull
private PerformanceInspector inspectorOf(@Nonnull CommandSender sender) {
if (sender instanceof Player) {
return new PlayerPerformanceInspector((Player) sender);
} else {
return new ConsolePerformanceInspector(sender);
}
}
}

View File

@ -8,7 +8,7 @@ import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.EntityInteractionListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.entity.EntityInteractionListener;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.handlers.ItemHandler;

View File

@ -12,7 +12,6 @@ import java.util.Map;
import java.util.Optional;
import java.util.Queue;
import java.util.Set;
import java.util.logging.Level;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@ -38,10 +37,8 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import io.papermc.lib.PaperLib;
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
import me.mrCookieSlime.Slimefun.api.inventory.DirtyChestMenu;
import me.mrCookieSlime.Slimefun.api.inventory.UniversalBlockMenu;
@ -426,12 +423,7 @@ abstract class AbstractItemNetwork extends Network {
}
} else if (BlockStorage.hasInventory(target)) {
BlockMenu blockMenu = BlockStorage.getInventory(target);
if (blockMenu.getPreset().getID().startsWith("BARREL_")) {
gatherItemsFromBarrel(l, blockMenu, items);
} else {
handleWithdraw(blockMenu, items, l);
}
handleWithdraw(blockMenu, items, l);
} else if (CargoUtils.hasInventory(target)) {
BlockState state = PaperLib.getBlockState(target, false).getState();
@ -445,41 +437,6 @@ abstract class AbstractItemNetwork extends Network {
}
}
@ParametersAreNonnullByDefault
private void gatherItemsFromBarrel(Location l, BlockMenu blockMenu, List<ItemStackAndInteger> items) {
try {
Config cfg = BlockStorage.getLocationInfo(blockMenu.getLocation());
String data = cfg.getString("storedItems");
if (data == null) {
return;
}
int stored = Integer.parseInt(data);
for (int slot : blockMenu.getPreset().getSlotsAccessedByItemTransport((DirtyChestMenu) blockMenu, ItemTransportFlow.WITHDRAW, null)) {
ItemStack stack = blockMenu.getItemInSlot(slot);
if (stack != null && CargoUtils.matchesFilter(this, l.getBlock(), stack)) {
boolean add = true;
for (ItemStackAndInteger item : items) {
if (SlimefunUtils.isItemSimilar(stack, item.getItemStackWrapper(), true, false)) {
add = false;
item.add(stack.getAmount() + stored);
}
}
if (add) {
items.add(new ItemStackAndInteger(stack, stack.getAmount() + stored));
}
}
}
} catch (Exception x) {
Slimefun.getLogger().log(Level.SEVERE, "An Exception occurred while trying to read data from a Barrel", x);
}
}
@ParametersAreNonnullByDefault
private void handleWithdraw(DirtyChestMenu menu, List<ItemStackAndInteger> items, Location l) {
for (int slot : menu.getPreset().getSlotsAccessedByItemTransport(menu, ItemTransportFlow.WITHDRAW, null)) {

View File

@ -64,7 +64,7 @@ class CargoNetworkTask implements Runnable {
long timestamp = System.nanoTime();
// Chest Terminal Code
if (SlimefunPlugin.getThirdPartySupportService().isChestTerminalInstalled()) {
if (SlimefunPlugin.getIntegrations().isChestTerminalInstalled()) {
network.handleItemRequests(inventories, chestTerminalInputs, chestTerminalOutputs);
}
@ -85,7 +85,7 @@ class CargoNetworkTask implements Runnable {
}
// Chest Terminal Code
if (SlimefunPlugin.getThirdPartySupportService().isChestTerminalInstalled()) {
if (SlimefunPlugin.getIntegrations().isChestTerminalInstalled()) {
// This will deduct any CT timings and attribute them towards the actual terminal
timestamp += network.updateTerminals(chestTerminalInputs);
}

View File

@ -30,7 +30,7 @@ final class CargoUtils {
/**
* These are the slots where our filter items sit.
*/
static final int[] FILTER_SLOTS = { 19, 20, 21, 28, 29, 30, 37, 38, 39 };
private static final int[] FILTER_SLOTS = { 19, 20, 21, 28, 29, 30, 37, 38, 39 };
private CargoUtils() {}
@ -372,9 +372,22 @@ final class CargoUtils {
* Get the whitelist/blacklist slots in a Cargo Input Node. If you wish to access the items
* in the cargo (without hardcoding the slots in case of change) then you can use this method.
*
* @deprecated Renamed to {@link #getFilteringSlots()}
*
* @return The slot indexes for the whitelist/blacklist section.
*/
@Deprecated
public static int[] getWhitelistBlacklistSlots() {
return FILTER_SLOTS;
}
/**
* Gets the {@link ItemFilter} slots for a Cargo Node. If you wish to access the items
* in the cargo (without hardcoding the slots in case of change) then you can use this method.
*
* @return The slots where the {@link ItemFilter} section for a cargo node sits
*/
public static int[] getFilteringSlots() {
return FILTER_SLOTS;
}
}

View File

@ -92,7 +92,7 @@ class ItemFilter implements Predicate<ItemStack> {
this.checkLore = Objects.equals(blockData.getString("filter-lore"), "true");
this.rejectOnMatch = !Objects.equals(blockData.getString("filter-type"), "whitelist");
for (int slot : CargoUtils.FILTER_SLOTS) {
for (int slot : CargoUtils.getFilteringSlots()) {
ItemStack stack = menu.getItemInSlot(slot);
if (stack != null && stack.getType() != Material.AIR) {

View File

@ -36,6 +36,8 @@ public class Translators {
addTranslator("ishi-sama", SupportedLanguage.FRENCH, true);
addTranslator("amarcais53", SupportedLanguage.FRENCH, true);
addTranslator("NinoFutur", SupportedLanguage.FRENCH, true);
addTranslator("TheRetix", SupportedLanguage.FRENCH, true);
addTranslator("Aeris1One", SupportedLanguage.FRENCH, true);
// Translators - Italian
addTranslator("xXDOTTORXx", SupportedLanguage.ITALIAN, true);
@ -58,6 +60,8 @@ public class Translators {
addTranslator("nahkd123", SupportedLanguage.VIETNAMESE, true);
addTranslator("JustAPieOP", SupportedLanguage.VIETNAMESE, true);
addTranslator("that4life", SupportedLanguage.VIETNAMESE, true);
addTranslator("CactusTheGuy", SupportedLanguage.VIETNAMESE, true);
addTranslator("hniV", SupportedLanguage.VIETNAMESE, true);
// Translators - Slovak
addTranslator("KillerXCoder", SupportedLanguage.SLOVAK, true);
@ -90,6 +94,7 @@ public class Translators {
addTranslator("Vravinite", SupportedLanguage.SPANISH, true);
addTranslator("NotUmBr4", SupportedLanguage.SPANISH, true);
addTranslator("dbzjjoe", SupportedLanguage.SPANISH, true);
addTranslator("DaHolyCheese", SupportedLanguage.SPANISH, true);
// Translators - Swedish
addTranslator("NihilistBrew", "ma1yang2", SupportedLanguage.SWEDISH, false);
@ -161,6 +166,7 @@ public class Translators {
// Translators - Bulgarian
addTranslator("DNBGlol", SupportedLanguage.BULGARIAN, true);
addTranslator("Pukejoy", SupportedLanguage.BULGARIAN, true);
// Translators - Tagalog
addTranslator("sccooottttie", SupportedLanguage.TAGALOG, true);

View File

@ -2,21 +2,16 @@ package io.github.thebusybiscuit.slimefun4.core.services.plugins;
import java.util.Optional;
import java.util.function.Function;
import java.util.logging.Level;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.block.Block;
import org.bukkit.event.Event;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.Plugin;
import com.gmail.nossr50.events.fake.FakeBlockBreakEvent;
import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.api.Slimefun;
import io.github.thebusybiscuit.slimefun4.integrations.IntegrationsManager;
/**
* This Service holds all interactions and hooks with third-party {@link Plugin Plugins}
@ -26,17 +21,13 @@ import me.mrCookieSlime.Slimefun.api.Slimefun;
*
* @author TheBusyBiscuit
*
* @deprecated Renamed to {@link IntegrationsManager}
*
* @see SlimefunPlugin
*
*/
public class ThirdPartyPluginService {
private final SlimefunPlugin plugin;
private boolean initialized = false;
private boolean isExoticGardenInstalled = false;
private boolean isChestTerminalInstalled = false;
private boolean isMcMMOInstalled = false;
@Deprecated
public class ThirdPartyPluginService extends IntegrationsManager {
/**
* This gets overridden if ExoticGarden is loaded
@ -50,111 +41,21 @@ public class ThirdPartyPluginService {
* Our instance of {@link SlimefunPlugin}
*/
public ThirdPartyPluginService(@Nonnull SlimefunPlugin plugin) {
this.plugin = plugin;
super(plugin);
}
/**
* This method initializes all third party integrations.
*/
public void start() {
if (initialized) {
throw new UnsupportedOperationException("Third Party Integrations have already been initialized!");
}
initialized = true;
if (isPluginInstalled("PlaceholderAPI")) {
try {
PlaceholderAPIIntegration hook = new PlaceholderAPIIntegration(plugin);
hook.register();
} catch (Exception | LinkageError x) {
String version = plugin.getServer().getPluginManager().getPlugin("PlaceholderAPI").getDescription().getVersion();
Slimefun.getLogger().log(Level.WARNING, "Maybe consider updating PlaceholderAPI or Slimefun?");
Slimefun.getLogger().log(Level.WARNING, x, () -> "Failed to hook into PlaceholderAPI v" + version);
}
}
// WorldEdit Hook to clear Slimefun Data upon //set 0 //cut or any other equivalent
if (isPluginInstalled("WorldEdit")) {
try {
Class.forName("com.sk89q.worldedit.extent.Extent");
new WorldEditIntegration();
} catch (Exception | LinkageError x) {
String version = plugin.getServer().getPluginManager().getPlugin("WorldEdit").getDescription().getVersion();
Slimefun.getLogger().log(Level.WARNING, "Maybe consider updating WorldEdit or Slimefun?");
Slimefun.getLogger().log(Level.WARNING, x, () -> "Failed to hook into WorldEdit v" + version);
}
}
// mcMMO Integration
if (isPluginInstalled("mcMMO")) {
try {
new McMMOIntegration(plugin);
isMcMMOInstalled = true;
} catch (Exception | LinkageError x) {
String version = plugin.getServer().getPluginManager().getPlugin("mcMMO").getDescription().getVersion();
Slimefun.getLogger().log(Level.WARNING, "Maybe consider updating mcMMO or Slimefun?");
Slimefun.getLogger().log(Level.WARNING, x, () -> "Failed to hook into mcMMO v" + version);
}
}
/*
* These Items are not marked as soft-dependencies and
* therefore need to be loaded after the Server has finished
* loading all plugins
*/
plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () -> {
if (isPluginInstalled("ClearLag")) {
new ClearLagIntegration(plugin);
}
isChestTerminalInstalled = isPluginInstalled("ChestTerminal");
});
}
private boolean isPluginInstalled(@Nonnull String hook) {
if (plugin.getServer().getPluginManager().isPluginEnabled(hook)) {
Slimefun.getLogger().log(Level.INFO, "Hooked into Plugin: {0}", hook);
return true;
} else {
return false;
}
}
@ParametersAreNonnullByDefault
@Deprecated
public void loadExoticGarden(Plugin plugin, Function<Block, Optional<ItemStack>> method) {
// TODO: Move this method to IntegrationsManager and think of a better way to handle this
// For next RC!
if (plugin.getName().equals("ExoticGarden")) {
isExoticGardenInstalled = true;
exoticGardenIntegration = method;
}
}
public boolean isExoticGardenInstalled() {
return isExoticGardenInstalled;
}
public boolean isChestTerminalInstalled() {
return isChestTerminalInstalled;
}
@Deprecated
public Optional<ItemStack> harvestExoticGardenPlant(Block block) {
return exoticGardenIntegration.apply(block);
}
/**
* This checks if one of our third party integrations faked an {@link Event}.
* Faked {@link Event Events} should be ignored in our logic.
*
* @param event
* The {@link Event} to test
*
* @return Whether this is a fake event
*/
public boolean isEventFaked(@Nonnull Event event) {
// This can be changed to "FakeEvent" in a later version
return isMcMMOInstalled && event instanceof FakeBlockBreakEvent;
}
}

View File

@ -0,0 +1,41 @@
package io.github.thebusybiscuit.slimefun4.core.services.profiler;
import javax.annotation.Nonnull;
import org.bukkit.Server;
/**
* This interface is used to identify someone as a {@link PerformanceInspector}.
* A {@link PerformanceInspector} can query the {@link SlimefunProfiler} and get the
* results send to them as a {@link PerformanceSummary}.
*
* @author TheBusyBiscuit
*
*/
public interface PerformanceInspector {
/**
* This returns whether this {@link PerformanceInspector} is still valid.
* An inspector will become invalid if they leave the {@link Server}.
*
* @return Whether this inspector is still valid
*/
boolean isValid();
/**
* This will send a text message to the {@link PerformanceInspector}.
*
* @param msg
* The message to send
*/
void sendMessage(@Nonnull String msg);
/**
* This determines whether the {@link PerformanceInspector} will get the full view
* or a trimmed version which only shows the most urgent samples.
*
* @return Whether to send the full {@link PerformanceSummary} or a trimmed version
*/
boolean hasFullView();
}

View File

@ -11,10 +11,8 @@ import java.util.stream.Stream;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import io.github.thebusybiscuit.cscorelib2.chat.ChatColors;
import io.github.thebusybiscuit.slimefun4.core.services.profiler.inspectors.PlayerPerformanceInspector;
import io.github.thebusybiscuit.slimefun4.utils.ChatUtils;
import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
import net.md_5.bungee.api.ChatColor;
@ -54,7 +52,7 @@ class PerformanceSummary {
items = profiler.getByItem();
}
public void send(@Nonnull CommandSender sender) {
public void send(@Nonnull PerformanceInspector sender) {
sender.sendMessage("");
sender.sendMessage(ChatColor.GREEN + "===== Slimefun Lag Profiler =====");
sender.sendMessage(ChatColor.GOLD + "Total time: " + ChatColor.YELLOW + NumberUtils.getAsMillis(totalElapsedTime));
@ -91,17 +89,17 @@ class PerformanceSummary {
}
@ParametersAreNonnullByDefault
private void summarizeTimings(int count, String name, CommandSender sender, Map<String, Long> map, Function<Map.Entry<String, Long>, String> formatter) {
private void summarizeTimings(int count, String name, PerformanceInspector inspector, Map<String, Long> map, Function<Map.Entry<String, Long>, String> formatter) {
Stream<Map.Entry<String, Long>> stream = map.entrySet().stream();
List<Entry<String, Long>> results = stream.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())).collect(Collectors.toList());
String prefix = count + " " + name + (count != 1 ? 's' : "");
if (sender instanceof Player) {
if (inspector instanceof PlayerPerformanceInspector) {
TextComponent component = summarizeAsTextComponent(count, prefix, results, formatter);
sender.spigot().sendMessage(component);
((PlayerPerformanceInspector) inspector).sendMessage(component);
} else {
String text = summarizeAsString(count, prefix, results, formatter);
sender.sendMessage(text);
String text = summarizeAsString(inspector, count, prefix, results, formatter);
inspector.sendMessage(text);
}
}
@ -143,7 +141,7 @@ class PerformanceSummary {
@Nonnull
@ParametersAreNonnullByDefault
private String summarizeAsString(int count, String prefix, List<Entry<String, Long>> results, Function<Entry<String, Long>, String> formatter) {
private String summarizeAsString(PerformanceInspector inspector, int count, String prefix, List<Entry<String, Long>> results, Function<Entry<String, Long>, String> formatter) {
int shownEntries = 0;
int hiddenEntries = 0;
@ -154,7 +152,7 @@ class PerformanceSummary {
builder.append(ChatColor.YELLOW);
for (Map.Entry<String, Long> entry : results) {
if (shownEntries < MAX_ITEMS && (shownEntries < MIN_ITEMS || entry.getValue() > VISIBILITY_THRESHOLD)) {
if (!inspector.hasFullView() || (shownEntries < MAX_ITEMS && (shownEntries < MIN_ITEMS || entry.getValue() > VISIBILITY_THRESHOLD))) {
builder.append("\n ");
builder.append(ChatColor.stripColor(formatter.apply(entry)));
shownEntries++;

View File

@ -19,7 +19,6 @@ import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.block.Block;
import org.bukkit.command.CommandSender;
import org.bukkit.scheduler.BukkitScheduler;
import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon;
@ -69,7 +68,7 @@ public class SlimefunProfiler {
private long totalElapsedTime;
private final Map<ProfiledBlock, Long> timings = new ConcurrentHashMap<>();
private final Queue<CommandSender> requests = new ConcurrentLinkedQueue<>();
private final Queue<PerformanceInspector> requests = new ConcurrentLinkedQueue<>();
/**
* This method terminates the {@link SlimefunProfiler}.
@ -183,7 +182,7 @@ public class SlimefunProfiler {
// If we waited for too long, then we should just abort
if (iterations <= 0) {
Iterator<CommandSender> iterator = requests.iterator();
Iterator<PerformanceInspector> iterator = requests.iterator();
while (iterator.hasNext()) {
iterator.next().sendMessage("Your timings report has timed out, we were still waiting for " + queued.get() + " samples to be collected :/");
@ -207,7 +206,7 @@ public class SlimefunProfiler {
if (!requests.isEmpty()) {
PerformanceSummary summary = new PerformanceSummary(this, totalElapsedTime, timings.size());
Iterator<CommandSender> iterator = requests.iterator();
Iterator<PerformanceInspector> iterator = requests.iterator();
while (iterator.hasNext()) {
summary.send(iterator.next());
@ -217,16 +216,16 @@ public class SlimefunProfiler {
}
/**
* This method requests a summary for the given {@link CommandSender}.
* This method requests a summary for the given {@link PerformanceInspector}.
* The summary will be sent upon the next available moment in time.
*
* @param sender
* The {@link CommandSender} who shall receive this summary.
* @param inspector
* The {@link PerformanceInspector} who shall receive this summary.
*/
public void requestSummary(@Nonnull CommandSender sender) {
Validate.notNull(sender, "Cannot request a summary for null");
public void requestSummary(@Nonnull PerformanceInspector inspector) {
Validate.notNull(inspector, "Cannot request a summary for null");
requests.add(sender);
requests.add(inspector);
}
@Nonnull

View File

@ -0,0 +1,54 @@
package io.github.thebusybiscuit.slimefun4.core.services.profiler.inspectors;
import javax.annotation.Nonnull;
import org.apache.commons.lang.Validate;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import io.github.thebusybiscuit.slimefun4.core.services.profiler.PerformanceInspector;
/**
* This implementation of {@link PerformanceInspector} refers to a {@link CommandSender}
* which is preferabbly a {@link ConsoleCommandSender}.
* But it can theoretically be used for any type of {@link CommandSender} as it uses uncolored texts.
*
* @author TheBusyBiscuit
*
*/
public class ConsolePerformanceInspector implements PerformanceInspector {
/**
* Our reference to the actual underlying {@link CommandSender}.
*/
private final CommandSender console;
/**
* This creates a new {@link ConsolePerformanceInspector} for the given {@link CommandSender}.
*
* @param console
* The {@link CommandSender}, preferabbly a {@link ConsoleCommandSender}
*/
public ConsolePerformanceInspector(@Nonnull CommandSender console) {
Validate.notNull(console, "CommandSender cannot be null");
this.console = console;
}
@Override
public boolean isValid() {
// The console is always "online".
return true;
}
@Override
public boolean hasFullView() {
return false;
}
@Override
public void sendMessage(@Nonnull String msg) {
console.sendMessage(msg);
}
}

View File

@ -0,0 +1,74 @@
package io.github.thebusybiscuit.slimefun4.core.services.profiler.inspectors;
import java.util.UUID;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import io.github.thebusybiscuit.slimefun4.core.services.profiler.PerformanceInspector;
import net.md_5.bungee.api.chat.TextComponent;
/**
* This implementation of {@link PerformanceInspector} refers to a {@link Player}.
* It also supports {@link TextComponent TextComponents} for rich text messages.
*
* @author TheBusyBiscuit
*
*/
public class PlayerPerformanceInspector implements PerformanceInspector {
/**
* Our reference to the {@link UUID} of the {@link Player}.
*/
private final UUID uuid;
/**
* This creates a new {@link PlayerPerformanceInspector} for the given {@link Player}.
*
* @param player
* The {@link Player}
*/
public PlayerPerformanceInspector(@Nonnull Player player) {
Validate.notNull(player, "Player cannot be null");
this.uuid = player.getUniqueId();
}
@Nullable
private Player getPlayer() {
return Bukkit.getPlayer(uuid);
}
@Override
public boolean isValid() {
Player player = getPlayer();
return player != null && player.isOnline();
}
@Override
public boolean hasFullView() {
return false;
}
@Override
public void sendMessage(@Nonnull String msg) {
Player player = getPlayer();
if (player != null) {
player.sendMessage(msg);
}
}
public void sendMessage(@Nonnull TextComponent component) {
Player player = getPlayer();
if (player != null) {
player.spigot().sendMessage(component);
}
}
}

View File

@ -0,0 +1,5 @@
/**
* This package holds the different implementations of
* {@link io.github.thebusybiscuit.slimefun4.core.services.profiler.PerformanceInspector}.
*/
package io.github.thebusybiscuit.slimefun4.core.services.profiler.inspectors;

View File

@ -301,56 +301,70 @@ public final class SlimefunItems {
public static final SlimefunItemStack BOOTS_OF_THE_STOMPER = new SlimefunItemStack("BOOTS_OF_THE_STOMPER", Material.LEATHER_BOOTS, Color.AQUA, "&bBoots of the Stomper", "", "&9All Fall Damage you receive", "&9will be applied to nearby Mobs/Players", "", "&9+ No Fall Damage");
public static final SlimefunItemStack BEE_HELMET = new SlimefunItemStack("BEE_HELMET", Material.GOLDEN_HELMET, "&e&lBee Helmet", " ", "&fBzzzzzzz");
public static final SlimefunItemStack BEE_WINGS = new SlimefunItemStack("BEE_WINGS", Material.ELYTRA, "&e&lBee Wings", " ", "&fBzzzzzzz", " ", "&9Activates Slow falling", "&9when approaching the ground");
public static final SlimefunItemStack BEE_LEGGINGS = new SlimefunItemStack("BEE_LEGGINGS", Material.GOLDEN_LEGGINGS, "&e&lBee Leggings", " ", "&fBzzzzzzz");
public static final SlimefunItemStack BEE_BOOTS = new SlimefunItemStack("BEE_BOOTS", Material.GOLDEN_BOOTS, "&e&lBee Boots", "", "&fBzzzzzzz", "", "&9+ Jump Boost", "&9+ No Fall Damage");
static {
Map<Enchantment, Integer> cactus = new HashMap<>();
cactus.put(Enchantment.THORNS, 3);
cactus.put(Enchantment.DURABILITY, 6);
Map<Enchantment, Integer> cactusEnchs = new HashMap<>();
cactusEnchs.put(Enchantment.THORNS, 3);
cactusEnchs.put(Enchantment.DURABILITY, 6);
CACTUS_HELMET.addUnsafeEnchantments(cactus);
CACTUS_CHESTPLATE.addUnsafeEnchantments(cactus);
CACTUS_LEGGINGS.addUnsafeEnchantments(cactus);
CACTUS_BOOTS.addUnsafeEnchantments(cactus);
CACTUS_HELMET.addUnsafeEnchantments(cactusEnchs);
CACTUS_CHESTPLATE.addUnsafeEnchantments(cactusEnchs);
CACTUS_LEGGINGS.addUnsafeEnchantments(cactusEnchs);
CACTUS_BOOTS.addUnsafeEnchantments(cactusEnchs);
Map<Enchantment, Integer> damascus = new HashMap<>();
damascus.put(Enchantment.DURABILITY, 5);
damascus.put(Enchantment.PROTECTION_ENVIRONMENTAL, 5);
Map<Enchantment, Integer> damascusEnchs = new HashMap<>();
damascusEnchs.put(Enchantment.DURABILITY, 5);
damascusEnchs.put(Enchantment.PROTECTION_ENVIRONMENTAL, 5);
DAMASCUS_STEEL_HELMET.addUnsafeEnchantments(damascus);
DAMASCUS_STEEL_CHESTPLATE.addUnsafeEnchantments(damascus);
DAMASCUS_STEEL_LEGGINGS.addUnsafeEnchantments(damascus);
DAMASCUS_STEEL_BOOTS.addUnsafeEnchantments(damascus);
DAMASCUS_STEEL_HELMET.addUnsafeEnchantments(damascusEnchs);
DAMASCUS_STEEL_CHESTPLATE.addUnsafeEnchantments(damascusEnchs);
DAMASCUS_STEEL_LEGGINGS.addUnsafeEnchantments(damascusEnchs);
DAMASCUS_STEEL_BOOTS.addUnsafeEnchantments(damascusEnchs);
Map<Enchantment, Integer> reinforced = new HashMap<>();
reinforced.put(Enchantment.DURABILITY, 9);
reinforced.put(Enchantment.PROTECTION_ENVIRONMENTAL, 9);
Map<Enchantment, Integer> reinforcedEnchs = new HashMap<>();
reinforcedEnchs.put(Enchantment.DURABILITY, 9);
reinforcedEnchs.put(Enchantment.PROTECTION_ENVIRONMENTAL, 9);
REINFORCED_ALLOY_HELMET.addUnsafeEnchantments(reinforced);
REINFORCED_ALLOY_CHESTPLATE.addUnsafeEnchantments(reinforced);
REINFORCED_ALLOY_LEGGINGS.addUnsafeEnchantments(reinforced);
REINFORCED_ALLOY_BOOTS.addUnsafeEnchantments(reinforced);
REINFORCED_ALLOY_HELMET.addUnsafeEnchantments(reinforcedEnchs);
REINFORCED_ALLOY_CHESTPLATE.addUnsafeEnchantments(reinforcedEnchs);
REINFORCED_ALLOY_LEGGINGS.addUnsafeEnchantments(reinforcedEnchs);
REINFORCED_ALLOY_BOOTS.addUnsafeEnchantments(reinforcedEnchs);
Map<Enchantment, Integer> gilded = new HashMap<>();
gilded.put(Enchantment.DURABILITY, 6);
gilded.put(Enchantment.PROTECTION_ENVIRONMENTAL, 8);
Map<Enchantment, Integer> gildedEnchs = new HashMap<>();
gildedEnchs.put(Enchantment.DURABILITY, 6);
gildedEnchs.put(Enchantment.PROTECTION_ENVIRONMENTAL, 8);
GILDED_IRON_HELMET.addUnsafeEnchantments(gilded);
GILDED_IRON_CHESTPLATE.addUnsafeEnchantments(gilded);
GILDED_IRON_LEGGINGS.addUnsafeEnchantments(gilded);
GILDED_IRON_BOOTS.addUnsafeEnchantments(gilded);
GILDED_IRON_HELMET.addUnsafeEnchantments(gildedEnchs);
GILDED_IRON_CHESTPLATE.addUnsafeEnchantments(gildedEnchs);
GILDED_IRON_LEGGINGS.addUnsafeEnchantments(gildedEnchs);
GILDED_IRON_BOOTS.addUnsafeEnchantments(gildedEnchs);
GOLDEN_HELMET_12K.addUnsafeEnchantment(Enchantment.DURABILITY, 10);
GOLDEN_CHESTPLATE_12K.addUnsafeEnchantment(Enchantment.DURABILITY, 10);
GOLDEN_LEGGINGS_12K.addUnsafeEnchantment(Enchantment.DURABILITY, 10);
GOLDEN_BOOTS_12K.addUnsafeEnchantment(Enchantment.DURABILITY, 10);
Map<Enchantment, Integer> slime = new HashMap<>();
slime.put(Enchantment.DURABILITY, 4);
slime.put(Enchantment.PROTECTION_ENVIRONMENTAL, 2);
Map<Enchantment, Integer> slimeEnchs = new HashMap<>();
slimeEnchs.put(Enchantment.DURABILITY, 4);
slimeEnchs.put(Enchantment.PROTECTION_ENVIRONMENTAL, 2);
SLIME_HELMET_STEEL.addUnsafeEnchantments(slime);
SLIME_CHESTPLATE_STEEL.addUnsafeEnchantments(slime);
SLIME_LEGGINGS_STEEL.addUnsafeEnchantments(slime);
SLIME_BOOTS_STEEL.addUnsafeEnchantments(slime);
SLIME_HELMET_STEEL.addUnsafeEnchantments(slimeEnchs);
SLIME_CHESTPLATE_STEEL.addUnsafeEnchantments(slimeEnchs);
SLIME_LEGGINGS_STEEL.addUnsafeEnchantments(slimeEnchs);
SLIME_BOOTS_STEEL.addUnsafeEnchantments(slimeEnchs);
Map<Enchantment, Integer> beeEnchs = new HashMap<>();
beeEnchs.put(Enchantment.DURABILITY, 4);
beeEnchs.put(Enchantment.PROTECTION_ENVIRONMENTAL, 2);
BEE_HELMET.addUnsafeEnchantments(beeEnchs);
BEE_WINGS.addUnsafeEnchantments(beeEnchs);
BEE_LEGGINGS.addUnsafeEnchantments(beeEnchs);
BEE_BOOTS.addUnsafeEnchantments(beeEnchs);
}
/* Magical components */

View File

@ -27,7 +27,6 @@ import org.bukkit.plugin.java.JavaPluginLoader;
import org.bukkit.scheduler.BukkitTask;
import io.github.thebusybiscuit.cscorelib2.config.Config;
import io.github.thebusybiscuit.cscorelib2.math.DoubleHandler;
import io.github.thebusybiscuit.cscorelib2.protection.ProtectionManager;
import io.github.thebusybiscuit.cscorelib2.reflection.ReflectionUtils;
import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion;
@ -56,12 +55,13 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.altar.AncientAlta
import io.github.thebusybiscuit.slimefun4.implementation.items.altar.AncientPedestal;
import io.github.thebusybiscuit.slimefun4.implementation.items.backpacks.Cooler;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.reactors.Reactor;
import io.github.thebusybiscuit.slimefun4.implementation.items.magical.BeeWings;
import io.github.thebusybiscuit.slimefun4.implementation.items.tools.GrapplingHook;
import io.github.thebusybiscuit.slimefun4.implementation.items.weapons.SeismicAxe;
import io.github.thebusybiscuit.slimefun4.implementation.items.weapons.VampireBlade;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.AncientAltarListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.BackpackListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.BeeListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.BeeWingsListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.BlockListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.BlockPhysicsListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.ButcherAndroidListener;
@ -72,18 +72,13 @@ import io.github.thebusybiscuit.slimefun4.implementation.listeners.DebugFishList
import io.github.thebusybiscuit.slimefun4.implementation.listeners.DispenserListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.ElytraImpactListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.EnhancedFurnaceListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.EntityInteractionListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.ExplosionsListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.FireworksListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.GadgetsListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.GrapplingHookListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.IronGolemListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.ItemDropListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.ItemPickupListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.MobDropListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.MultiBlockListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.NetworkListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.PiglinListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.PlayerProfileListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.SeismicAxeListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.SlimefunBootsListener;
@ -95,7 +90,6 @@ import io.github.thebusybiscuit.slimefun4.implementation.listeners.SoulboundList
import io.github.thebusybiscuit.slimefun4.implementation.listeners.TalismanListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.VampireBladeListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.VillagerTradingListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.WitherListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.WorldListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.crafting.AnvilListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.crafting.BrewingStandListener;
@ -103,6 +97,13 @@ import io.github.thebusybiscuit.slimefun4.implementation.listeners.crafting.Cart
import io.github.thebusybiscuit.slimefun4.implementation.listeners.crafting.CauldronListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.crafting.CraftingTableListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.crafting.GrindstoneListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.entity.BeeListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.entity.EntityInteractionListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.entity.FireworksListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.entity.IronGolemListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.entity.MobDropListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.entity.PiglinListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.entity.WitherListener;
import io.github.thebusybiscuit.slimefun4.implementation.resources.GEOResourcesSetup;
import io.github.thebusybiscuit.slimefun4.implementation.setup.PostSetup;
import io.github.thebusybiscuit.slimefun4.implementation.setup.ResearchSetup;
@ -110,6 +111,8 @@ import io.github.thebusybiscuit.slimefun4.implementation.setup.SlimefunItemSetup
import io.github.thebusybiscuit.slimefun4.implementation.tasks.ArmorTask;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.SlimefunStartupTask;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.TickerTask;
import io.github.thebusybiscuit.slimefun4.integrations.IntegrationsManager;
import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag;
import io.papermc.lib.PaperLib;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AContainer;
@ -145,8 +148,9 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
private final BackupService backupService = new BackupService();
private final PermissionsService permissionsService = new PermissionsService(this);
private final PerWorldSettingsService worldSettingsService = new PerWorldSettingsService(this);
private final ThirdPartyPluginService thirdPartySupportService = new ThirdPartyPluginService(this);
private final MinecraftRecipeService recipeService = new MinecraftRecipeService(this);
private final IntegrationsManager integrations = new ThirdPartyPluginService(this);
private final SlimefunProfiler profiler = new SlimefunProfiler();
private LocalizationService local;
@ -196,121 +200,26 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
*/
@Override
public void onEnable() {
instance = this;
if (minecraftVersion == MinecraftVersion.UNIT_TEST) {
// We handle Unit Tests seperately.
setInstance(this);
getLogger().log(Level.INFO, "This is a UNIT TEST Environment.");
onUnitTestStart();
} else if (isVersionUnsupported()) {
// We wanna ensure that the Server uses a compatible version of Minecraft.
setInstance(this);
getLogger().log(Level.WARNING, "Slimefun was not installed properly! Disabling...");
getServer().getPluginManager().disablePlugin(this);
} else if (getServer().getPluginManager().isPluginEnabled("CS-CoreLib")) {
// The Environment and dependencies have been validated.
setInstance(this);
getLogger().log(Level.INFO, "CS-CoreLib was detected!");
long timestamp = System.nanoTime();
PaperLib.suggestPaper(this);
if (PaperLib.isPaper()) {
getLogger().log(Level.INFO, "Paper was detected! Performance optimizations have been applied.");
}
// We wanna ensure that the Server uses a compatible version of Minecraft
if (isVersionUnsupported()) {
getServer().getPluginManager().disablePlugin(this);
return;
}
// Disabling backwards-compatibility for fresh Slimefun installs
if (!new File("data-storage/Slimefun").exists()) {
config.setValue("options.backwards-compatibility", false);
config.save();
isNewlyInstalled = true;
}
// Creating all necessary Folders
getLogger().log(Level.INFO, "Creating directories...");
createDirectories();
registry.load(config);
// Set up localization
getLogger().log(Level.INFO, "Loading language files...");
local = new LocalizationService(this, config.getString("options.chat-prefix"), config.getString("options.language"));
// Setting up Networks
gpsNetwork = new GPSNetwork();
int networkSize = config.getInt("networks.max-size");
if (networkSize < 1) {
getLogger().log(Level.WARNING, "Your 'networks.max-size' setting is misconfigured! It must be at least 1, it was set to: {0}", networkSize);
networkSize = 1;
}
networkManager = new NetworkManager(networkSize, config.getBoolean("networks.enable-visualizer"), config.getBoolean("networks.delete-excess-items"));
// Setting up bStats
new Thread(metricsService::start, "Slimefun Metrics").start();
// Starting the Auto-Updater
if (config.getBoolean("options.auto-update")) {
getLogger().log(Level.INFO, "Starting Auto-Updater...");
updaterService.start();
} else {
updaterService.disable();
}
// Registering all GEO Resources
getLogger().log(Level.INFO, "Loading GEO-Resources...");
GEOResourcesSetup.setup();
getLogger().log(Level.INFO, "Loading Tags...");
loadTags();
getLogger().log(Level.INFO, "Loading items...");
loadItems();
getLogger().log(Level.INFO, "Loading researches...");
loadResearches();
registry.setResearchingEnabled(getResearchCfg().getBoolean("enable-researching"));
PostSetup.setupWiki();
getLogger().log(Level.INFO, "Registering listeners...");
registerListeners();
// Initiating various Stuff and all items with a slight delay (0ms after the Server finished loading)
runSync(new SlimefunStartupTask(this, () -> {
protections = new ProtectionManager(getServer());
textureService.register(registry.getAllSlimefunItems(), true);
permissionsService.register(registry.getAllSlimefunItems(), true);
// This try/catch should prevent buggy Spigot builds from blocking item loading
try {
recipeService.refresh();
} catch (Exception | LinkageError x) {
getLogger().log(Level.SEVERE, x, () -> "An Exception occurred while iterating through the Recipe list on Minecraft Version " + minecraftVersion.getName() + " (Slimefun v" + getVersion() + ")");
}
}), 0);
// Setting up the command /sf and all subcommands
command.register();
// Armor Update Task
if (config.getBoolean("options.enable-armor-effects")) {
boolean radioactiveFire = config.getBoolean("options.burn-players-when-radioactive");
getServer().getScheduler().runTaskTimerAsynchronously(this, new ArmorTask(radioactiveFire), 0L, config.getInt("options.armor-update-interval") * 20L);
}
autoSavingService.start(this, config.getInt("options.auto-save-delay-in-minutes"));
ticker.start(this);
getLogger().log(Level.INFO, "Loading Third-Party plugin integrations...");
thirdPartySupportService.start();
gitHubService.start(this);
// Hooray!
getLogger().log(Level.INFO, "Slimefun has finished loading in {0}", getStartupTime(timestamp));
onPluginStart();
} else {
instance = null;
// Terminate our Plugin instance
setInstance(null);
// CS-CoreLib has not been installed!
getLogger().log(Level.INFO, "#################### - INFO - ####################");
getLogger().log(Level.INFO, " ");
getLogger().log(Level.INFO, "Slimefun could not be loaded (yet).");
@ -338,6 +247,112 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
loadTags();
}
/**
* This is our start method for a correct Slimefun installation.
*/
private void onPluginStart() {
long timestamp = System.nanoTime();
if (PaperLib.isPaper()) {
getLogger().log(Level.INFO, "Paper was detected! Performance optimizations have been applied.");
} else {
PaperLib.suggestPaper(this);
}
// Disabling backwards-compatibility for fresh Slimefun installs
if (!new File("data-storage/Slimefun").exists()) {
config.setValue("options.backwards-compatibility", false);
config.save();
isNewlyInstalled = true;
}
// Creating all necessary Folders
getLogger().log(Level.INFO, "Creating directories...");
createDirectories();
registry.load(config);
// Set up localization
getLogger().log(Level.INFO, "Loading language files...");
local = new LocalizationService(this, config.getString("options.chat-prefix"), config.getString("options.language"));
// Setting up Networks
gpsNetwork = new GPSNetwork();
int networkSize = config.getInt("networks.max-size");
if (networkSize < 1) {
getLogger().log(Level.WARNING, "Your 'networks.max-size' setting is misconfigured! It must be at least 1, it was set to: {0}", networkSize);
networkSize = 1;
}
networkManager = new NetworkManager(networkSize, config.getBoolean("networks.enable-visualizer"), config.getBoolean("networks.delete-excess-items"));
// Setting up bStats
new Thread(metricsService::start, "Slimefun Metrics").start();
// Starting the Auto-Updater
if (config.getBoolean("options.auto-update")) {
getLogger().log(Level.INFO, "Starting Auto-Updater...");
updaterService.start();
} else {
updaterService.disable();
}
// Registering all GEO Resources
getLogger().log(Level.INFO, "Loading GEO-Resources...");
GEOResourcesSetup.setup();
getLogger().log(Level.INFO, "Loading Tags...");
loadTags();
getLogger().log(Level.INFO, "Loading items...");
loadItems();
getLogger().log(Level.INFO, "Loading researches...");
loadResearches();
registry.setResearchingEnabled(getResearchCfg().getBoolean("enable-researching"));
PostSetup.setupWiki();
getLogger().log(Level.INFO, "Registering listeners...");
registerListeners();
// Initiating various Stuff and all items with a slight delay (0ms after the Server finished loading)
runSync(new SlimefunStartupTask(this, () -> {
protections = new ProtectionManager(getServer());
textureService.register(registry.getAllSlimefunItems(), true);
permissionsService.register(registry.getAllSlimefunItems(), true);
// This try/catch should prevent buggy Spigot builds from blocking item loading
try {
recipeService.refresh();
} catch (Exception | LinkageError x) {
getLogger().log(Level.SEVERE, x, () -> "An Exception occurred while iterating through the Recipe list on Minecraft Version " + minecraftVersion.getName() + " (Slimefun v" + getVersion() + ")");
}
}), 0);
// Setting up the command /sf and all subcommands
command.register();
// Armor Update Task
if (config.getBoolean("options.enable-armor-effects")) {
boolean radioactiveFire = config.getBoolean("options.burn-players-when-radioactive");
getServer().getScheduler().runTaskTimerAsynchronously(this, new ArmorTask(radioactiveFire), 0L, config.getInt("options.armor-update-interval") * 20L);
}
autoSavingService.start(this, config.getInt("options.auto-save-delay-in-minutes"));
ticker.start(this);
getLogger().log(Level.INFO, "Loading Third-Party plugin integrations...");
integrations.start();
gitHubService.start(this);
// Hooray!
getLogger().log(Level.INFO, "Slimefun has finished loading in {0}", getStartupTime(timestamp));
}
/**
* This method gets called when the {@link Plugin} gets disabled.
* Most often it is called when the {@link Server} is shutting down or reloading.
@ -385,20 +400,11 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
// Close and unload any resources from our Metrics Service
metricsService.cleanUp();
/**
* Prevent Memory Leaks for reloads...
* These static Maps should really be removed at some point...
*/
AContainer.processing = null;
AContainer.progress = null;
// Terminate our Plugin instance
setInstance(null);
AGenerator.processing = null;
AGenerator.progress = null;
Reactor.processing = null;
Reactor.progress = null;
instance = null;
// Clean up any static fields
cleanUp();
/**
* Close all inventories on the server to prevent item dupes
@ -409,17 +415,47 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
}
}
/**
* This is a private internal method to set the de-facto instance of {@link SlimefunPlugin}.
* Having this as a seperate method ensures the seperation between static and non-static fields.
* It also makes sonarcloud happy :)
* Only ever use it during {@link #onEnable()} or {@link #onDisable()}.
*
* @param pluginInstance
* Our instance of {@link SlimefunPlugin} or null
*/
private static void setInstance(@Nullable SlimefunPlugin pluginInstance) {
instance = pluginInstance;
}
@Nonnull
private String getStartupTime(long timestamp) {
long ms = (System.nanoTime() - timestamp) / 1000000;
if (ms > 1000) {
return DoubleHandler.fixDouble(ms / 1000.0) + "s";
return NumberUtils.roundDecimalNumber(ms / 1000.0) + "s";
} else {
return DoubleHandler.fixDouble(ms) + "ms";
return NumberUtils.roundDecimalNumber(ms) + "ms";
}
}
/**
* Cleaning up our static fields prevents memory leaks from a reload.
*
* @deprecated These static Maps should really be removed at some point...
*/
@Deprecated
private static void cleanUp() {
AContainer.processing = null;
AContainer.progress = null;
AGenerator.processing = null;
AGenerator.progress = null;
Reactor.processing = null;
Reactor.progress = null;
}
/**
* This method checks for the {@link MinecraftVersion} of the {@link Server}.
* If the version is unsupported, a warning will be printed to the console.
@ -427,30 +463,60 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
* @return Whether the {@link MinecraftVersion} is unsupported
*/
private boolean isVersionUnsupported() {
String currentVersion = ReflectionUtils.getVersion();
try {
// First check if they still use the unsupported CraftBukkit software.
if (!PaperLib.isSpigot() && Bukkit.getName().equals("CraftBukkit")) {
getLogger().log(Level.SEVERE, "###############################################");
getLogger().log(Level.SEVERE, "### Slimefun was not installed correctly!");
getLogger().log(Level.SEVERE, "### CraftBukkit is no longer supported!");
getLogger().log(Level.SEVERE, "###");
getLogger().log(Level.SEVERE, "### Slimefun requires you to use Spigot, Paper or");
getLogger().log(Level.SEVERE, "### any supported fork of Spigot or Paper.");
getLogger().log(Level.SEVERE, "### (We recommend Paper)");
getLogger().log(Level.SEVERE, "###############################################");
if (currentVersion.startsWith("v")) {
for (MinecraftVersion version : MinecraftVersion.valuesCache) {
if (version.matches(currentVersion)) {
minecraftVersion = version;
return false;
}
return true;
}
// Looks like you are using an unsupported Minecraft Version
getLogger().log(Level.SEVERE, "#############################################");
getLogger().log(Level.SEVERE, "### Slimefun was not installed correctly!");
getLogger().log(Level.SEVERE, "### You are using the wrong version of Minecraft!");
getLogger().log(Level.SEVERE, "###");
getLogger().log(Level.SEVERE, "### You are using Minecraft {0}", currentVersion);
getLogger().log(Level.SEVERE, "### but Slimefun {0} requires you to be using", getDescription().getVersion());
getLogger().log(Level.SEVERE, "### Minecraft {0}", String.join(" / ", getSupportedVersions()));
getLogger().log(Level.SEVERE, "#############################################");
// Now check the actual Version of Minecraft
String currentVersion = ReflectionUtils.getVersion();
if (currentVersion.startsWith("v")) {
// Check all supported versions of Minecraft
for (MinecraftVersion version : MinecraftVersion.valuesCache) {
if (version.matches(currentVersion)) {
minecraftVersion = version;
return false;
}
}
// Looks like you are using an unsupported Minecraft Version
getLogger().log(Level.SEVERE, "#############################################");
getLogger().log(Level.SEVERE, "### Slimefun was not installed correctly!");
getLogger().log(Level.SEVERE, "### You are using the wrong version of Minecraft!");
getLogger().log(Level.SEVERE, "###");
getLogger().log(Level.SEVERE, "### You are using Minecraft {0}", currentVersion);
getLogger().log(Level.SEVERE, "### but Slimefun {0} requires you to be using", getDescription().getVersion());
getLogger().log(Level.SEVERE, "### Minecraft {0}", String.join(" / ", getSupportedVersions()));
getLogger().log(Level.SEVERE, "#############################################");
return true;
}
getLogger().log(Level.WARNING, "We could not determine the version of Minecraft you were using ({0})", currentVersion);
/*
* If we are unsure about it, we will assume "supported".
* They could be using a non-Bukkit based Software which still
* might support Bukkit-based plugins.
* Use at your own risk in this case.
*/
return false;
} catch (Exception | LinkageError x) {
getLogger().log(Level.SEVERE, x, () -> "Error: Could not determine Environment or version of Minecraft for Slimefun v" + getDescription().getVersion());
// We assume "unsupported" if something went wrong.
return true;
}
getLogger().log(Level.WARNING, "We could not determine the version of Minecraft you were using ({0})", currentVersion);
return false;
}
@Nonnull
@ -525,6 +591,7 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
// Bees were added in 1.15
if (minecraftVersion.isAtLeast(MinecraftVersion.MINECRAFT_1_15)) {
new BeeListener(this);
new BeeWingsListener(this, (BeeWings) SlimefunItems.BEE_WINGS.getItem());
}
// Piglins were added in 1.16
@ -662,14 +729,33 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
return instance.blockDataService;
}
public static ThirdPartyPluginService getThirdPartySupportService() {
return instance.thirdPartySupportService;
}
public static PerWorldSettingsService getWorldSettingsService() {
return instance.worldSettingsService;
}
/**
* This method has been renamed.
*
* @deprecated Please use {@link #getIntegrations()} instead.
*
* @return the {@link ThirdPartyPluginService}
*/
@Deprecated
public static ThirdPartyPluginService getThirdPartySupportService() {
return (ThirdPartyPluginService) instance.integrations;
}
/**
* This returns our instance of {@link IntegrationsManager}.
* This is responsible for managing any integrations with third party {@link Plugin plugins}.
*
* @return Our instance of {@link IntegrationsManager}
*/
@Nonnull
public static IntegrationsManager getIntegrations() {
return instance.integrations;
}
/**
* This method returns the {@link UpdaterService} of Slimefun.
* It is used to handle automatic updates.
@ -730,7 +816,15 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
*/
@Nonnull
public static Set<Plugin> getInstalledAddons() {
return Arrays.stream(instance.getServer().getPluginManager().getPlugins()).filter(plugin -> plugin.getDescription().getDepend().contains(instance.getName()) || plugin.getDescription().getSoftDepend().contains(instance.getName())).collect(Collectors.toSet());
String pluginName = instance.getName();
// @formatter:off
return Arrays.stream(instance.getServer().getPluginManager().getPlugins())
.filter(plugin -> {
PluginDescriptionFile description = plugin.getDescription();
return description.getDepend().contains(pluginName) || description.getSoftDepend().contains(pluginName);
}).collect(Collectors.toSet());
// @formatter:on
}
/**

View File

@ -2,6 +2,8 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.androids;
import java.util.Optional;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Effect;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
@ -25,6 +27,7 @@ import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
*/
public class AdvancedFarmerAndroid extends FarmerAndroid {
@ParametersAreNonnullByDefault
public AdvancedFarmerAndroid(Category category, int tier, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, tier, item, recipeType, recipe);
}
@ -38,7 +41,7 @@ public class AdvancedFarmerAndroid extends FarmerAndroid {
protected void exoticFarm(BlockMenu menu, Block block) {
farm(menu, block);
if (SlimefunPlugin.getThirdPartySupportService().isExoticGardenInstalled()) {
if (SlimefunPlugin.getIntegrations().isExoticGardenInstalled()) {
Optional<ItemStack> result = SlimefunPlugin.getThirdPartySupportService().harvestExoticGardenPlant(block);
if (result.isPresent()) {

View File

@ -673,6 +673,7 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock,
}
}
@ParametersAreNonnullByDefault
private void executeInstruction(Instruction instruction, Block b, BlockMenu inv, Config data, int index) {
if (getAndroidType().isType(instruction.getRequiredType())) {
String rotationData = data.getString("rotation");
@ -830,11 +831,16 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock,
preset.addItem(34, getFuelSource().getItem(), ChestMenuUtils.getEmptyClickHandler());
}
@ParametersAreNonnullByDefault
public void addItems(Block b, ItemStack... items) {
Validate.notNull(b, "The Block cannot be null.");
BlockMenu inv = BlockStorage.getInventory(b);
for (ItemStack item : items) {
inv.pushItem(item, getOutputSlots());
if (inv != null) {
for (ItemStack item : items) {
inv.pushItem(item, getOutputSlots());
}
}
}

View File

@ -0,0 +1,27 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.armor;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.entity.EnderPearl;
import org.bukkit.inventory.ItemStack;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
/**
* {@link EnderBoots} are a pair of boots which negate damage caused
* by throwing an {@link EnderPearl}.
*
* @author TheBusyBiscuit
*
*/
public class EnderBoots extends SlimefunItem {
@ParametersAreNonnullByDefault
public EnderBoots(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
}
}

View File

@ -0,0 +1,28 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.armor;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
/**
* {@link LongFallBoots} are a pair of boots which negate fall damage.
* Nameworthy examples of this are Slime Boots and Bee Boots.
*
* <i>Yes, you just found a Portal reference :P</i>
*
* @author TheBusyBiscuit
*
*/
public class LongFallBoots extends SlimefunArmorPiece {
@ParametersAreNonnullByDefault
public LongFallBoots(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, PotionEffect[] effects) {
super(category, item, recipeType, recipe, effects);
}
}

View File

@ -1,5 +1,7 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.armor;
import javax.annotation.Nonnull;
import org.bukkit.Bukkit;
import org.bukkit.Effect;
import org.bukkit.Location;
@ -42,30 +44,30 @@ public class StomperBoots extends SlimefunItem {
* The {@link EntityDamageEvent} in which the {@link Player} has taken fall damage
*/
public void stomp(EntityDamageEvent fallDamageEvent) {
Player p = (Player) fallDamageEvent.getEntity();
p.getWorld().playSound(p.getLocation(), Sound.ENTITY_ZOMBIE_BREAK_WOODEN_DOOR, 1F, 2F);
p.setVelocity(new Vector(0, 0.7, 0));
Player player = (Player) fallDamageEvent.getEntity();
player.getWorld().playSound(player.getLocation(), Sound.ENTITY_ZOMBIE_BREAK_WOODEN_DOOR, 1F, 2F);
player.setVelocity(new Vector(0, 0.7, 0));
for (Entity n : p.getNearbyEntities(4, 4, 4)) {
if (n instanceof LivingEntity && n.isValid() && !n.getUniqueId().equals(p.getUniqueId())) {
Vector velocity = getShockwave(p.getLocation(), n.getLocation());
n.setVelocity(velocity);
for (Entity entity : player.getNearbyEntities(4, 4, 4)) {
if (entity instanceof LivingEntity && canPush(player, (LivingEntity) entity)) {
Vector velocity = getShockwave(player.getLocation(), entity.getLocation());
entity.setVelocity(velocity);
// Check if it's not a Player or if PvP is enabled
if (!(n instanceof Player) || (p.getWorld().getPVP() && SlimefunPlugin.getProtectionManager().hasPermission(p, n.getLocation(), ProtectableAction.ATTACK_PLAYER))) {
EntityDamageByEntityEvent event = new EntityDamageByEntityEvent(p, n, DamageCause.ENTITY_ATTACK, fallDamageEvent.getDamage() / 2);
if (!(entity instanceof Player) || (player.getWorld().getPVP() && SlimefunPlugin.getProtectionManager().hasPermission(player, entity.getLocation(), ProtectableAction.ATTACK_PLAYER))) {
EntityDamageByEntityEvent event = new EntityDamageByEntityEvent(player, entity, DamageCause.ENTITY_ATTACK, fallDamageEvent.getDamage() / 2);
Bukkit.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
((LivingEntity) n).damage(event.getDamage());
((LivingEntity) entity).damage(event.getDamage());
}
}
}
}
for (BlockFace face : BlockFace.values()) {
Block b = p.getLocation().getBlock().getRelative(BlockFace.DOWN).getRelative(face);
p.getWorld().playEffect(b.getLocation(), Effect.STEP_SOUND, b.getType());
Block block = player.getLocation().getBlock().getRelative(BlockFace.DOWN).getRelative(face);
player.getWorld().playEffect(block.getLocation(), Effect.STEP_SOUND, block.getType());
}
}
@ -79,7 +81,7 @@ public class StomperBoots extends SlimefunItem {
*
* @return A {@link Vector} to determine the velocity for our {@link Entity}
*/
private Vector getShockwave(Location origin, Location target) {
private Vector getShockwave(@Nonnull Location origin, @Nonnull Location target) {
// As the distance approaches zero we might slip into a "division by zero" when normalizing
if (origin.distanceSquared(target) < 0.05) {
return new Vector(0, 1, 0);
@ -89,4 +91,21 @@ public class StomperBoots extends SlimefunItem {
}
}
/**
* Checks if the stomper boots can move an entity and is not the player who is using the boots.
* <p>
* <b>For developers:</b> If you're spawning an immovable NPC, you should be denying
* collision with {@link LivingEntity#setCollidable(boolean)} or
* gravity with {@link LivingEntity#setGravity(boolean)}.
*
* @param entity
* The {@link LivingEntity} to check.
* @param player
* The {@link Player} using the {@link StomperBoots}.
* @return If the entity can move.
*/
protected boolean canPush(@Nonnull Player player, @Nonnull LivingEntity entity) {
return entity.isValid() && !entity.getUniqueId().equals(player.getUniqueId())
&& entity.isCollidable() && entity.hasGravity();
}
}

View File

@ -86,7 +86,7 @@ abstract class AbstractCargoNode extends SimpleSlimefunItem<BlockPlaceHandler> {
@ParametersAreNonnullByDefault
protected void addChannelSelector(Block b, BlockMenu menu, int slotPrev, int slotCurrent, int slotNext) {
boolean isChestTerminalInstalled = SlimefunPlugin.getThirdPartySupportService().isChestTerminalInstalled();
boolean isChestTerminalInstalled = SlimefunPlugin.getIntegrations().isChestTerminalInstalled();
int channel = getSelectedChannel(b);
menu.replaceExistingItem(slotPrev, new CustomItem(HeadTexture.CARGO_ARROW_LEFT.getAsItemStack(), "&bPrevious Channel", "", "&e> Click to decrease the Channel ID by 1"));

View File

@ -0,0 +1,19 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.magical;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.inventory.ItemStack;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
public class BeeWings extends SlimefunItem {
@ParametersAreNonnullByDefault
public BeeWings(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
}
}

View File

@ -115,6 +115,8 @@ class ExplosiveTool extends SimpleSlimefunItem<ToolUseHandler> implements NotPla
return false;
} else if (!b.getWorld().getWorldBorder().isInside(b.getLocation())) {
return false;
} else if (SlimefunPlugin.getIntegrations().isCustomBlock(b)) {
return false;
} else {
return SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.BREAK_BLOCK);
}

View File

@ -0,0 +1,51 @@
package io.github.thebusybiscuit.slimefun4.implementation.listeners;
import javax.annotation.Nonnull;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityToggleGlideEvent;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.magical.BeeWings;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.BeeWingsTask;
import me.mrCookieSlime.Slimefun.api.Slimefun;
/**
* This {@link Listener} is responsible for the slow falling effect given to the {@link Player}
* when nearing the ground while using the {@link BeeWings}.
*
* @author beSnow
* @author Linox
* @author TheBusyBiscuit
*
* @see BeeWings
* @see BeeWingsTask
*
*/
public class BeeWingsListener implements Listener {
private final BeeWings wings;
public BeeWingsListener(@Nonnull SlimefunPlugin plugin, @Nonnull BeeWings wings) {
plugin.getServer().getPluginManager().registerEvents(this, plugin);
this.wings = wings;
}
@EventHandler(ignoreCancelled = true)
public void onApproachGround(EntityToggleGlideEvent e) {
if (!e.isGliding() || wings.isDisabled() || !(e.getEntity() instanceof Player)) {
return;
}
Player player = (Player) e.getEntity();
ItemStack chestplate = player.getInventory().getChestplate();
if (wings.isItem(chestplate) && Slimefun.hasUnlocked(player, chestplate, true)) {
new BeeWingsTask(player).scheduleRepeating(3, 1);
}
}
}

View File

@ -41,6 +41,7 @@ import me.mrCookieSlime.Slimefun.api.Slimefun;
*
* @author TheBusyBiscuit
* @author Linox
* @author Patbox
*
* @see BlockPlaceHandler
* @see BlockBreakHandler
@ -55,10 +56,27 @@ public class BlockListener implements Listener {
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onBlockPlaceExisting(BlockPlaceEvent e) {
// This prevents Players from placing a block where another block already exists
// While this can cause ghost blocks it also prevents them from replacing grass
// or saplings etc...
if (BlockStorage.hasBlockInfo(e.getBlock())) {
/*
* This prevents Players from placing a block where another block already exists.
* While this can cause ghost blocks it also prevents them from replacing grass
* or saplings etc...
*/
Block block = e.getBlock();
if (e.getBlockReplacedState().getType().isAir()) {
SlimefunItem sfItem = BlockStorage.check(block);
if (sfItem != null) {
/* Temp fix for #2636
for (ItemStack item : sfItem.getDrops()) {
if (item != null && !item.getType().isAir()) {
block.getWorld().dropItemNaturally(block.getLocation(), item);
}
}
*/
BlockStorage.clearBlockInfo(block);
}
} else if (BlockStorage.hasBlockInfo(e.getBlock())) {
e.setCancelled(true);
}
}
@ -84,8 +102,13 @@ public class BlockListener implements Listener {
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onBlockBreak(BlockBreakEvent e) {
if (SlimefunPlugin.getThirdPartySupportService().isEventFaked(e)) {
// This is a "fake" event, we can ignore it.
// Simply ignore any events that were faked by other plugins
if (SlimefunPlugin.getIntegrations().isEventFaked(e)) {
return;
}
// Also ignore custom blocks which were placed by other plugins
if (SlimefunPlugin.getIntegrations().isCustomBlock(e.getBlock())) {
return;
}

View File

@ -68,7 +68,8 @@ public class ButcherAndroidListener implements Listener {
}
/**
* Some items are not dropped by default. Wither Skeleton Skulls but for some weird reason
* Some items are not dropped by default.
* Wither Skeleton Skulls but for some weird reason
* even Blaze rods...
*
* @param drops

View File

@ -6,6 +6,7 @@ import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.Skull;
@ -86,9 +87,14 @@ public class DebugFishListener implements Listener {
@ParametersAreNonnullByDefault
private void onRightClick(Player p, Block b, BlockFace face) {
if (p.isSneaking()) {
Block block = b.getRelative(face);
block.setType(Material.PLAYER_HEAD);
SkullBlock.setFromHash(block, HeadTexture.MISSING_TEXTURE.getTexture());
// Fixes #2655 - Delaying the placement to prevent a new event from being fired
SlimefunPlugin.runSync(() -> {
Block block = b.getRelative(face);
block.setType(Material.PLAYER_HEAD);
SkullBlock.setFromHash(block, HeadTexture.MISSING_TEXTURE.getTexture());
p.playSound(block.getLocation(), Sound.BLOCK_BAMBOO_PLACE, 1, 1);
}, 2L);
} else if (BlockStorage.hasBlockInfo(b)) {
try {
sendInfo(p, b);

View File

@ -10,7 +10,6 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import org.bukkit.Location;
import org.bukkit.entity.Arrow;
import org.bukkit.entity.Bat;
@ -21,16 +20,17 @@ import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
import org.bukkit.event.entity.EntityPortalEnterEvent;
import org.bukkit.event.entity.PlayerLeashEntityEvent;
import org.bukkit.event.entity.ProjectileHitEvent;
import org.bukkit.event.hanging.HangingBreakByEntityEvent;
import org.bukkit.event.player.PlayerKickEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.entity.PlayerLeashEntityEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.tools.GrapplingHook;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
/**
* This {@link Listener} is responsible for the mechanics behind the {@link GrapplingHook}.
@ -55,13 +55,9 @@ public class GrapplingHookListener implements Listener {
this.grapplingHook = grapplingHook;
}
private boolean isEnabled() {
return grapplingHook != null && !grapplingHook.isDisabled();
}
@EventHandler
public void onArrowHitEntity(EntityDamageByEntityEvent e) {
if (!isEnabled()) {
if (grapplingHook.isDisabled()) {
return;
}
@ -72,7 +68,7 @@ public class GrapplingHookListener implements Listener {
@EventHandler
public void onArrowHitSurface(ProjectileHitEvent e) {
if (!isEnabled()) {
if (grapplingHook.isDisabled()) {
return;
}
@ -85,7 +81,7 @@ public class GrapplingHookListener implements Listener {
@EventHandler
public void onArrowHitHanging(HangingBreakByEntityEvent e) {
if (!isEnabled()) {
if (grapplingHook.isDisabled()) {
return;
}
@ -97,7 +93,7 @@ public class GrapplingHookListener implements Listener {
@EventHandler
public void onLeave(PlayerQuitEvent e) {
if (!isEnabled()) {
if (grapplingHook.isDisabled()) {
return;
}
@ -108,7 +104,7 @@ public class GrapplingHookListener implements Listener {
@EventHandler
public void onLeave(PlayerKickEvent e) {
if (!isEnabled()) {
if (grapplingHook.isDisabled()) {
return;
}
@ -119,7 +115,7 @@ public class GrapplingHookListener implements Listener {
@EventHandler
public void onFallDamage(EntityDamageEvent e) {
if (!isEnabled()) {
if (grapplingHook.isDisabled()) {
return;
}
@ -130,7 +126,7 @@ public class GrapplingHookListener implements Listener {
@EventHandler
public void onPortalEnter(EntityPortalEnterEvent e) {
if (!isEnabled()) {
if (grapplingHook.isDisabled()) {
return;
}
@ -142,7 +138,7 @@ public class GrapplingHookListener implements Listener {
// Fixing Issue #2351
@EventHandler
public void onLeash(PlayerLeashEntityEvent e) {
if (!isEnabled()) {
if (grapplingHook.isDisabled()) {
return;
}

View File

@ -3,6 +3,7 @@ package io.github.thebusybiscuit.slimefun4.implementation.listeners;
import javax.annotation.Nonnull;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.block.Block;
import org.bukkit.entity.EnderPearl;
import org.bukkit.entity.Player;
@ -16,7 +17,9 @@ import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
import org.bukkit.event.player.PlayerInteractEvent;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.armor.EnderBoots;
import io.github.thebusybiscuit.slimefun4.implementation.items.armor.FarmerShoes;
import io.github.thebusybiscuit.slimefun4.implementation.items.armor.LongFallBoots;
import io.github.thebusybiscuit.slimefun4.implementation.items.armor.SlimefunArmorPiece;
import io.github.thebusybiscuit.slimefun4.implementation.items.armor.StomperBoots;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
@ -50,7 +53,7 @@ public class SlimefunBootsListener implements Listener {
Player p = (Player) e.getEntity();
SlimefunItem boots = SlimefunItem.getByItem(p.getInventory().getBoots());
if (boots != null && boots.getId().equals("ENDER_BOOTS") && Slimefun.hasUnlocked(p, boots, true)) {
if (boots instanceof EnderBoots && Slimefun.hasUnlocked(p, boots, true)) {
e.setCancelled(true);
}
}
@ -69,8 +72,12 @@ public class SlimefunBootsListener implements Listener {
if (boots instanceof StomperBoots) {
e.setCancelled(true);
((StomperBoots) boots).stomp(e);
} else if (boots.getId().equals("SLIME_BOOTS") || boots.getId().equals("SLIME_STEEL_BOOTS")) {
} else if (boots instanceof LongFallBoots) {
e.setCancelled(true);
if (boots.getId().equals("BEE_BOOTS")) {
e.getEntity().getWorld().playSound(e.getEntity().getLocation(), Sound.BLOCK_HONEY_BLOCK_FALL, 1, 2);
}
}
}
}

View File

@ -36,7 +36,7 @@ public class VampireBladeListener implements Listener {
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onDamage(EntityDamageByEntityEvent e) {
if (blade == null || blade.isDisabled()) {
if (blade.isDisabled()) {
return;
}

View File

@ -1,4 +1,4 @@
package io.github.thebusybiscuit.slimefun4.implementation.listeners;
package io.github.thebusybiscuit.slimefun4.implementation.listeners.entity;
import java.util.Optional;

View File

@ -1,4 +1,4 @@
package io.github.thebusybiscuit.slimefun4.implementation.listeners;
package io.github.thebusybiscuit.slimefun4.implementation.listeners.entity;
import javax.annotation.Nonnull;
@ -51,7 +51,7 @@ public class EntityInteractionListener implements Listener {
if (Slimefun.hasUnlocked(e.getPlayer(), sfItem, true)) {
sfItem.callItemHandler(EntityInteractHandler.class, handler -> handler.onInteract(e, itemStack, e.getHand() == EquipmentSlot.OFF_HAND));
} else if (sfItem.getState() != ItemState.VANILLA_FALLBACK) {
/**
/*
* If an Item is disabled, we don't want it to fallback to the vanilla behaviour
* unless it is a Vanilla Item of course.
* Related to Issue #2446

View File

@ -1,4 +1,4 @@
package io.github.thebusybiscuit.slimefun4.implementation.listeners;
package io.github.thebusybiscuit.slimefun4.implementation.listeners.entity;
import javax.annotation.Nonnull;

View File

@ -1,4 +1,4 @@
package io.github.thebusybiscuit.slimefun4.implementation.listeners;
package io.github.thebusybiscuit.slimefun4.implementation.listeners.entity;
import javax.annotation.Nonnull;
@ -49,7 +49,7 @@ public class IronGolemListener implements Listener {
e.setCancelled(true);
SlimefunPlugin.getLocalization().sendMessage(e.getPlayer(), "messages.no-iron-golem-heal");
/**
/*
* This is just there to update the Inventory...
* Somehow cancelling it isn't enough.
*/

View File

@ -1,4 +1,4 @@
package io.github.thebusybiscuit.slimefun4.implementation.listeners;
package io.github.thebusybiscuit.slimefun4.implementation.listeners.entity;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;

View File

@ -1,4 +1,4 @@
package io.github.thebusybiscuit.slimefun4.implementation.listeners;
package io.github.thebusybiscuit.slimefun4.implementation.listeners.entity;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;

View File

@ -1,4 +1,4 @@
package io.github.thebusybiscuit.slimefun4.implementation.listeners;
package io.github.thebusybiscuit.slimefun4.implementation.listeners.entity;
import javax.annotation.Nonnull;

View File

@ -0,0 +1,5 @@
/**
* This package contains any {@link org.bukkit.event.Listener} from Slimefun which is related to an
* {@link org.bukkit.entity.Entity}.
*/
package io.github.thebusybiscuit.slimefun4.implementation.listeners.entity;

View File

@ -279,6 +279,7 @@ public final class ResearchSetup {
register("caveman_talisman", 267, "Talisman of the Caveman", 20, SlimefunItems.TALISMAN_CAVEMAN);
register("elytra_cap", 268, "Crash Gear", 20, SlimefunItems.ELYTRA_CAP);
register("energy_connectors", 269, "Wired Connections", 12, SlimefunItems.ENERGY_CONNECTOR);
register("bee_armor", 270, "Bee Armor", 24, SlimefunItems.BEE_HELMET, SlimefunItems.BEE_WINGS, SlimefunItems.BEE_LEGGINGS, SlimefunItems.BEE_BOOTS);
}
@ParametersAreNonnullByDefault

View File

@ -34,8 +34,10 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.androids.MinerAnd
import io.github.thebusybiscuit.slimefun4.implementation.items.androids.ProgrammableAndroid;
import io.github.thebusybiscuit.slimefun4.implementation.items.androids.WoodcutterAndroid;
import io.github.thebusybiscuit.slimefun4.implementation.items.armor.ElytraCap;
import io.github.thebusybiscuit.slimefun4.implementation.items.armor.EnderBoots;
import io.github.thebusybiscuit.slimefun4.implementation.items.armor.FarmerShoes;
import io.github.thebusybiscuit.slimefun4.implementation.items.armor.HazmatArmorPiece;
import io.github.thebusybiscuit.slimefun4.implementation.items.armor.LongFallBoots;
import io.github.thebusybiscuit.slimefun4.implementation.items.armor.Parachute;
import io.github.thebusybiscuit.slimefun4.implementation.items.armor.SlimefunArmorPiece;
import io.github.thebusybiscuit.slimefun4.implementation.items.armor.StomperBoots;
@ -127,6 +129,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.gps.GPSTransmitte
import io.github.thebusybiscuit.slimefun4.implementation.items.gps.PersonalActivationPlate;
import io.github.thebusybiscuit.slimefun4.implementation.items.gps.Teleporter;
import io.github.thebusybiscuit.slimefun4.implementation.items.gps.TeleporterPylon;
import io.github.thebusybiscuit.slimefun4.implementation.items.magical.BeeWings;
import io.github.thebusybiscuit.slimefun4.implementation.items.magical.InfernalBonemeal;
import io.github.thebusybiscuit.slimefun4.implementation.items.magical.InfusedHopper;
import io.github.thebusybiscuit.slimefun4.implementation.items.magical.InfusedMagnet;
@ -329,7 +332,7 @@ public final class SlimefunItemSetup {
new ItemStack[] {SlimefunItems.ENDER_LUMP_1, new ItemStack(Material.ENDER_EYE), SlimefunItems.ENDER_LUMP_1, new ItemStack(Material.OBSIDIAN), null, new ItemStack(Material.OBSIDIAN), new ItemStack(Material.OBSIDIAN), null, new ItemStack(Material.OBSIDIAN)})
.register(plugin);
new SlimefunItem(categories.magicalArmor, SlimefunItems.ENDER_BOOTS, RecipeType.ARMOR_FORGE,
new EnderBoots(categories.magicalArmor, SlimefunItems.ENDER_BOOTS, RecipeType.ARMOR_FORGE,
new ItemStack[] {null, null, null, SlimefunItems.ENDER_LUMP_1, null, SlimefunItems.ENDER_LUMP_1, new ItemStack(Material.OBSIDIAN), null, new ItemStack(Material.OBSIDIAN)})
.register(plugin);
@ -358,7 +361,7 @@ public final class SlimefunItemSetup {
new PotionEffect[] {new PotionEffect(PotionEffectType.SPEED, 300, 2)})
.register(plugin);
new SlimefunArmorPiece(categories.magicalArmor, SlimefunItems.SLIME_BOOTS, RecipeType.ARMOR_FORGE,
new LongFallBoots(categories.magicalArmor, SlimefunItems.SLIME_BOOTS, RecipeType.ARMOR_FORGE,
new ItemStack[] {null, null, null, new ItemStack(Material.SLIME_BALL), null, new ItemStack(Material.SLIME_BALL), new ItemStack(Material.IRON_INGOT), null, new ItemStack(Material.IRON_INGOT)},
new PotionEffect[] {new PotionEffect(PotionEffectType.JUMP, 300, 5)})
.register(plugin);
@ -1021,7 +1024,7 @@ public final class SlimefunItemSetup {
new PotionEffect[] {new PotionEffect(PotionEffectType.SPEED, 300, 2)})
.register(plugin);
new SlimefunArmorPiece(categories.magicalArmor, SlimefunItems.SLIME_BOOTS_STEEL, RecipeType.ARMOR_FORGE,
new LongFallBoots(categories.magicalArmor, SlimefunItems.SLIME_BOOTS_STEEL, RecipeType.ARMOR_FORGE,
new ItemStack[] {null, null, null, new ItemStack(Material.SLIME_BALL), null, new ItemStack(Material.SLIME_BALL), new ItemStack(Material.SLIME_BALL), SlimefunItems.STEEL_PLATE, new ItemStack(Material.SLIME_BALL)},
new PotionEffect[] {new PotionEffect(PotionEffectType.JUMP, 300, 5)})
.register(plugin);
@ -2523,7 +2526,28 @@ public final class SlimefunItemSetup {
new ItemStack[] {SlimefunItems.SILICON, new ItemStack(Material.YELLOW_DYE), SlimefunItems.SILICON, new ItemStack(Material.YELLOW_DYE), new ItemStack(Material.STRING), new ItemStack(Material.YELLOW_DYE), SlimefunItems.GILDED_IRON, new ItemStack(Material.YELLOW_DYE), SlimefunItems.SILICON})
.register(plugin);
if (SlimefunPlugin.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_16)) {
MinecraftVersion minecraftVersion = SlimefunPlugin.getMinecraftVersion();
if (minecraftVersion.isAtLeast(MinecraftVersion.MINECRAFT_1_15)) {
new SlimefunItem(categories.magicalArmor, SlimefunItems.BEE_HELMET, RecipeType.ARMOR_FORGE,
new ItemStack[] {SlimefunItems.GOLD_8K, new ItemStack(Material.HONEY_BLOCK), SlimefunItems.GOLD_8K, new ItemStack(Material.HONEYCOMB_BLOCK), null, new ItemStack(Material.HONEYCOMB_BLOCK), null, null, null})
.register(plugin);
new BeeWings(categories.magicalArmor, SlimefunItems.BEE_WINGS, RecipeType.ARMOR_FORGE,
new ItemStack[] {SlimefunItems.GOLD_8K, null, SlimefunItems.GOLD_8K, new ItemStack(Material.HONEYCOMB_BLOCK), new ItemStack(Material.ELYTRA), new ItemStack(Material.HONEYCOMB_BLOCK), new ItemStack(Material.HONEY_BLOCK), SlimefunItems.GOLD_8K, new ItemStack(Material.HONEY_BLOCK)})
.register(plugin);
new SlimefunItem(categories.magicalArmor, SlimefunItems.BEE_LEGGINGS, RecipeType.ARMOR_FORGE,
new ItemStack[] {SlimefunItems.GOLD_8K, new ItemStack(Material.HONEY_BLOCK), SlimefunItems.GOLD_8K, new ItemStack(Material.HONEYCOMB_BLOCK), null, new ItemStack(Material.HONEYCOMB_BLOCK), new ItemStack(Material.HONEYCOMB_BLOCK), null, new ItemStack(Material.HONEYCOMB_BLOCK)})
.register(plugin);
new LongFallBoots(categories.magicalArmor, SlimefunItems.BEE_BOOTS, RecipeType.ARMOR_FORGE,
new ItemStack[] {null, null, null, SlimefunItems.GOLD_8K, null, SlimefunItems.GOLD_8K, new ItemStack(Material.HONEY_BLOCK), null, new ItemStack(Material.HONEY_BLOCK)},
new PotionEffect[] {new PotionEffect(PotionEffectType.JUMP, 300, 2)})
.register(plugin);
}
if (minecraftVersion.isAtLeast(MinecraftVersion.MINECRAFT_1_16)) {
new StrangeNetherGoo(categories.magicalResources, SlimefunItems.STRANGE_NETHER_GOO, RecipeType.BARTER_DROP,
new ItemStack[] {null, null, null, null, new CustomItem(HeadTexture.PIGLIN_HEAD.getAsItemStack(), "&fPiglin"), null, null, null, null})
.register(plugin);

View File

@ -0,0 +1,102 @@
package io.github.thebusybiscuit.slimefun4.implementation.tasks;
import javax.annotation.Nonnull;
import org.bukkit.HeightMap;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.magical.BeeWings;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.BeeWingsListener;
/**
* This task is responsible for the repeating checks for our {@link BeeWings}.
*
* @author beSnow
* @author TheBusyBiscuit
*
* @see BeeWings
* @see BeeWingsListener
*
*/
public class BeeWingsTask extends AbstractPlayerTask {
private static final int MIN_ALTITUDE = 4;
private Location lastLocation;
public BeeWingsTask(@Nonnull Player p) {
super(p);
lastLocation = p.getLocation();
}
@Override
protected void executeTask() {
if (p.getLocation().getY() < lastLocation.getY()) {
Location loc = p.getLocation();
int distanceToHighestBlock = (loc.getBlockY() - loc.getWorld().getHighestBlockYAt(loc, HeightMap.WORLD_SURFACE));
/*
* getDistanceToGround will only fire when distanceToHighestBlock is negative
* (which happens when a player flies beneath an existing structure)
*/
if (distanceToHighestBlock < 0) {
int distanceToGround = getDistanceToGround(loc.getBlock(), 6);
if (distanceToGround < 1) {
return;
}
slowDown();
} else if (distanceToHighestBlock <= MIN_ALTITUDE) {
slowDown();
}
}
lastLocation = p.getLocation();
}
private void slowDown() {
SlimefunPlugin.getLocalization().sendMessage(p, "messages.bee-suit-slow-fall");
p.setFallDistance(0);
p.addPotionEffect(new PotionEffect(PotionEffectType.SLOW_FALLING, 60, 0));
}
/**
* Calculates the distance of the given {@link Block} from the ground.
*
* @param b
* The {@link Block} to calculate from.
* @param limit
* The limit of {@link Block blocks} to check under the given {@link Block b}.
*
*/
private int getDistanceToGround(@Nonnull Block b, int limit) {
for (int i = 1; i <= limit; i++) {
Block relative = b.getRelative(0, -i, 0);
if (relative.getType().isSolid()) {
return i;
}
}
return 0;
}
@Override
protected boolean isValid() {
// The task is only valid as long as the Player is alive and gliding
if (!p.isOnline() || !p.isValid() || p.isDead() || !p.isGliding() || p.hasPotionEffect(PotionEffectType.SLOW_FALLING)) {
cancel();
return false;
}
return true;
}
}

View File

@ -1,4 +1,4 @@
package io.github.thebusybiscuit.slimefun4.core.services.plugins;
package io.github.thebusybiscuit.slimefun4.integrations;
import java.util.Iterator;
@ -23,7 +23,13 @@ import me.minebuilders.clearlag.events.EntityRemoveEvent;
*/
class ClearLagIntegration implements Listener {
private final SlimefunPlugin plugin;
ClearLagIntegration(@Nonnull SlimefunPlugin plugin) {
this.plugin = plugin;
}
public void register() {
plugin.getServer().getPluginManager().registerEvents(this, plugin);
}

View File

@ -0,0 +1,225 @@
package io.github.thebusybiscuit.slimefun4.integrations;
import java.util.function.Consumer;
import java.util.logging.Level;
import javax.annotation.Nonnull;
import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.block.Block;
import org.bukkit.event.Event;
import org.bukkit.plugin.Plugin;
import com.gmail.nossr50.events.fake.FakeBlockBreakEvent;
import dev.lone.itemsadder.api.ItemsAdder;
import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.api.Slimefun;
/**
* This Service holds all interactions and hooks with third-party {@link Plugin Plugins}
* that are not necessarily a dependency or a {@link SlimefunAddon}.
*
* Integration with these plugins happens inside Slimefun itself.
*
* @author TheBusyBiscuit
*
* @see SlimefunPlugin
*
*/
public class IntegrationsManager {
/**
* This is our instance of {@link SlimefunPlugin}.
*/
protected final SlimefunPlugin plugin;
/**
* This boolean determines whether {@link #start()} was run.
*/
private boolean isEnabled = false;
// Soft dependencies
private boolean isPlaceholderAPIInstalled = false;
private boolean isWorldEditInstalled = false;
private boolean isMcMMOInstalled = false;
private boolean isClearLagInstalled = false;
private boolean isItemsAdderInstalled = false;
// Addon support
private boolean isChestTerminalInstalled = false;
private boolean isExoticGardenInstalled = false;
/**
* This initializes the {@link IntegrationsManager}
*
* @param plugin
* Our instance of {@link SlimefunPlugin}
*/
public IntegrationsManager(@Nonnull SlimefunPlugin plugin) {
this.plugin = plugin;
}
/**
* This method returns whether the {@link IntegrationsManager} was enabled yet.
*
* @return Whether this {@link IntegrationsManager} has been enabled already.
*/
public boolean isEnabled() {
return isEnabled;
}
/**
* This method initializes all third party integrations.
*/
public final void start() {
if (isEnabled) {
// Prevent double-registration
throw new UnsupportedOperationException("All integrations have already been loaded.");
} else {
isEnabled = true;
}
// Load any soft dependencies
onServerLoad();
// Load any integrations which aren't dependencies (loadBefore)
plugin.getServer().getScheduler().runTask(plugin, this::onServerStart);
}
/**
* This method is called when the {@link Server} loaded its {@link Plugin Plugins}.
* We can safely assume that any {@link Plugin} which is a soft dependency of Slimefun
* to be enabled at this point.
*/
private void onServerLoad() {
// PlaceholderAPI hook to provide playerholders from Slimefun.
load("PlaceholderAPI", integration -> {
new PlaceholderAPIIntegration(plugin).register();
isPlaceholderAPIInstalled = true;
});
// WorldEdit Hook to clear Slimefun Data upon //set 0 //cut or any other equivalent
load("WorldEdit", integration -> {
new WorldEditIntegration().register();
isWorldEditInstalled = true;
});
// mcMMO Integration
load("mcMMO", integration -> {
new McMMOIntegration(plugin).register();
isMcMMOInstalled = true;
});
// ClearLag integration (to prevent display items from getting deleted)
load("ClearLag", integration -> {
new ClearLagIntegration(plugin).register();
isClearLagInstalled = true;
});
// ItemsAdder Integration (custom blocks)
load("ItemsAdder", integration -> isItemsAdderInstalled = true);
}
/**
* This method is called when the {@link Server} has finished loading all its {@link Plugin Plugins}.
*/
private void onServerStart() {
isChestTerminalInstalled = isAddonInstalled("ChestTerminal");
isExoticGardenInstalled = isAddonInstalled("ExoticGarden");
}
private boolean isAddonInstalled(@Nonnull String addon) {
if (plugin.getServer().getPluginManager().isPluginEnabled(addon)) {
Slimefun.getLogger().log(Level.INFO, "Hooked into Slimefun Addon: {0}", addon);
return true;
} else {
return false;
}
}
/**
* This method loads an integration with a {@link Plugin} of the specified name.
* If that {@link Plugin} is installed and enabled, the provided callback will be run.
*
* @param pluginName
* The name of this {@link Plugin}
* @param consumer
* The callback to run if that {@link Plugin} is installed and enabled
*/
private void load(@Nonnull String pluginName, @Nonnull Consumer<Plugin> consumer) {
Plugin integration = plugin.getServer().getPluginManager().getPlugin(pluginName);
if (integration != null && integration.isEnabled()) {
String version = integration.getDescription().getVersion();
Slimefun.getLogger().log(Level.INFO, "Hooked into Plugin: {0} v{1}", new Object[] { pluginName, version });
try {
// Run our callback
consumer.accept(integration);
} catch (Exception | LinkageError x) {
Slimefun.getLogger().log(Level.WARNING, "Maybe consider updating {0} or Slimefun?", pluginName);
Slimefun.getLogger().log(Level.WARNING, x, () -> "Failed to hook into " + pluginName + " v" + version);
}
}
}
/**
* This checks if one of our third party integrations faked an {@link Event}.
* Faked {@link Event Events} should be ignored in our logic.
*
* @param event
* The {@link Event} to test
*
* @return Whether this is a fake event
*/
public boolean isEventFaked(@Nonnull Event event) {
// This can be changed to "FakeEvent" in a later version
return isMcMMOInstalled && event instanceof FakeBlockBreakEvent;
}
/**
* This checks if one of our third party integrations has placed a custom
* {@link Block} at this {@link Location}.
*
* @param block
* The {@link Block} to check
*
* @return Whether a different custom {@link Block} exists at that {@link Location}
*/
@SuppressWarnings("deprecation")
public boolean isCustomBlock(@Nonnull Block block) {
return isItemsAdderInstalled && ItemsAdder.isCustomBlock(block);
}
public boolean isPlaceholderAPIInstalled() {
return isPlaceholderAPIInstalled;
}
public boolean isWorldEditInstalled() {
return isWorldEditInstalled;
}
public boolean isMcMMOInstalled() {
return isMcMMOInstalled;
}
public boolean isClearLagInstalled() {
return isClearLagInstalled;
}
public boolean isItemsAdderInstalled() {
return isItemsAdderInstalled;
}
public boolean isChestTerminalInstalled() {
return isChestTerminalInstalled;
}
public boolean isExoticGardenInstalled() {
return isExoticGardenInstalled;
}
}

View File

@ -1,4 +1,4 @@
package io.github.thebusybiscuit.slimefun4.core.services.plugins;
package io.github.thebusybiscuit.slimefun4.integrations;
import javax.annotation.Nonnull;
@ -23,7 +23,13 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
*/
class McMMOIntegration implements Listener {
private final SlimefunPlugin plugin;
McMMOIntegration(@Nonnull SlimefunPlugin plugin) {
this.plugin = plugin;
}
public void register() {
plugin.getServer().getPluginManager().registerEvents(this, plugin);
}

View File

@ -1,4 +1,4 @@
package io.github.thebusybiscuit.slimefun4.core.services.plugins;
package io.github.thebusybiscuit.slimefun4.integrations;
import java.util.Optional;
import java.util.Set;

View File

@ -1,4 +1,4 @@
package io.github.thebusybiscuit.slimefun4.core.services.plugins;
package io.github.thebusybiscuit.slimefun4.integrations;
import org.bukkit.Bukkit;
import org.bukkit.Location;
@ -24,6 +24,16 @@ import me.mrCookieSlime.Slimefun.api.BlockStorage;
class WorldEditIntegration {
WorldEditIntegration() {
try {
// This ensures that we are using a version which supports Extents
Class.forName("com.sk89q.worldedit.extent.Extent");
} catch (ClassNotFoundException e) {
// Re-throw the exception for the IntegrationsManager to catch
throw new IllegalStateException(e);
}
}
public void register() {
WorldEdit.getInstance().getEventBus().register(this);
}

View File

@ -0,0 +1,4 @@
/**
* This package holds classes which are related to integrations between Slimefun and Third-Party plugins.
*/
package io.github.thebusybiscuit.slimefun4.integrations;

View File

@ -223,6 +223,7 @@ public final class NumberUtils {
}
}
@Nonnull
public static String roundDecimalNumber(double number) {
return DECIMAL_FORMAT.format(number);
}

View File

@ -186,9 +186,12 @@ public class BlockStorage {
Config blockInfo = parseBlockInfo(l, json);
if (blockInfo != null && blockInfo.contains("id")) {
if (storage.containsKey(l)) {
// It should not be possible to have two blocks on the same location. Ignore the
// new entry if a block is already present and print an error to the console.
if (storage.putIfAbsent(l, blockInfo) != null) {
/*
* It should not be possible to have two blocks on the same location.
* Ignore the new entry if a block is already present and print an
* error to the console (if enabled).
*/
if (SlimefunPlugin.getRegistry().logDuplicateBlockEntries()) {
Slimefun.getLogger().log(Level.INFO, "Ignoring duplicate block @ {0}, {1}, {2} ({3} -> {4})", new Object[] { l.getBlockX(), l.getBlockY(), l.getBlockZ(), blockInfo.getString("id"), storage.get(l).getString("id") });
}
@ -196,9 +199,9 @@ public class BlockStorage {
return;
}
storage.put(l, blockInfo);
String fileName = file.getName().replace(".sfb", "");
if (SlimefunPlugin.getRegistry().getTickerBlocks().contains(file.getName().replace(".sfb", ""))) {
if (SlimefunPlugin.getRegistry().getTickerBlocks().contains(fileName)) {
SlimefunPlugin.getTickerTask().enableTicker(l);
}
}

View File

@ -12,6 +12,7 @@ import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.config.Config;
import me.mrCookieSlime.Slimefun.api.Slimefun;
// This class will be deprecated, relocated and rewritten in a future version.
public class BlockMenu extends DirtyChestMenu {
private Location location;

View File

@ -20,6 +20,7 @@ import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.item_transport.ItemTransportFlow;
// This class will be deprecated, relocated and rewritten in a future version.
public abstract class BlockMenuPreset extends ChestMenu {
private final Set<Integer> occupiedSlots = new HashSet<>();
@ -32,8 +33,6 @@ public abstract class BlockMenuPreset extends ChestMenu {
private final boolean universal;
private boolean locked;
private ItemManipulationEvent event;
public BlockMenuPreset(@Nonnull String id, @Nonnull String title) {
this(id, title, false);
}
@ -75,19 +74,6 @@ public abstract class BlockMenuPreset extends ChestMenu {
public abstract int[] getSlotsAccessedByItemTransport(ItemTransportFlow flow);
/**
* This method is deprecated.
*
* @deprecated Override {@link #onItemStackChange(DirtyChestMenu, int, ItemStack, ItemStack)} instead
*
* @param event
* The event
*/
@Deprecated
public void registerEvent(ItemManipulationEvent event) {
this.event = event;
}
/**
* This method is called whenever an {@link ItemStack} changes.
* You can override this as necessary if you need to listen to these events
@ -259,7 +245,6 @@ public abstract class BlockMenuPreset extends ChestMenu {
menu.addMenuOpeningHandler(getMenuOpeningHandler());
menu.addMenuCloseHandler(getMenuCloseHandler());
menu.registerEvent(event);
}
public void newInstance(@Nonnull BlockMenu menu, @Nonnull Location l) {

View File

@ -18,10 +18,10 @@ import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.slimefun4.utils.itemstack.ItemStackWrapper;
import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu;
// This class will be deprecated, relocated and rewritten in a future version.
public class DirtyChestMenu extends ChestMenu {
protected final BlockMenuPreset preset;
protected ItemManipulationEvent event;
protected int changes = 1;
public DirtyChestMenu(@Nonnull BlockMenuPreset preset) {
@ -61,35 +61,20 @@ public class DirtyChestMenu extends ChestMenu {
return preset.canOpen(b, p);
}
@Override
public void open(Player... players) {
super.open(players);
// The Inventory will likely be modified soon
markDirty();
}
public void close() {
for (HumanEntity human : new ArrayList<>(toInventory().getViewers())) {
human.closeInventory();
}
}
/**
* This method has been deprecated.
*
* @deprecated The {@link ItemManipulationEvent} has been deprecated.
*
* @param event
* deprecated class
*/
@Deprecated
public void registerEvent(ItemManipulationEvent event) {
this.event = event;
}
@Override
public ChestMenu addMenuOpeningHandler(MenuOpeningHandler handler) {
if (handler instanceof MenuSavingHandler) {
MenuOpeningHandler openingHandler = ((MenuSavingHandler) handler).getOpeningHandler();
return super.addMenuOpeningHandler(new MenuSavingHandler(this, openingHandler));
} else {
return super.addMenuOpeningHandler(new MenuSavingHandler(this, handler));
}
}
public boolean fits(@Nonnull ItemStack item, int... slots) {
for (int slot : slots) {
// A small optimization for empty slots
@ -161,11 +146,6 @@ public class DirtyChestMenu extends ChestMenu {
public void replaceExistingItem(int slot, ItemStack item, boolean event) {
if (event) {
ItemStack previous = getItemInSlot(slot);
if (this.event != null) {
item = this.event.onEvent(slot, previous, item);
}
item = preset.onItemStackChange(this, slot, previous, item);
}

View File

@ -1,17 +0,0 @@
package me.mrCookieSlime.Slimefun.api.inventory;
import org.bukkit.inventory.ItemStack;
/**
* @deprecated Please use {@link BlockMenuPreset#onItemStackChange(DirtyChestMenu, int, ItemStack, ItemStack)} instead.
*
* @author TheBusyBiscuit
*
*/
@Deprecated
@FunctionalInterface
public interface ItemManipulationEvent {
ItemStack onEvent(int slot, ItemStack previous, ItemStack next);
}

View File

@ -1,30 +0,0 @@
package me.mrCookieSlime.Slimefun.api.inventory;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.entity.Player;
import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu.MenuOpeningHandler;
public class MenuSavingHandler implements MenuOpeningHandler {
private final DirtyChestMenu menu;
private final MenuOpeningHandler handler;
@ParametersAreNonnullByDefault
public MenuSavingHandler(DirtyChestMenu menu, MenuOpeningHandler handler) {
this.menu = menu;
this.handler = handler;
}
@Override
public void onOpen(Player p) {
handler.onOpen(p);
menu.markDirty();
}
public MenuOpeningHandler getOpeningHandler() {
return handler;
}
}

View File

@ -4,6 +4,7 @@ import java.io.File;
import io.github.thebusybiscuit.cscorelib2.config.Config;
// This class will be deprecated, relocated and rewritten in a future version.
public class UniversalBlockMenu extends DirtyChestMenu {
public UniversalBlockMenu(BlockMenuPreset preset) {

View File

@ -2,25 +2,25 @@
slimefun:
weapons: Оръжия
tools: Инструменти
items: Полезни предмети
items: Полезни Предмети
food: Храна
basic_machines: Основни машини
basic_machines: Основни Машини
electricity: Енергия и Eлектричество
gps: GPS Машини
armor: Броня
armor: Брони
magical_items: Магически Предмети
magical_gadgets: Магически Джаджи
misc: Разни Предмети
technical_gadgets: Технически джаджи
technical_gadgets: Технически Джаджи
resources: Ресурси
cargo: Товарно Управление
tech_misc: Технически Компоненти
magical_armor: Магическа Броня
magical_armor: Магически Брони
talismans: Талисмани (Ниво I)
ender_talismans: Ендър Талисмани (Ниво II)
christmas: Коледа (Декември)
valentines_day: Свети Валентин (14ти Февруари)
easter: Великден (април)
easter: Великден (Април)
birthday: Рожденият Ден на TheBusyBiscuit (26ти Октомври)
halloween: Хелоуин (31и Октомври)
androids: Програмируеми Андроиди

View File

@ -108,11 +108,8 @@ messages:
no-permission: "&4Du hast nicht die benötigten Rechte hierfür"
usage: "&4Korrekte Schreibweise: &c%usage%"
not-online: "&4%player% &cist derzeit nicht online!"
invalid-item: "&4%item% &cist kein gültiges Item!"
invalid-amount: "&4%amount% &cist keine gültige Anzahl! Sie muss höher als 0 sein!"
given-item: '&bDir wurde &a%amount% &7mal "%item%&7" gegeben'
give-item: '&bDu hast %player% &a%amount% &7"%item%&7" gegeben'
invalid-research: "&4%research% &cist kein gültiger Erfahrungsgrad!"
give-research: '&bDu hast %player% den Erfahrungsgrad &7"%research%&7" vergeben'
hungry: "&cDu bist zu hungrig, um dies zu tun!"
disabled-in-world: "&4&lDieses Item wurde in dieser Welt deaktiviert!"
@ -190,6 +187,10 @@ messages:
dual-wielding: "&4Du musst zum Klettern einen KletterPickel in beiden Händen halten!"
wrong-material: "&cDu kannst nicht an dieser Wand klettern. Erkundige dich im
Slimefun Guide für mehr Infos!"
invalid-item: "&4%item% &cist kein gültiges Item!"
invalid-amount: "&4%amount% &cist keine gültige Anzahl! Sie muss höher als 0 sein!"
invalid-research: "&4%research% &cist kein gültiger Erfahrungsgrad!"
bee-suit-slow-fall: "&eDeine Bienenflügel haben dir eine sichere Landung ermöglicht"
mode-change: "&bDer Modus von deinem %device% wurde geändert zu: &9%mode%"
machines:
pattern-not-found: "&eEs tut mir leid, aber ich konnte kein passendes Rezept finden."
@ -249,6 +250,7 @@ machines:
gefunden!"
anvil:
not-working: "&4Items von Slimefun können nicht in einem Amboss verwendet werden!"
mcmmo-salvaging: "&4Du kannst Slimefun-Items nicht ausschlachten!"
backpack:
already-open: "&cDieser Rucksack wird derzeit von jemand anderem benutzt!"
no-stack: "&cRucksäcke dürfen nicht gestapelt werden"
@ -334,6 +336,7 @@ languages:
zh-CN: Chinesisch (China)
el: Griechisch
he: Hebräisch
pt: Portugiesisch (Portugal)
pt-BR: Portugiesisch (Brasilien)
ar: Arabisch
af: Afrikaans
@ -346,7 +349,6 @@ languages:
fa: Persisch
th: Thailändisch
ro: Rumänisch
pt: Portugiesisch (Portugal)
bg: Bulgarisch
ko: Koreanisch
tr: Türkisch
@ -361,5 +363,7 @@ villagers:
no-trading: "&4Items von Slimefun können nicht zum Handeln verwendet werden!"
cartography_table:
not-working: "&4Slimefun Items können nicht in einem Kartentisch verwendet werden!"
cauldron:
no-discoloring: "&4Du kannst Slimefun-Rüstung nicht entfärben"
miner:
no-ores: "&eIch konnte leider keine Erze in der Nähe finden!"

View File

@ -132,6 +132,7 @@ messages:
no-tome-yourself: '&cYou cannot use the &4Tome of Knowledge &con yourself...'
multimeter: '&bStored Energy: &3%stored% &b/ &3%capacity%'
piglin-barter: '&4You cannot barter with piglins using Slimefun items'
bee-suit-slow-fall: '&eYour Bee Wings will help you to get back to the ground safe and slow'
multi-tool:
mode-change: '&b%device% mode changed to: &9%mode%'

View File

@ -20,6 +20,10 @@ commands:
player-never-joined: "&4¡Ningún jugador con ese nombre pudo ser encontrado!"
backpack-does-not-exist: "&4¡La mochila especificada no existe!"
restored-backpack-given: "&a¡Tu mochila ha sido restaurada y añadida a tu inventario!"
charge:
description: Carga el ítem que estés sosteniendo
charge-success: El Ítem ha sido cargado!
not-rechargeable: Este ítem no puede ser cargado!
guide:
search:
message: "&b¿Qué te gustaría buscar?"
@ -102,12 +106,8 @@ messages:
no-permission: "&4No tienes el permiso requerido para hacer esto."
usage: "&4Uso: &c%usage%"
not-online: "&c¡&4%player% &cno está conectado!"
invalid-item: "&c¡&4%item% &cno es un objeto válido!"
invalid-amount: "&c¡&4%amount% &cno es un valor válido: tiene que ser mayor a
0!"
given-item: '&bTe han dado &a%amount% &7"%item%&7"'
give-item: '&bLe has dado a %player%, &a%amount% &7"%item%&7"'
invalid-research: "&c¡&4%research% &cno es un conocimiento válido!"
give-research: '&bLe has dado a %player% la investigación &7"%research%&7"'
hungry: "&c¡Tienes demasiada hambre para hacer eso!"
disabled-in-world: "&4&lEste item ha sido desactivado en el mundo."
@ -129,6 +129,7 @@ messages:
whirlwind: "&a&oTu talismán ha reflejado un proyectil."
wizard: "&a&oTu talismán te ha dado un mayor nivel de fortuna, pero pudo disminuír
el nivel de otros encantamientos."
caveman: "&a&oTu Talismán te ha dado Haste"
soulbound-rune:
fail: "&cSolo puedes ligar un objeto a tu alma."
success: "&a¡Has ligado este objeto a tu alma exitosamente! No lo perderás al
@ -181,6 +182,9 @@ messages:
dual-wielding: "&4Necesitas sostener Climbing Picks con las 2 manos para usarlos!"
wrong-material: "&cNo puedes escalar esta superficie. Mira tu guia de Slimefun
para mas info!"
invalid-item: "&c¡&4%item% &cno es un objeto válido!"
invalid-amount: "&c¡&4%amount% &cno es un valor válido: tiene que ser mayor a 0!"
invalid-research: "&c¡&4%research% &cno es un conocimiento válido!"
mode-change: 'El modo de &b%device% ha cambiado a: &9%mode%'
machines:
pattern-not-found: "&eLo siento, no puedo reconocer esta receta. Por favor coloca
@ -238,6 +242,7 @@ machines:
finished: "&e?¡Tu Industrial Miner ha acabado! ¡Obtuvo un total de %ores% mineral(es)!"
anvil:
not-working: "&4¡No puedes usar objetos de Slimefun en un yunque!"
mcmmo-salvaging: "&4No puedes salvar items de Slimefun!"
backpack:
already-open: "&cPerdón, ¡Esta mochila esta abierta en otro lugar!"
no-stack: "&cNo puedes juntar mochilas."
@ -349,5 +354,9 @@ brewing_stand:
not-working: "&4¡No puedes usar objetos de Slimefun en un soporte para pociones!"
villagers:
no-trading: "&4¡No puedes comerciar objetos de Slimefun con los aldeanos!"
cartography_table:
not-working: "&4No puedes usar items de Slimefun en una Mesa de Cartografía!"
cauldron:
no-discoloring: "&4No puedes descolorar Armaduras de Slimefun"
miner:
no-ores: "&ePerdón, ¡No encuentro ningún mineral cerca!"

View File

@ -110,12 +110,8 @@ messages:
no-permission: "&4Vous n'avez pas les permissions requises pour faire ceci"
usage: "&4Utilisation: &c%usage%"
not-online: "&4%player% &cn'est pas en ligne!"
invalid-item: "&4%item% &cn'est pas un item valide!"
invalid-amount: "&4%amount% &cn'est pas un montant valide: il doit être supérieur
à 0!"
given-item: '&bVous avez reçu &a%amount%&7 "%item%&7"'
give-item: '&bVous avez donné &a%amount% &7"%item%&7" à %player%'
invalid-research: "&4%research% &cn'est pas une recherche valide!"
give-research: '&bVous avez débloqué la recherche "%research%&7" à %player%'
hungry: "&cVous avez trop faim pour faire ça!"
disabled-in-world: "&4&lCet item a été désactivé dans ce monde"
@ -193,7 +189,13 @@ messages:
utiliser !"
wrong-material: "&cVous ne pouvez pas escalader cette surface. Consultez votre
guide Slimefun pour plus d'informations !"
invalid-item: "&4%item% &cn'est pas un item valide!"
invalid-amount: "&4%amount% &cn'est pas un montant valide: il doit être supérieur
à 0!"
invalid-research: "&4%research% &cn'est pas une recherche valide!"
mode-change: 'Vous avez changé votre &b%device% en mode : &9%mode%'
bee-suit-slow-fall: "&eVos ailes d'abeille vous aideront à revenir au sol lentement
et en toute sécurité"
machines:
pattern-not-found: "&eDésolé, je ne reconnais pas cette recette. Veuillez disposer
les objets correctement dans le distributeur."
@ -341,7 +343,6 @@ languages:
zh-CN: Chinois (Chine)
el: Grec
he: Hébreu
pt: Portugais (Portugal)
ar: Arabe
af: Afrikaans
da: Danois
@ -353,6 +354,7 @@ languages:
fa: Persan
th: Thaï
ro: Roumain
pt: Portugais (Portugal)
pt-BR: Portugais (Brésil)
bg: Bulgare
ko: Coréen

View File

@ -106,11 +106,8 @@ messages:
no-permission: "&4Ehhez nincs jogod"
usage: "&4Használat: &c%usage%"
not-online: "&4%player% &cjelenleg nem elérhető!"
invalid-item: "&4%item% &cnem megfelelő tárgy!"
invalid-amount: "&4%amount% &cnem megfelelő mennyiség: 0-nál nagyobbnak kell lennie!"
given-item: '&bKaptál &a%amount% darab &7"%item%&7"&b-t'
give-item: '&bAdtál %player%-nek/nak &a%amount% &7"%item%&7"&b-t'
invalid-research: "&4%research% &cnem érvényes Kutatás!"
give-research: '&bMegadtad %player% játékosnak a(z) &7"%research%&7" &bkutatást'
hungry: "&cTúl éhes vagy ehhez!"
disabled-in-world: "&4&lEz a tárgy tiltva van ebben a világban"
@ -185,6 +182,10 @@ messages:
őket!"
wrong-material: "&cEzt a felületet nem mászhatod meg. Nyisd meg a Slimefun Útmutatót
további információért!"
invalid-item: "&4%item% &cnem megfelelő tárgy!"
invalid-amount: "&4%amount% &cnem megfelelő mennyiség: 0-nál nagyobbnak kell lennie!"
invalid-research: "&4%research% &cnem érvényes Kutatás!"
bee-suit-slow-fall: "&eA Bee Wings segít neked visszatérni a földre lassan és biztonságosan"
mode-change: "&b%device% mód állítva erre: &9%mode%"
machines:
pattern-not-found: "&eSajnálom, nem ismerem fel ezt a receptet. Kérlek, helyezd
@ -329,6 +330,7 @@ languages:
zh-CN: Kínai (Kína)
el: Görög
he: Héber
pt-BR: Portugál (Brazília)
ar: Arab
af: Afrikaans
da: Dán
@ -341,7 +343,6 @@ languages:
th: Thai
ro: Román
pt: Portugál (Portugália)
pt-BR: Portugál (Brazília)
bg: Bolgár
ko: Koreai
tr: Török

View File

@ -106,11 +106,8 @@ messages:
no-permission: "&4権限がありません"
usage: "&4使用法: &c%usage%"
not-online: "&4%player% &cはオンラインではありません"
invalid-item: "&4%item% &cは正しくないアイテムです"
invalid-amount: "&4%amount% &cの部分には、正の整数を指定してください"
given-item: "&b%item%を%amount%個与えられました"
give-item: "&b%player%に%item%を%amount%個与えました"
invalid-research: "&4%research%&cは正しくないリサーチです"
give-research: "&b%player%のリサーチ%research%を完了させました"
hungry: "&c空腹のため使えません"
disabled-in-world: "&4&lこのワールドでは使用できません"
@ -178,6 +175,10 @@ messages:
climbing-pick:
dual-wielding: "&4Climbing Pickを両手に持って使用"
wrong-material: "&cこの地表はクライミングできません。Slimefunガイドを確認してください"
invalid-item: "&4%item% &cは正しくないアイテムです"
invalid-amount: "&4%amount% &cの部分には、正の整数を指定してください"
invalid-research: "&4%research%&cは正しくないリサーチです"
bee-suit-slow-fall: "&e蜂の羽が着地を安全でゆっくりにした"
mode-change: "&b%device%のモード変更: &9%mode%"
machines:
pattern-not-found: "&eレシピが確認できません、アイテムを正しく配置してください"
@ -313,6 +314,7 @@ languages:
el: ギリシャ語
he: ヘブライ語
pt: ポルトガル語(ポルトガル)
pt-BR: ポルトガル語(ブラジル)
ar: アラビア語
af: アフリカーンス語
da: デンマーク語
@ -324,7 +326,6 @@ languages:
fa: ペルシア語
th: タイ語
ro: ルーマニア語
pt-BR: ポルトガル語(ブラジル)
bg: ブルガリア語
ko: 韓国語
tr: トルコ語

View File

@ -107,12 +107,8 @@ messages:
no-permission: "&4У Вас недостаточно прав, чтобы сделать это"
usage: "&4Использование: &c%usage%"
not-online: "&4%player% &cсейчас не в игре!"
invalid-item: "&4%item% &cне является допустимым предметом!"
invalid-amount: "&4%amount% &cне является допустимым числом: количество должно
быть больше нуля!"
given-item: '&bВам выдали &a%amount% &7"%item%&7"'
give-item: '&bВы выдали игроку %player% &a%amount% &7"%item%&7"'
invalid-research: "&4%research% &cне является допустимым исследованием!"
give-research: '&bВы выдали игроку %player% исследование &7"%research%&7"'
hungry: "&cВы слишком голодны для этого!"
disabled-in-world: "&4&lДанный предмет отключен в этом мире"
@ -187,6 +183,12 @@ messages:
dual-wielding: "&4Вы должны держать кирку для скалолазания в обеих руках!"
wrong-material: "&cВы не можете карабкаться по этой поверхности. Проверьте руководство
Slimefun для большей информации!"
invalid-item: "&4%item% &cне является допустимым предметом!"
invalid-amount: "&4%amount% &cне является допустимым числом: количество должно быть
больше нуля!"
invalid-research: "&4%research% &cне является допустимым исследованием!"
bee-suit-slow-fall: "&eПчелиные крылья помогут Вам спуститься на землю медленно
и безопасно"
mode-change: "&b%device% | Режим изменён на: &9%mode%"
machines:
pattern-not-found: "&eК сожалению, не удалось распознать этот рецепт. Пожалуйста,
@ -245,6 +247,7 @@ machines:
finished: "&eВаш промышленный шахтёр закончил работу! Добыто руд: %ores%!"
anvil:
not-working: "&4Вы не можете использовать Slimefun предметы в наковальне!"
mcmmo-salvaging: "&4Вы не можете разбирать Slimefun предметы!"
backpack:
already-open: "&cИзвините, этот рюкзак уже открыт в другом месте!"
no-stack: "&cВы не можете складывать рюкзаки вместе"
@ -357,5 +360,7 @@ villagers:
no-trading: "&4Вы не можете торговаться с крестьянами Slimefun предметами!"
cartography_table:
not-working: "&4Вы не можете использовать Slimefun предметы в столе картографа!"
cauldron:
no-discoloring: "&4Вы не можете сбросить цвет Slimefun брони"
miner:
no-ores: "&eК сожалению, не удалось найти какую-либо руду поблизости!"

View File

@ -106,11 +106,8 @@ messages:
no-permission: "&4你没有足够的权限做这个"
usage: "&4用法: &c%usage%"
not-online: "&4%player% &c不在线"
invalid-item: "&4%item% &c不是一个有效的物品名!"
invalid-amount: "&4%amount% &ci不是一个有效的数字 : 它必须大于 0!"
given-item: '&b你获得了 &a%amount% &7"%item%&7"'
give-item: '&b成功给予玩家 %player% &a%amount% &7"%item%&7"'
invalid-research: "&4%research% &c不是一个有效的研究名!"
give-research: '&b你成功解锁了玩家 %player% 的研究 &7"%research%&7"'
hungry: "&c你太饿了, 先吃点东西再试试吧!"
disabled-in-world: "&4&l这个物品在此世界已被禁用"
@ -178,6 +175,10 @@ messages:
climbing-pick:
dual-wielding: "&4你需要双手拿着攀岩镐才能使用!"
wrong-material: "&c你不能爬上这个平面. 查看指南书了解更多!"
invalid-item: "&4%item% &c不是一个有效的物品名!"
invalid-amount: "&4%amount% &ci不是一个有效的数字 : 它必须大于 0!"
invalid-research: "&4%research% &c不是一个有效的研究名!"
bee-suit-slow-fall: "&e你的蜂翅会让你安全且缓慢地回到地面"
mode-change: "&b%device% 的模式已切换为: &9%mode%"
machines:
pattern-not-found: "&e抱歉, 你记错合成表了吧. 这不是一个正确的合成配方, 请检查发射器里放置物品的顺序."

View File

@ -178,6 +178,7 @@ messages:
invalid-item: "&4%item% &c不存在"
invalid-amount: "&4%amount% &c不是有效數量數值必須大於 0"
invalid-research: "&4%research% &c不存在!"
bee-suit-slow-fall: "&e你的蜂翅將會幫你緩慢且安全的回到地面"
mode-change: "&b%device% 模式切換至: &9%mode%"
machines:
pattern-not-found: "&e查無此合成表請確認使用的機器或合成表的材料。"
@ -312,7 +313,7 @@ languages:
zh-CN: 中文(簡體)
el: 希臘語
he: 希伯來語
pt: 葡萄牙文(葡萄牙
pt-BR: 葡萄牙文(巴西
ar: 阿拉伯文
af: 南非語
da: 丹麥文
@ -324,7 +325,7 @@ languages:
fa: 波斯語
th: 泰語
ro: 羅馬尼亞語
pt-BR: 葡萄牙文(巴西
pt: 葡萄牙文(葡萄牙
bg: 保加利亞語
ko: 韓語
tr: 土耳其

View File

@ -0,0 +1,168 @@
---
slimefun:
multiblock:
name: Multiblock
lore:
- Постройте показаната структура
- както е показана. Не се craft-ва.
enhanced_crafting_table:
name: Enhanced Crafting Table
lore:
- Направете този Предмет, както е показано
- в Enhanced Crafting Table.
- Нормален Crafting Table(Работна Маса) няма да е достатъчен!
armor_forge:
name: Armor Forge
lore:
- Направете този Предмет, както е показано
- използвайки Armor Forge
grind_stone:
name: Grind Stone
lore:
- Направете този Предмет, както е показано
- използвайки Grind Stone
smeltery:
name: Smeltery
lore:
- Направете този Предмет, както е показано
- използвайки Smeltery
ore_crusher:
name: Ore Crusher
lore:
- Направете този Предмет, както е показано
- използвайки Ore Crusher
mob_drop:
name: Mob Drop
lore:
- Убийте този Mob, за да
- получите този предмет
gold_pan:
name: Gold Pan
lore:
- Използвайте Gold Pan, за да
- получите този предмет
compressor:
name: Compressor
lore:
- Направете този Предмет, както е показано
- използвайки Compressor
pressure_chamber:
name: Pressure Chamber
lore:
- Направете този Предмет, както е показано
- използвайки Pressure Chamber
ore_washer:
name: Ore Washer
lore:
- Направете този Предмет, както е показано
- използвайки Ore Washer
juicer:
name: Juicer
lore:
- Направете този Предмет, както е показано
- използвайки Juicer
magic_workbench:
name: Magic Workbench
lore:
- Направете този Предмет, както е показано
- използвайки Magic Workbench
ancient_altar:
name: Ancient Altar
lore:
- Направете този Предмет, както е показано
- използвайки Ancient Altar.
- Вижте Ancient Altar за повече информация
heated_pressure_chamber:
name: Heated Pressure Chamber
lore:
- Направете този Предмет, както е показано
- използвайки Heated Pressure Chamber
food_fabricator:
name: Food Fabricator
lore:
- Направете този Предмет, както е показано
- използвайки Food Fabricator
food_composter:
name: Food Composter
lore:
- Направете този Предмет, както е показано
- използвайки Food Composter
freezer:
name: Freezer
lore:
- Направете този Предмет, както е показано
- използвайки Freezer
geo_miner:
name: GEO Miner
lore:
- Този Предмет може да бъде събран
- като използвате GEO Miner
nuclear_reactor:
name: Nuclear Reactor
lore:
- Този Предмет е вторичен-продукт
- направен от Nuclear Reactor
oil_pump:
name: Oil Pump
lore:
- Този Предмет може да бъде събран
- като използвате Oil Pump
pickaxe_of_containment:
name: Pickaxe of Containment
lore:
- Този Блок може да бъде получен
- като изкопаете Spawner(Спаунер) с
- предмета Pickaxe of Containment
refinery:
name: Refinery
lore:
- Направете този Предмет, както е показано
- използвайки Refinery
barter_drop:
name: Piglin Bartering Drop
lore:
- Търгувайте с Piglins(Пиглини), като използвате
- Gold Ingots(Златни Кюлчета), за да получите този Предмет
minecraft:
shaped:
name: Shaped Crafting Recipe
lore:
- Направете този Предмет, както е показано
- в нормалния Crafting Table(Работна Маса).
- Формата е много важна.
shapeless:
name: Shapeless Crafting Recipe
lore:
- Направете този Предмет, както е показано
- в нормалния Crafting Table(Работна Маса).
- Тази Рецепта е безформена.
furnace:
name: Furnace Recipe
lore:
- Изпечете този предмет в Furnace(Печка)
- за да си направите желания предмет
blasting:
name: Blast Furnace Recipe
lore:
- Изпечете този предмет в Blast Furnace(Бласт Печка)
- за да си направите желания предмет
smoking:
name: Smoker Recipe
lore:
- Изпечете този предмет в Smoker(Упошвател)
- за да си направите желания предмет
campfire:
name: Campfire Recipe
lore:
- Изпечете този предмет върху Campfire(Огън)
- за да си направите желания предмет
stonecutting:
name: Stonecutter Recipe
lore:
- Направете този Предмет, както е показано
- използвайки Stonecutter
smithing:
name: Smithing Table Recipe
lore:
- Направете този Предмет, както е показано
- използвайки Smithing Table

View File

@ -246,3 +246,5 @@ slimefun:
caveman_talisman: Des Höhlenmenschen's Talisman
even_higher_tier_capacitors: Kondensatoren Stufe 3
elytra_cap: Harter Aufprall
energy_connectors: Kupferkabel
bee_armor: Bienen-Rüstung

View File

@ -246,3 +246,4 @@ slimefun:
iron_golem_assembler: Automated Iron Golems
villager_rune: Reset Villager Trades
elytra_cap: Crash Gear
bee_armor: Bee Armor

View File

@ -243,3 +243,7 @@ slimefun:
climbing_pick: Block Raider
shulker_shell: Shulkers Sintéticos
villager_rune: Restablece los Intercambios de los Aldeanos
caveman_talisman: Talisman of the Caveman
even_higher_tier_capacitors: Capacitores Tier 3
elytra_cap: Equipo de choque
energy_connectors: Conexiones Instaladas

View File

@ -246,3 +246,5 @@ slimefun:
caveman_talisman: Talisman de l'Homme des cavernes
even_higher_tier_capacitors: Condensateurs de niveau 3
elytra_cap: Matériel d'urgence
energy_connectors: Connexions filaires
bee_armor: Armure d'abeille

View File

@ -247,3 +247,4 @@ slimefun:
even_higher_tier_capacitors: 3. szintű kondenzátorok
elytra_cap: Ütközésvédelem
energy_connectors: Vezetékes csatlakozás
bee_armor: Méhpáncél

View File

@ -247,3 +247,4 @@ slimefun:
even_higher_tier_capacitors: キャパシタⅢ
elytra_cap: 衝撃緩和装備
energy_connectors: 有線接続
bee_armor: 蜂アーマー

View File

@ -247,3 +247,4 @@ slimefun:
even_higher_tier_capacitors: Большой накопитель энергии
elytra_cap: Противоударная экипировка
energy_connectors: Проводные соединения
bee_armor: Пчелиная броня

View File

@ -247,3 +247,4 @@ slimefun:
even_higher_tier_capacitors: 三级电容器
elytra_cap: 无伤落地
energy_connectors: 有线连接
bee_armor: 蜜蜂服

View File

@ -247,3 +247,4 @@ slimefun:
even_higher_tier_capacitors: 第三級電容器
elytra_cap: 體驗動能
energy_connectors: 電線
bee_armor: 蜂裝

View File

@ -1,20 +1,38 @@
# Name and version
name: Slimefun
version: ${project.version}
# Project metadata
author: The Slimefun 4 Community
description: Slimefun basically turns your entire Server into a FTB modpack without installing a single mod
website: https://github.com/Slimefun
description: Slimefun basically turns your entire Server into a FTB modpack without installing a single mod
# Technical settings
main: io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin
softdepend: [CS-CoreLib, PlaceholderAPI, WorldEdit, EmeraldEnchants, mcMMO]
api-version: '1.14'
# (Soft) dependencies of Slimefun, we hook into these plugins.
softdepend:
- CS-CoreLib
- PlaceholderAPI
- WorldEdit
- ClearLag
- mcMMO
- ItemsAdder
# We hook into these plugins too, but they depend on Slimefun.
loadBefore:
- ChestTerminal
- ExoticGarden
# Our commands
commands:
slimefun:
description: Slimefun command
aliases: sf
description: Slimefun base command
usage: You either forgot to install CS-CoreLib or you installed an unsupported version.
# Default permissions
permissions:
slimefun.command.guide:
description: Allows you to obtain the Slimefun guide book

View File

@ -61,7 +61,7 @@ class TestPluginClass {
Assertions.assertNotNull(SlimefunPlugin.getItemTextureService());
Assertions.assertNotNull(SlimefunPlugin.getPermissionsService());
Assertions.assertNotNull(SlimefunPlugin.getBlockDataService());
Assertions.assertNotNull(SlimefunPlugin.getThirdPartySupportService());
Assertions.assertNotNull(SlimefunPlugin.getIntegrations());
Assertions.assertNotNull(SlimefunPlugin.getWorldSettingsService());
Assertions.assertNotNull(SlimefunPlugin.getGitHubService());
Assertions.assertNotNull(SlimefunPlugin.getUpdater());

View File

@ -17,7 +17,7 @@ import be.seeseemelk.mockbukkit.MockBukkit;
import be.seeseemelk.mockbukkit.ServerMock;
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.BeeListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.entity.BeeListener;
import io.github.thebusybiscuit.slimefun4.testing.TestUtilities;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;

View File

@ -14,7 +14,7 @@ import org.junit.jupiter.api.Test;
import be.seeseemelk.mockbukkit.MockBukkit;
import be.seeseemelk.mockbukkit.ServerMock;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.FireworksListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.entity.FireworksListener;
import io.github.thebusybiscuit.slimefun4.utils.FireworkUtils;
class TestFireworksListener {

View File

@ -19,7 +19,7 @@ import be.seeseemelk.mockbukkit.ServerMock;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.VanillaItem;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.IronGolemListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.entity.IronGolemListener;
import io.github.thebusybiscuit.slimefun4.testing.TestUtilities;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;

View File

@ -24,7 +24,7 @@ import be.seeseemelk.mockbukkit.ServerMock;
import be.seeseemelk.mockbukkit.entity.ItemEntityMock;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.PiglinListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.entity.PiglinListener;
import io.github.thebusybiscuit.slimefun4.testing.TestUtilities;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;