1
mirror of https://github.com/StarWishsama/Slimefun4.git synced 2024-09-20 11:45:51 +00:00

Merge branch 'experimental' into IcePick

This commit is contained in:
LinoxGH 2020-07-24 19:39:59 +03:00 committed by GitHub
commit 3b17874ea2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
216 changed files with 4007 additions and 3108 deletions

View File

@ -2,7 +2,8 @@
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of contents**
- [Release Candidate 14 (TBD)](#release-candidate-14-tbd)
- [Release Candidate 15 (TBD)](#release-candidate-15-tbd)
- [Release Candidate 14 (12 Jul 2020)](#release-candidate-14-12-jul-2020)
- [Release Candidate 13 (16 Jun 2020)](#release-candidate-13-16-jun-2020)
- [Release Candidate 12 (27 May 2020)](#release-candidate-12-27-may-2020)
- [Release Candidate 11 (25 Apr 2020)](#release-candidate-11-25-apr-2020)
@ -19,7 +20,39 @@
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
## Release Candidate 14 (TBD)
## Release Candidate 15 (TBD)
#### Additions
* Added "Bone Block -> Bone meal" recipe to the Grind Stone
* Added a [Metrics module](https://github.com/Slimefun/MetricsModule) which allows us to release updates to metrics (bStats) independently from the main plugin
* Added "Compressed Carbon -> Carbon" recipe to the Ore Crusher
* Added "Carbon -> Coal" recipe to the Ore Crusher
* Added Iron Golem Assembler
* Added Reinforced Cloth
* Added Bee protection to Hazmat Suit
* Added Enchantment Rune
* Added Tape Measure
#### Changes
* Refactored and reworked the Generator API
* Small performance improvements to Energy networks
* Big performance improvements to Cargo networks when using ChestTerminal
* Slight changes to /sf timings
* Changed recipe of Hazmat Suits
* Uranium can no longer be placed down
* Huge performance improvements when using Paper
* Optimized Cargo networks for Paper
* Optimized Multiblocks for Paper
* Optimized Enhanced Furnaces for Paper
#### Fixes
* Fixed Slimefun Armor sometimes not applying its effects
* Fixed #2075
* Fixed #2093
* Fixed #2086
* Fixed #1894
## Release Candidate 14 (12 Jul 2020)
#### Additions
* Added support for Minecraft 1.16
@ -42,9 +75,6 @@
* Added runtime deprecation warnings for ItemHandlers and Attributes used by Addons
* Added a proper lag profiler
* Added per-plugin lag info to /sf timings
* Added Reinforced Cloth
* Added Bee protection to Hazmat Suit
* Added Enchantment Rune
* Added Indonesian translations
#### Changes
@ -66,9 +96,9 @@
* performance improvements to Generators and Electric Machines
* Cargo timings will now be attributed to the corresponding node and not the Cargo manager
* Thunderstorms now count as night time for Solar Generators
* Fixed an issue with moving androids getting stuck
* Changed recipe of Hazmat Suits
* Uranium can no longer be placed down
* Coolant Cells can no longer be placed on the ground
* Crafting Nether Ice Coolant Cells now results in 4 items
* Moved Soulbound Backpack to the "Magical Gadgets" Category
#### Fixes
* Fixed #2005
@ -93,10 +123,12 @@
* Fixed #2066
* Fixed Rainbow Glass Panes not properly connecting to blocks
* Fixed Androids turning in the wrong direction
* Fixed a NullPointerException when generating an Error-Report
* Fixed Slimefun Armor sometimes not applying its effects
* Fixed contributors losing their texture after restarts
* Fixed "korean" showing up as "null"
* Fixed an issue with moving androids getting stuck
* Fixed Cargo nodes sometimes preventing chunks from unloading
* Fixed #2081
* Fixed a NullPointerException when Generators throw an Error Report
## Release Candidate 13 (16 Jun 2020)
https://thebusybiscuit.github.io/builds/TheBusyBiscuit/Slimefun4/stable/#13

View File

@ -30,7 +30,7 @@ Here is a full summary of the differences between the two different versions of
| | development (latest) | "stable" |
| ------------------ | -------- | -------- |
| **Minecraft version(s)** | :video_game: **1.13.\* - 1.16.\*** | :video_game: **1.13.\* - 1.15.\*** |
| **Minecraft version(s)** | :video_game: **1.13.\* - 1.16.\*** | :video_game: **1.13.\* - 1.16.\*** |
| **automatic updates** | :heavy_check_mark: | :heavy_check_mark: |
| **frequent updates** | :heavy_check_mark: | :x: |
| **latest content** | :heavy_check_mark: | :x: |
@ -114,6 +114,8 @@ To compile Slimefun yourself, follow these steps:
If you are already using an IDE, make sure to import the project via git and set it as a *Maven project*. Then you should be able build it via Maven using the goals `clean package`.
If you have any further questions, then please join our [Discord Support Server](#discord) and ask your questions in the `#programming-help` channel. Note that we will not accept any bug reports from custom-compiled versions of Slimefun.
### Code Quality
Slimefun uses [Sonarcloud.io](https://sonarcloud.io/dashboard?id=TheBusyBiscuit_Slimefun4) to monitor Code Quality.
@ -157,6 +159,10 @@ All of the collected data is publicly accessible: https://bstats.org/plugin/bukk
You can also disable this behaviour under `/plugins/bStats/config.yml`.<br>
For more info see [bStats' Privacy Policy](https://bstats.org/privacy-policy)
Our [bStats Module](https://github.com/Slimefun/MetricsModule) is downloaded automatically when installing this Plugin, this module will automatically update on server starts independently from the main plugin. This way we can automatically roll out updates to the bStats module, in cases of severe performance issues for example where live data and insight into what is impacting performance can be crucial.
These updates can of course be disabled under `/plugins/Slimefun/config.yml`. To disable metrics collection as a whole, see the paragraph above.
</details>
<details>

38
pom.xml
View File

@ -60,7 +60,7 @@
<url>https://repo.destroystokyo.com/repository/maven-public/</url>
</repository>
<repository>
<id>worldedit-worldguard-repo</id>
<id>worldedit-repo</id>
<url>https://maven.sk89q.com/repo/</url>
</repository>
<repository>
@ -169,6 +169,10 @@
<pattern>io.github.thebusybiscuit.cscorelib2</pattern>
<shadedPattern>me.mrCookieSlime.Slimefun.cscorelib2</shadedPattern>
</relocation>
<relocation>
<pattern>io.papermc.lib</pattern>
<shadedPattern>io.github.thebusybiscuit.slimefun4.libraries.paperlib</shadedPattern>
</relocation>
</relocations>
<!-- Exclude unneeded metadata files from shaded dependencies -->
@ -231,9 +235,17 @@
<packages>io.github.thebusybiscuit.slimefun4.utils*</packages>
</group>
<group>
<title>Slimefun4 - Item Implementations</title>
<title>Slimefun4 - Items</title>
<packages>io.github.thebusybiscuit.slimefun4.implementation.items*</packages>
</group>
<group>
<title>Slimefun4 - Multiblocks</title>
<packages>io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks*</packages>
</group>
<group>
<title>Slimefun4 - Electrical Machines</title>
<packages>io.github.thebusybiscuit.slimefun4.implementation.items.electric*</packages>
</group>
<group>
<title>Slimefun4 - Old packages</title>
<packages>me.mrCookieSlime.Slimefun*</packages>
@ -298,7 +310,7 @@
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.3.3</version>
<version>3.4.4</version>
<scope>test</scope>
</dependency>
@ -306,7 +318,7 @@
<dependency>
<groupId>com.github.TheBusyBiscuit</groupId>
<artifactId>CS-CoreLib2</artifactId>
<version>0.23.2</version>
<version>0.24</version>
<scope>compile</scope>
</dependency>
<dependency>
@ -315,6 +327,23 @@
<version>1.7</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.konghq</groupId>
<artifactId>unirest-java</artifactId>
<version>3.8.06</version>
<exclusions>
<exclusion>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.papermc</groupId>
<artifactId>paperlib</artifactId>
<version>1.0.4</version>
<scope>compile</scope>
</dependency>
<!-- Third party plugin integrations -->
<dependency>
@ -331,6 +360,7 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>me.clip</groupId>
<artifactId>placeholderapi</artifactId>

View File

@ -1,7 +1,6 @@
package io.github.thebusybiscuit.slimefun4.api;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
@ -18,6 +17,7 @@ import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.plugin.Plugin;
import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetProvider;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker;
@ -92,7 +92,7 @@ public class ErrorReport {
addon.getLogger().log(Level.WARNING, "");
}
catch (IOException x) {
catch (Exception x) {
addon.getLogger().log(Level.SEVERE, x, () -> "An Error occurred while saving an Error-Report for Slimefun " + SlimefunPlugin.getVersion());
}
});
@ -116,6 +116,12 @@ public class ErrorReport {
stream.println();
}
if (item instanceof EnergyNetProvider) {
stream.println("Ticker-Info:");
stream.println(" Type: Indirect (Energy Network)");
stream.println();
}
stream.println("Slimefun Data:");
stream.println(" ID: " + item.getID());
stream.println(" Inventory: " + BlockStorage.getStorage(l.getWorld()).hasInventory(l));

View File

@ -19,8 +19,8 @@ public class ResearchUnlockEvent extends Event implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private Player player;
private Research research;
private final Player player;
private final Research research;
private boolean cancelled;
public HandlerList getHandlers() {

View File

@ -0,0 +1,36 @@
package io.github.thebusybiscuit.slimefun4.api.exceptions;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.core.attributes.DamageableItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
/**
* A {@link WrongItemStackException} is thrown when someone tries to alter an {@link ItemStack}
* but actually wanted to alter a different one.
*
* If for example a {@link DamageableItem} accidentally damages the original {@link SlimefunItem}
* instead of the held {@link ItemStack}, this will be thrown.
*
* @author TheBusyBiscuit
*
* @see SlimefunItemStack
* @see SlimefunItem
*
*/
public class WrongItemStackException extends RuntimeException {
private static final long serialVersionUID = 9144658137363309071L;
/**
* This constructs a new {@link WrongItemStackException} with the given error context.
*
* @param message
* An error message to display
*/
public WrongItemStackException(String message) {
super("You probably wanted to alter a different ItemStack: " + message);
}
}

View File

@ -54,7 +54,7 @@ public class GPSNetwork {
private final Map<UUID, Set<Location>> transmitters = new HashMap<>();
private final TeleportationManager teleportation = new TeleportationManager();
private final ResourceManager resourceManager = new ResourceManager(SlimefunPlugin.instance);
private final ResourceManager resourceManager = new ResourceManager(SlimefunPlugin.instance());
/**
* This method updates the status of a {@link GPSTransmitter}.
@ -256,7 +256,7 @@ public class GPSNetwork {
SlimefunPlugin.getLocalization().sendMessage(p, "gps.waypoint.new", true);
p.playSound(p.getLocation(), Sound.BLOCK_NOTE_BLOCK_PLING, 0.5F, 1F);
ChatInput.waitForPlayer(SlimefunPlugin.instance, p, message -> addWaypoint(p, message, l));
ChatInput.waitForPlayer(SlimefunPlugin.instance(), p, message -> addWaypoint(p, message, l));
});
}

View File

@ -21,6 +21,7 @@ import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
import io.github.thebusybiscuit.slimefun4.utils.HeadTexture;
import io.papermc.lib.PaperLib;
import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu;
import me.mrCookieSlime.Slimefun.api.Slimefun;
@ -58,10 +59,21 @@ public final class TeleportationManager {
}
int slot = teleporterInventory[index];
Location l = waypoint.getLocation();
menu.addItem(slot,
new CustomItem(waypoint.getIcon(), waypoint.getName().replace("player:death ", ""), "", "&8\u21E8 &7" + SlimefunPlugin.getLocalization().getResourceString(p, "tooltips.world") + ": &f" + l.getWorld().getName(), "&8\u21E8 &7X: &f" + l.getX(), "&8\u21E8 &7Y: &f" + l.getY(), "&8\u21E8 &7Z: &f" + l.getZ(), "&8\u21E8 &7" + SlimefunPlugin.getLocalization().getMessage(p, "machines.TELEPORTER.gui.time") + ": &f" + DoubleHandler.fixDouble(0.5 * getTeleportationTime(complexity, source, l)) + "s", "", "&8\u21E8 &c" + SlimefunPlugin.getLocalization().getMessage(p, "machines.TELEPORTER.gui.tooltip")));
double time = DoubleHandler.fixDouble(0.5 * getTeleportationTime(complexity, source, l));
String[] lore = {
"",
"&8\u21E8 &7" + SlimefunPlugin.getLocalization().getResourceString(p, "tooltips.world") + ": &f" + l.getWorld().getName(),
"&8\u21E8 &7X: &f" + l.getX(),
"&8\u21E8 &7Y: &f" + l.getY(),
"&8\u21E8 &7Z: &f" + l.getZ(),
"&8\u21E8 &7" + SlimefunPlugin.getLocalization().getMessage(p, "machines.TELEPORTER.gui.time") + ": &f" + time + "s",
"",
"&8\u21E8 &c" + SlimefunPlugin.getLocalization().getMessage(p, "machines.TELEPORTER.gui.tooltip")
};
menu.addItem(slot, new CustomItem(waypoint.getIcon(), waypoint.getName().replace("player:death ", ""), lore));
menu.addMenuClickHandler(slot, (pl, s, item, action) -> {
pl.closeInventory();
teleport(pl.getUniqueId(), complexity, source, l, false);
@ -117,16 +129,24 @@ public final class TeleportationManager {
if (isValid(p, source)) {
if (progress > 99) {
p.sendTitle(ChatColors.color(SlimefunPlugin.getLocalization().getMessage(p, "machines.TELEPORTER.teleported")), ChatColors.color("&b100%"), 20, 60, 20);
p.teleport(destination);
if (resistance) {
p.addPotionEffect(new PotionEffect(PotionEffectType.DAMAGE_RESISTANCE, 600, 20));
SlimefunPlugin.getLocalization().sendMessage(p, "machines.TELEPORTER.invulnerability");
}
PaperLib.teleportAsync(p, destination).thenAccept(teleported -> {
if (teleported.booleanValue()) {
// This needs to run on the main Thread so we force it, as the
// async teleportation might happen on a seperate Thread.
Slimefun.runSync(() -> {
if (resistance) {
p.addPotionEffect(new PotionEffect(PotionEffectType.DAMAGE_RESISTANCE, 600, 20));
SlimefunPlugin.getLocalization().sendMessage(p, "machines.TELEPORTER.invulnerability");
}
destination.getWorld().spawnParticle(Particle.PORTAL, new Location(destination.getWorld(), destination.getX(), destination.getY() + 1, destination.getZ()), progress * 2, 0.2F, 0.8F, 0.2F);
destination.getWorld().playSound(destination, Sound.BLOCK_BEACON_ACTIVATE, 1F, 1F);
teleporterUsers.remove(uuid);
Location loc = new Location(destination.getWorld(), destination.getX(), destination.getY() + 1, destination.getZ());
destination.getWorld().spawnParticle(Particle.PORTAL, loc, progress * 2, 0.2F, 0.8F, 0.2F);
destination.getWorld().playSound(destination, Sound.BLOCK_BEACON_ACTIVATE, 1F, 1F);
teleporterUsers.remove(uuid);
});
}
});
}
else {
p.sendTitle(ChatColors.color(SlimefunPlugin.getLocalization().getMessage(p, "machines.TELEPORTER.teleporting")), ChatColors.color("&b" + progress + "%"), 0, 60, 0);

View File

@ -28,8 +28,8 @@ public class Waypoint {
private final PlayerProfile profile;
private final String id;
private String name;
private Location location;
private final String name;
private final Location location;
public Waypoint(PlayerProfile profile, String id, Location l, String name) {
Validate.notNull(profile, "Profile must never be null!");

View File

@ -29,7 +29,7 @@ public abstract class Network {
private final NetworkManager manager;
protected Location regulator;
private Queue<Location> nodeQueue = new ArrayDeque<>();
private final Queue<Location> nodeQueue = new ArrayDeque<>();
protected final Set<Location> connectedLocations = new HashSet<>();
protected final Set<Location> regulatorNodes = new HashSet<>();
@ -225,6 +225,10 @@ public abstract class Network {
});
}
public Location getRegulator() {
return regulator;
}
public void tick() {
discoverStep();
}

View File

@ -372,7 +372,7 @@ public final class PlayerProfile {
return true;
}
Bukkit.getScheduler().runTaskAsynchronously(SlimefunPlugin.instance, () -> {
Bukkit.getScheduler().runTaskAsynchronously(SlimefunPlugin.instance(), () -> {
PlayerProfile pp = new PlayerProfile(p);
SlimefunPlugin.getRegistry().getPlayerProfiles().put(uuid, pp);
callback.accept(pp);
@ -393,7 +393,7 @@ public final class PlayerProfile {
public static boolean request(OfflinePlayer p) {
if (!SlimefunPlugin.getRegistry().getPlayerProfiles().containsKey(p.getUniqueId())) {
// Should probably prevent multiple requests for the same profile in the future
Bukkit.getScheduler().runTaskAsynchronously(SlimefunPlugin.instance, () -> {
Bukkit.getScheduler().runTaskAsynchronously(SlimefunPlugin.instance(), () -> {
PlayerProfile pp = new PlayerProfile(p);
SlimefunPlugin.getRegistry().getPlayerProfiles().put(p.getUniqueId(), pp);
});
@ -446,9 +446,7 @@ public final class PlayerProfile {
fromUUID(UUID.fromString(uuid), profile -> {
Optional<PlayerBackpack> backpack = profile.getBackpack(number);
if (backpack.isPresent()) {
callback.accept(backpack.get());
}
backpack.ifPresent(callback);
});
}
}

View File

@ -21,7 +21,6 @@ import io.github.thebusybiscuit.cscorelib2.config.Config;
import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion;
import io.github.thebusybiscuit.slimefun4.api.geo.GEOResource;
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.core.attributes.WitherProof;
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideImplementation;
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideLayout;
import io.github.thebusybiscuit.slimefun4.core.multiblocks.MultiBlock;
@ -30,6 +29,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.guide.BookSlimefunGuide;
import io.github.thebusybiscuit.slimefun4.implementation.guide.CheatSheetSlimefunGuide;
import io.github.thebusybiscuit.slimefun4.implementation.guide.ChestSlimefunGuide;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.AutomatedCraftingChamber;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunBlockHandler;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
@ -71,21 +71,15 @@ public class SlimefunRegistry {
private final KeyMap<GEOResource> geoResources = new KeyMap<>();
private final Set<String> energyGenerators = new HashSet<>();
private final Set<String> energyCapacitors = new HashSet<>();
private final Set<String> energyConsumers = new HashSet<>();
private final Set<String> chargeableBlocks = new HashSet<>();
private final Map<String, WitherProof> witherProofBlocks = new HashMap<>();
private final Map<UUID, PlayerProfile> profiles = new ConcurrentHashMap<>();
private final Map<String, BlockStorage> worlds = new ConcurrentHashMap<>();
private final Map<String, BlockInfoConfig> chunks = new HashMap<>();
private final Map<SlimefunGuideLayout, SlimefunGuideImplementation> layouts = new EnumMap<>(SlimefunGuideLayout.class);
private final Map<EntityType, Set<ItemStack>> drops = new EnumMap<>(EntityType.class);
private final Map<EntityType, Set<ItemStack>> mobDrops = new EnumMap<>(EntityType.class);
private final Map<String, Integer> capacities = new HashMap<>();
private final Map<String, BlockMenuPreset> blockMenuPresets = new HashMap<>();
private final Map<String, UniversalBlockMenu> universalInventories = new HashMap<>();
private final Map<Class<? extends ItemHandler>, Set<ItemHandler>> itemHandlers = new HashMap<>();
private final Map<Class<? extends ItemHandler>, Set<ItemHandler>> globalItemHandlers = new HashMap<>();
private final Map<String, SlimefunBlockHandler> blockHandlers = new HashMap<>();
private final Map<String, Set<Location>> activeTickers = new HashMap<>();
@ -200,11 +194,7 @@ public class SlimefunRegistry {
}
public Map<EntityType, Set<ItemStack>> getMobDrops() {
return drops;
}
public Set<ItemStack> getMobDrops(EntityType entity) {
return drops.get(entity);
return mobDrops;
}
public Set<SlimefunItem> getRadioactiveItems() {
@ -240,7 +230,7 @@ public class SlimefunRegistry {
}
public Map<Class<? extends ItemHandler>, Set<ItemHandler>> getPublicItemHandlers() {
return itemHandlers;
return globalItemHandlers;
}
public Map<String, SlimefunBlockHandler> getBlockHandlers() {
@ -263,29 +253,16 @@ public class SlimefunRegistry {
return geoResources;
}
/**
* This method returns a list of recipes for the {@link AutomatedCraftingChamber}
*
* @deprecated This just a really bad way to do this. Someone needs to rewrite this.
*
* @return A list of recipes for the {@link AutomatedCraftingChamber}
*/
@Deprecated
public Map<String, ItemStack> getAutomatedCraftingChamberRecipes() {
return automatedCraftingChamberRecipes;
}
public Set<String> getEnergyGenerators() {
return energyGenerators;
}
public Set<String> getEnergyCapacitors() {
return energyCapacitors;
}
public Set<String> getEnergyConsumers() {
return energyConsumers;
}
public Set<String> getChargeableBlocks() {
return chargeableBlocks;
}
public Map<String, WitherProof> getWitherProofBlocks() {
return witherProofBlocks;
}
}

View File

@ -2,7 +2,6 @@ package io.github.thebusybiscuit.slimefun4.core.attributes;
import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNet;
import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNetComponentType;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
/**
@ -37,33 +36,4 @@ public interface EnergyNetComponent extends ItemAttribute {
*/
int getCapacity();
/**
* This method is used for internal purposes to register the component.
* You do not have to call this method yourself.
*
* @param id
* The id of the {@link SlimefunItem} this refers to
*/
default void registerComponent(String id) {
switch (getEnergyComponentType()) {
case CONSUMER:
SlimefunPlugin.getRegistry().getEnergyConsumers().add(id);
break;
case CAPACITOR:
SlimefunPlugin.getRegistry().getEnergyCapacitors().add(id);
break;
case GENERATOR:
SlimefunPlugin.getRegistry().getEnergyGenerators().add(id);
break;
default:
break;
}
int capacity = getCapacity();
if (capacity > 0) {
SlimefunPlugin.getRegistry().getEnergyCapacities().put(id, capacity);
}
}
}

View File

@ -0,0 +1,62 @@
package io.github.thebusybiscuit.slimefun4.core.attributes;
import org.bukkit.Location;
import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNet;
import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNetComponentType;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.AbstractEnergyProvider;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.reactors.Reactor;
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AGenerator;
/**
* An {@link EnergyNetProvider} is an extension of {@link EnergyNetComponent} which provides
* energy to an {@link EnergyNet}.
* It must be implemented on any Generator or {@link Reactor}.
*
* @author TheBusyBiscuit
*
* @see EnergyNet
* @see EnergyNetComponent
* @see AbstractEnergyProvider
* @see AGenerator
* @see Reactor
*
*/
public interface EnergyNetProvider extends EnergyNetComponent {
@Override
default EnergyNetComponentType getEnergyComponentType() {
return EnergyNetComponentType.GENERATOR;
}
/**
* This method returns how much energy this {@link EnergyNetProvider} provides to the {@link EnergyNet}.
* We call this method on every tick, so make sure to keep it light and fast.
* Stored energy does not have to be handled in here.
*
* @param l
* The {@link Location} of this {@link EnergyNetProvider}
* @param data
* The stored block data
*
* @return The generated output energy of this {@link EnergyNetProvider}.
*/
int getGeneratedOutput(Location l, Config data);
/**
* This method returns whether the given {@link Location} is going to explode on the
* next tick.
*
* @param l
* The {@link Location} of this {@link EnergyNetProvider}
* @param data
* The stored block data
*
* @return Whether or not this {@link Location} will explode.
*/
default boolean willExplode(Location l, Config data) {
return false;
}
}

View File

@ -0,0 +1,35 @@
package io.github.thebusybiscuit.slimefun4.core.attributes;
import org.bukkit.entity.EntityType;
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 me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
/**
* This interface, when attached to a {@link SlimefunItem}, provides an easy method for adding
* a % chance to drop for an {@link SlimefunItem} on {@link EntityDeathEvent}, this chance is 0-100
* and used in conjunction with the MOB_DROP {@link RecipeType}.
*
* @author dNiym
*
* @see BasicCircuitBoard
* @see MobDropListener
*
*/
@FunctionalInterface
public interface RandomMobDrop extends ItemAttribute {
/**
* Implement this method to make the object have a variable chance of being
* added to the dropList when {@link EntityType} (specified in the recipe)
* is killed by the {@link Player}
*
* @return The integer chance (0-100%) {@link SlimefunItem} has to drop.
*/
int getMobDropChance();
}

View File

@ -14,6 +14,7 @@ import io.github.thebusybiscuit.cscorelib2.chat.ChatColors;
import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.utils.PatternUtils;
import net.md_5.bungee.api.ChatColor;
/**
* This is just a simple helper class to provide static methods to the {@link Rechargeable}
@ -26,9 +27,9 @@ import io.github.thebusybiscuit.slimefun4.utils.PatternUtils;
*/
final class RechargeableHelper {
private static final NamespacedKey CHARGE_KEY = new NamespacedKey(SlimefunPlugin.instance, "item_charge");
private static final NamespacedKey CHARGE_KEY = new NamespacedKey(SlimefunPlugin.instance(), "item_charge");
private static final String LORE_PREFIX = ChatColors.color("&8\u21E8 &e\u26A1 &7");
private static final Pattern REGEX = Pattern.compile(ChatColors.color("(&c&o)?" + LORE_PREFIX) + "[0-9\\.]+ \\/ [0-9\\.]+ J");
private static final Pattern REGEX = Pattern.compile(ChatColors.color("(&c&o)?" + LORE_PREFIX) + "[0-9.]+ / [0-9.]+ J");
private RechargeableHelper() {}
@ -69,7 +70,8 @@ final class RechargeableHelper {
if (meta.hasLore()) {
for (String line : meta.getLore()) {
if (REGEX.matcher(line).matches()) {
return Float.parseFloat(PatternUtils.SLASH_SEPARATOR.split(line)[0].replace(LORE_PREFIX, ""));
String data = ChatColor.stripColor(PatternUtils.SLASH_SEPARATOR.split(line)[0].replace(LORE_PREFIX, ""));
return Float.parseFloat(data);
}
}
}

View File

@ -6,6 +6,7 @@ import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.apache.commons.lang.Validate;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
@ -14,7 +15,7 @@ import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import io.github.thebusybiscuit.cscorelib2.chat.ChatColors;
import io.github.thebusybiscuit.slimefun4.core.commands.subcommands.Commands;
import io.github.thebusybiscuit.slimefun4.core.commands.subcommands.SlimefunSubCommands;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
/**
@ -25,6 +26,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
*/
public class SlimefunCommand implements CommandExecutor, Listener {
private boolean registered = false;
private final SlimefunPlugin plugin;
private final List<SubCommand> commands = new LinkedList<>();
private final Map<SubCommand, Integer> commandUsage = new HashMap<>();
@ -40,11 +42,14 @@ public class SlimefunCommand implements CommandExecutor, Listener {
}
public void register() {
Validate.isTrue(!registered, "Slimefun's subcommands have already been registered!");
registered = true;
plugin.getServer().getPluginManager().registerEvents(this, plugin);
plugin.getCommand("slimefun").setExecutor(this);
plugin.getCommand("slimefun").setTabCompleter(new SlimefunTabCompleter(this));
Commands.addCommands(this, commands);
commands.addAll(SlimefunSubCommands.getAllCommands(this));
}
public SlimefunPlugin getPlugin() {

View File

@ -1,18 +1,28 @@
package io.github.thebusybiscuit.slimefun4.core.commands.subcommands;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import io.github.thebusybiscuit.slimefun4.core.commands.SlimefunCommand;
import io.github.thebusybiscuit.slimefun4.core.commands.SubCommand;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
public final class Commands {
/**
* This class holds the implementations of every {@link SubCommand}.
* The implementations themselves are package-private, this class only provides
* a static setup method
*
* @author TheBusyBiscuit
*
*/
public final class SlimefunSubCommands {
private Commands() {
}
private SlimefunSubCommands() {}
public static void addCommands(SlimefunCommand cmd, Collection<SubCommand> commands) {
public static Collection<SubCommand> getAllCommands(SlimefunCommand cmd) {
SlimefunPlugin plugin = cmd.getPlugin();
List<SubCommand> commands = new LinkedList<>();
commands.add(new HelpCommand(plugin, cmd));
commands.add(new VersionsCommand(plugin, cmd));
@ -27,5 +37,7 @@ public final class Commands {
commands.add(new SearchCommand(plugin, cmd));
commands.add(new DebugFishCommand(plugin, cmd));
commands.add(new BackpackCommand(plugin, cmd));
return commands;
}
}

View File

@ -2,17 +2,17 @@ package io.github.thebusybiscuit.slimefun4.core.commands.subcommands;
import java.util.Collection;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.plugin.Plugin;
import io.github.thebusybiscuit.cscorelib2.chat.ChatColors;
import io.github.thebusybiscuit.cscorelib2.reflection.ReflectionUtils;
import io.github.thebusybiscuit.slimefun4.core.commands.SlimefunCommand;
import io.github.thebusybiscuit.slimefun4.core.commands.SubCommand;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.plugin.Plugin;
import io.papermc.lib.PaperLib;
class VersionsCommand extends SubCommand {
@ -33,13 +33,19 @@ class VersionsCommand extends SubCommand {
@Override
public void onExecute(CommandSender sender, String[] args) {
if (sender.hasPermission("slimefun.command.versions") || sender instanceof ConsoleCommandSender) {
sender.sendMessage(ChatColors.color("&a" + Bukkit.getName() + " &2" + ReflectionUtils.getVersion()));
// After all these years... Spigot still displays as "CraftBukkit"
// so we will just fix this inconsistency for them :)
String serverSoftware = PaperLib.isSpigot() && !PaperLib.isPaper() ? "Spigot" : Bukkit.getName();
sender.sendMessage(ChatColors.color("&a" + serverSoftware + " &2" + ReflectionUtils.getVersion()));
sender.sendMessage("");
sender.sendMessage(ChatColors.color("&aCS-CoreLib &2v" + SlimefunPlugin.getCSCoreLibVersion()));
sender.sendMessage(ChatColors.color("&aSlimefun &2v" + SlimefunPlugin.getVersion()));
if (SlimefunPlugin.getMetricsService().getVersion() != null)
sender.sendMessage(ChatColors.color("&aMetrics: &2#" + SlimefunPlugin.getMetricsService().getVersion() + ')'));
if (SlimefunPlugin.getRegistry().isBackwardsCompatible()) {
sender.sendMessage(ChatColor.YELLOW + "Backwards compatiblity enabled!");
sender.sendMessage(ChatColor.YELLOW + "Backwards compatibility enabled!");
}
sender.sendMessage("");

View File

@ -60,13 +60,19 @@ final class ContributorsMenu {
menu.addItem(46, ChestMenuUtils.getPreviousButton(p, page + 1, pages));
menu.addMenuClickHandler(46, (pl, slot, item, action) -> {
if (page > 0) open(pl, page - 1);
if (page > 0) {
open(pl, page - 1);
}
return false;
});
menu.addItem(52, ChestMenuUtils.getNextButton(p, page + 1, pages));
menu.addMenuClickHandler(52, (pl, slot, item, action) -> {
if (page + 1 < pages) open(pl, page + 1);
if (page + 1 < pages) {
open(pl, page + 1);
}
return false;
});

View File

@ -16,12 +16,12 @@ class FireworksOption implements SlimefunGuideOption<Boolean> {
@Override
public SlimefunAddon getAddon() {
return SlimefunPlugin.instance;
return SlimefunPlugin.instance();
}
@Override
public NamespacedKey getKey() {
return new NamespacedKey(SlimefunPlugin.instance, "research_fireworks");
return new NamespacedKey(SlimefunPlugin.instance(), "research_fireworks");
}
@Override

View File

@ -22,12 +22,12 @@ class GuideLayoutOption implements SlimefunGuideOption<SlimefunGuideLayout> {
@Override
public SlimefunAddon getAddon() {
return SlimefunPlugin.instance;
return SlimefunPlugin.instance();
}
@Override
public NamespacedKey getKey() {
return new NamespacedKey(SlimefunPlugin.instance, "guide_layout");
return new NamespacedKey(SlimefunPlugin.instance(), "guide_layout");
}
@Override

View File

@ -23,7 +23,7 @@ class PlayerLanguageOption implements SlimefunGuideOption<String> {
@Override
public SlimefunAddon getAddon() {
return SlimefunPlugin.instance;
return SlimefunPlugin.instance();
}
@Override
@ -93,7 +93,7 @@ class PlayerLanguageOption implements SlimefunGuideOption<String> {
String defaultLanguageString = SlimefunPlugin.getLocalization().getMessage(p, "languages.default");
menu.addItem(9, new CustomItem(defaultLanguage.getItem(), ChatColor.GRAY + defaultLanguageString + ChatColor.DARK_GRAY + " (" + defaultLanguage.getName(p) + ")", "", "&7\u21E8 &e" + SlimefunPlugin.getLocalization().getMessage(p, "guide.languages.select-default")), (pl, i, item, action) -> {
SlimefunPlugin.instance.getServer().getPluginManager().callEvent(new PlayerLanguageChangeEvent(pl, SlimefunPlugin.getLocalization().getLanguage(pl), defaultLanguage));
SlimefunPlugin.instance().getServer().getPluginManager().callEvent(new PlayerLanguageChangeEvent(pl, SlimefunPlugin.getLocalization().getLanguage(pl), defaultLanguage));
setSelectedOption(pl, guide, null);
SlimefunPlugin.getLocalization().sendMessage(pl, "guide.languages.updated", msg -> msg.replace("%lang%", defaultLanguageString));
@ -106,7 +106,7 @@ class PlayerLanguageOption implements SlimefunGuideOption<String> {
for (Language language : SlimefunPlugin.getLocalization().getLanguages()) {
menu.addItem(slot, new CustomItem(language.getItem(), ChatColor.GREEN + language.getName(p), "&b" + SlimefunPlugin.getLocalization().getProgress(language) + '%', "", "&7\u21E8 &e" + SlimefunPlugin.getLocalization().getMessage(p, "guide.languages.select")), (pl, i, item, action) -> {
SlimefunPlugin.instance.getServer().getPluginManager().callEvent(new PlayerLanguageChangeEvent(pl, SlimefunPlugin.getLocalization().getLanguage(pl), language));
SlimefunPlugin.instance().getServer().getPluginManager().callEvent(new PlayerLanguageChangeEvent(pl, SlimefunPlugin.getLocalization().getLanguage(pl), language));
setSelectedOption(pl, guide, language.getId());
String name = language.getName(pl);

View File

@ -6,7 +6,7 @@ import org.bukkit.event.player.PlayerInteractAtEntityEvent;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SimpleSlimefunItem;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.handlers.ItemHandler;

View File

@ -5,7 +5,7 @@ import org.bukkit.entity.Player;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.inventory.ItemStack;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SimpleSlimefunItem;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.handlers.ItemHandler;

View File

@ -4,9 +4,9 @@ import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerItemConsumeEvent;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import io.github.thebusybiscuit.slimefun4.implementation.items.food.DietCookie;
import io.github.thebusybiscuit.slimefun4.implementation.items.food.FortuneCookie;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.handlers.ItemHandler;

View File

@ -3,7 +3,7 @@ package io.github.thebusybiscuit.slimefun4.core.handlers;
import org.bukkit.entity.Player;
import io.github.thebusybiscuit.slimefun4.api.events.PlayerRightClickEvent;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SimpleSlimefunItem;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.handlers.ItemHandler;

View File

@ -9,6 +9,7 @@ import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.block.Chest;
import org.bukkit.block.data.type.Dispenser;
import org.bukkit.entity.Player;
@ -22,6 +23,7 @@ import io.github.thebusybiscuit.slimefun4.core.attributes.NotPlaceable;
import io.github.thebusybiscuit.slimefun4.core.attributes.RecipeDisplayItem;
import io.github.thebusybiscuit.slimefun4.core.handlers.MultiBlockInteractionHandler;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.papermc.lib.PaperLib;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
@ -52,6 +54,16 @@ public abstract class MultiBlockMachine extends SlimefunItem implements NotPlace
this.displayRecipes = new ArrayList<>();
this.displayRecipes.addAll(Arrays.asList(machineRecipes));
this.multiblock = new MultiBlock(this, convertItemStacksToMaterial(recipe), trigger);
registerDefaultRecipes(displayRecipes);
}
public MultiBlockMachine(Category category, SlimefunItemStack item, ItemStack[] recipe, BlockFace trigger) {
this(category, item, recipe, new ItemStack[0], trigger);
}
protected void registerDefaultRecipes(List<ItemStack> recipes) {
// Override this method to register some default recipes
}
public List<ItemStack[]> getRecipes() {
@ -153,10 +165,14 @@ public abstract class MultiBlockMachine extends SlimefunItem implements NotPlace
if (id != null && id.equals("OUTPUT_CHEST")) {
// Found the output chest! Now, let's check if we can fit the product in it.
Inventory inv = ((Chest) potentialOutput.getState()).getInventory();
BlockState state = PaperLib.getBlockState(potentialOutput, false).getState();
if (InvUtils.fits(inv, output)) {
return inv;
if (state instanceof Chest) {
Inventory inv = ((Chest) state).getInventory();
if (InvUtils.fits(inv, output)) {
return inv;
}
}
}
}

View File

@ -1,6 +1,5 @@
package io.github.thebusybiscuit.slimefun4.core.networks.cargo;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
@ -8,23 +7,18 @@ import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.api.network.Network;
import io.github.thebusybiscuit.slimefun4.api.network.NetworkComponent;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.utils.holograms.SimpleHologram;
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.inventory.DirtyChestMenu;
/**
* The {@link CargoNet} is a type of {@link Network} which deals with {@link ItemStack} transportation.
@ -49,7 +43,7 @@ public class CargoNet extends ChestTerminalNetwork {
private final Set<Location> inputNodes = new HashSet<>();
private final Set<Location> outputNodes = new HashSet<>();
private final Map<Location, Integer> roundRobin = new HashMap<>();
protected final Map<Location, Integer> roundRobin = new HashMap<>();
private int tickDelayThreshold = 0;
public static CargoNet getNetworkFromLocation(Location l) {
@ -182,7 +176,9 @@ public class CargoNet extends ChestTerminalNetwork {
}
SlimefunPlugin.getProfiler().scheduleEntries(1 + inputNodes.size());
Slimefun.runSync(() -> run(inputs, outputs, chestTerminalInputs, chestTerminalOutputs));
CargoNetworkTask runnable = new CargoNetworkTask(this, inputs, outputs, chestTerminalInputs, chestTerminalOutputs);
Slimefun.runSync(runnable);
}
}
@ -240,135 +236,6 @@ public class CargoNet extends ChestTerminalNetwork {
return output;
}
private void run(Map<Location, Integer> inputs, Map<Integer, List<Location>> outputs, Set<Location> chestTerminalInputs, Set<Location> chestTerminalOutputs) {
long timestamp = System.nanoTime();
// Chest Terminal Code
if (SlimefunPlugin.getThirdPartySupportService().isChestTerminalInstalled()) {
handleItemRequests(chestTerminalInputs, chestTerminalOutputs);
}
// All operations happen here: Everything gets iterated from the Input Nodes.
// (Apart from ChestTerminal Buses)
for (Map.Entry<Location, Integer> entry : inputs.entrySet()) {
long nodeTimestamp = System.nanoTime();
Location input = entry.getKey();
Optional<Block> attachedBlock = getAttachedBlock(input.getBlock());
if (attachedBlock.isPresent()) {
routeItems(input, attachedBlock.get(), entry.getValue(), outputs);
}
// This will prevent this timings from showing up for the Cargo Manager
timestamp += SlimefunPlugin.getProfiler().closeEntry(entry.getKey(), SlimefunItems.CARGO_INPUT_NODE.getItem(), nodeTimestamp);
}
// Chest Terminal Code
if (SlimefunPlugin.getThirdPartySupportService().isChestTerminalInstalled()) {
updateTerminals(chestTerminalInputs);
}
// Submit a timings report
SlimefunPlugin.getProfiler().closeEntry(regulator, SlimefunItems.CARGO_MANAGER.getItem(), timestamp);
}
private void routeItems(Location inputNode, Block inputTarget, int frequency, Map<Integer, List<Location>> outputNodes) {
AtomicReference<Object> inventory = new AtomicReference<>();
ItemStackAndInteger slot = CargoUtils.withdraw(inputNode.getBlock(), inputTarget, inventory);
if (slot == null) {
return;
}
ItemStack stack = slot.getItem();
int previousSlot = slot.getInt();
List<Location> outputs = outputNodes.get(frequency);
if (outputs != null) {
stack = distributeItem(stack, inputNode, outputs);
}
if (stack != null) {
Object inputInventory = inventory.get();
if (inputInventory instanceof DirtyChestMenu) {
DirtyChestMenu menu = (DirtyChestMenu) inputInventory;
if (menu.getItemInSlot(previousSlot) == null) {
menu.replaceExistingItem(previousSlot, stack);
}
else {
inputTarget.getWorld().dropItem(inputTarget.getLocation().add(0, 1, 0), stack);
}
}
if (inputInventory instanceof Inventory) {
Inventory inv = (Inventory) inputInventory;
if (inv.getItem(previousSlot) == null) {
inv.setItem(previousSlot, stack);
}
else {
inputTarget.getWorld().dropItem(inputTarget.getLocation().add(0, 1, 0), stack);
}
}
}
}
private ItemStack distributeItem(ItemStack stack, Location inputNode, List<Location> outputNodes) {
ItemStack item = stack;
Deque<Location> destinations = new LinkedList<>(outputNodes);
Config cfg = BlockStorage.getLocationInfo(inputNode);
boolean roundrobin = "true".equals(cfg.getString("round-robin"));
if (roundrobin) {
roundRobinSort(inputNode, destinations);
}
for (Location output : destinations) {
Optional<Block> target = getAttachedBlock(output.getBlock());
if (target.isPresent()) {
item = CargoUtils.insert(output.getBlock(), target.get(), item);
if (item == null) {
break;
}
}
}
return item;
}
/**
* This method sorts a given {@link Deque} of output node locations using a semi-accurate
* round-robin method.
*
* @param inputNode
* The {@link Location} of the input node
* @param outputNodes
* A {@link Deque} of {@link Location Locations} of the output nodes
*/
private void roundRobinSort(Location inputNode, Deque<Location> outputNodes) {
int index = roundRobin.getOrDefault(inputNode, 0);
if (index < outputNodes.size()) {
// Not ideal but actually not bad performance-wise over more elegant alternatives
for (int i = 0; i < index; i++) {
Location temp = outputNodes.removeFirst();
outputNodes.add(temp);
}
index++;
}
else {
index = 1;
}
roundRobin.put(inputNode, index);
}
/**
* This method returns the frequency a given node is set to.
* Should there be an {@link Exception} to this method it will fall back to zero in

View File

@ -0,0 +1,181 @@
package io.github.thebusybiscuit.slimefun4.core.networks.cargo;
import java.util.Deque;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.inventory.DirtyChestMenu;
/**
* The {@link CargoNetworkTask} is the actual {@link Runnable} responsible for moving {@link ItemStack ItemStacks}
* around the {@link CargoNet}.
*
* Inbefore this was just a method in the {@link CargoNet} class.
* However for aesthetic reasons but mainly to prevent the Cargo Task from showing up as
* "lambda:xyz-123" in timing reports... this was moved.
*
* @see CargoNet
* @see CargoUtils
* @see ChestTerminalNetwork
*
*/
class CargoNetworkTask implements Runnable {
private final CargoNet network;
private final Map<Location, Inventory> inventories = new HashMap<>();
private final Map<Location, Integer> inputs;
private final Map<Integer, List<Location>> outputs;
private final Set<Location> chestTerminalInputs;
private final Set<Location> chestTerminalOutputs;
CargoNetworkTask(CargoNet network, Map<Location, Integer> inputs, Map<Integer, List<Location>> outputs, Set<Location> chestTerminalInputs, Set<Location> chestTerminalOutputs) {
this.network = network;
this.inputs = inputs;
this.outputs = outputs;
this.chestTerminalInputs = chestTerminalInputs;
this.chestTerminalOutputs = chestTerminalOutputs;
}
@Override
public void run() {
long timestamp = System.nanoTime();
// Chest Terminal Code
if (SlimefunPlugin.getThirdPartySupportService().isChestTerminalInstalled()) {
network.handleItemRequests(inventories, chestTerminalInputs, chestTerminalOutputs);
}
// All operations happen here: Everything gets iterated from the Input Nodes.
// (Apart from ChestTerminal Buses)
for (Map.Entry<Location, Integer> entry : inputs.entrySet()) {
long nodeTimestamp = System.nanoTime();
Location input = entry.getKey();
Optional<Block> attachedBlock = network.getAttachedBlock(input);
attachedBlock.ifPresent(block -> routeItems(input, block, entry.getValue(), outputs));
// This will prevent this timings from showing up for the Cargo Manager
timestamp += SlimefunPlugin.getProfiler().closeEntry(entry.getKey(), SlimefunItems.CARGO_INPUT_NODE.getItem(), nodeTimestamp);
}
// Chest Terminal Code
if (SlimefunPlugin.getThirdPartySupportService().isChestTerminalInstalled()) {
network.updateTerminals(chestTerminalInputs);
}
// Submit a timings report
SlimefunPlugin.getProfiler().closeEntry(network.getRegulator(), SlimefunItems.CARGO_MANAGER.getItem(), timestamp);
}
private void routeItems(Location inputNode, Block inputTarget, int frequency, Map<Integer, List<Location>> outputNodes) {
ItemStackAndInteger slot = CargoUtils.withdraw(inventories, inputNode.getBlock(), inputTarget);
if (slot == null) {
return;
}
ItemStack stack = slot.getItem();
int previousSlot = slot.getInt();
List<Location> destinations = outputNodes.get(frequency);
if (destinations != null) {
stack = distributeItem(stack, inputNode, destinations);
}
if (stack != null) {
Inventory inv = inventories.get(inputTarget.getLocation());
if (inv != null) {
if (inv.getItem(previousSlot) == null) {
inv.setItem(previousSlot, stack);
}
else {
inputTarget.getWorld().dropItem(inputTarget.getLocation().add(0, 1, 0), stack);
}
}
else {
DirtyChestMenu menu = CargoUtils.getChestMenu(inputTarget);
if (menu != null) {
if (menu.getItemInSlot(previousSlot) == null) {
menu.replaceExistingItem(previousSlot, stack);
}
else {
inputTarget.getWorld().dropItem(inputTarget.getLocation().add(0, 1, 0), stack);
}
}
}
}
}
private ItemStack distributeItem(ItemStack stack, Location inputNode, List<Location> outputNodes) {
ItemStack item = stack;
Deque<Location> destinations = new LinkedList<>(outputNodes);
Config cfg = BlockStorage.getLocationInfo(inputNode);
boolean roundrobin = "true".equals(cfg.getString("round-robin"));
if (roundrobin) {
roundRobinSort(inputNode, destinations);
}
for (Location output : destinations) {
Optional<Block> target = network.getAttachedBlock(output);
if (target.isPresent()) {
item = CargoUtils.insert(inventories, output.getBlock(), target.get(), item);
if (item == null) {
break;
}
}
}
return item;
}
/**
* This method sorts a given {@link Deque} of output node locations using a semi-accurate
* round-robin method.
*
* @param inputNode
* The {@link Location} of the input node
* @param outputNodes
* A {@link Deque} of {@link Location Locations} of the output nodes
*/
private void roundRobinSort(Location inputNode, Deque<Location> outputNodes) {
int index = network.roundRobin.getOrDefault(inputNode, 0);
if (index < outputNodes.size()) {
// Not ideal but actually not bad performance-wise over more elegant alternatives
for (int i = 0; i < index; i++) {
Location temp = outputNodes.removeFirst();
outputNodes.add(temp);
}
index++;
}
else {
index = 1;
}
network.roundRobin.put(inputNode, index);
}
}

View File

@ -1,10 +1,9 @@
package io.github.thebusybiscuit.slimefun4.core.networks.cargo;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.Map;
import java.util.logging.Level;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Tag;
import org.bukkit.block.Block;
@ -20,6 +19,7 @@ import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import io.github.thebusybiscuit.slimefun4.utils.itemstack.ItemStackWrapper;
import io.papermc.lib.PaperLib;
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.Slimefun;
@ -83,15 +83,23 @@ final class CargoUtils {
return false;
}
static ItemStack withdraw(Block node, Block target, ItemStack template) {
static ItemStack withdraw(Map<Location, Inventory> inventories, Block node, Block target, ItemStack template) {
DirtyChestMenu menu = getChestMenu(target);
if (menu == null) {
if (hasInventory(target)) {
BlockState state = target.getState();
Inventory inventory = inventories.get(target.getLocation());
if (inventory != null) {
return withdrawFromVanillaInventory(node, template, inventory);
}
BlockState state = PaperLib.getBlockState(target, false).getState();
if (state instanceof InventoryHolder) {
return withdrawFromVanillaInventory(node, template, ((InventoryHolder) state).getInventory());
inventory = ((InventoryHolder) state).getInventory();
inventories.put(target.getLocation(), inventory);
return withdrawFromVanillaInventory(node, template, inventory);
}
}
@ -135,10 +143,10 @@ final class CargoUtils {
ItemStackWrapper wrapper = new ItemStackWrapper(template);
for (int slot = minSlot; slot < maxSlot; slot++) {
// Changes to this ItemStack are synchronized with the Item in the Inventory
// Changes to these ItemStacks are synchronized with the Item in the Inventory
ItemStack itemInSlot = contents[slot];
if (SlimefunUtils.isItemSimilar(itemInSlot, wrapper, true) && matchesFilter(node, itemInSlot)) {
if (SlimefunUtils.isItemSimilar(itemInSlot, wrapper, true, false) && matchesFilter(node, itemInSlot)) {
if (itemInSlot.getAmount() > template.getAmount()) {
itemInSlot.setAmount(itemInSlot.getAmount() - template.getAmount());
return template;
@ -154,7 +162,7 @@ final class CargoUtils {
return null;
}
static ItemStackAndInteger withdraw(Block node, Block target, AtomicReference<Object> inventory) {
static ItemStackAndInteger withdraw(Map<Location, Inventory> inventories, Block node, Block target) {
DirtyChestMenu menu = getChestMenu(target);
if (menu != null) {
@ -163,45 +171,55 @@ final class CargoUtils {
if (matchesFilter(node, is)) {
menu.replaceExistingItem(slot, null);
inventory.set(menu);
return new ItemStackAndInteger(is, slot);
}
}
}
else if (hasInventory(target)) {
BlockState state = target.getState();
Inventory inventory = inventories.get(target.getLocation());
if (inventory != null) {
return withdrawFromVanillaInventory(node, inventory);
}
BlockState state = PaperLib.getBlockState(target, false).getState();
if (state instanceof InventoryHolder) {
Inventory inv = ((InventoryHolder) state).getInventory();
ItemStack[] contents = inv.getContents();
int minSlot = 0;
int maxSlot = contents.length;
if (inv instanceof FurnaceInventory) {
minSlot = 2;
maxSlot = 3;
}
else if (inv instanceof BrewerInventory) {
maxSlot = 3;
}
for (int slot = minSlot; slot < maxSlot; slot++) {
ItemStack is = contents[slot];
if (matchesFilter(node, is)) {
inv.setItem(slot, null);
inventory.set(inv);
return new ItemStackAndInteger(is, slot);
}
}
inventory = ((InventoryHolder) state).getInventory();
inventories.put(target.getLocation(), inventory);
return withdrawFromVanillaInventory(node, inventory);
}
}
return null;
}
static ItemStack insert(Block node, Block target, ItemStack stack) {
private static ItemStackAndInteger withdrawFromVanillaInventory(Block node, Inventory inv) {
ItemStack[] contents = inv.getContents();
int minSlot = 0;
int maxSlot = contents.length;
if (inv instanceof FurnaceInventory) {
minSlot = 2;
maxSlot = 3;
}
else if (inv instanceof BrewerInventory) {
maxSlot = 3;
}
for (int slot = minSlot; slot < maxSlot; slot++) {
ItemStack is = contents[slot];
if (matchesFilter(node, is)) {
inv.setItem(slot, null);
return new ItemStackAndInteger(is, slot);
}
}
return null;
}
static ItemStack insert(Map<Location, Inventory> inventories, Block node, Block target, ItemStack stack) {
if (!matchesFilter(node, stack)) {
return stack;
}
@ -210,10 +228,18 @@ final class CargoUtils {
if (menu == null) {
if (hasInventory(target)) {
BlockState state = target.getState();
Inventory inventory = inventories.get(target.getLocation());
if (inventory != null) {
return insertIntoVanillaInventory(stack, inventory);
}
BlockState state = PaperLib.getBlockState(target, false).getState();
if (state instanceof InventoryHolder) {
return insertIntoVanillaInventory(stack, ((InventoryHolder) state).getInventory());
inventory = ((InventoryHolder) state).getInventory();
inventories.put(target.getLocation(), inventory);
return insertIntoVanillaInventory(stack, inventory);
}
}
@ -222,8 +248,9 @@ final class CargoUtils {
ItemStackWrapper wrapper = new ItemStackWrapper(stack);
for (int slot : menu.getPreset().getSlotsAccessedByItemTransport(menu, ItemTransportFlow.INSERT, stack)) {
for (int slot : menu.getPreset().getSlotsAccessedByItemTransport(menu, ItemTransportFlow.INSERT, wrapper)) {
ItemStack itemInSlot = menu.getItemInSlot(slot);
if (itemInSlot == null) {
menu.replaceExistingItem(slot, stack);
return null;
@ -251,7 +278,7 @@ final class CargoUtils {
return stack;
}
static ItemStack insertIntoVanillaInventory(ItemStack stack, Inventory inv) {
private static ItemStack insertIntoVanillaInventory(ItemStack stack, Inventory inv) {
ItemStack[] contents = inv.getContents();
int minSlot = 0;
int maxSlot = contents.length;
@ -312,9 +339,6 @@ final class CargoUtils {
}
itemInSlot.setAmount(Math.min(amount, maxStackSize));
// Setting item in inventory will clone the ItemStack
inv.setItem(slot, itemInSlot);
return stack;
}
}
@ -359,9 +383,10 @@ final class CargoUtils {
}
// Store the returned Config instance to avoid heavy calls
Config blockInfo = BlockStorage.getLocationInfo(block.getLocation());
String id = blockInfo.getString("id");
Config blockData = BlockStorage.getLocationInfo(block.getLocation());
String id = blockData.getString("id");
// Cargo Output nodes have no filter actually
if (id.equals("CARGO_NODE_OUTPUT")) {
return true;
}
@ -373,43 +398,9 @@ final class CargoUtils {
return false;
}
boolean lore = "true".equals(blockInfo.getString("filter-lore"));
ItemStackWrapper wrapper = new ItemStackWrapper(item);
if ("whitelist".equals(blockInfo.getString("filter-type"))) {
List<ItemStack> templateItems = new LinkedList<>();
for (int slot : FILTER_SLOTS) {
ItemStack template = menu.getItemInSlot(slot);
if (template != null) {
templateItems.add(template);
}
}
if (templateItems.isEmpty()) {
return false;
}
for (ItemStack stack : templateItems) {
if (SlimefunUtils.isItemSimilar(wrapper, stack, lore)) {
return true;
}
}
return false;
}
else {
for (int slot : FILTER_SLOTS) {
ItemStack itemInSlot = menu.getItemInSlot(slot);
if (itemInSlot != null && SlimefunUtils.isItemSimilar(wrapper, itemInSlot, lore, false)) {
return false;
}
}
return true;
}
boolean lore = "true".equals(blockData.getString("filter-lore"));
boolean allowByDefault = !"whitelist".equals(blockData.getString("filter-type"));
return matchesFilterList(item, menu, lore, allowByDefault);
}
catch (Exception x) {
Slimefun.getLogger().log(Level.SEVERE, x, () -> "An Exception occurred while trying to filter items for a Cargo Node (" + id + ") at " + new BlockPosition(block));
@ -417,6 +408,27 @@ final class CargoUtils {
}
}
private static boolean matchesFilterList(ItemStack item, BlockMenu menu, boolean respectLore, boolean defaultValue) {
ItemStackWrapper wrapper = null;
for (int slot : FILTER_SLOTS) {
ItemStack stack = menu.getItemInSlot(slot);
if (stack != null) {
if (wrapper == null) {
// Only create this as needed to save performance
wrapper = new ItemStackWrapper(item);
}
if (SlimefunUtils.isItemSimilar(stack, wrapper, respectLore, false)) {
return !defaultValue;
}
}
}
return defaultValue;
}
/**
* 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.

View File

@ -12,7 +12,7 @@ import java.util.Map;
import java.util.Optional;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;
import org.bukkit.Location;
import org.bukkit.Material;
@ -32,9 +32,11 @@ import io.github.thebusybiscuit.slimefun4.api.network.Network;
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;
@ -69,40 +71,43 @@ abstract class ChestTerminalNetwork extends Network {
super(SlimefunPlugin.getNetworkManager(), regulator);
}
protected Optional<Block> getAttachedBlock(Block block) {
if (block.getType() == Material.PLAYER_WALL_HEAD) {
BlockFace cached = connectorCache.get(block.getLocation());
protected Optional<Block> getAttachedBlock(Location l) {
if (l.getWorld().isChunkLoaded(l.getBlockX() >> 4, l.getBlockZ() >> 4)) {
Block block = l.getBlock();
if (cached != null) {
return Optional.of(block.getRelative(cached));
if (block.getType() == Material.PLAYER_WALL_HEAD) {
BlockFace cached = connectorCache.get(l);
if (cached != null) {
return Optional.of(block.getRelative(cached));
}
BlockFace face = ((Directional) block.getBlockData()).getFacing().getOppositeFace();
connectorCache.put(l, face);
return Optional.of(block.getRelative(face));
}
BlockFace face = ((Directional) block.getBlockData()).getFacing().getOppositeFace();
connectorCache.put(block.getLocation(), face);
return Optional.of(block.getRelative(face));
}
return Optional.empty();
}
protected void handleItemRequests(Set<Location> providers, Set<Location> destinations) {
collectImportRequests();
collectExportRequests();
protected void handleItemRequests(Map<Location, Inventory> inventories, Set<Location> providers, Set<Location> destinations) {
collectImportRequests(inventories);
collectExportRequests(inventories);
collectTerminalRequests();
Iterator<ItemRequest> iterator = itemRequests.iterator();
while (iterator.hasNext()) {
ItemRequest request = iterator.next();
BlockMenu menu = BlockStorage.getInventory(request.getTerminal());
if (terminals.contains(request.getTerminal()) || imports.contains(request.getTerminal()) || exports.contains(request.getTerminal())) {
BlockMenu menu = BlockStorage.getInventory(request.getTerminal());
if (menu != null) {
switch (request.getDirection()) {
case INSERT:
distributeInsertionRequest(request, menu, iterator, destinations);
distributeInsertionRequest(inventories, request, menu, iterator, destinations);
break;
case WITHDRAW:
collectExtractionRequest(request, menu, iterator, providers);
collectExtractionRequest(inventories, request, menu, iterator, providers);
break;
default:
break;
@ -111,14 +116,14 @@ abstract class ChestTerminalNetwork extends Network {
}
}
private void distributeInsertionRequest(ItemRequest request, BlockMenu terminal, Iterator<ItemRequest> iterator, Set<Location> destinations) {
private void distributeInsertionRequest(Map<Location, Inventory> inventories, ItemRequest request, BlockMenu terminal, Iterator<ItemRequest> iterator, Set<Location> destinations) {
ItemStack item = request.getItem();
for (Location l : destinations) {
Optional<Block> target = getAttachedBlock(l.getBlock());
Optional<Block> target = getAttachedBlock(l);
if (target.isPresent()) {
item = CargoUtils.insert(l.getBlock(), target.get(), item);
item = CargoUtils.insert(inventories, l.getBlock(), target.get(), item);
if (item == null) {
terminal.replaceExistingItem(request.getSlot(), null);
@ -134,7 +139,7 @@ abstract class ChestTerminalNetwork extends Network {
iterator.remove();
}
private void collectExtractionRequest(ItemRequest request, BlockMenu terminal, Iterator<ItemRequest> iterator, Set<Location> providers) {
private void collectExtractionRequest(Map<Location, Inventory> inventories, ItemRequest request, BlockMenu terminal, Iterator<ItemRequest> iterator, Set<Location> providers) {
int slot = request.getSlot();
ItemStack prevStack = terminal.getItemInSlot(slot);
@ -147,10 +152,10 @@ abstract class ChestTerminalNetwork extends Network {
ItemStack item = request.getItem();
for (Location l : providers) {
Optional<Block> target = getAttachedBlock(l.getBlock());
Optional<Block> target = getAttachedBlock(l);
if (target.isPresent()) {
ItemStack is = CargoUtils.withdraw(l.getBlock(), target.get(), item);
ItemStack is = CargoUtils.withdraw(inventories, l.getBlock(), target.get(), item);
if (is != null) {
if (stack == null) {
@ -184,7 +189,7 @@ abstract class ChestTerminalNetwork extends Network {
iterator.remove();
}
private void collectImportRequests() {
private void collectImportRequests(Map<Location, Inventory> inventories) {
SlimefunItem item = SlimefunItem.getByID("CT_IMPORT_BUS");
for (Location bus : imports) {
@ -192,10 +197,10 @@ abstract class ChestTerminalNetwork extends Network {
BlockMenu menu = BlockStorage.getInventory(bus);
if (menu.getItemInSlot(17) == null) {
Optional<Block> target = getAttachedBlock(bus.getBlock());
Optional<Block> target = getAttachedBlock(bus);
if (target.isPresent()) {
ItemStackAndInteger stack = CargoUtils.withdraw(bus.getBlock(), target.get(), new AtomicReference<>());
ItemStackAndInteger stack = CargoUtils.withdraw(inventories, bus.getBlock(), target.get());
if (stack != null) {
menu.replaceExistingItem(17, stack.getItem());
@ -211,7 +216,7 @@ abstract class ChestTerminalNetwork extends Network {
}
}
private void collectExportRequests() {
private void collectExportRequests(Map<Location, Inventory> inventories) {
SlimefunItem item = SlimefunItem.getByID("CT_EXPORT_BUS");
for (Location bus : exports) {
@ -219,11 +224,9 @@ abstract class ChestTerminalNetwork extends Network {
BlockMenu menu = BlockStorage.getInventory(bus);
if (menu.getItemInSlot(17) != null) {
Optional<Block> target = getAttachedBlock(bus.getBlock());
Optional<Block> target = getAttachedBlock(bus);
if (target.isPresent()) {
menu.replaceExistingItem(17, CargoUtils.insert(bus.getBlock(), target.get(), menu.getItemInSlot(17)));
}
target.ifPresent(block -> menu.replaceExistingItem(17, CargoUtils.insert(inventories, bus.getBlock(), block, menu.getItemInSlot(17))));
}
if (menu.getItemInSlot(17) == null) {
@ -231,7 +234,10 @@ abstract class ChestTerminalNetwork extends Network {
for (int slot : slots) {
ItemStack template = menu.getItemInSlot(slot);
if (template != null) items.add(new CustomItem(template, 1));
if (template != null) {
items.add(new CustomItem(template, 1));
}
}
if (!items.isEmpty()) {
@ -252,18 +258,13 @@ abstract class ChestTerminalNetwork extends Network {
}
private void collectTerminalRequests() {
SlimefunItem item = SlimefunItem.getByID("CHEST_TERMINAL");
for (Location terminal : terminals) {
long timestamp = SlimefunPlugin.getProfiler().newEntry();
BlockMenu menu = BlockStorage.getInventory(terminal);
ItemStack sendingItem = menu.getItemInSlot(TERMINAL_OUT_SLOT);
if (sendingItem != null) {
itemRequests.add(new ItemRequest(terminal, TERMINAL_OUT_SLOT, sendingItem, ItemTransportFlow.INSERT));
}
SlimefunPlugin.getProfiler().closeEntry(terminal, item, timestamp);
}
}
@ -275,6 +276,16 @@ abstract class ChestTerminalNetwork extends Network {
* A {@link Set} of providers to this {@link ChestTerminalNetwork}
*/
protected void updateTerminals(Set<Location> providers) {
if (terminals.isEmpty()) {
// Performance improvement - We don't need to compute items for
// Cargo networks without any Chest Terminals
return;
}
// Timings will be slightly inaccurate here but most often people are gonna
// use no more than one terminal anyway, so this might be fine
long timestamp = SlimefunPlugin.getProfiler().newEntry();
SlimefunItem item = SlimefunItem.getByID("CHEST_TERMINAL");
List<ItemStackAndInteger> items = findAvailableItems(providers);
for (Location l : terminals) {
@ -291,6 +302,8 @@ abstract class ChestTerminalNetwork extends Network {
int index = i + (TERMINAL_SLOTS.length * (page - 1));
updateTerminal(l, terminal, slot, index, items);
}
SlimefunPlugin.getProfiler().closeEntry(l, item, timestamp);
}
}
@ -324,7 +337,8 @@ abstract class ChestTerminalNetwork extends Network {
terminal.replaceExistingItem(slot, stack);
terminal.addMenuClickHandler(slot, (p, sl, is, action) -> {
int amount = item.getInt() > item.getItem().getMaxStackSize() ? item.getItem().getMaxStackSize() : item.getInt();
itemRequests.add(new ItemRequest(l, 44, new CustomItem(item.getItem(), action.isRightClicked() ? amount : 1), ItemTransportFlow.WITHDRAW));
ItemStack requestedItem = new CustomItem(item.getItem(), action.isRightClicked() ? amount : 1);
itemRequests.add(new ItemRequest(l, 44, requestedItem, ItemTransportFlow.WITHDRAW));
return false;
});
@ -339,7 +353,7 @@ abstract class ChestTerminalNetwork extends Network {
List<ItemStackAndInteger> items = new LinkedList<>();
for (Location l : providers) {
Optional<Block> block = getAttachedBlock(l.getBlock());
Optional<Block> block = getAttachedBlock(l);
if (block.isPresent()) {
Block target = block.get();
@ -353,17 +367,21 @@ abstract class ChestTerminalNetwork extends Network {
}
else if (BlockStorage.hasInventory(target)) {
BlockMenu blockMenu = BlockStorage.getInventory(target);
Config cfg = BlockStorage.getLocationInfo(target.getLocation());
if (cfg.getString("id").startsWith("BARREL_") && cfg.getString("storedItems") != null) {
gatherItemsFromBarrel(l, cfg, blockMenu, items);
if (blockMenu.getPreset().getID().startsWith("BARREL_")) {
Config cfg = BlockStorage.getLocationInfo(target.getLocation());
String data = cfg.getString("storedItems");
if (data != null) {
gatherItemsFromBarrel(l, data, blockMenu, items);
}
}
else {
handleWithdraw(blockMenu, items, l);
}
}
else if (CargoUtils.hasInventory(target)) {
BlockState state = target.getState();
BlockState state = PaperLib.getBlockState(target, false).getState();
if (state instanceof InventoryHolder) {
Inventory inv = ((InventoryHolder) state).getInventory();
@ -380,27 +398,32 @@ abstract class ChestTerminalNetwork extends Network {
return items;
}
private void gatherItemsFromBarrel(Location l, Config cfg, BlockMenu blockMenu, List<ItemStackAndInteger> items) {
int stored = Integer.parseInt(cfg.getString("storedItems"));
private void gatherItemsFromBarrel(Location l, String data, BlockMenu blockMenu, List<ItemStackAndInteger> items) {
try {
int stored = Integer.parseInt(data);
for (int slot : blockMenu.getPreset().getSlotsAccessedByItemTransport((DirtyChestMenu) blockMenu, ItemTransportFlow.WITHDRAW, null)) {
ItemStack is = blockMenu.getItemInSlot(slot);
for (int slot : blockMenu.getPreset().getSlotsAccessedByItemTransport((DirtyChestMenu) blockMenu, ItemTransportFlow.WITHDRAW, null)) {
ItemStack is = blockMenu.getItemInSlot(slot);
if (is != null && CargoUtils.matchesFilter(l.getBlock(), is)) {
boolean add = true;
if (is != null && CargoUtils.matchesFilter(l.getBlock(), is)) {
boolean add = true;
for (ItemStackAndInteger item : items) {
if (SlimefunUtils.isItemSimilar(is, item.getItem(), true)) {
add = false;
item.add(is.getAmount() + stored);
for (ItemStackAndInteger item : items) {
if (SlimefunUtils.isItemSimilar(is, item.getItemStackWrapper(), true, false)) {
add = false;
item.add(is.getAmount() + stored);
}
}
if (add) {
items.add(new ItemStackAndInteger(is, is.getAmount() + stored));
}
}
if (add) {
items.add(new ItemStackAndInteger(is, is.getAmount() + stored));
}
}
}
catch (Exception x) {
Slimefun.getLogger().log(Level.SEVERE, "An Exception occured while trying to read data from a Barrel", x);
}
}
private void handleWithdraw(DirtyChestMenu menu, List<ItemStackAndInteger> items, Location l) {
@ -414,7 +437,7 @@ abstract class ChestTerminalNetwork extends Network {
boolean add = true;
for (ItemStackAndInteger item : items) {
if (SlimefunUtils.isItemSimilar(stack, item.getItem(), true)) {
if (SlimefunUtils.isItemSimilar(stack, item.getItemStackWrapper(), true)) {
add = false;
item.add(stack.getAmount());
}

View File

@ -2,9 +2,12 @@ package io.github.thebusybiscuit.slimefun4.core.networks.cargo;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.utils.itemstack.ItemStackWrapper;
class ItemStackAndInteger {
private final ItemStack item;
private ItemStackWrapper wrapper;
private int number;
ItemStackAndInteger(ItemStack item, int amount) {
@ -20,6 +23,14 @@ class ItemStackAndInteger {
return item;
}
public ItemStackWrapper getItemStackWrapper() {
if (wrapper == null && item != null) {
wrapper = new ItemStackWrapper(item);
}
return wrapper;
}
public void add(int amount) {
number += amount;
}

View File

@ -1,6 +1,8 @@
package io.github.thebusybiscuit.slimefun4.core.networks.energy;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
@ -15,6 +17,7 @@ import io.github.thebusybiscuit.slimefun4.api.ErrorReport;
import io.github.thebusybiscuit.slimefun4.api.network.Network;
import io.github.thebusybiscuit.slimefun4.api.network.NetworkComponent;
import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent;
import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetProvider;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.reactors.Reactor;
@ -35,6 +38,7 @@ import me.mrCookieSlime.Slimefun.api.energy.ChargableBlock;
*
* @see Network
* @see EnergyNetComponent
* @see EnergyNetProvider
* @see EnergyNetComponentType
*
*/
@ -49,16 +53,10 @@ public class EnergyNet extends Network {
return EnergyNetComponentType.NONE;
}
if (SlimefunPlugin.getRegistry().getEnergyGenerators().contains(id)) {
return EnergyNetComponentType.GENERATOR;
}
SlimefunItem item = SlimefunItem.getByID(id);
if (SlimefunPlugin.getRegistry().getEnergyCapacitors().contains(id)) {
return EnergyNetComponentType.CAPACITOR;
}
if (SlimefunPlugin.getRegistry().getEnergyConsumers().contains(id)) {
return EnergyNetComponentType.CONSUMER;
if (item instanceof EnergyNetComponent) {
return ((EnergyNetComponent) item).getEnergyComponentType();
}
return EnergyNetComponentType.NONE;
@ -143,10 +141,10 @@ public class EnergyNet extends Network {
SimpleHologram.update(b, "&4No Energy Network found");
}
else {
double supply = DoubleHandler.fixDouble(tickAllGenerators(timestamp::getAndAdd) + tickAllCapacitors());
double demand = 0;
int availableEnergy = (int) supply;
Map<Location, Integer> generatorsWithCapacity = new HashMap<>();
int supply = tickAllGenerators(generatorsWithCapacity, timestamp::getAndAdd) + tickAllCapacitors();
int remainingEnergy = supply;
int demand = 0;
for (Location machine : consumers) {
int capacity = ChargableBlock.getMaxCharge(machine);
@ -156,20 +154,20 @@ public class EnergyNet extends Network {
int availableSpace = capacity - charge;
demand += availableSpace;
if (availableEnergy > 0) {
if (availableEnergy > availableSpace) {
if (remainingEnergy > 0) {
if (remainingEnergy > availableSpace) {
ChargableBlock.setUnsafeCharge(machine, capacity, false);
availableEnergy -= availableSpace;
remainingEnergy -= availableSpace;
}
else {
ChargableBlock.setUnsafeCharge(machine, charge + availableEnergy, false);
availableEnergy = 0;
ChargableBlock.setUnsafeCharge(machine, charge + remainingEnergy, false);
remainingEnergy = 0;
}
}
}
}
storeExcessEnergy(availableEnergy);
storeExcessEnergy(generatorsWithCapacity, remainingEnergy);
updateHologram(b, supply, demand);
}
@ -177,7 +175,7 @@ public class EnergyNet extends Network {
SlimefunPlugin.getProfiler().closeEntry(b.getLocation(), SlimefunItems.ENERGY_REGULATOR.getItem(), timestamp.get());
}
private void storeExcessEnergy(int available) {
private void storeExcessEnergy(Map<Location, Integer> generators, int available) {
for (Location capacitor : storage) {
if (available > 0) {
int capacity = ChargableBlock.getMaxCharge(capacitor);
@ -196,40 +194,82 @@ public class EnergyNet extends Network {
}
}
for (Location generator : generators) {
int capacity = ChargableBlock.getMaxCharge(generator);
for (Map.Entry<Location, Integer> entry : generators.entrySet()) {
Location generator = entry.getKey();
int capacity = entry.getValue();
if (capacity > 0) {
if (available > 0) {
if (available > capacity) {
ChargableBlock.setUnsafeCharge(generator, capacity, false);
available = available - capacity;
}
else {
ChargableBlock.setUnsafeCharge(generator, available, false);
available = 0;
}
if (available > 0) {
if (available > capacity) {
ChargableBlock.setUnsafeCharge(generator, capacity, false);
available -= capacity;
}
else {
ChargableBlock.setUnsafeCharge(generator, 0, false);
ChargableBlock.setUnsafeCharge(generator, available, false);
available = 0;
}
}
else {
ChargableBlock.setUnsafeCharge(generator, 0, false);
}
}
}
private double tickAllGenerators(LongConsumer timeCallback) {
double supply = 0;
private int tickAllGenerators(Map<Location, Integer> generatorsWithCapacity, LongConsumer timeCallback) {
Set<Location> exploded = new HashSet<>();
int supply = 0;
for (Location source : generators) {
long timestamp = SlimefunPlugin.getProfiler().newEntry();
Config config = BlockStorage.getLocationInfo(source);
SlimefunItem item = SlimefunItem.getByID(config.getString("id"));
if (item != null) {
if (item instanceof EnergyNetProvider) {
try {
EnergyNetProvider provider = (EnergyNetProvider) item;
int energy = provider.getGeneratedOutput(source, config);
if (provider.getCapacity() > 0) {
generatorsWithCapacity.put(source, provider.getCapacity());
String charge = config.getString("energy-charge");
if (charge != null) {
energy += Integer.parseInt(charge);
}
}
if (provider.willExplode(source, config)) {
exploded.add(source);
BlockStorage.clearBlockInfo(source);
Slimefun.runSync(() -> {
source.getBlock().setType(Material.LAVA);
source.getWorld().createExplosion(source, 0F, false);
});
}
else {
supply += energy;
}
}
catch (Exception | LinkageError t) {
exploded.add(source);
new ErrorReport(t, source, item);
}
long time = SlimefunPlugin.getProfiler().closeEntry(source, item, timestamp);
timeCallback.accept(time);
}
else if (item != null) {
try {
// This will be removed very very soon
// It is only here for temporary backwards compatibility
GeneratorTicker generator = item.getEnergyTicker();
Integer capacity = SlimefunPlugin.getRegistry().getEnergyCapacities().get(item.getID());
if (capacity != null && capacity.intValue() > 0) {
generatorsWithCapacity.put(source, capacity);
}
if (generator != null) {
double energy = generator.generateEnergy(source, item, config);
@ -267,12 +307,11 @@ public class EnergyNet extends Network {
}
generators.removeAll(exploded);
return supply;
}
private double tickAllCapacitors() {
double supply = 0;
private int tickAllCapacitors() {
int supply = 0;
for (Location capacitor : storage) {
supply += ChargableBlock.getCharge(capacitor);

View File

@ -41,7 +41,7 @@ public class Research implements Keyed {
private final NamespacedKey key;
private final int id;
private String name;
private final String name;
private boolean enabled = true;
private int cost;

View File

@ -0,0 +1,242 @@
package io.github.thebusybiscuit.slimefun4.core.services;
import javax.annotation.Nullable;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.utils.PatternUtils;
import kong.unirest.HttpResponse;
import kong.unirest.JsonNode;
import kong.unirest.Unirest;
import kong.unirest.UnirestException;
import me.mrCookieSlime.Slimefun.api.Slimefun;
import org.bukkit.plugin.Plugin;
/**
* This Class represents a Metrics Service that sends data to https://bstats.org/
* This data is used to analyse the usage of this {@link Plugin}.
* <p>
* You can find more info in the README file of this Project on GitHub. <br>
* <b>Note:</b> To start the metrics you will need to be calling {@link #start()}
*
* @author WalshyDev
*/
public class MetricsService {
private static final String REPO_NAME = "MetricsModule";
private static final String GH_API = "https://api.github.com/repos/Slimefun/" + REPO_NAME;
private static final String GH_RELEASES = "https://github.com/Slimefun/" + REPO_NAME + "/releases/download";
private final SlimefunPlugin plugin;
private final File parentFolder;
private final File metricsModuleFile;
private URLClassLoader moduleClassLoader;
private String metricVersion = null;
private boolean hasDownloadedUpdate = false;
static {
Unirest.config()
.concurrency(2, 1)
.setDefaultHeader("User-Agent", "MetricsModule Auto-Updater")
.setDefaultHeader("Accept", "application/vnd.github.v3+json")
.enableCookieManagement(false)
.cookieSpec("ignoreCookies");
}
public MetricsService(SlimefunPlugin plugin) {
this.plugin = plugin;
this.parentFolder = new File(plugin.getDataFolder(), "cache" + File.separatorChar + "modules");
if (!parentFolder.exists()) {
parentFolder.mkdirs();
}
this.metricsModuleFile = new File(parentFolder, REPO_NAME + ".jar");
}
/**
* This method loads the metric module and starts the metrics collection.
*/
public void start() {
if (!metricsModuleFile.exists()) {
plugin.getLogger().info(REPO_NAME + " does not exist, downloading...");
if (!download(getLatestVersion())) {
plugin.getLogger().warning("Failed to start metrics as the file could not be downloaded.");
return;
}
}
try {
// Load the jar file into a child class loader using the SF PluginClassLoader
// as a parent.
moduleClassLoader = URLClassLoader.newInstance(new URL[] { metricsModuleFile.toURI().toURL() },
plugin.getClass().getClassLoader());
Class<?> cl = moduleClassLoader.loadClass("dev.walshy.sfmetrics.MetricsModule");
metricVersion = cl.getPackage().getImplementationVersion();
// If it has not been newly downloaded, auto-updates are on AND there's a new version
// then cleanup, download and start
if (!hasDownloadedUpdate && hasAutoUpdates() && checkForUpdate(metricVersion)
) {
plugin.getLogger().info("Cleaning up and re-loading Metrics.");
cleanUp();
start();
return;
}
// Finally, we're good to start this.
Method start = cl.getDeclaredMethod("start");
String version = cl.getPackage().getImplementationVersion();
// This is required to be sync due to bStats.
Slimefun.runSync(() -> {
try {
start.invoke(null);
plugin.getLogger().info("Metrics build #" + version + " started.");
} catch (Exception e) {
plugin.getLogger().log(Level.WARNING, "Failed to start metrics.", e);
}
});
} catch (Exception e) {
plugin.getLogger().log(Level.WARNING,
"Failed to load the metrics module. Maybe the jar is corrupt?", e);
}
}
/**
* This will close the child classloader and mark all the resources held under this no longer
* in use, they will be cleaned up the next GC run.
*/
public void cleanUp() {
try {
if (this.moduleClassLoader != null) {
this.moduleClassLoader.close();
}
} catch (IOException e) {
plugin.getLogger().log(Level.WARNING,
"Could not clean up module class loader. Some memory may have been leaked.");
}
}
/**
* Checks for a new update and compares it against the current version.
* If there is a new version available then this returns true.
*
* @param currentVersion The current version which is being used.
* @return True if there is an update available.
*/
public boolean checkForUpdate(String currentVersion) {
if (currentVersion == null || !PatternUtils.NUMERIC.matcher(currentVersion).matches()) {
return false;
}
int latest = getLatestVersion();
if (latest > Integer.parseInt(currentVersion)) {
return download(latest);
}
return false;
}
/**
* Gets the latest version available as an int.
* This is an internal method used by {@link #checkForUpdate(String)}.
* If it cannot get the version for whatever reason this will return 0, effectively always
* being behind.
*
* @return The latest version as an integer or -1 if it failed to fetch.
*/
private int getLatestVersion() {
try {
HttpResponse<JsonNode> response = Unirest.get(GH_API + "/releases/latest")
.asJson();
if (!response.isSuccess()) return -1;
JsonNode node = response.getBody();
if (node == null) return -1;
return node.getObject().getInt("tag_name");
} catch (UnirestException e) {
plugin.getLogger().log(Level.SEVERE, "Failed to fetch latest builds for SFMetrics");
return -1;
}
}
/**
* Downloads the version specified to Slimefun's data folder.
*
* @param version The version to download.
*/
private boolean download(int version) {
File f = new File(parentFolder, "Metrics-" + version + ".jar");
try {
plugin.getLogger().log(Level.INFO, "# Starting download of MetricsModule build: #{0}", version);
AtomicInteger lastPercentPosted = new AtomicInteger();
HttpResponse<File> response = Unirest.get(GH_RELEASES + "/" + version
+ "/" + REPO_NAME + ".jar")
.downloadMonitor((b, fileName, bytesWritten, totalBytes) -> {
int percent = (int) (20 * (Math.round((((double) bytesWritten / totalBytes) * 100) / 20)));
if (percent != 0 && percent != lastPercentPosted.get()) {
plugin.getLogger().info("# Downloading... " + percent + "% " +
"(" + bytesWritten + "/" + totalBytes + " bytes)");
lastPercentPosted.set(percent);
}
})
.asFile(f.getPath());
if (response.isSuccess()) {
plugin.getLogger().log(Level.INFO, "Successfully downloaded {0} build: #{1}", new Object[] {REPO_NAME, version});
// Replace the metric file with the new one
Files.move(f.toPath(), metricsModuleFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
metricVersion = String.valueOf(version);
hasDownloadedUpdate = true;
return true;
}
} catch (UnirestException e) {
plugin.getLogger().log(Level.WARNING, "Failed to fetch the latest jar file from the" +
" builds page. Perhaps GitHub is down.");
} catch (IOException e) {
plugin.getLogger().log(Level.WARNING, "Failed to replace the old metric file with the " +
"new one. Please do this manually! Error: {0}", e.getMessage());
}
return false;
}
/**
* Returns the currently downloaded metrics version.
* This <strong>can change</strong>! It may be null or an
* older version before it has downloaded a newer one.
*
* @return The current version or null if not loaded.
*/
@Nullable
public String getVersion() {
return metricVersion;
}
/**
* Returns if the current server has metrics auto-updates enabled.
*
* @return True if the current server has metrics auto-updates enabled.
*/
public boolean hasAutoUpdates() {
return SlimefunPlugin.instance().getConfig().getBoolean("metrics.auto-update");
}
}

View File

@ -6,10 +6,9 @@ import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import kong.unirest.JsonNode;
import kong.unirest.json.JSONArray;
import kong.unirest.json.JSONObject;
import me.mrCookieSlime.Slimefun.api.Slimefun;
class ContributionsConnector extends GitHubConnector {
@ -57,10 +56,10 @@ class ContributionsConnector extends GitHubConnector {
}
@Override
public void onSuccess(JsonElement element) {
public void onSuccess(JsonNode element) {
finished = true;
if (element.isJsonArray()) {
computeContributors(element.getAsJsonArray());
if (element.isArray()) {
computeContributors(element.getArray());
}
else {
Slimefun.getLogger().log(Level.WARNING, "Received an unusual answer from GitHub, possibly a timeout? ({0})", element);
@ -82,13 +81,13 @@ class ContributionsConnector extends GitHubConnector {
return "/contributors?per_page=100&page=" + page;
}
private void computeContributors(JsonArray array) {
for (int i = 0; i < array.size(); i++) {
JsonObject object = array.get(i).getAsJsonObject();
private void computeContributors(JSONArray array) {
for (int i = 0; i < array.length(); i++) {
JSONObject object = array.getJSONObject(i);
String name = object.get("login").getAsString();
int commits = object.get("contributions").getAsInt();
String profile = object.get("html_url").getAsString();
String name = object.getString("login");
int commits = object.getInt("contributions");
String profile = object.getString("html_url");
if (!blacklist.contains(name)) {
github.addContributor(aliases.getOrDefault(name, name), profile, role, commits);

View File

@ -6,17 +6,14 @@ import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.charset.StandardCharsets;
import java.util.logging.Level;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import kong.unirest.HttpResponse;
import kong.unirest.JsonNode;
import kong.unirest.Unirest;
import kong.unirest.UnirestException;
import kong.unirest.json.JSONException;
import me.mrCookieSlime.Slimefun.api.Slimefun;
abstract class GitHubConnector {
@ -34,7 +31,7 @@ abstract class GitHubConnector {
public abstract String getURLSuffix();
public abstract void onSuccess(JsonElement element);
public abstract void onSuccess(JsonNode element);
public void onFailure() {
// Don't do anything by default
@ -48,58 +45,54 @@ abstract class GitHubConnector {
}
try {
URL website = new URL("https://api.github.com/repos/" + repository + getURLSuffix());
HttpResponse<JsonNode> resp = Unirest.get("https://api.github.com/repos/" + repository + getURLSuffix())
.header("User-Agent", "Slimefun4 (https://github.com/Slimefun)")
.asJson();
URLConnection connection = website.openConnection();
connection.setConnectTimeout(8000);
connection.addRequestProperty("Accept-Charset", "UTF-8");
connection.addRequestProperty("User-Agent", "Slimefun 4 GitHub Agent (by TheBusyBiscuit)");
connection.setDoOutput(true);
try (ReadableByteChannel channel = Channels.newChannel(connection.getInputStream())) {
try (FileOutputStream stream = new FileOutputStream(file)) {
stream.getChannel().transferFrom(channel, 0, Long.MAX_VALUE);
parseData();
}
if (resp.isSuccess()) {
onSuccess(resp.getBody());
writeCacheFile(resp.getBody());
}
else {
Slimefun.getLogger().log(Level.WARNING, "Failed to fetch {0}", repository + getURLSuffix());
}
}
catch (IOException e) {
catch (UnirestException e) {
if (github.isLoggingEnabled()) {
Slimefun.getLogger().log(Level.WARNING, "Could not connect to GitHub in time.");
}
if (hasData()) {
parseData();
}
else {
onFailure();
}
}
}
// It has the cached file, let's just read that then
if (file.exists()) {
JsonNode cache = readCacheFile();
public boolean hasData() {
return getFile().exists();
}
public File getFile() {
return file;
}
public void parseData() {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(getFile()), StandardCharsets.UTF_8))) {
StringBuilder builder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
builder.append(line);
if (cache != null) {
onSuccess(cache);
return;
}
}
JsonElement element = new JsonParser().parse(builder.toString());
onSuccess(element);
}
catch (IOException x) {
Slimefun.getLogger().log(Level.SEVERE, x, () -> "An Error occurred while parsing GitHub-Data for Slimefun " + SlimefunPlugin.getVersion());
// If the request failed and it failed to read the cache then call onFailure.
onFailure();
}
}
private JsonNode readCacheFile() {
try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8))) {
return new JsonNode(br.readLine());
}
catch (IOException | JSONException e) {
Slimefun.getLogger().log(Level.WARNING, "Failed to read Github cache file: {0}", file.getName());
return null;
}
}
private void writeCacheFile(JsonNode node) {
try (FileOutputStream fos = new FileOutputStream(file)) {
fos.write(node.toString().getBytes(StandardCharsets.UTF_8));
}
catch (IOException e) {
Slimefun.getLogger().log(Level.WARNING, "Failed to populate GitHub cache");
}
}
}

View File

@ -2,10 +2,9 @@ package io.github.thebusybiscuit.slimefun4.core.services.github;
import java.util.logging.Level;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import kong.unirest.JsonNode;
import kong.unirest.json.JSONArray;
import kong.unirest.json.JSONObject;
import me.mrCookieSlime.Slimefun.api.Slimefun;
class GitHubIssuesTracker extends GitHubConnector {
@ -25,15 +24,15 @@ class GitHubIssuesTracker extends GitHubConnector {
}
@Override
public void onSuccess(JsonElement element) {
if (element.isJsonArray()) {
JsonArray array = element.getAsJsonArray();
public void onSuccess(JsonNode element) {
if (element.isArray()) {
JSONArray array = element.getArray();
int issues = 0;
int pullRequests = 0;
for (JsonElement elem : array) {
JsonObject obj = elem.getAsJsonObject();
for (int i = 0; i < array.length(); i++) {
JSONObject obj = array.getJSONObject(i);
if (obj.has("pull_request")) {
pullRequests++;

View File

@ -9,14 +9,13 @@ import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import io.github.thebusybiscuit.cscorelib2.config.Config;
import io.github.thebusybiscuit.slimefun4.core.services.localization.Translators;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.utils.HeadTexture;
import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
import kong.unirest.JsonNode;
import kong.unirest.json.JSONObject;
/**
* This Service is responsible for grabbing every {@link Contributor} to this project
@ -108,11 +107,11 @@ public class GitHubService {
connectors.add(new GitHubConnector(this, repository) {
@Override
public void onSuccess(JsonElement element) {
JsonObject object = element.getAsJsonObject();
forks = object.get("forks").getAsInt();
stars = object.get("stargazers_count").getAsInt();
lastUpdate = NumberUtils.parseGitHubDate(object.get("pushed_at").getAsString());
public void onSuccess(JsonNode element) {
JSONObject object = element.getObject();
forks = object.getInt("forks");
stars = object.getInt("stargazers_count");
lastUpdate = NumberUtils.parseGitHubDate(object.getString("pushed_at"));
}
@Override
@ -206,9 +205,7 @@ public class GitHubService {
for (Contributor contributor : contributors.values()) {
Optional<UUID> uuid = contributor.getUniqueId();
if (uuid.isPresent()) {
uuidCache.setValue(contributor.getName(), uuid.get());
}
uuid.ifPresent(value -> uuidCache.setValue(contributor.getName(), value));
if (contributor.hasTexture()) {
String texture = contributor.getTexture();

View File

@ -56,9 +56,9 @@ class GitHubTask implements Runnable {
}
}
if (requests >= MAX_REQUESTS_PER_MINUTE && SlimefunPlugin.instance != null && SlimefunPlugin.instance.isEnabled()) {
if (requests >= MAX_REQUESTS_PER_MINUTE && SlimefunPlugin.instance() != null && SlimefunPlugin.instance().isEnabled()) {
// Slow down API requests and wait a minute after more than x requests were made
Bukkit.getScheduler().runTaskLaterAsynchronously(SlimefunPlugin.instance, this::grabTextures, 2 * 60 * 20L);
Bukkit.getScheduler().runTaskLaterAsynchronously(SlimefunPlugin.instance(), this::grabTextures, 2 * 60 * 20L);
}
for (GitHubConnector connector : gitHubService.getConnectors()) {
@ -94,14 +94,14 @@ class GitHubTask implements Runnable {
// Retry after 5 minutes if it was rate-limiting
if (x.getMessage().contains("429")) {
Bukkit.getScheduler().runTaskLaterAsynchronously(SlimefunPlugin.instance, this::grabTextures, 5 * 60 * 20L);
Bukkit.getScheduler().runTaskLaterAsynchronously(SlimefunPlugin.instance(), this::grabTextures, 5 * 60 * 20L);
}
return -1;
}
catch (TooManyRequestsException x) {
Slimefun.getLogger().log(Level.WARNING, "Received a rate-limit from mojang.com, retrying in 4 minutes");
Bukkit.getScheduler().runTaskLaterAsynchronously(SlimefunPlugin.instance, this::grabTextures, 4 * 60 * 20L);
Bukkit.getScheduler().runTaskLaterAsynchronously(SlimefunPlugin.instance(), this::grabTextures, 4 * 60 * 20L);
return -1;
}
@ -116,9 +116,7 @@ class GitHubTask implements Runnable {
if (!uuid.isPresent()) {
uuid = MinecraftAccount.getUUID(contributor.getMinecraftName());
if (uuid.isPresent()) {
contributor.setUniqueId(uuid.get());
}
uuid.ifPresent(contributor::setUniqueId);
}
if (uuid.isPresent()) {

View File

@ -1,27 +0,0 @@
package io.github.thebusybiscuit.slimefun4.core.services.metrics;
import java.util.HashMap;
import java.util.Map;
import org.bstats.bukkit.Metrics.AdvancedPie;
import org.bukkit.plugin.Plugin;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
class AddonsChart extends AdvancedPie {
AddonsChart() {
super("installed_addons", () -> {
Map<String, Integer> addons = new HashMap<>();
for (Plugin plugin : SlimefunPlugin.getInstalledAddons()) {
if (plugin.isEnabled()) {
addons.put(plugin.getName(), 1);
}
}
return addons;
});
}
}

View File

@ -1,16 +0,0 @@
package io.github.thebusybiscuit.slimefun4.core.services.metrics;
import org.bstats.bukkit.Metrics.SimplePie;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
class AutoUpdaterChart extends SimplePie {
AutoUpdaterChart() {
super("auto_updates", () -> {
boolean enabled = SlimefunPlugin.getUpdater().isEnabled();
return enabled ? "enabled" : "disabled";
});
}
}

View File

@ -1,25 +0,0 @@
package io.github.thebusybiscuit.slimefun4.core.services.metrics;
import java.util.HashMap;
import java.util.Map;
import org.bstats.bukkit.Metrics.AdvancedPie;
import io.github.thebusybiscuit.slimefun4.core.commands.SubCommand;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
class CommandChart extends AdvancedPie {
CommandChart() {
super("commands_ran", () -> {
Map<String, Integer> commands = new HashMap<>();
for (Map.Entry<SubCommand, Integer> entry : SlimefunPlugin.getCommand().getCommandUsage().entrySet()) {
commands.put("/sf " + entry.getKey().getName(), entry.getValue());
}
return commands;
});
}
}

View File

@ -1,16 +0,0 @@
package io.github.thebusybiscuit.slimefun4.core.services.metrics;
import org.bstats.bukkit.Metrics.SimplePie;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
class CompatibilityModeChart extends SimplePie {
CompatibilityModeChart() {
super("compatibility_mode", () -> {
boolean enabled = SlimefunPlugin.getRegistry().isBackwardsCompatible();
return enabled ? "enabled" : "disabled";
});
}
}

View File

@ -1,17 +0,0 @@
package io.github.thebusybiscuit.slimefun4.core.services.metrics;
import org.bstats.bukkit.Metrics.SimplePie;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
class GuideLayoutChart extends SimplePie {
GuideLayoutChart() {
super("guide_layout", () -> {
boolean book = SlimefunPlugin.getCfg().getBoolean("guide.default-view-book");
return book ? "Book" : "Chest GUI";
});
}
}

View File

@ -1,55 +0,0 @@
package io.github.thebusybiscuit.slimefun4.core.services.metrics;
import org.bstats.bukkit.Metrics;
import org.bukkit.plugin.Plugin;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
/**
* This Class represents a Metrics Service that sends data to https://bstats.org/
* This data is used to analyse the usage of this {@link Plugin}.
*
* You can find more info in the README file of this Project on GitHub.
*
* @author TheBusyBiscuit
*
*/
public class MetricsService {
private final SlimefunPlugin plugin;
/**
* This creates a new {@link MetricsService}. The constructor does not set up
* anything related to bStats yet, that happens in the {@link MetricsService#start()} method.
*
* @param plugin
* The instance of our {@link SlimefunPlugin}
*/
public MetricsService(SlimefunPlugin plugin) {
this.plugin = plugin;
}
/**
* This method intializes and starts the metrics collection.
*/
public void start() {
Metrics metrics = new Metrics(plugin, 4574);
if (SlimefunPlugin.getUpdater().getBranch().isOfficial()) {
// We really do not need this data if it is an unofficially modified build...
metrics.addCustomChart(new AutoUpdaterChart());
}
metrics.addCustomChart(new ResourcePackChart());
metrics.addCustomChart(new SlimefunVersionChart());
metrics.addCustomChart(new ServerLanguageChart());
metrics.addCustomChart(new PlayerLanguageChart());
metrics.addCustomChart(new ResearchesEnabledChart());
metrics.addCustomChart(new GuideLayoutChart());
metrics.addCustomChart(new AddonsChart());
metrics.addCustomChart(new CommandChart());
metrics.addCustomChart(new ServerSizeChart());
metrics.addCustomChart(new CompatibilityModeChart());
}
}

View File

@ -1,31 +0,0 @@
package io.github.thebusybiscuit.slimefun4.core.services.metrics;
import java.util.HashMap;
import java.util.Map;
import org.bstats.bukkit.Metrics.AdvancedPie;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import io.github.thebusybiscuit.slimefun4.core.services.localization.Language;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
class PlayerLanguageChart extends AdvancedPie {
PlayerLanguageChart() {
super("player_languages", () -> {
Map<String, Integer> languages = new HashMap<>();
for (Player p : Bukkit.getOnlinePlayers()) {
Language language = SlimefunPlugin.getLocalization().getLanguage(p);
boolean supported = SlimefunPlugin.getLocalization().isLanguageLoaded(language.getId());
String lang = supported ? language.getId() : "Unsupported Language";
languages.merge(lang, 1, Integer::sum);
}
return languages;
});
}
}

View File

@ -1,16 +0,0 @@
package io.github.thebusybiscuit.slimefun4.core.services.metrics;
import org.bstats.bukkit.Metrics.SimplePie;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
class ResearchesEnabledChart extends SimplePie {
ResearchesEnabledChart() {
super("servers_with_researches_enabled", () -> {
boolean enabled = SlimefunPlugin.getRegistry().isFreeCreativeResearchingEnabled();
return enabled ? "enabled" : "disabled";
});
}
}

View File

@ -1,25 +0,0 @@
package io.github.thebusybiscuit.slimefun4.core.services.metrics;
import org.bstats.bukkit.Metrics.SimplePie;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
class ResourcePackChart extends SimplePie {
ResourcePackChart() {
super("resourcepack", () -> {
String version = SlimefunPlugin.getItemTextureService().getVersion();
if (version != null && version.startsWith("v")) {
return version + " (Official)";
}
else if (SlimefunPlugin.getItemTextureService().isActive()) {
return "Custom / Modified";
}
else {
return "None";
}
});
}
}

View File

@ -1,18 +0,0 @@
package io.github.thebusybiscuit.slimefun4.core.services.metrics;
import org.bstats.bukkit.Metrics.SimplePie;
import io.github.thebusybiscuit.slimefun4.core.services.localization.Language;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
class ServerLanguageChart extends SimplePie {
ServerLanguageChart() {
super("language", () -> {
Language language = SlimefunPlugin.getLocalization().getDefaultLanguage();
boolean supported = SlimefunPlugin.getLocalization().isLanguageLoaded(language.getId());
return supported ? language.getId() : "Unsupported Language";
});
}
}

View File

@ -1,40 +0,0 @@
package io.github.thebusybiscuit.slimefun4.core.services.metrics;
import org.bstats.bukkit.Metrics.SimplePie;
import org.bukkit.Bukkit;
class ServerSizeChart extends SimplePie {
ServerSizeChart() {
super("server_size", () -> {
int players = Bukkit.getOnlinePlayers().size();
if (players < 10) {
return "0-10";
}
if (players < 25) {
return "10-25";
}
if (players < 50) {
return "25-50";
}
if (players < 100) {
return "50-100";
}
if (players < 200) {
return "100-200";
}
if (players < 300) {
return "200-300";
}
return "300+";
});
}
}

View File

@ -1,24 +0,0 @@
package io.github.thebusybiscuit.slimefun4.core.services.metrics;
import java.util.HashMap;
import java.util.Map;
import org.bstats.bukkit.Metrics.DrilldownPie;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
class SlimefunVersionChart extends DrilldownPie {
SlimefunVersionChart() {
super("slimefun_version", () -> {
Map<String, Map<String, Integer>> outerMap = new HashMap<>();
Map<String, Integer> innerMap = new HashMap<>();
innerMap.put(SlimefunPlugin.getVersion(), 1);
outerMap.put(SlimefunPlugin.getUpdater().getBranch().getName(), innerMap);
return outerMap;
});
}
}

View File

@ -1,4 +0,0 @@
/**
* This package contains everything related to bStats Metrics
*/
package io.github.thebusybiscuit.slimefun4.core.services.metrics;

View File

@ -16,7 +16,7 @@ class PlaceholderAPIHook extends PlaceholderExpansion {
@Override
public String getAuthor() {
return SlimefunPlugin.instance.getDescription().getAuthors().toString();
return SlimefunPlugin.instance().getDescription().getAuthors().toString();
}
@Override
@ -26,7 +26,7 @@ class PlaceholderAPIHook extends PlaceholderExpansion {
@Override
public String getVersion() {
return SlimefunPlugin.instance.getDescription().getVersion();
return SlimefunPlugin.instance().getDescription().getVersion();
}
@Override

View File

@ -17,23 +17,22 @@ import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.chat.hover.content.Content;
import net.md_5.bungee.api.chat.hover.content.Text;
class PerformanceSummary {
// The threshold at which a Block or Chunk is significant enough to appear in /sf timings
private static final int VISIBILITY_THRESHOLD = 280_000;
private static final int MIN_ITEMS = 3;
private static final int MAX_ITEMS = 10;
// A minecraft server tick is 50ms and Slimefun ticks are stretched across
// two ticks (sync and async blocks), so we use 100ms as a reference here
static final int MAX_TICK_DURATION = 100;
private static final int VISIBILITY_THRESHOLD = 300_000;
private static final int MIN_ITEMS = 4;
private static final int MAX_ITEMS = 12;
private final SlimefunProfiler profiler;
private final PerformanceRating rating;
private final long totalElapsedTime;
private final int totalTickedBlocks;
private final float percentage;
private final int tickRate;
private final Map<String, Long> chunks;
private final Map<String, Long> plugins;
@ -45,6 +44,7 @@ class PerformanceSummary {
this.percentage = profiler.getPercentageOfTick();
this.totalElapsedTime = totalElapsedTime;
this.totalTickedBlocks = totalTickedBlocks;
this.tickRate = profiler.getTickRate();
chunks = profiler.getByChunk();
plugins = profiler.getByPlugin();
@ -54,7 +54,8 @@ class PerformanceSummary {
public void send(CommandSender sender) {
sender.sendMessage("");
sender.sendMessage(ChatColor.GREEN + "===== Slimefun Lag Profiler =====");
sender.sendMessage(ChatColor.GOLD + "Total: " + ChatColor.YELLOW + NumberUtils.getAsMillis(totalElapsedTime));
sender.sendMessage(ChatColor.GOLD + "Total time: " + ChatColor.YELLOW + NumberUtils.getAsMillis(totalElapsedTime));
sender.sendMessage(ChatColor.GOLD + "Running every: " + ChatColor.YELLOW + NumberUtils.roundDecimalNumber(tickRate / 20.0) + "s (" + tickRate + " ticks)");
sender.sendMessage(ChatColor.GOLD + "Performance: " + getPerformanceRating());
sender.sendMessage("");
@ -128,7 +129,8 @@ class PerformanceSummary {
builder.append("\n\n&c+ &6").append(hidden).append(" more");
}
hoverComponent.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.fromLegacyText(ChatColors.color(builder.toString()))));
Content content = new Text(TextComponent.fromLegacyText(ChatColors.color(builder.toString())));
hoverComponent.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, content));
component.addExtra(hoverComponent);
}

View File

@ -1,5 +1,6 @@
package io.github.thebusybiscuit.slimefun4.core.services.profiler;
import org.bukkit.Location;
import org.bukkit.block.Block;
import io.github.thebusybiscuit.cscorelib2.blocks.BlockPosition;
@ -11,6 +12,11 @@ class ProfiledBlock {
private final BlockPosition position;
private final SlimefunItem item;
ProfiledBlock(Location l, SlimefunItem item) {
this.position = new BlockPosition(l);
this.item = item;
}
ProfiledBlock(BlockPosition position, SlimefunItem item) {
this.position = position;
this.item = item;

View File

@ -19,7 +19,6 @@ import org.bukkit.Server;
import org.bukkit.block.Block;
import org.bukkit.command.CommandSender;
import io.github.thebusybiscuit.cscorelib2.blocks.BlockPosition;
import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.TickerTask;
@ -41,7 +40,11 @@ import me.mrCookieSlime.Slimefun.api.Slimefun;
*/
public class SlimefunProfiler {
private final ExecutorService executor = Executors.newFixedThreadPool(3);
// A minecraft server tick is 50ms and Slimefun ticks are stretched across
// two ticks (sync and async blocks), so we use 100ms as a reference here
private static final int MAX_TICK_DURATION = 100;
private final ExecutorService executor = Executors.newFixedThreadPool(4);
private final AtomicBoolean running = new AtomicBoolean(false);
private final AtomicInteger queued = new AtomicInteger(0);
@ -78,8 +81,10 @@ public class SlimefunProfiler {
* Be careful to {@link #closeEntry(Location, SlimefunItem, long)} all of them again!
* No {@link PerformanceSummary} will be sent until all entires were closed.
*
* If the specified amount is negative, scheduled entries will be removed
*
* @param amount
* The amount of entries that should be scheduled.
* The amount of entries that should be scheduled. Can be negative
*/
public void scheduleEntries(int amount) {
if (running.get()) {
@ -111,8 +116,9 @@ public class SlimefunProfiler {
long elapsedTime = System.nanoTime() - timestamp;
executor.execute(() -> {
ProfiledBlock block = new ProfiledBlock(new BlockPosition(l), item);
timings.put(block, elapsedTime);
ProfiledBlock block = new ProfiledBlock(l, item);
timings.putIfAbsent(block, elapsedTime);
queued.decrementAndGet();
});
@ -125,43 +131,53 @@ public class SlimefunProfiler {
public void stop() {
running.set(false);
if (SlimefunPlugin.instance == null || !SlimefunPlugin.instance.isEnabled()) {
if (SlimefunPlugin.instance() == null || !SlimefunPlugin.instance().isEnabled()) {
// Slimefun has been disabled
return;
}
// Since we got more than one Thread in our pool, blocking this one is completely fine
executor.execute(() -> {
// Since we got more than one Thread in our pool,
// blocking this one is (hopefully) completely fine
executor.execute(this::finishReport);
}
// Wait for all timing results to come in
while (queued.get() > 0 && !running.get()) {
try {
Thread.sleep(1);
}
catch (InterruptedException e) {
Slimefun.getLogger().log(Level.SEVERE, "A waiting Thread was interrupted", e);
Thread.currentThread().interrupt();
private void finishReport() {
// We will only wait for a maximum of this many 1ms sleeps
int iterations = 1000;
// Wait for all timing results to come in
while (!running.get() && queued.get() > 0) {
try {
Thread.sleep(1);
iterations--;
// If we waited for too long, then we should just abort
if (iterations <= 0) {
return;
}
}
if (running.get()) {
// Looks like the next profiling has already started, abort!
return;
catch (InterruptedException e) {
Slimefun.getLogger().log(Level.SEVERE, "A Profiler Thread was interrupted", e);
Thread.currentThread().interrupt();
}
}
totalElapsedTime = timings.values().stream().mapToLong(Long::longValue).sum();
if (running.get() && queued.get() > 0) {
// Looks like the next profiling has already started, abort!
return;
}
if (!requests.isEmpty()) {
PerformanceSummary summary = new PerformanceSummary(this, totalElapsedTime, timings.size());
Iterator<CommandSender> iterator = requests.iterator();
totalElapsedTime = timings.values().stream().mapToLong(Long::longValue).sum();
while (iterator.hasNext()) {
summary.send(iterator.next());
iterator.remove();
}
if (!requests.isEmpty()) {
PerformanceSummary summary = new PerformanceSummary(this, totalElapsedTime, timings.size());
Iterator<CommandSender> iterator = requests.iterator();
while (iterator.hasNext()) {
summary.send(iterator.next());
iterator.remove();
}
});
}
}
/**
@ -253,7 +269,7 @@ public class SlimefunProfiler {
protected float getPercentageOfTick() {
float millis = totalElapsedTime / 1000000.0F;
float fraction = (millis * 100.0F) / PerformanceSummary.MAX_TICK_DURATION;
float fraction = (millis * 100.0F) / MAX_TICK_DURATION;
return Math.round((fraction * 100.0F) / 100.0F);
}
@ -278,6 +294,10 @@ public class SlimefunProfiler {
return NumberUtils.getAsMillis(totalElapsedTime);
}
public int getTickRate() {
return SlimefunPlugin.getTickerTask().getTickRate();
}
/**
* This method checks whether the {@link SlimefunProfiler} has collected timings on
* the given {@link Block}

View File

@ -44,6 +44,7 @@ public final class SlimefunItems {
public static final SlimefunItemStack BROKEN_SPAWNER = new SlimefunItemStack("BROKEN_SPAWNER", Material.SPAWNER, "&cBroken Spawner", "&7Type: &b<Type>", "", "&cFractured, must be repaired in an Ancient Altar");
public static final SlimefunItemStack REPAIRED_SPAWNER = new SlimefunItemStack("REINFORCED_SPAWNER", Material.SPAWNER, "&bReinforced Spawner", "&7Type: &b<Type>");
public static final SlimefunItemStack INFERNAL_BONEMEAL = new SlimefunItemStack("INFERNAL_BONEMEAL", Material.BONE_MEAL, "&4Infernal Bonemeal", "", "&cSpeeds up the Growth of", "&cNether Warts as well");
public static final SlimefunItemStack TAPE_MEASURE = new SlimefunItemStack("TAPE_MEASURE", "180d5c43a6cf5bb7769fd0c8240e1e70d2ae38ef9d78a1db401aca6a2cb36f65", "&6Tape Measure", "", "&eCrouch & Right Click &7to set an anchor", "&eRight Click &7to measure");
/* Gadgets */
public static final SlimefunItemStack GOLD_PAN = new SlimefunItemStack("GOLD_PAN", Material.BOWL, "&6Gold Pan", "", "&eRight Click&7 to collect resources", "&7from Gravel");
@ -815,6 +816,7 @@ public final class SlimefunItems {
public static final SlimefunItemStack FLUID_PUMP = new SlimefunItemStack("FLUID_PUMP", Material.BLUE_TERRACOTTA, "&9Fluid Pump", "", LoreBuilder.machine(MachineTier.ADVANCED, MachineType.MACHINE), "&8\u21E8 &e\u26A1 &732 J/Block");
public static final SlimefunItemStack CHARGING_BENCH = new SlimefunItemStack("CHARGING_BENCH", Material.CRAFTING_TABLE, "&6Charging Bench", "", "&fCharges Items such as Jetpacks", "", LoreBuilder.machine(MachineTier.BASIC, MachineType.MACHINE), LoreBuilder.powerBuffer(128), "&8\u21E8 &e\u26A1 &7Energy Loss: &c50%");
public static final SlimefunItemStack IRON_GOLEM_ASSEMBLER = new SlimefunItemStack("IRON_GOLEM_ASSEMBLER", Material.IRON_BLOCK, "&6Iron Golem Assembler", "", LoreBuilder.machine(MachineTier.END_GAME, MachineType.MACHINE), "&8\u21E8 &7Cooldown: &b30 Seconds", LoreBuilder.powerBuffer(4096), "&8\u21E8 &e\u26A1 &72048 J/Golem");
public static final SlimefunItemStack WITHER_ASSEMBLER = new SlimefunItemStack("WITHER_ASSEMBLER", Material.OBSIDIAN, "&5Wither Assembler", "", LoreBuilder.machine(MachineTier.END_GAME, MachineType.MACHINE), "&8\u21E8 &7Cooldown: &b30 Seconds", LoreBuilder.powerBuffer(4096), "&8\u21E8 &e\u26A1 &74096 J/Wither");
public static final SlimefunItemStack TRASH_CAN = new SlimefunItemStack("TRASH_CAN_BLOCK", HeadTexture.TRASH_CAN, "&3Trash Can", "", "&fWill destroy all Items put into it");

View File

@ -41,12 +41,11 @@ import io.github.thebusybiscuit.slimefun4.core.services.PerWorldSettingsService;
import io.github.thebusybiscuit.slimefun4.core.services.PermissionsService;
import io.github.thebusybiscuit.slimefun4.core.services.UpdaterService;
import io.github.thebusybiscuit.slimefun4.core.services.github.GitHubService;
import io.github.thebusybiscuit.slimefun4.core.services.metrics.MetricsService;
import io.github.thebusybiscuit.slimefun4.core.services.MetricsService;
import io.github.thebusybiscuit.slimefun4.core.services.plugins.ThirdPartyPluginService;
import io.github.thebusybiscuit.slimefun4.core.services.profiler.SlimefunProfiler;
import io.github.thebusybiscuit.slimefun4.implementation.items.altar.AncientAltar;
import io.github.thebusybiscuit.slimefun4.implementation.items.backpacks.Cooler;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.BasicCircuitBoard;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.reactors.Reactor;
import io.github.thebusybiscuit.slimefun4.implementation.items.tools.GrapplingHook;
import io.github.thebusybiscuit.slimefun4.implementation.items.weapons.SeismicAxe;
@ -91,6 +90,7 @@ 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.papermc.lib.PaperLib;
import me.mrCookieSlime.CSCoreLibPlugin.CSCoreLib;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AContainer;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AGenerator;
@ -107,7 +107,7 @@ import me.mrCookieSlime.Slimefun.api.inventory.UniversalBlockMenu;
*/
public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
public static SlimefunPlugin instance;
private static SlimefunPlugin instance;
private MinecraftVersion minecraftVersion = MinecraftVersion.UNKNOWN;
@ -166,6 +166,8 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
}
else if (getServer().getPluginManager().isPluginEnabled("CS-CoreLib")) {
long timestamp = System.nanoTime();
PaperLib.suggestPaper(this);
// We wanna ensure that the Server uses a compatible version of Minecraft
if (isVersionUnsupported()) {
@ -195,7 +197,7 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
networkManager = new NetworkManager(networkSize);
// Setting up bStats
metricsService.start();
new Thread(metricsService::start).start();
// Starting the Auto-Updater
if (config.getBoolean("options.auto-update")) {
@ -331,7 +333,7 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
@Override
public void onDisable() {
// Slimefun never loaded successfully, so we don't even bother doing stuff here
if (instance == null || minecraftVersion == MinecraftVersion.UNIT_TEST) {
if (instance() == null || minecraftVersion == MinecraftVersion.UNIT_TEST) {
return;
}
@ -366,6 +368,8 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
// Create a new backup zip
backupService.run();
metricsService.cleanUp();
// Prevent Memory Leaks
// These static Maps should be removed at some point...
AContainer.processing = null;
@ -432,7 +436,7 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
new BeeListener(this);
}
new MobDropListener(this, (BasicCircuitBoard) SlimefunItems.BASIC_CIRCUIT_BOARD.getItem());
new MobDropListener(this);
// Item-specific Listeners
new VampireBladeListener(this, (VampireBlade) SlimefunItems.BLADE_OF_VAMPIRES.getItem());
@ -484,6 +488,10 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
}
}
public static SlimefunPlugin instance() {
return instance;
}
public static Config getCfg() {
return instance.config;
}
@ -564,6 +572,16 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
return instance.updaterService;
}
/**
* This method returns the {@link MetricsService} of Slimefun.
* It is used to handle sending metric information to bStats.
*
* @return The {@link MetricsService} for Slimefun
*/
public static MetricsService getMetricsService() {
return instance.metricsService;
}
/**
* This method returns the {@link GitHubService} of Slimefun.
* It is used to retrieve data from GitHub repositories.

View File

@ -35,7 +35,7 @@ import me.mrCookieSlime.Slimefun.api.Slimefun;
public class BookSlimefunGuide implements SlimefunGuideImplementation {
private final NamespacedKey guideSearch = new NamespacedKey(SlimefunPlugin.instance, "search");
private final NamespacedKey guideSearch = new NamespacedKey(SlimefunPlugin.instance(), "search");
@Override
public SlimefunGuideLayout getLayout() {
@ -53,7 +53,7 @@ public class BookSlimefunGuide implements SlimefunGuideImplementation {
}
private void openBook(Player p, PlayerProfile profile, List<ChatComponent> lines, boolean backButton) {
CustomBookInterface book = new CustomBookInterface(SlimefunPlugin.instance);
CustomBookInterface book = new CustomBookInterface(SlimefunPlugin.instance());
book.setTitle(SlimefunPlugin.getLocalization().getMessage(p, "guide.title.main"));
for (int i = 0; i < lines.size(); i = i + 10) {
@ -63,7 +63,7 @@ public class BookSlimefunGuide implements SlimefunGuideImplementation {
header.setClickEvent(new ClickEvent(guideSearch, player -> Slimefun.runSync(() -> {
SlimefunPlugin.getLocalization().sendMessage(player, "guide.search.message");
ChatInput.waitForPlayer(SlimefunPlugin.instance, player, msg -> SlimefunGuide.openSearch(profile, msg, true, true));
ChatInput.waitForPlayer(SlimefunPlugin.instance(), player, msg -> SlimefunGuide.openSearch(profile, msg, true, true));
}, 1)));
page.append(header);
@ -77,7 +77,7 @@ public class BookSlimefunGuide implements SlimefunGuideImplementation {
if (backButton) {
ChatComponent button = new ChatComponent(ChatColor.DARK_BLUE + "\u21E6 " + SlimefunPlugin.getLocalization().getMessage(p, "guide.back.title"));
button.setHoverEvent(new HoverEvent(ChatColor.DARK_BLUE + "\u21E6 " + SlimefunPlugin.getLocalization().getMessage(p, "guide.back.title"), "", ChatColor.GRAY + SlimefunPlugin.getLocalization().getMessage(p, "guide.back.guide")));
button.setClickEvent(new ClickEvent(new NamespacedKey(SlimefunPlugin.instance, "slimefun_guide"), pl -> openMainMenu(profile, 1)));
button.setClickEvent(new ClickEvent(new NamespacedKey(SlimefunPlugin.instance(), "slimefun_guide"), pl -> openMainMenu(profile, 1)));
page.append(button);
}
@ -189,7 +189,7 @@ public class BookSlimefunGuide implements SlimefunGuideImplementation {
}
private void appendSlimefunItem(Category category, int page, Player p, PlayerProfile profile, SlimefunItem item, List<ChatComponent> items) {
NamespacedKey key = new NamespacedKey(SlimefunPlugin.instance, item.getID().toLowerCase(Locale.ROOT));
NamespacedKey key = new NamespacedKey(SlimefunPlugin.instance(), item.getID().toLowerCase(Locale.ROOT));
if (!Slimefun.hasUnlocked(p, item, false) && item.getResearch() != null) {
Research research = item.getResearch();

View File

@ -561,7 +561,7 @@ public class ChestSlimefunGuide implements SlimefunGuideImplementation {
pl.closeInventory();
SlimefunPlugin.getLocalization().sendMessage(pl, "guide.search.message");
ChatInput.waitForPlayer(SlimefunPlugin.instance, pl, msg -> SlimefunGuide.openSearch(profile, msg, isSurvivalMode(), isSurvivalMode()));
ChatInput.waitForPlayer(SlimefunPlugin.instance(), pl, msg -> SlimefunGuide.openSearch(profile, msg, isSurvivalMode(), isSurvivalMode()));
return false;
});

View File

@ -31,7 +31,7 @@ class RecipeChoiceTask implements Runnable {
private Inventory inventory;
private int id;
private Map<Integer, LoopIterator<Material>> iterators = new HashMap<>();
private final Map<Integer, LoopIterator<Material>> iterators = new HashMap<>();
/**
* This will start this task for the given {@link Inventory}.
@ -42,7 +42,7 @@ class RecipeChoiceTask implements Runnable {
public void start(Inventory inv) {
Validate.notNull(inv, "Inventory must not be null");
inventory = inv;
id = Bukkit.getScheduler().runTaskTimerAsynchronously(SlimefunPlugin.instance, this, 0, UPDATE_INTERVAL).getTaskId();
id = Bukkit.getScheduler().runTaskTimerAsynchronously(SlimefunPlugin.instance(), this, 0, UPDATE_INTERVAL).getTaskId();
}
public void add(int slot, MaterialChoice choice) {

View File

@ -1,10 +1,11 @@
package me.mrCookieSlime.Slimefun.Objects.SlimefunItem;
package io.github.thebusybiscuit.slimefun4.implementation.items;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.handlers.ItemHandler;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;

View File

@ -20,7 +20,7 @@ public class AncientPedestal extends SlimefunItem {
Item stack = listener.findItem(b);
if (stack != null) {
stack.removeMetadata("no_pickup", SlimefunPlugin.instance);
stack.removeMetadata("no_pickup", SlimefunPlugin.instance());
b.getWorld().dropItem(b.getLocation(), listener.fixItemStack(stack.getItemStack(), stack.getCustomName()));
stack.remove();
}

View File

@ -14,7 +14,6 @@ import org.bukkit.metadata.FixedMetadataValue;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
public abstract class ButcherAndroid extends ProgrammableAndroid {
@ -31,14 +30,14 @@ public abstract class ButcherAndroid extends ProgrammableAndroid {
}
@Override
protected void attack(Block b, Predicate<LivingEntity> predicate) {
protected void attack(Block b, BlockFace face, Predicate<LivingEntity> predicate) {
double damage = getTier() >= 3 ? 20D : 4D * getTier();
double radius = 4.0 + getTier();
for (Entity n : b.getWorld().getNearbyEntities(b.getLocation(), radius, radius, radius, n -> n instanceof LivingEntity && !(n instanceof ArmorStand) && !(n instanceof Player) && n.isValid() && predicate.test((LivingEntity) n))) {
boolean attack = false;
switch (BlockFace.valueOf(BlockStorage.getLocationInfo(b.getLocation(), "rotation"))) {
switch (face) {
case NORTH:
attack = n.getLocation().getZ() < b.getZ();
break;
@ -57,10 +56,10 @@ public abstract class ButcherAndroid extends ProgrammableAndroid {
if (attack) {
if (n.hasMetadata(METADATA_KEY)) {
n.removeMetadata(METADATA_KEY, SlimefunPlugin.instance);
n.removeMetadata(METADATA_KEY, SlimefunPlugin.instance());
}
n.setMetadata(METADATA_KEY, new FixedMetadataValue(SlimefunPlugin.instance, new AndroidInstance(this, b)));
n.setMetadata(METADATA_KEY, new FixedMetadataValue(SlimefunPlugin.instance(), new AndroidInstance(this, b)));
((LivingEntity) n).damage(damage);
break;

View File

@ -83,22 +83,22 @@ enum Instruction {
// Action - Sword
ATTACK_MOBS_ANIMALS(AndroidType.FIGHTER, HeadTexture.SCRIPT_ATTACK, (android, b, inv, face) -> {
Predicate<LivingEntity> predicate = e -> true;
android.attack(b, predicate);
android.attack(b, face, predicate);
}),
ATTACK_MOBS(AndroidType.FIGHTER, HeadTexture.SCRIPT_ATTACK, (android, b, inv, face) -> {
Predicate<LivingEntity> predicate = e -> e instanceof Monster;
android.attack(b, predicate);
android.attack(b, face, predicate);
}),
ATTACK_ANIMALS(AndroidType.FIGHTER, HeadTexture.SCRIPT_ATTACK, (android, b, inv, face) -> {
Predicate<LivingEntity> predicate = e -> e instanceof Animals;
android.attack(b, predicate);
android.attack(b, face, predicate);
}),
ATTACK_ANIMALS_ADULT(AndroidType.FIGHTER, HeadTexture.SCRIPT_ATTACK, (android, b, inv, face) -> {
Predicate<LivingEntity> predicate = e -> e instanceof Animals && e instanceof Ageable && ((Ageable) e).isAdult();
android.attack(b, predicate);
android.attack(b, face, predicate);
}),
// Action - Axe

View File

@ -14,6 +14,7 @@ import org.bukkit.Sound;
import org.bukkit.Tag;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.block.Dispenser;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Rotatable;
@ -36,6 +37,7 @@ import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
import io.github.thebusybiscuit.slimefun4.utils.PatternUtils;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import io.papermc.lib.PaperLib;
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu;
import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu.AdvancedMenuClickHandler;
@ -441,7 +443,7 @@ public abstract class ProgrammableAndroid extends SlimefunItem implements Invent
SlimefunPlugin.getLocalization().sendMessages(p, "android.scripts.enter-name");
int id = nextId;
ChatInput.waitForPlayer(SlimefunPlugin.instance, p, msg -> {
ChatInput.waitForPlayer(SlimefunPlugin.instance(), p, msg -> {
Script.upload(p, getAndroidType(), id, msg, code);
SlimefunPlugin.getLocalization().sendMessages(p, "android.scripts.uploaded");
openScriptDownloader(p, b, page);
@ -532,7 +534,7 @@ public abstract class ProgrammableAndroid extends SlimefunItem implements Invent
private void registerDefaultFuelTypes() {
switch (getFuelSource()) {
case SOLID:
registerFuelType(new MachineFuel(800, new ItemStack(Material.COAL_BLOCK)));
registerFuelType(new MachineFuel(80, new ItemStack(Material.COAL_BLOCK)));
registerFuelType(new MachineFuel(45, new ItemStack(Material.BLAZE_ROD)));
registerFuelType(new MachineFuel(70, new ItemStack(Material.DRIED_KELP_BLOCK)));
@ -689,19 +691,23 @@ public abstract class ProgrammableAndroid extends SlimefunItem implements Invent
protected void depositItems(BlockMenu menu, Block facedBlock) {
if (facedBlock.getType() == Material.DISPENSER && BlockStorage.check(facedBlock, "ANDROID_INTERFACE_ITEMS")) {
Dispenser d = (Dispenser) facedBlock.getState();
BlockState state = PaperLib.getBlockState(facedBlock, false).getState();
for (int slot : getOutputSlots()) {
ItemStack stack = menu.getItemInSlot(slot);
if (state instanceof Dispenser) {
Dispenser d = (Dispenser) state;
if (stack != null) {
Optional<ItemStack> optional = d.getInventory().addItem(stack).values().stream().findFirst();
for (int slot : getOutputSlots()) {
ItemStack stack = menu.getItemInSlot(slot);
if (optional.isPresent()) {
menu.replaceExistingItem(slot, optional.get());
}
else {
menu.replaceExistingItem(slot, null);
if (stack != null) {
Optional<ItemStack> optional = d.getInventory().addItem(stack).values().stream().findFirst();
if (optional.isPresent()) {
menu.replaceExistingItem(slot, optional.get());
}
else {
menu.replaceExistingItem(slot, null);
}
}
}
}
@ -710,13 +716,17 @@ public abstract class ProgrammableAndroid extends SlimefunItem implements Invent
protected void refuel(BlockMenu menu, Block facedBlock) {
if (facedBlock.getType() == Material.DISPENSER && BlockStorage.check(facedBlock, "ANDROID_INTERFACE_FUEL")) {
Dispenser d = (Dispenser) facedBlock.getState();
BlockState state = PaperLib.getBlockState(facedBlock, false).getState();
for (int slot = 0; slot < 9; slot++) {
ItemStack item = d.getInventory().getItem(slot);
if (state instanceof Dispenser) {
Dispenser d = (Dispenser) state;
if (item != null) {
insertFuel(menu, d.getInventory(), slot, menu.getItemInSlot(43), item);
for (int slot = 0; slot < 9; slot++) {
ItemStack item = d.getInventory().getItem(slot);
if (item != null) {
insertFuel(menu, d.getInventory(), slot, menu.getItemInSlot(43), item);
}
}
}
}
@ -814,7 +824,7 @@ public abstract class ProgrammableAndroid extends SlimefunItem implements Invent
}
}
protected void attack(Block b, Predicate<LivingEntity> predicate) {
protected void attack(Block b, BlockFace face, Predicate<LivingEntity> predicate) {
throw new UnsupportedOperationException("Non-butcher Android tried to butcher!");
}

View File

@ -69,9 +69,7 @@ public abstract class WoodcutterAndroid extends ProgrammableAndroid {
if (log.getY() == android.getRelative(face).getY()) {
Optional<Material> sapling = MaterialConverter.getSaplingFromLog(log.getType());
if (sapling.isPresent()) {
log.setType(sapling.get());
}
sapling.ifPresent(log::setType);
}
else {
log.setType(Material.AIR);

View File

@ -30,7 +30,7 @@ public class HazmatArmorPiece extends SlimefunArmorPiece implements ProtectiveAr
super(category, item, recipeType, recipe, effects);
types = new ProtectionType[] { ProtectionType.BEES, ProtectionType.RADIATION };
namespacedKey = new NamespacedKey(SlimefunPlugin.instance, "hazmat_suit");
namespacedKey = new NamespacedKey(SlimefunPlugin.instance(), "hazmat_suit");
}
@Override

View File

@ -6,9 +6,9 @@ import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.core.attributes.NotPlaceable;
import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
public class EnderBackpack extends SimpleSlimefunItem<ItemUseHandler> implements NotPlaceable {

View File

@ -7,10 +7,10 @@ import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.api.player.PlayerBackpack;
import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.BackpackListener;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;

View File

@ -21,9 +21,9 @@ import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting;
import io.github.thebusybiscuit.slimefun4.core.attributes.NotPlaceable;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockDispenseHandler;
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.Objects.SlimefunItem.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.Slimefun;
@ -31,7 +31,7 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
public class BlockPlacer extends SimpleSlimefunItem<BlockDispenseHandler> {
private ItemSetting<List<String>> blacklist = new ItemSetting<>("unplaceable-blocks", MaterialCollections.getAllUnbreakableBlocks().stream().map(Material::name).collect(Collectors.toList()));
private final ItemSetting<List<String>> blacklist = new ItemSetting<>("unplaceable-blocks", MaterialCollections.getAllUnbreakableBlocks().stream().map(Material::name).collect(Collectors.toList()));
public BlockPlacer(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);

View File

@ -10,6 +10,7 @@ import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.block.Chest;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
@ -22,10 +23,11 @@ import io.github.thebusybiscuit.cscorelib2.scheduling.TaskQueue;
import io.github.thebusybiscuit.slimefun4.core.attributes.RecipeDisplayItem;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockUseHandler;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import io.papermc.lib.PaperLib;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
@ -98,7 +100,7 @@ public class Composter extends SimpleSlimefunItem<BlockUseHandler> implements Re
pushItem(b, output.clone());
});
tasks.execute(SlimefunPlugin.instance);
tasks.execute(SlimefunPlugin.instance());
}
else {
SlimefunPlugin.getLocalization().sendMessage(p, "machines.wrong-item", true);
@ -129,10 +131,14 @@ public class Composter extends SimpleSlimefunItem<BlockUseHandler> implements Re
if (id != null && id.equals("OUTPUT_CHEST")) {
// Found the output chest! Now, let's check if we can fit the product in it.
Inventory inv = ((Chest) potentialOutput.getState()).getInventory();
BlockState state = PaperLib.getBlockState(potentialOutput, false).getState();
if (InvUtils.fits(inv, output)) {
return Optional.of(inv);
if (state instanceof Chest) {
Inventory inv = ((Chest) state).getInventory();
if (InvUtils.fits(inv, output)) {
return Optional.of(inv);
}
}
}
}

View File

@ -19,10 +19,10 @@ import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction;
import io.github.thebusybiscuit.slimefun4.core.attributes.RecipeDisplayItem;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockUseHandler;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;

View File

@ -7,10 +7,10 @@ import org.bukkit.block.Block;
import org.bukkit.block.Furnace;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker;
import me.mrCookieSlime.Slimefun.api.BlockStorage;

View File

@ -0,0 +1,28 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.blocks;
import org.bukkit.entity.Wither;
import org.bukkit.entity.WitherSkull;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.core.attributes.WitherProof;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
/**
* {@link HardenedGlass} is a special kind of block which cannot be destroyed by explosions.
* It is partially {@link WitherProof}, as it cannot be destroyed through explosions caused by
* a {@link WitherSkull}. However the {@link Wither} is still able to destroy it directly.
*
* @author TheBusyBiscuit
*
* @see WitherProofBlock
*
*/
public class HardenedGlass extends WitherProofBlock {
public HardenedGlass(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, ItemStack recipeOutput) {
super(category, item, recipeType, recipe, recipeOutput);
}
}

View File

@ -13,13 +13,13 @@ import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.cscorelib2.math.DoubleHandler;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockUseHandler;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import io.github.thebusybiscuit.slimefun4.utils.ChatUtils;
import io.github.thebusybiscuit.slimefun4.utils.holograms.SimpleHologram;
import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunBlockHandler;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.UnregisterReason;
import me.mrCookieSlime.Slimefun.api.BlockStorage;

View File

@ -10,11 +10,11 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker;
import me.mrCookieSlime.Slimefun.api.BlockStorage;

View File

@ -3,9 +3,9 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.blocks;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.core.handlers.RainbowTickHandler;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
public class RainbowBlock extends SimpleSlimefunItem<RainbowTickHandler> {

View File

@ -10,10 +10,10 @@ import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
public class RepairedSpawner extends SimpleSlimefunItem<BlockPlaceHandler> {

View File

@ -5,9 +5,9 @@ import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.api.events.PlayerRightClickEvent;
import io.github.thebusybiscuit.slimefun4.core.attributes.NotPlaceable;
import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
public class UnplaceableBlock extends SimpleSlimefunItem<ItemUseHandler> implements NotPlaceable {
@ -16,6 +16,10 @@ public class UnplaceableBlock extends SimpleSlimefunItem<ItemUseHandler> impleme
super(category, item, recipeType, recipe);
}
public UnplaceableBlock(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, ItemStack recipeOutput) {
super(category, item, recipeType, recipe, recipeOutput);
}
@Override
public ItemUseHandler getItemHandler() {
return PlayerRightClickEvent::cancel;

View File

@ -7,9 +7,9 @@ import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.chat.ChatColors;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockUseHandler;
import io.github.thebusybiscuit.slimefun4.core.networks.cargo.CargoNet;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
public class CargoConnectorNode extends SimpleSlimefunItem<BlockUseHandler> {

View File

@ -46,8 +46,6 @@ public class CargoManager extends SlimefunItem {
}, new BlockUseHandler() {
private String visualizerKey = "visualizer";
@Override
public void onRightClick(PlayerRightClickEvent e) {
Optional<Block> block = e.getClickedBlock();
@ -56,12 +54,12 @@ public class CargoManager extends SlimefunItem {
Player p = e.getPlayer();
Block b = block.get();
if (BlockStorage.getLocationInfo(b.getLocation(), visualizerKey) == null) {
BlockStorage.addBlockInfo(b, visualizerKey, "disabled");
if (BlockStorage.getLocationInfo(b.getLocation(), "visualizer") == null) {
BlockStorage.addBlockInfo(b, "visualizer", "disabled");
p.sendMessage(ChatColor.translateAlternateColorCodes('&', "&cCargo Net Visualizer: " + "&4\u2718"));
}
else {
BlockStorage.addBlockInfo(b, visualizerKey, null);
BlockStorage.addBlockInfo(b, "visualizer", null);
p.sendMessage(ChatColor.translateAlternateColorCodes('&', "&cCargo Net Visualizer: " + "&2\u2714"));
}
}

View File

@ -11,8 +11,8 @@ import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.reactors.Reactor;
import io.github.thebusybiscuit.slimefun4.implementation.items.misc.CoolantCell;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
@ -74,18 +74,27 @@ public class ReactorAccessPort extends SlimefunItem {
@Override
public int[] getSlotsAccessedByItemTransport(ItemTransportFlow flow) {
if (flow == ItemTransportFlow.INSERT) return getInputSlots();
else return getOutputSlots();
if (flow == ItemTransportFlow.INSERT) {
return getInputSlots();
}
else {
return getOutputSlots();
}
}
@Override
public int[] getSlotsAccessedByItemTransport(DirtyChestMenu menu, ItemTransportFlow flow, ItemStack item) {
if (flow == ItemTransportFlow.INSERT) {
if (SlimefunUtils.isItemSimilar(item, SlimefunItems.REACTOR_COOLANT_CELL, true)) return getCoolantSlots();
else if (SlimefunUtils.isItemSimilar(item, SlimefunItems.NETHER_ICE_COOLANT_CELL, true)) return getCoolantSlots();
else return getFuelSlots();
if (SlimefunItem.getByItem(item) instanceof CoolantCell) {
return getCoolantSlots();
}
else {
return getFuelSlots();
}
}
else {
return getOutputSlots();
}
else return getOutputSlots();
}
};
@ -157,12 +166,11 @@ public class ReactorAccessPort extends SlimefunItem {
}
private BlockMenu getReactor(Location l) {
Location reactorL = new Location(l.getWorld(), l.getX(), l.getY() - 3, l.getZ());
SlimefunItem item = BlockStorage.check(reactorL.getBlock());
Location location = new Location(l.getWorld(), l.getX(), l.getY() - 3, l.getZ());
SlimefunItem item = BlockStorage.check(location.getBlock());
if (item instanceof Reactor) {
return BlockStorage.getInventory(reactorL);
return BlockStorage.getInventory(location);
}
return null;

View File

@ -5,17 +5,19 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.bukkit.Location;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import io.github.thebusybiscuit.cscorelib2.chat.ChatColors;
import io.github.thebusybiscuit.cscorelib2.math.DoubleHandler;
import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent;
import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetProvider;
import io.github.thebusybiscuit.slimefun4.core.attributes.RecipeDisplayItem;
import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNetComponentType;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.reactors.Reactor;
import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
@ -34,7 +36,7 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
* @see Reactor
*
*/
public abstract class AbstractEnergyProvider extends SlimefunItem implements InventoryBlock, RecipeDisplayItem, EnergyNetComponent {
public abstract class AbstractEnergyProvider extends SlimefunItem implements InventoryBlock, RecipeDisplayItem, EnergyNetProvider {
protected final Set<MachineFuel> fuelTypes = new HashSet<>();
@ -79,13 +81,48 @@ public abstract class AbstractEnergyProvider extends SlimefunItem implements Inv
return EnergyNetComponentType.GENERATOR;
}
protected abstract GeneratorTicker onTick();
/**
* @deprecated Please implement the methods
* {@link #getGeneratedOutput(org.bukkit.Location, me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config)}
* and {@link #willExplode(org.bukkit.Location, me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config)}
* instead
*
* @return A {@link GeneratorTicker}
*/
@Deprecated
protected GeneratorTicker onTick() {
return null;
}
@Override
public int getGeneratedOutput(Location l, Config data) {
if (generatorTicker != null) {
return (int) generatorTicker.generateEnergy(l, this, data);
}
else {
return 0;
}
}
@Override
public boolean willExplode(Location l, Config data) {
if (generatorTicker != null) {
return generatorTicker.explode(l);
}
else {
return false;
}
}
@Override
public void preRegister() {
super.preRegister();
addItemHandler(onTick());
GeneratorTicker ticker = onTick();
if (ticker != null) {
addItemHandler(ticker);
}
}
public void registerFuel(MachineFuel fuel) {

View File

@ -9,9 +9,9 @@ import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.math.DoubleHandler;
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.Objects.SlimefunItem.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
import me.mrCookieSlime.Slimefun.api.energy.ChargableBlock;

View File

@ -6,23 +6,25 @@ import org.bukkit.World.Environment;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.api.events.PlayerRightClickEvent;
import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent;
import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetProvider;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockUseHandler;
import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNetComponentType;
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.handlers.GeneratorTicker;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
public abstract class SolarGenerator extends SimpleSlimefunItem<GeneratorTicker> implements EnergyNetComponent {
public class SolarGenerator extends SlimefunItem implements EnergyNetProvider {
private static final int DEFAULT_NIGHT_ENERGY = 0;
private final int dayEnergy;
private final int nightEnergy;
public SolarGenerator(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
public SolarGenerator(Category category, int dayEnergy, int nightEnergy, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
this.dayEnergy = dayEnergy;
this.nightEnergy = nightEnergy;
}
/**
@ -31,19 +33,18 @@ public abstract class SolarGenerator extends SimpleSlimefunItem<GeneratorTicker>
*
* @return The amount of energy generated at daylight
*/
public abstract double getDayEnergy();
public int getDayEnergy() {
return dayEnergy;
}
/**
* This method returns the amount of energy that this {@link SolarGenerator}
* produces during the night.
*
* This is 0 by default.
*
* @return The amount of energy generated at night time
*/
public double getNightEnergy() {
// Override this as necessary for highly advanced Solar Generators
return DEFAULT_NIGHT_ENERGY;
public int getNightEnergy() {
return nightEnergy;
}
@Override
@ -57,40 +58,29 @@ public abstract class SolarGenerator extends SimpleSlimefunItem<GeneratorTicker>
}
@Override
public GeneratorTicker getItemHandler() {
return new GeneratorTicker() {
public int getGeneratedOutput(Location l, Config data) {
World world = l.getWorld();
@Override
public double generateEnergy(Location l, SlimefunItem item, Config data) {
World world = l.getWorld();
if (world.getEnvironment() != Environment.NORMAL) {
return 0;
}
if (world.getEnvironment() != Environment.NORMAL) {
return 0;
}
boolean isDaytime = isDaytime(world);
boolean isDaytime = isDaytime(world);
// Performance optimization for daytime-only solar generators
if (!isDaytime && getNightEnergy() < 0.1) {
return 0;
}
// Performance optimization for daytime-only solar generators
if (!isDaytime && getNightEnergy() < 0.1) {
return 0;
}
if (!world.isChunkLoaded(l.getBlockX() >> 4, l.getBlockZ() >> 4) || l.getBlock().getLightFromSky() != 15) {
return 0;
}
if (!world.isChunkLoaded(l.getBlockX() >> 4, l.getBlockZ() >> 4) || l.getBlock().getLightFromSky() != 15) {
return 0;
}
if (isDaytime) {
return getDayEnergy();
}
if (isDaytime) {
return getDayEnergy();
}
return getNightEnergy();
}
@Override
public boolean explode(Location l) {
return false;
}
};
return getNightEnergy();
}
/**

View File

@ -0,0 +1,293 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.cscorelib2.math.DoubleHandler;
import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction;
import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent;
import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNetComponentType;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunBlockHandler;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.UnregisterReason;
import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
import me.mrCookieSlime.Slimefun.api.energy.ChargableBlock;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenuPreset;
import me.mrCookieSlime.Slimefun.api.inventory.DirtyChestMenu;
import me.mrCookieSlime.Slimefun.api.item_transport.ItemTransportFlow;
/**
* This is an abstract super class for Entity Assemblers.
*
* @author TheBusyBiscuit
*
* @see WitherAssembler
* @see IronGolemAssembler
*
*/
public abstract class AbstractEntityAssembler extends SimpleSlimefunItem<BlockTicker> implements EnergyNetComponent {
private final int[] border = { 0, 2, 3, 4, 5, 6, 8, 12, 14, 21, 23, 30, 32, 39, 40, 41 };
private final int[] inputSlots = { 19, 28, 25, 34 };
private final int[] headSlots = { 19, 28 };
private final int[] headBorder = { 9, 10, 11, 18, 20, 27, 29, 36, 37, 38 };
private final int[] bodySlots = { 25, 34 };
private final int[] bodyBorder = { 15, 16, 17, 24, 26, 33, 35, 42, 43, 44 };
private int lifetime = 0;
public AbstractEntityAssembler(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
new BlockMenuPreset(getID(), item.getImmutableMeta().getDisplayName().orElse("Entity Assembler")) {
@Override
public void init() {
for (int i : border) {
addItem(i, ChestMenuUtils.getBackground(), ChestMenuUtils.getEmptyClickHandler());
}
for (int i : headBorder) {
addItem(i, new CustomItem(getHeadBorder(), " "), ChestMenuUtils.getEmptyClickHandler());
}
for (int i : bodyBorder) {
addItem(i, new CustomItem(getBodyBorder(), " "), ChestMenuUtils.getEmptyClickHandler());
}
constructMenu(this);
}
@Override
public void newInstance(BlockMenu menu, Block b) {
if (!BlockStorage.hasBlockInfo(b) || BlockStorage.getLocationInfo(b.getLocation(), "enabled") == null || BlockStorage.getLocationInfo(b.getLocation(), "enabled").equals(String.valueOf(false))) {
menu.replaceExistingItem(22, new CustomItem(Material.GUNPOWDER, "&7Enabled: &4\u2718", "", "&e> Click to enable this Machine"));
menu.addMenuClickHandler(22, (p, slot, item, action) -> {
BlockStorage.addBlockInfo(b, "enabled", String.valueOf(true));
newInstance(menu, b);
return false;
});
}
else {
menu.replaceExistingItem(22, new CustomItem(Material.REDSTONE, "&7Enabled: &2\u2714", "", "&e> Click to disable this Machine"));
menu.addMenuClickHandler(22, (p, slot, item, action) -> {
BlockStorage.addBlockInfo(b, "enabled", String.valueOf(false));
newInstance(menu, b);
return false;
});
}
double offset = (!BlockStorage.hasBlockInfo(b) || BlockStorage.getLocationInfo(b.getLocation(), "offset") == null) ? 3.0F : Double.valueOf(BlockStorage.getLocationInfo(b.getLocation(), "offset"));
menu.replaceExistingItem(31, new CustomItem(Material.PISTON, "&7Offset: &3" + offset + " Block(s)", "", "&rLeft Click: &7+0.1", "&rRight Click: &7-0.1"));
menu.addMenuClickHandler(31, (p, slot, item, action) -> {
double offsetv = DoubleHandler.fixDouble(Double.valueOf(BlockStorage.getLocationInfo(b.getLocation(), "offset")) + (action.isRightClicked() ? -0.1F : 0.1F));
BlockStorage.addBlockInfo(b, "offset", String.valueOf(offsetv));
newInstance(menu, b);
return false;
});
}
@Override
public boolean canOpen(Block b, Player p) {
return p.hasPermission("slimefun.inventory.bypass") || SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.ACCESS_INVENTORIES);
}
@Override
public int[] getSlotsAccessedByItemTransport(ItemTransportFlow flow) {
if (flow == ItemTransportFlow.INSERT) {
return inputSlots;
}
else {
return new int[0];
}
}
@Override
public int[] getSlotsAccessedByItemTransport(DirtyChestMenu menu, ItemTransportFlow flow, ItemStack item) {
if (flow == ItemTransportFlow.INSERT && item != null) {
if (item.getType() == getBody().getType()) {
return bodySlots;
}
if (item.getType() == getHead().getType()) {
return headSlots;
}
}
return new int[0];
}
};
registerBlockHandler(getID(), new SlimefunBlockHandler() {
@Override
public void onPlace(Player p, Block b, SlimefunItem item) {
BlockStorage.addBlockInfo(b, "offset", "3.0");
BlockStorage.addBlockInfo(b, "enabled", String.valueOf(false));
}
@Override
public boolean onBreak(Player p, Block b, SlimefunItem item, UnregisterReason reason) {
if (reason == UnregisterReason.EXPLODE) {
return false;
}
BlockMenu inv = BlockStorage.getInventory(b);
if (inv != null) {
for (int slot : bodySlots) {
if (inv.getItemInSlot(slot) != null) {
b.getWorld().dropItemNaturally(b.getLocation(), inv.getItemInSlot(slot));
inv.replaceExistingItem(slot, null);
}
}
for (int slot : headSlots) {
if (inv.getItemInSlot(slot) != null) {
b.getWorld().dropItemNaturally(b.getLocation(), inv.getItemInSlot(slot));
inv.replaceExistingItem(slot, null);
}
}
}
return true;
}
});
}
@Override
public BlockTicker getItemHandler() {
return new BlockTicker() {
@Override
public void tick(Block b, SlimefunItem sf, Config data) {
if (String.valueOf(false).equals(BlockStorage.getLocationInfo(b.getLocation(), "enabled"))) {
return;
}
if (lifetime % 60 == 0 && ChargableBlock.getCharge(b) >= getEnergyConsumption()) {
BlockMenu menu = BlockStorage.getInventory(b);
boolean hasBody = findResource(menu, getBody(), bodySlots);
boolean hasHead = findResource(menu, getHead(), headSlots);
if (hasBody && hasHead) {
consumeResources(menu);
ChargableBlock.addCharge(b, -getEnergyConsumption());
double offset = Double.parseDouble(BlockStorage.getLocationInfo(b.getLocation(), "offset"));
Slimefun.runSync(() -> {
Location loc = new Location(b.getWorld(), b.getX() + 0.5D, b.getY() + offset, b.getZ() + 0.5D);
b.getWorld().spawnEntity(loc, EntityType.WITHER);
});
}
}
}
@Override
public void uniqueTick() {
lifetime++;
}
@Override
public boolean isSynchronized() {
return false;
}
};
}
private boolean findResource(BlockMenu menu, ItemStack item, int[] slots) {
Material resource = item.getType();
int required = item.getAmount();
int found = 0;
for (int slot : slots) {
if (SlimefunUtils.isItemSimilar(menu.getItemInSlot(slot), new ItemStack(resource), true, false)) {
found += menu.getItemInSlot(slot).getAmount();
if (found > required) {
return true;
}
}
}
return false;
}
private void consumeResources(BlockMenu inv) {
int bodyCount = getBody().getAmount();
int headCount = getHead().getAmount();
for (int slot : bodySlots) {
if (SlimefunUtils.isItemSimilar(inv.getItemInSlot(slot), new ItemStack(getBody().getType()), true, false)) {
int amount = inv.getItemInSlot(slot).getAmount();
if (amount >= bodyCount) {
inv.consumeItem(slot, bodyCount);
break;
}
else {
bodyCount -= amount;
inv.replaceExistingItem(slot, null);
}
}
}
for (int slot : headSlots) {
if (SlimefunUtils.isItemSimilar(inv.getItemInSlot(slot), new ItemStack(getHead().getType()), true, false)) {
int amount = inv.getItemInSlot(slot).getAmount();
if (amount >= headCount) {
inv.consumeItem(slot, headCount);
break;
}
else {
headCount -= amount;
inv.replaceExistingItem(slot, null);
}
}
}
}
protected void constructMenu(BlockMenuPreset preset) {
preset.addItem(1, new CustomItem(getHead(), "&7Head Slot", "", "&rThis Slot accepts the head type"), ChestMenuUtils.getEmptyClickHandler());
preset.addItem(7, new CustomItem(getBody(), "&7Body Slot", "", "&rThis Slot accepts the body type"), ChestMenuUtils.getEmptyClickHandler());
preset.addItem(13, new CustomItem(Material.CLOCK, "&7Cooldown: &b30 Seconds", "", "&rThis Machine takes up to half a Minute to operate", "&rso give it some Time!"), ChestMenuUtils.getEmptyClickHandler());
}
@Override
public EnergyNetComponentType getEnergyComponentType() {
return EnergyNetComponentType.CONSUMER;
}
public abstract int getEnergyConsumption();
public abstract ItemStack getHead();
public abstract ItemStack getBody();
public abstract Material getHeadBorder();
public abstract Material getBodyBorder();
}

View File

@ -14,6 +14,7 @@ import io.github.thebusybiscuit.cscorelib2.blocks.Vein;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent;
import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNetComponentType;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
@ -21,7 +22,6 @@ import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu.AdvancedMenu
import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ClickAction;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.interfaces.InventoryBlock;
import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker;

View File

@ -0,0 +1,66 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines;
import org.bukkit.Material;
import org.bukkit.entity.IronGolem;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenuPreset;
/**
* The {@link IronGolemAssembler} is an electrical machine that can automatically spawn
* a {@link IronGolem} if the required ingredients have been provided.
*
* @author TheBusyBiscuit
*
* @see WitherAssembler
*
*/
public class IronGolemAssembler extends AbstractEntityAssembler {
public IronGolemAssembler(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
}
@Override
public int getCapacity() {
return 4096;
}
@Override
public int getEnergyConsumption() {
return 2048;
}
@Override
public ItemStack getHead() {
return new ItemStack(Material.PUMPKIN);
}
@Override
public Material getHeadBorder() {
return Material.ORANGE_STAINED_GLASS_PANE;
}
@Override
public ItemStack getBody() {
return new ItemStack(Material.IRON_BLOCK, 4);
}
@Override
public Material getBodyBorder() {
return Material.WHITE_STAINED_GLASS_PANE;
}
@Override
protected void constructMenu(BlockMenuPreset preset) {
preset.addItem(1, new CustomItem(getHead(), "&7Pumpkin Slot", "", "&rThis Slot accepts Pumpkins"), ChestMenuUtils.getEmptyClickHandler());
preset.addItem(7, new CustomItem(getBody(), "&7Iron Block Slot", "", "&rThis Slot accepts Iron Blocks"), ChestMenuUtils.getEmptyClickHandler());
preset.addItem(13, new CustomItem(Material.CLOCK, "&7Cooldown: &b30 Seconds", "", "&rThis Machine takes up to half a Minute to operate", "&rso give it some Time!"), ChestMenuUtils.getEmptyClickHandler());
}
}

View File

@ -1,182 +1,29 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.entity.Wither;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.cscorelib2.math.DoubleHandler;
import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction;
import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent;
import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNetComponentType;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunBlockHandler;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.UnregisterReason;
import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
import me.mrCookieSlime.Slimefun.api.energy.ChargableBlock;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenuPreset;
import me.mrCookieSlime.Slimefun.api.inventory.DirtyChestMenu;
import me.mrCookieSlime.Slimefun.api.item_transport.ItemTransportFlow;
/**
* The {@link WitherAssembler} is an electrical machine that can automatically spawn
* a {@link Wither} if the required ingredients have been provided.
*
* @author TheBusyBiscuit
*
* @see IronGolemAssembler
*
*/
public class WitherAssembler extends SimpleSlimefunItem<BlockTicker> implements EnergyNetComponent {
private static final int ENERGY_CONSUMPTION = 4096;
private final int[] border = { 0, 2, 3, 4, 5, 6, 8, 12, 14, 21, 23, 30, 32, 39, 40, 41 };
private final int[] skullBorder = { 9, 10, 11, 18, 20, 27, 29, 36, 37, 38 };
private final int[] sandBorder = { 15, 16, 17, 24, 26, 33, 35, 42, 43, 44 };
private int lifetime = 0;
public class WitherAssembler extends AbstractEntityAssembler {
public WitherAssembler(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
new BlockMenuPreset(getID(), "&5Wither Assembler") {
@Override
public void init() {
constructMenu(this);
}
@Override
public void newInstance(BlockMenu menu, Block b) {
if (!BlockStorage.hasBlockInfo(b) || BlockStorage.getLocationInfo(b.getLocation(), "enabled") == null || BlockStorage.getLocationInfo(b.getLocation(), "enabled").equals(String.valueOf(false))) {
menu.replaceExistingItem(22, new CustomItem(new ItemStack(Material.GUNPOWDER), "&7Enabled: &4\u2718", "", "&e> Click to enable this Machine"));
menu.addMenuClickHandler(22, (p, slot, item, action) -> {
BlockStorage.addBlockInfo(b, "enabled", String.valueOf(true));
newInstance(menu, b);
return false;
});
}
else {
menu.replaceExistingItem(22, new CustomItem(new ItemStack(Material.REDSTONE), "&7Enabled: &2\u2714", "", "&e> Click to disable this Machine"));
menu.addMenuClickHandler(22, (p, slot, item, action) -> {
BlockStorage.addBlockInfo(b, "enabled", String.valueOf(false));
newInstance(menu, b);
return false;
});
}
double offset = (!BlockStorage.hasBlockInfo(b) || BlockStorage.getLocationInfo(b.getLocation(), "offset") == null) ? 3.0F : Double.valueOf(BlockStorage.getLocationInfo(b.getLocation(), "offset"));
menu.replaceExistingItem(31, new CustomItem(new ItemStack(Material.PISTON), "&7Offset: &3" + offset + " Block(s)", "", "&rLeft Click: &7+0.1", "&rRight Click: &7-0.1"));
menu.addMenuClickHandler(31, (p, slot, item, action) -> {
double offsetv = DoubleHandler.fixDouble(Double.valueOf(BlockStorage.getLocationInfo(b.getLocation(), "offset")) + (action.isRightClicked() ? -0.1F : 0.1F));
BlockStorage.addBlockInfo(b, "offset", String.valueOf(offsetv));
newInstance(menu, b);
return false;
});
}
@Override
public boolean canOpen(Block b, Player p) {
return p.hasPermission("slimefun.inventory.bypass") || SlimefunPlugin.getProtectionManager().hasPermission(p, b.getLocation(), ProtectableAction.ACCESS_INVENTORIES);
}
@Override
public int[] getSlotsAccessedByItemTransport(ItemTransportFlow flow) {
if (flow == ItemTransportFlow.INSERT) return getInputSlots();
else return new int[0];
}
@Override
public int[] getSlotsAccessedByItemTransport(DirtyChestMenu menu, ItemTransportFlow flow, ItemStack item) {
if (flow == ItemTransportFlow.INSERT) {
if (SlimefunUtils.isItemSimilar(item, new ItemStack(Material.SOUL_SAND), true)) return getSoulSandSlots();
else return getWitherSkullSlots();
}
else return new int[0];
}
};
registerBlockHandler(getID(), new SlimefunBlockHandler() {
@Override
public void onPlace(Player p, Block b, SlimefunItem item) {
BlockStorage.addBlockInfo(b, "offset", "3.0");
BlockStorage.addBlockInfo(b, "enabled", String.valueOf(false));
}
@Override
public boolean onBreak(Player p, Block b, SlimefunItem item, UnregisterReason reason) {
if (reason == UnregisterReason.EXPLODE) return false;
BlockMenu inv = BlockStorage.getInventory(b);
if (inv != null) {
for (int slot : getSoulSandSlots()) {
if (inv.getItemInSlot(slot) != null) {
b.getWorld().dropItemNaturally(b.getLocation(), inv.getItemInSlot(slot));
inv.replaceExistingItem(slot, null);
}
}
for (int slot : getWitherSkullSlots()) {
if (inv.getItemInSlot(slot) != null) {
b.getWorld().dropItemNaturally(b.getLocation(), inv.getItemInSlot(slot));
inv.replaceExistingItem(slot, null);
}
}
}
return true;
}
});
}
private void constructMenu(BlockMenuPreset preset) {
for (int i : border) {
preset.addItem(i, ChestMenuUtils.getBackground(), ChestMenuUtils.getEmptyClickHandler());
}
for (int i : skullBorder) {
preset.addItem(i, new CustomItem(Material.BLACK_STAINED_GLASS_PANE, " "), ChestMenuUtils.getEmptyClickHandler());
}
for (int i : sandBorder) {
preset.addItem(i, new CustomItem(Material.BROWN_STAINED_GLASS_PANE, " "), ChestMenuUtils.getEmptyClickHandler());
}
preset.addItem(1, new CustomItem(Material.WITHER_SKELETON_SKULL, "&7Wither Skull Slot", "", "&rThis Slot accepts Wither Skeleton Skulls"), ChestMenuUtils.getEmptyClickHandler());
preset.addItem(7, new CustomItem(Material.SOUL_SAND, "&7Soul Sand Slot", "", "&rThis Slot accepts Soul Sand"), ChestMenuUtils.getEmptyClickHandler());
preset.addItem(13, new CustomItem(Material.CLOCK, "&7Cooldown: &b30 Seconds", "", "&rThis Machine takes up to half a Minute to operate", "&rso give it some Time!"), ChestMenuUtils.getEmptyClickHandler());
}
public int[] getInputSlots() {
return new int[] { 19, 28, 25, 34 };
}
public int[] getWitherSkullSlots() {
return new int[] { 19, 28 };
}
public int[] getSoulSandSlots() {
return new int[] { 25, 34 };
}
@Override
public EnergyNetComponentType getEnergyComponentType() {
return EnergyNetComponentType.CONSUMER;
}
@Override
@ -185,93 +32,35 @@ public class WitherAssembler extends SimpleSlimefunItem<BlockTicker> implements
}
@Override
public BlockTicker getItemHandler() {
return new BlockTicker() {
@Override
public void tick(Block b, SlimefunItem sf, Config data) {
if (String.valueOf(false).equals(BlockStorage.getLocationInfo(b.getLocation(), "enabled"))) {
return;
}
if (lifetime % 60 == 0 && ChargableBlock.getCharge(b) >= ENERGY_CONSUMPTION) {
BlockMenu menu = BlockStorage.getInventory(b);
boolean soulsand = findResource(menu, Material.SOUL_SAND, 4, getSoulSandSlots());
boolean skulls = findResource(menu, Material.WITHER_SKELETON_SKULL, 3, getWitherSkullSlots());
if (soulsand && skulls) {
consumeResources(menu);
ChargableBlock.addCharge(b, -ENERGY_CONSUMPTION);
double offset = Double.parseDouble(BlockStorage.getLocationInfo(b.getLocation(), "offset"));
Slimefun.runSync(() -> b.getWorld().spawnEntity(new Location(b.getWorld(), b.getX() + 0.5D, b.getY() + offset, b.getZ() + 0.5D), EntityType.WITHER));
}
}
}
@Override
public void uniqueTick() {
lifetime++;
}
@Override
public boolean isSynchronized() {
return false;
}
};
public int getEnergyConsumption() {
return 4096;
}
private boolean findResource(BlockMenu menu, Material resource, int required, int[] slots) {
int found = 0;
for (int slot : slots) {
if (SlimefunUtils.isItemSimilar(menu.getItemInSlot(slot), new ItemStack(resource), true)) {
found += menu.getItemInSlot(slot).getAmount();
if (found > required) {
return true;
}
}
}
return false;
@Override
public ItemStack getHead() {
return new ItemStack(Material.WITHER_SKELETON_SKULL, 3);
}
private void consumeResources(BlockMenu inv) {
int soulsand = 4;
int skulls = 3;
@Override
public Material getHeadBorder() {
return Material.BLACK_STAINED_GLASS_PANE;
}
for (int slot : getSoulSandSlots()) {
if (SlimefunUtils.isItemSimilar(inv.getItemInSlot(slot), new ItemStack(Material.SOUL_SAND), true)) {
int amount = inv.getItemInSlot(slot).getAmount();
@Override
public ItemStack getBody() {
return new ItemStack(Material.SOUL_SAND, 4);
}
if (amount >= soulsand) {
inv.consumeItem(slot, soulsand);
break;
}
else {
soulsand -= amount;
inv.replaceExistingItem(slot, null);
}
}
}
@Override
public Material getBodyBorder() {
return Material.BROWN_STAINED_GLASS_PANE;
}
for (int slot : getWitherSkullSlots()) {
if (SlimefunUtils.isItemSimilar(inv.getItemInSlot(slot), new ItemStack(Material.WITHER_SKELETON_SKULL), true)) {
int amount = inv.getItemInSlot(slot).getAmount();
if (amount >= skulls) {
inv.consumeItem(slot, skulls);
break;
}
else {
skulls -= amount;
inv.replaceExistingItem(slot, null);
}
}
}
@Override
protected void constructMenu(BlockMenuPreset preset) {
preset.addItem(1, new CustomItem(getHead(), "&7Wither Skeleton Skull Slot", "", "&rThis Slot accepts Wither Skeleton Skulls"), ChestMenuUtils.getEmptyClickHandler());
preset.addItem(7, new CustomItem(getBody(), "&7Soul Sand Slot", "", "&rThis Slot accepts Soul Sand"), ChestMenuUtils.getEmptyClickHandler());
preset.addItem(13, new CustomItem(Material.CLOCK, "&7Cooldown: &b30 Seconds", "", "&rThis Machine takes up to half a Minute to operate", "&rso give it some Time!"), ChestMenuUtils.getEmptyClickHandler());
}
}

View File

@ -29,14 +29,11 @@ import io.github.thebusybiscuit.slimefun4.utils.holograms.SimpleHologram;
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AGenerator;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineFuel;
import me.mrCookieSlime.Slimefun.Objects.handlers.GeneratorTicker;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
import me.mrCookieSlime.Slimefun.api.energy.ChargableBlock;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenuPreset;
import me.mrCookieSlime.Slimefun.api.item_transport.ItemTransportFlow;
@ -72,6 +69,8 @@ public abstract class Reactor extends AbstractEnergyProvider {
// No coolant border
private static final int[] border_4 = { 25, 34, 43 };
private final Set<Location> explosionsQueue = new HashSet<>();
public Reactor(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
@ -107,7 +106,7 @@ public abstract class Reactor extends AbstractEnergyProvider {
BlockMenu port = getAccessPort(b.getLocation());
if (port != null) {
menu.replaceExistingItem(INFO_SLOT, new CustomItem(new ItemStack(Material.GREEN_WOOL), "&7Access Port", "", "&6Detected", "", "&7> Click to view Access Port"));
menu.replaceExistingItem(INFO_SLOT, new CustomItem(Material.GREEN_WOOL, "&7Access Port", "", "&6Detected", "", "&7> Click to view Access Port"));
menu.addMenuClickHandler(INFO_SLOT, (p, slot, item, action) -> {
port.open(p);
newInstance(menu, b);
@ -116,7 +115,7 @@ public abstract class Reactor extends AbstractEnergyProvider {
});
}
else {
menu.replaceExistingItem(INFO_SLOT, new CustomItem(new ItemStack(Material.RED_WOOL), "&7Access Port", "", "&cNot detected", "", "&7Access Port must be", "&7placed 3 blocks above", "&7a reactor!"));
menu.replaceExistingItem(INFO_SLOT, new CustomItem(Material.RED_WOOL, "&7Access Port", "", "&cNot detected", "", "&7Access Port must be", "&7placed 3 blocks above", "&7a reactor!"));
menu.addMenuClickHandler(INFO_SLOT, (p, slot, item, action) -> {
newInstance(menu, b);
menu.open(p);
@ -261,89 +260,86 @@ public abstract class Reactor extends AbstractEnergyProvider {
}
@Override
protected GeneratorTicker onTick() {
return new GeneratorTicker() {
public int getGeneratedOutput(Location l, Config data) {
BlockMenu inv = BlockStorage.getInventory(l);
BlockMenu accessPort = getAccessPort(l);
private final Set<Location> explosionsQueue = new HashSet<>();
if (isProcessing(l)) {
extraTick(l);
int timeleft = progress.get(l);
@Override
public double generateEnergy(Location l, SlimefunItem sf, Config data) {
BlockMenu inv = BlockStorage.getInventory(l);
BlockMenu accessPort = getAccessPort(l);
int charge = ChargableBlock.getCharge(l);
if (timeleft > 0) {
int produced = getEnergyProduction();
int charge = 0;
if (isProcessing(l)) {
extraTick(l);
int timeleft = progress.get(l);
if (data.contains("energy-charge")) {
charge = Integer.parseInt(data.getString("energy-charge"));
}
if (timeleft > 0) {
int produced = getEnergyProduction();
int space = getCapacity() - charge;
int space = getCapacity() - charge;
if (space >= produced || !ReactorMode.GENERATOR.toString().equals(BlockStorage.getLocationInfo(l, MODE))) {
progress.put(l, timeleft - 1);
checkForWaterBlocks(l);
if (space >= produced || !ReactorMode.GENERATOR.toString().equals(BlockStorage.getLocationInfo(l, MODE))) {
progress.put(l, timeleft - 1);
checkForWaterBlocks(l);
ChestMenuUtils.updateProgressbar(inv, 22, timeleft, processing.get(l).getTicks(), getProgressBar());
ChestMenuUtils.updateProgressbar(inv, 22, timeleft, processing.get(l).getTicks(), getProgressBar());
if (needsCooling() && !hasEnoughCoolant(l, inv, accessPort, timeleft)) {
explosionsQueue.add(l);
return 0;
}
}
if (space >= produced) {
ChargableBlock.addCharge(l, getEnergyProduction());
return (double) (charge + getEnergyProduction());
}
else {
return charge;
}
}
else {
createByproduct(l, inv, accessPort);
return charge;
if (needsCooling() && !hasEnoughCoolant(l, inv, accessPort, timeleft)) {
explosionsQueue.add(l);
return 0;
}
}
if (space >= produced) {
return getEnergyProduction();
}
else {
burnNextFuel(l, inv, accessPort);
return charge;
return 0;
}
}
@Override
public boolean explode(Location l) {
boolean explosion = explosionsQueue.contains(l);
if (explosion) {
Slimefun.runSync(() -> {
ReactorExplodeEvent event = new ReactorExplodeEvent(l, Reactor.this);
Bukkit.getPluginManager().callEvent(event);
BlockStorage.getInventory(l).close();
SimpleHologram.remove(l.getBlock());
});
explosionsQueue.remove(l);
processing.remove(l);
progress.remove(l);
}
return explosion;
else {
createByproduct(l, inv, accessPort);
return 0;
}
}
else {
burnNextFuel(l, inv, accessPort);
return 0;
}
}
private void checkForWaterBlocks(Location l) {
Slimefun.runSync(() -> {
// We will pick a surrounding block at random and see if this is water.
// If it isn't, then we will make it explode.
BlockFace randomNeighbour = WATER_BLOCKS[ThreadLocalRandom.current().nextInt(WATER_BLOCKS.length)];
@Override
public boolean willExplode(Location l, Config data) {
boolean explosion = explosionsQueue.contains(l);
if (l.getBlock().getRelative(randomNeighbour).getType() != Material.WATER) {
explosionsQueue.add(l);
}
});
if (explosion) {
Slimefun.runSync(() -> {
ReactorExplodeEvent event = new ReactorExplodeEvent(l, Reactor.this);
Bukkit.getPluginManager().callEvent(event);
BlockStorage.getInventory(l).close();
SimpleHologram.remove(l.getBlock());
});
explosionsQueue.remove(l);
processing.remove(l);
progress.remove(l);
}
return explosion;
}
private void checkForWaterBlocks(Location l) {
Slimefun.runSync(() -> {
// We will pick a surrounding block at random and see if this is water.
// If it isn't, then we will make it explode.
int index = ThreadLocalRandom.current().nextInt(WATER_BLOCKS.length);
BlockFace randomNeighbour = WATER_BLOCKS[index];
if (l.getBlock().getRelative(randomNeighbour).getType() != Material.WATER) {
explosionsQueue.add(l);
}
};
});
}
private void createByproduct(Location l, BlockMenu inv, BlockMenu accessPort) {
@ -404,7 +400,8 @@ public abstract class Reactor extends AbstractEnergyProvider {
if (accessPort != null) {
for (int slot : getCoolantSlots()) {
if (SlimefunUtils.isItemSimilar(accessPort.getItemInSlot(slot), getCoolant(), true)) {
accessPort.replaceExistingItem(slot, menu.pushItem(accessPort.getItemInSlot(slot), getCoolantSlots()));
ItemStack remainingItem = menu.pushItem(accessPort.getItemInSlot(slot), getCoolantSlots());
accessPort.replaceExistingItem(slot, remainingItem);
}
}
}

View File

@ -7,9 +7,9 @@ import org.bukkit.potion.PotionEffectType;
import io.github.thebusybiscuit.slimefun4.core.handlers.ItemConsumptionHandler;
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.Objects.SlimefunItem.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
/**

View File

@ -10,9 +10,9 @@ import io.github.thebusybiscuit.cscorelib2.chat.ChatColors;
import io.github.thebusybiscuit.slimefun4.core.handlers.ItemConsumptionHandler;
import io.github.thebusybiscuit.slimefun4.core.services.LocalizationService;
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.Objects.SlimefunItem.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;

View File

@ -10,9 +10,9 @@ import org.bukkit.potion.PotionEffectType;
import io.github.thebusybiscuit.cscorelib2.inventory.ItemUtils;
import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
public class MagicSugar extends SimpleSlimefunItem<ItemUseHandler> {

View File

@ -4,9 +4,9 @@ import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting;
import io.github.thebusybiscuit.slimefun4.core.handlers.ItemConsumptionHandler;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
/**

View File

@ -5,9 +5,9 @@ import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import io.github.thebusybiscuit.slimefun4.core.handlers.ItemConsumptionHandler;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;

View File

@ -5,9 +5,9 @@ import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockUseHandler;
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.Objects.SlimefunItem.SimpleSlimefunItem;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
public class GEOScanner extends SimpleSlimefunItem<BlockUseHandler> {

View File

@ -36,7 +36,7 @@ public abstract class OilPump extends AContainer implements RecipeDisplayItem {
public OilPump(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(category, item, recipeType, recipe);
oil = SlimefunPlugin.getRegistry().getGEOResources().get(new NamespacedKey(SlimefunPlugin.instance, "oil")).orElse(null);
oil = SlimefunPlugin.getRegistry().getGEOResources().get(new NamespacedKey(SlimefunPlugin.instance(), "oil")).orElse(null);
new BlockMenuPreset(getID(), getInventoryTitle()) {

Some files were not shown because too many files have changed in this diff Show More