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

Merge branch 'master' of https://github.com/Slimefun/Slimefun4.git into api/machine-operations

This commit is contained in:
TheBusyBiscuit 2021-05-24 11:09:52 +02:00
commit a249ca7848
55 changed files with 693 additions and 180 deletions

View File

@ -1,7 +1,6 @@
name: Auto approve
on:
pull_request
on: pull_request
jobs:
auto-approve:
@ -9,6 +8,9 @@ jobs:
name: Auto approve Pull Request
runs-on: ubuntu-latest
## Only run this on the main repo
if: github.event.pull_request.head.repo.full_name == 'Slimefun/Slimefun4'
steps:
- name: Approve via actions
uses: hmarr/auto-approve-action@v2.1.0

View File

@ -17,12 +17,17 @@ jobs:
name: Auto squash
runs-on: ubuntu-latest
## Only run this on the main repo
if: github.event.pull_request.head.repo.full_name == 'Slimefun/Slimefun4'
steps:
- name: Auto squash
uses: pascalgn/automerge-action@v0.13.1
uses: pascalgn/automerge-action@v0.14.1
env:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
MERGE_METHOD: "squash"
GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }}
UPDATE_RETRIES: 0
MERGE_METHOD: squash
MERGE_FORKS: false
MERGE_LABELS: "📄 Translations Update"
MERGE_COMMIT_MESSAGE: "[CI skip] New locale updates from Crowdin"
MERGE_DELETE_BRANCH: true
MERGE_LABELS: '📄 Translations Update'
MERGE_COMMIT_MESSAGE: '[CI skip] New locale updates from Crowdin'

View File

@ -12,13 +12,15 @@ jobs:
name: Discord Webhook
runs-on: ubuntu-latest
## Only run this on the main repo
if: github.repository == 'Slimefun/Slimefun4'
steps:
- name: Checkout repository
uses: actions/checkout@v2.3.4
- name: Set up Java JDK 11
uses: actions/setup-java@v2.0.0
uses: actions/setup-java@v2.1.0
with:
distribution: 'adopt'
java-version: '11'

View File

@ -24,7 +24,7 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v2
- name: Set up JDK 1.8
uses: actions/setup-java@v2.0.0
uses: actions/setup-java@v2.1.0
with:
distribution: 'adopt'
java-version: '8'

View File

@ -1,5 +1,6 @@
# Table of contents
- [Release Candidate 23 (TBD)](#release-candidate-23-tbd)
- [Release Candidate 24 (TBD)](#release-candidate-24-tbd)
- [Release Candidate 23 (19 May 2021)](#release-candidate-23-19-may-2021)
- [Release Candidate 22 (18 Apr 2021)](#release-candidate-22-18-apr-2021)
- [Release Candidate 21 (14 Mar 2021)](#release-candidate-21-14-mar-2021)
- [Release Candidate 20 (30 Jan 2021)](#release-candidate-20-30-jan-2021)
@ -23,7 +24,21 @@
- [Release Candidate 2 (29 Sep 2019)](#release-candidate-2-29-sep-2019)
- [Release Candidate 1 (26 Sep 2019)](#release-candidate-1-26-sep-2019)
## Release Candidate 23 (TBD)
## Release Candidate 24 (TBD)
#### Additions
* The speed of the Ancient Altar can now be configured in the `Items.yml` file
#### Changes
#### Fixes
* Fixed #3064
* Fixed #2964
* Fixed #2979
* Fixed a permissions issue with `/sf charge`
## Release Candidate 23 (19 May 2021)
https://thebusybiscuit.github.io/builds/TheBusyBiscuit/Slimefun4/stable/#23
#### Additions
* Added "Quartz Block -> 4 Quartz" recipe to Grind Stone
@ -35,8 +50,12 @@
* Added "Ender Lump Tier 3 -> 4 Ender Lump Tier 2" recipe to Grind Stone
* Added Tier 2 Auto-Enchanter
* Added Tier 2 Auto-Disenchanter
* (API) Added AsyncAutoEnchanterProcessEvent
* (API) Added Category#setTier() to modify a category's position in the guide
* Added the ability to disable auto (dis)enchanting with a lore - `use-ignored-lores` & `ignored-lores` in Items.yml
* Added an option to turn off the "researching animation" in the `config.yml`
* Added the option to turn off the "researching animation" within your Slimefun Guide
* Added Portable Teleporter
#### Changes
* Renamed "Solar Panel" to "Photovoltaic Cell" to avoid confusions with solar generators
@ -47,6 +66,7 @@
* (API) Removed deprecated "SlimefunBlockHandler"
* (API) Refactored "Machine Process" API
* Removed Automated Crafting Chamber
* Memory and performance improvements for Cargo and Energy networks
#### Fixes
* Fixed #2987
@ -58,9 +78,13 @@
* Fixed #2927
* Fixed #3007
* Fixed #3012
* Fixed #3013
* Fixed #3027
* Fixed #2978
* Fixed #3041
* Fixed #3036
* Possibly fixed #2927
* Fixed #3060
## Release Candidate 22 (18 Apr 2021)
https://thebusybiscuit.github.io/builds/TheBusyBiscuit/Slimefun4/stable/#22

12
pom.xml
View File

@ -230,7 +230,7 @@
<!-- Javadocs -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.2.0</version>
<version>3.3.0</version>
<configuration>
<reportOutputDirectory>${project.basedir}</reportOutputDirectory>
@ -343,19 +343,19 @@
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.7.1</version>
<version>5.7.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.9.0</version>
<version>3.10.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.seeseemelk</groupId>
<artifactId>MockBukkit-v1.16</artifactId>
<version>0.34.2</version>
<version>1.0.1</version>
<scope>test</scope>
<exclusions>
@ -370,7 +370,7 @@
<!-- Shaded packages -->
<dependency>
<groupId>com.github.TheBusyBiscuit</groupId>
<groupId>com.github.thebusybiscuit</groupId>
<artifactId>CS-CoreLib2</artifactId>
<version>0.31.0</version>
<scope>compile</scope>
@ -470,7 +470,7 @@
<dependency>
<groupId>com.github.LoneDev6</groupId>
<artifactId>itemsadder-api</artifactId>
<version>2.3.3</version>
<version>2.3.8</version>
<scope>provided</scope>
<exclusions>

View File

@ -0,0 +1,92 @@
package io.github.thebusybiscuit.slimefun4.api.events;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting.AutoEnchanter;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
import org.apache.commons.lang.Validate;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.bukkit.inventory.ItemStack;
import javax.annotation.Nonnull;
/**
* An {@link Event} that is called whenever an {@link AutoEnchanter} is
* enchanting an {@link ItemStack}.
*
* @author StarWishsama
*/
public class AsyncAutoEnchanterProcessEvent extends Event implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private final ItemStack item;
private final ItemStack enchantedBook;
private final BlockMenu menu;
private boolean cancelled;
public AsyncAutoEnchanterProcessEvent(@Nonnull ItemStack item, @Nonnull ItemStack enchantedBook, @Nonnull BlockMenu menu) {
super(true);
Validate.notNull(item, "The item to enchant cannot be null!");
Validate.notNull(enchantedBook, "The enchanted book to enchant cannot be null!");
Validate.notNull(menu, "The menu of auto-enchanter cannot be null!");
this.item = item;
this.enchantedBook = enchantedBook;
this.menu = menu;
}
/**
* This returns the {@link ItemStack} that is being enchanted.
*
* @return The {@link ItemStack} that is being enchanted
*/
@Nonnull
public ItemStack getItem() {
return item;
}
/**
* This returns the {@link ItemStack} that is being used enchanted book
*
* @return The {@link ItemStack} that is being used enchanted book
*/
@Nonnull
public ItemStack getEnchantedBook() {
return enchantedBook;
}
/**
* This returns the {@link AutoEnchanter}'s {@link BlockMenu}
*
* @return The {@link BlockMenu} of {@link AutoEnchanter} that is enchanting item
*/
@Nonnull
public BlockMenu getMenu() {
return menu;
}
@Nonnull
public static HandlerList getHandlerList() {
return handlers;
}
@Nonnull
@Override
public HandlerList getHandlers() {
return getHandlerList();
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
}

View File

@ -51,12 +51,24 @@ public final class TeleportationManager {
*/
private final Set<UUID> teleporterUsers = new HashSet<>();
/**
* Opens the GUI of the teleporter and calculates the network complexity of the {@link Player}
*
* @param p {@link Player} to be teleported
* @param ownerUUID {@link UUID} of the {@link Player} who owns the teleporter device
* @param b {@link Block} from where the {@link Player} is being teleported
*/
@ParametersAreNonnullByDefault
public void openTeleporterGUI(Player p, UUID uuid, Block b, int complexity) {
public void openTeleporterGUI(Player p, UUID ownerUUID, Block b) {
openTeleporterGUI(p, ownerUUID, b, SlimefunPlugin.getGPSNetwork().getNetworkComplexity(ownerUUID));
}
@ParametersAreNonnullByDefault
public void openTeleporterGUI(Player p, UUID ownerUUID, Block b, int complexity) {
if (teleporterUsers.add(p.getUniqueId())) {
p.playSound(p.getLocation(), Sound.UI_BUTTON_CLICK, 1F, 1F);
PlayerProfile.fromUUID(uuid, profile -> {
PlayerProfile.fromUUID(ownerUUID, profile -> {
ChestMenu menu = new ChestMenu("&3Teleporter");
menu.addMenuCloseHandler(pl -> teleporterUsers.remove(pl.getUniqueId()));

View File

@ -4,14 +4,18 @@ import java.util.ArrayDeque;
import java.util.HashSet;
import java.util.Queue;
import java.util.Set;
import java.util.UUID;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.apache.commons.lang.Validate;
import org.bukkit.Color;
import org.bukkit.Location;
import org.bukkit.Particle;
import org.bukkit.World;
import io.github.thebusybiscuit.cscorelib2.blocks.BlockPosition;
import io.github.thebusybiscuit.slimefun4.core.networks.NetworkManager;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.NetworkListener;
@ -20,6 +24,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.listeners.NetworkListen
* An abstract Network class to manage networks in a stateful way
*
* @author meiamsome
* @author TheBusyBiscuit
*
* @see NetworkListener
* @see NetworkManager
@ -37,8 +42,19 @@ public abstract class Network {
*/
protected Location regulator;
/**
* The {@link UUID} of the {@link World} this {@link Network} exists within.
*/
private final UUID worldId;
/**
* This {@link Set} holds all {@link Network} positions that are part of this {@link Network}.
* The {@link World} should be equal for all positions, therefore we can save memory by simply
* storing {@link BlockPosition#getAsLong(int, int, int)}.
*/
private final Set<Long> positions = new HashSet<>();
private final Queue<Location> nodeQueue = new ArrayDeque<>();
protected final Set<Location> connectedLocations = new HashSet<>();
protected final Set<Location> regulatorNodes = new HashSet<>();
protected final Set<Location> connectorNodes = new HashSet<>();
protected final Set<Location> terminusNodes = new HashSet<>();
@ -57,8 +73,9 @@ public abstract class Network {
this.manager = manager;
this.regulator = regulator;
this.worldId = regulator.getWorld().getUID();
connectedLocations.add(regulator);
positions.add(BlockPosition.getAsLong(regulator));
nodeQueue.add(regulator.clone());
}
@ -115,7 +132,10 @@ public abstract class Network {
* The {@link Location} to add
*/
protected void addLocationToNetwork(@Nonnull Location l) {
if (connectedLocations.add(l.clone())) {
Validate.notNull(l, "You cannot add a Location to a Network which is null!");
Validate.isTrue(l.getWorld().getUID().equals(worldId), "Networks cannot exist in multiple worlds!");
if (positions.add(BlockPosition.getAsLong(l))) {
markDirty(l);
}
}
@ -144,10 +164,14 @@ public abstract class Network {
* @return Whether the given {@link Location} is part of this {@link Network}
*/
public boolean connectsTo(@Nonnull Location l) {
if (regulator.equals(l)) {
Validate.notNull(l, "The Location cannot be null.");
if (this.regulator.equals(l)) {
return true;
} else if (!l.getWorld().getUID().equals(this.worldId)) {
return false;
} else {
return connectedLocations.contains(l);
return positions.contains(BlockPosition.getAsLong(l));
}
}
@ -225,7 +249,8 @@ public abstract class Network {
*/
public void display() {
if (manager.isVisualizerEnabled()) {
SlimefunPlugin.runSync(new NetworkVisualizer(this));
// TODO: Make Color configurable / network-dependent
SlimefunPlugin.runSync(new NetworkVisualizer(this, Color.BLUE));
}
}

View File

@ -2,6 +2,7 @@ package io.github.thebusybiscuit.slimefun4.api.network;
import javax.annotation.Nonnull;
import org.apache.commons.lang.Validate;
import org.bukkit.Color;
import org.bukkit.Location;
import org.bukkit.Particle;
@ -18,7 +19,7 @@ class NetworkVisualizer implements Runnable {
/**
* The {@link DustOptions} define the {@link Color} and size of our particles.
*/
private final DustOptions options = new DustOptions(Color.BLUE, 3.5F);
private final DustOptions particleOptions;
/**
* This is our {@link Network} instance.
@ -31,8 +32,12 @@ class NetworkVisualizer implements Runnable {
* @param network
* The {@link Network} to visualize
*/
NetworkVisualizer(@Nonnull Network network) {
NetworkVisualizer(@Nonnull Network network, @Nonnull Color color) {
Validate.notNull(network, "The network should not be null.");
Validate.notNull(color, "The color cannot be null.");
this.network = network;
this.particleOptions = new DustOptions(color, 3F);
}
@Override
@ -53,7 +58,7 @@ class NetworkVisualizer implements Runnable {
* The {@link Location} of our node
*/
private void spawnParticles(@Nonnull Location l) {
l.getWorld().spawnParticle(Particle.REDSTONE, l.getX() + 0.5, l.getY() + 0.5, l.getZ() + 0.5, 1, 0, 0, 0, 1, options);
l.getWorld().spawnParticle(Particle.REDSTONE, l.getX() + 0.5, l.getY() + 0.5, l.getZ() + 0.5, 1, 0, 0, 0, 1, particleOptions);
}
}

View File

@ -69,6 +69,7 @@ public final class SlimefunRegistry {
private boolean enableResearches;
private boolean freeCreativeResearches;
private boolean researchFireworks;
private boolean disableLearningAnimation;
private boolean logDuplicateBlockEntries;
private boolean talismanActionBarMessages;
@ -109,6 +110,7 @@ public final class SlimefunRegistry {
backwardsCompatibility = cfg.getBoolean("options.backwards-compatibility");
freeCreativeResearches = cfg.getBoolean("researches.free-in-creative-mode");
researchFireworks = cfg.getBoolean("researches.enable-fireworks");
disableLearningAnimation = cfg.getBoolean("researches.disable-learning-animation");
logDuplicateBlockEntries = cfg.getBoolean("options.log-duplicate-block-entries");
talismanActionBarMessages = cfg.getBoolean("talismans.use-actionbar");
}
@ -238,6 +240,15 @@ public final class SlimefunRegistry {
return researchFireworks;
}
/**
* Returns whether the research learning animations is disabled
*
* @return Whether the research learning animations is disabled
*/
public boolean isLearningAnimationDisabled() {
return disableLearningAnimation;
}
/**
* This method returns a {@link List} of every enabled {@link MultiBlock}.
*

View File

@ -1,5 +1,7 @@
package io.github.thebusybiscuit.slimefun4.core.commands.subcommands;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
@ -11,10 +13,22 @@ import io.github.thebusybiscuit.slimefun4.core.commands.SlimefunCommand;
import io.github.thebusybiscuit.slimefun4.core.commands.SubCommand;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.backpacks.RestoredBackpack;
import io.github.thebusybiscuit.slimefun4.utils.PatternUtils;
/**
* This command that allows for backpack retrieval in the event they are lost.
* The command accepts a name and id, if those match up it spawns a Medium Backpack
* with the correct lore set in the sender's inventory.
*
* @author Sfiguz7
*
* @see RestoredBackpack
*
*/
class BackpackCommand extends SubCommand {
@ParametersAreNonnullByDefault
BackpackCommand(SlimefunPlugin plugin, SlimefunCommand cmd) {
super(plugin, cmd, "backpack", false);
}

View File

@ -1,5 +1,7 @@
package io.github.thebusybiscuit.slimefun4.core.commands.subcommands;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
@ -19,6 +21,7 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
*/
class ChargeCommand extends SubCommand {
@ParametersAreNonnullByDefault
ChargeCommand(SlimefunPlugin plugin, SlimefunCommand cmd) {
super(plugin, cmd, "charge", false);
}
@ -31,10 +34,11 @@ class ChargeCommand extends SubCommand {
@Override
public void onExecute(CommandSender sender, String[] args) {
if (sender instanceof Player) {
if (sender.hasPermission("slimefun.charge.command")) {
if (sender.hasPermission("slimefun.command.charge")) {
Player p = (Player) sender;
ItemStack item = p.getInventory().getItemInMainHand();
SlimefunItem slimefunItem = SlimefunItem.getByItem(item);
if (slimefunItem instanceof Rechargeable) {
Rechargeable rechargeableItem = (Rechargeable) slimefunItem;
rechargeableItem.setItemCharge(item, rechargeableItem.getMaxItemCharge(item));

View File

@ -1,5 +1,7 @@
package io.github.thebusybiscuit.slimefun4.core.commands.subcommands;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@ -10,6 +12,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
class CheatCommand extends SubCommand {
@ParametersAreNonnullByDefault
CheatCommand(SlimefunPlugin plugin, SlimefunCommand cmd) {
super(plugin, cmd, "cheat", false);
}

View File

@ -1,5 +1,7 @@
package io.github.thebusybiscuit.slimefun4.core.commands.subcommands;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@ -10,6 +12,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
class DebugFishCommand extends SubCommand {
@ParametersAreNonnullByDefault
DebugFishCommand(SlimefunPlugin plugin, SlimefunCommand cmd) {
super(plugin, cmd, "debug_fish", true);
}

View File

@ -16,12 +16,15 @@ import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import javax.annotation.ParametersAreNonnullByDefault;
class GiveCommand extends SubCommand {
private static final String PLACEHOLDER_PLAYER = "%player%";
private static final String PLACEHOLDER_ITEM = "%item%";
private static final String PLACEHOLDER_AMOUNT = "%amount%";
@ParametersAreNonnullByDefault
GiveCommand(SlimefunPlugin plugin, SlimefunCommand cmd) {
super(plugin, cmd, "give", false);
}

View File

@ -1,5 +1,7 @@
package io.github.thebusybiscuit.slimefun4.core.commands.subcommands;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@ -11,6 +13,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
class GuideCommand extends SubCommand {
@ParametersAreNonnullByDefault
GuideCommand(SlimefunPlugin plugin, SlimefunCommand cmd) {
super(plugin, cmd, "guide", false);
}

View File

@ -1,5 +1,7 @@
package io.github.thebusybiscuit.slimefun4.core.commands.subcommands;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.command.CommandSender;
import io.github.thebusybiscuit.slimefun4.core.commands.SlimefunCommand;
@ -8,6 +10,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
class HelpCommand extends SubCommand {
@ParametersAreNonnullByDefault
HelpCommand(SlimefunPlugin plugin, SlimefunCommand cmd) {
super(plugin, cmd, "help", false);
}

View File

@ -13,6 +13,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
class OpenGuideCommand extends SubCommand {
@ParametersAreNonnullByDefault
OpenGuideCommand(SlimefunPlugin plugin, SlimefunCommand cmd) {
super(plugin, cmd, "open_guide", false);
}

View File

@ -3,6 +3,9 @@ package io.github.thebusybiscuit.slimefun4.core.commands.subcommands;
import java.util.Optional;
import java.util.function.UnaryOperator;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@ -18,6 +21,7 @@ class ResearchCommand extends SubCommand {
private static final String PLACEHOLDER_PLAYER = "%player%";
private static final String PLACEHOLDER_RESEARCH = "%research%";
@ParametersAreNonnullByDefault
ResearchCommand(SlimefunPlugin plugin, SlimefunCommand cmd) {
super(plugin, cmd, "research", false);
}
@ -57,6 +61,7 @@ class ResearchCommand extends SubCommand {
}
}
@ParametersAreNonnullByDefault
private void giveResearch(CommandSender sender, Player p, String input) {
Optional<Research> research = getResearchFromString(input);
@ -70,6 +75,7 @@ class ResearchCommand extends SubCommand {
}
}
@ParametersAreNonnullByDefault
private void researchAll(CommandSender sender, PlayerProfile profile, Player p) {
for (Research res : SlimefunPlugin.getRegistry().getResearches()) {
if (!profile.hasUnlocked(res)) {
@ -80,6 +86,7 @@ class ResearchCommand extends SubCommand {
}
}
@ParametersAreNonnullByDefault
private void reset(PlayerProfile profile, Player p) {
for (Research research : SlimefunPlugin.getRegistry().getResearches()) {
profile.setResearched(research, false);
@ -88,7 +95,8 @@ class ResearchCommand extends SubCommand {
SlimefunPlugin.getLocalization().sendMessage(p, "commands.research.reset", true, msg -> msg.replace(PLACEHOLDER_PLAYER, p.getName()));
}
private Optional<Research> getResearchFromString(String input) {
@Nonnull
private Optional<Research> getResearchFromString(@Nonnull String input) {
if (!input.contains(":")) {
return Optional.empty();
}

View File

@ -2,6 +2,8 @@ package io.github.thebusybiscuit.slimefun4.core.commands.subcommands;
import java.util.Arrays;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@ -14,6 +16,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
class SearchCommand extends SubCommand {
@ParametersAreNonnullByDefault
SearchCommand(SlimefunPlugin plugin, SlimefunCommand cmd) {
super(plugin, cmd, "search", false);
}

View File

@ -4,6 +4,8 @@ import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import javax.annotation.Nonnull;
import io.github.thebusybiscuit.slimefun4.core.commands.SlimefunCommand;
import io.github.thebusybiscuit.slimefun4.core.commands.SubCommand;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
@ -20,7 +22,8 @@ public final class SlimefunSubCommands {
private SlimefunSubCommands() {}
public static Collection<SubCommand> getAllCommands(SlimefunCommand cmd) {
@Nonnull
public static Collection<SubCommand> getAllCommands(@Nonnull SlimefunCommand cmd) {
SlimefunPlugin plugin = cmd.getPlugin();
List<SubCommand> commands = new LinkedList<>();

View File

@ -2,6 +2,8 @@ package io.github.thebusybiscuit.slimefun4.core.commands.subcommands;
import java.util.Optional;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.entity.Player;
@ -14,6 +16,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
class StatsCommand extends SubCommand {
@ParametersAreNonnullByDefault
StatsCommand(SlimefunPlugin plugin, SlimefunCommand cmd) {
super(plugin, cmd, "stats", false);
}

View File

@ -1,5 +1,7 @@
package io.github.thebusybiscuit.slimefun4.core.commands.subcommands;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.block.BlockFace;
@ -12,6 +14,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
class TeleporterCommand extends SubCommand {
@ParametersAreNonnullByDefault
TeleporterCommand(SlimefunPlugin plugin, SlimefunCommand cmd) {
super(plugin, cmd, "teleporter", false);
}

View File

@ -24,6 +24,7 @@ class TimingsCommand extends SubCommand {
private static final String FLAG_PREFIX = "--";
private final Set<String> flags = new HashSet<>(Arrays.asList("verbose"));
@ParametersAreNonnullByDefault
TimingsCommand(SlimefunPlugin plugin, SlimefunCommand cmd) {
super(plugin, cmd, "timings", false);
}

View File

@ -3,6 +3,7 @@ package io.github.thebusybiscuit.slimefun4.core.commands.subcommands;
import java.util.Collection;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
@ -29,6 +30,7 @@ import net.md_5.bungee.api.chat.hover.content.Text;
*/
class VersionsCommand extends SubCommand {
@ParametersAreNonnullByDefault
VersionsCommand(SlimefunPlugin plugin, SlimefunCommand cmd) {
super(plugin, cmd, "versions", false);
}

View File

@ -3,12 +3,14 @@ package io.github.thebusybiscuit.slimefun4.core.guide;
import java.util.function.Consumer;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.GameMode;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.core.guide.options.SlimefunGuideSettings;
import io.github.thebusybiscuit.slimefun4.core.researching.Research;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.guide.SurvivalSlimefunGuide;
@ -18,7 +20,7 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
/**
* This interface is used for the different implementations that add behaviour
* to the {@link SlimefunGuide}.
*
*
* @author TheBusyBiscuit
*
* @see SlimefunGuideMode
@ -30,7 +32,7 @@ public interface SlimefunGuideImplementation {
/**
* Every {@link SlimefunGuideImplementation} can be associated with a
* {@link SlimefunGuideMode}.
*
*
* @return The mode this {@link SlimefunGuideImplementation} represents
*/
@Nonnull
@ -40,22 +42,28 @@ public interface SlimefunGuideImplementation {
* Returns the {@link ItemStack} representation for this {@link SlimefunGuideImplementation}.
* In other words: The {@link ItemStack} you hold in your hand and that you use to
* open your {@link SlimefunGuide}
*
*
* @return The {@link ItemStack} representation for this {@link SlimefunGuideImplementation}
*/
@Nonnull
ItemStack getItem();
@ParametersAreNonnullByDefault
void openMainMenu(PlayerProfile profile, int page);
@ParametersAreNonnullByDefault
void openCategory(PlayerProfile profile, Category category, int page);
@ParametersAreNonnullByDefault
void openSearch(PlayerProfile profile, String input, boolean addToHistory);
@ParametersAreNonnullByDefault
void displayItem(PlayerProfile profile, ItemStack item, int index, boolean addToHistory);
@ParametersAreNonnullByDefault
void displayItem(PlayerProfile profile, SlimefunItem item, boolean addToHistory);
@ParametersAreNonnullByDefault
default void unlockItem(Player p, SlimefunItem sfitem, Consumer<Player> callback) {
Research research = sfitem.getResearch();
@ -63,7 +71,9 @@ public interface SlimefunGuideImplementation {
research.unlock(p, true, callback);
} else {
p.setLevel(p.getLevel() - research.getCost());
research.unlock(p, false, callback);
boolean skipLearningAnimation = SlimefunPlugin.getRegistry().isLearningAnimationDisabled() || !SlimefunGuideSettings.hasLearningAnimationEnabled(p);
research.unlock(p, skipLearningAnimation, callback);
}
}

View File

@ -0,0 +1,74 @@
package io.github.thebusybiscuit.slimefun4.core.guide.options;
import java.util.List;
import java.util.Optional;
import javax.annotation.Nonnull;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.data.PersistentDataAPI;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
/**
* {@link LearningAnimationOption} represents a setting in the Slimefun guide book.
* It allows users to disable/enable the "learning animation",
* the information in chat when doing a Slimefun research.
*
* @author martinbrom
*/
class LearningAnimationOption implements SlimefunGuideOption<Boolean> {
@Nonnull
@Override
public SlimefunAddon getAddon() {
return SlimefunPlugin.instance();
}
@Nonnull
@Override
public NamespacedKey getKey() {
return new NamespacedKey(SlimefunPlugin.instance(), "research_learning_animation");
}
@Nonnull
@Override
public Optional<ItemStack> getDisplayItem(@Nonnull Player p, @Nonnull ItemStack guide) {
if (SlimefunPlugin.getRegistry().isLearningAnimationDisabled()) {
return Optional.empty();
} else {
boolean enabled = getSelectedOption(p, guide).orElse(true);
String optionState = enabled ? "enabled" : "disabled";
List<String> lore = SlimefunPlugin.getLocalization().getMessages(p, "guide.options.learning-animation." + optionState + ".text");
lore.add("");
lore.add("&7\u21E8 " + SlimefunPlugin.getLocalization().getMessage(p, "guide.options.learning-animation." + optionState + ".click"));
ItemStack item = new CustomItem(enabled ? Material.MAP : Material.PAPER, lore);
return Optional.of(item);
}
}
@Override
public void onClick(@Nonnull Player p, @Nonnull ItemStack guide) {
setSelectedOption(p, guide, !getSelectedOption(p, guide).orElse(true));
SlimefunGuideSettings.openSettings(p, guide);
}
@Override
public Optional<Boolean> getSelectedOption(@Nonnull Player p, @Nonnull ItemStack guide) {
NamespacedKey key = getKey();
boolean value = !PersistentDataAPI.hasByte(p, key) || PersistentDataAPI.getByte(p, key) == (byte) 1;
return Optional.of(value);
}
@Override
public void setSelectedOption(@Nonnull Player p, @Nonnull ItemStack guide, @Nonnull Boolean value) {
PersistentDataAPI.setByte(p, getKey(), (byte) (value.booleanValue() ? 1 : 0));
}
}

View File

@ -47,6 +47,7 @@ public final class SlimefunGuideSettings {
static {
options.add(new GuideModeOption());
options.add(new FireworksOption());
options.add(new LearningAnimationOption());
options.add(new PlayerLanguageOption());
}
@ -238,15 +239,51 @@ public final class SlimefunGuideSettings {
* @return Whether this {@link Player} wants to see fireworks when unlocking a {@link Research}
*/
public static boolean hasFireworksEnabled(@Nonnull Player p) {
return getOptionValue(p, FireworksOption.class, true);
}
/**
* This method checks if the given {@link Player} has enabled the {@link LearningAnimationOption}
* in their {@link SlimefunGuide}.
* If they enabled this setting, they will see messages in chat about the progress of their {@link Research}.
*
* @param p
* The {@link Player}
*
* @return Whether this {@link Player} wants to info messages in chat when unlocking a {@link Research}
*/
public static boolean hasLearningAnimationEnabled(@Nonnull Player p) {
return getOptionValue(p, LearningAnimationOption.class, true);
}
/**
* Helper method to get the value of a {@link SlimefunGuideOption} that the {@link Player}
* has set in their {@link SlimefunGuide}
*
* @param p
* The {@link Player}
* @param optionsClass
* Class of the {@link SlimefunGuideOption} to get the value of
* @param defaultValue
* Default value to return in case the option is not found at all or has no value set
* @param <T>
* Type of the {@link SlimefunGuideOption}
* @param <V>
* Type of the {@link SlimefunGuideOption} value
*
* @return The value of given {@link SlimefunGuideOption}
*/
@Nonnull
private static <T extends SlimefunGuideOption<V>, V> V getOptionValue(@Nonnull Player p, @Nonnull Class<T> optionsClass, @Nonnull V defaultValue) {
for (SlimefunGuideOption<?> option : options) {
if (option instanceof FireworksOption) {
FireworksOption fireworks = (FireworksOption) option;
if (optionsClass.isInstance(option)) {
T o = optionsClass.cast(option);
ItemStack guide = SlimefunGuide.getItem(SlimefunGuideMode.SURVIVAL_MODE);
return fireworks.getSelectedOption(p, guide).orElse(true);
return o.getSelectedOption(p, guide).orElse(defaultValue);
}
}
return true;
return defaultValue;
}
}

View File

@ -1,9 +1,11 @@
package io.github.thebusybiscuit.slimefun4.core.networks;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Level;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@ -12,16 +14,21 @@ import org.apache.commons.lang.Validate;
import org.bukkit.Location;
import org.bukkit.Server;
import io.github.thebusybiscuit.cscorelib2.blocks.BlockPosition;
import io.github.thebusybiscuit.cscorelib2.config.Config;
import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion;
import io.github.thebusybiscuit.slimefun4.api.network.Network;
import io.github.thebusybiscuit.slimefun4.core.networks.cargo.CargoNet;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.NetworkListener;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
/**
* The {@link NetworkManager} is responsible for holding all instances of {@link Network}
* and providing some utility methods that would have probably been static otherwise.
*
* @author TheBusyBiscuit
* @author meiamsome
*
* @see Network
* @see NetworkListener
@ -32,7 +39,16 @@ public class NetworkManager {
private final int maxNodes;
private final boolean enableVisualizer;
private final boolean deleteExcessItems;
private final List<Network> networks = new LinkedList<>();
/**
* Fixes #3041
*
* We use a {@link CopyOnWriteArrayList} here to ensure thread-safety.
* This {@link List} is also much more frequently read than being written to.
* Therefore a {@link CopyOnWriteArrayList} should be perfect for this, even
* if insertions come at a slight cost.
*/
private final List<Network> networks = new CopyOnWriteArrayList<>();
/**
* This creates a new {@link NetworkManager} with the given capacity.
@ -93,12 +109,13 @@ public class NetworkManager {
/**
* This returns a {@link List} of every {@link Network} on the {@link Server}.
* The returned {@link List} is not modifiable.
*
* @return A {@link List} containing every {@link Network} on the {@link Server}
*/
@Nonnull
public List<Network> getNetworkList() {
return networks;
return Collections.unmodifiableList(networks);
}
@Nonnull
@ -169,11 +186,30 @@ public class NetworkManager {
public void updateAllNetworks(@Nonnull Location l) {
Validate.notNull(l, "The Location cannot be null");
// No need to create a sublist and loop through it if there are no Networks
if (!networks.isEmpty()) {
try {
/*
* No need to create a sublist and loop through it if
* there aren't even any networks on the server.
*/
if (networks.isEmpty()) {
return;
}
/*
* Only a Slimefun block can be part of a Network.
* This check helps to speed up performance.
*
* (Skip for Unit Tests as they don't support block info yet)
*/
if (!BlockStorage.hasBlockInfo(l) && SlimefunPlugin.getMinecraftVersion() != MinecraftVersion.UNIT_TEST) {
return;
}
for (Network network : getNetworksFromLocation(l, Network.class)) {
network.markDirty(l);
}
} catch (Exception x) {
SlimefunPlugin.logger().log(Level.SEVERE, x, () -> "An Exception was thrown while causing a networks update @ " + new BlockPosition(l));
}
}

View File

@ -74,6 +74,7 @@ class ContributionsConnector extends GitHubConnector {
aliases.put("bverhoeven", "soczol");
aliases.put("ramdon-person", "ramdon_person");
aliases.put("NCBPFluffyBear", "FluffyBear_");
aliases.put("martinbrom", "OneTime97");
}
/**

View File

@ -745,6 +745,7 @@ public final class SlimefunItems {
public static final SlimefunItemStack GPS_TELEPORTATION_MATRIX = new SlimefunItemStack("GPS_TELEPORTATION_MATRIX", Material.IRON_BLOCK, "&bGPS Teleporter Matrix", "", "&fThis is your Teleporter's Main Component", "&fThis Matrix allows Players to choose from all", "&fWaypoints made by the Player who has placed", "&fthis Device.");
public static final SlimefunItemStack GPS_ACTIVATION_DEVICE_SHARED = new SlimefunItemStack("GPS_ACTIVATION_DEVICE_SHARED", Material.STONE_PRESSURE_PLATE, "&fGPS Activation Device &3(Shared)", "", "&fPlace this onto a Teleportation Matrix", "&fand step onto this Plate to activate", "&fthe Teleportation Process");
public static final SlimefunItemStack GPS_ACTIVATION_DEVICE_PERSONAL = new SlimefunItemStack("GPS_ACTIVATION_DEVICE_PERSONAL", Material.STONE_PRESSURE_PLATE, "&fGPS Activation Device &a(Personal)", "", "&fPlace this onto a Teleportation Matrix", "&fand step onto this Plate to activate", "&fthe Teleportation Process", "", "&fThis Version only allows the Person who", "&fplaced this Device to use it");
public static final SlimefunItemStack PORTABLE_TELEPORTER = new SlimefunItemStack("PORTABLE_TELEPORTER", Material.COMPASS, "&bPortable Teleporter", "", "&fThis device allows you to teleport", "&fto your waypoints from anywhere", "", LoreBuilder.powerCharged(0, 50), "", "&eRight Click&7 to use");
public static final SlimefunItemStack ELEVATOR_PLATE = new SlimefunItemStack("ELEVATOR_PLATE", Material.STONE_PRESSURE_PLATE, "&bElevator Plate", "", "&fPlace an Elevator Plate on every floor", "&fand you will be able to teleport between them.", "", "&eRight Click this Block &7to name it");
public static final SlimefunItemStack INFUSED_HOPPER = new SlimefunItemStack("INFUSED_HOPPER", Material.HOPPER, "&5Infused Hopper", "", "&fAutomatically picks up nearby Items in a 7x7x7", "&fRadius when placed.");

View File

@ -3,9 +3,14 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.altar;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.api.events.AncientAltarCraftEvent;
import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting;
import io.github.thebusybiscuit.slimefun4.api.items.settings.IntRangeSetting;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.AncientAltarListener;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.AncientAltarTask;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
@ -17,41 +22,47 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
* The {@link AncientAltar} is a multiblock structure.
* The altar itself stands in the center, surrounded by {@link AncientPedestal Pedestals}, it is used
* to craft various magical items.
*
*
* @author TheBusyBiscuit
*
* @author martinbrom
*
* @see AncientAltarListener
* @see AncientAltarTask
* @see AncientAltarCraftEvent
* @see AncientPedestal
*
*/
public class AncientAltar extends SlimefunItem {
private final int speed;
/**
* This number represents a delay in ticks between two ritual steps.
* The whole ritual process consists of 36 steps, an item is consumed every 4 steps (8 times)
* and the output is spawned after the 36th step completes.
*/
private static final int DEFAULT_STEP_DELAY = 8;
private final List<AltarRecipe> recipes = new ArrayList<>();
public AncientAltar(Category category, int speed, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
private final ItemSetting<Integer> stepDelay = new IntRangeSetting(this, "step-delay", 0, DEFAULT_STEP_DELAY, Integer.MAX_VALUE);
@ParametersAreNonnullByDefault
public AncientAltar(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
if (speed < 1) {
throw new IllegalArgumentException("The speed must be at least 1.");
}
this.speed = speed;
addItemSetting(stepDelay);
}
/**
* This returns the speed of this {@link AncientAltar}.
* This number determines how much ticks happen inbetween a step in the ritual animation.
* The default is 8 ticks.
*
* @return The speed of this {@link AncientAltar}
* This returns the delay of this {@link AncientAltar}.
* This number determines how many ticks happen in between a step in the ritual animation.
* The default is {@value #DEFAULT_STEP_DELAY} ticks.
*
* @return The delay between two ritual steps of this {@link AncientAltar}
*/
public int getSpeed() {
return speed;
public int getStepDelay() {
return stepDelay.getValue();
}
@Nonnull
public List<AltarRecipe> getRecipes() {
return recipes;
}

View File

@ -684,7 +684,7 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock,
if ("false".equals(data.getString("paused"))) {
BlockMenu menu = BlockStorage.getInventory(b);
String fuelData = data.getString("fuel");
float fuel = fuelData == null ? 0 : Float.parseFloat(fuelData);

View File

@ -67,15 +67,16 @@ public class WoodcutterAndroid extends ProgrammableAndroid {
private void breakLog(Block log, Block android, BlockMenu menu, BlockFace face) {
ItemStack drop = new ItemStack(log.getType());
if (menu.fits(drop, getOutputSlots())) {
menu.pushItem(drop, getOutputSlots());
log.getWorld().playEffect(log.getLocation(), Effect.STEP_SOUND, log.getType());
// We try to push the log into the android's inventory, but nothing happens if it does not fit
menu.pushItem(drop, getOutputSlots());
if (log.getY() == android.getRelative(face).getY()) {
replant(log);
} else {
log.setType(Material.AIR);
}
log.getWorld().playEffect(log.getLocation(), Effect.STEP_SOUND, log.getType());
// If the android just chopped the bottom log, we replant the appropriate sapling
if (log.getY() == android.getRelative(face).getY()) {
replant(log);
} else {
log.setType(Material.AIR);
}
}

View File

@ -1,18 +1,7 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
import io.github.thebusybiscuit.cscorelib2.inventory.InvUtils;
import io.github.thebusybiscuit.slimefun4.api.events.AsyncAutoEnchanterProcessEvent;
import io.github.thebusybiscuit.slimefun4.api.events.AutoEnchantEvent;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
@ -20,6 +9,16 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineRecipe;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.HashMap;
import java.util.Map;
/**
* The {@link AutoEnchanter}, in contrast to the {@link AutoDisenchanter}, adds
@ -65,10 +64,10 @@ public class AutoEnchanter extends AbstractEnchantmentMachine {
return null;
}
ItemStack secondItem = menu.getItemInSlot(slot);
ItemStack enchantedBook = menu.getItemInSlot(slot);
if (secondItem != null && secondItem.getType() == Material.ENCHANTED_BOOK) {
return enchant(menu, item, secondItem);
if (enchantedBook != null && enchantedBook.getType() == Material.ENCHANTED_BOOK) {
return enchant(menu, item, enchantedBook);
}
}
@ -78,6 +77,14 @@ public class AutoEnchanter extends AbstractEnchantmentMachine {
@Nullable
@ParametersAreNonnullByDefault
protected MachineRecipe enchant(BlockMenu menu, ItemStack target, ItemStack enchantedBook) {
// Call an event so other Plugins can modify it.
AsyncAutoEnchanterProcessEvent event = new AsyncAutoEnchanterProcessEvent(target, enchantedBook, menu);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) {
return null;
}
EnchantmentStorageMeta meta = (EnchantmentStorageMeta) enchantedBook.getItemMeta();
Map<Enchantment, Integer> enchantments = new HashMap<>();

View File

@ -0,0 +1,61 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.teleporter;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting;
import io.github.thebusybiscuit.slimefun4.api.items.settings.IntRangeSetting;
import io.github.thebusybiscuit.slimefun4.core.attributes.Rechargeable;
import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
/**
* This item allows a {@link Player} to access and teleport to his waypoints
* from anywhere.
*
* @author martinbrom
*
* @see Teleporter
*/
public class PortableTeleporter extends SimpleSlimefunItem<ItemUseHandler> implements Rechargeable {
private static final int CAPACITY = 50;
private static final int DEFAULT_COST = 10;
private final ItemSetting<Integer> cost = new IntRangeSetting(this, "teleportation-cost", 0, DEFAULT_COST, CAPACITY);
@ParametersAreNonnullByDefault
public PortableTeleporter(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
addItemSetting(cost);
}
@Nonnull
@Override
public ItemUseHandler getItemHandler() {
return e -> {
ItemStack item = e.getItem();
e.cancel();
if (removeItemCharge(item, cost.getValue())) {
Player p = e.getPlayer();
SlimefunPlugin.getGPSNetwork().getTeleportationManager().openTeleporterGUI(
p, p.getUniqueId(), p.getLocation().getBlock().getRelative(BlockFace.DOWN));
}
};
}
@Override
public float getMaxItemCharge(ItemStack item) {
return CAPACITY;
}
}

View File

@ -156,7 +156,14 @@ public class ExplosiveTool extends SimpleSlimefunItem<ToolUseHandler> implements
*/
BlockBreakEvent dummyEvent = new BlockBreakEvent(b, e.getPlayer());
if (!sfItem.callItemHandler(BlockBreakHandler.class, handler -> handler.onPlayerBreak(dummyEvent, item, drops)) && !dummyEvent.isCancelled()) {
/*
* Fixes #3036 and handling in general.
* Call the BlockBreakHandler if the block has one to allow for proper handling.
*/
sfItem.callItemHandler(BlockBreakHandler.class, handler -> handler.onPlayerBreak(dummyEvent, item, drops));
// Make sure the event wasn't cancelled by the BlockBreakHandler.
if (!dummyEvent.isCancelled()) {
drops.addAll(sfItem.getDrops(p));
b.setType(Material.AIR);
BlockStorage.clearBlockInfo(b);

View File

@ -94,7 +94,9 @@ public class GoldPan extends SimpleSlimefunItem<ItemUseHandler> implements Recip
randomizer.clear();
for (GoldPanDrop setting : drops) {
randomizer.add(setting.getOutput(), setting.getValue());
if (setting.getValue() > 0) {
randomizer.add(setting.getOutput(), setting.getValue());
}
}
}
@ -112,11 +114,13 @@ public class GoldPan extends SimpleSlimefunItem<ItemUseHandler> implements Recip
return item != null ? item : new ItemStack(Material.AIR);
}
@Nonnull
@Override
public String getLabelLocalPath() {
return "guide.tooltips.recipes.gold-pan";
}
@Nonnull
@Override
public ItemUseHandler getItemHandler() {
return e -> {
@ -158,6 +162,7 @@ public class GoldPan extends SimpleSlimefunItem<ItemUseHandler> implements Recip
};
}
@Nonnull
@Override
public List<ItemStack> getDisplayRecipes() {
List<ItemStack> recipes = new LinkedList<>();

View File

@ -44,6 +44,7 @@ public class ExplosiveBow extends SlimefunBow {
addItemSetting(range);
}
@Nonnull
@Override
public BowShootHandler onShoot() {
return (e, target) -> {

View File

@ -1,10 +1,12 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.weapons;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Effect;
import org.bukkit.Material;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
@ -16,8 +18,9 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
/**
* The {@link IcyBow} is a special kind of bow which slows down any
* {@link LivingEntity} it hits.
*
*
* @author TheBusyBiscuit
* @author martinbrom
*
*/
public class IcyBow extends SlimefunBow {
@ -27,9 +30,19 @@ public class IcyBow extends SlimefunBow {
super(category, item, recipe);
}
@Nonnull
@Override
public BowShootHandler onShoot() {
return (e, n) -> {
if (n instanceof Player) {
Player p = (Player) n;
// Fixes #3060 - Don't apply effects if the arrow was successfully blocked.
if (p.isBlocking() && e.getFinalDamage() <= 0) {
return;
}
}
n.getWorld().playEffect(n.getLocation(), Effect.STEP_SOUND, Material.ICE);
n.getWorld().playEffect(n.getEyeLocation(), Effect.STEP_SOUND, Material.ICE);
n.addPotionEffect(new PotionEffect(PotionEffectType.SLOW, 20 * 2, 10));

View File

@ -225,7 +225,7 @@ public class AncientAltarListener implements Listener {
b.getWorld().playSound(b.getLocation(), Sound.ENTITY_ILLUSIONER_PREPARE_MIRROR, 1, 1);
AncientAltarTask task = new AncientAltarTask(this, b, altarItem.getSpeed(), result.get(), pedestals, consumed, p);
AncientAltarTask task = new AncientAltarTask(this, b, altarItem.getStepDelay(), result.get(), pedestals, consumed, p);
SlimefunPlugin.runSync(task, 10L);
} else {
altars.remove(b);

View File

@ -2,12 +2,14 @@ package io.github.thebusybiscuit.slimefun4.implementation.listeners;
import javax.annotation.Nonnull;
import org.bukkit.block.Block;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import io.github.thebusybiscuit.slimefun4.api.events.ExplosiveToolBreakBlocksEvent;
import io.github.thebusybiscuit.slimefun4.api.network.Network;
import io.github.thebusybiscuit.slimefun4.core.networks.NetworkManager;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
@ -16,6 +18,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
* This {@link Listener} is responsible for all updates to a {@link Network}.
*
* @author meiamsome
* @author TheBusyBiscuit
*
* @see Network
* @see NetworkManager
@ -23,6 +26,9 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
*/
public class NetworkListener implements Listener {
/**
* Our {@link NetworkManager} instance.
*/
private final NetworkManager manager;
public NetworkListener(@Nonnull SlimefunPlugin plugin, @Nonnull NetworkManager manager) {
@ -39,4 +45,12 @@ public class NetworkListener implements Listener {
public void onBlockPlace(BlockPlaceEvent e) {
manager.updateAllNetworks(e.getBlock().getLocation());
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onExplosiveToolUse(ExplosiveToolBreakBlocksEvent e) {
// Fixes #3013 - Also update networks when using an explosive tool
for (Block b : e.getAdditionalBlocks()) {
manager.updateAllNetworks(b.getLocation());
}
}
}

View File

@ -59,7 +59,7 @@ public class TeleporterListener implements Listener {
if (teleporter instanceof Teleporter && checkForPylons(b.getRelative(BlockFace.DOWN))) {
Block block = b.getRelative(BlockFace.DOWN);
UUID owner = UUID.fromString(BlockStorage.getLocationInfo(block.getLocation(), "owner"));
SlimefunPlugin.getGPSNetwork().getTeleportationManager().openTeleporterGUI(p, owner, block, SlimefunPlugin.getGPSNetwork().getNetworkComplexity(owner));
SlimefunPlugin.getGPSNetwork().getTeleportationManager().openTeleporterGUI(p, owner, block);
}
}
}

View File

@ -287,6 +287,7 @@ public final class ResearchSetup {
register("improved_generators", 275, "Improved Generators", 24, SlimefunItems.COAL_GENERATOR_2, SlimefunItems.LAVA_GENERATOR_2);
register("ingredients_and_cheese", 276, "Slimefun Cuisine", 5, SlimefunItems.SALT, SlimefunItems.WHEAT_FLOUR, SlimefunItems.HEAVY_CREAM, SlimefunItems.CHEESE, SlimefunItems.BUTTER);
register("medium_tier_auto_enchanting", 277, "Fast Automatic Enchanting and Disenchanting", 48, SlimefunItems.AUTO_ENCHANTER_2, SlimefunItems.AUTO_DISENCHANTER_2);
register("portable_teleporter", 278, "Teleportation from Anywhere", 42, SlimefunItems.PORTABLE_TELEPORTER);
}
@ParametersAreNonnullByDefault

View File

@ -182,6 +182,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks.miner
import io.github.thebusybiscuit.slimefun4.implementation.items.seasonal.ChristmasPresent;
import io.github.thebusybiscuit.slimefun4.implementation.items.seasonal.EasterEgg;
import io.github.thebusybiscuit.slimefun4.implementation.items.teleporter.PersonalActivationPlate;
import io.github.thebusybiscuit.slimefun4.implementation.items.teleporter.PortableTeleporter;
import io.github.thebusybiscuit.slimefun4.implementation.items.teleporter.SharedActivationPlate;
import io.github.thebusybiscuit.slimefun4.implementation.items.teleporter.Teleporter;
import io.github.thebusybiscuit.slimefun4.implementation.items.teleporter.TeleporterPylon;
@ -1492,7 +1493,7 @@ public final class SlimefunItemSetup {
new SlimefunItemStack(SlimefunItems.ANCIENT_PEDESTAL, 4))
.register(plugin);
new AncientAltar(categories.magicalGadgets, 8, SlimefunItems.ANCIENT_ALTAR, RecipeType.MAGIC_WORKBENCH,
new AncientAltar(categories.magicalGadgets, SlimefunItems.ANCIENT_ALTAR, RecipeType.MAGIC_WORKBENCH,
new ItemStack[] {null, new ItemStack(Material.ENCHANTING_TABLE), null, SlimefunItems.MAGIC_LUMP_3, SlimefunItems.GOLD_8K, SlimefunItems.MAGIC_LUMP_3, new ItemStack(Material.OBSIDIAN), SlimefunItems.GOLD_8K, new ItemStack(Material.OBSIDIAN)})
.register(plugin);
@ -2221,6 +2222,10 @@ public final class SlimefunItemSetup {
new ItemStack[] {SlimefunItems.GPS_TELEPORTER_PYLON, SlimefunItems.REINFORCED_ALLOY_INGOT, SlimefunItems.GPS_TELEPORTER_PYLON, SlimefunItems.ELECTRO_MAGNET, SlimefunItems.GPS_CONTROL_PANEL, SlimefunItems.ELECTRO_MAGNET, SlimefunItems.GPS_TELEPORTER_PYLON, SlimefunItems.REINFORCED_ALLOY_INGOT, SlimefunItems.GPS_TELEPORTER_PYLON})
.register(plugin);
new PortableTeleporter(categories.gps, SlimefunItems.PORTABLE_TELEPORTER, RecipeType.ENHANCED_CRAFTING_TABLE,
new ItemStack[] {SlimefunItems.ELECTRO_MAGNET, SlimefunItems.GPS_TRANSMITTER_3, SlimefunItems.ELECTRO_MAGNET, SlimefunItems.REINFORCED_PLATE, SlimefunItems.GPS_TELEPORTATION_MATRIX, SlimefunItems.REINFORCED_PLATE, SlimefunItems.BLISTERING_INGOT_3, SlimefunItems.MEDIUM_CAPACITOR, SlimefunItems.BLISTERING_INGOT_3})
.register(plugin);
new SharedActivationPlate(categories.gps, SlimefunItems.GPS_ACTIVATION_DEVICE_SHARED, RecipeType.ENHANCED_CRAFTING_TABLE,
new ItemStack[] {null, new ItemStack(Material.STONE_PRESSURE_PLATE), null, new ItemStack(Material.REDSTONE), SlimefunItems.GPS_TRANSMITTER, new ItemStack(Material.REDSTONE), SlimefunItems.BILLON_INGOT, SlimefunItems.BILLON_INGOT, SlimefunItems.BILLON_INGOT})
.register(plugin);

View File

@ -46,7 +46,7 @@ public class AncientAltarTask implements Runnable {
private final AncientPedestal pedestalItem = (AncientPedestal) SlimefunItems.ANCIENT_PEDESTAL.getItem();
private final Block altar;
private final int speed;
private final int stepDelay;
private final Location dropLocation;
private final ItemStack output;
private final List<Block> pedestals;
@ -60,10 +60,10 @@ public class AncientAltarTask implements Runnable {
private final Player player;
@ParametersAreNonnullByDefault
public AncientAltarTask(AncientAltarListener listener, Block altar, int speed, ItemStack output, List<Block> pedestals, List<ItemStack> items, Player player) {
public AncientAltarTask(AncientAltarListener listener, Block altar, int stepDelay, ItemStack output, List<Block> pedestals, List<ItemStack> items, Player player) {
this.listener = listener;
this.dropLocation = altar.getLocation().add(0.5, 1.3, 0.5);
this.speed = speed;
this.stepDelay = stepDelay;
this.altar = altar;
this.output = output;
this.pedestals = pedestals;
@ -102,7 +102,7 @@ public class AncientAltarTask implements Runnable {
}
this.stage += 1;
SlimefunPlugin.runSync(this, speed);
SlimefunPlugin.runSync(this, stepDelay);
}
private boolean checkLockedItems() {

View File

@ -59,6 +59,8 @@ public class BlockStorage {
private final Map<String, Config> blocksCache = new ConcurrentHashMap<>();
private static int chunkChanges = 0;
private static boolean chunksLoaded = false;
private static boolean universalInventoriesLoaded = false;
private int changes = 0;
private AtomicBoolean isMarkedForRemoval = new AtomicBoolean(false);
@ -214,6 +216,12 @@ public class BlockStorage {
}
private void loadChunks() {
if (chunksLoaded) {
return;
}
chunksLoaded = true;
File chunks = new File(PATH_CHUNKS + "chunks.sfc");
if (chunks.exists()) {
@ -237,6 +245,12 @@ public class BlockStorage {
if (file.getName().startsWith(world.getName()) && file.getName().endsWith(".sfi")) {
try {
Location l = deserializeLocation(file.getName().replace(".sfi", ""));
// We only want to only load this world's menus
if (world != l.getWorld()) {
continue;
}
io.github.thebusybiscuit.cscorelib2.config.Config cfg = new io.github.thebusybiscuit.cscorelib2.config.Config(file);
BlockMenuPreset preset = BlockMenuPreset.getPreset(cfg.getString("preset"));
@ -253,6 +267,12 @@ public class BlockStorage {
}
}
if (universalInventoriesLoaded) {
return;
}
universalInventoriesLoaded = true;
for (File file : new File("data-storage/Slimefun/universal-inventories").listFiles()) {
if (file.getName().endsWith(".sfi")) {
try {

View File

@ -1,84 +0,0 @@
package me.mrCookieSlime.Slimefun.api;
import org.bukkit.entity.Player;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
/**
* Provides a few static convenience methods.
*
* @deprecated This class is slowly getting stripped away in favour of a more object-oriented approach.
*
* @author TheBusyBiscuit
* @author Walshy
* @author Poslovitch
*/
@Deprecated
public final class Slimefun {
private Slimefun() {}
/**
* Checks if this player has the permission to use this item.
*
* @param p
* the player to check, not null
* @param item
* the item to check, null returns <code>true</code>
* @param message
* whether a message should be sent to the player or not
*
* @deprecated This method will soon be removed.
*
* @return <code>true</code> if the item is not null and if the player has the permission to use it,
* <code>false</code> otherwise.
*/
@Deprecated
public static boolean hasPermission(Player p, SlimefunItem item, boolean message) {
if (item == null) {
return true;
} else if (SlimefunPlugin.getPermissionsService().hasPermission(p, item)) {
return true;
} else {
if (message) {
SlimefunPlugin.getLocalization().sendMessage(p, "messages.no-permission", true);
}
return false;
}
}
/**
* Checks if this item is enabled in the world this player is in.
*
* @param p
* the player to get the world he is in, not null
* @param sfItem
* the item to check, not null
* @param message
* whether a message should be sent to the player or not
*
* @deprecated Please use {@link SlimefunItem#isDisabledIn(org.bukkit.World)} instead.
*
* @return <code>true</code> if the item is enabled in the world the player is in,
* <code>false</code> otherwise.
*/
@Deprecated
public static boolean isEnabled(Player p, SlimefunItem sfItem, boolean message) {
if (sfItem.isDisabled()) {
if (message) {
SlimefunPlugin.getLocalization().sendMessage(p, "messages.disabled-item", true);
}
return false;
} else if (!SlimefunPlugin.getWorldSettingsService().isEnabled(p.getWorld(), sfItem)) {
if (message) {
SlimefunPlugin.getLocalization().sendMessage(p, "messages.disabled-in-world", true);
}
return false;
}
return true;
}
}

View File

@ -86,6 +86,17 @@ public class DirtyChestMenu extends ChestMenu {
return InvUtils.fits(toInventory(), new ItemStackWrapper(item), slots);
}
/**
* Adds given {@link ItemStack} to any of the given inventory slots.
* Items will be added to the inventory slots based on their order in the function argument.
* Items will be added either to any empty inventory slots or any partially filled slots, in which case
* as many items as can fit will be added to that specific spot.
*
* @param item {@link ItemStack} to be added to the inventory
* @param slots Numbers of slots to add the {@link ItemStack} to
* @return {@link ItemStack} with any items that did not fit into the inventory
* or null when everything had fit
*/
@Nullable
public ItemStack pushItem(ItemStack item, int... slots) {
if (item == null || item.getType() == Material.AIR) {

View File

@ -26,6 +26,7 @@ guide:
researches:
free-in-creative-mode: true
enable-fireworks: true
disable-learning-animation: false
URID:
info-delay: 3000

View File

@ -75,6 +75,24 @@ guide:
translations:
name: '&aFehlt etwas?'
lore: 'Klicke um eine Übersetzung hinzuzufügen'
options:
learning-animation:
enabled:
text:
- '&bLern-Animation: &aAn'
- ''
- '&7Du kannst nun entscheiden, ob'
- '&7du eine Animation beim Freischalten von'
- '&7Items sehen wirst.'
click: '&eKlicke um die Lern-Animation zu deaktivieren'
disabled:
text:
- '&bLern-Animation: &4Aus'
- ''
- '&7Du kannst nun entscheiden, ob'
- '&7du eine Animation beim Freischalten von'
- '&7Items sehen wirst.'
click: '&eKlicke um die Lern-Animation zu aktivieren'
title:
main: 'Slimefun-Handbuch'
settings: 'Einstellungen & Infos'
@ -139,6 +157,11 @@ messages:
- ''
- '&eLeft Click &7to temporarily disable the recipe'
- '&eRight Click &7to remove this recipe'
disabled:
- '&cDieses Rezept ist momentan deaktiviert'
- ''
- '&eLeft Click &7to re-enable this recipe'
- '&eRight Click &7to remove this recipe'
talisman:
anvil: '&a&oDein Talisman hat dein Werkzeug vor dem Zerfall gerettet'
miner: '&a&oDein Talisman hat soeben die Drops verdoppelt'
@ -197,6 +220,8 @@ messages:
- '&7Always look on the bright side of life!'
- '&7Ist das jetzt ein Keks, Cookie oder ein Biscuit?'
- '&7Jetzt auch zuckerfrei!'
pickaxe-of-the-seeker:
no-ores: '&cEs konnten keine Erze in deiner Nähe gefunden werden!'
machines:
pattern-not-found: '&eEs tut mir leid, aber ich konnte kein passendes Rezept finden.'
unknown-material: '&eEs tut mir leid, aber ich erkenne das Item in meinem Werfer nicht, probier ein anderes Item aus.'

View File

@ -91,6 +91,25 @@ guide:
name: '&aIs something missing?'
lore: 'Click to add your own translation'
options:
learning-animation:
enabled:
text:
- '&bLearning Animation: &aYes'
- ''
- '&7You can now toggle whether you'
- '&7will see information about your pondering in chat'
- '&7upon researching an item.'
click: '&eClick to disable your learning animation'
disabled:
text:
- '&bLearning Animation: &4No'
- ''
- '&7You can now toggle whether you'
- '&7will see information about your pondering in chat'
- '&7upon researching an item.'
click: '&eClick to enable your learning animation'
title:
main: 'Slimefun Guide'
settings: 'Settings & Info'

View File

@ -255,3 +255,4 @@ slimefun:
improved_generators: Improved Generators
ingredients_and_cheese: Slimefun Cuisine
medium_tier_auto_enchanting: Fast Automatic Enchanting and Disenchanting
portable_teleporter: Teleportation from Anywhere

View File

@ -35,7 +35,7 @@ guide:
languages: 'Izvēlies savu vēlamo valodu,'
credits: 'Slimefun4 Ieguldītāji'
credits:
commit: "Ieguldījums"
commit: 'Ieguldījums'
commits: 'Ieguldījumi'
profile-link: 'Spied, lai apmeklētu GitHub profilu'
roles: