diff --git a/.github/workflows/closed_issues.yml b/.github/workflows/closed_issues.yml
index 38decb4ea..bd7c7f216 100644
--- a/.github/workflows/closed_issues.yml
+++ b/.github/workflows/closed_issues.yml
@@ -15,14 +15,14 @@ jobs:
token: ${{ secrets.ACCESS_TOKEN }}
max_commits: 20
- name: Add label
- if: contains(toJson(steps.resolved.outputs.issues), github.event.issue.number)
+ if: contains(steps.resolved.outputs.issues, github.event.issue.number)
uses: maxkomarychev/octions/octions/issues/add-labels@master
with:
token: ${{ secrets.ACCESS_TOKEN }}
issue_number: ${{ github.event.issue.number }}
labels: 'Resolved'
- uses: maxkomarychev/octions/octions/issues/create-comment@master
- if: contains(toJson(steps.resolved.outputs.issues), github.event.issue.number) == false
+ if: contains(steps.resolved.outputs.issues, github.event.issue.number) == false
with:
token: ${{ secrets.ACCESS_TOKEN }}
issue_number: ${{ github.event.issue.number }}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8b8acaa53..e7ef0f015 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -52,12 +52,28 @@
* Added SlimefunGuide-Options API
* Added ItemSettings API
* Added experimental 1.13 backwards compatibility
+* Added "Magma Cream to Magma Blocks" recipe to the Electric Press
+* Added "Magma Blocks to Sulfate" recipe
+* You can now search for items from within the book variant of the Guide
#### Changes
+* Replaced GuideHandlers with FlexCategories
+* Removed support for old EmeraldEnchants versions
+* Updated the book variant of the guide to use the newer API
+* Removed internal /sf elevator command
+* Split whitelist.yml up into individual /world-settings/worldname.yml files
+* Performance improvements
+* Slimefun Guide runs much faster now and can better deal with many Categories and items
+* Lots of API improvements
+* Faulty addons are now identified more easily and will no longer break Slimefun's main content this quickly
#### Fixes
* Fixed error message when clicking empty slots in the Slimefun Guide
* Fixed #1779
+* Fixed localized messages not showing in the book guide
+* Fixed empty categories showing up when items inside were hidden
+* Fixed ghost pages showing up when too many categories were disabled
+* Fixed debug fish not showing the correct chunk timings
## Release Candidate 10 (28 Mar 2020)
diff --git a/docs/allclasses-frame.html b/docs/allclasses-frame.html
index c3ef3db18..b46c0c2a5 100644
--- a/docs/allclasses-frame.html
+++ b/docs/allclasses-frame.html
@@ -2,10 +2,10 @@
This is an admin-only design which creates a SlimefunGuide that allows
@@ -996,6 +1001,10 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
This method returns an OptionalInt describing the level of this status
@@ -2972,6 +3000,8 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
This package holds an implementation of Network
@@ -3788,7 +3829,10 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
that are related to food.
This returns whether or not this SlimefunItem is allowed to be used in
@@ -3961,6 +4019,8 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
This method checks whether this Category will be hidden for the specified
@@ -3991,8 +4051,6 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
A PrematureCodeException is thrown when a SlimefunAddon tried
+ to access Slimefun code before Slimefun was enabled.
+ Always let your code inside onEnable() or later, never on class initialization.
public abstract class FlexCategory
+extends Category
+
A FlexCategory is a Category inside the SlimefunGuide that can
+ be completely modified.
+ It cannot hold any SlimefunItem.
+ It can be completely overridden to perform any action upon being opened.
This method checks whether this Category will be hidden for the specified
+ Player.
+
+ Categories are hidden if all of their items have been disabled.
Represents a Category that is only displayed in the Guide during
diff --git a/docs/io/github/thebusybiscuit/slimefun4/core/categories/package-tree.html b/docs/io/github/thebusybiscuit/slimefun4/core/categories/package-tree.html
index 309610e69..0aa0b449b 100644
--- a/docs/io/github/thebusybiscuit/slimefun4/core/categories/package-tree.html
+++ b/docs/io/github/thebusybiscuit/slimefun4/core/categories/package-tree.html
@@ -2,10 +2,10 @@
-
+
io.github.thebusybiscuit.slimefun4.core.categories Class Hierarchy (Slimefun4 - Javadocs)
-
+
@@ -114,6 +114,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
This package holds implementations of any SlimefunItem that
+ deals with the GEOResource API.
+ The most prominent example of this being the
+ GEOScanner and the
+ GEOMiner.
This method is called after SlimefunItem.register(SlimefunAddon).
+ Override this method to add any additional setup that needs to happen after
+ the original registration of this SlimefunItem.
public final void addOficialWikipage(String page)
This method will assign the given wiki page to this Item.
Note that you only need to provide the page name itself,
the URL to our wiki is prepended automatically.
This package provides the different implementations of
@@ -201,7 +213,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
notably: Cargo Nodes.
This package contains the different implementations of
@@ -209,7 +221,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
EnergyNetComponent
This package holds implementations of SlimefunItem
@@ -290,39 +305,39 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
SlimefunBow for example.
This package provides the different implementations of
@@ -201,7 +213,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
notably: Cargo Nodes.
This package contains the different implementations of
@@ -209,7 +221,7 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
EnergyNetComponent
This package holds implementations of SlimefunItem
@@ -290,39 +305,39 @@ $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
SlimefunBow for example.
diff --git a/docs/type-search-index.js b/docs/type-search-index.js
index a61af8170..60c831a1d 100644
--- a/docs/type-search-index.js
+++ b/docs/type-search-index.js
@@ -1 +1 @@
-typeSearchIndex = [{"p":"me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems","l":"AContainer"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.cargo","l":"AdvancedCargoOutputNode"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.androids","l":"AdvancedFarmerAndroid"},{"p":"me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems","l":"AGenerator"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.altar","l":"AltarRecipe"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.altar","l":"AncientAltar"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"AncientAltarListener"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.tasks","l":"AncientAltarTask"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.altar","l":"AncientPedestal"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.androids","l":"AndroidInstance"},{"p":"io.github.thebusybiscuit.slimefun4.api.events","l":"AndroidMineEvent"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.androids","l":"AndroidType"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"AnimalGrowthAccelerator"},{"p":"me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems","l":"AReactor"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks","l":"ArmorForge"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.tasks","l":"ArmorTask"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"AutoAnvil"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"AutoBreeder"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"AutoDisenchanter"},{"p":"io.github.thebusybiscuit.slimefun4.api.events","l":"AutoDisenchantEvent"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"AutoDrier"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"AutoEnchanter"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"AutomatedCraftingChamber"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks","l":"AutomatedPanningMachine"},{"p":"io.github.thebusybiscuit.slimefun4.core.services","l":"AutoSavingService"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"BackpackListener"},{"p":"io.github.thebusybiscuit.slimefun4.core.services","l":"BackupService"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.medical","l":"Bandage"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric","l":"BasicCircuitBoard"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.generators","l":"BioGenerator"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.food","l":"BirthdayCake"},{"p":"me.mrCookieSlime.Slimefun.Objects.handlers","l":"BlockBreakHandler"},{"p":"io.github.thebusybiscuit.slimefun4.core.services","l":"BlockDataService"},{"p":"me.mrCookieSlime.Slimefun.Objects.handlers","l":"BlockDispenseHandler"},{"p":"me.mrCookieSlime.Slimefun.api","l":"BlockInfoConfig"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"BlockListener"},{"p":"me.mrCookieSlime.Slimefun.api.inventory","l":"BlockMenu"},{"p":"me.mrCookieSlime.Slimefun.api.inventory","l":"BlockMenuPreset"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"BlockPhysicsListener"},{"p":"me.mrCookieSlime.Slimefun.Objects.handlers","l":"BlockPlaceHandler"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.blocks","l":"BlockPlacer"},{"p":"me.mrCookieSlime.Slimefun.api","l":"BlockStorage"},{"p":"me.mrCookieSlime.Slimefun.Objects.handlers","l":"BlockTicker"},{"p":"me.mrCookieSlime.Slimefun.Objects.handlers","l":"BlockUseHandler"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.guide","l":"BookSlimefunGuide"},{"p":"me.mrCookieSlime.Slimefun.Objects.handlers","l":"BowShootHandler"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.androids","l":"ButcherAndroid"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"ButcherAndroidListener"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric","l":"Capacitor"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"CarbonPress"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.cargo","l":"CargoConnectorNode"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.cargo","l":"CargoInputNode"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.cargo","l":"CargoManager"},{"p":"io.github.thebusybiscuit.slimefun4.core.networks.cargo","l":"CargoNet"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.cargo","l":"CargoOutputNode"},{"p":"me.mrCookieSlime.Slimefun.Lists","l":"Categories"},{"p":"me.mrCookieSlime.Slimefun.Objects","l":"Category"},{"p":"me.mrCookieSlime.Slimefun.api.energy","l":"ChargableBlock"},{"p":"me.mrCookieSlime.Slimefun.Objects.SlimefunItem","l":"ChargableItem"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"ChargingBench"},{"p":"io.github.thebusybiscuit.slimefun4.utils","l":"ChatUtils"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.guide","l":"CheatSheetSlimefunGuide"},{"p":"io.github.thebusybiscuit.slimefun4.utils","l":"ChestMenuUtils"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.guide","l":"ChestSlimefunGuide"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.generators","l":"CoalGenerator"},{"p":"io.github.thebusybiscuit.slimefun4.utils.itemstack","l":"ColoredFireworkStar"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.generators","l":"CombustionGenerator"},{"p":"io.github.thebusybiscuit.slimefun4.core.commands.subcommands","l":"Commands"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.blocks","l":"Composter"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks","l":"Compressor"},{"p":"io.github.thebusybiscuit.slimefun4.core.services.github","l":"Contributor"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.food","l":"Cooler"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"CoolerListener"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"CropGrowthAccelerator"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.blocks","l":"Crucible"},{"p":"io.github.thebusybiscuit.slimefun4.core.services","l":"CustomItemDataService"},{"p":"io.github.thebusybiscuit.slimefun4.core.services","l":"CustomTextureService"},{"p":"io.github.thebusybiscuit.slimefun4.core.attributes","l":"DamageableItem"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"DeathpointListener"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"DebugFishListener"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.food","l":"DietCookie"},{"p":"me.mrCookieSlime.Slimefun.api.inventory","l":"DirtyChestMenu"},{"p":"me.mrCookieSlime.Slimefun.api.inventory","l":"DirtyChestMenu.SaveHandler"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"DispenserListener"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items","l":"EasterEgg"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"ElectricDustWasher"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"ElectricFurnace"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"ElectricGoldPan"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"ElectricIngotFactory"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"ElectricIngotPulverizer"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"ElectricOreGrinder"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"ElectricPress"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"ElectricSmeltery"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"ElectrifiedCrucible"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.gps","l":"ElevatorPlate"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.magical","l":"EnderBackpack"},{"p":"io.github.thebusybiscuit.slimefun4.core.networks.energy","l":"EnergyNet"},{"p":"io.github.thebusybiscuit.slimefun4.core.attributes","l":"EnergyNetComponent"},{"p":"io.github.thebusybiscuit.slimefun4.core.networks.energy","l":"EnergyNetComponentType"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"EnergyRegulator"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks","l":"EnhancedCraftingTable"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.blocks","l":"EnhancedFurnace"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"EnhancedFurnaceListener"},{"p":"me.mrCookieSlime.Slimefun.Objects.handlers","l":"EntityKillHandler"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"EntityKillListener"},{"p":"io.github.thebusybiscuit.slimefun4.api","l":"ErrorReport"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"ExplosionsListener"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.weapons","l":"ExplosiveBow"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.tools","l":"ExplosivePickaxe"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.tools","l":"ExplosiveShovel"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.androids","l":"FarmerAndroid"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"FireworksListener"},{"p":"io.github.thebusybiscuit.slimefun4.utils","l":"FireworkUtils"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.androids","l":"FisherAndroid"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"FluidPump"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"FoodComposter"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"FoodFabricator"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.food","l":"FortuneCookie"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"Freezer"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"GadgetsListener"},{"p":"me.mrCookieSlime.Slimefun.Objects.handlers","l":"GeneratorTicker"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.geo","l":"GEOMiner"},{"p":"io.github.thebusybiscuit.slimefun4.api.geo","l":"GEOResource"},{"p":"io.github.thebusybiscuit.slimefun4.api.events","l":"GEOResourceGenerationEvent"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.resources","l":"GEOResourcesSetup"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.geo","l":"GEOScanner"},{"p":"io.github.thebusybiscuit.slimefun4.core.services.github","l":"GitHubService"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.tools","l":"GoldPan"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.gps","l":"GPSControlPanel"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.gps","l":"GPSMarkerTool"},{"p":"io.github.thebusybiscuit.slimefun4.api.gps","l":"GPSNetwork"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.gps","l":"GPSTransmitter"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.tools","l":"GrapplingHook"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"GrapplingHookListener"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks","l":"GrindStone"},{"p":"me.mrCookieSlime.Slimefun.api","l":"GuideHandler"},{"p":"io.github.thebusybiscuit.slimefun4.core.guide","l":"GuideHistory"},{"p":"me.mrCookieSlime.Slimefun.Objects.SlimefunItem","l":"HandledBlock"},{"p":"io.github.thebusybiscuit.slimefun4.api.items","l":"HashedArmorpiece"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"HeatedPressureChamber"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.tools","l":"HerculesPickaxe"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.blocks","l":"HologramProjector"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.weapons","l":"IcyBow"},{"p":"io.github.thebusybiscuit.slimefun4.api.exceptions","l":"IdConflictException"},{"p":"io.github.thebusybiscuit.slimefun4.api.exceptions","l":"IncompatibleItemHandlerException"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.magical","l":"InfernalBonemeal"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.blocks","l":"InfusedHopper"},{"p":"me.mrCookieSlime.Slimefun.Objects.SlimefunItem.interfaces","l":"InventoryBlock"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"IronGolemListener"},{"p":"io.github.thebusybiscuit.slimefun4.core.attributes","l":"ItemAttribute"},{"p":"me.mrCookieSlime.Slimefun.Objects.handlers","l":"ItemConsumptionHandler"},{"p":"me.mrCookieSlime.Slimefun.Objects.handlers","l":"ItemDropHandler"},{"p":"me.mrCookieSlime.Slimefun.api.energy","l":"ItemEnergy"},{"p":"me.mrCookieSlime.Slimefun.Objects.handlers","l":"ItemHandler"},{"p":"me.mrCookieSlime.Slimefun.api.inventory","l":"ItemManipulationEvent"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"ItemPickupListener"},{"p":"io.github.thebusybiscuit.slimefun4.api.items","l":"ItemRestriction"},{"p":"io.github.thebusybiscuit.slimefun4.api.items","l":"ItemSetting"},{"p":"me.mrCookieSlime.Slimefun.Objects.SlimefunItem","l":"ItemState"},{"p":"me.mrCookieSlime.Slimefun.api.item_transport","l":"ItemTransportFlow"},{"p":"me.mrCookieSlime.Slimefun.Objects.handlers","l":"ItemUseHandler"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.gadgets","l":"JetBoots"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.tasks","l":"JetBootsTask"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.gadgets","l":"Jetpack"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.tasks","l":"JetpackTask"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.food","l":"Juice"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks","l":"Juicer"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.magical","l":"KnowledgeFlask"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.magical","l":"KnowledgeTome"},{"p":"io.github.thebusybiscuit.slimefun4.core.services.localization","l":"Language"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.generators","l":"LavaGenerator"},{"p":"io.github.thebusybiscuit.slimefun4.core.services","l":"LocalizationService"},{"p":"me.mrCookieSlime.Slimefun.Objects","l":"LockedCategory"},{"p":"io.github.thebusybiscuit.slimefun4.utils","l":"LoreBuilder"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.tools","l":"LumberAxe"},{"p":"me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems","l":"MachineFuel"},{"p":"me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems","l":"MachineRecipe"},{"p":"io.github.thebusybiscuit.slimefun4.core.attributes","l":"MachineTier"},{"p":"io.github.thebusybiscuit.slimefun4.core.attributes","l":"MachineType"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.magical","l":"MagicEyeOfEnder"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.food","l":"MagicSugar"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks","l":"MagicWorkbench"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.generators","l":"MagnesiumGenerator"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.tasks","l":"MagnetTask"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks","l":"MakeshiftSmeltery"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.food","l":"MeatJerky"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.medical","l":"Medicine"},{"p":"io.github.thebusybiscuit.slimefun4.core.services.metrics","l":"MetricsService"},{"p":"io.github.thebusybiscuit.slimefun4.core.services","l":"MinecraftRecipeService"},{"p":"io.github.thebusybiscuit.slimefun4.api","l":"MinecraftVersion"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.androids","l":"MinerAndroid"},{"p":"io.github.thebusybiscuit.slimefun4.api.exceptions","l":"MissingDependencyException"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.food","l":"MonsterJerky"},{"p":"io.github.thebusybiscuit.slimefun4.core","l":"MultiBlock"},{"p":"io.github.thebusybiscuit.slimefun4.api.events","l":"MultiBlockInteractEvent"},{"p":"me.mrCookieSlime.Slimefun.Objects.handlers","l":"MultiBlockInteractionHandler"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"MultiBlockListener"},{"p":"me.mrCookieSlime.Slimefun.Objects.SlimefunItem.multiblocks","l":"MultiBlockMachine"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.gadgets","l":"Multimeter"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.gadgets","l":"MultiTool"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.tools","l":"NetherGoldPan"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.reactors","l":"NetherStarReactor"},{"p":"io.github.thebusybiscuit.slimefun4.api.network","l":"Network"},{"p":"io.github.thebusybiscuit.slimefun4.api.network","l":"NetworkComponent"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"NetworkListener"},{"p":"io.github.thebusybiscuit.slimefun4.api.network","l":"NetworkManager"},{"p":"me.mrCookieSlime.Slimefun.Objects.SlimefunItem.interfaces","l":"NotPlaceable"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.reactors","l":"NuclearReactor"},{"p":"io.github.thebusybiscuit.slimefun4.utils","l":"NumberUtils"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.geo","l":"OilPump"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks","l":"OreCrusher"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks","l":"OreWasher"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.armor","l":"Parachute"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.tasks","l":"ParachuteTask"},{"p":"io.github.thebusybiscuit.slimefun4.utils","l":"PatternUtils"},{"p":"io.github.thebusybiscuit.slimefun4.core.services","l":"PermissionsService"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.gps","l":"PersonalActivationPlate"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.tools","l":"PickaxeOfContainment"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.tools","l":"PickaxeOfTheSeeker"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.tools","l":"PickaxeOfVeinMining"},{"p":"io.github.thebusybiscuit.slimefun4.api.items","l":"Placeable"},{"p":"io.github.thebusybiscuit.slimefun4.api.player","l":"PlayerBackpack"},{"p":"io.github.thebusybiscuit.slimefun4.api.events","l":"PlayerLanguageChangeEvent"},{"p":"io.github.thebusybiscuit.slimefun4.api.player","l":"PlayerProfile"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"PlayerProfileListener"},{"p":"io.github.thebusybiscuit.slimefun4.api.events","l":"PlayerRightClickEvent"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.tools","l":"PortableCrafter"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.tools","l":"PortableDustbin"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.geo","l":"PortableGEOScanner"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.setup","l":"PostSetup"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks","l":"PressureChamber"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.androids","l":"ProgrammableAndroid"},{"p":"io.github.thebusybiscuit.slimefun4.core.attributes","l":"Radioactive"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items","l":"RadioactiveItem"},{"p":"io.github.thebusybiscuit.slimefun4.core.attributes","l":"Radioactivity"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.medical","l":"Rag"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.blocks","l":"RainbowBlock"},{"p":"me.mrCookieSlime.Slimefun.Objects.handlers","l":"RainbowTicker"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.cargo","l":"ReactorAccessPort"},{"p":"io.github.thebusybiscuit.slimefun4.utils.holograms","l":"ReactorHologram"},{"p":"io.github.thebusybiscuit.slimefun4.core.attributes","l":"RecipeDisplayItem"},{"p":"me.mrCookieSlime.Slimefun.Lists","l":"RecipeType"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"Refinery"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.blocks","l":"RepairedSpawner"},{"p":"me.mrCookieSlime.Slimefun.Objects","l":"Research"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.setup","l":"ResearchSetup"},{"p":"io.github.thebusybiscuit.slimefun4.api.events","l":"ResearchUnlockEvent"},{"p":"io.github.thebusybiscuit.slimefun4.api.geo","l":"ResourceManager"},{"p":"io.github.thebusybiscuit.slimefun4.core.categories","l":"SeasonalCategory"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.weapons","l":"SeismicAxe"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"SeismicAxeListener"},{"p":"io.github.thebusybiscuit.slimefun4.utils.holograms","l":"SimpleHologram"},{"p":"me.mrCookieSlime.Slimefun.Objects.SlimefunItem","l":"SimpleSlimefunItem"},{"p":"me.mrCookieSlime.Slimefun.api","l":"Slimefun"},{"p":"io.github.thebusybiscuit.slimefun4.api","l":"SlimefunAddon"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.armor","l":"SlimefunArmorPiece"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.tools","l":"SlimefunBackpack"},{"p":"me.mrCookieSlime.Slimefun.Objects","l":"SlimefunBlockHandler"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"SlimefunBootsListener"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.weapons","l":"SlimefunBow"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"SlimefunBowListener"},{"p":"io.github.thebusybiscuit.slimefun4.api","l":"SlimefunBranch"},{"p":"io.github.thebusybiscuit.slimefun4.core.commands","l":"SlimefunCommand"},{"p":"io.github.thebusybiscuit.slimefun4.core.guide","l":"SlimefunGuide"},{"p":"io.github.thebusybiscuit.slimefun4.core.guide","l":"SlimefunGuideImplementation"},{"p":"io.github.thebusybiscuit.slimefun4.core.guide","l":"SlimefunGuideLayout"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"SlimefunGuideListener"},{"p":"io.github.thebusybiscuit.slimefun4.core.guide.options","l":"SlimefunGuideOption"},{"p":"io.github.thebusybiscuit.slimefun4.core.guide.options","l":"SlimefunGuideSettings"},{"p":"me.mrCookieSlime.Slimefun.Objects.SlimefunItem","l":"SlimefunItem"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"SlimefunItemConsumeListener"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"SlimefunItemListener"},{"p":"me.mrCookieSlime.Slimefun.Lists","l":"SlimefunItems"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.setup","l":"SlimefunItemSetup"},{"p":"me.mrCookieSlime.Slimefun.api","l":"SlimefunItemStack"},{"p":"io.github.thebusybiscuit.slimefun4.core.services.localization","l":"SlimefunLocalization"},{"p":"me.mrCookieSlime.Slimefun.Objects.SlimefunItem","l":"SlimefunMachine"},{"p":"me.mrCookieSlime.Slimefun.Setup","l":"SlimefunManager"},{"p":"me.mrCookieSlime.Slimefun","l":"SlimefunPlugin"},{"p":"io.github.thebusybiscuit.slimefun4.core","l":"SlimefunRegistry"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.tasks","l":"SlimefunStartupTask"},{"p":"io.github.thebusybiscuit.slimefun4.utils","l":"SlimefunUtils"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.tools","l":"SmeltersPickaxe"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks","l":"Smeltery"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.generators","l":"SolarGenerator"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.gadgets","l":"SolarHelmet"},{"p":"io.github.thebusybiscuit.slimefun4.core.attributes","l":"Soulbound"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.magical","l":"SoulboundBackpack"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.magical","l":"SoulboundItem"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"SoulboundListener"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.magical","l":"SoulboundRune"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.medical","l":"Splint"},{"p":"io.github.thebusybiscuit.slimefun4.api.player","l":"StatusEffect"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.magical","l":"StormStaff"},{"p":"io.github.thebusybiscuit.slimefun4.core.commands","l":"SubCommand"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.weapons","l":"SwordOfBeheading"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks","l":"TableSaw"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.magical","l":"Talisman"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"TalismanListener"},{"p":"io.github.thebusybiscuit.slimefun4.api.gps","l":"TeleportationManager"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.gps","l":"Teleporter"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"TeleporterListener"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.magical","l":"TelepositionScroll"},{"p":"io.github.thebusybiscuit.slimefun4.core.services.plugins","l":"ThirdPartyPluginService"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.tasks","l":"TickerTask"},{"p":"io.github.thebusybiscuit.slimefun4.core.services.localization","l":"Translators"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.cargo","l":"TrashCan"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"TreeGrowthAccelerator"},{"p":"me.mrCookieSlime.Slimefun.api.inventory","l":"UniversalBlockMenu"},{"p":"io.github.thebusybiscuit.slimefun4.api.exceptions","l":"UnregisteredItemException"},{"p":"me.mrCookieSlime.Slimefun.Objects.SlimefunItem","l":"UnregisterReason"},{"p":"io.github.thebusybiscuit.slimefun4.core.services","l":"UpdaterService"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"VampireBladeListener"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items","l":"VanillaItem"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"VanillaMachinesListener"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.medical","l":"Vitamins"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.magical","l":"WaterStaff"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.magical","l":"WindStaff"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"WitherAssembler"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"WitherListener"},{"p":"io.github.thebusybiscuit.slimefun4.core.attributes","l":"WitherProof"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.blocks","l":"WitherProofBlock"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.androids","l":"WoodcutterAndroid"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"WorldListener"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"XPCollector"}]
\ No newline at end of file
+typeSearchIndex = [{"p":"me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems","l":"AContainer"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.cargo","l":"AdvancedCargoOutputNode"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.androids","l":"AdvancedFarmerAndroid"},{"p":"me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems","l":"AGenerator"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.altar","l":"AltarRecipe"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.altar","l":"AncientAltar"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"AncientAltarListener"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.tasks","l":"AncientAltarTask"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.altar","l":"AncientPedestal"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.androids","l":"AndroidInstance"},{"p":"io.github.thebusybiscuit.slimefun4.api.events","l":"AndroidMineEvent"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.androids","l":"AndroidType"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"AnimalGrowthAccelerator"},{"p":"me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems","l":"AReactor"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks","l":"ArmorForge"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.tasks","l":"ArmorTask"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"AutoAnvil"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"AutoBreeder"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"AutoDisenchanter"},{"p":"io.github.thebusybiscuit.slimefun4.api.events","l":"AutoDisenchantEvent"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"AutoDrier"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"AutoEnchanter"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"AutomatedCraftingChamber"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks","l":"AutomatedPanningMachine"},{"p":"io.github.thebusybiscuit.slimefun4.core.services","l":"AutoSavingService"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"BackpackListener"},{"p":"io.github.thebusybiscuit.slimefun4.core.services","l":"BackupService"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.medical","l":"Bandage"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric","l":"BasicCircuitBoard"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.generators","l":"BioGenerator"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.food","l":"BirthdayCake"},{"p":"me.mrCookieSlime.Slimefun.Objects.handlers","l":"BlockBreakHandler"},{"p":"io.github.thebusybiscuit.slimefun4.core.services","l":"BlockDataService"},{"p":"me.mrCookieSlime.Slimefun.Objects.handlers","l":"BlockDispenseHandler"},{"p":"me.mrCookieSlime.Slimefun.api","l":"BlockInfoConfig"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"BlockListener"},{"p":"me.mrCookieSlime.Slimefun.api.inventory","l":"BlockMenu"},{"p":"me.mrCookieSlime.Slimefun.api.inventory","l":"BlockMenuPreset"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"BlockPhysicsListener"},{"p":"me.mrCookieSlime.Slimefun.Objects.handlers","l":"BlockPlaceHandler"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.blocks","l":"BlockPlacer"},{"p":"me.mrCookieSlime.Slimefun.api","l":"BlockStorage"},{"p":"me.mrCookieSlime.Slimefun.Objects.handlers","l":"BlockTicker"},{"p":"me.mrCookieSlime.Slimefun.Objects.handlers","l":"BlockUseHandler"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.guide","l":"BookSlimefunGuide"},{"p":"me.mrCookieSlime.Slimefun.Objects.handlers","l":"BowShootHandler"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.androids","l":"ButcherAndroid"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"ButcherAndroidListener"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric","l":"Capacitor"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"CarbonPress"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.cargo","l":"CargoConnectorNode"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.cargo","l":"CargoInputNode"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.cargo","l":"CargoManager"},{"p":"io.github.thebusybiscuit.slimefun4.core.networks.cargo","l":"CargoNet"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.cargo","l":"CargoOutputNode"},{"p":"me.mrCookieSlime.Slimefun.Lists","l":"Categories"},{"p":"me.mrCookieSlime.Slimefun.Objects","l":"Category"},{"p":"me.mrCookieSlime.Slimefun.api.energy","l":"ChargableBlock"},{"p":"me.mrCookieSlime.Slimefun.Objects.SlimefunItem","l":"ChargableItem"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"ChargingBench"},{"p":"io.github.thebusybiscuit.slimefun4.utils","l":"ChatUtils"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.guide","l":"CheatSheetSlimefunGuide"},{"p":"io.github.thebusybiscuit.slimefun4.utils","l":"ChestMenuUtils"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.guide","l":"ChestSlimefunGuide"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.generators","l":"CoalGenerator"},{"p":"io.github.thebusybiscuit.slimefun4.utils.itemstack","l":"ColoredFireworkStar"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.generators","l":"CombustionGenerator"},{"p":"io.github.thebusybiscuit.slimefun4.core.commands.subcommands","l":"Commands"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.blocks","l":"Composter"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks","l":"Compressor"},{"p":"io.github.thebusybiscuit.slimefun4.core.services.github","l":"Contributor"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.food","l":"Cooler"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"CoolerListener"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"CropGrowthAccelerator"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.blocks","l":"Crucible"},{"p":"io.github.thebusybiscuit.slimefun4.core.services","l":"CustomItemDataService"},{"p":"io.github.thebusybiscuit.slimefun4.core.services","l":"CustomTextureService"},{"p":"io.github.thebusybiscuit.slimefun4.core.attributes","l":"DamageableItem"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"DeathpointListener"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"DebugFishListener"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.food","l":"DietCookie"},{"p":"me.mrCookieSlime.Slimefun.api.inventory","l":"DirtyChestMenu"},{"p":"me.mrCookieSlime.Slimefun.api.inventory","l":"DirtyChestMenu.SaveHandler"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"DispenserListener"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items","l":"EasterEgg"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"ElectricDustWasher"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"ElectricFurnace"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"ElectricGoldPan"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"ElectricIngotFactory"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"ElectricIngotPulverizer"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"ElectricOreGrinder"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"ElectricPress"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"ElectricSmeltery"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"ElectrifiedCrucible"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.gps","l":"ElevatorPlate"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.magical","l":"EnderBackpack"},{"p":"io.github.thebusybiscuit.slimefun4.core.networks.energy","l":"EnergyNet"},{"p":"io.github.thebusybiscuit.slimefun4.core.attributes","l":"EnergyNetComponent"},{"p":"io.github.thebusybiscuit.slimefun4.core.networks.energy","l":"EnergyNetComponentType"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"EnergyRegulator"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks","l":"EnhancedCraftingTable"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.blocks","l":"EnhancedFurnace"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"EnhancedFurnaceListener"},{"p":"me.mrCookieSlime.Slimefun.Objects.handlers","l":"EntityKillHandler"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"EntityKillListener"},{"p":"io.github.thebusybiscuit.slimefun4.api","l":"ErrorReport"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"ExplosionsListener"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.weapons","l":"ExplosiveBow"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.tools","l":"ExplosivePickaxe"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.tools","l":"ExplosiveShovel"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.androids","l":"FarmerAndroid"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"FireworksListener"},{"p":"io.github.thebusybiscuit.slimefun4.utils","l":"FireworkUtils"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.androids","l":"FisherAndroid"},{"p":"io.github.thebusybiscuit.slimefun4.core.categories","l":"FlexCategory"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"FluidPump"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"FoodComposter"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"FoodFabricator"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.food","l":"FortuneCookie"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"Freezer"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"GadgetsListener"},{"p":"me.mrCookieSlime.Slimefun.Objects.handlers","l":"GeneratorTicker"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.geo","l":"GEOMiner"},{"p":"io.github.thebusybiscuit.slimefun4.api.geo","l":"GEOResource"},{"p":"io.github.thebusybiscuit.slimefun4.api.events","l":"GEOResourceGenerationEvent"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.resources","l":"GEOResourcesSetup"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.geo","l":"GEOScanner"},{"p":"io.github.thebusybiscuit.slimefun4.core.services.github","l":"GitHubService"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.tools","l":"GoldPan"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.gps","l":"GPSControlPanel"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.gps","l":"GPSMarkerTool"},{"p":"io.github.thebusybiscuit.slimefun4.api.gps","l":"GPSNetwork"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.gps","l":"GPSTransmitter"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.tools","l":"GrapplingHook"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"GrapplingHookListener"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks","l":"GrindStone"},{"p":"me.mrCookieSlime.Slimefun.api","l":"GuideHandler"},{"p":"io.github.thebusybiscuit.slimefun4.core.guide","l":"GuideHistory"},{"p":"me.mrCookieSlime.Slimefun.Objects.SlimefunItem","l":"HandledBlock"},{"p":"io.github.thebusybiscuit.slimefun4.api.items","l":"HashedArmorpiece"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"HeatedPressureChamber"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.tools","l":"HerculesPickaxe"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.blocks","l":"HologramProjector"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.weapons","l":"IcyBow"},{"p":"io.github.thebusybiscuit.slimefun4.api.exceptions","l":"IdConflictException"},{"p":"io.github.thebusybiscuit.slimefun4.api.exceptions","l":"IncompatibleItemHandlerException"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.magical","l":"InfernalBonemeal"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.blocks","l":"InfusedHopper"},{"p":"me.mrCookieSlime.Slimefun.Objects.SlimefunItem.interfaces","l":"InventoryBlock"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"IronGolemListener"},{"p":"io.github.thebusybiscuit.slimefun4.core.attributes","l":"ItemAttribute"},{"p":"me.mrCookieSlime.Slimefun.Objects.handlers","l":"ItemConsumptionHandler"},{"p":"me.mrCookieSlime.Slimefun.Objects.handlers","l":"ItemDropHandler"},{"p":"me.mrCookieSlime.Slimefun.api.energy","l":"ItemEnergy"},{"p":"me.mrCookieSlime.Slimefun.Objects.handlers","l":"ItemHandler"},{"p":"me.mrCookieSlime.Slimefun.api.inventory","l":"ItemManipulationEvent"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"ItemPickupListener"},{"p":"io.github.thebusybiscuit.slimefun4.api.items","l":"ItemRestriction"},{"p":"io.github.thebusybiscuit.slimefun4.api.items","l":"ItemSetting"},{"p":"me.mrCookieSlime.Slimefun.Objects.SlimefunItem","l":"ItemState"},{"p":"me.mrCookieSlime.Slimefun.api.item_transport","l":"ItemTransportFlow"},{"p":"me.mrCookieSlime.Slimefun.Objects.handlers","l":"ItemUseHandler"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.gadgets","l":"JetBoots"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.tasks","l":"JetBootsTask"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.gadgets","l":"Jetpack"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.tasks","l":"JetpackTask"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.food","l":"Juice"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks","l":"Juicer"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.magical","l":"KnowledgeFlask"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.magical","l":"KnowledgeTome"},{"p":"io.github.thebusybiscuit.slimefun4.core.services.localization","l":"Language"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.generators","l":"LavaGenerator"},{"p":"io.github.thebusybiscuit.slimefun4.core.services","l":"LocalizationService"},{"p":"me.mrCookieSlime.Slimefun.Objects","l":"LockedCategory"},{"p":"io.github.thebusybiscuit.slimefun4.utils","l":"LoreBuilder"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.tools","l":"LumberAxe"},{"p":"me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems","l":"MachineFuel"},{"p":"me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems","l":"MachineRecipe"},{"p":"io.github.thebusybiscuit.slimefun4.core.attributes","l":"MachineTier"},{"p":"io.github.thebusybiscuit.slimefun4.core.attributes","l":"MachineType"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.magical","l":"MagicEyeOfEnder"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.magical","l":"MagicianTalisman"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.magical","l":"MagicianTalisman.TalismanEnchantment"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.food","l":"MagicSugar"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks","l":"MagicWorkbench"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.generators","l":"MagnesiumGenerator"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.tasks","l":"MagnetTask"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks","l":"MakeshiftSmeltery"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.food","l":"MeatJerky"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.medical","l":"Medicine"},{"p":"io.github.thebusybiscuit.slimefun4.core.services.metrics","l":"MetricsService"},{"p":"io.github.thebusybiscuit.slimefun4.core.services","l":"MinecraftRecipeService"},{"p":"io.github.thebusybiscuit.slimefun4.api","l":"MinecraftVersion"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.androids","l":"MinerAndroid"},{"p":"io.github.thebusybiscuit.slimefun4.api.exceptions","l":"MissingDependencyException"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.food","l":"MonsterJerky"},{"p":"io.github.thebusybiscuit.slimefun4.core","l":"MultiBlock"},{"p":"io.github.thebusybiscuit.slimefun4.api.events","l":"MultiBlockInteractEvent"},{"p":"me.mrCookieSlime.Slimefun.Objects.handlers","l":"MultiBlockInteractionHandler"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"MultiBlockListener"},{"p":"me.mrCookieSlime.Slimefun.Objects.SlimefunItem.multiblocks","l":"MultiBlockMachine"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.gadgets","l":"Multimeter"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.gadgets","l":"MultiTool"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.tools","l":"NetherGoldPan"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.reactors","l":"NetherStarReactor"},{"p":"io.github.thebusybiscuit.slimefun4.api.network","l":"Network"},{"p":"io.github.thebusybiscuit.slimefun4.api.network","l":"NetworkComponent"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"NetworkListener"},{"p":"io.github.thebusybiscuit.slimefun4.api.network","l":"NetworkManager"},{"p":"me.mrCookieSlime.Slimefun.Objects.SlimefunItem.interfaces","l":"NotPlaceable"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.reactors","l":"NuclearReactor"},{"p":"io.github.thebusybiscuit.slimefun4.utils","l":"NumberUtils"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.geo","l":"OilPump"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks","l":"OreCrusher"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks","l":"OreWasher"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.armor","l":"Parachute"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.tasks","l":"ParachuteTask"},{"p":"io.github.thebusybiscuit.slimefun4.utils","l":"PatternUtils"},{"p":"io.github.thebusybiscuit.slimefun4.core.services","l":"PermissionsService"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.gps","l":"PersonalActivationPlate"},{"p":"io.github.thebusybiscuit.slimefun4.core.services","l":"PerWorldSettingsService"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.tools","l":"PickaxeOfContainment"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.tools","l":"PickaxeOfTheSeeker"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.tools","l":"PickaxeOfVeinMining"},{"p":"io.github.thebusybiscuit.slimefun4.api.items","l":"Placeable"},{"p":"io.github.thebusybiscuit.slimefun4.api.player","l":"PlayerBackpack"},{"p":"io.github.thebusybiscuit.slimefun4.api.events","l":"PlayerLanguageChangeEvent"},{"p":"io.github.thebusybiscuit.slimefun4.api.player","l":"PlayerProfile"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"PlayerProfileListener"},{"p":"io.github.thebusybiscuit.slimefun4.api.events","l":"PlayerRightClickEvent"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.tools","l":"PortableCrafter"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.tools","l":"PortableDustbin"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.geo","l":"PortableGEOScanner"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.setup","l":"PostSetup"},{"p":"io.github.thebusybiscuit.slimefun4.api.exceptions","l":"PrematureCodeException"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks","l":"PressureChamber"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.androids","l":"ProgrammableAndroid"},{"p":"io.github.thebusybiscuit.slimefun4.core.attributes","l":"Radioactive"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items","l":"RadioactiveItem"},{"p":"io.github.thebusybiscuit.slimefun4.core.attributes","l":"Radioactivity"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.medical","l":"Rag"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.blocks","l":"RainbowBlock"},{"p":"me.mrCookieSlime.Slimefun.Objects.handlers","l":"RainbowTicker"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.cargo","l":"ReactorAccessPort"},{"p":"io.github.thebusybiscuit.slimefun4.utils.holograms","l":"ReactorHologram"},{"p":"io.github.thebusybiscuit.slimefun4.core.attributes","l":"RecipeDisplayItem"},{"p":"me.mrCookieSlime.Slimefun.Lists","l":"RecipeType"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"Refinery"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.blocks","l":"RepairedSpawner"},{"p":"me.mrCookieSlime.Slimefun.Objects","l":"Research"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.setup","l":"ResearchSetup"},{"p":"io.github.thebusybiscuit.slimefun4.api.events","l":"ResearchUnlockEvent"},{"p":"io.github.thebusybiscuit.slimefun4.api.geo","l":"ResourceManager"},{"p":"io.github.thebusybiscuit.slimefun4.core.categories","l":"SeasonalCategory"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.weapons","l":"SeismicAxe"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"SeismicAxeListener"},{"p":"io.github.thebusybiscuit.slimefun4.utils.holograms","l":"SimpleHologram"},{"p":"me.mrCookieSlime.Slimefun.Objects.SlimefunItem","l":"SimpleSlimefunItem"},{"p":"me.mrCookieSlime.Slimefun.api","l":"Slimefun"},{"p":"io.github.thebusybiscuit.slimefun4.api","l":"SlimefunAddon"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.armor","l":"SlimefunArmorPiece"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.tools","l":"SlimefunBackpack"},{"p":"me.mrCookieSlime.Slimefun.Objects","l":"SlimefunBlockHandler"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"SlimefunBootsListener"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.weapons","l":"SlimefunBow"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"SlimefunBowListener"},{"p":"io.github.thebusybiscuit.slimefun4.api","l":"SlimefunBranch"},{"p":"io.github.thebusybiscuit.slimefun4.core.commands","l":"SlimefunCommand"},{"p":"io.github.thebusybiscuit.slimefun4.core.guide","l":"SlimefunGuide"},{"p":"io.github.thebusybiscuit.slimefun4.core.guide","l":"SlimefunGuideImplementation"},{"p":"io.github.thebusybiscuit.slimefun4.core.guide","l":"SlimefunGuideLayout"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"SlimefunGuideListener"},{"p":"io.github.thebusybiscuit.slimefun4.core.guide.options","l":"SlimefunGuideOption"},{"p":"io.github.thebusybiscuit.slimefun4.core.guide.options","l":"SlimefunGuideSettings"},{"p":"me.mrCookieSlime.Slimefun.Objects.SlimefunItem","l":"SlimefunItem"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"SlimefunItemConsumeListener"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"SlimefunItemListener"},{"p":"me.mrCookieSlime.Slimefun.Lists","l":"SlimefunItems"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.setup","l":"SlimefunItemSetup"},{"p":"me.mrCookieSlime.Slimefun.api","l":"SlimefunItemStack"},{"p":"io.github.thebusybiscuit.slimefun4.core.services.localization","l":"SlimefunLocalization"},{"p":"me.mrCookieSlime.Slimefun.Objects.SlimefunItem","l":"SlimefunMachine"},{"p":"me.mrCookieSlime.Slimefun.Setup","l":"SlimefunManager"},{"p":"me.mrCookieSlime.Slimefun","l":"SlimefunPlugin"},{"p":"io.github.thebusybiscuit.slimefun4.core","l":"SlimefunRegistry"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.tasks","l":"SlimefunStartupTask"},{"p":"io.github.thebusybiscuit.slimefun4.utils","l":"SlimefunUtils"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.tools","l":"SmeltersPickaxe"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks","l":"Smeltery"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.generators","l":"SolarGenerator"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.gadgets","l":"SolarHelmet"},{"p":"io.github.thebusybiscuit.slimefun4.core.attributes","l":"Soulbound"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.magical","l":"SoulboundBackpack"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.magical","l":"SoulboundItem"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"SoulboundListener"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.magical","l":"SoulboundRune"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.medical","l":"Splint"},{"p":"io.github.thebusybiscuit.slimefun4.api.player","l":"StatusEffect"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.magical","l":"StormStaff"},{"p":"io.github.thebusybiscuit.slimefun4.core.commands","l":"SubCommand"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.weapons","l":"SwordOfBeheading"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks","l":"TableSaw"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.magical","l":"Talisman"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"TalismanListener"},{"p":"io.github.thebusybiscuit.slimefun4.api.gps","l":"TeleportationManager"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.gps","l":"Teleporter"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"TeleporterListener"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.magical","l":"TelepositionScroll"},{"p":"io.github.thebusybiscuit.slimefun4.core.services.plugins","l":"ThirdPartyPluginService"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.tasks","l":"TickerTask"},{"p":"io.github.thebusybiscuit.slimefun4.core.services.localization","l":"Translators"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.cargo","l":"TrashCan"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"TreeGrowthAccelerator"},{"p":"me.mrCookieSlime.Slimefun.api.inventory","l":"UniversalBlockMenu"},{"p":"io.github.thebusybiscuit.slimefun4.api.exceptions","l":"UnregisteredItemException"},{"p":"me.mrCookieSlime.Slimefun.Objects.SlimefunItem","l":"UnregisterReason"},{"p":"io.github.thebusybiscuit.slimefun4.core.services","l":"UpdaterService"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"VampireBladeListener"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items","l":"VanillaItem"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"VanillaMachinesListener"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.medical","l":"Vitamins"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.magical","l":"WaterStaff"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.magical","l":"WindStaff"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"WitherAssembler"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"WitherListener"},{"p":"io.github.thebusybiscuit.slimefun4.core.attributes","l":"WitherProof"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.blocks","l":"WitherProofBlock"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.androids","l":"WoodcutterAndroid"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.listeners","l":"WorldListener"},{"p":"io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines","l":"XPCollector"}]
\ No newline at end of file
diff --git a/docs/type-search-index.zip b/docs/type-search-index.zip
index 2f18de21e..7bba247a2 100644
Binary files a/docs/type-search-index.zip and b/docs/type-search-index.zip differ
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/ErrorReport.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/ErrorReport.java
index d166fa319..2af6fbec3 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/ErrorReport.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/ErrorReport.java
@@ -16,7 +16,6 @@ import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.plugin.Plugin;
-import me.mrCookieSlime.CSCoreLibPlugin.CSCoreLib;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker;
@@ -52,8 +51,8 @@ public class ErrorReport {
stream.println(" Minecraft: " + Bukkit.getBukkitVersion());
stream.println();
stream.println("Slimefun Environment:");
- stream.println(" CS-CoreLib v" + CSCoreLib.getLib().getDescription().getVersion());
- stream.println(" Slimefun v" + SlimefunPlugin.instance.getDescription().getVersion());
+ stream.println(" CS-CoreLib v" + SlimefunPlugin.getCSCoreLibVersion());
+ stream.println(" Slimefun v" + SlimefunPlugin.getVersion());
stream.println(" Caused by: " + addon.getName() + " v" + addon.getPluginVersion());
stream.println();
@@ -81,7 +80,7 @@ public class ErrorReport {
addon.getLogger().log(Level.WARNING, "");
addon.getLogger().log(Level.WARNING, "An Error occured! It has been saved as: ");
addon.getLogger().log(Level.WARNING, "/plugins/Slimefun/error-reports/{0}", file.getName());
- addon.getLogger().log(Level.WARNING, "Please put this file on https://pastebin.com and report this to the developers.");
+ addon.getLogger().log(Level.WARNING, "Please put this file on https://pastebin.com and report this to the developer(s).");
if (addon.getBugTrackerURL() != null) {
addon.getLogger().log(Level.WARNING, "Bug Tracker: " + addon.getBugTrackerURL());
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/exceptions/PrematureCodeException.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/exceptions/PrematureCodeException.java
new file mode 100644
index 000000000..f05218a56
--- /dev/null
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/exceptions/PrematureCodeException.java
@@ -0,0 +1,27 @@
+package io.github.thebusybiscuit.slimefun4.api.exceptions;
+
+import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon;
+
+/**
+ * A {@link PrematureCodeException} is thrown when a {@link SlimefunAddon} tried
+ * to access Slimefun code before Slimefun was enabled.
+ * Always let your code inside onEnable() or later, never on class initialization.
+ *
+ * @author TheBusyBiscuit
+ *
+ */
+public class PrematureCodeException extends RuntimeException {
+
+ private static final long serialVersionUID = -7409054512888866955L;
+
+ /**
+ * This constructs a new {@link PrematureCodeException} with the given error context.
+ *
+ * @param message
+ * An error message to display
+ */
+ public PrematureCodeException(String message) {
+ super("Slimefun code was invoked before Slimefun finished loading: " + message);
+ }
+
+}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/gps/GPSNetwork.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/gps/GPSNetwork.java
index ffbe10be5..88e46fe57 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/gps/GPSNetwork.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/gps/GPSNetwork.java
@@ -2,6 +2,7 @@ package io.github.thebusybiscuit.slimefun4.api.gps;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
@@ -166,7 +167,7 @@ public class GPSNetwork {
menu.addItem(slot, new CustomItem(globe, entry.getKey().replace("player:death ", ""), "&8\u21E8 &7World: &r" + l.getWorld().getName(), "&8\u21E8 &7X: &r" + l.getX(), "&8\u21E8 &7Y: &r" + l.getY(), "&8\u21E8 &7Z: &r" + l.getZ(), "", "&8\u21E8 &cClick to delete"));
menu.addMenuClickHandler(slot, (pl, slotn, item, action) -> {
- String id = ChatColor.stripColor(ChatColor.translateAlternateColorCodes('&', entry.getKey())).toUpperCase().replace(' ', '_');
+ String id = ChatColor.stripColor(ChatColor.translateAlternateColorCodes('&', entry.getKey())).toUpperCase(Locale.ROOT).replace(' ', '_');
Config cfg = new Config(WAYPOINTS_DIRECTORY + pl.getUniqueId().toString() + ".yml");
cfg.setValue(id, null);
cfg.save();
@@ -214,7 +215,7 @@ public class GPSNetwork {
}
Config cfg = new Config(WAYPOINTS_DIRECTORY + p.getUniqueId().toString() + ".yml");
- String id = ChatColor.stripColor(ChatColor.translateAlternateColorCodes('&', name)).toUpperCase().replace(' ', '_');
+ String id = ChatColor.stripColor(ChatColor.translateAlternateColorCodes('&', name)).toUpperCase(Locale.ROOT).replace(' ', '_');
cfg.setValue(id, l);
cfg.setValue(id + ".name", name);
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/items/package-info.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/items/package-info.java
new file mode 100644
index 000000000..4fab4fc76
--- /dev/null
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/items/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * This package contains a few classes that revolve around the API for
+ * {@link me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem}, such as
+ * {@link io.github.thebusybiscuit.slimefun4.api.items.ItemSetting}
+ */
+package io.github.thebusybiscuit.slimefun4.api.items;
\ No newline at end of file
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/player/PlayerProfile.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/player/PlayerProfile.java
index 092079ec9..e86ee00d5 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/player/PlayerProfile.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/player/PlayerProfile.java
@@ -7,6 +7,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
+import java.util.OptionalInt;
import java.util.Set;
import java.util.UUID;
import java.util.function.Consumer;
@@ -19,9 +20,11 @@ import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
+import io.github.thebusybiscuit.cscorelib2.chat.ChatColors;
import io.github.thebusybiscuit.cscorelib2.config.Config;
import io.github.thebusybiscuit.slimefun4.api.items.HashedArmorpiece;
import io.github.thebusybiscuit.slimefun4.core.guide.GuideHistory;
+import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
import io.github.thebusybiscuit.slimefun4.utils.PatternUtils;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Objects.Research;
@@ -201,27 +204,28 @@ public final class PlayerProfile {
public void sendStats(CommandSender sender) {
Set researched = getResearches();
int levels = researched.stream().mapToInt(Research::getCost).sum();
+ int totalResearches = SlimefunPlugin.getRegistry().getResearches().size();
- String progress = String.valueOf(Math.round(((researched.size() * 100.0F) / SlimefunPlugin.getRegistry().getResearches().size()) * 100.0F) / 100.0F);
- if (Float.parseFloat(progress) < 16.0F) progress = "&4" + progress + " &r% ";
- else if (Float.parseFloat(progress) < 32.0F) progress = "&c" + progress + " &r% ";
- else if (Float.parseFloat(progress) < 48.0F) progress = "&6" + progress + " &r% ";
- else if (Float.parseFloat(progress) < 64.0F) progress = "&e" + progress + " &r% ";
- else if (Float.parseFloat(progress) < 80.0F) progress = "&2" + progress + " &r% ";
- else progress = "&a" + progress + " &r% ";
+ float progress = Math.round(((researched.size() * 100.0F) / totalResearches) * 100.0F) / 100.0F;
sender.sendMessage("");
- sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&7Statistics for Player: &b" + name));
+ sender.sendMessage(ChatColors.color("&7Statistics for Player: &b" + name));
sender.sendMessage("");
- sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&7Title: &b" + getTitle()));
- sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&7Research Progress: " + progress + "&e(" + researched.size() + " / " + SlimefunPlugin.getRegistry().getResearches().size() + ")"));
- sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&7Total XP Levels spent: &b" + levels));
+ sender.sendMessage(ChatColors.color("&7Title: " + ChatColor.AQUA + getTitle()));
+ sender.sendMessage(ChatColors.color("&7Research Progress: " + NumberUtils.getColorFromPercentage(progress) + progress + " &r% " + ChatColor.YELLOW + '(' + researched.size() + " / " + totalResearches + ')'));
+ sender.sendMessage(ChatColors.color("&7Total XP Levels spent: " + ChatColor.AQUA + levels));
}
public Player getPlayer() {
return Bukkit.getPlayer(getUUID());
}
+ /**
+ * This returns the {@link GuideHistory} of this {@link Player}.
+ * It is basically that player's browsing history.
+ *
+ * @return The {@link GuideHistory} of this {@link Player}
+ */
public GuideHistory getGuideHistory() {
return guideHistory;
}
@@ -291,28 +295,26 @@ public final class PlayerProfile {
* The player who's profile to retrieve
* @param callback
* The callback with the PlayerProfile
+ *
* @return If the player was cached or not.
*/
public static boolean get(OfflinePlayer p, Consumer callback) {
- PlayerProfile profile = SlimefunPlugin.getRegistry().getPlayerProfiles().get(p.getUniqueId());
+ PlayerProfile cached = SlimefunPlugin.getRegistry().getPlayerProfiles().get(p.getUniqueId());
- if (profile != null) {
- callback.accept(profile);
+ if (cached != null) {
+ callback.accept(cached);
return true;
}
Bukkit.getScheduler().runTaskAsynchronously(SlimefunPlugin.instance, () -> {
- PlayerProfile pp = new PlayerProfile(p);
- SlimefunPlugin.getRegistry().getPlayerProfiles().put(p.getUniqueId(), pp);
- callback.accept(pp);
+ PlayerProfile profile = new PlayerProfile(p);
+ SlimefunPlugin.getRegistry().getPlayerProfiles().put(p.getUniqueId(), profile);
+ callback.accept(profile);
});
+
return false;
}
- public static boolean isLoaded(UUID uuid) {
- return SlimefunPlugin.getRegistry().getPlayerProfiles().containsKey(uuid);
- }
-
public static Optional find(OfflinePlayer p) {
return Optional.ofNullable(SlimefunPlugin.getRegistry().getPlayerProfiles().get(p.getUniqueId()));
}
@@ -324,24 +326,23 @@ public final class PlayerProfile {
public static PlayerBackpack getBackpack(ItemStack item) {
if (item == null || !item.hasItemMeta() || !item.getItemMeta().hasLore()) return null;
- Optional id = Optional.empty();
+ OptionalInt id = OptionalInt.empty();
String uuid = "";
for (String line : item.getItemMeta().getLore()) {
- if (line.startsWith(ChatColor.translateAlternateColorCodes('&', "&7ID: ")) && line.indexOf('#') != -1) {
- try {
- String[] splitLine = PatternUtils.HASH.split(line);
- id = Optional.of(Integer.parseInt(splitLine[1]));
- uuid = splitLine[0].replace(ChatColor.translateAlternateColorCodes('&', "&7ID: "), "");
- }
- catch (NumberFormatException x) {
- return null;
+ if (line.startsWith(ChatColors.color("&7ID: ")) && line.indexOf('#') != -1) {
+ String[] splitLine = PatternUtils.HASH.split(line);
+
+ if (PatternUtils.NUMERIC.matcher(splitLine[1]).matches()) {
+ id = OptionalInt.of(Integer.parseInt(splitLine[1]));
+ uuid = splitLine[0].replace(ChatColors.color("&7ID: "), "");
}
}
}
if (id.isPresent()) {
- return PlayerProfile.fromUUID(UUID.fromString(uuid)).getBackpack(id.get());
+ PlayerProfile profile = fromUUID(UUID.fromString(uuid));
+ return profile.getBackpack(id.getAsInt());
}
else {
return null;
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/SlimefunRegistry.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/SlimefunRegistry.java
index fa73f99db..311d7338b 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/SlimefunRegistry.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/SlimefunRegistry.java
@@ -9,6 +9,8 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import org.bukkit.Location;
import org.bukkit.entity.EntityType;
@@ -31,7 +33,6 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.handlers.ItemHandler;
import me.mrCookieSlime.Slimefun.api.BlockInfoConfig;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
-import me.mrCookieSlime.Slimefun.api.GuideHandler;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenuPreset;
import me.mrCookieSlime.Slimefun.api.inventory.UniversalBlockMenu;
@@ -56,6 +57,7 @@ public class SlimefunRegistry {
private final Set researchingPlayers = new HashSet<>();
private final KeyMap researchIds = new KeyMap<>();
+ private boolean automaticallyLoadItems;
private boolean enableResearches;
private boolean freeCreativeResearches;
private boolean researchFireworks;
@@ -72,9 +74,9 @@ public class SlimefunRegistry {
private final Set chargeableBlocks = new HashSet<>();
private final Map witherProofBlocks = new HashMap<>();
+ private final ConcurrentMap profiles = new ConcurrentHashMap<>();
private final Map worlds = new HashMap<>();
private final Map chunks = new HashMap<>();
- private final Map profiles = new HashMap<>();
private final Map layouts = new EnumMap<>(SlimefunGuideLayout.class);
private final Map> drops = new EnumMap<>(EntityType.class);
private final Map capacities = new HashMap<>();
@@ -85,7 +87,6 @@ public class SlimefunRegistry {
private final Map> activeTickers = new HashMap<>();
- private final Map> guideHandlers = new HashMap<>();
private final Map automatedCraftingChamberRecipes = new HashMap<>();
public void load(Config cfg) {
@@ -101,7 +102,15 @@ public class SlimefunRegistry {
researchFireworks = cfg.getBoolean("options.research-unlock-fireworks");
}
- public List getEnabledCategories() {
+ public boolean isAutoLoadingEnabled() {
+ return automaticallyLoadItems;
+ }
+
+ public void setAutoLoadingMode(boolean mode) {
+ automaticallyLoadItems = mode;
+ }
+
+ public List getCategories() {
return categories;
}
@@ -203,7 +212,7 @@ public class SlimefunRegistry {
return universalInventories;
}
- public Map getPlayerProfiles() {
+ public ConcurrentMap getPlayerProfiles() {
return profiles;
}
@@ -231,18 +240,6 @@ public class SlimefunRegistry {
return geoResources;
}
- /**
- * This method will soon be removed.
- *
- * @deprecated The {@link GuideHandler} API is deprecated. It will soon be removed.
- *
- * @return A Map of handlers
- */
- @Deprecated
- public Map> getGuideHandlers() {
- return guideHandlers;
- }
-
@Deprecated
public Map getAutomatedCraftingChamberRecipes() {
return automatedCraftingChamberRecipes;
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/categories/FlexCategory.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/categories/FlexCategory.java
new file mode 100644
index 000000000..696937dfd
--- /dev/null
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/categories/FlexCategory.java
@@ -0,0 +1,55 @@
+package io.github.thebusybiscuit.slimefun4.core.categories;
+
+import java.util.List;
+
+import org.bukkit.NamespacedKey;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.ItemStack;
+
+import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
+import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuide;
+import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideLayout;
+import me.mrCookieSlime.Slimefun.Objects.Category;
+import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
+
+/**
+ * A {@link FlexCategory} is a {@link Category} inside the {@link SlimefunGuide} that can
+ * be completely modified.
+ * It cannot hold any {@link SlimefunItem}.
+ * It can be completely overridden to perform any action upon being opened.
+ *
+ * @author TheBusyBiscuit
+ *
+ */
+public abstract class FlexCategory extends Category {
+
+ public FlexCategory(NamespacedKey key, ItemStack item) {
+ this(key, item, 3);
+ }
+
+ public abstract boolean isVisible(Player p, PlayerProfile profile, SlimefunGuideLayout layout);
+
+ public abstract void open(Player p, PlayerProfile profile, SlimefunGuideLayout layout);
+
+ public FlexCategory(NamespacedKey key, ItemStack item, int tier) {
+ super(key, item, tier);
+ }
+
+ @Override
+ public final boolean isHidden(Player p) {
+ // We can stop this method right here.
+ // We provide a custom method for this. See isVisible(...)
+ return false;
+ }
+
+ @Override
+ public final void add(SlimefunItem item) {
+ throw new UnsupportedOperationException("You cannot add items to a FlexCategory!");
+ }
+
+ @Override
+ public final List getItems() {
+ throw new UnsupportedOperationException("A FlexCategory has no items!");
+ }
+
+}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/categories/SeasonalCategory.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/categories/SeasonalCategory.java
index e1d9710b3..21e995c18 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/categories/SeasonalCategory.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/categories/SeasonalCategory.java
@@ -4,6 +4,7 @@ import java.time.LocalDate;
import java.time.Month;
import org.bukkit.NamespacedKey;
+import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import me.mrCookieSlime.Slimefun.Objects.Category;
@@ -49,13 +50,12 @@ public class SeasonalCategory extends Category {
return month;
}
- /**
- * Checks if the category should currently be displayed in the Guide.
- * This is based on {@link SeasonalCategory#getMonth()}.
- *
- * @return true if it should, otherwise false
- */
- public boolean isVisible() {
- return month == LocalDate.now().getMonth();
+ @Override
+ public boolean isHidden(Player p) {
+ if (month != LocalDate.now().getMonth()) {
+ return true;
+ }
+
+ return super.isHidden(p);
}
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/Commands.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/Commands.java
index dc25b37d5..9e7c5894b 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/Commands.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/Commands.java
@@ -25,6 +25,5 @@ public final class Commands {
commands.add(new OpenGuideCommand(plugin, cmd));
commands.add(new SearchCommand(plugin, cmd));
commands.add(new DebugFishCommand(plugin, cmd));
- commands.add(new ElevatorCommand(plugin, cmd));
}
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/ElevatorCommand.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/ElevatorCommand.java
deleted file mode 100644
index 38f3f32c4..000000000
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/ElevatorCommand.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package io.github.thebusybiscuit.slimefun4.core.commands.subcommands;
-
-import java.util.Map;
-
-import org.bukkit.ChatColor;
-import org.bukkit.Location;
-import org.bukkit.command.CommandSender;
-import org.bukkit.entity.Player;
-
-import io.github.thebusybiscuit.cscorelib2.chat.ChatColors;
-import io.github.thebusybiscuit.slimefun4.core.commands.SlimefunCommand;
-import io.github.thebusybiscuit.slimefun4.core.commands.SubCommand;
-import io.github.thebusybiscuit.slimefun4.implementation.items.gps.ElevatorPlate;
-import me.mrCookieSlime.Slimefun.SlimefunPlugin;
-import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
-import me.mrCookieSlime.Slimefun.api.BlockStorage;
-
-class ElevatorCommand extends SubCommand {
-
- private final ElevatorPlate elevatorPlate;
-
- ElevatorCommand(SlimefunPlugin plugin, SlimefunCommand cmd) {
- super(plugin, cmd);
-
- elevatorPlate = ((ElevatorPlate) SlimefunItem.getByID("ELEVATOR_PLATE"));
- }
-
- @Override
- public void recordUsage(Map commandUsage) {
- // This command is only for internal purposes, we do not wanna record the
- // usage of this one.
- }
-
- @Override
- public String getName() {
- return "elevator";
- }
-
- @Override
- public boolean isHidden() {
- return true;
- }
-
- @Override
- public void onExecute(CommandSender sender, String[] args) {
- if (sender instanceof Player && args.length == 4) {
- Player p = (Player) sender;
-
- int x = Integer.parseInt(args[1]);
- int y = Integer.parseInt(args[2]);
- int z = Integer.parseInt(args[3]);
-
- if (BlockStorage.getLocationInfo(p.getWorld().getBlockAt(x, y, z).getLocation(), "floor") != null) {
- elevatorPlate.getUsers().add(p.getUniqueId());
- float yaw = p.getEyeLocation().getYaw() + 180;
- if (yaw > 180) yaw = -180 + (yaw - 180);
-
- p.teleport(new Location(p.getWorld(), x + 0.5, y + 0.4, z + 0.5, yaw, p.getEyeLocation().getPitch()));
-
- String floor = BlockStorage.getLocationInfo(p.getWorld().getBlockAt(x, y, z).getLocation(), "floor");
- p.sendTitle(ChatColor.RESET + ChatColors.color(floor), " ", 20, 60, 20);
- }
- }
- }
-
-}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/VersionsCommand.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/VersionsCommand.java
index b85e5e6a2..f00ca84f5 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/VersionsCommand.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/VersionsCommand.java
@@ -11,7 +11,6 @@ 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 me.mrCookieSlime.CSCoreLibPlugin.CSCoreLib;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
class VersionsCommand extends SubCommand {
@@ -35,8 +34,8 @@ class VersionsCommand extends SubCommand {
if (sender.hasPermission("slimefun.command.versions") || sender instanceof ConsoleCommandSender) {
sender.sendMessage(ChatColors.color("&a" + Bukkit.getName() + " &2" + ReflectionUtils.getVersion()));
sender.sendMessage("");
- sender.sendMessage(ChatColors.color("&aCS-CoreLib &2v" + CSCoreLib.getLib().getDescription().getVersion()));
- sender.sendMessage(ChatColors.color("&aSlimefun &2v" + plugin.getDescription().getVersion()));
+ sender.sendMessage(ChatColors.color("&aCS-CoreLib &2v" + SlimefunPlugin.getCSCoreLibVersion()));
+ sender.sendMessage(ChatColors.color("&aSlimefun &2v" + SlimefunPlugin.getVersion()));
sender.sendMessage("");
Collection addons = SlimefunPlugin.getInstalledAddons();
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/SlimefunGuide.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/SlimefunGuide.java
index 94656396b..334936907 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/SlimefunGuide.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/SlimefunGuide.java
@@ -84,11 +84,12 @@ public final class SlimefunGuide {
}
public static void openGuide(Player p, SlimefunGuideLayout layout) {
- if (!SlimefunPlugin.getWhitelist().getBoolean(p.getWorld().getName() + ".enabled")) return;
- if (!SlimefunPlugin.getWhitelist().getBoolean(p.getWorld().getName() + ".enabled-items.SLIMEFUN_GUIDE")) return;
-
- Optional optional = PlayerProfile.find(p);
+ if (!SlimefunPlugin.getWorldSettingsService().isWorldEnabled(p.getWorld())) {
+ return;
+ }
+ Optional optional = PlayerProfile.find(p);
+
if (optional.isPresent()) {
PlayerProfile profile = optional.get();
SlimefunGuideImplementation guide = SlimefunPlugin.getRegistry().getGuideLayout(layout);
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/SlimefunGuideImplementation.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/SlimefunGuideImplementation.java
index 497ac6064..7875a08fc 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/SlimefunGuideImplementation.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/SlimefunGuideImplementation.java
@@ -1,12 +1,17 @@
package io.github.thebusybiscuit.slimefun4.core.guide;
+import org.bukkit.GameMode;
+import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.implementation.guide.BookSlimefunGuide;
import io.github.thebusybiscuit.slimefun4.implementation.guide.ChestSlimefunGuide;
+import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Objects.Category;
+import me.mrCookieSlime.Slimefun.Objects.Research;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
+import me.mrCookieSlime.Slimefun.api.Slimefun;
/**
* This interface is used for the different implementations that add behaviour
@@ -48,4 +53,18 @@ public interface SlimefunGuideImplementation {
void displayItem(PlayerProfile profile, SlimefunItem item, boolean addToHistory);
+ default void unlockItem(Player p, SlimefunItem sfitem, Runnable callback) {
+ Research research = sfitem.getResearch();
+
+ if (p.getGameMode() == GameMode.CREATIVE && SlimefunPlugin.getRegistry().isFreeCreativeResearchingEnabled()) {
+ research.unlock(p, true);
+ Slimefun.runSync(callback, 5L);
+ }
+ else {
+ research.unlock(p, false);
+ p.setLevel(p.getLevel() - research.getCost());
+ Slimefun.runSync(callback, 103L);
+ }
+ }
+
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/options/SlimefunGuideSettings.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/options/SlimefunGuideSettings.java
index ffe1141af..7ad60bf5a 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/options/SlimefunGuideSettings.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/options/SlimefunGuideSettings.java
@@ -26,7 +26,6 @@ import io.github.thebusybiscuit.slimefun4.utils.ChatUtils;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
import io.github.thebusybiscuit.slimefun4.utils.PatternUtils;
-import me.mrCookieSlime.CSCoreLibPlugin.CSCoreLib;
import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
@@ -86,7 +85,7 @@ public final class SlimefunGuideSettings {
return false;
});
- menu.addItem(4, new CustomItem(Material.WRITABLE_BOOK, "&aSlimefun Version", "&7&o" + SlimefunPlugin.getLocal().getMessage(p, "guide.tooltips.versions-notice"), "", "&rMinecraft Version: &a" + Bukkit.getBukkitVersion(), "&rSlimefun Version: &a" + SlimefunPlugin.getVersion(), "&rCS-CoreLib Version: &a" + CSCoreLib.getLib().getDescription().getVersion()), ChestMenuUtils.getEmptyClickHandler());
+ menu.addItem(4, new CustomItem(Material.WRITABLE_BOOK, "&aSlimefun Version", "&7&o" + SlimefunPlugin.getLocal().getMessage(p, "guide.tooltips.versions-notice"), "", "&rMinecraft Version: &a" + Bukkit.getBukkitVersion(), "&rSlimefun Version: &a" + SlimefunPlugin.getVersion(), "&rCS-CoreLib Version: &a" + SlimefunPlugin.getCSCoreLibVersion()), ChestMenuUtils.getEmptyClickHandler());
menu.addItem(6, new CustomItem(Material.COMPARATOR, "&e" + SlimefunPlugin.getLocal().getMessage(p, "guide.title.source"), "", "&7Last Activity: &a" + NumberUtils.timeDelta(SlimefunPlugin.getGitHubService().getLastUpdate()) + " ago", "&7Forks: &e" + SlimefunPlugin.getGitHubService().getForks(), "&7Stars: &e" + SlimefunPlugin.getGitHubService().getStars(), "", "&7&oSlimefun 4 is a community project,", "&7&othe source code is available on GitHub", "&7&oand if you want to keep this Plugin alive,", "&7&othen please consider contributing to it", "", "&7\u21E8 &eClick to go to GitHub"));
menu.addMenuClickHandler(6, (pl, slot, item, action) -> {
@@ -107,11 +106,16 @@ public final class SlimefunGuideSettings {
return false;
});
- menu.addItem(49, new CustomItem(Material.REDSTONE_TORCH, "&4" + SlimefunPlugin.getLocal().getMessage(p, "guide.title.bugs"), "", "&7&oBug reports have to be made in English!", "", "&7Open Issues: &a" + SlimefunPlugin.getGitHubService().getIssues(), "&7Pending Pull Requests: &a" + SlimefunPlugin.getGitHubService().getPullRequests(), "", "&7\u21E8 &eClick to go to the Slimefun4 Bug Tracker"), (pl, slot, item, action) -> {
- pl.closeInventory();
- ChatUtils.sendURL(pl, "https://github.com/TheBusyBiscuit/Slimefun4/issues");
- return false;
- });
+ if (SlimefunPlugin.getUpdater().getBranch().isOfficial()) {
+ menu.addItem(49, new CustomItem(Material.REDSTONE_TORCH, "&4" + SlimefunPlugin.getLocal().getMessage(p, "guide.title.bugs"), "", "&7&oBug reports have to be made in English!", "", "&7Open Issues: &a" + SlimefunPlugin.getGitHubService().getIssues(), "&7Pending Pull Requests: &a" + SlimefunPlugin.getGitHubService().getPullRequests(), "", "&7\u21E8 &eClick to go to the Slimefun4 Bug Tracker"), (pl, slot, item, action) -> {
+ pl.closeInventory();
+ ChatUtils.sendURL(pl, "https://github.com/TheBusyBiscuit/Slimefun4/issues");
+ return false;
+ });
+ }
+ else {
+ menu.addItem(49, ChestMenuUtils.getBackground(), ChestMenuUtils.getEmptyClickHandler());
+ }
menu.addItem(51, new CustomItem(Material.TOTEM_OF_UNDYING, "&cSoon", "", "&7Something will be added here later..."), (pl, slot, item, action) -> {
// Add something here
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/options/package-info.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/options/package-info.java
new file mode 100644
index 000000000..87fda6b4e
--- /dev/null
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/options/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * This package contains the Settings menu forthe {@link io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuide} as
+ * well as the interface {@link io.github.thebusybiscuit.slimefun4.core.guide.options.SlimefunGuideOption} for adding
+ * your own options
+ */
+package io.github.thebusybiscuit.slimefun4.core.guide.options;
\ No newline at end of file
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/CustomTextureService.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/CustomTextureService.java
index eb0e42458..4f648d30e 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/CustomTextureService.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/CustomTextureService.java
@@ -20,15 +20,10 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
*/
public class CustomTextureService {
- private final Plugin plugin;
- private Config config;
+ private final Config config;
private boolean modified = false;
public CustomTextureService(Plugin plugin) {
- this.plugin = plugin;
- }
-
- public void load() {
config = new Config(plugin, "item-models.yml");
config.getConfiguration().options().header("This file is used to assign items from Slimefun or any of its addons\n" + "the 'CustomModelData' NBT tag. This can be used in conjunction with a custom resource pack\n" + "to give items custom textures.\n\n" + "There is no official Slimefun resource pack at the moment.");
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/LocalizationService.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/LocalizationService.java
index ad9cf285d..4383e0af6 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/LocalizationService.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/LocalizationService.java
@@ -66,8 +66,6 @@ public class LocalizationService extends SlimefunLocalization implements Persist
}
Slimefun.getLogger().log(Level.INFO, "Available languages: {0}", String.join(", ", languages.keySet()));
-
- setPrefix("&aSlimefun 4 &7> ");
save();
}
@@ -124,6 +122,7 @@ public class LocalizationService extends SlimefunLocalization implements Persist
// Clearing out the old Language (if necessary)
if (reset) {
getConfig().clear();
+ setPrefix("&aSlimefun 4 &7> ");
}
defaultLanguage.setResearches(streamConfigFile("researches_" + language + ".yml", null));
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/MinecraftRecipeService.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/MinecraftRecipeService.java
index ddde78336..8c0993c5d 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/MinecraftRecipeService.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/MinecraftRecipeService.java
@@ -4,6 +4,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
+import org.bukkit.inventory.FurnaceRecipe;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.Recipe;
import org.bukkit.inventory.RecipeChoice;
@@ -33,10 +34,22 @@ public class MinecraftRecipeService {
this.plugin = plugin;
}
- public void load() {
+ /**
+ * This method refreshes the {@link RecipeSnapshot} that is used by the {@link MinecraftRecipeService}.
+ */
+ public void refresh() {
snapshot = new RecipeSnapshot(plugin);
}
+ /**
+ * This method returns an {@link Optional} describing the output of a {@link FurnaceRecipe}
+ * with the given {@link ItemStack} as an input.
+ *
+ * @param input
+ * The input {@link ItemStack}
+ *
+ * @return An {@link Optional} describing the furnace output of the given {@link ItemStack}
+ */
public Optional getFurnaceOutput(ItemStack input) {
return snapshot.getRecipeOutput(MinecraftRecipe.FURNACE, input);
}
@@ -65,8 +78,21 @@ public class MinecraftRecipeService {
}
}
+ /**
+ * This returns an array containing all {@link Recipe Recipes} for crafting the given
+ * {@link ItemStack}.
+ *
+ * @param item
+ * The {@link ItemStack} for which to get the recipes
+ * @return An array of {@link Recipe Recipes} to craft the given {@link ItemStack}
+ */
public Recipe[] getRecipesFor(ItemStack item) {
- return snapshot.getRecipesFor(item).toArray(new Recipe[0]);
+ if (item == null) {
+ return new Recipe[0];
+ }
+ else {
+ return snapshot.getRecipesFor(item).toArray(new Recipe[0]);
+ }
}
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/PerWorldSettingsService.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/PerWorldSettingsService.java
new file mode 100644
index 000000000..d4c2d4bc2
--- /dev/null
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/PerWorldSettingsService.java
@@ -0,0 +1,190 @@
+package io.github.thebusybiscuit.slimefun4.core.services;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.logging.Level;
+
+import org.bukkit.World;
+
+import io.github.thebusybiscuit.cscorelib2.collections.OptionalMap;
+import io.github.thebusybiscuit.cscorelib2.config.Config;
+import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon;
+import me.mrCookieSlime.Slimefun.SlimefunPlugin;
+import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
+
+/**
+ * This Service is responsible for disabling a {@link SlimefunItem} in a certain {@link World}.
+ *
+ * @author TheBusyBiscuit
+ *
+ */
+public class PerWorldSettingsService {
+
+ private final SlimefunPlugin plugin;
+
+ private final OptionalMap> disabledItems = new OptionalMap<>(HashMap::new);
+ private final Map> disabledAddons = new HashMap<>();
+ private final Set disabledWorlds = new HashSet<>();
+
+ public PerWorldSettingsService(SlimefunPlugin plugin) {
+ this.plugin = plugin;
+ }
+
+ /**
+ * This method will forcefully load all currently active Worlds to load up their settings.
+ */
+ public void load(Iterable worlds) {
+ try {
+ migrate();
+ }
+ catch (IOException e) {
+ plugin.getLogger().log(Level.WARNING, "An error occured while migrating old world settings", e);
+ }
+
+ for (World world : worlds) {
+ load(world);
+ }
+ }
+
+ /**
+ * This method loads the given {@link World} if it was not loaded before.
+ *
+ * @param world
+ * The {@link World} to load
+ */
+ public void load(World world) {
+ disabledItems.putIfAbsent(world.getName(), loadWorld(world.getName()));
+ }
+
+ /**
+ * Temporary migration method for the old system
+ *
+ * @throws IOException
+ * This will be thrown if we failed to delete the old {@link File}
+ */
+ private void migrate() throws IOException {
+ Config oldConfig = new Config(plugin, "whitelist.yml");
+
+ if (oldConfig.getFile().exists()) {
+ for (String world : oldConfig.getKeys()) {
+ Config newConfig = new Config(plugin, "world-settings/" + world + ".yml");
+ newConfig.setDefaultValue("enabled", oldConfig.getBoolean(world + ".enabled"));
+
+ for (String id : oldConfig.getKeys(world + ".enabled-items")) {
+ SlimefunItem item = SlimefunItem.getByID(id);
+
+ if (item != null) {
+ String addon = item.getAddon().getName().toLowerCase(Locale.ROOT);
+ newConfig.setDefaultValue(addon + ".enabled", true);
+ newConfig.setDefaultValue(addon + '.' + id, oldConfig.getBoolean(world + ".enabled-items." + id));
+ }
+ }
+
+ newConfig.save();
+ }
+
+ Files.delete(oldConfig.getFile().toPath());
+ }
+ }
+
+ /**
+ * This method checks whether the given {@link SlimefunItem} is enabled in the given {@link World}.
+ *
+ * @param world
+ * The {@link World} to check
+ * @param item
+ * The {@link SlimefunItem} that should be checked
+ *
+ * @return Whether the given {@link SlimefunItem} is enabled in that {@link World}
+ */
+ public boolean isEnabled(World world, SlimefunItem item) {
+ Set items = disabledItems.computeIfAbsent(world.getName(), this::loadWorld);
+
+ if (disabledWorlds.contains(world.getName())) {
+ return false;
+ }
+
+ return !items.contains(item.getID());
+ }
+
+ /**
+ * This checks whether the given {@link World} is enabled or not.
+ *
+ * @param world
+ * The {@link World} to check
+ *
+ * @return Whether this {@link World} is enabled
+ */
+ public boolean isWorldEnabled(World world) {
+ loadWorld(world.getName());
+ return !disabledWorlds.contains(world.getName());
+ }
+
+ /**
+ * This method checks whether the given {@link SlimefunAddon} is enabled in that {@link World}.
+ *
+ * @param world
+ * The {@link World} to check
+ * @param addon
+ * The {@link SlimefunAddon} to check
+ *
+ * @return Whether this addon is enabled in that {@link World}
+ */
+ public boolean isAddonEnabled(World world, SlimefunAddon addon) {
+ return isWorldEnabled(world) && disabledAddons.getOrDefault(addon, Collections.emptySet()).contains(world.getName());
+ }
+
+ private Set loadWorld(String name) {
+ Optional> optional = disabledItems.get(name);
+
+ if (optional.isPresent()) {
+ return optional.get();
+ }
+ else {
+ Set items = new LinkedHashSet<>();
+ Config config = new Config(plugin, "world-settings/" + name + ".yml");
+
+ config.getConfiguration().options().header("This file is used to disable certain items in a particular world.\nYou can set any item to 'false' to disable it in the world '" + name + "'.\nYou can also disable an entire addon from Slimefun by setting the respective\nvalue of 'enabled' for that Addon.\n\nItems which are disabled in this world will not show up in the Slimefun Guide.\nYou won't be able to use these items either. Using them will result in a warning message.");
+ config.getConfiguration().options().copyHeader(true);
+ config.setDefaultValue("enabled", true);
+
+ if (config.getBoolean("enabled")) {
+ for (SlimefunItem item : SlimefunPlugin.getRegistry().getEnabledSlimefunItems()) {
+ if (item != null && item.getID() != null) {
+ String addon = item.getAddon().getName().toLowerCase(Locale.ROOT);
+ config.setDefaultValue(addon + ".enabled", true);
+ config.setDefaultValue(addon + '.' + item.getID(), true);
+
+ boolean isAddonDisabled = config.getBoolean(addon + ".enabled");
+
+ if (isAddonDisabled) {
+ Set blacklist = disabledAddons.computeIfAbsent(plugin, key -> new HashSet<>());
+ blacklist.add(name);
+ }
+
+ if (!isAddonDisabled || !config.getBoolean(addon + '.' + item.getID())) {
+ items.add(item.getID());
+ }
+ }
+ }
+
+ config.save();
+ }
+ else {
+ disabledWorlds.add(name);
+ }
+
+ return items;
+ }
+ }
+
+}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/PermissionsService.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/PermissionsService.java
index 849e4e03e..7edfe86cc 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/PermissionsService.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/PermissionsService.java
@@ -21,22 +21,11 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
*/
public class PermissionsService {
- private final SlimefunPlugin plugin;
- private Config config;
+ private final Config config;
public PermissionsService(SlimefunPlugin plugin) {
- this.plugin = plugin;
- }
-
- public void load() {
- config = new Config(plugin, "permissions.yml");
-
- config.getConfiguration().options().header(
- "This file is used to assign permission nodes to items from Slimefun or any of its addons.\n" +
- "To assign an item a certain permission node you simply have to set the 'permission' attribute\n" +
- "to your desired permission node. You can also customize the text that is displayed when a Player does not have that permission."
- );
-
+ this.config = new Config(plugin, "permissions.yml");
+ config.getConfiguration().options().header("This file is used to assign permission nodes to items from Slimefun or any of its addons.\nTo assign an item a certain permission node you simply have to set the 'permission' attribute\nto your desired permission node. You can also customize the text that is displayed when a Player does not have that permission.");
config.getConfiguration().options().copyHeader(true);
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/localization/Language.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/localization/Language.java
index ee988c487..a137e6ea0 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/localization/Language.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/localization/Language.java
@@ -1,5 +1,8 @@
package io.github.thebusybiscuit.slimefun4.core.services.localization;
+import java.util.Locale;
+
+import org.apache.commons.lang.Validate;
import org.bukkit.Server;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player;
@@ -39,10 +42,13 @@ public final class Language {
* The hash of the skull texture to use
*/
public Language(String id, String hash) {
+ Validate.notNull(id, "A Language must have an id that is not null!");
+ Validate.notNull(hash, "A Language must have a texture that is not null!");
+
this.id = id;
item = SkullItem.fromHash(hash);
- SlimefunPlugin.getItemTextureService().setTexture(item, "_UI_LANGUAGE_" + id.toUpperCase());
+ SlimefunPlugin.getItemTextureService().setTexture(item, "_UI_LANGUAGE_" + id.toUpperCase(Locale.ROOT));
}
/**
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/EmeraldEnchantsCategory.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/EmeraldEnchantsCategory.java
new file mode 100644
index 000000000..dfab32455
--- /dev/null
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/EmeraldEnchantsCategory.java
@@ -0,0 +1,29 @@
+package io.github.thebusybiscuit.slimefun4.core.services.plugins;
+
+import org.bukkit.Material;
+import org.bukkit.NamespacedKey;
+import org.bukkit.entity.Player;
+
+import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
+import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
+import io.github.thebusybiscuit.slimefun4.core.categories.FlexCategory;
+import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideLayout;
+import me.mrCookieSlime.EmeraldEnchants.EnchantmentGuide;
+
+class EmeraldEnchantsCategory extends FlexCategory {
+
+ public EmeraldEnchantsCategory(NamespacedKey key) {
+ super(key, new CustomItem(Material.ENCHANTED_BOOK, "&2EmeraldEnchants &a(Enchantment Guide)"), 2);
+ }
+
+ @Override
+ public void open(Player p, PlayerProfile profile, SlimefunGuideLayout layout) {
+ EnchantmentGuide.open(p);
+ }
+
+ @Override
+ public boolean isVisible(Player p, PlayerProfile profile, SlimefunGuideLayout layout) {
+ return true;
+ }
+
+}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/EmeraldEnchantsHook.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/EmeraldEnchantsHook.java
deleted file mode 100644
index 2d55168e5..000000000
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/EmeraldEnchantsHook.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package io.github.thebusybiscuit.slimefun4.core.services.plugins;
-
-import java.util.List;
-
-import org.bukkit.ChatColor;
-import org.bukkit.Material;
-import org.bukkit.entity.Player;
-
-import me.mrCookieSlime.CSCoreLibPlugin.PlayerRunnable;
-import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu;
-import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.Item.CustomItem;
-import me.mrCookieSlime.EmeraldEnchants.EnchantmentGuide;
-import me.mrCookieSlime.Slimefun.api.GuideHandler;
-
-// GuideHandler is deprecated and will be removed quite soon.
-// Now that this hook is in Slimefun vs. EmeraldEnchants, we can start deconstructing it.
-class EmeraldEnchantsHook implements GuideHandler {
-
- private PlayerRunnable runnable;
-
- public EmeraldEnchantsHook() {
- runnable = new PlayerRunnable(-1) {
-
- @Override
- public void run(Player p) {
- EnchantmentGuide.open(p);
- }
- };
- }
-
- @Override
- public int next(Player p, int index, ChestMenu menu) {
- menu.addItem(index, new CustomItem(Material.ENCHANTED_BOOK, "&2EmeraldEnchants &a(Enchantment Guide)", "", "&a> Click to view a List of all custom Enchantments"));
- menu.addMenuClickHandler(index, (pl, slot, item, action) -> {
- EnchantmentGuide.open(p);
- return false;
- });
-
- return index + 1;
- }
-
- @Override
- public void addEntry(List text, List tooltip) {
- text.add(ChatColor.translateAlternateColorCodes('&', "&2Enchantment Guide"));
- tooltip.add(ChatColor.translateAlternateColorCodes('&', "&aClick to open\n&aEmeraldEnchants' Enchantment Guide"));
- }
-
- @Override
- public int getTier() {
- return 1;
- }
-
- @Override
- public PlayerRunnable getRunnable() {
- return runnable;
- }
-
- @Override
- public boolean trackHistory() {
- return false;
- }
-
-}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/ThirdPartyPluginService.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/ThirdPartyPluginService.java
index 51f3129f4..56b55151e 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/ThirdPartyPluginService.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/ThirdPartyPluginService.java
@@ -1,18 +1,17 @@
package io.github.thebusybiscuit.slimefun4.core.services.plugins;
-import java.util.ArrayList;
-import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.logging.Level;
+import org.bukkit.NamespacedKey;
import org.bukkit.block.Block;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.Plugin;
import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon;
+import io.github.thebusybiscuit.slimefun4.core.categories.FlexCategory;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
-import me.mrCookieSlime.Slimefun.api.GuideHandler;
import me.mrCookieSlime.Slimefun.api.Slimefun;
/**
@@ -51,11 +50,9 @@ public class ThirdPartyPluginService {
if (isPluginInstalled("EmeraldEnchants")) {
isEmeraldEnchantsInstalled = true;
-
- GuideHandler handler = new EmeraldEnchantsHook();
- List handlers = SlimefunPlugin.getRegistry().getGuideHandlers().getOrDefault(handler.getTier(), new ArrayList<>());
- handlers.add(handler);
- SlimefunPlugin.getRegistry().getGuideHandlers().put(handler.getTier(), handlers);
+ Plugin emeraldEnchants = plugin.getServer().getPluginManager().getPlugin("EmeraldEnchants");
+ FlexCategory category = new EmeraldEnchantsCategory(new NamespacedKey(emeraldEnchants, "enchantment_guide"));
+ category.register();
}
/*
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/BookSlimefunGuide.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/BookSlimefunGuide.java
index 76ffb7d27..b47d4e783 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/BookSlimefunGuide.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/BookSlimefunGuide.java
@@ -1,37 +1,42 @@
package io.github.thebusybiscuit.slimefun4.implementation.guide;
import java.util.ArrayList;
+import java.util.LinkedList;
import java.util.List;
+import java.util.Locale;
import org.bukkit.ChatColor;
-import org.bukkit.GameMode;
import org.bukkit.Material;
+import org.bukkit.NamespacedKey;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.chat.ChatColors;
+import io.github.thebusybiscuit.cscorelib2.chat.ChatInput;
+import io.github.thebusybiscuit.cscorelib2.chat.json.ChatComponent;
+import io.github.thebusybiscuit.cscorelib2.chat.json.ClickEvent;
+import io.github.thebusybiscuit.cscorelib2.chat.json.CustomBookInterface;
+import io.github.thebusybiscuit.cscorelib2.chat.json.HoverEvent;
import io.github.thebusybiscuit.cscorelib2.inventory.ItemUtils;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
-import io.github.thebusybiscuit.slimefun4.core.categories.SeasonalCategory;
+import io.github.thebusybiscuit.slimefun4.core.categories.FlexCategory;
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuide;
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideImplementation;
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideLayout;
import io.github.thebusybiscuit.slimefun4.utils.ChatUtils;
-import me.mrCookieSlime.CSCoreLibPlugin.PlayerRunnable;
-import me.mrCookieSlime.CSCoreLibPlugin.general.Chat.TellRawMessage;
-import me.mrCookieSlime.CSCoreLibPlugin.general.Chat.TellRawMessage.HoverAction;
-import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.CustomBookOverlay;
+import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.LockedCategory;
import me.mrCookieSlime.Slimefun.Objects.Research;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
-import me.mrCookieSlime.Slimefun.api.GuideHandler;
import me.mrCookieSlime.Slimefun.api.Slimefun;
public class BookSlimefunGuide implements SlimefunGuideImplementation {
+ private final NamespacedKey guideSearch = new NamespacedKey(SlimefunPlugin.instance, "search");
+
@Override
public SlimefunGuideLayout getLayout() {
return SlimefunGuideLayout.BOOK;
@@ -42,124 +47,89 @@ public class BookSlimefunGuide implements SlimefunGuideImplementation {
return new CustomItem(new ItemStack(Material.ENCHANTED_BOOK), "&aSlimefun Guide &7(Book GUI)", "", "&eRight Click &8\u21E8 &7Browse Items", "&eShift + Right Click &8\u21E8 &7Open Settings / Credits");
}
+ private void openBook(Player p, List lines, boolean backButton) {
+ CustomBookInterface book = new CustomBookInterface(SlimefunPlugin.instance);
+ book.setTitle(SlimefunPlugin.getLocal().getMessage(p, "guide.title.main"));
+
+ for (int i = 0; i < lines.size(); i = i + 10) {
+ ChatComponent page = new ChatComponent(ChatColors.color("&b&l- " + SlimefunPlugin.getLocal().getMessage(p, "guide.title.main") + " -\n\n"));
+ page.setHoverEvent(new HoverEvent(ChestMenuUtils.getSearchButton(p)));
+
+ page.setClickEvent(new ClickEvent(guideSearch, player -> PlayerProfile.get(player, profile -> Slimefun.runSync(() -> {
+ SlimefunPlugin.getLocal().sendMessage(player, "guide.search.message");
+ ChatInput.waitForPlayer(SlimefunPlugin.instance, player, msg -> SlimefunGuide.openSearch(profile, msg, true, true));
+ }, 1))));
+
+ for (int j = i; j < lines.size() && j < i + 10; j++) {
+ page.append(lines.get(j));
+ }
+
+ page.append(new ChatComponent("\n"));
+
+ if (backButton) {
+ ChatComponent button = new ChatComponent(ChatColor.DARK_BLUE + "\u21E6 " + SlimefunPlugin.getLocal().getMessage(p, "guide.back.title"));
+ button.setHoverEvent(new HoverEvent(ChatColor.DARK_BLUE + "\u21E6 " + SlimefunPlugin.getLocal().getMessage(p, "guide.back.title"), "", ChatColor.GRAY + SlimefunPlugin.getLocal().getMessage(p, "guide.back.guide")));
+ button.setClickEvent(new ClickEvent(new NamespacedKey(SlimefunPlugin.instance, "slimefun_guide"), pl -> openMainMenu(PlayerProfile.get(pl), 1)));
+ page.append(button);
+ }
+
+ book.addPage(page);
+ }
+
+ book.open(p);
+ }
+
@Override
public void openMainMenu(PlayerProfile profile, int page) {
Player p = profile.getPlayer();
if (p == null) return;
- List pages = new ArrayList<>();
- List texts = new ArrayList<>();
- List tooltips = new ArrayList<>();
- List actions = new ArrayList<>();
-
+ List lines = new LinkedList<>();
int tier = 0;
- for (Category category : SlimefunPlugin.getRegistry().getEnabledCategories()) {
- boolean locked = true;
-
- for (SlimefunItem item : category.getItems()) {
- if (Slimefun.isEnabled(p, item, false)) {
- locked = false;
- break;
- }
- }
-
- if (!locked) {
+ for (Category category : SlimefunPlugin.getRegistry().getCategories()) {
+ if (!category.isHidden(p) && (!(category instanceof FlexCategory) || ((FlexCategory) category).isVisible(p, profile, getLayout()))) {
if (tier < category.getTier()) {
- for (GuideHandler handler : Slimefun.getGuideHandlers(tier)) {
- handler.addEntry(texts, tooltips);
- actions.add(new PlayerRunnable(2) {
-
- @Override
- public void run(Player p) {
- handler.run(p, true, true);
- }
-
- });
- }
-
tier = category.getTier();
if (tier > 1) {
- for (int i = 0; i < 10; i++) {
- if (texts.size() % 10 == 0) break;
- texts.add(" ");
- tooltips.add(null);
- actions.add(null);
+ for (int i = 0; i < 10 && lines.size() % 10 != 0; i++) {
+ lines.add(new ChatComponent("\n"));
}
}
- texts.add(ChatColors.color("&8\u21E8 &6Tier " + tier));
- tooltips.add(null);
- actions.add(null);
+ lines.add(new ChatComponent(ChatColor.DARK_GRAY + "\u21E8" + ChatColor.DARK_BLUE + " Tier " + tier + "\n"));
}
+
if (category instanceof LockedCategory && !((LockedCategory) category).hasUnlocked(p, profile)) {
- StringBuilder parents = new StringBuilder(ChatColors.color("&4&lLOCKED\n\n&7In order to unlock this Category,\n&7you need to unlock all Items from\n&7the following Categories first:\n"));
+ List lore = new LinkedList<>();
+ lore.add(ChatColor.DARK_RED + SlimefunPlugin.getLocal().getMessage(p, "guide.locked") + " " + ChatColor.GRAY + "- " + ChatColor.RESET + category.getItem(p).getItemMeta().getDisplayName());
+ lore.add("");
+
+ for (String line : SlimefunPlugin.getLocal().getMessages(p, "guide.locked-category")) {
+ lore.add(ChatColor.RESET + line);
+ }
+
+ lore.add("");
for (Category parent : ((LockedCategory) category).getParents()) {
- parents.append(ChatColors.color("\n&c" + ItemUtils.getItemName(parent.getItem(p))));
+ lore.add(parent.getItem(p).getItemMeta().getDisplayName());
}
- texts.add(ChatColors.color(ChatUtils.crop(ChatColor.RED, ItemUtils.getItemName(category.getItem(p)))));
- tooltips.add(parents.toString());
- actions.add(null);
- }
- else if (category instanceof SeasonalCategory) {
- if (((SeasonalCategory) category).isVisible()) {
- texts.add(ChatColors.color(ChatUtils.crop(ChatColor.GREEN, ItemUtils.getItemName(category.getItem(p)))));
- tooltips.add(ChatColors.color("&eClick to open the following Category:\n" + ItemUtils.getItemName(category.getItem(p))));
- actions.add(new PlayerRunnable(1) {
-
- @Override
- public void run(Player p) {
- Slimefun.runSync(() -> openCategory(profile, category, 1), 1L);
- }
-
- });
- }
+ ChatComponent chatComponent = new ChatComponent(ChatUtils.crop(ChatColor.RED, ItemUtils.getItemName(category.getItem(p))) + "\n");
+ chatComponent.setHoverEvent(new HoverEvent(lore));
+ lines.add(chatComponent);
}
else {
- texts.add(ChatColors.color(ChatUtils.crop(ChatColor.GREEN, ItemUtils.getItemName(category.getItem(p)))));
- tooltips.add(ChatColors.color("&eClick to open the following Category:\n" + ItemUtils.getItemName(category.getItem(p))));
- actions.add(new PlayerRunnable(1) {
-
- @Override
- public void run(Player p) {
- Slimefun.runSync(() -> openCategory(profile, category, 1), 1L);
- }
-
- });
+ ChatComponent chatComponent = new ChatComponent(ChatUtils.crop(ChatColor.DARK_GREEN, ItemUtils.getItemName(category.getItem(p))) + "\n");
+ chatComponent.setHoverEvent(new HoverEvent(ItemUtils.getItemName(category.getItem(p)), "", ChatColor.GRAY + "\u21E8 " + ChatColor.GREEN + SlimefunPlugin.getLocal().getMessage(p, "guide.tooltips.open-category")));
+ chatComponent.setClickEvent(new ClickEvent(category.getKey(), pl -> openCategory(profile, category, 1)));
+ lines.add(chatComponent);
}
}
}
- for (GuideHandler handler : Slimefun.getGuideHandlers(tier)) {
- handler.addEntry(texts, tooltips);
- actions.add(new PlayerRunnable(2) {
-
- @Override
- public void run(Player p) {
- handler.run(p, true, true);
- }
-
- });
- }
-
- for (int i = 0; i < texts.size(); i = i + 10) {
- TellRawMessage pageMessage = new TellRawMessage();
- pageMessage.addText(ChatColors.color("&b&l- Slimefun Guide -\n\n"));
-
- for (int j = i; j < texts.size() && j < i + 10; j++) {
- pageMessage.addText(texts.get(j) + "\n");
-
- if (tooltips.get(j) != null) pageMessage.addHoverEvent(HoverAction.SHOW_TEXT, tooltips.get(j));
- if (actions.get(j) != null) pageMessage.addClickEvent(actions.get(j));
- }
-
- pages.add(pageMessage);
- }
-
- new CustomBookOverlay("Slimefun Guide", "TheBusyBiscuit", pages.toArray(new TellRawMessage[0])).open(p);
+ openBook(p, lines, false);
}
@Override
@@ -167,110 +137,70 @@ public class BookSlimefunGuide implements SlimefunGuideImplementation {
Player p = profile.getPlayer();
if (p == null) return;
- if (category.getItems().size() < 250) {
+ if (category instanceof FlexCategory) {
+ ((FlexCategory) category).open(p, profile, getLayout());
+ }
+ else if (category.getItems().size() < 250) {
profile.getGuideHistory().add(category, page);
- List pages = new ArrayList<>();
- List texts = new ArrayList<>();
- List tooltips = new ArrayList<>();
- List actions = new ArrayList<>();
+ List lines = new LinkedList<>();
for (SlimefunItem item : category.getItems()) {
if (Slimefun.hasPermission(p, item, false)) {
if (Slimefun.isEnabled(p, item, false)) {
+ NamespacedKey key = new NamespacedKey(SlimefunPlugin.instance, item.getID().toLowerCase(Locale.ROOT));
+
if (!Slimefun.hasUnlocked(p, item, false) && item.getResearch() != null) {
Research research = item.getResearch();
- texts.add(ChatColors.color(ChatUtils.crop(ChatColor.GRAY, item.getItemName())));
- tooltips.add(ChatColors.color(item.getItemName() + "\n&c&lLOCKED\n\n&7Cost: " + (p.getLevel() >= research.getCost() ? "&b" : "&4") + research.getCost() + " Levels\n\n&a> Click to unlock"));
- actions.add(new PlayerRunnable(2) {
-
- @Override
- public void run(Player p) {
- if (!SlimefunPlugin.getRegistry().getCurrentlyResearchingPlayers().contains(p.getUniqueId())) {
- if (research.canUnlock(p)) {
- if (profile.hasUnlocked(research)) {
- openCategory(profile, category, page);
- }
- else {
- if (!(p.getGameMode() == GameMode.CREATIVE && SlimefunPlugin.getRegistry().isFreeCreativeResearchingEnabled())) {
- p.setLevel(p.getLevel() - research.getCost());
- }
-
- if (p.getGameMode() == GameMode.CREATIVE) {
- research.unlock(p, true);
-
- Slimefun.runSync(() -> openCategory(profile, category, page), 1L);
- }
- else {
- research.unlock(p, false);
- Slimefun.runSync(() -> openCategory(profile, category, page), 103L);
- }
- }
+ ChatComponent component = new ChatComponent(ChatUtils.crop(ChatColor.RED, item.getItemName()) + "\n");
+ component.setHoverEvent(new HoverEvent(ChatColor.RESET + item.getItemName(), ChatColor.DARK_RED.toString() + ChatColor.BOLD + SlimefunPlugin.getLocal().getMessage(p, "guide.locked"), "", ChatColor.GREEN + "> Click to unlock", "", ChatColor.GRAY + "Cost: " + ChatColor.AQUA.toString() + research.getCost() + " Level(s)"));
+ component.setClickEvent(new ClickEvent(key, player -> Slimefun.runSync(() -> {
+ if (!SlimefunPlugin.getRegistry().getCurrentlyResearchingPlayers().contains(p.getUniqueId())) {
+ if (research.canUnlock(p)) {
+ if (profile.hasUnlocked(research)) {
+ openCategory(profile, category, page);
+ }
+ else {
+ unlockItem(p, item, () -> openCategory(profile, category, page));
}
- else SlimefunPlugin.getLocal().sendMessage(p, "messages.not-enough-xp", true);
}
+ else SlimefunPlugin.getLocal().sendMessage(p, "messages.not-enough-xp", true);
}
- });
+ })));
+
+ lines.add(component);
}
else {
- texts.add(ChatColors.color(ChatUtils.crop(ChatColor.GREEN, item.getItemName())));
+ ChatComponent component = new ChatComponent(ChatUtils.crop(ChatColor.DARK_GREEN, item.getItemName()) + "\n");
- StringBuilder tooltip = new StringBuilder();
- tooltip.append(item.getItemName());
+ List lore = new ArrayList<>();
+ lore.add(item.getItemName());
if (item.getItem().hasItemMeta() && item.getItem().getItemMeta().hasLore()) {
- for (String line : item.getItem().getItemMeta().getLore()) {
- tooltip.append('\n').append(line);
- }
+ lore.addAll(item.getItem().getItemMeta().getLore());
}
- tooltip.append(ChatColors.color("\n\n&e&oClick for more Info"));
-
- tooltips.add(tooltip.toString());
- actions.add(new PlayerRunnable(2) {
-
- @Override
- public void run(Player p) {
- displayItem(profile, item, true);
- }
-
- });
+ component.setHoverEvent(new HoverEvent(lore));
+ component.setClickEvent(new ClickEvent(key, player -> Slimefun.runSync(() -> displayItem(profile, item, true))));
+ lines.add(component);
}
}
}
else {
- texts.add(ChatColors.color(ChatUtils.crop(ChatColor.DARK_RED, ItemUtils.getItemName(item.getItem()))));
- tooltips.add(ChatColors.color("&cNo Permission!"));
- actions.add(null);
+ ChatComponent component = new ChatComponent(ChatUtils.crop(ChatColor.DARK_RED, ItemUtils.getItemName(item.getItem())) + "\n");
+
+ List lore = new ArrayList<>();
+ lore.add(ChatColor.DARK_RED + ChatColor.stripColor(ItemUtils.getItemName(item.getItem())));
+ lore.add("");
+ lore.addAll(SlimefunPlugin.getPermissionsService().getLore(item));
+
+ component.setHoverEvent(new HoverEvent(lore));
+ lines.add(component);
}
}
- for (int i = 0; i < texts.size(); i = i + 10) {
- TellRawMessage pageMessage = new TellRawMessage();
- pageMessage.addText(ChatColors.color("&b&l- Slimefun Guide -\n\n"));
-
- for (int j = i; j < texts.size() && j < i + 10; j++) {
- pageMessage.addText(texts.get(j) + "\n");
- if (tooltips.get(j) != null) pageMessage.addHoverEvent(HoverAction.SHOW_TEXT, tooltips.get(j));
- if (actions.get(j) != null) pageMessage.addClickEvent(actions.get(j));
- }
-
- pageMessage.addText("\n");
- pageMessage.addText(ChatColors.color("&6\u21E6 &lBack"));
- pageMessage.addHoverEvent(HoverAction.SHOW_TEXT, ChatColors.color("&eClick to go back to the Category Overview"));
- pageMessage.addClickEvent(new PlayerRunnable(2) {
-
- @Override
- public void run(Player p) {
- openMainMenu(profile, 1);
- }
-
- });
- pages.add(pageMessage);
- }
-
- new CustomBookOverlay("Slimefun Guide", "TheBusyBiscuit", pages.toArray(new TellRawMessage[0])).open(p);
+ openBook(p, lines, true);
}
else {
p.sendMessage(ChatColor.RED + "That Category is too big to open :/");
@@ -279,6 +209,7 @@ public class BookSlimefunGuide implements SlimefunGuideImplementation {
@Override
public void openSearch(PlayerProfile profile, String input, boolean addToHistory) {
+ // We need to write a book implementation for this at some point
SlimefunGuide.openSearch(profile, input, true, addToHistory);
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/CheatSheetSlimefunGuide.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/CheatSheetSlimefunGuide.java
index 084eb7255..b717f99f6 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/CheatSheetSlimefunGuide.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/CheatSheetSlimefunGuide.java
@@ -1,6 +1,11 @@
package io.github.thebusybiscuit.slimefun4.implementation.guide;
+import org.bukkit.entity.Player;
+
+import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideLayout;
+import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
+import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu;
public class CheatSheetSlimefunGuide extends ChestSlimefunGuide {
@@ -17,4 +22,13 @@ public class CheatSheetSlimefunGuide extends ChestSlimefunGuide {
public SlimefunGuideLayout getLayout() {
return SlimefunGuideLayout.CHEAT_SHEET;
}
+
+ @Override
+ protected void createHeader(Player p, PlayerProfile profile, ChestMenu menu) {
+ super.createHeader(p, profile, menu);
+
+ // Remove Settings Panel
+ menu.addItem(1, ChestMenuUtils.getBackground());
+ menu.addMenuClickHandler(1, ChestMenuUtils.getEmptyClickHandler());
+ }
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/ChestSlimefunGuide.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/ChestSlimefunGuide.java
index 018b07be6..94739d780 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/ChestSlimefunGuide.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/ChestSlimefunGuide.java
@@ -2,13 +2,13 @@ package io.github.thebusybiscuit.slimefun4.implementation.guide;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.LinkedList;
import java.util.List;
+import java.util.Locale;
import java.util.Optional;
import java.util.logging.Level;
-import java.util.stream.Collectors;
import org.bukkit.ChatColor;
-import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.Tag;
@@ -27,7 +27,7 @@ import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion;
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.core.MultiBlock;
import io.github.thebusybiscuit.slimefun4.core.attributes.RecipeDisplayItem;
-import io.github.thebusybiscuit.slimefun4.core.categories.SeasonalCategory;
+import io.github.thebusybiscuit.slimefun4.core.categories.FlexCategory;
import io.github.thebusybiscuit.slimefun4.core.guide.GuideHistory;
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuide;
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideImplementation;
@@ -44,7 +44,6 @@ import me.mrCookieSlime.Slimefun.Objects.LockedCategory;
import me.mrCookieSlime.Slimefun.Objects.Research;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.multiblocks.MultiBlockMachine;
-import me.mrCookieSlime.Slimefun.api.GuideHandler;
import me.mrCookieSlime.Slimefun.api.Slimefun;
public class ChestSlimefunGuide implements SlimefunGuideImplementation {
@@ -80,6 +79,18 @@ public class ChestSlimefunGuide implements SlimefunGuideImplementation {
return true;
}
+ private List getVisibleCategories(Player p, PlayerProfile profile) {
+ List categories = new LinkedList<>();
+
+ for (Category category : SlimefunPlugin.getRegistry().getCategories()) {
+ if (!category.isHidden(p) && (!(category instanceof FlexCategory) || ((FlexCategory) category).isVisible(p, profile, getLayout()))) {
+ categories.add(category);
+ }
+ }
+
+ return categories;
+ }
+
@Override
public void openMainMenu(PlayerProfile profile, int page) {
Player p = profile.getPlayer();
@@ -91,31 +102,23 @@ public class ChestSlimefunGuide implements SlimefunGuideImplementation {
ChestMenu menu = create(p);
- List categories = SlimefunPlugin.getRegistry().getEnabledCategories();
- List handlers = SlimefunPlugin.getRegistry().getGuideHandlers().values().stream().flatMap(List::stream).collect(Collectors.toList());
+ List categories = getVisibleCategories(p, profile);
int index = 9;
- int pages = (categories.size() + handlers.size() - 1) / CATEGORY_SIZE + 1;
-
createHeader(p, profile, menu);
int target = (CATEGORY_SIZE * (page - 1)) - 1;
- while (target < (categories.size() + handlers.size() - 1) && index < CATEGORY_SIZE + 9) {
+ while (target < (categories.size() - 1) && index < CATEGORY_SIZE + 9) {
target++;
+ Category category = categories.get(target);
- if (target >= categories.size()) {
- index = handlers.get(target - categories.size()).next(p, index, menu);
- }
- else {
- Category category = categories.get(target);
-
- if (!category.isHidden(p) && displayCategory(menu, p, profile, category, index)) {
- index++;
- }
- }
+ displayCategory(menu, p, profile, category, index);
+ index++;
}
+ int pages = target == categories.size() - 1 ? page : (categories.size() - 1) / CATEGORY_SIZE + 1;
+
menu.addItem(46, ChestMenuUtils.getPreviousButton(p, page, pages));
menu.addMenuClickHandler(46, (pl, slot, item, action) -> {
int next = page - 1;
@@ -133,19 +136,13 @@ public class ChestSlimefunGuide implements SlimefunGuideImplementation {
menu.open(p);
}
- private boolean displayCategory(ChestMenu menu, Player p, PlayerProfile profile, Category category, int index) {
+ private void displayCategory(ChestMenu menu, Player p, PlayerProfile profile, Category category, int index) {
if (!(category instanceof LockedCategory)) {
- if (!(category instanceof SeasonalCategory) || ((SeasonalCategory) category).isVisible()) {
- menu.addItem(index, category.getItem(p));
- menu.addMenuClickHandler(index, (pl, slot, item, action) -> {
- openCategory(profile, category, 1);
- return false;
- });
-
- return true;
- }
-
- return false;
+ menu.addItem(index, category.getItem(p));
+ menu.addMenuClickHandler(index, (pl, slot, item, action) -> {
+ openCategory(profile, category, 1);
+ return false;
+ });
}
else if (!isSurvivalMode() || ((LockedCategory) category).hasUnlocked(p, profile)) {
menu.addItem(index, category.getItem(p));
@@ -153,8 +150,6 @@ public class ChestSlimefunGuide implements SlimefunGuideImplementation {
openCategory(profile, category, 1);
return false;
});
-
- return true;
}
else {
List lore = new ArrayList<>();
@@ -172,7 +167,6 @@ public class ChestSlimefunGuide implements SlimefunGuideImplementation {
menu.addItem(index, new CustomItem(Material.BARRIER, "&4" + SlimefunPlugin.getLocal().getMessage(p, "guide.locked") + " &7- &r" + category.getItem(p).getItemMeta().getDisplayName(), lore.toArray(new String[0])));
menu.addMenuClickHandler(index, ChestMenuUtils.getEmptyClickHandler());
- return true;
}
}
@@ -181,6 +175,11 @@ public class ChestSlimefunGuide implements SlimefunGuideImplementation {
Player p = profile.getPlayer();
if (p == null) return;
+ if (category instanceof FlexCategory) {
+ ((FlexCategory) category).open(p, profile, getLayout());
+ return;
+ }
+
if (isSurvivalMode()) {
profile.getGuideHistory().add(category, page);
}
@@ -224,7 +223,7 @@ public class ChestSlimefunGuide implements SlimefunGuideImplementation {
if (isSurvivalMode() && research != null && !profile.hasUnlocked(research)) {
if (Slimefun.hasPermission(p, sfitem, false)) {
- menu.addItem(index, new CustomItem(Material.BARRIER, "&r" + ItemUtils.getItemName(sfitem.getItem()), "&4&l" + SlimefunPlugin.getLocal().getMessage(p, "guide.locked"), "", "&a> Click to unlock", "", "&7Cost: &b" + research.getCost() + " Level"));
+ menu.addItem(index, new CustomItem(Material.BARRIER, "&r" + ItemUtils.getItemName(sfitem.getItem()), "&4&l" + SlimefunPlugin.getLocal().getMessage(p, "guide.locked"), "", "&a> Click to unlock", "", "&7Cost: &b" + research.getCost() + " Level(s)"));
menu.addMenuClickHandler(index, (pl, slot, item, action) -> {
if (!SlimefunPlugin.getRegistry().getCurrentlyResearchingPlayers().contains(pl.getUniqueId())) {
if (research.canUnlock(pl)) {
@@ -232,18 +231,7 @@ public class ChestSlimefunGuide implements SlimefunGuideImplementation {
openCategory(profile, category, page);
}
else {
- if (!(pl.getGameMode() == GameMode.CREATIVE && SlimefunPlugin.getRegistry().isFreeCreativeResearchingEnabled())) {
- pl.setLevel(pl.getLevel() - research.getCost());
- }
-
- if (pl.getGameMode() == GameMode.CREATIVE) {
- research.unlock(pl, SlimefunPlugin.getRegistry().isFreeCreativeResearchingEnabled());
- Slimefun.runSync(() -> openCategory(profile, category, page), 5L);
- }
- else {
- research.unlock(pl, false);
- Slimefun.runSync(() -> openCategory(profile, category, page), 103L);
- }
+ unlockItem(pl, sfitem, () -> openCategory(profile, category, page));
}
}
else {
@@ -299,7 +287,7 @@ public class ChestSlimefunGuide implements SlimefunGuideImplementation {
if (p == null) return;
ChestMenu menu = new ChestMenu(SlimefunPlugin.getLocal().getMessage(p, "guide.search.inventory").replace("%item%", ChatUtils.crop(ChatColor.RESET, input)));
- String searchTerm = input.toLowerCase();
+ String searchTerm = input.toLowerCase(Locale.ROOT);
if (addToHistory) {
profile.getGuideHistory().add(searchTerm);
@@ -312,7 +300,7 @@ public class ChestSlimefunGuide implements SlimefunGuideImplementation {
int index = 9;
// Find items and add them
for (SlimefunItem item : SlimefunPlugin.getRegistry().getEnabledSlimefunItems()) {
- String itemName = ChatColor.stripColor(item.getItemName()).toLowerCase();
+ String itemName = ChatColor.stripColor(item.getItemName()).toLowerCase(Locale.ROOT);
if (index == 44) break;
@@ -534,7 +522,7 @@ public class ChestSlimefunGuide implements SlimefunGuideImplementation {
menu.addItem(16, output, ChestMenuUtils.getEmptyClickHandler());
}
- private void createHeader(Player p, PlayerProfile profile, ChestMenu menu) {
+ protected void createHeader(Player p, PlayerProfile profile, ChestMenu menu) {
for (int i = 0; i < 9; i++) {
menu.addItem(i, ChestMenuUtils.getBackground(), ChestMenuUtils.getEmptyClickHandler());
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/EnhancedFurnace.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/EnhancedFurnace.java
index eb76caf56..ee358a947 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/EnhancedFurnace.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/blocks/EnhancedFurnace.java
@@ -72,8 +72,12 @@ public class EnhancedFurnace extends SimpleSlimefunItem {
if (furnace.getCookTime() > 0) {
int newCookTime = furnace.getCookTime() + getSpeed() * 10;
- if (newCookTime > 200) furnace.setCookTime((short) 188);
- else furnace.setCookTime((short) newCookTime);
+ if (newCookTime > 200) {
+ furnace.setCookTime((short) 188);
+ }
+ else {
+ furnace.setCookTime((short) newCookTime);
+ }
furnace.update(true, false);
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AnimalGrowthAccelerator.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AnimalGrowthAccelerator.java
index 2382ec120..9214bdfbb 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AnimalGrowthAccelerator.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AnimalGrowthAccelerator.java
@@ -11,6 +11,7 @@ import org.bukkit.inventory.ItemStack;
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.utils.ChestMenuUtils;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
@@ -53,7 +54,7 @@ public class AnimalGrowthAccelerator extends SlimefunItem implements InventoryBl
private void constructMenu(BlockMenuPreset preset) {
for (int i : border) {
- preset.addItem(i, new CustomItem(new ItemStack(Material.CYAN_STAINED_GLASS_PANE), " "), (p, slot, item, action) -> false);
+ preset.addItem(i, new CustomItem(new ItemStack(Material.CYAN_STAINED_GLASS_PANE), " "), ChestMenuUtils.getEmptyClickHandler());
}
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/ElectricGoldPan.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/ElectricGoldPan.java
index b7015c7e4..0b19f97bb 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/ElectricGoldPan.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/ElectricGoldPan.java
@@ -1,15 +1,15 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines;
-import java.util.Arrays;
+import java.util.ArrayList;
import java.util.List;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.inventory.ItemStack;
-import io.github.thebusybiscuit.cscorelib2.collections.RandomizedSet;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.slimefun4.core.attributes.RecipeDisplayItem;
+import io.github.thebusybiscuit.slimefun4.implementation.items.tools.GoldPan;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
@@ -18,151 +18,112 @@ import me.mrCookieSlime.Slimefun.Objects.Category;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AContainer;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineRecipe;
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;
public abstract class ElectricGoldPan extends AContainer implements RecipeDisplayItem {
- private final RandomizedSet randomizer = new RandomizedSet<>();
- private final RandomizedSet randomizerNether = new RandomizedSet<>();
-
- private final List displayRecipes = Arrays.asList(
- new ItemStack(Material.GRAVEL), new ItemStack(Material.FLINT),
- new ItemStack(Material.GRAVEL), SlimefunItems.SIFTED_ORE,
- new ItemStack(Material.GRAVEL), new ItemStack(Material.CLAY_BALL),
- new ItemStack(Material.GRAVEL), new ItemStack(Material.IRON_NUGGET),
-
- new ItemStack(Material.SOUL_SAND), new ItemStack(Material.QUARTZ),
- new ItemStack(Material.SOUL_SAND), new ItemStack(Material.GOLD_NUGGET),
- new ItemStack(Material.SOUL_SAND), new ItemStack(Material.NETHER_WART),
- new ItemStack(Material.SOUL_SAND), new ItemStack(Material.BLAZE_POWDER),
- new ItemStack(Material.SOUL_SAND), new ItemStack(Material.GLOWSTONE_DUST),
- new ItemStack(Material.SOUL_SAND), new ItemStack(Material.GHAST_TEAR)
- );
-
- public ElectricGoldPan(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
- super(category, item, recipeType, recipe);
- }
-
- @Override
- public void postRegister() {
- super.postRegister();
-
- String goldPan = "GOLD_PAN";
- String netherGoldPan = "NETHER_GOLD_PAN";
-
- add(false, SlimefunItems.SIFTED_ORE, (int) Slimefun.getItemValue(goldPan, "chance.SIFTED_ORE"));
- add(false, new ItemStack(Material.CLAY_BALL), (int) Slimefun.getItemValue(goldPan, "chance.CLAY"));
- add(false, new ItemStack(Material.FLINT), (int) Slimefun.getItemValue(goldPan, "chance.FLINT"));
- add(false, new ItemStack(Material.IRON_NUGGET), (int) Slimefun.getItemValue(goldPan, "chance.IRON_NUGGET"));
-
- add(true, new ItemStack(Material.QUARTZ), (int) Slimefun.getItemValue(netherGoldPan, "chance.QUARTZ"));
- add(true, new ItemStack(Material.GOLD_NUGGET), (int) Slimefun.getItemValue(netherGoldPan, "chance.GOLD_NUGGET"));
- add(true, new ItemStack(Material.NETHER_WART), (int) Slimefun.getItemValue(netherGoldPan, "chance.NETHER_WART"));
- add(true, new ItemStack(Material.BLAZE_POWDER), (int) Slimefun.getItemValue(netherGoldPan, "chance.BLAZE_POWDER"));
- add(true, new ItemStack(Material.GLOWSTONE_DUST), (int) Slimefun.getItemValue(netherGoldPan, "chance.GLOWSTONE_DUST"));
- add(true, new ItemStack(Material.GHAST_TEAR), (int) Slimefun.getItemValue(netherGoldPan, "chance.GHAST_TEAR"));
- }
-
- private void add(boolean nether, ItemStack item, int chance) {
- if (nether) {
- randomizerNether.add(item, chance);
- }
- else {
- randomizer.add(item, chance);
- }
- }
+ private final GoldPan goldPan = (GoldPan) SlimefunItems.GOLD_PAN.getItem();
+ private final GoldPan netherGoldPan = (GoldPan) SlimefunItems.NETHER_GOLD_PAN.getItem();
- @Override
- public String getInventoryTitle() {
- return "&6Electric Gold Pan";
- }
-
- @Override
- public ItemStack getProgressBar() {
- return new ItemStack(Material.DIAMOND_SHOVEL);
- }
-
- public abstract int getSpeed();
-
- @Override
- protected void tick(Block b) {
- BlockMenu menu = BlockStorage.getInventory(b);
-
- if (isProcessing(b)) {
- int timeleft = progress.get(b);
-
- if (timeleft > 0 && getSpeed() < 10) {
- ChestMenuUtils.updateProgressbar(menu, 22, timeleft, processing.get(b).getTicks(), getProgressBar());
-
- if (ChargableBlock.isChargable(b)) {
- if (ChargableBlock.getCharge(b) < getEnergyConsumption()) return;
- ChargableBlock.addCharge(b, -getEnergyConsumption());
- progress.put(b, timeleft - 1);
- }
- else progress.put(b, timeleft - 1);
- }
- else if (ChargableBlock.isChargable(b)) {
- if (ChargableBlock.getCharge(b) < getEnergyConsumption()) return;
- ChargableBlock.addCharge(b, -getEnergyConsumption());
-
- menu.replaceExistingItem(22, new CustomItem(new ItemStack(Material.BLACK_STAINED_GLASS_PANE), " "));
- menu.pushItem(processing.get(b).getOutput()[0].clone(), getOutputSlots());
-
- progress.remove(b);
- processing.remove(b);
- }
- }
- else {
- for (int slot : getInputSlots()) {
- if (process(b, menu, slot)) {
- break;
- }
- }
- }
- }
-
- private boolean process(Block b, BlockMenu menu, int slot) {
- if (SlimefunUtils.isItemSimilar(menu.getItemInSlot(slot), new ItemStack(Material.GRAVEL), true)) {
- ItemStack output = randomizer.getRandom();
-
- MachineRecipe r = new MachineRecipe(3 / getSpeed(), new ItemStack[0], new ItemStack[] {output});
-
- if (menu.fits(output, getOutputSlots())) {
- menu.consumeItem(slot);
- processing.put(b, r);
- progress.put(b, r.getTicks());
- }
-
- return true;
- }
- else if (SlimefunUtils.isItemSimilar(menu.getItemInSlot(slot), new ItemStack(Material.SOUL_SAND), true)) {
- ItemStack output = randomizerNether.getRandom();
-
- MachineRecipe r = new MachineRecipe(4 / getSpeed(), new ItemStack[0], new ItemStack[] {output});
-
- if (menu.fits(output, getOutputSlots())) {
- menu.consumeItem(slot);
- processing.put(b, r);
- progress.put(b, r.getTicks());
- }
-
- return true;
- }
-
- return false;
+ public ElectricGoldPan(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
+ super(category, item, recipeType, recipe);
}
@Override
- public String getMachineIdentifier() {
- return "ELECTRIC_GOLD_PAN";
- }
-
- @Override
- public List getDisplayRecipes() {
- return displayRecipes;
- }
+ public List getDisplayRecipes() {
+ List recipes = new ArrayList<>();
+
+ recipes.addAll(goldPan.getDisplayRecipes());
+ recipes.addAll(netherGoldPan.getDisplayRecipes());
+
+ return recipes;
+ }
+
+ @Override
+ public String getInventoryTitle() {
+ return "&6Electric Gold Pan";
+ }
+
+ @Override
+ public ItemStack getProgressBar() {
+ return new ItemStack(Material.DIAMOND_SHOVEL);
+ }
+
+ public abstract int getSpeed();
+
+ @Override
+ protected void tick(Block b) {
+ BlockMenu menu = BlockStorage.getInventory(b);
+
+ if (isProcessing(b)) {
+ int timeleft = progress.get(b);
+
+ if (timeleft > 0 && getSpeed() < 10) {
+ ChestMenuUtils.updateProgressbar(menu, 22, timeleft, processing.get(b).getTicks(), getProgressBar());
+
+ if (ChargableBlock.isChargable(b)) {
+ if (ChargableBlock.getCharge(b) < getEnergyConsumption()) return;
+ ChargableBlock.addCharge(b, -getEnergyConsumption());
+ progress.put(b, timeleft - 1);
+ }
+ else progress.put(b, timeleft - 1);
+ }
+ else if (ChargableBlock.isChargable(b)) {
+ if (ChargableBlock.getCharge(b) < getEnergyConsumption()) return;
+ ChargableBlock.addCharge(b, -getEnergyConsumption());
+
+ menu.replaceExistingItem(22, new CustomItem(new ItemStack(Material.BLACK_STAINED_GLASS_PANE), " "));
+ menu.pushItem(processing.get(b).getOutput()[0].clone(), getOutputSlots());
+
+ progress.remove(b);
+ processing.remove(b);
+ }
+ }
+ else {
+ for (int slot : getInputSlots()) {
+ if (process(b, menu, slot)) {
+ break;
+ }
+ }
+ }
+ }
+
+ private boolean process(Block b, BlockMenu menu, int slot) {
+ if (SlimefunUtils.isItemSimilar(menu.getItemInSlot(slot), new ItemStack(Material.GRAVEL), true)) {
+ ItemStack output = goldPan.getRandomOutput();
+
+ MachineRecipe r = new MachineRecipe(3 / getSpeed(), new ItemStack[0], new ItemStack[] { output });
+
+ if (menu.fits(output, getOutputSlots())) {
+ menu.consumeItem(slot);
+ processing.put(b, r);
+ progress.put(b, r.getTicks());
+ }
+
+ return true;
+ }
+ else if (SlimefunUtils.isItemSimilar(menu.getItemInSlot(slot), new ItemStack(Material.SOUL_SAND), true)) {
+ ItemStack output = netherGoldPan.getRandomOutput();
+
+ MachineRecipe r = new MachineRecipe(4 / getSpeed(), new ItemStack[0], new ItemStack[] { output });
+
+ if (menu.fits(output, getOutputSlots())) {
+ menu.consumeItem(slot);
+ processing.put(b, r);
+ progress.put(b, r.getTicks());
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public String getMachineIdentifier() {
+ return "ELECTRIC_GOLD_PAN";
+ }
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/ElectricPress.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/ElectricPress.java
index a534b1717..9c9d54a5c 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/ElectricPress.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/ElectricPress.java
@@ -23,6 +23,7 @@ public abstract class ElectricPress extends AContainer implements RecipeDisplayI
addRecipe(4, new ItemStack(Material.FLINT, 6), new ItemStack(Material.COBBLESTONE));
addRecipe(5, new ItemStack(Material.GLASS), new ItemStack(Material.GLASS_PANE, 3));
addRecipe(4, new ItemStack(Material.SNOWBALL, 4), new ItemStack(Material.SNOW_BLOCK));
+ addRecipe(4, new ItemStack(Material.MAGMA_CREAM, 4), new ItemStack(Material.MAGMA_BLOCK));
addRecipe(6, SlimefunItems.COPPER_INGOT, new CustomItem(SlimefunItems.COPPER_WIRE, 3));
addRecipe(16, new CustomItem(SlimefunItems.STEEL_INGOT, 8), SlimefunItems.STEEL_PLATE);
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/package-info.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/package-info.java
new file mode 100644
index 000000000..99392e2a9
--- /dev/null
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/package-info.java
@@ -0,0 +1,8 @@
+/**
+ * This package holds implementations of any {@link me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem} that
+ * deals with the {@link io.github.thebusybiscuit.slimefun4.api.geo.GEOResource} API.
+ * The most prominent example of this being the
+ * {@link io.github.thebusybiscuit.slimefun4.implementation.items.geo.GEOScanner} and the
+ * {@link io.github.thebusybiscuit.slimefun4.implementation.items.geo.GEOMiner}.
+ */
+package io.github.thebusybiscuit.slimefun4.implementation.items.geo;
\ No newline at end of file
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/gps/ElevatorPlate.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/gps/ElevatorPlate.java
index 01bce2dff..b1e720c0a 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/gps/ElevatorPlate.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/gps/ElevatorPlate.java
@@ -7,7 +7,9 @@ import java.util.Set;
import java.util.UUID;
import org.bukkit.ChatColor;
+import org.bukkit.Location;
import org.bukkit.Material;
+import org.bukkit.NamespacedKey;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
@@ -15,7 +17,6 @@ import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.cscorelib2.chat.ChatColors;
import io.github.thebusybiscuit.cscorelib2.chat.json.ChatComponent;
import io.github.thebusybiscuit.cscorelib2.chat.json.ClickEvent;
-import io.github.thebusybiscuit.cscorelib2.chat.json.ClickEventAction;
import io.github.thebusybiscuit.cscorelib2.chat.json.CustomBookInterface;
import io.github.thebusybiscuit.cscorelib2.chat.json.HoverEvent;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
@@ -30,11 +31,13 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.UnregisterReason;
import me.mrCookieSlime.Slimefun.Objects.handlers.BlockUseHandler;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
+import me.mrCookieSlime.Slimefun.api.Slimefun;
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
public class ElevatorPlate extends SimpleSlimefunItem {
private final Set users = new HashSet<>();
+ private final NamespacedKey elevatorKey = new NamespacedKey(SlimefunPlugin.instance, "elevator");
public ElevatorPlate(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, ItemStack recipeOutput) {
super(category, item, recipeType, recipe, recipeOutput);
@@ -104,7 +107,9 @@ public class ElevatorPlate extends SimpleSlimefunItem {
for (int i = 0; i < floors.size(); i++) {
if (i % 10 == 0) {
- if (page != null) book.addPage(page);
+ if (page != null) {
+ book.addPage(page);
+ }
page = new ChatComponent(ChatColors.color(SlimefunPlugin.getLocal().getMessage(p, "machines.ELEVATOR.pick-a-floor")) + "\n");
}
@@ -115,18 +120,32 @@ public class ElevatorPlate extends SimpleSlimefunItem {
if (block.getY() == b.getY()) {
line = new ChatComponent("\n" + ChatColor.GRAY + "> " + (floors.size() - i) + ". " + ChatColor.RESET + floor);
- line.setHoverEvent(new HoverEvent(ChatColors.color(SlimefunPlugin.getLocal().getMessage(p, "machines.ELEVATOR.current-floor")), ChatColor.RESET + floor, ""));
+ line.setHoverEvent(new HoverEvent(ChatColors.color(SlimefunPlugin.getLocal().getMessage(p, "machines.ELEVATOR.current-floor")), "", ChatColor.RESET + floor, ""));
}
else {
line = new ChatComponent("\n" + ChatColor.GRAY.toString() + (floors.size() - i) + ". " + ChatColor.RESET + floor);
- line.setHoverEvent(new HoverEvent(ChatColors.color(SlimefunPlugin.getLocal().getMessage(p, "machines.ELEVATOR.click-to-teleport")), ChatColor.RESET + floor, ""));
- line.setClickEvent(new ClickEvent(ClickEventAction.RUN_COMMAND, "/sf elevator " + block.getX() + ' ' + block.getY() + ' ' + block.getZ() + " "));
+ line.setHoverEvent(new HoverEvent(ChatColors.color(SlimefunPlugin.getLocal().getMessage(p, "machines.ELEVATOR.click-to-teleport")), "", ChatColor.RESET + floor, ""));
+ line.setClickEvent(new ClickEvent(elevatorKey, player -> Slimefun.runSync(() -> {
+ users.add(player.getUniqueId());
+
+ float yaw = player.getEyeLocation().getYaw() + 180;
+
+ if (yaw > 180) {
+ yaw = -180 + (yaw - 180);
+ }
+
+ player.teleport(new Location(player.getWorld(), block.getX() + 0.5, block.getY() + 0.4, block.getZ() + 0.5, yaw, player.getEyeLocation().getPitch()));
+ player.sendTitle(ChatColor.RESET + ChatColors.color(floor), " ", 20, 60, 20);
+ })));
}
page.append(line);
}
- book.addPage(page);
+ if (page != null) {
+ book.addPage(page);
+ }
+
book.open(p);
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/EnderTalisman.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/EnderTalisman.java
index 52f8a1de5..90d620eba 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/EnderTalisman.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/EnderTalisman.java
@@ -17,7 +17,7 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
class EnderTalisman extends Talisman {
public EnderTalisman(Talisman parent) {
- super(Categories.TALISMANS_2, parent.upgrade(), new ItemStack[] { SlimefunItems.ENDER_LUMP_3, null, SlimefunItems.ENDER_LUMP_3, null, parent.getItem(), null, SlimefunItems.ENDER_LUMP_3, null, SlimefunItems.ENDER_LUMP_3 }, parent.isConsumable(), parent.isEventCancelled(), parent.getSuffix(), parent.getChance(), parent.getEffects());
+ super(Categories.ENDER_TALISMANS, parent.upgrade(), new ItemStack[] { SlimefunItems.ENDER_LUMP_3, null, SlimefunItems.ENDER_LUMP_3, null, parent.getItem(), null, SlimefunItems.ENDER_LUMP_3, null, SlimefunItems.ENDER_LUMP_3 }, parent.isConsumable(), parent.isEventCancelled(), parent.getSuffix(), parent.getChance(), parent.getEffects());
}
@Override
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/MagicianTalisman.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/MagicianTalisman.java
index 0700d6ea9..cfe689eae 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/MagicianTalisman.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/MagicianTalisman.java
@@ -41,7 +41,7 @@ public class MagicianTalisman extends Talisman {
* @author TheBusyBiscuit
*
*/
- public class TalismanEnchantment extends ItemSetting {
+ public static class TalismanEnchantment extends ItemSetting {
private final Enchantment enchantment;
private final int level;
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/Talisman.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/Talisman.java
index 060ac1667..3f5af4a9a 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/Talisman.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/Talisman.java
@@ -44,7 +44,7 @@ public class Talisman extends SlimefunItem {
}
public Talisman(SlimefunItemStack item, ItemStack[] recipe, boolean consumable, boolean cancelEvent, String messageSuffix, int chance, PotionEffect... effects) {
- this(Categories.TALISMANS_1, item, recipe, consumable, cancelEvent, messageSuffix, chance, effects);
+ this(Categories.TALISMANS, item, recipe, consumable, cancelEvent, messageSuffix, chance, effects);
}
protected Talisman(Category category, SlimefunItemStack item, ItemStack[] recipe, boolean consumable, boolean cancelEvent, String messageSuffix, int chance, PotionEffect... effects) {
@@ -106,7 +106,7 @@ public class Talisman extends SlimefunItem {
Research research = Research.getByID(112);
if (talisman != null && research != null) {
- talisman.bindToResearch(research);
+ talisman.setResearch(research);
}
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/AutomatedPanningMachine.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/AutomatedPanningMachine.java
index 17d0ddd02..420520a64 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/AutomatedPanningMachine.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/AutomatedPanningMachine.java
@@ -1,5 +1,8 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks;
+import java.util.ArrayList;
+import java.util.List;
+
import org.bukkit.Effect;
import org.bukkit.GameMode;
import org.bukkit.Material;
@@ -10,141 +13,73 @@ import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
-import io.github.thebusybiscuit.cscorelib2.collections.RandomizedSet;
import io.github.thebusybiscuit.cscorelib2.inventory.ItemUtils;
import io.github.thebusybiscuit.cscorelib2.scheduling.TaskQueue;
+import io.github.thebusybiscuit.slimefun4.implementation.items.tools.GoldPan;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Lists.Categories;
import me.mrCookieSlime.Slimefun.Lists.SlimefunItems;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.multiblocks.MultiBlockMachine;
-import me.mrCookieSlime.Slimefun.api.Slimefun;
public class AutomatedPanningMachine extends MultiBlockMachine {
-
- private final RandomizedSet randomizer = new RandomizedSet<>();
- private int weights;
-
- private final RandomizedSet randomizerNether = new RandomizedSet<>();
- private int weightsNether;
- public AutomatedPanningMachine() {
- super(
- Categories.MACHINES_1,
- SlimefunItems.AUTOMATED_PANNING_MACHINE,
- new ItemStack[] {
- null, null, null,
- null, new ItemStack(Material.OAK_TRAPDOOR), null,
- null, new ItemStack(Material.CAULDRON), null
- },
- new ItemStack[] {
- new ItemStack(Material.GRAVEL), new ItemStack(Material.FLINT),
- new ItemStack(Material.GRAVEL), SlimefunItems.SIFTED_ORE,
- new ItemStack(Material.GRAVEL), new ItemStack(Material.CLAY_BALL),
- new ItemStack(Material.GRAVEL), new ItemStack(Material.IRON_NUGGET),
- new ItemStack(Material.SOUL_SAND), new ItemStack(Material.QUARTZ),
- new ItemStack(Material.SOUL_SAND), new ItemStack(Material.GOLD_NUGGET),
- new ItemStack(Material.SOUL_SAND), new ItemStack(Material.NETHER_WART),
- new ItemStack(Material.SOUL_SAND), new ItemStack(Material.BLAZE_POWDER),
- new ItemStack(Material.SOUL_SAND), new ItemStack(Material.GLOWSTONE_DUST),
- new ItemStack(Material.SOUL_SAND), new ItemStack(Material.GHAST_TEAR)
- },
- BlockFace.SELF
- );
- }
-
- @Override
- public void postRegister() {
- super.postRegister();
-
- String goldPan = "GOLD_PAN";
- String netherGoldPan = "NETHER_GOLD_PAN";
-
- add(false, SlimefunItems.SIFTED_ORE, (int) Slimefun.getItemValue(goldPan, "chance.SIFTED_ORE"));
- add(false, new ItemStack(Material.CLAY_BALL), (int) Slimefun.getItemValue(goldPan, "chance.CLAY"));
- add(false, new ItemStack(Material.FLINT), (int) Slimefun.getItemValue(goldPan, "chance.FLINT"));
- add(false, new ItemStack(Material.IRON_NUGGET), (int) Slimefun.getItemValue(goldPan, "chance.IRON_NUGGET"));
+ private final GoldPan goldPan = (GoldPan) SlimefunItems.GOLD_PAN.getItem();
+ private final GoldPan netherGoldPan = (GoldPan) SlimefunItems.NETHER_GOLD_PAN.getItem();
- if (weights < 100) {
- add(false, new ItemStack(Material.AIR), 100 - weights);
- }
-
- add(true, new ItemStack(Material.QUARTZ), (int) Slimefun.getItemValue(netherGoldPan, "chance.QUARTZ"));
- add(true, new ItemStack(Material.GOLD_NUGGET), (int) Slimefun.getItemValue(netherGoldPan, "chance.GOLD_NUGGET"));
- add(true, new ItemStack(Material.NETHER_WART), (int) Slimefun.getItemValue(netherGoldPan, "chance.NETHER_WART"));
- add(true, new ItemStack(Material.BLAZE_POWDER), (int) Slimefun.getItemValue(netherGoldPan, "chance.BLAZE_POWDER"));
- add(true, new ItemStack(Material.GLOWSTONE_DUST), (int) Slimefun.getItemValue(netherGoldPan, "chance.GLOWSTONE_DUST"));
- add(true, new ItemStack(Material.GHAST_TEAR), (int) Slimefun.getItemValue(netherGoldPan, "chance.GHAST_TEAR"));
-
+ public AutomatedPanningMachine() {
+ super(Categories.MACHINES_1, SlimefunItems.AUTOMATED_PANNING_MACHINE, new ItemStack[] { null, null, null, null, new ItemStack(Material.OAK_TRAPDOOR), null, null, new ItemStack(Material.CAULDRON), null }, new ItemStack[0], BlockFace.SELF);
+ }
- if (weightsNether < 100) {
- add(true, new ItemStack(Material.AIR), 100 - weightsNether);
- }
- }
-
- private void add(boolean nether, ItemStack item, int chance) {
- if (nether) {
- randomizerNether.add(item, chance);
- weightsNether += chance;
- }
- else {
- randomizer.add(item, chance);
- weights += chance;
- }
- }
-
- @Override
- public void onInteract(Player p, Block b) {
- ItemStack input = p.getInventory().getItemInMainHand();
-
- if (SlimefunUtils.isItemSimilar(input, new ItemStack(Material.GRAVEL), true) || SlimefunUtils.isItemSimilar(input, new ItemStack(Material.SOUL_SAND), true)) {
- Material block = input.getType();
-
- if (p.getGameMode() != GameMode.CREATIVE) {
- ItemUtils.consumeItem(input, false);
- }
-
- ItemStack output = getRandomDrop(block);
- TaskQueue queue = new TaskQueue();
-
- queue.thenRepeatEvery(20, 5, () ->
- b.getWorld().playEffect(b.getRelative(BlockFace.DOWN).getLocation(), Effect.STEP_SOUND, block)
- );
-
- queue.thenRun(20, () -> {
- if (output.getType() != Material.AIR) {
- Inventory outputChest = findOutputChest(b.getRelative(BlockFace.DOWN), output);
-
- if (outputChest != null) {
- outputChest.addItem(output.clone());
- }
- else {
- b.getWorld().dropItemNaturally(b.getLocation(), output.clone());
- }
-
- p.getWorld().playSound(p.getLocation(), Sound.ENTITY_ARROW_HIT_PLAYER, 1F, 1F);
- }
- else {
- p.getWorld().playSound(p.getLocation(), Sound.ENTITY_ARMOR_STAND_BREAK, 1F, 1F);
- }
- });
-
- queue.execute(SlimefunPlugin.instance);
- }
- else {
- SlimefunPlugin.getLocal().sendMessage(p, "machines.wrong-item", true);
- }
- }
+ @Override
+ public List getDisplayRecipes() {
+ List recipes = new ArrayList<>();
- private ItemStack getRandomDrop(Material input) {
- if (input == Material.GRAVEL) {
- return randomizer.getRandom();
- }
- else if (input == Material.SOUL_SAND) {
- return randomizerNether.getRandom();
- }
-
- return new ItemStack(Material.AIR);
- }
+ recipes.addAll(goldPan.getDisplayRecipes());
+ recipes.addAll(netherGoldPan.getDisplayRecipes());
+
+ return recipes;
+ }
+
+ @Override
+ public void onInteract(Player p, Block b) {
+ ItemStack input = p.getInventory().getItemInMainHand();
+
+ if (SlimefunUtils.isItemSimilar(input, new ItemStack(Material.GRAVEL), true) || SlimefunUtils.isItemSimilar(input, new ItemStack(Material.SOUL_SAND), true)) {
+ Material material = input.getType();
+
+ if (p.getGameMode() != GameMode.CREATIVE) {
+ ItemUtils.consumeItem(input, false);
+ }
+
+ ItemStack output = material == Material.GRAVEL ? goldPan.getRandomOutput() : netherGoldPan.getRandomOutput();
+ TaskQueue queue = new TaskQueue();
+
+ queue.thenRepeatEvery(20, 5, () -> b.getWorld().playEffect(b.getRelative(BlockFace.DOWN).getLocation(), Effect.STEP_SOUND, material));
+
+ queue.thenRun(20, () -> {
+ if (output.getType() != Material.AIR) {
+ Inventory outputChest = findOutputChest(b.getRelative(BlockFace.DOWN), output);
+
+ if (outputChest != null) {
+ outputChest.addItem(output.clone());
+ }
+ else {
+ b.getWorld().dropItemNaturally(b.getLocation(), output.clone());
+ }
+
+ p.getWorld().playSound(p.getLocation(), Sound.ENTITY_ARROW_HIT_PLAYER, 1F, 1F);
+ }
+ else {
+ p.getWorld().playSound(p.getLocation(), Sound.ENTITY_ARMOR_STAND_BREAK, 1F, 1F);
+ }
+ });
+
+ queue.execute(SlimefunPlugin.instance);
+ }
+ else {
+ SlimefunPlugin.getLocal().sendMessage(p, "machines.wrong-item", true);
+ }
+ }
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/OreCrusher.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/OreCrusher.java
index 838876230..316d834d4 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/OreCrusher.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/multiblocks/OreCrusher.java
@@ -34,29 +34,32 @@ public class OreCrusher extends MultiBlockMachine {
new ItemStack[] {
new ItemStack(Material.COBBLESTONE, 8), new ItemStack(Material.SAND, 1),
SlimefunItems.GOLD_4K, SlimefunItems.GOLD_DUST,
- new ItemStack(Material.GRAVEL), new ItemStack(Material.SAND)
+ new ItemStack(Material.GRAVEL), new ItemStack(Material.SAND),
+ new ItemStack(Material.MAGMA_BLOCK, 4), SlimefunItems.SULFATE
},
BlockFace.SELF
);
+
addItemSetting(doubleOres);
}
- @Override
- public void postRegister() {
- super.postRegister();
- shownRecipes.addAll(Arrays.asList(
- new ItemStack(Material.COAL_ORE), new ItemStack(Material.COAL, isDoubleDropsEnabled() ? 2: 1),
- new ItemStack(Material.LAPIS_ORE), new ItemStack(Material.LAPIS_LAZULI, isDoubleDropsEnabled() ? 14: 7),
- new ItemStack(Material.REDSTONE_ORE), new ItemStack(Material.REDSTONE, isDoubleDropsEnabled() ? 8: 4),
- new ItemStack(Material.DIAMOND_ORE), new ItemStack(Material.DIAMOND, isDoubleDropsEnabled() ? 2: 1),
- new ItemStack(Material.EMERALD_ORE), new ItemStack(Material.EMERALD, isDoubleDropsEnabled() ? 2: 1)
- ));
- }
-
public boolean isDoubleDropsEnabled() {
return doubleOres.getValue();
}
+ @Override
+ public void postRegister() {
+ super.postRegister();
+
+ shownRecipes.addAll(Arrays.asList(
+ new ItemStack(Material.COAL_ORE), new ItemStack(Material.COAL, isDoubleDropsEnabled() ? 2: 1),
+ new ItemStack(Material.LAPIS_ORE), new ItemStack(Material.LAPIS_LAZULI, isDoubleDropsEnabled() ? 14: 7),
+ new ItemStack(Material.REDSTONE_ORE), new ItemStack(Material.REDSTONE, isDoubleDropsEnabled() ? 8: 4),
+ new ItemStack(Material.DIAMOND_ORE), new ItemStack(Material.DIAMOND, isDoubleDropsEnabled() ? 2: 1),
+ new ItemStack(Material.EMERALD_ORE), new ItemStack(Material.EMERALD, isDoubleDropsEnabled() ? 2: 1)
+ ));
+ }
+
@Override
public List getDisplayRecipes() {
return recipes.stream().map(items -> items[0]).collect(Collectors.toList());
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/ExplosivePickaxe.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/ExplosivePickaxe.java
index 2ce833316..877df6287 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/ExplosivePickaxe.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/ExplosivePickaxe.java
@@ -91,6 +91,7 @@ public class ExplosivePickaxe extends SimpleSlimefunItem impl
for (ItemStack drop : b.getDrops(getItem())) {
b.getWorld().dropItemNaturally(b.getLocation(), (b.getType().toString().endsWith("_ORE") && b.getType() != Material.IRON_ORE && b.getType() != Material.GOLD_ORE) ? new CustomItem(drop, fortune) : drop);
}
+
b.setType(Material.AIR);
}
@@ -103,7 +104,9 @@ public class ExplosivePickaxe extends SimpleSlimefunItem impl
return true;
}
- else return false;
+ else {
+ return false;
+ }
}
};
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/GoldPan.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/GoldPan.java
index 3721b45b6..148b0fa07 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/GoldPan.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/GoldPan.java
@@ -81,6 +81,10 @@ public class GoldPan extends SimpleSlimefunItem implements Recip
randomizer.add(new ItemStack(Material.AIR), 100 - randomizer.sumWeights());
}
}
+
+ public ItemStack getRandomOutput() {
+ return randomizer.getRandom();
+ }
@Override
public String getLabelLocalPath() {
@@ -96,7 +100,7 @@ public class GoldPan extends SimpleSlimefunItem implements Recip
Block b = block.get();
if (b.getType() == getInput() && SlimefunPlugin.getProtectionManager().hasPermission(e.getPlayer(), b.getLocation(), ProtectableAction.BREAK_BLOCK)) {
- ItemStack output = randomizer.getRandom();
+ ItemStack output = getRandomOutput();
b.getWorld().playEffect(b.getLocation(), Effect.STEP_SOUND, b.getType());
b.setType(Material.AIR);
@@ -125,11 +129,11 @@ public class GoldPan extends SimpleSlimefunItem implements Recip
return recipes;
}
- class GoldPanDrop extends ItemSetting {
+ public class GoldPanDrop extends ItemSetting {
private final ItemStack output;
- public GoldPanDrop(String key, int defaultValue, ItemStack output) {
+ protected GoldPanDrop(String key, int defaultValue, ItemStack output) {
super(key, defaultValue);
this.output = output;
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/GrapplingHook.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/GrapplingHook.java
index d077df023..b5ac4e35e 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/GrapplingHook.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/GrapplingHook.java
@@ -62,7 +62,7 @@ public class GrapplingHook extends SimpleSlimefunItem {
b.setLeashHolder(arrow);
boolean state = item.getType() != Material.SHEARS;
- SlimefunPlugin.getGrapplingHookListener().addGrapplingHook(uuid, arrow, b, state, despawnTicks.getValue() * 20);
+ SlimefunPlugin.getGrapplingHookListener().addGrapplingHook(uuid, arrow, b, state, despawnTicks.getValue() * 20L);
}
};
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/AncientAltarListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/AncientAltarListener.java
index 4235ea6ac..a44305769 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/AncientAltarListener.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/AncientAltarListener.java
@@ -57,7 +57,7 @@ public class AncientAltarListener implements Listener {
private final List altars = new ArrayList<>();
private final Set removedItems = new HashSet<>();
- public void load(SlimefunPlugin plugin) {
+ public void register(SlimefunPlugin plugin) {
plugin.getServer().getPluginManager().registerEvents(this, plugin);
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BackpackListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BackpackListener.java
index 1acc3d121..2d6f5d98b 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BackpackListener.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BackpackListener.java
@@ -5,7 +5,6 @@ import java.util.List;
import java.util.Map;
import java.util.UUID;
-import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
@@ -19,6 +18,7 @@ import org.bukkit.event.player.PlayerDropItemEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
+import io.github.thebusybiscuit.cscorelib2.chat.ChatColors;
import io.github.thebusybiscuit.slimefun4.api.player.PlayerBackpack;
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.implementation.items.food.Cooler;
@@ -47,7 +47,7 @@ public class BackpackListener implements Listener {
private Map backpacks = new HashMap<>();
- public void load(SlimefunPlugin plugin) {
+ public void register(SlimefunPlugin plugin) {
plugin.getServer().getPluginManager().registerEvents(this, plugin);
}
@@ -117,7 +117,7 @@ public class BackpackListener implements Listener {
public void openBackpack(Player p, ItemStack item, SlimefunBackpack backpack) {
if (item.getAmount() == 1) {
- if (Slimefun.hasUnlocked(p, backpack, true) && !PlayerProfile.get(p, profile -> openBackpack(item, profile, backpack.getSize()))) {
+ if (Slimefun.hasUnlocked(p, backpack, true) && !PlayerProfile.get(p, profile -> openBackpack(p, item, profile, backpack.getSize()))) {
SlimefunPlugin.getLocal().sendMessage(p, "messages.opening-backpack");
}
}
@@ -126,11 +126,10 @@ public class BackpackListener implements Listener {
}
}
- private void openBackpack(ItemStack item, PlayerProfile profile, int size) {
- Player p = profile.getPlayer();
-
- for (int line = 0; line < item.getItemMeta().getLore().size(); line++) {
- if (item.getItemMeta().getLore().get(line).equals(ChatColor.translateAlternateColorCodes('&', "&7ID: "))) {
+ private void openBackpack(Player p, ItemStack item, PlayerProfile profile, int size) {
+ List lore = item.getItemMeta().getLore();
+ for (int line = 0; line < lore.size(); line++) {
+ if (lore.get(line).equals(ChatColors.color("&7ID: "))) {
setBackpackId(p, item, line, profile.createBackpack(size).getID());
break;
}
@@ -140,7 +139,13 @@ public class BackpackListener implements Listener {
p.playSound(p.getLocation(), Sound.ENTITY_HORSE_ARMOR, 1F, 1F);
backpacks.put(p.getUniqueId(), item);
- Slimefun.runSync(() -> PlayerProfile.getBackpack(item).open(p));
+ Slimefun.runSync(() -> {
+ PlayerBackpack backpack = PlayerProfile.getBackpack(item);
+
+ if (backpack != null) {
+ backpack.open(p);
+ }
+ });
}
else {
SlimefunPlugin.getLocal().sendMessage(p, "backpack.already-open", true);
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockPhysicsListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockPhysicsListener.java
index e8d71e604..1ac1faeab 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockPhysicsListener.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockPhysicsListener.java
@@ -52,7 +52,7 @@ public class BlockPhysicsListener implements Listener {
@EventHandler
public void onPistonExtend(BlockPistonExtendEvent e) {
for (Block b : e.getBlocks()) {
- if (BlockStorage.hasBlockInfo(b) || b.getRelative(e.getDirection()).getType() == Material.AIR && BlockStorage.hasBlockInfo(b.getRelative(e.getDirection()))) {
+ if (BlockStorage.hasBlockInfo(b) || (b.getRelative(e.getDirection()).getType() == Material.AIR && BlockStorage.hasBlockInfo(b.getRelative(e.getDirection())))) {
e.setCancelled(true);
return;
}
@@ -63,7 +63,7 @@ public class BlockPhysicsListener implements Listener {
public void onPistonRetract(BlockPistonRetractEvent e) {
if (e.isSticky()) {
for (Block b : e.getBlocks()) {
- if (BlockStorage.hasBlockInfo(b) || b.getRelative(e.getDirection()).getType() == Material.AIR && BlockStorage.hasBlockInfo(b.getRelative(e.getDirection()))) {
+ if (BlockStorage.hasBlockInfo(b) || (b.getRelative(e.getDirection()).getType() == Material.AIR && BlockStorage.hasBlockInfo(b.getRelative(e.getDirection())))) {
e.setCancelled(true);
return;
}
@@ -71,13 +71,16 @@ public class BlockPhysicsListener implements Listener {
}
}
- @EventHandler
+ @EventHandler(ignoreCancelled = true)
public void onLiquidFlow(BlockFromToEvent e) {
Block block = e.getToBlock();
- String item = BlockStorage.checkID(block);
- if (item != null) {
- e.setCancelled(true);
+ if (block.getType() == Material.PLAYER_HEAD || block.getType() == Material.PLAYER_WALL_HEAD) {
+ String item = BlockStorage.checkID(block);
+
+ if (item != null) {
+ e.setCancelled(true);
+ }
}
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/DebugFishListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/DebugFishListener.java
index 9334186b2..2ec8d5a21 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/DebugFishListener.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/DebugFishListener.java
@@ -16,9 +16,11 @@ import org.bukkit.inventory.EquipmentSlot;
import io.github.thebusybiscuit.cscorelib2.chat.ChatColors;
import io.github.thebusybiscuit.cscorelib2.skull.SkullBlock;
import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNet;
+import io.github.thebusybiscuit.slimefun4.implementation.tasks.TickerTask;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Lists.SlimefunItems;
+import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.energy.ChargableBlock;
@@ -69,9 +71,12 @@ public class DebugFishListener implements Listener {
}
private void sendInfo(Player p, Block b) {
+ SlimefunItem item = BlockStorage.check(b);
+
p.sendMessage(" ");
p.sendMessage(ChatColors.color("&d" + b.getType() + " &e@ X: " + b.getX() + " Y: " + b.getY() + " Z: " + b.getZ()));
- p.sendMessage(ChatColors.color("&dID: " + "&e" + BlockStorage.checkID(b)));
+ p.sendMessage(ChatColors.color("&dId: " + "&e" + item.getID()));
+ p.sendMessage(ChatColors.color("&dPlugin: " + "&e" + item.getAddon().getName()));
if (b.getState() instanceof Skull) {
p.sendMessage(ChatColors.color("&dSkull: " + enabledTooltip));
@@ -92,17 +97,19 @@ public class DebugFishListener implements Listener {
p.sendMessage(ChatColors.color("&dInventory: " + disabledTooltip));
}
- if (BlockStorage.check(b).isTicking()) {
+ TickerTask ticker = SlimefunPlugin.getTicker();
+
+ if (item.isTicking()) {
p.sendMessage(ChatColors.color("&dTicker: " + enabledTooltip));
p.sendMessage(ChatColors.color(" &dAsync: &e" + (BlockStorage.check(b).getBlockTicker().isSynchronized() ? disabledTooltip : enabledTooltip)));
- p.sendMessage(ChatColors.color(" &dTimings: &e" + SlimefunPlugin.getTicker().getTimings(b) + "ns"));
- p.sendMessage(ChatColors.color(" &dTotal Timings: &e" + SlimefunPlugin.getTicker().getTimings(BlockStorage.checkID(b)) + "ns"));
- p.sendMessage(ChatColors.color(" &dChunk Timings: &e" + SlimefunPlugin.getTicker().getTimings(b.getChunk()) + "ns"));
+ p.sendMessage(ChatColors.color(" &dTimings: &e" + ticker.toMillis(ticker.getTimings(b), true)));
+ p.sendMessage(ChatColors.color(" &dTotal Timings: &e" + ticker.toMillis(ticker.getTimings(BlockStorage.checkID(b)), true)));
+ p.sendMessage(ChatColors.color(" &dChunk Timings: &e" + ticker.toMillis(ticker.getTimings(b.getChunk()), true)));
}
- else if (BlockStorage.check(b).getEnergyTicker() != null) {
+ else if (item.getEnergyTicker() != null) {
p.sendMessage(ChatColors.color("&dTicking: " + "&3Indirect"));
- p.sendMessage(ChatColors.color(" &dTimings: &e" + SlimefunPlugin.getTicker().getTimings(b) + "ns"));
- p.sendMessage(ChatColors.color(" &dChunk Timings: &e" + SlimefunPlugin.getTicker().getTimings(b.getChunk()) + "ns"));
+ p.sendMessage(ChatColors.color(" &dTimings: &e" + ticker.toMillis(ticker.getTimings(b), true)));
+ p.sendMessage(ChatColors.color(" &dChunk Timings: &e" + ticker.toMillis(ticker.getTimings(b.getChunk()), true)));
}
else {
p.sendMessage(ChatColors.color("&dTicker: " + disabledTooltip));
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/GrapplingHookListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/GrapplingHookListener.java
index 97a205e7d..852d6110a 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/GrapplingHookListener.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/GrapplingHookListener.java
@@ -30,7 +30,7 @@ public class GrapplingHookListener implements Listener {
private final Set invulnerable = new HashSet<>();
private final Map temporaryEntities = new HashMap<>();
- public void load(SlimefunPlugin plugin) {
+ public void register(SlimefunPlugin plugin) {
plugin.getServer().getPluginManager().registerEvents(this, plugin);
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/PlayerProfileListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/PlayerProfileListener.java
index cb133da51..c7aa87e36 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/PlayerProfileListener.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/PlayerProfileListener.java
@@ -1,12 +1,25 @@
package io.github.thebusybiscuit.slimefun4.implementation.listeners;
+import java.util.Optional;
+
+import org.bukkit.Server;
+import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerKickEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
+/**
+ * This {@link Listener} removes a {@link PlayerProfile} from memory if the corresponding {@link Player}
+ * has left the {@link Server} or was kicked.
+ *
+ * @author TheBusyBiscuit
+ * @author SoSeDiK
+ *
+ */
public class PlayerProfileListener implements Listener {
public PlayerProfileListener(SlimefunPlugin plugin) {
@@ -15,8 +28,21 @@ public class PlayerProfileListener implements Listener {
@EventHandler
public void onDisconnect(PlayerQuitEvent e) {
- if (PlayerProfile.isLoaded(e.getPlayer().getUniqueId())) {
- PlayerProfile.get(e.getPlayer()).markForDeletion();
+ Optional profile = PlayerProfile.find(e.getPlayer());
+
+ // if we still have a profile of this Player in memory, delete it
+ if (profile.isPresent()) {
+ profile.get().markForDeletion();
+ }
+ }
+
+ @EventHandler(ignoreCancelled = true)
+ public void onKick(PlayerKickEvent e) {
+ Optional profile = PlayerProfile.find(e.getPlayer());
+
+ // if we still have a profile of this Player in memory, delete it
+ if (profile.isPresent()) {
+ profile.get().markForDeletion();
}
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunBowListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunBowListener.java
index 416c49d3e..0c34199c2 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunBowListener.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunBowListener.java
@@ -23,7 +23,7 @@ public class SlimefunBowListener implements Listener {
private final Map bows = new HashMap<>();
- public void load(SlimefunPlugin plugin) {
+ public void register(SlimefunPlugin plugin) {
plugin.getServer().getPluginManager().registerEvents(this, plugin);
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunGuideListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunGuideListener.java
index ed08bd3e7..186365caa 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunGuideListener.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunGuideListener.java
@@ -1,6 +1,7 @@
package io.github.thebusybiscuit.slimefun4.implementation.listeners;
import org.bukkit.entity.Player;
+import org.bukkit.event.Event.Result;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
@@ -8,10 +9,10 @@ import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.api.events.PlayerRightClickEvent;
-import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuide;
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideLayout;
import io.github.thebusybiscuit.slimefun4.core.guide.options.SlimefunGuideSettings;
+import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
public class SlimefunGuideListener implements Listener {
@@ -27,8 +28,10 @@ public class SlimefunGuideListener implements Listener {
public void onJoin(PlayerJoinEvent e) {
if (giveOnFirstJoin && !e.getPlayer().hasPlayedBefore()) {
Player p = e.getPlayer();
- if (!SlimefunPlugin.getWhitelist().getBoolean(p.getWorld().getName() + ".enabled")) return;
- if (!SlimefunPlugin.getWhitelist().getBoolean(p.getWorld().getName() + ".enabled-items.SLIMEFUN_GUIDE")) return;
+
+ if (!SlimefunPlugin.getWorldSettingsService().isWorldEnabled(p.getWorld())) {
+ return;
+ }
SlimefunGuideLayout type = SlimefunPlugin.getCfg().getBoolean("guide.default-view-book") ? SlimefunGuideLayout.BOOK : SlimefunGuideLayout.CHEST;
p.getInventory().addItem(SlimefunGuide.getItem(type));
@@ -38,40 +41,46 @@ public class SlimefunGuideListener implements Listener {
@EventHandler(priority = EventPriority.LOWEST)
public void onInteract(PlayerRightClickEvent e) {
Player p = e.getPlayer();
- ItemStack item = e.getItem();
-
- if (SlimefunUtils.isItemSimilar(item, SlimefunGuide.getItem(SlimefunGuideLayout.BOOK), true)) {
- e.cancel();
+ if (openGuide(e, SlimefunGuideLayout.BOOK) == Result.ALLOW) {
if (p.isSneaking()) {
- SlimefunGuideSettings.openSettings(p, item);
+ SlimefunGuideSettings.openSettings(p, e.getItem());
}
else {
SlimefunGuide.openGuide(p, SlimefunGuideLayout.BOOK);
}
}
- else if (SlimefunUtils.isItemSimilar(item, SlimefunGuide.getItem(SlimefunGuideLayout.CHEST), true)) {
- e.cancel();
-
+ else if (openGuide(e, SlimefunGuideLayout.CHEST) == Result.ALLOW) {
if (p.isSneaking()) {
- SlimefunGuideSettings.openSettings(p, item);
+ SlimefunGuideSettings.openSettings(p, e.getItem());
}
else {
SlimefunGuide.openGuide(p, SlimefunGuideLayout.CHEST);
}
}
- else if (SlimefunUtils.isItemSimilar(item, SlimefunGuide.getItem(SlimefunGuideLayout.CHEAT_SHEET), true)) {
- e.cancel();
-
- if (p.isSneaking()) {
- SlimefunGuideSettings.openSettings(p, item);
- }
- else {
- // We rather just run the command here,
- // all necessary permission checks will be handled there.
- p.chat("/sf cheat");
- }
+ else if (openGuide(e, SlimefunGuideLayout.CHEAT_SHEET) == Result.ALLOW) {
+ // We rather just run the command here,
+ // all necessary permission checks will be handled there.
+ p.chat("/sf cheat");
}
}
+ private Result openGuide(PlayerRightClickEvent e, SlimefunGuideLayout layout) {
+ Player p = e.getPlayer();
+ ItemStack item = e.getItem();
+
+ if (SlimefunUtils.isItemSimilar(item, SlimefunGuide.getItem(layout), true)) {
+ e.cancel();
+
+ if (!SlimefunPlugin.getWorldSettingsService().isWorldEnabled(p.getWorld())) {
+ SlimefunPlugin.getLocal().sendMessage(p, "messages.disabled-item", true);
+ return Result.DENY;
+ }
+
+ return Result.ALLOW;
+ }
+
+ return Result.DEFAULT;
+ }
+
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunItemListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunItemListener.java
index 92ebaea9b..b002ec9bc 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunItemListener.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunItemListener.java
@@ -39,6 +39,10 @@ public class SlimefunItemListener implements Listener {
@EventHandler
public void onRightClick(PlayerInteractEvent e) {
if (e.getAction() == Action.RIGHT_CLICK_AIR || e.getAction() == Action.RIGHT_CLICK_BLOCK) {
+ if (SlimefunUtils.isItemSimilar(e.getItem(), SlimefunItems.DEBUG_FISH, true)) {
+ return;
+ }
+
PlayerRightClickEvent event = new PlayerRightClickEvent(e);
Bukkit.getPluginManager().callEvent(event);
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/WorldListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/WorldListener.java
index 8fdc770a3..2ebb33834 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/WorldListener.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/WorldListener.java
@@ -19,11 +19,8 @@ public class WorldListener implements Listener {
@EventHandler
public void onWorldLoad(WorldLoadEvent e) {
+ SlimefunPlugin.getWorldSettingsService().load(e.getWorld());
BlockStorage.getForcedStorage(e.getWorld());
-
- SlimefunPlugin.getWhitelist().setDefaultValue(e.getWorld().getName() + ".enabled", true);
- SlimefunPlugin.getWhitelist().setDefaultValue(e.getWorld().getName() + ".enabled-items.SLIMEFUN_GUIDE", true);
- SlimefunPlugin.getWhitelist().save();
}
@EventHandler
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/setup/PostSetup.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/setup/PostSetup.java
index 262f001c9..e3d5ddb60 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/setup/PostSetup.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/setup/PostSetup.java
@@ -13,7 +13,6 @@ import java.util.stream.Stream;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
-import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.inventory.ItemStack;
@@ -62,12 +61,6 @@ public final class PostSetup {
}
}
- public static void setupItemSettings() {
- for (World world : Bukkit.getWorlds()) {
- SlimefunPlugin.getWhitelist().setDefaultValue(world.getName() + ".enabled-items.SLIMEFUN_GUIDE", true);
- }
- }
-
public static void loadItems() {
Iterator iterator = SlimefunPlugin.getRegistry().getEnabledSlimefunItems().iterator();
@@ -117,7 +110,8 @@ public final class PostSetup {
SlimefunPlugin.getItemCfg().save();
SlimefunPlugin.getResearchCfg().save();
- SlimefunPlugin.getWhitelist().save();
+
+ SlimefunPlugin.getRegistry().setAutoLoadingMode(true);
}
private static void loadAutomaticCraftingChamber() {
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/setup/SlimefunItemSetup.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/setup/SlimefunItemSetup.java
index cee34e46f..fd4107822 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/setup/SlimefunItemSetup.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/setup/SlimefunItemSetup.java
@@ -2,7 +2,6 @@ package io.github.thebusybiscuit.slimefun4.implementation.setup;
import java.util.ArrayList;
import java.util.List;
-import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/SlimefunStartupTask.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/SlimefunStartupTask.java
index b83690daa..925997235 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/SlimefunStartupTask.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/SlimefunStartupTask.java
@@ -48,6 +48,7 @@ public class SlimefunStartupTask implements Runnable {
PostSetup.loadItems();
// Load all worlds
+ SlimefunPlugin.getWorldSettingsService().load(Bukkit.getWorlds());
for (World world : Bukkit.getWorlds()) {
new BlockStorage(world);
}
@@ -55,11 +56,11 @@ public class SlimefunStartupTask implements Runnable {
// Load all listeners that depend on items to be enabled
if (isEnabled("ANCIENT_ALTAR")) {
- SlimefunPlugin.getAncientAltarListener().load(plugin);
+ SlimefunPlugin.getAncientAltarListener().register(plugin);
}
if (isEnabled("GRAPPLING_HOOK")) {
- SlimefunPlugin.getGrapplingHookListener().load(plugin);
+ SlimefunPlugin.getGrapplingHookListener().register(plugin);
}
if (isEnabled("BLADE_OF_VAMPIRES")) {
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/TickerTask.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/TickerTask.java
index 73c4dc266..bedde79c7 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/TickerTask.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/TickerTask.java
@@ -7,6 +7,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@@ -36,7 +37,7 @@ import me.mrCookieSlime.Slimefun.api.Slimefun;
public class TickerTask implements Runnable {
- private final DecimalFormat decimalFormat = new DecimalFormat("#.###");
+ private final DecimalFormat decimalFormat = new DecimalFormat("#.##");
private final ConcurrentMap move = new ConcurrentHashMap<>();
private final ConcurrentMap delete = new ConcurrentHashMap<>();
private final ConcurrentMap blockTimings = new ConcurrentHashMap<>();
@@ -198,19 +199,19 @@ public class TickerTask implements Runnable {
}
public String getTime() {
- return toMillis(time);
+ return toMillis(time, false);
}
public void info(CommandSender sender) {
- sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&2== &aSlimefun Diagnostic Tool &2=="));
- sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&6Halted: &e&l" + String.valueOf(halted).toUpperCase()));
+ sender.sendMessage(ChatColors.color("&2== &aSlimefun Diagnostic Tool &2=="));
+ sender.sendMessage(ChatColors.color("&6Halted: &e&l" + String.valueOf(halted).toUpperCase(Locale.ROOT)));
sender.sendMessage("");
- sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&6Impact: &e" + toMillis(time)));
- sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&6Ticked Chunks: &e" + chunks));
- sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&6Ticked Machines: &e" + machines));
- sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&6Skipped Machines: &e" + skipped));
+ sender.sendMessage(ChatColors.color("&6Impact: &e" + toMillis(time, true)));
+ sender.sendMessage(ChatColors.color("&6Ticked Chunks: &e" + chunks));
+ sender.sendMessage(ChatColors.color("&6Ticked Machines: &e" + machines));
+ sender.sendMessage(ChatColors.color("&6Skipped Machines: &e" + skipped));
sender.sendMessage("");
- sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&6Ticking Machines:"));
+ sender.sendMessage(ChatColors.color("&6Ticking Machines:"));
List> timings = machineCount.keySet().stream().map(key -> new AbstractMap.SimpleEntry<>(key, machineTimings.getOrDefault(key, 0L))).sorted((o1, o2) -> o2.getValue().compareTo(o1.getValue())).collect(Collectors.toList());
@@ -222,8 +223,8 @@ public class TickerTask implements Runnable {
for (Map.Entry entry : timings) {
int count = machineCount.get(entry.getKey());
- if (entry.getValue() > 500_000) {
- builder.append("\n&c").append(entry.getKey()).append(" - ").append(count).append("x &7(").append(toMillis(entry.getValue())).append(", ").append(toMillis(entry.getValue() / count)).append(" avg/machine)");
+ if (entry.getValue() > 300_000) {
+ builder.append("\n&c").append(entry.getKey()).append(" - ").append(count).append("x &7(").append(toMillis(entry.getValue(), true)).append(", ").append(toMillis(entry.getValue() / count, true)).append(" avg/machine)");
}
else hidden++;
}
@@ -238,8 +239,8 @@ public class TickerTask implements Runnable {
for (Map.Entry entry : timings) {
int count = machineCount.get(entry.getKey());
- if (entry.getValue() > 500_000) {
- sender.sendMessage(" " + entry.getKey() + " - " + count + "x (" + toMillis(entry.getValue()) + ", " + toMillis(entry.getValue() / count) + " avg/machine)");
+ if (entry.getValue() > 300_000) {
+ sender.sendMessage(" " + entry.getKey() + " - " + count + "x (" + toMillis(entry.getValue(), false) + ", " + toMillis(entry.getValue() / count, false) + " avg/machine)");
}
else hidden++;
}
@@ -260,7 +261,7 @@ public class TickerTask implements Runnable {
for (Map.Entry entry : timings) {
if (!chunksSkipped.contains(entry.getKey())) {
if (entry.getValue() > 0) {
- builder.append("\n&c").append(formatChunk(entry.getKey())).append(" - ").append(chunkItemCount.getOrDefault(entry.getKey(), 0)).append("x &7(").append(toMillis(entry.getValue())).append(')');
+ builder.append("\n&c").append(formatChunk(entry.getKey())).append(" - ").append(chunkItemCount.getOrDefault(entry.getKey(), 0)).append("x &7(").append(toMillis(entry.getValue(), true)).append(')');
}
else hidden++;
}
@@ -277,7 +278,7 @@ public class TickerTask implements Runnable {
for (Map.Entry entry : timings) {
if (!chunksSkipped.contains(entry.getKey())) {
if (entry.getValue() > 0) {
- sender.sendMessage(" " + formatChunk(entry.getKey()) + " - " + (chunkItemCount.getOrDefault(entry.getKey(), 0)) + "x (" + toMillis(entry.getValue()) + ")");
+ sender.sendMessage(" " + formatChunk(entry.getKey()) + " - " + (chunkItemCount.getOrDefault(entry.getKey(), 0)) + "x (" + toMillis(entry.getValue(), false) + ")");
}
else hidden++;
}
@@ -301,7 +302,8 @@ public class TickerTask implements Runnable {
}
public long getTimings(Chunk c) {
- return chunkTimings.getOrDefault(c.toString(), 0L);
+ String id = c.getWorld().getName() + ';' + c.getX() + ';' + c.getZ();
+ return chunkTimings.getOrDefault(id, 0L);
}
public void addBlockTimings(Location l, long time) {
@@ -316,8 +318,22 @@ public class TickerTask implements Runnable {
halted = true;
}
- private String toMillis(long time) {
- return decimalFormat.format(time / 1000000F) + "ms";
+ public String toMillis(long nanoseconds, boolean colors) {
+ String number = decimalFormat.format(nanoseconds / 1000000.0);
+
+ if (!colors) {
+ return number;
+ }
+ else {
+ String[] parts = PatternUtils.NUMBER_SEPERATOR.split(number);
+
+ if (parts.length == 1) {
+ return parts[0];
+ }
+ else {
+ return parts[0] + ',' + ChatColor.GRAY + parts[1] + "ms";
+ }
+ }
}
@Override
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/ChatUtils.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/ChatUtils.java
index 7b384d912..358fd8ca9 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/ChatUtils.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/ChatUtils.java
@@ -1,5 +1,6 @@
package io.github.thebusybiscuit.slimefun4.utils;
+import java.util.Locale;
import java.util.function.Consumer;
import org.bukkit.ChatColor;
@@ -10,11 +11,19 @@ import io.github.thebusybiscuit.cscorelib2.chat.ChatColors;
import io.github.thebusybiscuit.cscorelib2.chat.ChatInput;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
+/**
+ * This utility class contains a few static methods that are all about {@link String} manipulation
+ * or sending a {@link String} to a {@link Player}.
+ *
+ * @author TheBusyBiscuit
+ *
+ */
public final class ChatUtils {
private ChatUtils() {}
public static void sendURL(CommandSender sender, String url) {
+ // If we get access to the URL prompt one day, we can just prompt the link to the Player that way.
sender.sendMessage("");
SlimefunPlugin.getLocal().sendMessage(sender, "messages.link-prompt", false);
sender.sendMessage(ChatColors.color("&7&o" + url));
@@ -41,7 +50,7 @@ public final class ChatUtils {
public static String humanize(String string) {
StringBuilder builder = new StringBuilder();
- String[] segments = string.toLowerCase().split("_");
+ String[] segments = string.toLowerCase(Locale.ROOT).split("_");
builder.append(Character.toUpperCase(segments[0].charAt(0))).append(segments[0].substring(1));
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/ChestMenuUtils.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/ChestMenuUtils.java
index f38c5ea5f..785deb4b9 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/ChestMenuUtils.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/ChestMenuUtils.java
@@ -55,7 +55,7 @@ public final class ChestMenuUtils {
return new CustomItem(SEARCH_BUTTON, meta -> {
meta.setDisplayName(ChatColors.color(SlimefunPlugin.getLocal().getMessage(p, "guide.search.name")));
- List lore = Arrays.asList("", ChatColor.GRAY + "\u21E6 " + SlimefunPlugin.getLocal().getMessage(p, "guide.search.tooltip"));
+ List lore = Arrays.asList("", ChatColor.GRAY + "\u21E8 " + SlimefunPlugin.getLocal().getMessage(p, "guide.search.tooltip"));
lore.replaceAll(ChatColors::color);
meta.setLore(lore);
});
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/NumberUtils.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/NumberUtils.java
index 403da6a15..c0043118f 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/NumberUtils.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/NumberUtils.java
@@ -7,6 +7,8 @@ import java.util.Date;
import java.util.Locale;
import java.util.logging.Level;
+import org.bukkit.ChatColor;
+
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.api.Slimefun;
@@ -30,6 +32,15 @@ public final class NumberUtils {
}
}
+ public static ChatColor getColorFromPercentage(float percentage) {
+ if (percentage < 16.0F) return ChatColor.DARK_RED;
+ else if (percentage < 32.0F) return ChatColor.RED;
+ else if (percentage < 48.0F) return ChatColor.GOLD;
+ else if (percentage < 64.0F) return ChatColor.YELLOW;
+ else if (percentage < 80.0F) return ChatColor.DARK_GREEN;
+ else return ChatColor.GREEN;
+ }
+
public static String timeDelta(Date date) {
long timestamp = date.getTime();
int hours = (int) ((System.currentTimeMillis() - timestamp) / (1000 * 60 * 60));
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/PatternUtils.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/PatternUtils.java
index f3f9f92a8..c79bae32e 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/PatternUtils.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/PatternUtils.java
@@ -9,6 +9,7 @@ import java.util.regex.Pattern;
* This class solves that, one compile but many uses!
*
* @author Walshy
+ * @author TheBusyBiscuit
*
*/
public final class PatternUtils {
@@ -21,4 +22,9 @@ public final class PatternUtils {
public static final Pattern SLASH_SEPARATOR = Pattern.compile(" / ");
public static final Pattern DASH = Pattern.compile("-");
public static final Pattern ASCII = Pattern.compile("[A-Za-z \"_]+");
+ public static final Pattern ALPHANUMERIC = Pattern.compile("[A-Fa-f0-9]+");
+ public static final Pattern NUMERIC = Pattern.compile("[0-9]+");
+
+ public static final Pattern NUMBER_SEPERATOR = Pattern.compile(",|\\.");
+
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/holograms/SimpleHologram.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/holograms/SimpleHologram.java
index 183d4f60c..afbfb5c89 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/holograms/SimpleHologram.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/holograms/SimpleHologram.java
@@ -9,6 +9,12 @@ import org.bukkit.entity.EntityType;
import io.github.thebusybiscuit.cscorelib2.chat.ChatColors;
import me.mrCookieSlime.Slimefun.api.Slimefun;
+/**
+ * This utility class provides a few static methods for modifying a simple Text-based Hologram.
+ *
+ * @author TheBusyBiscuit
+ *
+ */
public final class SimpleHologram {
private SimpleHologram() {}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/holograms/package-info.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/holograms/package-info.java
new file mode 100644
index 000000000..bdb15ed9d
--- /dev/null
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/holograms/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * This package contains a few utility classes that handle holograms in Slimefun.
+ */
+package io.github.thebusybiscuit.slimefun4.utils.holograms;
\ No newline at end of file
diff --git a/src/main/java/me/mrCookieSlime/Slimefun/Lists/Categories.java b/src/main/java/me/mrCookieSlime/Slimefun/Lists/Categories.java
index 8710a14cc..f6d6aae87 100644
--- a/src/main/java/me/mrCookieSlime/Slimefun/Lists/Categories.java
+++ b/src/main/java/me/mrCookieSlime/Slimefun/Lists/Categories.java
@@ -42,12 +42,12 @@ public final class Categories {
public static final Category CARGO = new LockedCategory(new NamespacedKey(SlimefunPlugin.instance, "cargo"), new CustomItem(SlimefunItems.CARGO_MANAGER, "&cCargo Management"), 4, MACHINES_1);
public static final Category TECH_MISC = new Category(new NamespacedKey(SlimefunPlugin.instance, "tech_misc"), new CustomItem(SlimefunItems.HEATING_COIL, "&7Technical Components"), 2);
public static final Category MAGIC_ARMOR = new Category(new NamespacedKey(SlimefunPlugin.instance, "magical_armor"), new CustomItem(SlimefunItems.ENDER_HELMET, "&7Magical Armor"), 2);
- public static final Category TALISMANS_1 = new Category(new NamespacedKey(SlimefunPlugin.instance, "talismans"), new CustomItem(SlimefunItems.TALISMAN, "&7Talismans - &aTier I"), 2);
+ public static final Category TALISMANS = new Category(new NamespacedKey(SlimefunPlugin.instance, "talismans"), new CustomItem(SlimefunItems.TALISMAN, "&7Talismans - &aTier I"), 2);
// Locked Categories
public static final LockedCategory ELECTRICITY = new LockedCategory(new NamespacedKey(SlimefunPlugin.instance, "electricity"), new CustomItem(SlimefunItems.NUCLEAR_REACTOR, "&bEnergy and Electricity"), 4, MACHINES_1);
public static final LockedCategory GPS = new LockedCategory(new NamespacedKey(SlimefunPlugin.instance, "gps"), new CustomItem(SlimefunItems.GPS_TRANSMITTER, "&bGPS-based Machines"), 4, MACHINES_1);
- public static final LockedCategory TALISMANS_2 = new LockedCategory(new NamespacedKey(SlimefunPlugin.instance, "ender_talismans"), new CustomItem(SlimefunItems.ENDER_TALISMAN, "&7Talismans - &aTier II"), 3, TALISMANS_1);
+ public static final LockedCategory ENDER_TALISMANS = new LockedCategory(new NamespacedKey(SlimefunPlugin.instance, "ender_talismans"), new CustomItem(SlimefunItems.ENDER_TALISMAN, "&7Talismans - &aTier II"), 3, TALISMANS);
// Seasonal Categories
public static final SeasonalCategory CHRISTMAS = new SeasonalCategory(new NamespacedKey(SlimefunPlugin.instance, "christmas"), Month.DECEMBER, 1, new CustomItem(Material.NETHER_STAR, ChatUtils.christmas("Christmas") + " &7(December only)"));
diff --git a/src/main/java/me/mrCookieSlime/Slimefun/Lists/RecipeType.java b/src/main/java/me/mrCookieSlime/Slimefun/Lists/RecipeType.java
index 03e442a39..ebafa4107 100644
--- a/src/main/java/me/mrCookieSlime/Slimefun/Lists/RecipeType.java
+++ b/src/main/java/me/mrCookieSlime/Slimefun/Lists/RecipeType.java
@@ -75,7 +75,7 @@ public class RecipeType implements Keyed {
this.machine = machine;
if (machine.length() > 0) {
- this.key = new NamespacedKey(SlimefunPlugin.instance, machine.toLowerCase());
+ this.key = new NamespacedKey(SlimefunPlugin.instance, machine.toLowerCase(Locale.ROOT));
}
else {
this.key = new NamespacedKey(SlimefunPlugin.instance, "unknown");
@@ -152,7 +152,7 @@ public class RecipeType implements Keyed {
}
private static void registerMobDrop(ItemStack[] recipe, ItemStack output) {
- String mob = ChatColor.stripColor(recipe[4].getItemMeta().getDisplayName()).toUpperCase().replace(' ', '_');
+ String mob = ChatColor.stripColor(recipe[4].getItemMeta().getDisplayName()).toUpperCase(Locale.ROOT).replace(' ', '_');
EntityType entity = EntityType.valueOf(mob);
Set dropping = SlimefunPlugin.getRegistry().getMobDrops().getOrDefault(entity, new HashSet<>());
dropping.add(output);
diff --git a/src/main/java/me/mrCookieSlime/Slimefun/Lists/SlimefunItems.java b/src/main/java/me/mrCookieSlime/Slimefun/Lists/SlimefunItems.java
index da9ed8605..8fa062b67 100644
--- a/src/main/java/me/mrCookieSlime/Slimefun/Lists/SlimefunItems.java
+++ b/src/main/java/me/mrCookieSlime/Slimefun/Lists/SlimefunItems.java
@@ -695,7 +695,7 @@ public final class SlimefunItems {
public static final ItemStack BLISTERING_INGOT_3 = new SlimefunItemStack("BLISTERING_INGOT_3", Material.GOLD_INGOT, "&6Blistering Ingot", "", LoreBuilder.radioactive(Radioactivity.VERY_HIGH), LoreBuilder.HAZMAT_SUIT_REQUIRED);
public static final ItemStack ENERGY_REGULATOR = new SlimefunItemStack("ENERGY_REGULATOR", "d78f2b7e5e75639ea7fb796c35d364c4df28b4243e66b76277aadcd6261337", "&6Energy Regulator", "", "&rCore Component of an Energy Network");
- public static final ItemStack DEBUG_FISH = new CustomItem(Material.SALMON, "&3How much is the Fish?", "", "&eRight Click &rany Block to view it's BlockData", "&eLeft Click &rto break a Block", "&eShift + Left Click &rany Block to erase it's BlockData", "&eShift + Right Click &rto place a Placeholder Block");
+ public static final ItemStack DEBUG_FISH = new SlimefunItemStack("DEBUG_FISH", Material.SALMON, "&3How much is the Fish?", "", "&eRight Click &rany Block to view it's BlockData", "&eLeft Click &rto break a Block", "&eShift + Left Click &rany Block to erase it's BlockData", "&eShift + Right Click &rto place a Placeholder Block");
public static final ItemStack NETHER_ICE = new SlimefunItemStack("NETHER_ICE", "3ce2dad9baf7eaba7e80d4d0f9fac0aab01a76b12fb71c3d2af2a16fdd4c7383", "&eNether Ice", "", LoreBuilder.radioactive(Radioactivity.MODERATE), LoreBuilder.HAZMAT_SUIT_REQUIRED);
public static final ItemStack ENRICHED_NETHER_ICE = new SlimefunItemStack("ENRICHED_NETHER_ICE", "7c818aa13aabc7294838d21caac057e97bd8c89641a0c0f8a55442ff4e27", "&eEnriched Nether Ice", "", LoreBuilder.radioactive(Radioactivity.VERY_HIGH), LoreBuilder.HAZMAT_SUIT_REQUIRED);
diff --git a/src/main/java/me/mrCookieSlime/Slimefun/Objects/Category.java b/src/main/java/me/mrCookieSlime/Slimefun/Objects/Category.java
index 0cb310985..f1b61c027 100644
--- a/src/main/java/me/mrCookieSlime/Slimefun/Objects/Category.java
+++ b/src/main/java/me/mrCookieSlime/Slimefun/Objects/Category.java
@@ -34,9 +34,9 @@ import me.mrCookieSlime.Slimefun.api.Slimefun;
*/
public class Category implements Keyed {
+ protected final List items = new ArrayList<>();
protected final NamespacedKey key;
protected final ItemStack item;
- protected final List items;
protected final int tier;
/**
@@ -73,8 +73,6 @@ public class Category implements Keyed {
meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES);
meta.addItemFlags(ItemFlag.HIDE_ENCHANTS);
this.item.setItemMeta(meta);
-
- this.items = new ArrayList<>();
this.tier = tier;
}
@@ -86,19 +84,11 @@ public class Category implements Keyed {
/**
* Registers this category.
*
- * By default, a category is automatically registered when a {@link SlimefunItem} is bound to it.
+ * By default, a category is automatically registered when a {@link SlimefunItem} was added to it.
*/
public void register() {
- if (this instanceof SeasonalCategory) {
- if (((SeasonalCategory) this).isVisible()) {
- SlimefunPlugin.getRegistry().getEnabledCategories().add(this);
- Collections.sort(SlimefunPlugin.getRegistry().getEnabledCategories(), Comparator.comparingInt(Category::getTier));
- }
- }
- else {
- SlimefunPlugin.getRegistry().getEnabledCategories().add(this);
- Collections.sort(SlimefunPlugin.getRegistry().getEnabledCategories(), Comparator.comparingInt(Category::getTier));
- }
+ SlimefunPlugin.getRegistry().getCategories().add(this);
+ Collections.sort(SlimefunPlugin.getRegistry().getCategories(), Comparator.comparingInt(Category::getTier));
}
/**
@@ -111,6 +101,16 @@ public class Category implements Keyed {
items.add(item);
}
+ /**
+ * Removes the given {@link SlimefunItem} from this {@link Category}.
+ *
+ * @param item
+ * the {@link SlimefunItem} that should be removed from this {@link Category}
+ */
+ public void remove(SlimefunItem item) {
+ items.remove(item);
+ }
+
/**
* This method returns a localized display item of this {@link Category}
* for the specified {@link Player}.
@@ -151,7 +151,7 @@ public class Category implements Keyed {
* @return the list of SlimefunItems bound to this category
*/
public List getItems() {
- return this.items;
+ return items;
}
/**
@@ -166,7 +166,7 @@ public class Category implements Keyed {
@Override
public String toString() {
- return "Slimefun Category {" + key + ",tier=" + tier + "}";
+ return getClass().getSimpleName() + " {" + key + ",tier=" + tier + "}";
}
/**
@@ -181,7 +181,7 @@ public class Category implements Keyed {
*/
public boolean isHidden(Player p) {
for (SlimefunItem slimefunItem : getItems()) {
- if (Slimefun.isEnabled(p, slimefunItem, false)) {
+ if (!slimefunItem.isHidden() && Slimefun.isEnabled(p, slimefunItem, false)) {
return false;
}
}
diff --git a/src/main/java/me/mrCookieSlime/Slimefun/Objects/LockedCategory.java b/src/main/java/me/mrCookieSlime/Slimefun/Objects/LockedCategory.java
index 9f5c20737..288df3fee 100644
--- a/src/main/java/me/mrCookieSlime/Slimefun/Objects/LockedCategory.java
+++ b/src/main/java/me/mrCookieSlime/Slimefun/Objects/LockedCategory.java
@@ -88,7 +88,7 @@ public class LockedCategory extends Category {
throw new IllegalArgumentException("Category '" + item.getItemMeta().getDisplayName() + "' cannot be a parent of itself or have a 'null' parent.");
}
- this.parents.add(category);
+ parents.add(category);
}
/**
@@ -101,7 +101,7 @@ public class LockedCategory extends Category {
* @see #addParent(Category)
*/
public void removeParent(Category category) {
- this.parents.remove(category);
+ parents.remove(category);
}
/**
diff --git a/src/main/java/me/mrCookieSlime/Slimefun/Objects/Research.java b/src/main/java/me/mrCookieSlime/Slimefun/Objects/Research.java
index 58987a932..1dccec5b6 100644
--- a/src/main/java/me/mrCookieSlime/Slimefun/Objects/Research.java
+++ b/src/main/java/me/mrCookieSlime/Slimefun/Objects/Research.java
@@ -138,7 +138,7 @@ public class Research implements Keyed {
public void addItems(SlimefunItem... items) {
for (SlimefunItem item : items) {
if (item != null) {
- item.bindToResearch(this);
+ item.setResearch(this);
}
}
}
@@ -242,7 +242,7 @@ public class Research implements Keyed {
Iterator iterator = items.iterator();
while (iterator.hasNext()) {
SlimefunItem item = iterator.next();
- if (item != null) item.bindToResearch(null);
+ if (item != null) item.setResearch(null);
iterator.remove();
}
return;
diff --git a/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/ItemState.java b/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/ItemState.java
index 9d2b7814c..a200c7bf4 100644
--- a/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/ItemState.java
+++ b/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/ItemState.java
@@ -31,5 +31,5 @@ public enum ItemState {
* This {@link SlimefunItem} has fallen back to its vanilla behavior, because it is disabled and an instance of
* {@link VanillaItem}.
*/
- VANILLA
+ VANILLA_FALLBACK
}
\ No newline at end of file
diff --git a/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/SlimefunItem.java b/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/SlimefunItem.java
index 82bbd3976..e2488e05f 100644
--- a/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/SlimefunItem.java
+++ b/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/SlimefunItem.java
@@ -10,8 +10,6 @@ import java.util.function.Consumer;
import java.util.logging.Level;
import org.apache.commons.lang.Validate;
-import org.bukkit.Bukkit;
-import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
@@ -105,6 +103,7 @@ public class SlimefunItem implements Placeable {
public SlimefunItem(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, ItemStack recipeOutput) {
Validate.notNull(category, "'category' is not allowed to be null!");
Validate.notNull(item, "'item' is not allowed to be null!");
+ Validate.notNull(recipeType, "'recipeType' is not allowed to be null!");
this.category = category;
this.item = item;
@@ -250,40 +249,32 @@ public class SlimefunItem implements Placeable {
*
* @return Whether this {@link SlimefunItem} is hidden.
*/
- public boolean isHidden() {
+ public final boolean isHidden() {
return hidden;
}
+ public void setHidden(boolean hidden) {
+ this.hidden = hidden;
+
+ if (state == ItemState.ENABLED) {
+ if (hidden) {
+ category.remove(this);
+ }
+ else {
+ category.add(this);
+ }
+ }
+ }
+
/**
* This method returns whether this {@link SlimefunItem} was added by an addon.
*
* @return Whether this {@link SlimefunItem} was added by an addon.
*/
- public boolean isAddonItem() {
+ public final boolean isAddonItem() {
return !(addon instanceof SlimefunPlugin);
}
- /**
- * This method returns the {@link SlimefunAddon} that registered this
- * {@link SlimefunItem}. If this Item is from Slimefun itself, the current
- * instance of {@link SlimefunPlugin} will be returned.
- * Use an instanceof check or {@link SlimefunItem#isAddonItem()} to account for that.
- *
- * @return The {@link SlimefunAddon} that registered this {@link SlimefunItem}
- */
- public SlimefunAddon getAddon() {
- return addon;
- }
-
- public BlockTicker getBlockTicker() {
- return blockTicker;
- }
-
- // We should maybe refactor this and move it to a subclass
- public GeneratorTicker getEnergyTicker() {
- return generatorTicker;
- }
-
/**
* This method returns whether this {@link SlimefunItem} is disabled.
*
@@ -298,6 +289,32 @@ public class SlimefunItem implements Placeable {
return state != ItemState.ENABLED;
}
+ /**
+ * This method returns the {@link SlimefunAddon} that registered this
+ * {@link SlimefunItem}. If this Item is from Slimefun itself, the current
+ * instance of {@link SlimefunPlugin} will be returned.
+ * Use an instanceof check or {@link SlimefunItem#isAddonItem()} to account for that.
+ *
+ * @return The {@link SlimefunAddon} that registered this {@link SlimefunItem}
+ */
+ public SlimefunAddon getAddon() {
+ if (addon == null) {
+ error("getAddon() cannot be called before registering the item", new UnregisteredItemException(this));
+ return null;
+ }
+
+ return addon;
+ }
+
+ public BlockTicker getBlockTicker() {
+ return blockTicker;
+ }
+
+ // We should maybe refactor this and move it to a subclass
+ public GeneratorTicker getEnergyTicker() {
+ return generatorTicker;
+ }
+
/**
* This method registers this {@link SlimefunItem}.
* Always call this method after your {@link SlimefunItem} has been initialized.
@@ -336,15 +353,11 @@ public class SlimefunItem implements Placeable {
SlimefunPlugin.getItemCfg().setDefaultValue(id + ".allow-enchanting", enchantable);
SlimefunPlugin.getItemCfg().setDefaultValue(id + ".allow-disenchanting", disenchantable);
+ // Load all item settings
for (ItemSetting> setting : itemSettings) {
setting.load(this);
}
- for (World world : Bukkit.getWorlds()) {
- SlimefunPlugin.getWhitelist().setDefaultValue(world.getName() + ".enabled", true);
- SlimefunPlugin.getWhitelist().setDefaultValue(world.getName() + ".enabled-items." + id, true);
- }
-
if (ticking && !SlimefunPlugin.getCfg().getBoolean("URID.enable-tickers")) {
state = ItemState.DISABLED;
return;
@@ -364,7 +377,7 @@ public class SlimefunItem implements Placeable {
if (SlimefunPlugin.getItemCfg().getBoolean(id + ".enabled")) {
- if (!SlimefunPlugin.getRegistry().getEnabledCategories().contains(category)) {
+ if (!SlimefunPlugin.getRegistry().getCategories().contains(category)) {
category.register();
}
@@ -380,13 +393,18 @@ public class SlimefunItem implements Placeable {
loadItemHandlers();
}
else if (this instanceof VanillaItem) {
- state = ItemState.VANILLA;
+ state = ItemState.VANILLA_FALLBACK;
}
else {
state = ItemState.DISABLED;
}
postRegister();
+
+ if (SlimefunPlugin.getRegistry().isAutoLoadingEnabled() && state == ItemState.ENABLED) {
+ info("Item was registered during runtime.");
+ load();
+ }
}
catch (Exception x) {
error("Registering " + toString() + " has failed", x);
@@ -408,12 +426,24 @@ public class SlimefunItem implements Placeable {
}
}
- public void bindToResearch(Research r) {
- if (r != null) {
- r.getAffectedItems().add(this);
+ /**
+ * This method will set the {@link Research} of this {@link SlimefunItem}.
+ * You don't have to call this method if your {@link SlimefunItem} was linked to your {@link Research}
+ * using {@link Research#addItems(SlimefunItem...)}
+ *
+ * @param research
+ * The new {@link Research} for this {@link SlimefunItem}
+ */
+ public void setResearch(Research research) {
+ if (this.research != null) {
+ this.research.getAffectedItems().remove(this);
}
- this.research = r;
+ if (research != null) {
+ research.getAffectedItems().add(this);
+ }
+
+ this.research = research;
}
public void setRecipe(ItemStack[] recipe) {
@@ -425,11 +455,16 @@ public class SlimefunItem implements Placeable {
}
public void setRecipeType(RecipeType type) {
+ Validate.notNull(type, "'recipeType' is not allowed to be null!");
this.recipeType = type;
}
public void setCategory(Category category) {
Validate.notNull(category, "'category' is not allowed to be null!");
+
+ this.category.remove(this);
+ category.add(this);
+
this.category = category;
}
@@ -587,7 +622,7 @@ public class SlimefunItem implements Placeable {
* @param page
* The associated wiki page
*/
- public void addOficialWikipage(String page) {
+ public final void addOficialWikipage(String page) {
Validate.notNull(page, "Wiki page cannot be null.");
wikiLink = Optional.of("https://github.com/TheBusyBiscuit/Slimefun4/wiki/" + page);
}
@@ -678,11 +713,13 @@ public class SlimefunItem implements Placeable {
}
public void info(String message) {
- addon.getLogger().log(Level.INFO, message);
+ String msg = toString() + ": " + message;
+ addon.getLogger().log(Level.INFO, msg);
}
public void warn(String message) {
- addon.getLogger().log(Level.WARNING, message);
+ String msg = toString() + ": " + message;
+ addon.getLogger().log(Level.WARNING, msg);
}
/**
@@ -709,6 +746,22 @@ public class SlimefunItem implements Placeable {
return SlimefunPlugin.getRegistry().getSlimefunItemIds().get(id);
}
+ /**
+ * This gets an ItemStack from the SlimefunItem with that id.
+ *
+ * @deprecated Please use {@link #getByID(String)} to obtain the {@link SlimefunItem} and then get the ItemStack
+ * from that.
+ *
+ * @param id
+ * the item id
+ * @return The item
+ */
+ @Deprecated
+ public static ItemStack getItem(String id) {
+ SlimefunItem sfi = getByID(id);
+ return sfi == null ? null : sfi.getItem();
+ }
+
public static SlimefunItem getByItem(ItemStack item) {
if (item == null) return null;
@@ -739,7 +792,7 @@ public class SlimefunItem implements Placeable {
if (SlimefunUtils.isItemSimilar(item, SlimefunItems.BROKEN_SPAWNER, false)) {
return getByID("BROKEN_SPAWNER");
}
-
+
if (SlimefunUtils.isItemSimilar(item, SlimefunItems.REPAIRED_SPAWNER, false)) {
return getByID("REINFORCED_SPAWNER");
}
@@ -747,11 +800,6 @@ public class SlimefunItem implements Placeable {
return null;
}
- public static ItemStack getItem(String id) {
- SlimefunItem item = getByID(id);
- return item != null ? item.getItem() : null;
- }
-
public static Set getPublicItemHandlers(Class extends ItemHandler> identifier) {
return SlimefunPlugin.getRegistry().getPublicItemHandlers().computeIfAbsent(identifier, c -> new HashSet<>());
}
diff --git a/src/main/java/me/mrCookieSlime/Slimefun/SlimefunPlugin.java b/src/main/java/me/mrCookieSlime/Slimefun/SlimefunPlugin.java
index 9654dcc4f..635802cc8 100644
--- a/src/main/java/me/mrCookieSlime/Slimefun/SlimefunPlugin.java
+++ b/src/main/java/me/mrCookieSlime/Slimefun/SlimefunPlugin.java
@@ -34,6 +34,7 @@ import io.github.thebusybiscuit.slimefun4.core.services.CustomItemDataService;
import io.github.thebusybiscuit.slimefun4.core.services.CustomTextureService;
import io.github.thebusybiscuit.slimefun4.core.services.LocalizationService;
import io.github.thebusybiscuit.slimefun4.core.services.MinecraftRecipeService;
+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;
@@ -108,6 +109,7 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
private final AutoSavingService autoSavingService = new AutoSavingService();
private final BackupService backupService = new BackupService();
private final PermissionsService permissionsService = new PermissionsService(this);
+ private final PerWorldSettingsService worldSettingsService = new PerWorldSettingsService(this);
private final ThirdPartyPluginService thirdPartySupportService = new ThirdPartyPluginService(this);
private final MinecraftRecipeService recipeService = new MinecraftRecipeService(this);
private LocalizationService local;
@@ -117,10 +119,9 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
private ProtectionManager protections;
// Important config files for Slimefun
- private Config researches;
- private Config items;
- private Config whitelist;
- private Config config;
+ private final Config config = new Config(this);
+ private final Config items = new Config(this, "Items.yml");
+ private final Config researches = new Config(this, "Researches.yml");
// Listeners that need to be accessed elsewhere
private final AncientAltarListener ancientAltarListener = new AncientAltarListener();
@@ -142,22 +143,11 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
instance = this;
// Creating all necessary Folders
- getLogger().log(Level.INFO, "Loading files...");
+ getLogger().log(Level.INFO, "Loading various systems...");
createDirectories();
-
- // Setup config.yml
- getLogger().log(Level.INFO, "Loading config...");
- config = new Config(this);
registry.load(config);
- // Loading all extra configs
- researches = new Config(this, "Researches.yml");
- items = new Config(this, "Items.yml");
- whitelist = new Config(this, "whitelist.yml");
-
- // Setup various other config files
- textureService.load();
- permissionsService.load();
+ // Set up localization
local = new LocalizationService(this, config.getString("options.language"));
// Setting up Networks
@@ -209,7 +199,7 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
new WitherListener(this);
new IronGolemListener(this);
- bowListener.load(this);
+ bowListener.register(this);
// Toggleable Listeners for performance reasons
if (config.getBoolean("items.talismans")) {
@@ -221,7 +211,7 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
}
if (config.getBoolean("items.backpacks")) {
- backpackListener.load(this);
+ backpackListener.register(this);
}
// Handle Slimefun Guide being given on Join
@@ -238,7 +228,7 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
protections = new ProtectionManager(getServer());
textureService.register(registry.getAllSlimefunItems());
permissionsService.register(registry.getAllSlimefunItems());
- recipeService.load();
+ recipeService.refresh();
}), 0);
// Setting up the command /sf and all subcommands
@@ -254,9 +244,6 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
thirdPartySupportService.start();
gitHubService.start(this);
- // Exclude the command /sf elevator from our server log, it could get quite spammy
- CSCoreLib.getLib().filterLog("([A-Za-z0-9_]{3,16}) issued server command: /sf elevator (.{0,})");
-
// Hooray!
getLogger().log(Level.INFO, "Slimefun has finished loading in {0}", getStartupTime(timestamp));
}
@@ -333,6 +320,7 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
return;
}
+ // Cancel all tasks from this plugin immediately
Bukkit.getScheduler().cancelTasks(this);
if (ticker != null) {
@@ -367,9 +355,11 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
menu.save();
}
+ // Create a new backup zip
backupService.run();
// Prevent Memory Leaks
+ // These static Maps should be removed at some point...
AContainer.processing = null;
AContainer.progress = null;
@@ -381,6 +371,8 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
instance = null;
+ // Close all inventories on the server to prevent item dupes
+ // (Incase some idiot uses /reload)
for (Player p : Bukkit.getOnlinePlayers()) {
p.closeInventory();
}
@@ -388,22 +380,21 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
private void createDirectories() {
String[] storageFolders = { "Players", "blocks", "stored-blocks", "stored-inventories", "stored-chunks", "universal-inventories", "waypoints", "block-backups" };
- String[] pluginFolders = { "scripts", "generators", "error-reports", "cache/github" };
+ String[] pluginFolders = { "scripts", "generators", "error-reports", "cache/github", "world-settings" };
for (String folder : storageFolders) {
- File file = new File("data-storage/Slimefun/" + folder);
+ File file = new File("data-storage/Slimefun", folder);
if (!file.exists()) file.mkdirs();
}
for (String folder : pluginFolders) {
- File file = new File("plugins/Slimefun/" + folder);
+ File file = new File("plugins/Slimefun", folder);
if (!file.exists()) file.mkdirs();
}
}
private void loadItems() {
try {
- PostSetup.setupItemSettings();
SlimefunItemSetup.setup(this);
}
catch (Throwable x) {
@@ -432,10 +423,6 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
return instance.items;
}
- public static Config getWhitelist() {
- return instance.whitelist;
- }
-
public static GPSNetwork getGPSNetwork() {
return instance.gpsNetwork;
}
@@ -490,6 +477,10 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
return instance.thirdPartySupportService;
}
+ public static PerWorldSettingsService getWorldSettingsService() {
+ return instance.worldSettingsService;
+ }
+
/**
* This method returns the {@link UpdaterService} of Slimefun.
* It is used to handle automatic updates.
@@ -564,6 +555,10 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
return instance.minecraftVersion;
}
+ public static String getCSCoreLibVersion() {
+ return CSCoreLib.getLib().getDescription().getVersion();
+ }
+
@Override
public JavaPlugin getJavaPlugin() {
return this;
diff --git a/src/main/java/me/mrCookieSlime/Slimefun/api/BlockStorage.java b/src/main/java/me/mrCookieSlime/Slimefun/api/BlockStorage.java
index c7dc7a916..8d632379f 100644
--- a/src/main/java/me/mrCookieSlime/Slimefun/api/BlockStorage.java
+++ b/src/main/java/me/mrCookieSlime/Slimefun/api/BlockStorage.java
@@ -38,15 +38,16 @@ import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenuPreset;
import me.mrCookieSlime.Slimefun.api.inventory.UniversalBlockMenu;
+// This class really needs a big overhaul
public class BlockStorage {
private static final String PATH_BLOCKS = "data-storage/Slimefun/stored-blocks/";
private static final String PATH_CHUNKS = "data-storage/Slimefun/stored-chunks/";
- private World world;
- private Map storage = new ConcurrentHashMap<>();
- private Map inventories = new ConcurrentHashMap<>();
- private Map blocksCache = new ConcurrentHashMap<>();
+ private final World world;
+ private final Map storage = new ConcurrentHashMap<>();
+ private final Map inventories = new ConcurrentHashMap<>();
+ private final Map blocksCache = new ConcurrentHashMap<>();
public static BlockStorage getStorage(World world) {
return SlimefunPlugin.getRegistry().getWorlds().get(world.getName());
@@ -83,9 +84,13 @@ public class BlockStorage {
}
public BlockStorage(World w) {
- if (SlimefunPlugin.getRegistry().getWorlds().containsKey(w.getName())) return;
this.world = w;
+ if (SlimefunPlugin.getRegistry().getWorlds().containsKey(w.getName())) {
+ // Cancel the loading process if the world was already loaded
+ return;
+ }
+
Slimefun.getLogger().log(Level.INFO, "Loading Blocks for World \"" + w.getName() + "\"");
Slimefun.getLogger().log(Level.INFO, "This may take a long time...");
diff --git a/src/main/java/me/mrCookieSlime/Slimefun/api/GuideHandler.java b/src/main/java/me/mrCookieSlime/Slimefun/api/GuideHandler.java
deleted file mode 100644
index f7360f0c9..000000000
--- a/src/main/java/me/mrCookieSlime/Slimefun/api/GuideHandler.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package me.mrCookieSlime.Slimefun.api;
-
-import java.util.List;
-
-import org.bukkit.entity.Player;
-
-import me.mrCookieSlime.CSCoreLibPlugin.PlayerRunnable;
-import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu;
-
-/**
- * Guide Handlers are used to add "fake" categories to the Guide.
- *
- * @deprecated Soon we will simply allow to override the "opening" method of a Category instead.
- *
- * @author TheBusyBiscuit
- *
- */
-@Deprecated
-public interface GuideHandler {
-
- void addEntry(List texts, List tooltips);
-
- PlayerRunnable getRunnable();
-
- int getTier();
-
- boolean trackHistory();
-
- int next(Player p, int index, ChestMenu menu);
-
- default PlayerRunnable getRunnable(boolean book) {
- return this.getRunnable();
- }
-
- default void run(Player p, boolean survival, boolean book) {
- this.getRunnable(book).run(p);
- }
-
-}
diff --git a/src/main/java/me/mrCookieSlime/Slimefun/api/Slimefun.java b/src/main/java/me/mrCookieSlime/Slimefun/api/Slimefun.java
index 622a241c4..2215c18ba 100644
--- a/src/main/java/me/mrCookieSlime/Slimefun/api/Slimefun.java
+++ b/src/main/java/me/mrCookieSlime/Slimefun/api/Slimefun.java
@@ -1,8 +1,5 @@
package me.mrCookieSlime.Slimefun.api;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.logging.Level;
import java.util.logging.Logger;
import org.bukkit.Bukkit;
@@ -11,8 +8,6 @@ import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.scheduler.BukkitTask;
-import io.github.thebusybiscuit.cscorelib2.config.Config;
-import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting;
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.implementation.items.VanillaItem;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
@@ -29,46 +24,10 @@ public final class Slimefun {
private Slimefun() {}
- @Deprecated
- public static void registerGuideHandler(GuideHandler handler) {
- Bukkit.getLogger().log(Level.SEVERE, "The Plugin \"EmeraldEnchants\" is outdated!");
- Bukkit.getLogger().log(Level.SEVERE, "Your version will soon stop working.");
- Bukkit.getLogger().log(Level.SEVERE, "Update it immediately: https://thebusybiscuit.github.io/builds/TheBusyBiscuit/EmeraldEnchants2/master/");
- }
-
public static Logger getLogger() {
return SlimefunPlugin.instance.getLogger();
}
- /**
- * Returns the value associated to this key for the SlimefunItem corresponding to this id.
- *
- * @deprecated Please use the {@link ItemSetting} API instead.
- *
- * @param id
- * the id of the SlimefunItem, not null
- * @param key
- * the key of the value to get, not null
- *
- * @return the value associated to the key for the SlimefunItem corresponding to the id,
- * or null if it doesn't exist.
- */
- @Deprecated
- public static Object getItemValue(String id, String key) {
- return getItemConfig().getValue(id + '.' + key);
- }
-
- /**
- * Returns the Config instance of Items.yml file.
- *
- * It calls {@code SlimefunStartup#getItemCfg()}.
- *
- * @return the Items.yml Config instance.
- */
- public static Config getItemConfig() {
- return SlimefunPlugin.getItemCfg();
- }
-
/**
* Registers this Research and automatically binds these ItemStacks to it.
*
@@ -99,13 +58,7 @@ public final class Slimefun {
}
public static void registerResearch(NamespacedKey key, int id, String name, int cost, ItemStack... items) {
- Research research = new Research(key, id, name, cost);
-
- for (ItemStack item : items) {
- research.addItems(SlimefunItem.getByItem(item));
- }
-
- research.register();
+ registerResearch(new Research(key, id, name, cost), items);
}
/**
@@ -127,7 +80,10 @@ public final class Slimefun {
if (sfItem != null) {
if (sfItem.getState() == ItemState.DISABLED) {
- if (message) SlimefunPlugin.getLocal().sendMessage(p, "messages.disabled-item", true);
+ if (message) {
+ SlimefunPlugin.getLocal().sendMessage(p, "messages.disabled-item", true);
+ }
+
return false;
}
@@ -176,6 +132,7 @@ public final class Slimefun {
return false;
}
}
+
return false;
}
@@ -200,7 +157,10 @@ public final class Slimefun {
return true;
}
else {
- if (message) SlimefunPlugin.getLocal().sendMessage(p, "messages.no-permission", true);
+ if (message) {
+ SlimefunPlugin.getLocal().sendMessage(p, "messages.no-permission", true);
+ }
+
return false;
}
}
@@ -239,43 +199,20 @@ public final class Slimefun {
*/
public static boolean isEnabled(Player p, SlimefunItem sfItem, boolean message) {
if (sfItem.isDisabled()) {
+ if (message) {
+ SlimefunPlugin.getLocal().sendMessage(p, "messages.disabled-item", true);
+ }
+
+ return false;
+ }
+ else if (!SlimefunPlugin.getWorldSettingsService().isEnabled(p.getWorld(), sfItem)) {
if (message) {
SlimefunPlugin.getLocal().sendMessage(p, "messages.disabled-in-world", true);
}
return false;
}
-
- String world = p.getWorld().getName();
- if (SlimefunPlugin.getWhitelist().contains(world + ".enabled")) {
- if (SlimefunPlugin.getWhitelist().getBoolean(world + ".enabled")) {
- if (!SlimefunPlugin.getWhitelist().contains(world + ".enabled-items." + sfItem.getID())) SlimefunPlugin.getWhitelist().setDefaultValue(world + ".enabled-items." + sfItem.getID(), true);
- if (SlimefunPlugin.getWhitelist().getBoolean(world + ".enabled-items." + sfItem.getID())) return true;
- else {
- if (message) SlimefunPlugin.getLocal().sendMessage(p, "messages.disabled-in-world", true);
- return false;
- }
- }
- else {
- if (message) SlimefunPlugin.getLocal().sendMessage(p, "messages.disabled-in-world", true);
- return false;
- }
- }
- else return true;
- }
-
- /**
- * This method will soon be removed.
- *
- * @deprecated The {@link GuideHandler} API is deprecated. It will soon be removed.
- *
- * @param tier
- * The tier
- * @return A list of handlers
- */
- @Deprecated
- public static List getGuideHandlers(int tier) {
- return SlimefunPlugin.getRegistry().getGuideHandlers().getOrDefault(tier, new ArrayList<>());
+ return true;
}
public static BukkitTask runSync(Runnable r) {
diff --git a/src/main/java/me/mrCookieSlime/Slimefun/api/SlimefunItemStack.java b/src/main/java/me/mrCookieSlime/Slimefun/api/SlimefunItemStack.java
index f560640f8..41914756c 100644
--- a/src/main/java/me/mrCookieSlime/Slimefun/api/SlimefunItemStack.java
+++ b/src/main/java/me/mrCookieSlime/Slimefun/api/SlimefunItemStack.java
@@ -3,9 +3,11 @@ package me.mrCookieSlime.Slimefun.api;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
+import java.util.Locale;
import java.util.Optional;
import java.util.function.Consumer;
+import org.apache.commons.lang.Validate;
import org.bukkit.ChatColor;
import org.bukkit.Color;
import org.bukkit.Material;
@@ -19,6 +21,8 @@ import org.bukkit.potion.PotionEffectType;
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
import io.github.thebusybiscuit.cscorelib2.item.ImmutableItemMeta;
import io.github.thebusybiscuit.cscorelib2.skull.SkullItem;
+import io.github.thebusybiscuit.slimefun4.api.exceptions.PrematureCodeException;
+import io.github.thebusybiscuit.slimefun4.utils.PatternUtils;
import me.mrCookieSlime.Slimefun.SlimefunPlugin;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
@@ -101,14 +105,14 @@ public class SlimefunItemStack extends CustomItem {
}
public SlimefunItemStack(String id, String texture, String name, String... lore) {
- super(getSkull(texture), name, lore);
- this.texture = getTexture(texture);
+ super(getSkull(id, texture), name, lore);
+ this.texture = getTexture(id, texture);
setID(id);
}
public SlimefunItemStack(String id, String texture, String name, Consumer consumer) {
- super(getSkull(texture), meta -> {
+ super(getSkull(id, texture), meta -> {
if (name != null) {
meta.setDisplayName(ChatColor.translateAlternateColorCodes('&', name));
}
@@ -116,19 +120,25 @@ public class SlimefunItemStack extends CustomItem {
consumer.accept(meta);
});
- this.texture = getTexture(texture);
+ this.texture = getTexture(id, texture);
setID(id);
}
public SlimefunItemStack(String id, String texture, Consumer consumer) {
- super(getSkull(texture), consumer);
- this.texture = getTexture(texture);
+ super(getSkull(id, texture), consumer);
+ this.texture = getTexture(id, texture);
setID(id);
}
private void setID(String id) {
+ Validate.isTrue(id.equals(id.toUpperCase(Locale.ROOT)), "Slimefun Item Ids must be uppercase! (e.g. 'MY_ITEM_ID')");
+
+ if (SlimefunPlugin.instance == null) {
+ throw new PrematureCodeException("A SlimefunItemStack must never be be created before your Plugin was enabled.");
+ }
+
this.id = id;
ItemMeta meta = getItemMeta();
@@ -149,7 +159,7 @@ public class SlimefunItemStack extends CustomItem {
* @return The {@link SlimefunItem} for this {@link SlimefunItemStack}, null if not found.
*/
public SlimefunItem getItem() {
- return SlimefunItem.getByID(this.id);
+ return SlimefunItem.getByID(id);
}
public ImmutableItemMeta getImmutableMeta() {
@@ -174,19 +184,20 @@ public class SlimefunItemStack extends CustomItem {
return Optional.ofNullable(texture);
}
- private static ItemStack getSkull(String texture) {
- return SkullItem.fromBase64(getTexture(texture));
+ private static ItemStack getSkull(String id, String texture) {
+ return SkullItem.fromBase64(getTexture(id, texture));
}
- private static String getTexture(String texture) {
- String base64 = texture;
-
- // At this point we can be sure it's not a base64 encoded texture
- if (!texture.startsWith("ey")) {
- base64 = Base64.getEncoder().encodeToString(("{\"textures\":{\"SKIN\":{\"url\":\"http://textures.minecraft.net/texture/" + texture + "\"}}}").getBytes());
+ private static String getTexture(String id, String texture) {
+ if (texture.startsWith("ey")) {
+ return texture;
+ }
+ else if (PatternUtils.ALPHANUMERIC.matcher(texture).matches()) {
+ return Base64.getEncoder().encodeToString(("{\"textures\":{\"SKIN\":{\"url\":\"http://textures.minecraft.net/texture/" + texture + "\"}}}").getBytes());
+ }
+ else {
+ throw new IllegalArgumentException("The provided texture for Item \"" + id + "\" does not seem to be a valid texture String!");
}
-
- return base64;
}
}
diff --git a/src/main/resources/languages/recipes_tr.yml b/src/main/resources/languages/recipes_tr.yml
index bb910a829..49ae5eb6e 100644
--- a/src/main/resources/languages/recipes_tr.yml
+++ b/src/main/resources/languages/recipes_tr.yml
@@ -68,8 +68,18 @@ slimefun:
food_fabricator:
lore:
- Bu eşyayı Food Fabricator kullanarak
- - gösterildiği gibi üretin.
+ - gösterildiği gibi üretin
name: Food Fabricator
+ freezer:
+ lore:
+ - Bu eşyayı Freezer kullanarak
+ - gösterildiği gibi üretin
+ name: Freezer
+ geo_miner:
+ lore:
+ - Bu eşyayı GEO Miner kullanarak
+ - elde edin
+ name: GEO Miner
gold_pan:
lore:
- Bu eşyayı almak için
@@ -105,6 +115,11 @@ slimefun:
- Gösterilen yapıyı olduğu gibi inşa edin.
- Üretim masasında üretilmez.
name: Yapı İnşa Etme
+ nuclear_reactor:
+ lore:
+ - Bu eşya Nuclear Reactor'ın
+ - bir yan ürünüdür
+ name: Nuclear Reactor
ore_crusher:
lore:
- Bu eşyayı Ore Crusher kullanarak
@@ -125,18 +140,19 @@ slimefun:
- Bu eşyayı Smeltery kullanarak
- gösterildiği gibi üretin.
name: Smeltery
- freezer:
- name: Freezer
+ oil_pump:
+ name: Oil Pump
lore:
- - Bu eşyayı Freezer kullanarak
- - gösterildiği gibi üretin
- geo_miner:
- name: GEO Miner
- lore:
- - Bu eşyayı GEO Miner kullanarak
+ - Bu eşyayı Oil Pump kullanarak
- elde edin
- nuclear_reactor:
- name: Nuclear Reactor
+ pickaxe_of_containment:
+ name: Pickaxe of Containment
lore:
- - Bu eşya Nuclear Reactor'ın
- - bir yan ürünüdür
+ - Bu bloku Pickaxe of Containment kullanarak
+ - ve bir Spawner kırarak
+ - elde edin
+ refinery:
+ name: Refinery
+ lore:
+ - Bu eşyayı Refinery kullanarak
+ - üretin
diff --git a/src/main/resources/languages/researches_tr.yml b/src/main/resources/languages/researches_tr.yml
index 323c10dc5..7950658f1 100644
--- a/src/main/resources/languages/researches_tr.yml
+++ b/src/main/resources/languages/researches_tr.yml
@@ -1,232 +1,234 @@
---
slimefun:
- walking_sticks: Bastonlar
- portable_crafter: Portatif Üretim Masası
- portable_dustbin: Portatif Çöp Kovası
- glowstone_armor: Işık Taşı Zırhı
- sword_of_beheading: Baş Kesme Kılıcı
- smeltery: Dökümhane
- misc_power_items: Güçle ilgili önemli eşyalar
- multitools: Çoklu Aletler
- solar_panel_and_helmet: Güneş Enerjisi
- elemental_staff: Elementsel Asalar
- cactus_armor: Kaktüs Takımı
- gold_pan: Altın Tavası
- magical_book_cover: Sihirli Kitap Eşleme
- gilded_iron_armor: Yaldızlı Demir Zırhı
- synthetic_sapphire: Sentetik Safirler
- damascus_steel_armor: Şam Çeliği Zırhı
- magic_workbench: Sihirli Üretim Masası
- wind_staff: Rüzgar Asası
- fire_staff: Ateş Asası
- smelters_pickaxe: Demircinin Kazması
- hazmat_suit: Koruyucu Takım
- redstone_alloy: Kızıltaş Alaşımı
- carbonado_tools: Üst Seviye Makineler
- pickaxe_of_containment: Kapsama Kazması
- hercules_pickaxe: Herkülün Kazması
- slime_steel_armor: Çelik Balçık Zırhı
- blade_of_vampires: Vampirlerin Bıçağı
- water_staff: Su Asası
- composter: Toprak Gübreleme
- farmer_shoes: Çiftçi Ayakkabıları
- explosive_tools: Patlayıcı Aletler
- automated_panning_machine: Otomatik Altın Tavası
- pickaxe_of_the_seeker: Arayıcının Kazması
- infused_magnet: Büyülü Mıknatıslar
- essence_of_afterlife: Nekromansi
- pickaxe_of_vein_mining: Damar Madenciliği Kazması
- bound_tools: Ruh Bağlı Aletler
- repaired_spawner: Çağırıcı Tamiratı
- carbonado_furnace: Kara Elmas Kaplamalı Fırın
- tome_of_knowledge_sharing: Arkadaşlarla paylaşma
- cooler: Portatif İçecekler
- ancient_runes: Elementsel Rünler
- special_runes: Mor Rünler
- infused_hopper: Büyülü Huni
- solar_generators: Güneş Enerjisi Elektrik Santrali
- bio_reactor: Biyo-Reaktör
- multimeter: Elektrik Ölçümü
- combustion_reactor: İçten Yanmalı Reaktör
- teleporter: Işınlayıcı Temel Bileşenleri
- teleporter_activation_plates: Işınlayıcı Etkinleştirmesi
- better_solar_generators: Gelişmiş Güneş Enerjisi Jeneratörleri
- better_gps_transmitters: Gelişmiş Vericiler
- organic_food: Organik Yemek
- organic_fertilizer: Organik Gübreleme
- crop_growth_accelerator: Bitki Büyümesi Hızlandırması
- better_crop_growth_accelerator: Gelişmiş Bitki Büyümesi Hızlandırıcı
- nuclear_reactor: Nükleer Enerji Santrali
- freezer: Bay Donmuş
- better_food_fabricator: Gelişmiş Yemek Üretimi
- better_freezer: Gelişmiş Dondurucu
- boosted_uranium: Sonsuz Döngü
- advanced_output_node: Gelişmiş Çıkış Noktası
- carbon_press: Karbon Presi
- electric_smeltery: Elektrikli Dökümhane
- better_electric_furnace: Gelişmiş Elektrikli Fırın
- better_carbon_press: Gelişmiş Karbon Presi
- empowered_android: Güçlendirilmiş Androidler
- high_tier_carbon_press: Güçlü Karbon Presi
- better_heated_pressure_chamber: Gelişmiş Isıtmalı Basınç Odası
- advanced_electric_smeltery: Gelişmiş Elektrikli Dökümhane
- blistering_ingots: Parlayan Radyoaktivite
- radiant_backpack: Göz Alıcı Sırt Çantası
- storm_staff: Fırtına Asası
- nether_gold_pan: Nether Altın Tavası
- magnesium_generator: Magnezyum Elektriği
- kelp_cookie: Lezzetli Yosun
- fortune_cookie: Şans Kurabiyesi
- meat_jerky: Yağsız Et
- armor_forge: Zırh Üretimi
- lumps: Yumrular ve Büyü
- ender_backpack: Ender Sırt Çantası
- ender_armor: Ender Zırhı
- magic_eye_of_ender: Sihirli Ender Gözü
- magic_sugar: Sihirli Şeker
- monster_jerky: Yağsız Yaratık Eti
- slime_armor: Balçık Zırhı
- basic_circuit_board: Temel Devre Kartı
- advanced_circuit_board: Gelişmiş Devre Kartı
- steel: Çelik Çağı
- battery: İlk Piliniz
- steel_plate: Çelik Kaplama
- steel_thruster: Çelik İtici
- parachute: Paraşüt
- grappling_hook: Kanca
- jetpacks: Jetpackler
- grind_stone: Taş Öğütücü
- slimefun_metals: Yeni Metaller
- ore_crusher: Maden Katlama
- bronze: Bronz Üretimi
- alloys: Gelişmiş Alaşımlar
- compressor_and_carbon: Karbon Üretimi
- synthetic_diamond: Sentetik Elmaslar
- pressure_chamber: Basınç Odası
- damascus_steel: Şam Çeliği
- reinforced_alloy: Güçlendirilmiş Alaşım
- carbonado: Siyah Elmaslar
- reinforced_armor: Güçlendirilmiş Zırh
- ore_washer: Maden Yıkayıcı
- gold_carats: Saf Altın
- silicon: Silikon Vadisi
- common_talisman: Sıradan Tılsım
- anvil_talisman: Örs Tılsımı
- miner_talisman: Madenci Tılsımı
- hunter_talisman: Avcı Tılsımı
- lava_talisman: Lavda Yürüyen Tılsımı
- water_talisman: Suda Nefes Alan Tılsımı
- angel_talisman: Melek Tılsımı
- fire_talisman: İtfaiyeci Tılsımı
- lava_crystal: Ateşli Durum
- magician_talisman: Sihirbaz Tılsımı
- traveller_talisman: Gezgin Tılsımı
- warrior_talisman: Savaşçı Tılsımı
- knight_talisman: Şövalye Tılsımı
- gilded_iron: Parlak Demir
- synthetic_emerald: Sahte Mücevher
- chainmail_armor: Zincir Zırh
- whirlwind_talisman: Kasırga Tılsımı
- wizard_talisman: Büyücü Tılsımı
- lumber_axe: Kereste Baltası
- uranium: Radyoaktif
- crushed_ore: Maden Arıtma
- first_aid: İlk yardım
- gold_armor: Parlak Zırh
- night_vision_googles: Gece Görüş Gözlüğü
- table_saw: Masa Testeresi
24k_gold_block: Altın Şehir
- boots_of_the_stomper: Ağır Ayak Çizmeleri
- backpacks: Sırt Çantaları
- woven_backpack: Dokuma Sırt Çantası
- crucible: Pota
- gilded_backpack: Yaldızlı Sırt Çantası
- armored_jetpack: Zırhlı Jetpack
- ender_talismans: Ender Tılsımları
- nickel_and_cobalt: Daha fazla Maden
- magnet: Manyetik Metaller
- cobalt_pickaxe: Hızlı Kazma
- bound_backpack: Ruh Bağlı Depolama
- jetboots: Jet Botlar
- armored_jetboots: Zırhlı Jet Botlar
- seismic_axe: Sismik Balta
- bound_weapons: Ruh Bağlı Silahlar
- bound_armor: Ruh Bağlı Zırhlar
- juicer: Lezzetli İçecekler
- enhanced_furnace: Geliştirilmiş Fırın
- more_enhanced_furnaces: Daha İyi Fırınlar
- high_tier_enhanced_furnaces: Yüksek Seviye Fırın
- reinforced_furnace: Güçlendirilmiş Fırın
- electric_motor: Kızışıyor
- block_placer: Blok Yerleştirici
- scroll_of_dimensional_teleposition: Bir şeyleri etrafında çevirmek
- special_bows: Robin Hood
- flask_of_knowledge: XP Depolama
- hardened_glass: Patlamalara Dayanıklı
- golden_apple_juice: Altın iksir
- ancient_altar: Antik Sunak
- wither_proof_obsidian: Wither-Geçirmez Obsidyen
- infernal_bonemeal: Şeytani Kemik Tozu
- rainbow_blocks: Gökkuşağı Blokları
- wither_proof_glass: Wither-Geçirmez Cam
- duct_tape: Koli Bandı
- plastic_sheet: Plastik
- android_memory_core: Bellek Çekirdeği
- oil: Petrol
- fuel: Yakıt
- hologram_projector: Hologramlar
- capacitors: Seviye 1 Kapasitörler
- high_tier_capacitors: Seviye 2 Kapasitörler
- electric_furnaces: Elektrikli Fırın
- electric_ore_grinding: Kırma ve Öğütme
- heated_pressure_chamber: Isıtmalı Basınç Odası
- coal_generator: Kömür Jeneratörü
- auto_enchanting: Otomatik Büyüleyici ve Büyü Sökücü
- wither_assembler: Otomatik Wither Öldürücü
- elytra: Elytralar
- special_elytras: Özel Elytralar
- nether_ice: Nether Buzu Soğutucu
- output_chest: Temel Makine Çıkış Sandığı
- soulbound_rune: Ruh Bağı Rünü
- geo_miner: GEO-Madenci
- lightning_rune: Yıldırım Rünü
- auto_anvil: Otomatik Örs
- gps_setup: Temel GPS Kurulumu
- gps_emergency_transmitter: GPS Acil Durum Noktası
- programmable_androids: Programlanabilir Androidler
- android_interfaces: Android Arayüzleri
- geo_scanner: GEO-Taramalar
- elevator: Asansörler
- energized_solar_generator: Tam Zamanlı Güneş Enerjisi
- energized_gps_transmitter: Üst Seviye Verici
- energy_regulator: Enerji Ağları 101
- butcher_androids: Kasap Androidleri
- auto_breeder: Otomatik Besleme
advanced_android: Gelişmiş Androidler
advanced_butcher_android: Gelişmiş Androidler - Kasap
+ advanced_circuit_board: Gelişmiş Devre Kartı
+ advanced_electric_smeltery: Gelişmiş Elektrikli Dökümhane
+ advanced_farmer_android: Gelişmiş Androidler - Çiftçi
advanced_fisherman_android: Gelişmiş Androidler - Balıkçı
+ advanced_output_node: Gelişmiş Çıkış Noktası
+ alloys: Gelişmiş Alaşımlar
+ ancient_altar: Antik Sunak
+ ancient_runes: Elementsel Rünler
+ android_interfaces: Android Arayüzleri
+ android_memory_core: Bellek Çekirdeği
+ angel_talisman: Melek Tılsımı
animal_growth_accelerator: Hayvan Büyüme Manipülasyonu
- xp_collector: XP Toplayıcı
- reactor_essentials: Reaktör Temelleri
+ anvil_talisman: Örs Tılsımı
+ armored_jetboots: Zırhlı Jet Botlar
+ armored_jetpack: Zırhlı Jetpack
+ armor_forge: Zırh Üretimi
+ auto_anvil: Otomatik Örs
+ auto_breeder: Otomatik Besleme
+ auto_drier: Kuru Bir Gün
+ auto_enchanting: Otomatik Büyüleyici ve Büyü Sökücü
+ automated_crafting_chamber: Otomatik Üretim
+ automated_panning_machine: Otomatik Altın Tavası
+ automatic_ignition_chamber: Otomatik Ateşleme Odası
+ backpacks: Sırt Çantaları
+ basic_circuit_board: Temel Devre Kartı
+ battery: İlk Piliniz
+ better_carbon_press: Gelişmiş Karbon Presi
+ better_crop_growth_accelerator: Gelişmiş Bitki Büyümesi Hızlandırıcı
+ better_electric_crucibles: Sıcak Potalar
+ better_electric_furnace: Gelişmiş Elektrikli Fırın
+ better_food_fabricator: Gelişmiş Yemek Üretimi
+ better_freezer: Gelişmiş Dondurucu
+ better_gps_transmitters: Gelişmiş Vericiler
+ better_heated_pressure_chamber: Gelişmiş Isıtmalı Basınç Odası
+ better_solar_generators: Gelişmiş Güneş Enerjisi Jeneratörleri
+ bio_reactor: Biyo-Reaktör
+ blade_of_vampires: Vampirlerin Bıçağı
+ blistering_ingots: Parlayan Radyoaktivite
+ block_placer: Blok Yerleştirici
+ boosted_uranium: Sonsuz Döngü
+ boots_of_the_stomper: Ağır Ayak Çizmeleri
+ bound_armor: Ruh Bağlı Zırhlar
+ bound_backpack: Ruh Bağlı Depolama
+ bound_tools: Ruh Bağlı Aletler
+ bound_weapons: Ruh Bağlı Silahlar
+ bronze: Bronz Üretimi
+ butcher_androids: Kasap Androidleri
+ cactus_armor: Kaktüs Takımı
+ capacitors: Seviye 1 Kapasitörler
+ carbonado: Siyah Elmaslar
+ carbonado_furnace: Kara Elmas Kaplamalı Fırın
+ carbonado_tools: Üst Seviye Makineler
+ carbon_press: Karbon Presi
cargo_basics: Kargo Temelleri
cargo_nodes: Kargo Kurulumu
+ chainmail_armor: Zincir Zırh
+ charging_bench: Şarj Tezgahı
+ coal_generator: Kömür Jeneratörü
+ cobalt_pickaxe: Hızlı Kazma
+ combustion_reactor: İçten Yanmalı Reaktör
+ common_talisman: Sıradan Tılsım
+ composter: Toprak Gübreleme
+ compressor_and_carbon: Karbon Üretimi
+ cooler: Portatif İçecekler
+ copper_wire: İnceltilmiş İletkenlik
+ crop_growth_accelerator: Bitki Büyümesi Hızlandırması
+ crucible: Pota
+ crushed_ore: Maden Arıtma
+ damascus_steel: Şam Çeliği
+ damascus_steel_armor: Şam Çeliği Zırhı
+ diet_cookie: Diyet Kurabiyesi
+ duct_tape: Koli Bandı
+ electric_crucible: Elektrikli Pota
+ electric_furnaces: Elektrikli Fırın
electric_ingot_machines: Elektrikli Külçe İmalatı
- high_tier_electric_ingot_machines: Süper Hızlı Külçe İmalatı
- automated_crafting_chamber: Otomatik Üretim
- reactor_access_port: Reaktör Etkileşimi
- fluid_pump: Sıvı Pompası
- trash_can: Çöp
+ electric_motor: Kızışıyor
+ electric_ore_grinding: Kırma ve Öğütme
+ electric_press: Elektrikli Pres
+ electric_smeltery: Elektrikli Dökümhane
+ elemental_staff: Elementsel Asalar
+ elevator: Asansörler
+ elytra: Elytralar
+ empowered_android: Güçlendirilmiş Androidler
empowered_butcher_android: Güçlendirilmiş Androidler - Kasap
empowered_fisherman_android: Güçlendirilmiş Androidler - Balıkçı
- electric_crucible: Elektrikli Pota
- better_electric_crucibles: Sıcak Potalar
- advanced_farmer_android: Gelişmiş Androidler - Çiftçi
+ ender_armor: Ender Zırhı
+ ender_backpack: Ender Sırt Çantası
+ ender_talismans: Ender Tılsımları
+ energized_gps_transmitter: Üst Seviye Verici
+ energized_solar_generator: Tam Zamanlı Güneş Enerjisi
+ energy_regulator: Enerji Ağları 101
+ enhanced_furnace: Geliştirilmiş Fırın
+ essence_of_afterlife: Nekromansi
+ explosive_tools: Patlayıcı Aletler
+ farmer_shoes: Çiftçi Ayakkabıları
+ fire_staff: Ateş Asası
+ fire_talisman: İtfaiyeci Tılsımı
+ first_aid: İlk yardım
+ flask_of_knowledge: XP Depolama
+ fluid_pump: Sıvı Pompası
+ fortune_cookie: Şans Kurabiyesi
+ freezer: Bay Donmuş
+ fuel: Yakıt
+ geo_miner: GEO-Madenci
+ geo_scanner: GEO-Taramalar
+ gilded_backpack: Yaldızlı Sırt Çantası
+ gilded_iron: Parlak Demir
+ gilded_iron_armor: Yaldızlı Demir Zırhı
+ glowstone_armor: Işık Taşı Zırhı
+ gold_armor: Parlak Zırh
+ gold_carats: Saf Altın
+ golden_apple_juice: Altın iksir
+ gold_pan: Altın Tavası
+ gps_emergency_transmitter: GPS Acil Durum Noktası
+ gps_setup: Temel GPS Kurulumu
+ grappling_hook: Kanca
+ grind_stone: Taş Öğütücü
+ hardened_glass: Patlamalara Dayanıklı
+ hazmat_suit: Koruyucu Takım
+ heated_pressure_chamber: Isıtmalı Basınç Odası
+ hercules_pickaxe: Herkülün Kazması
+ high_tier_capacitors: Seviye 2 Kapasitörler
+ high_tier_carbon_press: Güçlü Karbon Presi
+ high_tier_electric_ingot_machines: Süper Hızlı Külçe İmalatı
+ high_tier_enhanced_furnaces: Yüksek Seviye Fırın
+ hologram_projector: Hologramlar
+ hunter_talisman: Avcı Tılsımı
+ infernal_bonemeal: Şeytani Kemik Tozu
+ infused_hopper: Büyülü Huni
+ infused_magnet: Büyülü Mıknatıslar
+ jetboots: Jet Botlar
+ jetpacks: Jetpackler
+ juicer: Lezzetli İçecekler
+ kelp_cookie: Lezzetli Yosun
+ knight_talisman: Şövalye Tılsımı
+ lava_crystal: Ateşli Durum
lava_generator: Lav Jeneratörü
+ lava_talisman: Lavda Yürüyen Tılsımı
+ lightning_rune: Yıldırım Rünü
+ lumber_axe: Kereste Baltası
+ lumps: Yumrular ve Büyü
+ magical_book_cover: Sihirli Kitap Eşleme
+ magic_eye_of_ender: Sihirli Ender Gözü
+ magician_talisman: Sihirbaz Tılsımı
+ magic_sugar: Sihirli Şeker
+ magic_workbench: Sihirli Üretim Masası
+ magnesium_generator: Magnezyum Elektriği
+ magnet: Manyetik Metaller
+ meat_jerky: Yağsız Et
+ miner_talisman: Madenci Tılsımı
+ misc_power_items: Güçle ilgili önemli eşyalar
+ monster_jerky: Yağsız Yaratık Eti
+ more_enhanced_furnaces: Daha İyi Fırınlar
+ multimeter: Elektrik Ölçümü
+ multitools: Çoklu Aletler
+ nether_gold_pan: Nether Altın Tavası
+ nether_ice: Nether Buzu Soğutucu
nether_star_reactor: Nether Yıldız Reaktörü
- automatic_ignition_chamber: Otomatik Ateşleme Odası
- copper_wire: İnceltilmiş İletkenlik
- auto_drier: Kuru Bir Gün
- diet_cookie: Diyet Kurabiyesi
+ nickel_and_cobalt: Daha fazla Maden
+ night_vision_googles: Gece Görüş Gözlüğü
+ nuclear_reactor: Nükleer Enerji Santrali
+ oil: Petrol
+ ore_crusher: Maden Katlama
+ ore_washer: Maden Yıkayıcı
+ organic_fertilizer: Organik Gübreleme
+ organic_food: Organik Yemek
+ output_chest: Temel Makine Çıkış Sandığı
+ parachute: Paraşüt
+ pickaxe_of_containment: Kapsama Kazması
+ pickaxe_of_the_seeker: Arayıcının Kazması
+ pickaxe_of_vein_mining: Damar Madenciliği Kazması
+ plastic_sheet: Plastik
+ portable_crafter: Portatif Üretim Masası
+ portable_dustbin: Portatif Çöp Kovası
+ pressure_chamber: Basınç Odası
+ programmable_androids: Programlanabilir Androidler
+ radiant_backpack: Göz Alıcı Sırt Çantası
+ rainbow_blocks: Gökkuşağı Blokları
+ reactor_access_port: Reaktör Etkileşimi
+ reactor_essentials: Reaktör Temelleri
+ redstone_alloy: Kızıltaş Alaşımı
+ reinforced_alloy: Güçlendirilmiş Alaşım
+ reinforced_armor: Güçlendirilmiş Zırh
+ reinforced_furnace: Güçlendirilmiş Fırın
+ repaired_spawner: Çağırıcı Tamiratı
+ scroll_of_dimensional_teleposition: Bir şeyleri etrafında çevirmek
+ seismic_axe: Sismik Balta
+ silicon: Silikon Vadisi
+ slime_armor: Balçık Zırhı
+ slimefun_metals: Yeni Metaller
+ slime_steel_armor: Çelik Balçık Zırhı
+ smelters_pickaxe: Demircinin Kazması
+ smeltery: Dökümhane
+ solar_generators: Güneş Enerjisi Elektrik Santrali
+ solar_panel_and_helmet: Güneş Enerjisi
+ soulbound_rune: Ruh Bağı Rünü
+ special_bows: Robin Hood
+ special_elytras: Özel Elytralar
+ special_runes: Mor Rünler
+ steel: Çelik Çağı
+ steel_plate: Çelik Kaplama
+ steel_thruster: Çelik İtici
+ storm_staff: Fırtına Asası
+ sword_of_beheading: Baş Kesme Kılıcı
+ synthetic_diamond: Sentetik Elmaslar
+ synthetic_emerald: Sahte Mücevher
+ synthetic_sapphire: Sentetik Safirler
+ table_saw: Masa Testeresi
+ teleporter: Işınlayıcı Temel Bileşenleri
+ teleporter_activation_plates: Işınlayıcı Etkinleştirmesi
+ tome_of_knowledge_sharing: Arkadaşlarla paylaşma
totem_of_undying: Ölümsüzlük Totemi
- charging_bench: Şarj Tezgahı
- electric_press: Elektrikli Pres
+ trash_can: Çöp
+ traveller_talisman: Gezgin Tılsımı
+ uranium: Radyoaktif
+ walking_sticks: Bastonlar
+ warrior_talisman: Savaşçı Tılsımı
+ water_staff: Su Asası
+ water_talisman: Suda Nefes Alan Tılsımı
+ whirlwind_talisman: Kasırga Tılsımı
+ wind_staff: Rüzgar Asası
+ wither_assembler: Otomatik Wither Öldürücü
+ wither_proof_glass: Wither-Geçirmez Cam
+ wither_proof_obsidian: Wither-Geçirmez Obsidyen
+ wizard_talisman: Büyücü Tılsımı
+ woven_backpack: Dokuma Sırt Çantası
+ xp_collector: XP Toplayıcı
+ makeshift_smeltery: Doğaçlama Dökümhane
+ tree_growth_accelerator: Daha Hızlı Ağaçlar