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

Merge branch 'master' into api/slimefun-item-get-optional-by

This commit is contained in:
JustAHuman-xD 2023-08-29 16:55:22 -05:00 committed by GitHub
commit 6a34470b47
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
181 changed files with 3406 additions and 756 deletions

View File

@ -113,6 +113,7 @@ body:
label: '🎮 Minecraft Version'
description: 'Please select the Minecraft version of the server'
options:
- 1.20.x
- 1.19.x
- 1.18.x
- 1.17.x

View File

@ -17,7 +17,7 @@
<!-- Don't worry, these are not requirements. They only serve as guidance. -->
- [ ] I have fully tested the proposed changes and promise that they will not break everything into chaos.
- [ ] I have also tested the proposed changes in combination with various popular addons and can confirm my changes do not break them.
- [ ] I have made sure that the proposed changes do not break compatibility across the supported Minecraft versions (1.16.* - 1.19.*).
- [ ] I have made sure that the proposed changes do not break compatibility across the supported Minecraft versions (1.16.* - 1.20.*).
- [ ] I followed the existing code standards and didn't mess up the formatting.
- [ ] I did my best to add documentation to any public classes or methods I added.
- [ ] I have added `Nonnull` and `Nullable` annotations to my methods to indicate their behaviour for null values

View File

@ -20,7 +20,7 @@ jobs:
steps:
- name: Approve via actions
uses: hmarr/auto-approve-action@v3.2.0
uses: hmarr/auto-approve-action@v3.2.1
if: github.actor == 'TheBusyBot' || github.actor == 'renovate[bot]'
with:
github-token: "${{ secrets.GITHUB_TOKEN }}"

View File

@ -22,7 +22,7 @@ jobs:
steps:
- name: Auto squash
uses: pascalgn/automerge-action@v0.15.5
uses: pascalgn/automerge-action@v0.15.6
env:
GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }}
UPDATE_RETRIES: 0
@ -42,7 +42,7 @@ jobs:
steps:
- name: Auto squash
uses: pascalgn/automerge-action@v0.15.5
uses: pascalgn/automerge-action@v0.15.6
env:
GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }}
UPDATE_RETRIES: 0

View File

@ -21,10 +21,10 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v3.3.0
uses: actions/checkout@v3.5.3
- name: Set up Java JDK 17
uses: actions/setup-java@v3.10.0
uses: actions/setup-java@v3.12.0
with:
distribution: 'adopt'
java-version: '17'

View File

@ -28,7 +28,7 @@ jobs:
uses: actions/checkout@v3
- name: Set up JDK 17
uses: actions/setup-java@v3.10.0
uses: actions/setup-java@v3.12.0
with:
distribution: 'adopt'
java-version: '17'

View File

@ -11,7 +11,7 @@ permissions:
jobs:
validate:
if: github.repository == 'Slimefun/Slimefun4'
name: Check for merge conflicts
runs-on: ubuntu-latest

View File

@ -1,7 +1,7 @@
name: Pull Request Labels
on:
pull_request:
pull_request_target:
types:
- opened
@ -31,7 +31,7 @@ jobs:
api: '🔧 API'
compatibility: '🤝 Compatibility'
- uses: thollander/actions-comment-pull-request@v2.3.1
- uses: thollander/actions-comment-pull-request@v2.4.2
name: Leave a comment about the applied label
if: ${{ steps.labeller.outputs.applied != 0 }}
with:
@ -40,7 +40,7 @@ jobs:
Your Pull Request was automatically labelled as: "${{ steps.labeller.outputs.applied }}"
Thank you for contributing to this project! ❤️
- uses: thollander/actions-comment-pull-request@v2.3.1
- uses: thollander/actions-comment-pull-request@v2.4.2
name: Leave a comment about our branch naming convention
if: ${{ steps.labeller.outputs.applied == 0 }}
with:

82
.github/workflows/preview-builds.yml vendored Normal file
View File

@ -0,0 +1,82 @@
name: Preview builds
on:
workflow_run:
workflows: ["Pull Request"]
types:
- completed
permissions:
contents: read
pull-requests: write
jobs:
preview:
if: ${{ github.repository_owner == 'Slimefun' && github.event.workflow_run.conclusion == 'success' }}
name: Build and Publish the jar
runs-on: ubuntu-latest
steps:
# Kinda jank way to grab the PR and commit hash and then download the artifact
# TODO: Move this code to our own mini-action
- name: Grab PR & run ID and download the artifact
uses: actions/github-script@v6
with:
script: |
const allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.payload.workflow_run.id,
});
for (const artifact of allArtifacts.data.artifacts) {
// Extract the PR number and commit hash from the artifact name
const match = /^slimefun-(\d+)-([a-f0-9]{8})$/.exec(artifact.name);
if (match) {
require("fs").appendFileSync(
process.env.GITHUB_ENV,
`\nPR_NUMBER=${match[1]}` +
`\nCOMMIT_HASH=${match[2]}`
);
const download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: artifact.id,
archive_format: 'zip',
});
require('fs').writeFileSync(`${process.env.GITHUB_WORKSPACE}/preview.zip`, Buffer.from(download.data))
break;
}
}
# Unzip the artifact
- name: Unzip
run: |
unzip preview.zip
rm preview.zip
mv 'Slimefun vPreview Build #${{ env.PR_NUMBER }}-${{ env.COMMIT_HASH }}.jar' preview.jar
- name: Upload to preview service
run: |
curl -X POST \
-H 'Authorization: ${{ secrets.PUBLISH_TOKEN }}' \
-H "X-Checksum: $(sha256sum 'preview.jar' | awk '{print $1}')" \
--data-binary '@preview.jar' \
https://preview-builds.walshy.dev/upload/Slimefun/${{ env.PR_NUMBER }}/${{ env.COMMIT_HASH }}
- name: Post comment
uses: marocchino/sticky-pull-request-comment@v2
with:
number: ${{ env.PR_NUMBER }}
message: |
### Slimefun preview build
A Slimefun preview build is available for testing!
Commit: ${{ env.COMMIT_HASH }}
https://preview-builds.walshy.dev/download/Slimefun/${{ env.PR_NUMBER }}/${{ env.COMMIT_HASH }}
> **Note**: This is not a supported build and is only here for the purposes of testing.
> Do not run this on a live server and do not report bugs anywhere but this PR!

52
.github/workflows/pull-request.yml vendored Normal file
View File

@ -0,0 +1,52 @@
name: Pull Request
on:
pull_request:
paths:
- '.github/workflows/**'
- 'src/**'
- 'pom.xml'
permissions:
contents: read
jobs:
setup-preview-build:
name: Preview build
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Set up JDK 17
uses: actions/setup-java@v3.12.0
with:
distribution: 'adopt'
java-version: '17'
java-package: jdk
architecture: x64
- name: Cache Maven packages
uses: actions/cache@v3
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2
# Setup for the preview build
- run: |
SHORT_COMMIT_HASH=$(git rev-parse --short=8 ${{ github.sha }})
JAR_VERSION="Preview Build #${{ github.event.number }}-$SHORT_COMMIT_HASH"
echo "SHORT_COMMIT_HASH=$SHORT_COMMIT_HASH" >> "$GITHUB_ENV"
echo "JAR_VERSION=$JAR_VERSION" >> "$GITHUB_ENV"
sed -i "s/<version>4.9-UNOFFICIAL<\/version>/<version>$JAR_VERSION<\/version>/g" pom.xml
- name: Build with Maven
run: mvn package
- name: Upload the artifact
uses: actions/upload-artifact@v3
with:
name: slimefun-${{ github.event.number }}-${{ env.SHORT_COMMIT_HASH }}
path: 'target/Slimefun v${{ env.JAR_VERSION }}.jar'

View File

@ -19,12 +19,12 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v3.3.0
uses: actions/checkout@v3.5.3
with:
fetch-depth: 0
- name: Set up JDK 17
uses: actions/setup-java@v3.10.0
uses: actions/setup-java@v3.12.0
with:
distribution: 'adopt'
java-version: '17'

View File

@ -1,5 +1,7 @@
# Table of contents
- [Release Candidate 34 (TBD)](#release-candidate-34-tbd)
- [Release Candidate 36 (TBD)](#release-candidate-36-tbd)
- [Release Candidate 35 (7 Jul 2023)](#release-candidate-35-7-jul-2023)
- [Release Candidate 34 (20 Jun 2023)](#release-candidate-34-20-jun-2023)
- [Release Candidate 33 (07 Jan 2023)](#release-candidate-33-07-jan-2023)
- [Release Candidate 32 (26 Jun 2022)](#release-candidate-32-26-jun-2022)
- [Release Candidate 31 (14 Mar 2022)](#release-candidate-31-14-mar-2022)
@ -34,8 +36,33 @@
- [Release Candidate 2 (29 Sep 2019)](#release-candidate-2-29-sep-2019)
- [Release Candidate 1 (26 Sep 2019)](#release-candidate-1-26-sep-2019)
## Release Candidate 36 (TBD)
## Release Candidate 34 (TBD)
#### Additions
#### Changes
#### Fixes
## Release Candidate 35 (7 Jul 2023)
#### Additions
* Added `sounds.yml` file to configure sound effects for Slimefun
* Added preview builds to the repo, PRs will now have a build which testers can use
* (API) Added SlimefunBlockBreakEvent and SlimefunBlockPlaceEvent events for plugins/addons to implement
* (API) Added an efficient way to clear BlockStorage within a chunk - BlockStorage.clearAllBlockInfoAtChunk
* (API) Added DistinctiveItem, a way to distinguish your item with more than just ID
* (API) Added ExternallyInteractable, a way for addons to define "interactions" for blocks
#### Changes
* Moved all sound effects to the new sound system
#### Fixes
* Fixed recipe shift in multiblocks when items are disabled (#3286)
* Fixed backpack dupe within cargo (#3379)
## Release Candidate 34 (20 Jun 2023)
https://thebusybiscuit.github.io/builds/TheBusyBiscuit/Slimefun4/stable/#34
#### Additions
* Added "Cobbled Deepslate -> Gravel" recipe to the Grind Stone
@ -45,6 +72,8 @@
* (API) Added EnergyNet#getConsumers()
* Added Bamboo as a fuel type for Tier 1 Androids
* Added "Basalt -> Blackstone" recipe to the Grind Stone
* Added a way to automate salt with the Ore Washer
* Added compatibility for Minecraft 1.20
#### Changes
* Removed 1.14.* and 1.15.* support
@ -56,6 +85,7 @@
* Tuff
* Clay
* Skulk
* Lumber Axe no longer works when shifting
#### Fixes
* Fixed #3741
@ -64,6 +94,13 @@
* Fixed #3758
* Fixed #3701
* Fixed #3361
* Fixed #3254
* Fixed #3443
* Fixed #3511
* Fixed #3524
* Fixed #3657
* Fixed #3768
* Fixed #3414
## Release Candidate 33 (07 Jan 2023)
https://thebusybiscuit.github.io/builds/TheBusyBiscuit/Slimefun4/stable/#33

View File

@ -30,7 +30,7 @@ Here is a full summary of the differences between the two different versions of
| | development (latest) | "stable" |
| ------------------ | -------- | -------- |
| **Minecraft version(s)** | :video_game: **1.16.\* - 1.19.\*** | :video_game: **1.14.\* - 1.19.\*** |
| **Minecraft version(s)** | :video_game: **1.16.\* - 1.20.\*** | :video_game: **1.16.\* - 1.20.\*** |
| **Java version** | :computer: **Java 16 (or higher)** | :computer: **Java 16 (or higher)** |
| **automatic updates** | :heavy_check_mark: | :heavy_check_mark: |
| **frequent updates** | :heavy_check_mark: | :x: |

41
pom.xml
View File

@ -26,7 +26,7 @@
<maven.compiler.target>16</maven.compiler.target>
<!-- Spigot properties -->
<spigot.version>1.19</spigot.version>
<spigot.version>1.20</spigot.version>
<spigot.javadocs>https://hub.spigotmc.org/javadocs/spigot/</spigot.javadocs>
<!-- Default settings for sonarcloud.io -->
@ -63,7 +63,7 @@
<repository>
<!-- PaperLib -->
<id>paper-repo</id>
<url>https://papermc.io/repo/repository/maven-public</url>
<url>https://repo.papermc.io/repository/maven-public/</url>
</repository>
<repository>
<!-- ItemsAdder -->
@ -130,7 +130,7 @@
<!-- Attach sources -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
<version>3.3.0</version>
<executions>
<execution>
@ -146,7 +146,7 @@
<!-- Plugin for Unit Tests -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M9</version>
<version>3.1.2</version>
<configuration>
<junitArtifactName>org.junit.jupiter:junit-jupiter</junitArtifactName>
@ -165,7 +165,7 @@
<!-- Code Coverage Reports -->
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.8</version>
<version>0.8.10</version>
<executions>
<execution>
@ -191,7 +191,7 @@
<!-- Dependency shading -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.4.1</version>
<version>3.5.0</version>
<configuration>
<!-- Relocate these to avoid clashes and conflicts -->
@ -351,10 +351,11 @@
</dependency>
<!-- Shaded packages -->
<!-- TODO: Revert changes back to maven when dough 1.3 released -->
<dependency>
<groupId>io.github.baked-libs</groupId>
<groupId>com.github.baked-libs.dough</groupId>
<artifactId>dough-api</artifactId>
<version>1.2.0</version>
<version>d3b0997226</version>
<scope>compile</scope>
</dependency>
<dependency>
@ -366,7 +367,7 @@
<dependency>
<groupId>com.konghq</groupId>
<artifactId>unirest-java</artifactId>
<version>3.14.1</version>
<version>3.14.5</version>
<scope>compile</scope>
<exclusions>
@ -382,13 +383,19 @@
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.9.2</version>
<version>5.10.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.2.0</version>
<version>5.4.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.7</version>
<scope>test</scope>
</dependency>
<dependency>
@ -411,7 +418,7 @@
<dependency>
<groupId>com.sk89q.worldedit</groupId>
<artifactId>worldedit-core</artifactId>
<version>7.2.13</version>
<version>7.2.15</version>
<scope>provided</scope>
<exclusions>
@ -425,7 +432,7 @@
<dependency>
<groupId>com.sk89q.worldedit</groupId>
<artifactId>worldedit-bukkit</artifactId>
<version>7.2.13</version>
<version>7.2.15</version>
<scope>provided</scope>
<exclusions>
@ -439,7 +446,7 @@
<dependency>
<groupId>com.gmail.nossr50.mcMMO</groupId>
<artifactId>mcMMO</artifactId>
<version>2.1.218</version>
<version>2.1.222</version>
<scope>provided</scope>
<exclusions>
@ -453,7 +460,7 @@
<dependency>
<groupId>me.clip</groupId>
<artifactId>placeholderapi</artifactId>
<version>2.11.2</version>
<version>2.11.3</version>
<scope>provided</scope>
<exclusions>
@ -481,7 +488,7 @@
<dependency>
<groupId>com.github.LoneDev6</groupId>
<artifactId>itemsadder-api</artifactId>
<version>3.2.5</version>
<version>3.5.0b</version>
<scope>provided</scope>
<exclusions>
@ -495,7 +502,7 @@
<dependency>
<groupId>net.imprex</groupId>
<artifactId>orebfuscator-api</artifactId>
<version>5.3.0</version>
<version>5.3.3</version>
<scope>provided</scope>
<exclusions>

View File

@ -43,6 +43,12 @@ public enum MinecraftVersion {
*/
MINECRAFT_1_19(19, "1.19.x"),
/**
* This constant represents Minecraft (Java Edition) Version 1.20
* ("The Trails &amp; Tales Update")
*/
MINECRAFT_1_20(20, "1.20.x"),
/**
* This constant represents an exceptional state in which we were unable
* to identify the Minecraft Version we are using

View File

@ -0,0 +1,106 @@
package io.github.thebusybiscuit.slimefun4.api.events;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.bukkit.event.block.BlockEvent;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
/**
* This {@link Event} is fired whenever a {@link SlimefunItem} placed as a {@link Block} in the world is broken.
*
* @author J3fftw1
*/
public class SlimefunBlockBreakEvent extends Event implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private final Block blockBroken;
private final SlimefunItem slimefunItem;
private final ItemStack heldItem;
private final Player player;
private boolean cancelled = false;
/**
* @param player
* The {@link Player} who broke this {@link SlimefunItem}
* @param heldItem
* The {@link ItemStack} held by the {@link Player}
* @param blockBroken
* The {@link Block} broken by the {@link Player}
* @param slimefunItem
* The {@link SlimefunItem} within the {@link ItemStack}
*/
@ParametersAreNonnullByDefault
public SlimefunBlockBreakEvent(Player player, ItemStack heldItem, Block blockBroken, SlimefunItem slimefunItem) {
super();
this.player = player;
this.heldItem = heldItem;
this.blockBroken = blockBroken;
this.slimefunItem = slimefunItem;
}
/**
* This gets the broken {@link Block}
*
* @return The broken {@link Block}
*/
public @Nonnull Block getBlockBroken() {
return blockBroken;
}
/**
* This gets the {@link SlimefunItem} being broken
*
* @return The {@link SlimefunItem} being broken
*/
public @Nonnull SlimefunItem getSlimefunItem() {
return slimefunItem;
}
/**
* The {@link ItemStack} held by the {@link Player}
*
* @return The held {@link ItemStack}
*/
public @Nonnull ItemStack getHeldItem() {
return heldItem;
}
/**
* This gets the {@link Player}
*
* @return The {@link Player}
*/
public @Nonnull Player getPlayer() {
return player;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
public static @Nonnull HandlerList getHandlerList() {
return handlers;
}
@Override
public @Nonnull HandlerList getHandlers() {
return getHandlerList();
}
}

View File

@ -0,0 +1,105 @@
package io.github.thebusybiscuit.slimefun4.api.events;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
/**
* This {@link Event} is fired whenever a {@link SlimefunItem} is placed as a {@link Block} in the world.
*
* @author J3fftw1
*/
public class SlimefunBlockPlaceEvent extends Event implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private final Block blockPlaced;
private final SlimefunItem slimefunItem;
private final ItemStack placedItem;
private final Player player;
private boolean cancelled = false;
/**
* @param player
* The {@link Player} who placed this {@link SlimefunItem}
* @param placedItem
* The {@link ItemStack} held by the {@link Player}
* @param blockPlaced
* The {@link Block} placed by the {@link Player}
* @param slimefunItem
* The {@link SlimefunItem} within the {@link ItemStack}
*/
@ParametersAreNonnullByDefault
public SlimefunBlockPlaceEvent(Player player, ItemStack placedItem, Block blockPlaced, SlimefunItem slimefunItem) {
super();
this.player = player;
this.placedItem = placedItem;
this.blockPlaced = blockPlaced;
this.slimefunItem = slimefunItem;
}
/**
* This gets the placed {@link Block}
*
* @return The placed {@link Block}
*/
public @Nonnull Block getBlockPlaced() {
return blockPlaced;
}
/**
* This gets the {@link SlimefunItem} being placed
*
* @return The {@link SlimefunItem} being placed
*/
public @Nonnull SlimefunItem getSlimefunItem() {
return slimefunItem;
}
/**
* This gets the placed {@link ItemStack}.
*
* @return The placed {@link ItemStack}
*/
public @Nonnull ItemStack getItemStack() {
return placedItem;
}
/**
* This gets the {@link Player}
*
* @return The {@link Player}
*/
public @Nonnull Player getPlayer() {
return player;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
public static @Nonnull HandlerList getHandlerList() {
return handlers;
}
@Override
public @Nonnull HandlerList getHandlers() {
return getHandlerList();
}
}

View File

@ -15,7 +15,6 @@ import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.Sound;
import org.bukkit.World;
import org.bukkit.World.Environment;
import org.bukkit.entity.Player;
@ -29,6 +28,7 @@ import io.github.thebusybiscuit.slimefun4.api.geo.GEOResource;
import io.github.thebusybiscuit.slimefun4.api.geo.ResourceManager;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
import io.github.thebusybiscuit.slimefun4.implementation.items.gps.GPSTransmitter;
@ -257,7 +257,7 @@ public class GPSNetwork {
menu.addItem(slot, new CustomItemStack(waypoint.getIcon(), waypoint.getName().replace("player:death ", ""), "&8\u21E8 &7World: &f" + l.getWorld().getName(), "&8\u21E8 &7X: &f" + l.getX(), "&8\u21E8 &7Y: &f" + l.getY(), "&8\u21E8 &7Z: &f" + l.getZ(), "", "&8\u21E8 &cClick to delete"));
menu.addMenuClickHandler(slot, (pl, s, item, action) -> {
profile.removeWaypoint(waypoint);
pl.playSound(pl.getLocation(), Sound.UI_BUTTON_CLICK, 1F, 1F);
SoundEffect.GPS_NETWORK_OPEN_PANEL_SOUND.playFor(p);
openWaypointControlPanel(pl);
return false;
@ -290,7 +290,7 @@ public class GPSNetwork {
}
Slimefun.getLocalization().sendMessage(p, "gps.waypoint.new", true);
p.playSound(p.getLocation(), Sound.BLOCK_NOTE_BLOCK_PLING, 0.5F, 1F);
SoundEffect.GPS_NETWORK_CREATE_WAYPOINT.playFor(p);
ChatInput.waitForPlayer(Slimefun.instance(), p, message -> addWaypoint(p, message, l));
});
@ -333,7 +333,7 @@ public class GPSNetwork {
profile.addWaypoint(new Waypoint(profile, id, event.getLocation(), event.getName()));
p.playSound(p.getLocation(), Sound.BLOCK_NOTE_BLOCK_PLING, 1F, 1F);
SoundEffect.GPS_NETWORK_ADD_WAYPOINT.playFor(p);
Slimefun.getLocalization().sendMessage(p, "gps.waypoint.added", true);
}
});

View File

@ -13,7 +13,6 @@ import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Particle;
import org.bukkit.Sound;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffect;
@ -22,6 +21,7 @@ import org.bukkit.potion.PotionEffectType;
import io.github.bakedlibs.dough.common.ChatColors;
import io.github.bakedlibs.dough.items.CustomItemStack;
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import io.github.thebusybiscuit.slimefun4.implementation.items.teleporter.Teleporter;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
@ -70,8 +70,7 @@ public final class TeleportationManager {
@ParametersAreNonnullByDefault
public void openTeleporterGUI(Player p, UUID ownerUUID, Block b, int complexity) {
if (teleporterUsers.add(p.getUniqueId())) {
p.playSound(p.getLocation(), Sound.UI_BUTTON_CLICK, 1F, 1F);
SoundEffect.TELEPORTATION_MANAGER_OPEN_GUI.playFor(p);
PlayerProfile.fromUUID(ownerUUID, profile -> {
ChestMenu menu = new ChestMenu("&3Teleporter");
menu.addMenuCloseHandler(pl -> teleporterUsers.remove(pl.getUniqueId()));
@ -203,8 +202,7 @@ public final class TeleportationManager {
p.sendTitle(ChatColors.color(Slimefun.getLocalization().getMessage(p, "machines.TELEPORTER.teleporting")), ChatColors.color("&b" + progress + "%"), 0, 60, 0);
source.getWorld().spawnParticle(Particle.PORTAL, source, progress * 2, 0.2F, 0.8F, 0.2F);
source.getWorld().playSound(source, Sound.BLOCK_BEACON_AMBIENT, 1F, 0.6F);
SoundEffect.TELEPORT_UPDATE_SOUND.playFor(p);
Slimefun.runSync(() -> updateProgress(uuid, speed, progress + speed, source, destination, resistance), 10L);
}
} else {
@ -229,7 +227,7 @@ public final class TeleportationManager {
// Spawn some particles for aesthetic reasons.
Location loc = new Location(destination.getWorld(), destination.getX(), destination.getY() + 1, destination.getZ());
destination.getWorld().spawnParticle(Particle.PORTAL, loc, 200, 0.2F, 0.8F, 0.2F);
destination.getWorld().playSound(destination, Sound.BLOCK_BEACON_ACTIVATE, 1F, 1F);
SoundEffect.TELEPORT_SOUND.playFor(p);
teleporterUsers.remove(p.getUniqueId());
} else {
/*

View File

@ -12,7 +12,7 @@ import org.bukkit.inventory.meta.Damageable;
import org.bukkit.inventory.meta.ItemMeta;
import io.github.thebusybiscuit.slimefun4.implementation.items.armor.SlimefunArmorPiece;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.ArmorTask;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.armor.SlimefunArmorTask;
/**
* This class serves as a way of checking whether a {@link Player} has changed their armor
@ -25,7 +25,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.tasks.ArmorTask;
* @author TheBusyBiscuit
*
* @see SlimefunArmorPiece
* @see ArmorTask
* @see SlimefunArmorTask
*/
public final class HashedArmorpiece {

View File

@ -39,16 +39,12 @@ import io.github.thebusybiscuit.slimefun4.core.SlimefunRegistry;
import io.github.thebusybiscuit.slimefun4.core.attributes.NotConfigurable;
import io.github.thebusybiscuit.slimefun4.core.attributes.Placeable;
import io.github.thebusybiscuit.slimefun4.core.attributes.Radioactive;
import io.github.thebusybiscuit.slimefun4.core.attributes.Rechargeable;
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuide;
import io.github.thebusybiscuit.slimefun4.core.handlers.GlobalItemHandler;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import io.github.thebusybiscuit.slimefun4.implementation.items.VanillaItem;
import io.github.thebusybiscuit.slimefun4.implementation.items.backpacks.SlimefunBackpack;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting.AutoDisenchanter;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting.AutoEnchanter;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import io.github.thebusybiscuit.slimefun4.utils.itemstack.ItemStackWrapper;
import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker;
@ -479,6 +475,14 @@ public class SlimefunItem implements Placeable {
// Now we can be certain this item should be enabled
if (state == ItemState.ENABLED) {
onEnable();
} else {
// Clear item handlers if we are disabled so that calling them isn't possible later on
for (ItemHandler handler : this.itemhandlers.values()) {
if (handler instanceof BlockTicker) {
Slimefun.getRegistry().getTickerBlocks().remove(getId());
}
}
this.itemhandlers.clear();
}
// Lock the SlimefunItemStack from any accidental manipulations
@ -767,13 +771,7 @@ public class SlimefunItem implements Placeable {
}
}
// Backwards compatibility
if (Slimefun.getRegistry().isBackwardsCompatible()) {
boolean loreInsensitive = this instanceof Rechargeable || this instanceof SlimefunBackpack || id.equals("BROKEN_SPAWNER") || id.equals("REINFORCED_SPAWNER");
return SlimefunUtils.isItemSimilar(item, this.itemStackTemplate, !loreInsensitive);
} else {
return false;
}
return false;
}
/**
@ -1190,33 +1188,8 @@ public class SlimefunItem implements Placeable {
Optional<String> itemID = Slimefun.getItemDataService().getItemData(item);
if (itemID.isPresent()) {
return getById(itemID.get());
}
return itemID.map(SlimefunItem::getById).orElse(null);
// Backwards compatibility
if (Slimefun.getRegistry().isBackwardsCompatible()) {
// This wrapper improves the heavy ItemStack#getItemMeta() call by caching it.
ItemStackWrapper wrapper = ItemStackWrapper.wrap(item);
/*
* Quite expensive performance-wise.
* But necessary for supporting legacy items
*/
for (SlimefunItem sfi : Slimefun.getRegistry().getAllSlimefunItems()) {
if (sfi.isItem(wrapper)) {
/*
* If we have to loop all items for the given item, then at least
* set the id via PersistentDataAPI for future performance boosts
*/
Slimefun.getItemDataService().setItemData(item, sfi.getId());
return sfi;
}
}
}
return null;
}
/**
@ -1230,4 +1203,4 @@ public class SlimefunItem implements Placeable {
return Optional.ofNullable(getByItem(item));
}
}
}

View File

@ -17,6 +17,7 @@ import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.core.guide.GuideHistory;
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuide;
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideMode;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import io.github.thebusybiscuit.slimefun4.implementation.guide.SurvivalSlimefunGuide;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
@ -86,7 +87,7 @@ public class NestedItemGroup extends FlexItemGroup {
SurvivalSlimefunGuide guide = (SurvivalSlimefunGuide) Slimefun.getRegistry().getSlimefunGuide(mode);
menu.setEmptySlotsClickable(false);
menu.addMenuOpeningHandler(pl -> pl.playSound(pl.getLocation(), guide.getSound(), 1, 1));
menu.addMenuOpeningHandler(SoundEffect.GUIDE_BUTTON_CLICK_SOUND::playFor);
guide.createHeader(p, profile, menu);
menu.addItem(1, new CustomItemStack(ChestMenuUtils.getBackButton(p, "", ChatColor.GRAY + Slimefun.getLocalization().getMessage(p, "guide.back.guide"))));

View File

@ -36,6 +36,7 @@ import io.github.bakedlibs.dough.config.Config;
import io.github.thebusybiscuit.slimefun4.api.events.AsyncProfileLoadEvent;
import io.github.thebusybiscuit.slimefun4.api.gps.Waypoint;
import io.github.thebusybiscuit.slimefun4.api.items.HashedArmorpiece;
import io.github.thebusybiscuit.slimefun4.api.items.ItemState;
import io.github.thebusybiscuit.slimefun4.api.researches.Research;
import io.github.thebusybiscuit.slimefun4.core.attributes.ProtectionType;
import io.github.thebusybiscuit.slimefun4.core.attributes.ProtectiveArmor;
@ -324,10 +325,18 @@ public class PlayerProfile {
return Optional.empty();
}
// returns the amount of researches with at least 1 enabled item
private int nonEmptyResearches() {
return (int) Slimefun.getRegistry().getResearches()
.stream()
.filter(research -> research.getAffectedItems().stream().anyMatch(item -> item.getState() == ItemState.ENABLED))
.count();
}
public @Nonnull String getTitle() {
List<String> titles = Slimefun.getRegistry().getResearchRanks();
float fraction = (float) researches.size() / Slimefun.getRegistry().getResearches().size();
float fraction = (float) researches.size() / nonEmptyResearches();
int index = (int) (fraction * (titles.size() - 1));
return titles.get(index);
@ -336,7 +345,7 @@ public class PlayerProfile {
public void sendStats(@Nonnull CommandSender sender) {
Set<Research> unlockedResearches = getResearches();
int levels = unlockedResearches.stream().mapToInt(Research::getCost).sum();
int allResearches = Slimefun.getRegistry().getResearches().size();
int allResearches = nonEmptyResearches();
float progress = Math.round(((unlockedResearches.size() * 100.0F) / allResearches) * 100.0F) / 100.0F;

View File

@ -7,12 +7,12 @@ import javax.annotation.Nullable;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import io.github.thebusybiscuit.slimefun4.api.events.ResearchUnlockEvent;
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.core.guide.options.SlimefunGuideSettings;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import io.github.thebusybiscuit.slimefun4.utils.FireworkUtils;
@ -64,7 +64,7 @@ public class PlayerResearchTask implements Consumer<PlayerProfile> {
if (!isInstant) {
Slimefun.runSync(() -> {
p.playSound(p.getLocation(), Sound.ENTITY_BAT_TAKEOFF, 0.7F, 1F);
SoundEffect.PLAYER_RESEARCHING_SOUND.playFor(p);
Slimefun.getLocalization().sendMessage(p, "messages.research.progress", true, msg -> msg.replace(PLACEHOLDER, research.getName(p)).replace("%progress%", "0%"));
}, 5L);
}
@ -93,7 +93,7 @@ public class PlayerResearchTask implements Consumer<PlayerProfile> {
int index = i;
Slimefun.runSync(() -> {
p.playSound(p.getLocation(), Sound.ENTITY_BAT_TAKEOFF, 0.7F, 1);
SoundEffect.PLAYER_RESEARCHING_SOUND.playFor(p);
Slimefun.getLocalization().sendMessage(p, "messages.research.progress", true, msg -> {
String progress = RESEARCH_PROGRESS[index - 1] + "%";
@ -125,5 +125,4 @@ public class PlayerResearchTask implements Consumer<PlayerProfile> {
callback.accept(p);
}
}
}

View File

@ -65,7 +65,6 @@ public final class SlimefunRegistry {
private final Set<UUID> researchingPlayers = Collections.synchronizedSet(new HashSet<>());
// TODO: Move this all into a proper "config cache" class
private boolean backwardsCompatibility;
private boolean automaticallyLoadItems;
private boolean enableResearches;
private boolean freeCreativeResearches;
@ -109,7 +108,6 @@ public final class SlimefunRegistry {
researchRanks.addAll(cfg.getStringList("research-ranks"));
backwardsCompatibility = cfg.getBoolean("options.backwards-compatibility");
freeCreativeResearches = cfg.getBoolean("researches.free-in-creative-mode");
researchFireworks = cfg.getBoolean("researches.enable-fireworks");
disableLearningAnimation = cfg.getBoolean("researches.disable-learning-animation");
@ -129,29 +127,6 @@ public final class SlimefunRegistry {
return automaticallyLoadItems;
}
/**
* This method returns whether backwards-compatibility is enabled.
* Backwards compatibility allows Slimefun to recognize items from older versions but comes
* at a huge performance cost.
*
* @return Whether backwards compatibility is enabled
*/
public boolean isBackwardsCompatible() {
return backwardsCompatibility;
}
/**
* This method sets the status of backwards compatibility.
* Backwards compatibility allows Slimefun to recognize items from older versions but comes
* at a huge performance cost.
*
* @param compatible
* Whether backwards compatibility should be enabled
*/
public void setBackwardsCompatible(boolean compatible) {
backwardsCompatibility = compatible;
}
/**
* This method will make any {@link SlimefunItem} which is registered automatically
* call {@link SlimefunItem#load()}.

View File

@ -59,10 +59,11 @@ public interface DamageableItem extends ItemAttribute {
ItemMeta meta = item.getItemMeta();
if (!meta.isUnbreakable()) {
if (meta != null && !meta.isUnbreakable()) {
Damageable damageable = (Damageable) meta;
if (damageable.getDamage() >= item.getType().getMaxDurability()) {
// No need for a SoundEffect equivalent here since this is supposed to be a vanilla sound.
p.playSound(p.getEyeLocation(), Sound.ENTITY_ITEM_BREAK, 1, 1);
item.setAmount(0);
} else {

View File

@ -0,0 +1,33 @@
package io.github.thebusybiscuit.slimefun4.core.attributes;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import org.bukkit.inventory.meta.ItemMeta;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
import javax.annotation.Nonnull;
/**
* Implement this interface for any {@link SlimefunItem} to prevent
* cargo using only its ID when comparing. #canStack is used when
* comparing stacks
*
* @author Sefiraat
*/
public interface DistinctiveItem extends ItemAttribute {
/**
* This method is called by {@link SlimefunUtils#isItemSimilar} when two {@link SlimefunItemStack}
* IDs match on a DistinctiveItem and should return if the two items can stack
* with one another.
*
* @param itemMetaOne
* The {@link ItemMeta} of the first stack being compared.
* @param itemMetaTwo
* The {@link ItemMeta} of the second stack being compared.
*
* @return Whether the two {@link ItemMeta}s are stackable
*/
boolean canStack(@Nonnull ItemMeta itemMetaOne, @Nonnull ItemMeta itemMetaTwo);
}

View File

@ -0,0 +1,30 @@
package io.github.thebusybiscuit.slimefun4.core.attributes;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
import io.github.thebusybiscuit.slimefun4.core.attributes.interactions.InteractionResult;
import org.bukkit.Location;
import javax.annotation.Nonnull;
/**
* Implement this interface for any {@link SlimefunItem} to provide methods for
* external code to 'interact' with the item when placed as a block in the world.
*
* @author Sefiraat
*/
@FunctionalInterface
public interface ExternallyInteractable {
/**
* This method should be used by the implementing class to fulfill the actions needed
* when being interacted with returning the result of the interaction.
*
* @param location
* The {@link Location} of the Block being targeted for the interaction.
*
* @return The {@link InteractionResult} denoting the result of the interaction.
*/
@Nonnull
InteractionResult onInteract(@Nonnull Location location);
}

View File

@ -0,0 +1,69 @@
package io.github.thebusybiscuit.slimefun4.core.attributes;
import javax.annotation.Nonnull;
import com.google.common.base.Preconditions;
import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import io.github.thebusybiscuit.slimefun4.utils.RadiationUtils;
/**
* An enum of potential radiation symptoms.
* A symptom will be applied when the minExposure
* threshold is reached on the {@link Player}'s
* exposure level.
* When the {@link Player} gets above the minExposure threshold
* the {@link PotionEffect} will be applied.
*
* @author Semisol
*
* @see RadiationUtils
*/
public enum RadiationSymptom {
SLOW(10, PotionEffectType.SLOW, 3),
WITHER_LOW(25, PotionEffectType.WITHER, 0),
BLINDNESS(50, PotionEffectType.BLINDNESS, 4),
WITHER_HIGH(75, PotionEffectType.WITHER, 3),
IMMINENT_DEATH(100, PotionEffectType.HARM, 49);
private final int minExposure;
private final PotionEffect potionEffect;
RadiationSymptom(int minExposure, @Nonnull PotionEffectType type, int level) {
Preconditions.checkNotNull(type, "The effect type cannot be null");
Preconditions.checkArgument(minExposure > 0, "The minimum exposure must be greater than 0.");
Preconditions.checkArgument(level >= 0, "The status effect level must be non-negative.");
this.minExposure = minExposure;
this.potionEffect = new PotionEffect(type, Slimefun.getCfg().getOrSetDefault("options.radiation-update-interval", 1) * 20 + 20, level);
}
/**
* This method applies the symptom to a player.
*
* @param p
* The player
*/
public void apply(@Nonnull Player p) {
Preconditions.checkNotNull(p, "The player cannot be null");
p.addPotionEffect(potionEffect);
}
/**
* This method returns if this symptom
* should be applied.
*
* @param exposure
* Exposure level
*
* @return If the symptom should be applied
*/
public boolean shouldApply(int exposure) {
return exposure >= minExposure;
}
}

View File

@ -2,6 +2,8 @@ package io.github.thebusybiscuit.slimefun4.core.attributes;
import javax.annotation.Nonnull;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.armor.RadiationTask;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
@ -20,41 +22,53 @@ public enum Radioactivity {
* This represents a low level of radiation.
* It will still cause damage but will take a while before it becomes deadly.
*/
LOW(ChatColor.YELLOW),
LOW(ChatColor.YELLOW, 1),
/**
* This represents a medium level of radiation.
* This can be considered the default.
*/
MODERATE(ChatColor.YELLOW),
MODERATE(ChatColor.YELLOW, 2),
/**
* This is a high level of radiation.
* It will cause death if the {@link Player} does not act quickly.
*/
HIGH(ChatColor.DARK_GREEN),
HIGH(ChatColor.GOLD, 3),
/**
* A very high level of radiation will be deadly.
* The {@link Player} should not take this too lightly...
*/
VERY_HIGH(ChatColor.RED),
VERY_HIGH(ChatColor.RED, 5),
/**
* This is the deadlies level of radiation.
* This is the deadliest level of radiation.
* The {@link Player} has basically no chance to protect themselves in time.
* It will cause certain death.
*/
VERY_DEADLY(ChatColor.DARK_RED);
VERY_DEADLY(ChatColor.DARK_RED, 10);
private final ChatColor color;
private final int exposureModifier;
Radioactivity(@Nonnull ChatColor color) {
Radioactivity(@Nonnull ChatColor color, int exposureModifier) {
this.color = color;
this.exposureModifier = exposureModifier;
}
@Nonnull
public String getLore() {
/**
* This method returns the amount of exposure applied
* to a player every run of the {@link RadiationTask}
* for this radiation level.
*
* @return The exposure amount applied per run.
*/
public int getExposureModifier() {
return exposureModifier;
}
public @Nonnull String getLore() {
return ChatColor.GREEN + "\u2622" + ChatColor.GRAY + " Radiation level: " + color + toString().replace('_', ' ');
}

View File

@ -0,0 +1,61 @@
package io.github.thebusybiscuit.slimefun4.core.attributes.interactions;
import io.github.thebusybiscuit.slimefun4.core.attributes.ExternallyInteractable;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
/**
* This class represents the result of an interaction on an {@link ExternallyInteractable} item.
*/
public class InteractionResult {
private final boolean interactionSuccessful;
private @Nullable String resultMessage;
/**
* Creates a new InteractionResult.
*
* @param successful Whether the interaction was successful or not.
*/
@ParametersAreNonnullByDefault
public InteractionResult(boolean successful) {
this.interactionSuccessful = successful;
}
/**
* Returns whether the interaction was successful or not.
*
* @return boolean denoting whether the interaction was successful or not.
*/
public boolean isInteractionSuccessful() {
return interactionSuccessful;
}
/**
* Sets a custom result message for this interaction.
*
* @param resultMessage The message to be sent with the Result
*/
public void setResultMessage(@Nullable String resultMessage) {
this.resultMessage = resultMessage;
}
/**
* Returns whether this result has a result message or is null.
*
* @return true if a result message is present
*/
public boolean hasResultMessage() {
return this.resultMessage != null;
}
/**
* Returns the custom result message for this result or null if not set.
*
* @return A String of the provided custom result message.
*/
public @Nullable String getResultMessage() {
return resultMessage;
}
}

View File

@ -0,0 +1,64 @@
package io.github.thebusybiscuit.slimefun4.core.attributes.interactions;
import io.github.thebusybiscuit.slimefun4.core.attributes.ExternallyInteractable;
import org.bukkit.inventory.ItemStack;
import javax.annotation.Nonnull;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
/**
* This class represents the result of an interaction on an {@link ExternallyInteractable} item.
*/
public class ItemInteractionResult extends InteractionResult {
private final @Nonnull Set<ItemStack> resultItems = new HashSet<>();
/**
* Creates a new InteractionResult.
*
* @param successful Whether the interaction was successful or not.
*/
public ItemInteractionResult(boolean successful) {
super(successful);
}
/**
* Creates a new InteractionResult.
*
* @param successful Whether the interaction was successful or not.
* @param itemStacks The {@link ItemStack}(s) that would be returned due to this interaction.
*/
public ItemInteractionResult(boolean successful, ItemStack... itemStacks) {
super(successful);
addResultItems(itemStacks);
}
/**
* Adds an or several {@link ItemStack}'s into the result.
*
* @param itemStacks The {@link ItemStack}(s) that would be returned due to this interaction.
*/
public void addResultItems(ItemStack... itemStacks) {
Collections.addAll(resultItems, itemStacks);
}
/**
* This returned whether items are included as part of the result.
*
* @return True if items are included in the result.
*/
public boolean resultedInItems() {
return !this.resultItems.isEmpty();
}
/**
* Returns the {@link ItemStack}(s) produced as a result of this interaction, if any.
*
* @return An unmodifiable {@link Set} of {@link ItemStack}(s) created due to the interaction.
*/
public @Nonnull Set<ItemStack> getResultItems() {
return Collections.unmodifiableSet(resultItems);
}
}

View File

@ -0,0 +1,5 @@
/**
* This package contains the various possible {@link io.github.thebusybiscuit.slimefun4.core.attributes.interactions.InteractionResult}s
* that can be returned by an {@link io.github.thebusybiscuit.slimefun4.core.attributes.ExternallyInteractable} object.
*/
package io.github.thebusybiscuit.slimefun4.core.attributes.interactions;

View File

@ -15,6 +15,7 @@ import org.bukkit.entity.Player;
import io.github.thebusybiscuit.slimefun4.core.commands.SlimefunCommand;
import io.github.thebusybiscuit.slimefun4.core.commands.SubCommand;
import io.github.thebusybiscuit.slimefun4.core.services.profiler.PerformanceInspector;
import io.github.thebusybiscuit.slimefun4.core.services.profiler.SummaryOrderType;
import io.github.thebusybiscuit.slimefun4.core.services.profiler.inspectors.ConsolePerformanceInspector;
import io.github.thebusybiscuit.slimefun4.core.services.profiler.inspectors.PlayerPerformanceInspector;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
@ -22,7 +23,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
class TimingsCommand extends SubCommand {
private static final String FLAG_PREFIX = "--";
private final Set<String> flags = new HashSet<>(Arrays.asList("verbose"));
private final Set<String> flags = new HashSet<>(Arrays.asList("verbose", "avg", "low"));
@ParametersAreNonnullByDefault
TimingsCommand(Slimefun plugin, SlimefunCommand cmd) {
@ -30,31 +31,40 @@ class TimingsCommand extends SubCommand {
}
@Override
protected String getDescription() {
protected @Nonnull String getDescription() {
return "commands.timings.description";
}
@Override
public void onExecute(CommandSender sender, String[] args) {
if (sender.hasPermission("slimefun.command.timings") || sender instanceof ConsoleCommandSender) {
if (hasInvalidFlags(sender, args)) {
return;
}
boolean verbose = hasFlag(args, "verbose");
if (verbose && sender instanceof Player) {
Slimefun.getLocalization().sendMessage(sender, "commands.timings.verbose-player", true);
return;
}
Slimefun.getLocalization().sendMessage(sender, "commands.timings.please-wait", true);
PerformanceInspector inspector = inspectorOf(sender, verbose);
Slimefun.getProfiler().requestSummary(inspector);
} else {
public void onExecute(CommandSender sender, @Nonnull String[] args) {
if (!sender.hasPermission("slimefun.command.timings") && !(sender instanceof ConsoleCommandSender)) {
Slimefun.getLocalization().sendMessage(sender, "messages.no-permission", true);
return;
}
if (hasInvalidFlags(sender, args)) {
return;
}
boolean verbose = hasFlag(args, "verbose");
if (verbose && sender instanceof Player) {
Slimefun.getLocalization().sendMessage(sender, "commands.timings.verbose-player", true);
return;
}
SummaryOrderType orderType = SummaryOrderType.HIGHEST;
if (hasFlag(args, "avg")) {
orderType = SummaryOrderType.AVERAGE;
} else if (hasFlag(args, "low")) {
orderType = SummaryOrderType.LOWEST;
}
Slimefun.getLocalization().sendMessage(sender, "commands.timings.please-wait", true);
PerformanceInspector inspector = inspectorOf(sender, verbose, orderType);
Slimefun.getProfiler().requestSummary(inspector);
}
@ParametersAreNonnullByDefault
@ -87,12 +97,12 @@ class TimingsCommand extends SubCommand {
}
@Nonnull
private PerformanceInspector inspectorOf(@Nonnull CommandSender sender, boolean verbose) {
@ParametersAreNonnullByDefault
private PerformanceInspector inspectorOf(CommandSender sender, boolean verbose, SummaryOrderType orderType) {
if (sender instanceof Player player) {
return new PlayerPerformanceInspector(player);
return new PlayerPerformanceInspector(player, orderType);
} else {
return new ConsolePerformanceInspector(sender, verbose);
return new ConsolePerformanceInspector(sender, verbose, orderType);
}
}
}

View File

@ -83,18 +83,6 @@ class VersionsCommand extends SubCommand {
addJavaVersion(builder);
if (Slimefun.getRegistry().isBackwardsCompatible()) {
// @formatter:off
HoverEvent hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(
"Backwards compatibility has a negative impact on performance!\n" +
"We recommend you to disable this setting unless your server still " +
"has legacy Slimefun items (from before summer 2019) in circulation."
));
// @formatter:on
builder.append("\nBackwards compatibility enabled!\n").color(ChatColor.RED).event(hoverEvent);
}
builder.append("\n").event((HoverEvent) null);
addPluginVersions(builder);

View File

@ -6,7 +6,6 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.SkullMeta;
@ -15,6 +14,7 @@ import io.github.bakedlibs.dough.common.ChatColors;
import io.github.bakedlibs.dough.common.CommonPatterns;
import io.github.bakedlibs.dough.items.CustomItemStack;
import io.github.thebusybiscuit.slimefun4.core.services.github.Contributor;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import io.github.thebusybiscuit.slimefun4.utils.ChatUtils;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
@ -36,7 +36,7 @@ final class ContributorsMenu {
ChestMenu menu = new ChestMenu(Slimefun.getLocalization().getMessage(p, "guide.title.credits"));
menu.setEmptySlotsClickable(false);
menu.addMenuOpeningHandler(pl -> pl.playSound(pl.getLocation(), Sound.BLOCK_NOTE_BLOCK_HARP, 0.7F, 0.7F));
menu.addMenuOpeningHandler(SoundEffect.GUIDE_CONTRIBUTORS_OPEN_SOUND::playFor);
ChestMenuUtils.drawBackground(menu, 0, 2, 3, 4, 5, 6, 7, 8, 45, 47, 48, 49, 50, 51, 53);

View File

@ -6,7 +6,6 @@ import java.util.Optional;
import org.bukkit.ChatColor;
import org.bukkit.NamespacedKey;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
@ -15,6 +14,7 @@ import io.github.bakedlibs.dough.items.CustomItemStack;
import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon;
import io.github.thebusybiscuit.slimefun4.api.events.PlayerLanguageChangeEvent;
import io.github.thebusybiscuit.slimefun4.core.services.localization.Language;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import io.github.thebusybiscuit.slimefun4.utils.ChatUtils;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
@ -79,7 +79,7 @@ class PlayerLanguageOption implements SlimefunGuideOption<String> {
ChestMenu menu = new ChestMenu(Slimefun.getLocalization().getMessage(p, "guide.title.languages"));
menu.setEmptySlotsClickable(false);
menu.addMenuOpeningHandler(pl -> pl.playSound(pl.getLocation(), Sound.BLOCK_NOTE_BLOCK_HARP, 0.7F, 0.7F));
menu.addMenuOpeningHandler(SoundEffect.GUIDE_LANGUAGE_OPEN_SOUND::playFor);
for (int i = 0; i < 9; i++) {
if (i == 1) {

View File

@ -10,7 +10,6 @@ import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
@ -21,6 +20,7 @@ import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideMode;
import io.github.thebusybiscuit.slimefun4.core.services.LocalizationService;
import io.github.thebusybiscuit.slimefun4.core.services.github.GitHubService;
import io.github.thebusybiscuit.slimefun4.core.services.localization.Language;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import io.github.thebusybiscuit.slimefun4.utils.ChatUtils;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
@ -63,7 +63,7 @@ public final class SlimefunGuideSettings {
ChestMenu menu = new ChestMenu(Slimefun.getLocalization().getMessage(p, "guide.title.settings"));
menu.setEmptySlotsClickable(false);
menu.addMenuOpeningHandler(pl -> pl.playSound(pl.getLocation(), Sound.BLOCK_NOTE_BLOCK_HARP, 0.7F, 0.7F));
menu.addMenuOpeningHandler(SoundEffect.GUIDE_OPEN_SETTING_SOUND::playFor);
ChestMenuUtils.drawBackground(menu, BACKGROUND_SLOTS);

View File

@ -9,7 +9,10 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import com.google.common.base.Preconditions;
import org.apache.commons.lang.Validate;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
@ -105,11 +108,21 @@ public abstract class MultiBlockMachine extends SlimefunItem implements NotPlace
public void load() {
super.load();
for (ItemStack recipeItem : displayRecipes) {
SlimefunItem item = SlimefunItem.getByItem(recipeItem);
Preconditions.checkArgument(displayRecipes.size() % 2 == 0, "This MultiBlockMachine's display recipes were illegally modified!");
if (item == null || !item.isDisabled()) {
recipes.add(new ItemStack[] { recipeItem });
for (int i = 0; i < displayRecipes.size(); i += 2) {
ItemStack inputStack = displayRecipes.get(i);
ItemStack outputStack = null;
if (displayRecipes.size() >= i + 2) {
outputStack = displayRecipes.get(i + 1);
}
SlimefunItem inputItem = SlimefunItem.getByItem(inputStack);
SlimefunItem outputItem = SlimefunItem.getByItem(outputStack);
// If the input/output is not a Slimefun item or it's not disabled then it's valid.
if ((inputItem == null || !inputItem.isDisabled()) && (outputItem == null || !outputItem.isDisabled())) {
recipes.add(new ItemStack[] { inputStack });
recipes.add(new ItemStack[] { outputStack });
}
}
}

View File

@ -1,6 +1,7 @@
package io.github.thebusybiscuit.slimefun4.core.services;
import java.io.File;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

View File

@ -77,6 +77,7 @@ class ContributionsConnector extends GitHubConnector {
aliases.put("NCBPFluffyBear", "FluffyBear_");
aliases.put("martinbrom", "OneTime97");
aliases.put("LilBC", "Lil_BC");
aliases.put("st392", "BlueWood");
}
/**

View File

@ -38,4 +38,10 @@ public interface PerformanceInspector {
*/
boolean isVerbose();
/**
* The order type for the summary of timings.
*
* @return The order type for the summary of timings.
*/
@Nonnull SummaryOrderType getOrderType();
}

View File

@ -1,12 +1,10 @@
package io.github.thebusybiscuit.slimefun4.core.services.profiler;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
@ -64,13 +62,18 @@ class PerformanceSummary {
summarizeTimings(totalTickedBlocks, "block", sender, items, entry -> {
int count = profiler.getBlocksOfId(entry.getKey());
String time = NumberUtils.getAsMillis(entry.getValue());
String message = entry.getKey() + " - " + count + "x (%s)";
if (count > 1) {
String average = NumberUtils.getAsMillis(entry.getValue() / count);
if (count <= 1) {
return String.format(message, time);
}
return entry.getKey() + " - " + count + "x (" + time + " | avg: " + average + ')';
String average = NumberUtils.getAsMillis(entry.getValue() / count);
if (sender.getOrderType() == SummaryOrderType.AVERAGE) {
return String.format(message, average + " | total: " + time);
} else {
return entry.getKey() + " - " + count + "x (" + time + ')';
return String.format(message, time + " | avg: " + average);
}
});
@ -91,8 +94,8 @@ class PerformanceSummary {
@ParametersAreNonnullByDefault
private void summarizeTimings(int count, String name, PerformanceInspector inspector, Map<String, Long> map, Function<Map.Entry<String, Long>, String> formatter) {
Stream<Map.Entry<String, Long>> stream = map.entrySet().stream();
List<Entry<String, Long>> results = stream.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())).collect(Collectors.toList());
Set<Entry<String, Long>> entrySet = map.entrySet();
List<Entry<String, Long>> results = inspector.getOrderType().sort(profiler, entrySet);
String prefix = count + " " + name + (count != 1 ? 's' : "");
if (inspector instanceof PlayerPerformanceInspector playerPerformanceInspector) {
@ -181,22 +184,15 @@ class PerformanceSummary {
rest--;
}
builder.append(ChatColor.DARK_GRAY);
for (int i = 0; i < rest; i++) {
builder.append(':');
}
builder.append(" - ");
builder.append(rating.getColor() + ChatUtils.humanize(rating.name()));
builder.append(ChatColor.GRAY);
builder.append(" (");
builder.append(NumberUtils.roundDecimalNumber(percentage));
builder.append("%)");
builder.append(ChatColor.DARK_GRAY)
.append(":".repeat(Math.max(0, rest)))
.append(" - ")
.append(rating.getColor()).append(ChatUtils.humanize(rating.name()))
.append(ChatColor.GRAY)
.append(" (")
.append(NumberUtils.roundDecimalNumber(percentage))
.append("%)");
return builder.toString();
}
}

View File

@ -0,0 +1,55 @@
package io.github.thebusybiscuit.slimefun4.core.services.profiler;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* Holds the different types of ordering for summaries.
*
* @author Walshy
*/
public enum SummaryOrderType {
/**
* Sort by highest to the lowest total timings
*/
HIGHEST,
/**
* Sort by lowest to the highest total timings
*/
LOWEST,
/**
* Sort by average timings (highest to lowest)
*/
AVERAGE;
@ParametersAreNonnullByDefault
List<Map.Entry<String, Long>> sort(SlimefunProfiler profiler, Set<Map.Entry<String, Long>> entrySet) {
switch(this) {
case HIGHEST:
return entrySet.stream()
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.collect(Collectors.toList());
case LOWEST:
return entrySet.stream()
.sorted(Comparator.comparingLong(Map.Entry::getValue))
.collect(Collectors.toList());
default:
final Map<String, Long> map = new HashMap<>();
for (Map.Entry<String, Long> entry : entrySet) {
int count = profiler.getBlocksOfId(entry.getKey());
long avg = count > 0 ? entry.getValue() / count : entry.getValue();
map.put(entry.getKey(), avg);
}
return map.entrySet().stream()
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.collect(Collectors.toList());
}
}
}

View File

@ -1,7 +1,9 @@
package io.github.thebusybiscuit.slimefun4.core.services.profiler.inspectors;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import io.github.thebusybiscuit.slimefun4.core.services.profiler.SummaryOrderType;
import org.apache.commons.lang.Validate;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
@ -28,35 +30,61 @@ public class ConsolePerformanceInspector implements PerformanceInspector {
*/
private final boolean verbose;
/**
* The order type of the timings.
*/
private final SummaryOrderType orderType;
/**
* This creates a new {@link ConsolePerformanceInspector} for the given {@link CommandSender}.
*
* @param console
* The {@link CommandSender}, preferabbly a {@link ConsoleCommandSender}
* The {@link CommandSender}, preferably a {@link ConsoleCommandSender}
* @param verbose
* Whether the summary will be verbose or not
* @param orderType
* The {@link SummaryOrderType} of the timings
*/
public ConsolePerformanceInspector(@Nonnull CommandSender console, boolean verbose) {
@ParametersAreNonnullByDefault
public ConsolePerformanceInspector(CommandSender console, boolean verbose, SummaryOrderType orderType) {
Validate.notNull(console, "CommandSender cannot be null");
Validate.notNull(orderType, "SummaryOrderType cannot be null");
this.console = console;
this.verbose = verbose;
this.orderType = orderType;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isValid() {
// The console is always "online".
return true;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isVerbose() {
return verbose;
}
/**
* {@inheritDoc}
*/
@Override
public @Nonnull SummaryOrderType getOrderType() {
return orderType;
}
/**
* {@inheritDoc}
*/
@Override
public void sendMessage(@Nonnull String msg) {
console.sendMessage(msg);
}
}

View File

@ -5,6 +5,7 @@ import java.util.UUID;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import io.github.thebusybiscuit.slimefun4.core.services.profiler.SummaryOrderType;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
@ -27,34 +28,62 @@ public class PlayerPerformanceInspector implements PerformanceInspector {
*/
private final UUID uuid;
/**
* The order type of the timings.
*/
private final SummaryOrderType orderType;
/**
* This creates a new {@link PlayerPerformanceInspector} for the given {@link Player}.
*
* @param player
* The {@link Player}
* @param orderType
* The {@link SummaryOrderType} of the timings
*/
public PlayerPerformanceInspector(@Nonnull Player player) {
public PlayerPerformanceInspector(@Nonnull Player player, @Nonnull SummaryOrderType orderType) {
Validate.notNull(player, "Player cannot be null");
Validate.notNull(orderType, "SummaryOrderType cannot be null");
this.uuid = player.getUniqueId();
this.orderType = orderType;
}
@Nullable
private Player getPlayer() {
/**
* {@inheritDoc}
*/
private @Nullable Player getPlayer() {
return Bukkit.getPlayer(uuid);
}
/**
* {@inheritDoc}
*/
@Override
public boolean isValid() {
Player player = getPlayer();
return player != null && player.isOnline();
}
/**
* {@inheritDoc}
*/
@Override
public boolean isVerbose() {
return false;
}
/**
* {@inheritDoc}
*/
@Override
public @Nonnull SummaryOrderType getOrderType() {
return orderType;
}
/**
* {@inheritDoc}
*/
@Override
public void sendMessage(@Nonnull String msg) {
Player player = getPlayer();

View File

@ -0,0 +1,38 @@
package io.github.thebusybiscuit.slimefun4.core.services.sounds;
import javax.annotation.Nonnull;
/**
* This structure class holds configured values for a {@link SoundEffect}.
*
* @author TheBusyBiscuit
*
* @see SoundService
* @see SoundEffect
*
*/
public class SoundConfiguration {
private final String sound;
private final float volume;
private final float pitch;
protected SoundConfiguration(@Nonnull String sound, float volume, float pitch) {
this.sound = sound;
this.volume = volume;
this.pitch = pitch;
}
public @Nonnull String getSoundId() {
return sound;
}
public float getVolume() {
return volume;
}
public float getPitch() {
return pitch;
}
}

View File

@ -0,0 +1,218 @@
package io.github.thebusybiscuit.slimefun4.core.services.sounds;
import java.util.Locale;
import java.util.logging.Level;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import org.bukkit.Location;
import org.bukkit.Sound;
import org.bukkit.SoundCategory;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import com.google.common.base.Preconditions;
/**
* This enum holds references to all our sounds.
*
* @author TheBusyBiscuit
* @author J3fftw1
*
* @see SoundService
* @see SoundConfiguration
*
*/
public enum SoundEffect {
ANCIENT_ALTAR_ITEM_CHECK_SOUND(Sound.ENTITY_ENDERMAN_TELEPORT, 1F, 2F),
ANCIENT_ALTAR_ITEM_DROP_SOUND(Sound.ENTITY_ZOMBIE_ATTACK_IRON_DOOR, 1F, 1F),
ANCIENT_ALTAR_ITEM_PICK_UP_SOUND(Sound.ENTITY_ITEM_PICKUP, 1F, 1F),
ANCIENT_ALTAR_FINISH_SOUND(Sound.ENTITY_ZOMBIE_VILLAGER_CURE, 1F, 1F),
ANCIENT_ALTAR_START_SOUND(Sound.ENTITY_ILLUSIONER_PREPARE_MIRROR, 1F, 1F),
ANCIENT_PEDESTAL_ITEM_PLACE_SOUND(Sound.ENTITY_ITEM_PICKUP, 0.5F, 0.5F),
ARMOR_FORGE_FINISH_SOUND(Sound.BLOCK_ANVIL_USE, 1F, 1F),
ARMOR_FORGE_WORKING_SOUND(Sound.ENTITY_ARROW_HIT_PLAYER, 1F, 1F),
AUTO_CRAFTER_GUI_CLICK_SOUND(Sound.UI_BUTTON_CLICK, 1F, 1F),
AUTO_CRAFTER_UPDATE_RECIPE(Sound.UI_BUTTON_CLICK, 1F, 1F),
AUTOMATED_PANNING_MACHINE_FAIL_SOUND(Sound.ENTITY_ARMOR_STAND_BREAK, 1F, 1F),
AUTOMATED_PANNING_MACHINE_SUCCESS_SOUND(Sound.ENTITY_ARROW_HIT_PLAYER, 1F, 1F),
BEE_BOOTS_FALL_SOUND(Sound.BLOCK_HONEY_BLOCK_FALL, 1F, 1F),
BACKPACK_CLOSE_SOUND(Sound.ENTITY_HORSE_ARMOR, 1F, 1F),
BACKPACK_OPEN_SOUND(Sound.ENTITY_HORSE_ARMOR, 1F, 1F),
COMPOSTER_COMPOST_SOUND(Sound.ENTITY_ARROW_HIT_PLAYER, 1F, 1F),
COMPRESSOR_CRAFT_SOUND(Sound.ENTITY_ARROW_HIT_PLAYER, 1F, 1F),
COMPRESSOR_CRAFT_CONTRACT_SOUND(Sound.BLOCK_PISTON_CONTRACT, 1F, 1F),
COMPRESSOR_CRAFT_EXTEND_SOUND(Sound.BLOCK_PISTON_EXTEND, 1F, 1F),
COOLER_CONSUME_SOUND(Sound.ENTITY_GENERIC_DRINK, 1F, 1F),
CRUCIBLE_ADD_WATER_SOUND(Sound.ENTITY_PLAYER_SPLASH, 1F, 1F),
CRUCIBLE_ADD_LAVA_SOUND(Sound.BLOCK_LAVA_POP, 1F , 1F),
CRUCIBLE_BLOCK_BREAK_SOUND(Sound.BLOCK_METAL_BREAK, 1F, 1F),
CRUCIBLE_GENERATE_LIQUID_SOUND(Sound.BLOCK_LAVA_EXTINGUISH, 1F, 1F),
CRUCIBLE_INTERACT_SOUND(Sound.ENTITY_ARROW_HIT_PLAYER, 1F, 1F),
CRUCIBLE_PLACE_LAVA_SOUND(Sound.BLOCK_LAVA_POP, 1F , 1F),
CRUCIBLE_PLACE_WATER_SOUND(Sound.ENTITY_PLAYER_SPLASH, 1F, 1F),
DEBUG_FISH_CLICK_SOUND(Sound.BLOCK_BAMBOO_PLACE, 1F, 1F),
DIET_COOKIE_CONSUME_SOUND(Sound.ENTITY_GENERIC_EAT, 1F, 1F),
ENCHANTMENT_RUNE_ADD_ENCHANT_SOUND(Sound.ENTITY_ZOMBIE_VILLAGER_CURE, 1F, 1F),
ENDER_BACKPACK_OPEN_SOUND(Sound.ENTITY_ENDERMAN_TELEPORT, 1F, 1F),
ENHANCED_CRAFTING_TABLE_CRAFT_SOUND(Sound.BLOCK_WOODEN_BUTTON_CLICK_ON, 1F, 1F),
ELYTRA_CAP_IMPACT_SOUND(Sound.BLOCK_STONE_HIT, 1F, 1F),
EXPLOSIVE_BOW_HIT_SOUND(Sound.ENTITY_GENERIC_EXPLODE, 1F, 1F),
EXPLOSIVE_TOOL_EXPLODE_SOUND(Sound.ENTITY_GENERIC_EXPLODE, 0.2F, 1F),
FISHERMAN_ANDROID_FISHING_SOUND(Sound.ENTITY_PLAYER_SPLASH, 0.3F, 0.7F),
FLASK_OF_KNOWLEDGE_FILLUP_SOUND(Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1F, 0.5F),
GUIDE_BUTTON_CLICK_SOUND(Sound.ITEM_BOOK_PAGE_TURN, 1F, 1F),
GUIDE_CONTRIBUTORS_OPEN_SOUND(Sound.BLOCK_NOTE_BLOCK_HARP, 0.7F, 0.7F),
GUIDE_LANGUAGE_OPEN_SOUND(Sound.BLOCK_NOTE_BLOCK_HARP, 0.7F, 0.7F),
GUIDE_OPEN_SETTING_SOUND(Sound.BLOCK_NOTE_BLOCK_HARP, 0.7F, 0.7F),
GRIND_STONE_INTERACT_SOUND(Sound.BLOCK_WOODEN_BUTTON_CLICK_ON, 1F, 1F),
IGNITION_CHAMBER_USE_FLINT_AND_STEEL_SOUND(Sound.ENTITY_ITEM_BREAK, 1F, 1F),
INFUSED_HOPPER_TELEPORT_SOUND(Sound.ENTITY_ENDERMAN_TELEPORT, 0.5F, 2F),
INFUSED_MAGNET_TELEPORT_SOUND(Sound.ENTITY_ENDERMAN_TELEPORT, 0.25F, 0.9F),
IRON_GOLEM_ASSEMBLER_ASSEMBLE_SOUND(Sound.ENTITY_IRON_GOLEM_REPAIR, 0.5F, 1F),
JETBOOTS_THRUST_SOUND(Sound.ENTITY_TNT_PRIMED, 0.25F, 1F),
JETPACK_THRUST_SOUND(Sound.ENTITY_GENERIC_EXPLODE, 0.25F, 1F),
JUICER_USE_SOUND(Sound.ENTITY_PLAYER_SPLASH, 1F, 1F),
LIMITED_USE_ITEM_BREAK_SOUND(Sound.ENTITY_ITEM_BREAK, 1F, 1F),
MAGICAL_EYE_OF_ENDER_USE_SOUND(Sound.ENTITY_ENDERMAN_TELEPORT, 1F, 1F),
MAGIC_SUGAR_CONSUME_SOUND(Sound.ENTITY_GENERIC_EAT, 1F, 1F),
MAGIC_WORKBENCH_FINISH_SOUND(Sound.ENTITY_ARROW_HIT_PLAYER, 1F, 1F),
MAGIC_WORKBENCH_START_ANIMATION_SOUND(Sound.BLOCK_WOODEN_BUTTON_CLICK_ON, 1F, 1F),
MINER_ANDROID_BLOCK_GENERATION_SOUND(Sound.BLOCK_FIRE_EXTINGUISH, 0.075F, 0.8F),
MINING_TASK_SOUND(Sound.ENTITY_ARROW_HIT_PLAYER, 0.2F, 1F),
ORE_WASHER_WASH_SOUND(Sound.ENTITY_PLAYER_SPLASH, 1F, 1F),
PLAYER_RESEARCHING_SOUND(Sound.ENTITY_BAT_TAKEOFF, 0.7F, 1F),
PORTABLE_DUSTBIN_OPEN_SOUND(Sound.BLOCK_ANVIL_LAND, 1F, 1F),
PORTABLE_CRAFTER_OPEN_SOUND(Sound.BLOCK_WOODEN_BUTTON_CLICK_ON, 1F, 1F),
PRESSURE_CHAMBER_FINISH_SOUND(Sound.ENTITY_ARROW_HIT_PLAYER, 1F, 1F),
PRESSURE_CHAMBER_WORKING_SOUND(Sound.ENTITY_TNT_PRIMED, 1F, 1F),
PROGRAMMABLE_ANDROID_SCRIPT_DOWNLOAD_SOUND(Sound.BLOCK_NOTE_BLOCK_HAT, 0.7F, 0.7F),
SLIME_BOOTS_FALL_SOUND(Sound.BLOCK_SLIME_BLOCK_FALL, 1F, 1F),
TELEPORTATION_MANAGER_OPEN_GUI(Sound.UI_BUTTON_CLICK, 1F, 1F),
GPS_NETWORK_ADD_WAYPOINT(Sound.BLOCK_NOTE_BLOCK_PLING, 1F, 1F),
GPS_NETWORK_CREATE_WAYPOINT(Sound.BLOCK_NOTE_BLOCK_PLING, 0.5F, 1F),
GPS_NETWORK_OPEN_PANEL_SOUND(Sound.UI_BUTTON_CLICK, 1F, 1F),
SMELTERY_CRAFT_SOUND(Sound.BLOCK_LAVA_POP, 1F, 1F),
SOULBOUND_RUNE_RITUAL_SOUND(Sound.ENTITY_GENERIC_EXPLODE, 0.3F, 1F),
SPLINT_CONSUME_SOUND(Sound.ENTITY_SKELETON_HURT, 1F, 1F),
STOMPER_BOOTS_STOMP_SOUND(Sound.ENTITY_ZOMBIE_BREAK_WOODEN_DOOR, 1F, 2F),
TAPE_MEASURE_MEASURE_SOUND(Sound.ITEM_BOOK_PUT, 1, 0.7F),
TOME_OF_KNOWLEDGE_USE_SOUND(Sound.ENTITY_PLAYER_LEVELUP, 1F, 1F),
TELEPORT_UPDATE_SOUND(Sound.BLOCK_BEACON_AMBIENT, 1F, 0.6F),
TELEPORT_SOUND(Sound.BLOCK_BEACON_ACTIVATE, 1F, 1F),
VAMPIRE_BLADE_HEALING_SOUND(Sound.ENTITY_ARROW_HIT_PLAYER, 0.7F, 0.7F),
VANILLA_AUTO_CRAFTER_UPDATE_RECIPE_SOUND(Sound.UI_BUTTON_CLICK, 1F, 1F),
VILLAGER_RUNE_TRANSFORM_SOUND(Sound.ENTITY_VILLAGER_CELEBRATE, 1F, 1.4F),
VITAMINS_CONSUME_SOUND(Sound.ENTITY_GENERIC_EAT, 1F, 1F),
WIND_STAFF_USE_SOUND(Sound.ENTITY_TNT_PRIMED, 1F, 1F);
private final String defaultSound;
private final float defaultVolume;
private final float defaultPitch;
SoundEffect(@Nonnull String sound, float volume, float pitch) {
Preconditions.checkNotNull(sound, "The Sound id cannot be null!");
Preconditions.checkArgument(volume >= 0, "The volume cannot be a negative number.");
Preconditions.checkArgument(pitch >= 0.5, "A pitch below 0.5 has no effect on the sound.");
this.defaultSound = sound;
this.defaultVolume = volume;
this.defaultPitch = pitch;
}
SoundEffect(@Nonnull Sound sound, float volume, float pitch) {
Preconditions.checkNotNull(sound, "The Sound id cannot be null!");
Preconditions.checkArgument(volume >= 0, "The volume cannot be a negative number.");
Preconditions.checkArgument(pitch >= 0.5, "A pitch below 0.5 has no effect on the sound.");
this.defaultSound = sound.getKey().getKey();
this.defaultVolume = volume;
this.defaultPitch = pitch;
}
private @Nullable SoundConfiguration getConfiguration() {
SoundConfiguration config = Slimefun.getSoundService().getConfiguration(this);
if (config == null) {
// This should not happen. But if it does... send a warning
Slimefun.logger().log(Level.WARNING, "Could not find any sound configuration for: {0}", name());
}
return config;
}
/**
* This method will play this {@link SoundEffect} only to the given {@link Player} using the
* eye {@link Location} of the {@link Player} and the {@link SoundCategory} {@code PLAYERS}.
*
* @param player The {@link Player} which to play the {@link Sound} to.
*/
public void playFor(@Nonnull Player player) {
Preconditions.checkNotNull(player, "Cannot play sounds to a Player that is null!");
SoundConfiguration config = getConfiguration();
if (config != null) {
Location loc = player.getEyeLocation();
player.playSound(loc, config.getSoundId(), SoundCategory.PLAYERS, config.getVolume(), config.getPitch());
}
}
/**
* This method will play this {@link SoundEffect} at the given {@link Location} using the
* provided {@link SoundCategory}.
*
* @param loc The {@link Location} at which to play the {@link SoundEffect}.
* @param category The {@link SoundCategory} that should be used.
*/
public void playAt(@Nonnull Location loc, @Nonnull SoundCategory category) {
Preconditions.checkNotNull(loc, "The location should not be null.");
SoundConfiguration config = getConfiguration();
if (config != null && loc.getWorld() != null) {
loc.getWorld().playSound(loc, config.getSoundId(), category, config.getVolume(), config.getPitch());
}
}
/**
* This method will play this {@link SoundEffect} at the {@link Location} of the given {@link Block},
* the used {@link SoundCategory} will be {@code BLOCKS}.
*
* @param block The {@link Block} at which to play the {@link SoundEffect}
*/
public void playAt(@Nonnull Block block) {
Preconditions.checkNotNull(block, "The block cannot be null.");
playAt(block.getLocation(), SoundCategory.BLOCKS);
}
/**
* This returns the default sound id.
*
* @return The default sound id.
*/
public @Nonnull String getDefaultSoundId() {
return defaultSound;
}
/**
* This returns the default volume.
*
* @return The default volume.
*/
public float getDefaultVolume() {
return defaultVolume;
}
/**
* This returns the default pitch.
*
* @return The default pitch.
*/
public float getDefaultPitch() {
return defaultPitch;
}
}

View File

@ -0,0 +1,109 @@
package io.github.thebusybiscuit.slimefun4.core.services.sounds;
import java.util.EnumMap;
import java.util.Map;
import java.util.logging.Level;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import io.github.bakedlibs.dough.config.Config;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import com.google.common.base.Preconditions;
/**
* The {@link SoundService} is responsible for our sound management.
* It allows server owners to fully customize their users' sound experience.
*
* @author TheBusyBiscuit
*/
public class SoundService {
/**
* Our {@link Config} instance.
*/
private final Config config;
/**
* In this map we cache the corresponding {@link SoundConfiguration} to each {@link SoundEffect}.
*/
private final Map<SoundEffect, SoundConfiguration> soundMap = new EnumMap<>(SoundEffect.class);
public SoundService(@Nonnull Slimefun plugin) {
config = new Config(plugin, "sounds.yml");
// @formatter:off
config.getConfiguration().options().header(
"This file is used to assign the sounds which Slimefun will play.\n" +
"You can fully customize any sound you want and even change their pitch\n" +
"and volume. To disable a sound, simply set the volume to zero.\n"
);
// @formatter:on
config.getConfiguration().options().copyHeader();
}
/**
* This method reloads every {@link SoundConfiguration}.
*
* @param save
* Whether to save the defaults to disk
*/
public void reload(boolean save) {
config.reload();
for (SoundEffect sound : SoundEffect.values()) {
try {
reloadSound(sound);
} catch (Exception | LinkageError x) {
Slimefun.logger().log(Level.SEVERE, x, () -> "An exception was thrown while trying to load the configuration data for the following sound:" + sound.name());
}
}
if (save) {
config.save();
}
}
private void reloadSound(@Nonnull SoundEffect sound) {
// Set up default values
config.setDefaultValue(sound.name() + ".sound", sound.getDefaultSoundId());
config.setDefaultValue(sound.name() + ".volume", sound.getDefaultVolume());
config.setDefaultValue(sound.name() + ".pitch", sound.getDefaultPitch());
// Read the values
String soundId = config.getString(sound.name() + ".sound");
float volume = config.getFloat(sound.name() + ".volume");
float pitch = config.getFloat(sound.name() + ".pitch");
// Check whether the volume is at least 0.0
if (volume < 0) {
Slimefun.logger().log(Level.WARNING, "Invalid value in sounds.yml! Volume for Sound \"{0}\" was {1} (must be at least 0.0)", new Object[] { sound.name(), volume });
volume = 0;
}
// Check if the pitch is at least 0.5
if (pitch < 0.5F) {
Slimefun.logger().log(Level.WARNING, "Invalid value in sounds.yml! Pitch for Sound \"{0}\" was {1} (must be at least 0.5)", new Object[] { sound.name(), pitch });
pitch = 0.5F;
}
// Cache this configuration
SoundConfiguration configuration = new SoundConfiguration(soundId, volume, pitch);
soundMap.put(sound, configuration);
}
/**
* This returns the currently used (immutable) {@link SoundConfiguration} for the given {@link SoundEffect}.
*
* @param sound
* The {@link SoundEffect}
*
* @return The corresponding {@link SoundConfiguration}. This may be null if something went wrong
*/
public @Nullable SoundConfiguration getConfiguration(@Nonnull SoundEffect sound) {
Preconditions.checkNotNull(sound, "The sound must not be null!");
return soundMap.get(sound);
}
}

View File

@ -0,0 +1,7 @@
/**
* This package holds classes related to the
* {@link io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundService}.
* This service is responsible for our sound management and allowing server owners to fully customize
* their sound experience.
*/
package io.github.thebusybiscuit.slimefun4.core.services.sounds;

View File

@ -55,6 +55,7 @@ import io.github.thebusybiscuit.slimefun4.core.services.UpdaterService;
import io.github.thebusybiscuit.slimefun4.core.services.github.GitHubService;
import io.github.thebusybiscuit.slimefun4.core.services.holograms.HologramsService;
import io.github.thebusybiscuit.slimefun4.core.services.profiler.SlimefunProfiler;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundService;
import io.github.thebusybiscuit.slimefun4.implementation.items.altar.AncientAltar;
import io.github.thebusybiscuit.slimefun4.implementation.items.altar.AncientPedestal;
import io.github.thebusybiscuit.slimefun4.implementation.items.backpacks.Cooler;
@ -86,6 +87,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.listeners.MiningAndroid
import io.github.thebusybiscuit.slimefun4.implementation.listeners.MultiBlockListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.NetworkListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.PlayerProfileListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.RadioactivityListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.SeismicAxeListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.SlimefunBootsListener;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.SlimefunBowListener;
@ -114,7 +116,10 @@ import io.github.thebusybiscuit.slimefun4.implementation.resources.GEOResourcesS
import io.github.thebusybiscuit.slimefun4.implementation.setup.PostSetup;
import io.github.thebusybiscuit.slimefun4.implementation.setup.ResearchSetup;
import io.github.thebusybiscuit.slimefun4.implementation.setup.SlimefunItemSetup;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.ArmorTask;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.armor.RadiationTask;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.armor.RainbowArmorTask;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.armor.SlimefunArmorTask;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.armor.SolarHelmetTask;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.SlimefunStartupTask;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.TickerTask;
import io.github.thebusybiscuit.slimefun4.integrations.IntegrationsManager;
@ -175,6 +180,7 @@ public final class Slimefun extends JavaPlugin implements SlimefunAddon {
private final PerWorldSettingsService worldSettingsService = new PerWorldSettingsService(this);
private final MinecraftRecipeService recipeService = new MinecraftRecipeService(this);
private final HologramsService hologramsService = new HologramsService(this);
private final SoundService soundService = new SoundService(this);
// Some other things we need
private final IntegrationsManager integrations = new IntegrationsManager(this);
@ -250,6 +256,7 @@ public final class Slimefun extends JavaPlugin implements SlimefunAddon {
command.register();
registry.load(this, config);
loadTags();
soundService.reload(false);
}
/**
@ -338,6 +345,7 @@ public final class Slimefun extends JavaPlugin implements SlimefunAddon {
runSync(new SlimefunStartupTask(this, () -> {
textureService.register(registry.getAllSlimefunItems(), true);
permissionsService.register(registry.getAllSlimefunItems(), true);
soundService.reload(true);
// This try/catch should prevent buggy Spigot builds from blocking item loading
try {
@ -357,8 +365,10 @@ public final class Slimefun extends JavaPlugin implements SlimefunAddon {
// Armor Update Task
if (config.getBoolean("options.enable-armor-effects")) {
boolean radioactiveFire = config.getBoolean("options.burn-players-when-radioactive");
getServer().getScheduler().runTaskTimerAsynchronously(this, new ArmorTask(radioactiveFire), 0L, config.getInt("options.armor-update-interval") * 20L);
new SlimefunArmorTask().schedule(this, config.getInt("options.armor-update-interval") * 20L);
new RadiationTask().schedule(this, config.getInt("options.radiation-update-interval") * 20L);
new RainbowArmorTask().schedule(this, config.getInt("options.rainbow-armor-update-interval") * 20L);
new SolarHelmetTask().schedule(this, config.getInt("options.armor-update-interval"));
}
// Starting our tasks
@ -640,6 +650,7 @@ public final class Slimefun extends JavaPlugin implements SlimefunAddon {
// Item-specific Listeners
new CoolerListener(this, (Cooler) SlimefunItems.COOLER.getItem());
new SeismicAxeListener(this, (SeismicAxe) SlimefunItems.SEISMIC_AXE.getItem());
new RadioactivityListener(this);
new AncientAltarListener(this, (AncientAltar) SlimefunItems.ANCIENT_ALTAR.getItem(), (AncientPedestal) SlimefunItems.ANCIENT_PEDESTAL.getItem());
grapplingHookListener.register(this, (GrapplingHook) SlimefunItems.GRAPPLING_HOOK.getItem());
bowListener.register(this);
@ -833,6 +844,17 @@ public final class Slimefun extends JavaPlugin implements SlimefunAddon {
return instance.hologramsService;
}
/**
* This returns our {@link SoundService} which handles the configuration of all sounds used in Slimefun
*
* @return Our instance of {@link SoundService}
*/
@Nonnull
public static SoundService getSoundService() {
validateInstance();
return instance.soundService;
}
/**
* This returns our instance of {@link IntegrationsManager}.
* This is responsible for managing any integrations with third party {@link Plugin plugins}.

View File

@ -221,7 +221,11 @@ public final class SlimefunItems {
public static final SlimefunItemStack GLOWSTONE_CHESTPLATE = new SlimefunItemStack("GLOWSTONE_CHESTPLATE", Material.LEATHER_CHESTPLATE, Color.YELLOW, "&e&lGlowstone Chestplate", "", "&a&oShining like the sun!", "", "&9+ Night Vision");
public static final SlimefunItemStack GLOWSTONE_LEGGINGS = new SlimefunItemStack("GLOWSTONE_LEGGINGS", Material.LEATHER_LEGGINGS, Color.YELLOW, "&e&lGlowstone Leggings", "", "&a&oShining like the sun!", "", "&9+ Night Vision");
public static final SlimefunItemStack GLOWSTONE_BOOTS = new SlimefunItemStack("GLOWSTONE_BOOTS", Material.LEATHER_BOOTS, Color.YELLOW, "&e&lGlowstone Boots", "", "&a&oShining like the sun!", "", "&9+ Night Vision");
public static final SlimefunItemStack RAINBOW_LEATHER = new SlimefunItemStack("RAINBOW_LEATHER", Material.RABBIT_HIDE, Color.FUCHSIA, "&dRainbow Leather", "", "&fCan be used to craft rainbow armor");
public static final SlimefunItemStack RAINBOW_HELMET = new SlimefunItemStack("RAINBOW_HELMET", Material.LEATHER_HELMET, Color.FUCHSIA, "&d&lRainbow Helmet", "", LoreBuilder.RAINBOW);
public static final SlimefunItemStack RAINBOW_CHESTPLATE = new SlimefunItemStack("RAINBOW_CHESTPLATE", Material.LEATHER_CHESTPLATE, Color.FUCHSIA, "&d&lRainbow Chestplate", "", LoreBuilder.RAINBOW);
public static final SlimefunItemStack RAINBOW_LEGGINGS = new SlimefunItemStack("RAINBOW_LEGGINGS", Material.LEATHER_LEGGINGS, Color.FUCHSIA, "&d&lRainbow Leggings", "", LoreBuilder.RAINBOW);
public static final SlimefunItemStack RAINBOW_BOOTS = new SlimefunItemStack("RAINBOW_BOOTS", Material.LEATHER_BOOTS, Color.FUCHSIA, "&d&lRainbow Boots", "", LoreBuilder.RAINBOW);
public static final SlimefunItemStack ENDER_HELMET = new SlimefunItemStack("ENDER_HELMET", Material.LEATHER_HELMET, Color.fromRGB(28, 25, 112), "&5&lEnder Helmet", "", "&a&oSometimes its here, sometimes there!");
public static final SlimefunItemStack ENDER_CHESTPLATE = new SlimefunItemStack("ENDER_CHESTPLATE", Material.LEATHER_CHESTPLATE, Color.fromRGB(28, 25, 112), "&5&lEnder Chestplate", "", "&a&oSometimes its here, sometimes there!");
public static final SlimefunItemStack ENDER_LEGGINGS = new SlimefunItemStack("ENDER_LEGGINGS", Material.LEATHER_LEGGINGS, Color.fromRGB(28, 25, 112), "&5&lEnder Leggings", "", "&a&oSometimes its here, sometimes there!");
@ -419,14 +423,12 @@ public final class SlimefunItems {
public static final SlimefunItemStack CRAFTING_MOTOR = new SlimefunItemStack("CRAFTING_MOTOR", HeadTexture.CRAFTING_MOTOR, "&6Crafting Motor", "", "&7Important component of Auto-Crafters");
/* Rainbow blocks */
private static final String RAINBOW = "&dCycles through all Colors of the Rainbow!";
public static final SlimefunItemStack RAINBOW_WOOL = new SlimefunItemStack("RAINBOW_WOOL", Material.WHITE_WOOL, "&5Rainbow Wool", "", RAINBOW);
public static final SlimefunItemStack RAINBOW_GLASS = new SlimefunItemStack("RAINBOW_GLASS", Material.WHITE_STAINED_GLASS, "&5Rainbow Glass", "", RAINBOW);
public static final SlimefunItemStack RAINBOW_CLAY = new SlimefunItemStack("RAINBOW_CLAY", Material.WHITE_TERRACOTTA, "&5Rainbow Clay", "", RAINBOW);
public static final SlimefunItemStack RAINBOW_GLASS_PANE = new SlimefunItemStack("RAINBOW_GLASS_PANE", Material.WHITE_STAINED_GLASS_PANE, "&5Rainbow Glass Pane", "", RAINBOW);
public static final SlimefunItemStack RAINBOW_CONCRETE = new SlimefunItemStack("RAINBOW_CONCRETE", Material.WHITE_CONCRETE, "&5Rainbow Concrete", "", RAINBOW);
public static final SlimefunItemStack RAINBOW_GLAZED_TERRACOTTA = new SlimefunItemStack("RAINBOW_GLAZED_TERRACOTTA", Material.WHITE_GLAZED_TERRACOTTA, "&5Rainbow Glazed Terracotta", "", RAINBOW);
public static final SlimefunItemStack RAINBOW_WOOL = new SlimefunItemStack("RAINBOW_WOOL", Material.WHITE_WOOL, "&5Rainbow Wool", "", LoreBuilder.RAINBOW);
public static final SlimefunItemStack RAINBOW_GLASS = new SlimefunItemStack("RAINBOW_GLASS", Material.WHITE_STAINED_GLASS, "&5Rainbow Glass", "", LoreBuilder.RAINBOW);
public static final SlimefunItemStack RAINBOW_CLAY = new SlimefunItemStack("RAINBOW_CLAY", Material.WHITE_TERRACOTTA, "&5Rainbow Clay", "", LoreBuilder.RAINBOW);
public static final SlimefunItemStack RAINBOW_GLASS_PANE = new SlimefunItemStack("RAINBOW_GLASS_PANE", Material.WHITE_STAINED_GLASS_PANE, "&5Rainbow Glass Pane", "", LoreBuilder.RAINBOW);
public static final SlimefunItemStack RAINBOW_CONCRETE = new SlimefunItemStack("RAINBOW_CONCRETE", Material.WHITE_CONCRETE, "&5Rainbow Concrete", "", LoreBuilder.RAINBOW);
public static final SlimefunItemStack RAINBOW_GLAZED_TERRACOTTA = new SlimefunItemStack("RAINBOW_GLAZED_TERRACOTTA", Material.WHITE_GLAZED_TERRACOTTA, "&5Rainbow Glazed Terracotta", "", LoreBuilder.RAINBOW);
/* Seasonal */
private static final String CHRISTMAS = ChatUtils.christmas("[Christmas Edition]");
public static final SlimefunItemStack RAINBOW_WOOL_XMAS = new SlimefunItemStack("RAINBOW_WOOL_XMAS", Material.WHITE_WOOL, "&5Rainbow Wool &7(Christmas)", "", CHRISTMAS);

View File

@ -14,7 +14,6 @@ import javax.annotation.ParametersAreNonnullByDefault;
import org.apache.commons.lang.Validate;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.Tag;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
@ -44,6 +43,7 @@ import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideMode;
import io.github.thebusybiscuit.slimefun4.core.guide.options.SlimefunGuideSettings;
import io.github.thebusybiscuit.slimefun4.core.multiblocks.MultiBlock;
import io.github.thebusybiscuit.slimefun4.core.multiblocks.MultiBlockMachine;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.AsyncRecipeChoiceTask;
import io.github.thebusybiscuit.slimefun4.utils.ChatUtils;
@ -67,7 +67,6 @@ import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu.MenuClickHan
public class SurvivalSlimefunGuide implements SlimefunGuideImplementation {
private static final int MAX_ITEM_GROUPS = 36;
private static final Sound sound = Sound.ITEM_BOOK_PAGE_TURN;
private final int[] recipeSlots = { 3, 4, 5, 12, 13, 14, 21, 22, 23 };
private final ItemStack item;
@ -80,16 +79,6 @@ public class SurvivalSlimefunGuide implements SlimefunGuideImplementation {
item = new SlimefunGuideItem(this, "&aSlimefun Guide &7(Chest GUI)");
}
/**
* This returns the {@link Sound} which is played when someone navigates through
* the {@link SlimefunGuide}
*
* @return The {@link Sound}
*/
public @Nonnull Sound getSound() {
return sound;
}
@Override
public @Nonnull SlimefunGuideMode getMode() {
return SlimefunGuideMode.SURVIVAL_MODE;
@ -683,7 +672,7 @@ public class SurvivalSlimefunGuide implements SlimefunGuideImplementation {
menu.addMenuClickHandler(28, (pl, slot, itemstack, action) -> {
if (page > 0) {
displayRecipes(pl, profile, menu, sfItem, page - 1);
pl.playSound(pl.getLocation(), sound, 1, 1);
SoundEffect.GUIDE_BUTTON_CLICK_SOUND.playFor(pl);
}
return false;
@ -693,7 +682,7 @@ public class SurvivalSlimefunGuide implements SlimefunGuideImplementation {
menu.addMenuClickHandler(34, (pl, slot, itemstack, action) -> {
if (recipes.size() > (18 * (page + 1))) {
displayRecipes(pl, profile, menu, sfItem, page + 1);
pl.playSound(pl.getLocation(), sound, 1, 1);
SoundEffect.GUIDE_BUTTON_CLICK_SOUND.playFor(pl);
}
return false;
@ -753,7 +742,7 @@ public class SurvivalSlimefunGuide implements SlimefunGuideImplementation {
ChestMenu menu = new ChestMenu(Slimefun.getLocalization().getMessage(p, "guide.title.main"));
menu.setEmptySlotsClickable(false);
menu.addMenuOpeningHandler(pl -> pl.playSound(pl.getLocation(), sound, 1, 1));
menu.addMenuOpeningHandler(SoundEffect.GUIDE_BUTTON_CLICK_SOUND::playFor);
return menu;
}

View File

@ -0,0 +1,30 @@
package io.github.thebusybiscuit.slimefun4.implementation.items;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
/**
* The {@link EnchantedItem} is an enchanted {@link SlimefunItem}.
* By default, this class sets items to be not disenchantable.
*
* @author Fury_Phoenix
*
*/
public class EnchantedItem extends SlimefunItem {
@ParametersAreNonnullByDefault
public EnchantedItem(ItemGroup itemGroup, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(itemGroup, item, recipeType, recipe);
disenchantable = false;
}
}

View File

@ -9,7 +9,6 @@ import javax.annotation.ParametersAreNonnullByDefault;
import org.apache.commons.lang.Validate;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
@ -22,6 +21,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import io.github.thebusybiscuit.slimefun4.implementation.items.magical.staves.StormStaff;
import io.github.thebusybiscuit.slimefun4.utils.LoreBuilder;
@ -116,7 +116,7 @@ public abstract class LimitedUseItem extends SimpleSlimefunItem<ItemUseHandler>
int usesLeft = pdc.getOrDefault(key, PersistentDataType.INTEGER, getMaxUseCount());
if (usesLeft == 1) {
p.playSound(p.getLocation(), Sound.ENTITY_ITEM_BREAK, 1, 1);
SoundEffect.LIMITED_USE_ITEM_BREAK_SOUND.playFor(p);
item.setAmount(0);
item.setType(Material.AIR);
} else {

View File

@ -8,8 +8,8 @@ import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.Sound;
import org.bukkit.block.Block;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Item;
import org.bukkit.entity.Player;
@ -24,13 +24,16 @@ import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup;
import io.github.thebusybiscuit.slimefun4.api.items.ItemSpawnReason;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.attributes.NotHopperable;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockDispenseHandler;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import io.github.thebusybiscuit.slimefun4.implementation.handlers.SimpleBlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.AncientAltarListener;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.AncientAltarTask;
import io.github.thebusybiscuit.slimefun4.utils.ArmorStandUtils;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
/**
@ -40,13 +43,14 @@ import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
*
* @author Redemption198
* @author TheBusyBiscuit
* @author JustAHuman
*
* @see AncientAltar
* @see AncientAltarListener
* @see AncientAltarTask
*
*/
public class AncientPedestal extends SimpleSlimefunItem<BlockDispenseHandler> {
public class AncientPedestal extends SimpleSlimefunItem<BlockDispenseHandler> implements NotHopperable {
public static final String ITEM_PREFIX = ChatColors.color("&dALTAR &3Probe - &e");
@ -63,7 +67,8 @@ public class AncientPedestal extends SimpleSlimefunItem<BlockDispenseHandler> {
@Override
public void onBlockBreak(@Nonnull Block b) {
Optional<Item> entity = getPlacedItem(b);
ArmorStand armorStand = getArmorStand(b, false);
if (entity.isPresent()) {
Item stack = entity.get();
@ -73,6 +78,10 @@ public class AncientPedestal extends SimpleSlimefunItem<BlockDispenseHandler> {
stack.remove();
}
}
if (armorStand != null && armorStand.isValid()) {
armorStand.remove();
}
}
};
}
@ -85,7 +94,7 @@ public class AncientPedestal extends SimpleSlimefunItem<BlockDispenseHandler> {
public @Nonnull Optional<Item> getPlacedItem(@Nonnull Block pedestal) {
Location l = pedestal.getLocation().add(0.5, 1.2, 0.5);
for (Entity n : l.getWorld().getNearbyEntities(l, 0.5, 0.5, 0.5, this::testItem)) {
for (Entity n : l.getWorld().getNearbyEntities(l, 0.5, 0.5, 0.5, AncientPedestal::testItem)) {
if (n instanceof Item item) {
return Optional.of(item);
}
@ -93,8 +102,25 @@ public class AncientPedestal extends SimpleSlimefunItem<BlockDispenseHandler> {
return Optional.empty();
}
public @Nullable ArmorStand getArmorStand(@Nonnull Block pedestal, boolean createIfNoneExists) {
Optional<Item> entity = getPlacedItem(pedestal);
if (entity.isPresent() && entity.get().getVehicle() instanceof ArmorStand armorStand) {
return armorStand;
}
Location l = pedestal.getLocation().add(0.5, 1.2, 0.5);
for (Entity n : l.getWorld().getNearbyEntities(l, 0.5, 0.5, 0.5, this::testArmorStand)) {
if (n instanceof ArmorStand armorStand) {
return armorStand;
}
}
return createIfNoneExists ? ArmorStandUtils.spawnArmorStand(l) : null;
}
private boolean testItem(@Nullable Entity n) {
public static boolean testItem(@Nullable Entity n) {
if (n instanceof Item item && n.isValid()) {
ItemMeta meta = item.getItemStack().getItemMeta();
@ -103,17 +129,24 @@ public class AncientPedestal extends SimpleSlimefunItem<BlockDispenseHandler> {
return false;
}
}
private boolean testArmorStand(@Nullable Entity n) {
if (n instanceof ArmorStand && n.isValid()) {
String customName = n.getCustomName();
return customName != null && customName.startsWith(ITEM_PREFIX);
} else {
return false;
}
}
public @Nonnull ItemStack getOriginalItemStack(@Nonnull Item item) {
ItemStack stack = item.getItemStack().clone();
ItemMeta im = stack.getItemMeta();
String customName = item.getCustomName();
im.setDisplayName(null);
stack.setItemMeta(im);
if (customName.equals(ItemUtils.getItemName(new ItemStack(stack.getType())))) {
ItemMeta im = stack.getItemMeta();
im.setDisplayName(null);
stack.setItemMeta(im);
} else {
ItemMeta im = stack.getItemMeta();
if (customName == null || !customName.equals(ItemUtils.getItemName(stack))) {
im.setDisplayName(customName);
stack.setItemMeta(im);
}
@ -123,7 +156,8 @@ public class AncientPedestal extends SimpleSlimefunItem<BlockDispenseHandler> {
public void placeItem(@Nonnull Player p, @Nonnull Block b) {
ItemStack hand = p.getInventory().getItemInMainHand();
ItemStack displayItem = new CustomItemStack(hand, ITEM_PREFIX + System.nanoTime());
String displayName = ITEM_PREFIX + System.nanoTime();
ItemStack displayItem = new CustomItemStack(hand, displayName);
displayItem.setAmount(1);
// Get the display name of the original Item in the Player's hand
@ -136,11 +170,15 @@ public class AncientPedestal extends SimpleSlimefunItem<BlockDispenseHandler> {
Item entity = SlimefunUtils.spawnItem(b.getLocation().add(0.5, 1.2, 0.5), displayItem, ItemSpawnReason.ANCIENT_PEDESTAL_PLACE_ITEM);
if (entity != null) {
ArmorStand armorStand = getArmorStand(b, true);
entity.setInvulnerable(true);
entity.setVelocity(new Vector(0, 0.1, 0));
entity.setCustomNameVisible(true);
entity.setCustomName(nametag);
armorStand.setCustomName(displayName);
armorStand.addPassenger(entity);
SlimefunUtils.markAsNoPickup(entity, "altar_item");
p.playSound(b.getLocation(), Sound.ENTITY_ITEM_PICKUP, 0.3F, 0.3F);
SoundEffect.ANCIENT_PEDESTAL_ITEM_PLACE_SOUND.playAt(b);
}
}
}

View File

@ -46,7 +46,7 @@ public enum AndroidType {
FIGHTER,
/**
* The {@link FisherAndroid} can catch a fish and other materials.
* The {@link FishermanAndroid} can catch a fish and other materials.
*/
FISHERMAN,

View File

@ -2,8 +2,9 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.androids;
import java.util.concurrent.ThreadLocalRandom;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.Tag;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
@ -13,14 +14,16 @@ import io.github.bakedlibs.dough.collections.RandomizedSet;
import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
public class FisherAndroid extends ProgrammableAndroid {
public class FishermanAndroid extends ProgrammableAndroid {
private final RandomizedSet<ItemStack> fishingLoot = new RandomizedSet<>();
public FisherAndroid(ItemGroup itemGroup, int tier, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
@ParametersAreNonnullByDefault
public FishermanAndroid(ItemGroup itemGroup, int tier, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(itemGroup, tier, item, recipeType, recipe);
// Fish
@ -54,14 +57,12 @@ public class FisherAndroid extends ProgrammableAndroid {
Block water = b.getRelative(BlockFace.DOWN);
if (water.getType() == Material.WATER) {
water.getWorld().playSound(water.getLocation(), Sound.ENTITY_PLAYER_SPLASH, 0.3F, 0.7F);
SoundEffect.FISHERMAN_ANDROID_FISHING_SOUND.playAt(water);
if (ThreadLocalRandom.current().nextInt(100) < 10 * getTier()) {
ItemStack drop = fishingLoot.getRandom();
menu.pushItem(drop.clone(), getOutputSlots());
}
}
}
}

View File

@ -182,7 +182,7 @@ public enum Instruction {
CHOP_TREE(AndroidType.WOODCUTTER, HeadTexture.SCRIPT_CHOP_TREE),
/**
* This {@link Instruction} makes a {@link FisherAndroid} try to catch fish from
* This {@link Instruction} makes a {@link FishermanAndroid} try to catch fish from
* the water below.
*/
CATCH_FISH(AndroidType.FISHERMAN, HeadTexture.SCRIPT_FISH, (android, b, inv, face) -> android.fish(b, inv)),

View File

@ -11,7 +11,6 @@ import org.bukkit.Effect;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.Particle;
import org.bukkit.Sound;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.inventory.ItemStack;
@ -22,6 +21,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup;
import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import io.github.thebusybiscuit.slimefun4.utils.InfiniteBlockGenerator;
import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag;
@ -148,7 +148,7 @@ public class MinerAndroid extends ProgrammableAndroid {
}
// "poof" a "new" block was generated
block.getWorld().playSound(block.getLocation(), Sound.BLOCK_FIRE_EXTINGUISH, 0.075F, 0.8F);
SoundEffect.MINER_ANDROID_BLOCK_GENERATION_SOUND.playAt(block);
block.getWorld().spawnParticle(Particle.SMOKE_NORMAL, block.getX() + 0.5, block.getY() + 1.25, block.getZ() + 0.5, 8, 0.5, 0.5, 0.5, 0.015);
} else {
block.setType(Material.AIR);

View File

@ -14,7 +14,6 @@ import org.apache.commons.lang.Validate;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.Tag;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
@ -45,6 +44,7 @@ import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.attributes.RecipeDisplayItem;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
@ -373,7 +373,7 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock,
ChestMenu menu = new ChestMenu("Android Scripts");
menu.setEmptySlotsClickable(false);
menu.addMenuOpeningHandler(pl -> pl.playSound(pl.getLocation(), Sound.BLOCK_NOTE_BLOCK_HAT, 0.7F, 0.7F));
menu.addMenuOpeningHandler(SoundEffect.PROGRAMMABLE_ANDROID_SCRIPT_DOWNLOAD_SOUND::playFor);
List<Script> scripts = Script.getUploadedScripts(getAndroidType());
int pages = (scripts.size() / 45) + 1;
@ -895,7 +895,11 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock,
Slimefun.runSync(() -> {
PlayerSkin skin = PlayerSkin.fromBase64(texture);
PlayerHead.setSkin(block, skin, true);
Material type = block.getType();
// Ensure that this Block is still a Player Head
if (type == Material.PLAYER_HEAD || type == Material.PLAYER_WALL_HEAD) {
PlayerHead.setSkin(block, skin, true);
}
});
b.setType(Material.AIR);

View File

@ -162,6 +162,17 @@ public class WoodcutterAndroid extends ProgrammableAndroid {
}
}
if (Slimefun.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_20)) {
switch (logType) {
case CHERRY_LOG,
STRIPPED_CHERRY_LOG -> {
saplingType = Material.CHERRY_SAPLING;
soilRequirement = SlimefunTag.DIRT_VARIANTS::isTagged;
}
default -> {}
}
}
if (saplingType != null && soilRequirement != null) {
if (soilRequirement.test(block.getRelative(BlockFace.DOWN).getType())) {
// Replant the block

View File

@ -1,5 +1,6 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.armor;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.inventory.ItemStack;
@ -8,11 +9,12 @@ import org.bukkit.potion.PotionEffect;
import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
/**
* {@link LongFallBoots} are a pair of boots which negate fall damage.
* Nameworthy examples of this are Slime Boots and Bee Boots.
*
* <p>
* <i>Yes, you just found a Portal reference :P</i>
*
* @author TheBusyBiscuit
@ -20,9 +22,31 @@ import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
*/
public class LongFallBoots extends SlimefunArmorPiece {
private final SoundEffect soundEffect;
/**
* @deprecated In RC-35, marked for removal in RC-36
*/
@Deprecated
@ParametersAreNonnullByDefault
public LongFallBoots(ItemGroup itemGroup, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, PotionEffect[] effects) {
super(itemGroup, item, recipeType, recipe, effects);
this(itemGroup, item, recipeType, recipe, effects, SoundEffect.SLIME_BOOTS_FALL_SOUND);
}
@ParametersAreNonnullByDefault
public LongFallBoots(ItemGroup itemGroup, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, PotionEffect[] effects, SoundEffect soundEffect) {
super(itemGroup, item, recipeType, recipe, effects);
this.soundEffect = soundEffect;
}
/**
* This returns the {@link SoundEffect} that is played upon landing with these boots.
*
* @return The {@link SoundEffect} played when landing
*/
@Nonnull
public SoundEffect getSoundEffect() {
return soundEffect;
}
}

View File

@ -9,7 +9,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.gadgets.Jetpack;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.ParachuteTask;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.player.ParachuteTask;
/**
* The {@link Parachute} is a {@link SlimefunItem} that can be equipped as a chestplate.

View File

@ -0,0 +1,62 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.armor;
import java.util.Arrays;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.apache.commons.lang.Validate;
import org.bukkit.Color;
import org.bukkit.DyeColor;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect;
import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag;
/**
* Represents a {@link SlimefunArmorPiece} with rainbow properties (leather armor changing color).
*
* @author martinbrom
*/
public class RainbowArmorPiece extends SlimefunArmorPiece {
private final Color[] colors;
/**
* This creates a new {@link RainbowArmorPiece} from the given arguments.
*
* @param itemGroup The {@link ItemGroup} this {@link RainbowArmorPiece} belongs to
* @param item The {@link SlimefunItemStack} that describes the visual features of our {@link RainbowArmorPiece}
* @param recipeType the {@link RecipeType} that determines how this {@link RainbowArmorPiece} is crafted
* @param recipe An Array representing the recipe of this {@link RainbowArmorPiece}
* @param dyeColors An Array representing the {@link DyeColor}s this {@link RainbowArmorPiece} will cycle between
*/
@ParametersAreNonnullByDefault
public RainbowArmorPiece(ItemGroup itemGroup, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, DyeColor[] dyeColors) {
super(itemGroup, item, recipeType, recipe, new PotionEffect[0]);
// TODO Change this validation over to our custom validation blocked by https://github.com/baked-libs/dough/pull/184
Validate.notEmpty(dyeColors, "RainbowArmorPiece colors cannot be empty!");
if (!SlimefunTag.LEATHER_ARMOR.isTagged(item.getType())) {
throw new IllegalArgumentException("Rainbow armor needs to be a leather armor piece!");
}
colors = Arrays.stream(dyeColors)
.map(DyeColor::getColor)
.toArray(Color[]::new);
}
/**
* Returns the {@link Color}s this {@link RainbowArmorPiece} cycles between
*
* @return The {@link Color}s of this {@link RainbowArmorPiece}
*/
public @Nonnull Color[] getColors() {
return colors;
}
}

View File

@ -6,7 +6,6 @@ import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Bukkit;
import org.bukkit.Effect;
import org.bukkit.Location;
import org.bukkit.Sound;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Entity;
@ -23,6 +22,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
/**
@ -47,7 +47,7 @@ public class StomperBoots extends SlimefunItem {
*/
public void stomp(@Nonnull EntityDamageEvent fallDamageEvent) {
Player player = (Player) fallDamageEvent.getEntity();
player.getWorld().playSound(player.getLocation(), Sound.ENTITY_ZOMBIE_BREAK_WOODEN_DOOR, 1F, 2F);
SoundEffect.STOMPER_BOOTS_STOMP_SOUND.playFor(player);
player.setVelocity(new Vector(0, 0.7, 0));
for (Entity entity : player.getNearbyEntities(4, 4, 4)) {

View File

@ -15,7 +15,6 @@ import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.Particle;
import org.bukkit.Sound;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
@ -36,6 +35,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent;
import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNetComponentType;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.AutoCrafterListener;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.AsyncRecipeChoiceTask;
@ -314,7 +314,7 @@ public abstract class AbstractAutoCrafter extends SlimefunItem implements Energy
recipe.show(menu, task);
menu.open(p);
p.playSound(p.getLocation(), Sound.UI_BUTTON_CLICK, 1, 1);
SoundEffect.AUTO_CRAFTER_GUI_CLICK_SOUND.playFor(p);
// Only schedule the task if necessary
if (!task.isEmpty()) {
@ -325,7 +325,7 @@ public abstract class AbstractAutoCrafter extends SlimefunItem implements Energy
@ParametersAreNonnullByDefault
private void setRecipeEnabled(Player p, Block b, boolean enabled) {
p.closeInventory();
p.playSound(p.getLocation(), Sound.UI_BUTTON_CLICK, 1, 1);
SoundEffect.AUTO_CRAFTER_GUI_CLICK_SOUND.playFor(p);
BlockState state = PaperLib.getBlockState(b, false).getState();
// Make sure the block is still a Skull
@ -344,7 +344,7 @@ public abstract class AbstractAutoCrafter extends SlimefunItem implements Energy
private void deleteRecipe(Player p, Block b) {
setSelectedRecipe(b, null);
p.closeInventory();
p.playSound(p.getLocation(), Sound.UI_BUTTON_CLICK, 1, 1);
SoundEffect.AUTO_CRAFTER_GUI_CLICK_SOUND.playFor(p);
Slimefun.getLocalization().sendMessage(p, "messages.auto-crafting.recipe-removed");
}

View File

@ -7,7 +7,6 @@ import javax.annotation.ParametersAreNonnullByDefault;
import org.apache.commons.lang.Validate;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.Skull;
@ -21,6 +20,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.AsyncRecipeChoiceTask;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
@ -98,7 +98,7 @@ public class SlimefunAutoCrafter extends AbstractAutoCrafter {
menu.addItem(49, new CustomItemStack(Material.CRAFTING_TABLE, ChatColor.GREEN + Slimefun.getLocalization().getMessage(p, "messages.auto-crafting.select")));
menu.addMenuClickHandler(49, (pl, stack, slot, action) -> {
setSelectedRecipe(b, recipe);
p.playSound(p.getLocation(), Sound.UI_BUTTON_CLICK, 1, 1);
SoundEffect.AUTO_CRAFTER_UPDATE_RECIPE.playAt(b);
Slimefun.getLocalization().sendMessage(p, "messages.auto-crafting.recipe-set");
showRecipe(p, b, recipe);
return false;
@ -108,7 +108,7 @@ public class SlimefunAutoCrafter extends AbstractAutoCrafter {
recipe.show(menu, task);
menu.open(p);
p.playSound(p.getLocation(), Sound.UI_BUTTON_CLICK, 1, 1);
SoundEffect.AUTO_CRAFTER_UPDATE_RECIPE.playAt(b);;
if (!task.isEmpty()) {
task.start(menu.toInventory());

View File

@ -12,7 +12,7 @@ import org.apache.commons.lang.Validate;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.Sound;
import org.bukkit.SoundCategory;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.Skull;
@ -31,6 +31,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.services.MinecraftRecipeService;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.AsyncRecipeChoiceTask;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
@ -123,7 +124,7 @@ public class VanillaAutoCrafter extends AbstractAutoCrafter {
menu.open(p);
task.start(menu.toInventory());
p.playSound(p.getLocation(), Sound.UI_BUTTON_CLICK, 1, 1);
SoundEffect.VANILLA_AUTO_CRAFTER_UPDATE_RECIPE_SOUND.playAt(p.getLocation(), SoundCategory.PLAYERS);
}
}
@ -134,7 +135,7 @@ public class VanillaAutoCrafter extends AbstractAutoCrafter {
menu.replaceExistingItem(46, ChestMenuUtils.getPreviousButton(p, index + 1, recipes.size()));
menu.addMenuClickHandler(46, (pl, slot, item, action) -> {
if (index > 0) {
pl.playSound(pl.getLocation(), Sound.UI_BUTTON_CLICK, 1, 1);
SoundEffect.AUTO_CRAFTER_GUI_CLICK_SOUND.playFor(pl);
offerRecipe(p, b, recipes, index - 1, menu, task);
}
@ -144,7 +145,7 @@ public class VanillaAutoCrafter extends AbstractAutoCrafter {
menu.replaceExistingItem(52, ChestMenuUtils.getNextButton(p, index + 1, recipes.size()));
menu.addMenuClickHandler(52, (pl, slot, item, action) -> {
if (index < (recipes.size() - 1)) {
pl.playSound(pl.getLocation(), Sound.UI_BUTTON_CLICK, 1, 1);
SoundEffect.AUTO_CRAFTER_GUI_CLICK_SOUND.playFor(pl);
offerRecipe(p, b, recipes, index + 1, menu, task);
}
@ -158,7 +159,7 @@ public class VanillaAutoCrafter extends AbstractAutoCrafter {
setSelectedRecipe(b, recipe);
pl.closeInventory();
p.playSound(p.getLocation(), Sound.UI_BUTTON_CLICK, 1, 1);
SoundEffect.AUTO_CRAFTER_GUI_CLICK_SOUND.playFor(pl);
Slimefun.getLocalization().sendMessage(p, "messages.auto-crafting.recipe-set");
showRecipe(p, b, recipe);

View File

@ -1,8 +1,8 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.backpacks;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Sound;
import org.bukkit.block.EnderChest;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
@ -13,6 +13,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.attributes.NotPlaceable;
import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
/**
@ -30,11 +31,11 @@ public class EnderBackpack extends SimpleSlimefunItem<ItemUseHandler> implements
}
@Override
public ItemUseHandler getItemHandler() {
public @Nonnull ItemUseHandler getItemHandler() {
return e -> {
Player p = e.getPlayer();
p.openInventory(p.getEnderChest());
p.playSound(p.getEyeLocation(), Sound.ENTITY_ENDERMAN_TELEPORT, 1F, 1F);
SoundEffect.ENDER_BACKPACK_OPEN_SOUND.playFor(p);
e.cancel();
};
}

View File

@ -6,16 +6,19 @@ import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.player.PlayerBackpack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.attributes.DistinctiveItem;
import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.BackpackListener;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag;
/**
@ -28,7 +31,7 @@ import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag;
* @see PlayerBackpack
*
*/
public class SlimefunBackpack extends SimpleSlimefunItem<ItemUseHandler> {
public class SlimefunBackpack extends SimpleSlimefunItem<ItemUseHandler> implements DistinctiveItem {
private final int size;
@ -82,4 +85,14 @@ public class SlimefunBackpack extends SimpleSlimefunItem<ItemUseHandler> {
};
}
@Override
public boolean canStack(@Nonnull ItemMeta itemMetaOne, @Nonnull ItemMeta itemMetaTwo) {
boolean hasLoreItem = itemMetaTwo.hasLore();
boolean hasLoreSfItem = itemMetaOne.hasLore();
if (hasLoreItem && hasLoreSfItem && SlimefunUtils.equalsLore(itemMetaTwo.getLore(), itemMetaOne.getLore())) {
return true;
}
return !hasLoreItem && !hasLoreSfItem;
}
}

View File

@ -10,7 +10,6 @@ import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Effect;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.Tag;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
@ -25,6 +24,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.attributes.RecipeDisplayItem;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockUseHandler;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
@ -94,7 +94,7 @@ public class Composter extends SimpleSlimefunItem<BlockUseHandler> implements Re
});
tasks.thenRun(20, () -> {
p.getWorld().playSound(p.getLocation(), Sound.ENTITY_ARROW_HIT_PLAYER, 1F, 1F);
SoundEffect.COMPOSTER_COMPOST_SOUND.playFor(p);
pushItem(b, output.clone());
});

View File

@ -9,7 +9,6 @@ import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Material;
import org.bukkit.Particle;
import org.bukkit.Sound;
import org.bukkit.Tag;
import org.bukkit.World.Environment;
import org.bukkit.block.Block;
@ -27,6 +26,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.attributes.RecipeDisplayItem;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockUseHandler;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
@ -166,7 +166,7 @@ public class Crucible extends SimpleSlimefunItem<BlockUseHandler> implements Rec
if (isWater && block.getWorld().getEnvironment() == Environment.NETHER && !allowWaterInNether.getValue()) {
// We will still consume the items but won't generate water in the Nether.
block.getWorld().spawnParticle(Particle.SMOKE_NORMAL, block.getLocation().add(0.5, 0.5, 0.5), 4);
block.getWorld().playSound(block.getLocation(), Sound.BLOCK_LAVA_EXTINGUISH, 1F, 1F);
SoundEffect.CRUCIBLE_GENERATE_LIQUID_SOUND.playAt(block);
return;
}
@ -175,7 +175,7 @@ public class Crucible extends SimpleSlimefunItem<BlockUseHandler> implements Rec
} else if (block.getType() == (isWater ? Material.LAVA : Material.WATER)) {
int level = ((Levelled) block.getBlockData()).getLevel();
block.setType(level == 0 || level == 8 ? Material.OBSIDIAN : Material.STONE);
block.getWorld().playSound(block.getLocation(), Sound.BLOCK_LAVA_EXTINGUISH, 1F, 1F);
SoundEffect.CRUCIBLE_GENERATE_LIQUID_SOUND.playAt(block);
} else {
Slimefun.runSync(() -> placeLiquid(block, isWater), 50L);
}
@ -189,10 +189,10 @@ public class Crucible extends SimpleSlimefunItem<BlockUseHandler> implements Rec
}
if (level == 0) {
block.getWorld().playSound(block.getLocation(), water ? Sound.ENTITY_PLAYER_SPLASH : Sound.BLOCK_LAVA_POP, 1F, 1F);
Slimefun.runSync(() -> runPostTask(block, water ? SoundEffect.CRUCIBLE_ADD_WATER_SOUND : SoundEffect.CRUCIBLE_ADD_LAVA_SOUND, 1));
} else {
int finalLevel = 7 - level;
Slimefun.runSync(() -> runPostTask(block, water ? Sound.ENTITY_PLAYER_SPLASH : Sound.BLOCK_LAVA_POP, finalLevel), 50L);
Slimefun.runSync(() -> runPostTask(block, water ? SoundEffect.CRUCIBLE_ADD_WATER_SOUND : SoundEffect.CRUCIBLE_ADD_LAVA_SOUND, finalLevel), 50L);
}
}
@ -204,7 +204,7 @@ public class Crucible extends SimpleSlimefunItem<BlockUseHandler> implements Rec
if (water && block.getBlockData() instanceof Waterlogged waterlogged) {
waterlogged.setWaterlogged(true);
block.setBlockData(waterlogged, false);
block.getWorld().playSound(block.getLocation(), Sound.ENTITY_PLAYER_SPLASH, 1F, 1F);
SoundEffect.CRUCIBLE_PLACE_WATER_SOUND.playAt(block);
return;
}
@ -212,18 +212,17 @@ public class Crucible extends SimpleSlimefunItem<BlockUseHandler> implements Rec
BlockStorage.clearBlockInfo(block);
}
}
runPostTask(block, water ? Sound.ENTITY_PLAYER_SPLASH : Sound.BLOCK_LAVA_POP, 1);
runPostTask(block, water ? SoundEffect.CRUCIBLE_PLACE_WATER_SOUND : SoundEffect.CRUCIBLE_PLACE_LAVA_SOUND, 1);
}
@ParametersAreNonnullByDefault
private void runPostTask(Block block, Sound sound, int times) {
private void runPostTask(Block block, SoundEffect sound, int times) {
if (!(block.getBlockData() instanceof Levelled le)) {
block.getWorld().playSound(block.getLocation(), Sound.BLOCK_METAL_BREAK, 1F, 1F);
SoundEffect.CRUCIBLE_BLOCK_BREAK_SOUND.playAt(block);
return;
}
block.getWorld().playSound(block.getLocation(), sound, 1F, 1F);
sound.playAt(block);
int level = 8 - times;
le.setLevel(level);
block.setBlockData(le, false);
@ -231,7 +230,7 @@ public class Crucible extends SimpleSlimefunItem<BlockUseHandler> implements Rec
if (times < 8) {
Slimefun.runSync(() -> runPostTask(block, sound, times + 1), 50L);
} else {
block.getWorld().playSound(block.getLocation(), Sound.ENTITY_ARROW_HIT_PLAYER, 1F, 1F);
SoundEffect.CRUCIBLE_INTERACT_SOUND.playAt(block);
}
}

View File

@ -8,7 +8,6 @@ import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.inventory.ItemStack;
@ -26,6 +25,7 @@ import io.github.thebusybiscuit.slimefun4.core.handlers.BlockUseHandler;
import io.github.thebusybiscuit.slimefun4.core.services.holograms.HologramsService;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import io.github.thebusybiscuit.slimefun4.implementation.handlers.SimpleBlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.utils.ArmorStandUtils;
import io.github.thebusybiscuit.slimefun4.utils.ChatUtils;
import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
@ -152,22 +152,8 @@ public class HologramProjector extends SlimefunItem implements HologramOwner {
if (!createIfNoneExists) {
return null;
}
ArmorStand hologram = spawnArmorStand(l);
hologram.setCustomName(nametag);
return hologram;
}
private static @Nonnull ArmorStand spawnArmorStand(@Nonnull Location l) {
ArmorStand armorStand = (ArmorStand) l.getWorld().spawnEntity(l, EntityType.ARMOR_STAND);
armorStand.setVisible(false);
armorStand.setSilent(true);
armorStand.setMarker(true);
armorStand.setGravity(false);
armorStand.setBasePlate(false);
armorStand.setCustomNameVisible(true);
armorStand.setRemoveWhenFarAway(false);
return armorStand;
return ArmorStandUtils.spawnArmorStand(l, nametag);
}
private static void killArmorStand(@Nonnull Block b) {

View File

@ -6,7 +6,6 @@ import javax.annotation.ParametersAreNonnullByDefault;
import org.apache.commons.lang.Validate;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
@ -22,6 +21,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import io.github.thebusybiscuit.slimefun4.implementation.handlers.VanillaInventoryDropHandler;
import io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks.Smeltery;
@ -94,13 +94,13 @@ public class IgnitionChamber extends SlimefunItem {
if (((Damageable) meta).getDamage() >= item.getType().getMaxDurability()) {
// The Flint and Steel broke
item.setAmount(0);
smelteryBlock.getWorld().playSound(smelteryBlock.getLocation(), Sound.ENTITY_ITEM_BREAK, 1, 1);
SoundEffect.IGNITION_CHAMBER_USE_FLINT_AND_STEEL_SOUND.playAt(smelteryBlock);
} else {
item.setItemMeta(meta);
}
}
smelteryBlock.getWorld().playSound(smelteryBlock.getLocation(), Sound.ITEM_FLINTANDSTEEL_USE, 1, 1);
SoundEffect.IGNITION_CHAMBER_USE_FLINT_AND_STEEL_SOUND.playAt(smelteryBlock);
return true;
} else {
// Notify the Player there is a chamber but without any Flint and Steel

View File

@ -9,7 +9,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.attributes.Rechargeable;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.JetBootsTask;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.player.JetBootsTask;
/**
* {@link JetBoots} allow you to hover for a bit.

View File

@ -9,7 +9,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.attributes.Rechargeable;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.JetpackTask;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.player.JetpackTask;
/**
* {@link JetBoots} allow you to fly up into the air.

View File

@ -15,7 +15,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.items.settings.DoubleRangeSetting;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.attributes.Rechargeable;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.ArmorTask;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.armor.SolarHelmetTask;
/**
* The {@link SolarHelmet} can be worn by {@link Player}.
@ -24,8 +24,8 @@ import io.github.thebusybiscuit.slimefun4.implementation.tasks.ArmorTask;
* or holding.
*
* @author TheBusyBiscuit
*
* @see ArmorTask
*
* @see SolarHelmetTask
* @see Rechargeable
*
*/

View File

@ -1,5 +1,6 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Material;
@ -45,25 +46,28 @@ public class ElectricDustWasher extends AContainer {
@Override
protected MachineRecipe findNextRecipe(BlockMenu menu) {
for (int slot : getInputSlots()) {
if (SlimefunUtils.isItemSimilar(menu.getItemInSlot(slot), SlimefunItems.SIFTED_ORE, true, false)) {
ItemStack input = menu.getItemInSlot(slot);
MachineRecipe recipe = null;
if (SlimefunUtils.isItemSimilar(input, SlimefunItems.SIFTED_ORE, true, false)) {
if (!legacyMode && !hasFreeSlot(menu)) {
return null;
}
ItemStack dust = oreWasher.getRandomDust();
MachineRecipe recipe = new MachineRecipe(4 / getSpeed(), new ItemStack[] { SlimefunItems.SIFTED_ORE }, new ItemStack[] { dust });
recipe = new MachineRecipe(4 / getSpeed(), new ItemStack[] { SlimefunItems.SIFTED_ORE }, new ItemStack[] { oreWasher.getRandomDust() });
if (!legacyMode || menu.fits(recipe.getOutput()[0], getOutputSlots())) {
menu.consumeItem(slot);
return recipe;
}
} else if (SlimefunUtils.isItemSimilar(menu.getItemInSlot(slot), SlimefunItems.PULVERIZED_ORE, true)) {
MachineRecipe recipe = new MachineRecipe(4 / getSpeed(), new ItemStack[] { SlimefunItems.PULVERIZED_ORE }, new ItemStack[] { SlimefunItems.PURE_ORE_CLUSTER });
} else if (SlimefunUtils.isItemSimilar(input, SlimefunItems.PULVERIZED_ORE, true)) {
recipe = new MachineRecipe(4 / getSpeed(), new ItemStack[] { SlimefunItems.PULVERIZED_ORE }, new ItemStack[] { SlimefunItems.PURE_ORE_CLUSTER });
} else if (SlimefunUtils.isItemSimilar(input, new ItemStack(Material.SAND), true)) {
recipe = new MachineRecipe(4 / getSpeed(), new ItemStack[] { new ItemStack(Material.SAND) }, new ItemStack[] { SlimefunItems.SALT });
}
if (menu.fits(recipe.getOutput()[0], getOutputSlots())) {
menu.consumeItem(slot);
return recipe;
}
if (recipe != null && menu.fits(recipe.getOutput()[0], getOutputSlots())) {
menu.consumeItem(slot);
return recipe;
}
}
@ -83,7 +87,7 @@ public class ElectricDustWasher extends AContainer {
}
@Override
public String getMachineIdentifier() {
public @Nonnull String getMachineIdentifier() {
return "ELECTRIC_DUST_WASHER";
}

View File

@ -17,7 +17,6 @@ import io.github.thebusybiscuit.slimefun4.core.attributes.RecipeDisplayItem;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
import io.github.thebusybiscuit.slimefun4.implementation.items.tools.GoldPan;
import io.github.thebusybiscuit.slimefun4.implementation.items.tools.NetherGoldPan;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AContainer;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineRecipe;
@ -28,10 +27,11 @@ import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
* It also serves as a {@link NetherGoldPan}.
*
* @author TheBusyBiscuit
*
* @author svr333
* @author JustAHuman
*
* @see GoldPan
* @see NetherGoldPan
*
*/
public class ElectricGoldPan extends AContainer implements RecipeDisplayItem {
@ -40,9 +40,6 @@ public class ElectricGoldPan extends AContainer implements RecipeDisplayItem {
private final GoldPan goldPan = SlimefunItems.GOLD_PAN.getItem(GoldPan.class);
private final GoldPan netherGoldPan = SlimefunItems.NETHER_GOLD_PAN.getItem(GoldPan.class);
private final ItemStack gravel = new ItemStack(Material.GRAVEL);
private final ItemStack soulSand = new ItemStack(Material.SOUL_SAND);
@ParametersAreNonnullByDefault
public ElectricGoldPan(ItemGroup itemGroup, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(itemGroup, item, recipeType, recipe);
@ -50,21 +47,30 @@ public class ElectricGoldPan extends AContainer implements RecipeDisplayItem {
}
/**
* This returns whether the {@link ElectricGoldPan} will stop proccessing inputs
* @deprecated since RC-36
* Use {@link ElectricGoldPan#isOutputLimitOverridden()} instead.
*/
@Deprecated(since = "RC-36")
public boolean isOutputLimitOverriden() {
return isOutputLimitOverridden();
}
/**
* This returns whether the {@link ElectricGoldPan} will stop processing inputs
* if both output slots contain items or if that default behavior should be
* overriden and allow the {@link ElectricGoldPan} to continue processing inputs
* overridden and allow the {@link ElectricGoldPan} to continue processing inputs
* even if both output slots are occupied. Note this option will allow players
* to force specific outputs from the {@link ElectricGoldPan} but can be
* necessary when a server has disabled cargo networks.
*
* @return If output limits are overriden
* @return If output limits are overridden
*/
public boolean isOutputLimitOverriden() {
public boolean isOutputLimitOverridden() {
return overrideOutputLimit.getValue();
}
@Override
public List<ItemStack> getDisplayRecipes() {
public @Nonnull List<ItemStack> getDisplayRecipes() {
List<ItemStack> recipes = new ArrayList<>();
recipes.addAll(goldPan.getDisplayRecipes());
@ -80,30 +86,26 @@ public class ElectricGoldPan extends AContainer implements RecipeDisplayItem {
@Override
protected MachineRecipe findNextRecipe(BlockMenu menu) {
if (!isOutputLimitOverriden() && !hasFreeSlot(menu)) {
if (!isOutputLimitOverridden() && !hasFreeSlot(menu)) {
return null;
}
for (int slot : getInputSlots()) {
ItemStack item = menu.getItemInSlot(slot);
MachineRecipe recipe = null;
ItemStack output = null;
if (SlimefunUtils.isItemSimilar(item, gravel, true, false)) {
ItemStack output = goldPan.getRandomOutput();
MachineRecipe recipe = new MachineRecipe(3 / getSpeed(), new ItemStack[] { gravel }, new ItemStack[] { output });
if (output.getType() != Material.AIR && menu.fits(output, getOutputSlots())) {
menu.consumeItem(slot);
return recipe;
}
} else if (SlimefunUtils.isItemSimilar(item, soulSand, true, false)) {
ItemStack output = netherGoldPan.getRandomOutput();
MachineRecipe recipe = new MachineRecipe(4 / getSpeed(), new ItemStack[] { soulSand }, new ItemStack[] { output });
if (output.getType() != Material.AIR && menu.fits(output, getOutputSlots())) {
menu.consumeItem(slot);
return recipe;
}
if (goldPan.isValidInput(item)) {
output = goldPan.getRandomOutput();
recipe = new MachineRecipe(3 / getSpeed(), new ItemStack[] { item }, new ItemStack[] { output });
} else if (netherGoldPan.isValidInput(item)) {
output = netherGoldPan.getRandomOutput();
recipe = new MachineRecipe(4 / getSpeed(), new ItemStack[] { item }, new ItemStack[] { output });
}
if (output != null && output.getType() != Material.AIR && menu.fits(output, getOutputSlots())) {
menu.consumeItem(slot);
return recipe;
}
}
@ -121,7 +123,7 @@ public class ElectricGoldPan extends AContainer implements RecipeDisplayItem {
}
@Override
public String getMachineIdentifier() {
public @Nonnull String getMachineIdentifier() {
return "ELECTRIC_GOLD_PAN";
}

View File

@ -7,6 +7,7 @@ import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Material;
import org.bukkit.entity.Item;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
@ -28,6 +29,7 @@ import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
*
* @author TheBusyBiscuit
* @author Rothes
* @author J3fftw1
*
* @see AutoEnchanter
* @see AutoDisenchanter
@ -37,6 +39,8 @@ abstract class AbstractEnchantmentMachine extends AContainer {
private final ItemSetting<Boolean> useLevelLimit = new ItemSetting<>(this, "use-enchant-level-limit", false);
private final IntRangeSetting levelLimit = new IntRangeSetting(this, "enchant-level-limit", 0, 10, Short.MAX_VALUE);
private final ItemSetting<Integer> maxEnchants = new IntRangeSetting(this, "max-enchants", 0, 10, Short.MAX_VALUE);
private final ItemSetting<Boolean> useMaxEnchants= new ItemSetting<>(this, "use-max-enchants", false);
private final ItemSetting<Boolean> useIgnoredLores = new ItemSetting<>(this, "use-ignored-lores", false);
private final ItemSetting<List<String>> ignoredLores = new ItemSetting<>(this, "ignored-lores", Collections.singletonList("&7- &cCan't be used in " + this.getItemName()));
@ -48,6 +52,8 @@ abstract class AbstractEnchantmentMachine extends AContainer {
addItemSetting(levelLimit);
addItemSetting(useIgnoredLores);
addItemSetting(ignoredLores);
addItemSetting(maxEnchants);
addItemSetting(useMaxEnchants);
}
protected boolean isEnchantmentLevelAllowed(int enchantmentLevel) {
@ -84,4 +90,11 @@ abstract class AbstractEnchantmentMachine extends AContainer {
return false;
}
protected boolean isEnchantmentAmountAllowed(int numberOfEnchants) {
if (!useMaxEnchants.getValue()) {
return true;
}
return numberOfEnchants <= maxEnchants.getValue();
}
}

View File

@ -2,6 +2,7 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.electric.machine
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
@ -20,6 +21,8 @@ import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineRecipe;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
@ -94,6 +97,10 @@ public class AutoDisenchanter extends AbstractEnchantmentMachine {
}
}
if (!isEnchantmentAmountAllowed(enchantments.size())) {
return null;
}
// Check if we found any valid enchantments
if (!enchantments.isEmpty()) {
ItemStack disenchantedItem = item.clone();
@ -124,16 +131,25 @@ public class AutoDisenchanter extends AbstractEnchantmentMachine {
ItemMeta bookMeta = book.getItemMeta();
((Repairable) bookMeta).setRepairCost(((Repairable) itemMeta).getRepairCost());
((Repairable) itemMeta).setRepairCost(0);
item.setItemMeta(itemMeta);
book.setItemMeta(bookMeta);
EnchantmentStorageMeta meta = (EnchantmentStorageMeta) book.getItemMeta();
for (Map.Entry<Enchantment, Integer> entry : enchantments.entrySet()) {
item.removeEnchantment(entry.getKey());
meta.addStoredEnchant(entry.getKey(), entry.getValue(), true);
Enchantment enchantmentToTransfer = entry.getKey();
boolean wasEnchantmentRemoved = itemMeta.removeEnchant(enchantmentToTransfer);
boolean stillHasEnchantment = itemMeta.getEnchants().containsKey(enchantmentToTransfer);
// Prevent future enchantment duplication (#3837)
if (wasEnchantmentRemoved && !stillHasEnchantment) {
meta.addStoredEnchant(enchantmentToTransfer, entry.getValue(), true);
} else {
// Get Enchantment Name
Slimefun.logger().log(Level.SEVERE, "AutoDisenchanter has failed to remove enchantment \"{0}\"", enchantmentToTransfer.getKey().getKey());
}
}
item.setItemMeta(itemMeta);
book.setItemMeta(meta);
}

View File

@ -116,6 +116,22 @@ public class AutoEnchanter extends AbstractEnchantmentMachine {
enchantments.entrySet().removeIf(e -> target.getEnchantmentLevel(e.getKey()) >= e.getValue());
}
/*
* When maxEnchants is set to -1 it will be ignored. When it's set to 0 it will not allow any enchants to go
* on an item. When maxEnchants is set to any other value it will allow that many enchants to go on the item.
*/
int preExistingEnchants = 0;
for (Map.Entry<Enchantment, Integer> entry : target.getEnchantments().entrySet()) {
if (meta.hasEnchant(entry.getKey())) {
preExistingEnchants++;
}
}
int totalEnchants = enchantments.size() + preExistingEnchants;
if (!isEnchantmentAmountAllowed(totalEnchants)) {
return null;
}
// Check if we found any valid enchantments
if (!enchantments.isEmpty()) {
ItemStack enchantedItem = target.clone();

View File

@ -5,6 +5,7 @@ import java.util.Iterator;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
@ -123,46 +124,59 @@ public class ExpCollector extends SlimefunItem implements InventoryBlock, Energy
});
}
protected void tick(Block b) {
Iterator<Entity> iterator = b.getWorld().getNearbyEntities(b.getLocation(), 4.0, 4.0, 4.0, n -> n instanceof ExperienceOrb && n.isValid()).iterator();
protected void tick(Block block) {
Location location = block.getLocation();
Iterator<Entity> iterator = block.getWorld().getNearbyEntities(location, 4.0, 4.0, 4.0, n -> n instanceof ExperienceOrb && n.isValid()).iterator();
int experiencePoints = 0;
while (iterator.hasNext() && experiencePoints == 0) {
Entity entity = iterator.next();
ExperienceOrb orb = (ExperienceOrb) iterator.next();
if (getCharge(b.getLocation()) < ENERGY_CONSUMPTION) {
if (getCharge(location) < ENERGY_CONSUMPTION) {
return;
}
experiencePoints = getStoredExperience(b) + ((ExperienceOrb) entity).getExperience();
experiencePoints = getStoredExperience(location) + orb.getExperience();
removeCharge(b.getLocation(), ENERGY_CONSUMPTION);
entity.remove();
int withdrawn = 0;
BlockMenu menu = BlockStorage.getInventory(b);
for (int level = 0; level < getStoredExperience(b); level = level + 10) {
if (menu.fits(SlimefunItems.FILLED_FLASK_OF_KNOWLEDGE, getOutputSlots())) {
withdrawn = withdrawn + 10;
menu.pushItem(SlimefunItems.FILLED_FLASK_OF_KNOWLEDGE.clone(), getOutputSlots());
}
}
BlockStorage.addBlockInfo(b, DATA_KEY, String.valueOf(experiencePoints - withdrawn));
removeCharge(location, ENERGY_CONSUMPTION);
orb.remove();
produceFlasks(location, experiencePoints);
}
}
private int getStoredExperience(Block b) {
Config cfg = BlockStorage.getLocationInfo(b.getLocation());
/**
* Produces Flasks of Knowledge for the given block until it either uses all stored
* experience or runs out of room.
*
* @param location
* The {@link Location} of the {@link ExpCollector} to produce flasks in.
* @param experiencePoints
* The number of experience points to use during production.
*/
private void produceFlasks(@Nonnull Location location, int experiencePoints) {
int withdrawn = 0;
BlockMenu menu = BlockStorage.getInventory(location);
for (int level = 0; level < getStoredExperience(location); level = level + 10) {
if (menu.fits(SlimefunItems.FILLED_FLASK_OF_KNOWLEDGE, getOutputSlots())) {
withdrawn = withdrawn + 10;
menu.pushItem(SlimefunItems.FILLED_FLASK_OF_KNOWLEDGE.clone(), getOutputSlots());
} else {
// There is no room for more bottles, so lets stop checking if more will fit.
break;
}
}
BlockStorage.addBlockInfo(location, DATA_KEY, String.valueOf(experiencePoints - withdrawn));
}
private int getStoredExperience(Location location) {
Config cfg = BlockStorage.getLocationInfo(location);
String value = cfg.getString(DATA_KEY);
if (value != null) {
return Integer.parseInt(value);
} else {
BlockStorage.addBlockInfo(b, DATA_KEY, "0");
BlockStorage.addBlockInfo(location, DATA_KEY, "0");
return 0;
}
}
}

View File

@ -4,7 +4,7 @@ import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.SoundCategory;
import org.bukkit.entity.IronGolem;
import org.bukkit.inventory.ItemStack;
@ -12,6 +12,7 @@ import io.github.bakedlibs.dough.items.CustomItemStack;
import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenuPreset;
@ -71,8 +72,7 @@ public class IronGolemAssembler extends AbstractEntityAssembler<IronGolem> {
@Override
public IronGolem spawnEntity(Location l) {
l.getWorld().playSound(l, Sound.ENTITY_IRON_GOLEM_REPAIR, 0.5F, 1);
SoundEffect.IRON_GOLEM_ASSEMBLER_ASSEMBLE_SOUND.playAt(l, SoundCategory.BLOCKS);
return l.getWorld().spawn(l, IronGolem.class);
}
}

View File

@ -1,8 +1,8 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.food;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Sound;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
@ -11,6 +11,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.handlers.ItemConsumptionHandler;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
@ -32,10 +33,10 @@ public class DietCookie extends SimpleSlimefunItem<ItemConsumptionHandler> {
}
@Override
public ItemConsumptionHandler getItemHandler() {
public @Nonnull ItemConsumptionHandler getItemHandler() {
return (e, p, item) -> {
Slimefun.getLocalization().sendMessage(p, "messages.diet-cookie");
p.playSound(p.getLocation(), Sound.ENTITY_GENERIC_EAT, 1, 1);
SoundEffect.DIET_COOKIE_CONSUME_SOUND.playFor(p);
if (p.hasPotionEffect(PotionEffectType.LEVITATION)) {
p.removePotionEffect(PotionEffectType.LEVITATION);
@ -44,5 +45,4 @@ public class DietCookie extends SimpleSlimefunItem<ItemConsumptionHandler> {
p.addPotionEffect(PotionEffectType.LEVITATION.createEffect(60, 1));
};
}
}

View File

@ -1,10 +1,10 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.food;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect;
@ -15,6 +15,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
/**
@ -32,7 +33,7 @@ public class MagicSugar extends SimpleSlimefunItem<ItemUseHandler> {
}
@Override
public ItemUseHandler getItemHandler() {
public @Nonnull ItemUseHandler getItemHandler() {
return e -> {
// Check if it is being placed into an ancient altar.
if (e.getClickedBlock().isPresent()) {
@ -49,7 +50,7 @@ public class MagicSugar extends SimpleSlimefunItem<ItemUseHandler> {
ItemUtils.consumeItem(e.getItem(), false);
}
p.playSound(p.getLocation(), Sound.ENTITY_GENERIC_EAT, 1, 1);
SoundEffect.MAGIC_SUGAR_CONSUME_SOUND.playFor(p);
p.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, 600, 3));
};
}

View File

@ -9,7 +9,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.BeeWingsListener;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.BeeWingsTask;
import io.github.thebusybiscuit.slimefun4.implementation.tasks.player.BeeWingsTask;
/**
* The {@link BeeWings} are a special form of the elytra which gives you a slow falling effect

View File

@ -5,8 +5,6 @@ import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.SoundCategory;
import org.bukkit.block.Block;
import org.bukkit.block.data.type.Hopper;
import org.bukkit.entity.Entity;
@ -20,6 +18,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.items.settings.DoubleRangeSetting;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
import io.github.thebusybiscuit.slimefun4.implementation.handlers.VanillaInventoryDropHandler;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
@ -55,7 +54,7 @@ public class InfusedHopper extends SimpleSlimefunItem<BlockTicker> {
}
@Override
public BlockTicker getItemHandler() {
public @Nonnull BlockTicker getItemHandler() {
return new BlockTicker() {
@Override
@ -94,8 +93,8 @@ public class InfusedHopper extends SimpleSlimefunItem<BlockTicker> {
* Play a sound if at least one item was teleported and
* the "silent" setting is set to false.
*/
if (playSound && !silent.getValue().booleanValue()) {
b.getWorld().playSound(b.getLocation(), Sound.ENTITY_ENDERMAN_TELEPORT, SoundCategory.BLOCKS, 1F, 2F);
if (playSound && !silent.getValue()) {
SoundEffect.INFUSED_HOPPER_TELEPORT_SOUND.playAt(b);
}
}

View File

@ -1,8 +1,8 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.magical;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
@ -12,6 +12,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
@ -30,11 +31,12 @@ public class KnowledgeFlask extends SimpleSlimefunItem<ItemUseHandler> {
}
@Override
public ItemUseHandler getItemHandler() {
public @Nonnull ItemUseHandler getItemHandler() {
return e -> {
e.cancel();
Player p = e.getPlayer();
if (p.getLevel() >= 1 && (!e.getClickedBlock().isPresent() || !(e.getClickedBlock().get().getType().isInteractable()))) {
if (p.getLevel() >= 1 && (e.getClickedBlock().isEmpty() || !(e.getClickedBlock().get().getType().isInteractable()))) {
p.setLevel(p.getLevel() - 1);
ItemStack item = SlimefunItems.FILLED_FLASK_OF_KNOWLEDGE.clone();
@ -44,10 +46,8 @@ public class KnowledgeFlask extends SimpleSlimefunItem<ItemUseHandler> {
p.getWorld().dropItemNaturally(p.getLocation(), item);
}
p.playSound(p.getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1F, 0.5F);
SoundEffect.FLASK_OF_KNOWLEDGE_FILLUP_SOUND.playFor(p);
ItemUtils.consumeItem(e.getItem(), false);
e.cancel();
}
};
}

View File

@ -3,9 +3,11 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.magical;
import java.util.List;
import java.util.UUID;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.ChatColor;
import org.bukkit.GameMode;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.event.Event.Result;
import org.bukkit.inventory.ItemStack;
@ -19,17 +21,26 @@ import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.api.researches.Research;
import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
/**
* The {@link KnowledgeTome} allows you to copy every unlocked {@link Research}
* from one {@link Player} to another.
*
* @author TheBusyBiscuit
*
*/
public class KnowledgeTome extends SimpleSlimefunItem<ItemUseHandler> {
@ParametersAreNonnullByDefault
public KnowledgeTome(ItemGroup itemGroup, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
super(itemGroup, item, recipeType, recipe);
}
@Override
public ItemUseHandler getItemHandler() {
public @Nonnull ItemUseHandler getItemHandler() {
return e -> {
Player p = e.getPlayer();
ItemStack item = e.getItem();
@ -44,7 +55,7 @@ public class KnowledgeTome extends SimpleSlimefunItem<ItemUseHandler> {
lore.set(1, ChatColor.BLACK + "" + p.getUniqueId());
im.setLore(lore);
item.setItemMeta(im);
p.getWorld().playSound(p.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1F, 1F);
SoundEffect.TOME_OF_KNOWLEDGE_USE_SOUND.playFor(p);
} else {
UUID uuid = UUID.fromString(ChatColor.stripColor(item.getItemMeta().getLore().get(1)));
@ -65,5 +76,4 @@ public class KnowledgeTome extends SimpleSlimefunItem<ItemUseHandler> {
}
};
}
}

View File

@ -3,7 +3,6 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.magical;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Sound;
import org.bukkit.entity.EnderPearl;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
@ -13,6 +12,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
@ -32,7 +32,7 @@ public class MagicEyeOfEnder extends SimpleSlimefunItem<ItemUseHandler> {
}
@Override
public ItemUseHandler getItemHandler() {
public @Nonnull ItemUseHandler getItemHandler() {
return e -> {
e.cancel();
@ -40,14 +40,14 @@ public class MagicEyeOfEnder extends SimpleSlimefunItem<ItemUseHandler> {
if (hasArmor(p.getInventory())) {
p.launchProjectile(EnderPearl.class);
p.getWorld().playSound(p.getLocation(), Sound.ENTITY_ENDERMAN_TELEPORT, 1, 1);
SoundEffect.MAGICAL_EYE_OF_ENDER_USE_SOUND.playFor(p);
}
};
}
private boolean hasArmor(@Nonnull PlayerInventory inv) {
// @formatter:off
return SlimefunUtils.isItemSimilar(inv.getHelmet(), SlimefunItems.ENDER_HELMET, true)
return SlimefunUtils.isItemSimilar(inv.getHelmet(), SlimefunItems.ENDER_HELMET, true)
&& SlimefunUtils.isItemSimilar(inv.getChestplate(), SlimefunItems.ENDER_CHESTPLATE, true)
&& SlimefunUtils.isItemSimilar(inv.getLeggings(), SlimefunItems.ENDER_LEGGINGS, true)
&& SlimefunUtils.isItemSimilar(inv.getBoots(), SlimefunItems.ENDER_BOOTS, true);

View File

@ -46,7 +46,7 @@ public class MagicalZombiePills extends SimpleSlimefunItem<EntityInteractHandler
}
@Override
public EntityInteractHandler getItemHandler() {
public @Nonnull EntityInteractHandler getItemHandler() {
return (e, item, offhand) -> {
Entity entity = e.getRightClicked();
@ -81,6 +81,7 @@ public class MagicalZombiePills extends SimpleSlimefunItem<EntityInteractHandler
ItemUtils.consumeItem(item, false);
}
// This is supposed to be a vanilla sound. No need for a SoundEffect
p.playSound(p.getLocation(), Sound.ENTITY_ZOMBIE_VILLAGER_CONVERTED, 1, 1);
}

View File

@ -15,7 +15,7 @@ import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Particle;
import org.bukkit.Sound;
import org.bukkit.SoundCategory;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Item;
@ -27,6 +27,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.handlers.ItemDropHandler;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
@ -140,7 +141,7 @@ public class EnchantmentRune extends SimpleSlimefunItem<ItemDropHandler> {
if (rune.isValid() && item.isValid() && itemStack.getAmount() == 1) {
l.getWorld().spawnParticle(Particle.CRIT_MAGIC, l, 1);
l.getWorld().playSound(l, Sound.ENTITY_ZOMBIE_VILLAGER_CURE, 1F, 1F);
SoundEffect.ENCHANTMENT_RUNE_ADD_ENCHANT_SOUND.playAt(l, SoundCategory.PLAYERS);
item.remove();
rune.remove();

View File

@ -7,7 +7,7 @@ import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Location;
import org.bukkit.Sound;
import org.bukkit.SoundCategory;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Item;
import org.bukkit.entity.Player;
@ -19,6 +19,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.attributes.Soulbound;
import io.github.thebusybiscuit.slimefun4.core.handlers.ItemDropHandler;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import io.github.thebusybiscuit.slimefun4.implementation.items.magical.SoulboundItem;
@ -46,7 +47,7 @@ public class SoulboundRune extends SimpleSlimefunItem<ItemDropHandler> {
}
@Override
public ItemDropHandler getItemHandler() {
public @Nonnull ItemDropHandler getItemHandler() {
return (e, p, item) -> {
if (isItem(item.getItemStack())) {
@ -85,7 +86,7 @@ public class SoulboundRune extends SimpleSlimefunItem<ItemDropHandler> {
if (rune.isValid() && item.isValid() && itemStack.getAmount() == 1) {
l.getWorld().createExplosion(l, 0);
l.getWorld().playSound(l, Sound.ENTITY_GENERIC_EXPLODE, 0.3F, 1);
SoundEffect.SOULBOUND_RUNE_RITUAL_SOUND.playAt(l, SoundCategory.PLAYERS);
item.remove();
rune.remove();
@ -115,13 +116,10 @@ public class SoulboundRune extends SimpleSlimefunItem<ItemDropHandler> {
* @return Whether this {@link Entity} is compatible
*/
private boolean findCompatibleItem(@Nonnull Entity entity) {
if (entity instanceof Item) {
Item item = (Item) entity;
return !SlimefunUtils.isSoulbound(item.getItemStack()) && !isItem(item.getItemStack());
if (entity instanceof Item item) {
return item.getPickupDelay() <= 0 && !SlimefunUtils.isSoulbound(item.getItemStack()) && !isItem(item.getItemStack());
}
return false;
}
}

View File

@ -2,11 +2,12 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.magical.runes;
import java.util.concurrent.ThreadLocalRandom;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.GameMode;
import org.bukkit.Particle;
import org.bukkit.Sound;
import org.bukkit.SoundCategory;
import org.bukkit.entity.Villager;
import org.bukkit.entity.Villager.Profession;
import org.bukkit.inventory.ItemStack;
@ -18,6 +19,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.handlers.EntityInteractHandler;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
@ -36,7 +38,7 @@ public class VillagerRune extends SimpleSlimefunItem<EntityInteractHandler> {
}
@Override
public EntityInteractHandler getItemHandler() {
public @Nonnull EntityInteractHandler getItemHandler() {
return (e, item, offhand) -> {
if (e.isCancelled() || !Slimefun.getProtectionManager().hasPermission(e.getPlayer(), e.getRightClicked().getLocation(), Interaction.INTERACT_ENTITY)) {
// They don't have permission to use it in this area
@ -60,7 +62,7 @@ public class VillagerRune extends SimpleSlimefunItem<EntityInteractHandler> {
double offset = ThreadLocalRandom.current().nextDouble(0.5);
villager.getWorld().playSound(villager.getLocation(), Sound.ENTITY_VILLAGER_CELEBRATE, 1, 1.4F);
SoundEffect.VILLAGER_RUNE_TRANSFORM_SOUND.playAt(villager.getLocation(), SoundCategory.NEUTRAL);
villager.getWorld().spawnParticle(Particle.CRIMSON_SPORE, villager.getLocation(), 10, 0, offset / 2, 0, 0);
villager.getWorld().spawnParticle(Particle.ENCHANTMENT_TABLE, villager.getLocation(), 5, 0.04, 1, 0.04);
}

View File

@ -1,11 +1,11 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.magical.staves;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Bukkit;
import org.bukkit.Effect;
import org.bukkit.GameMode;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.FoodLevelChangeEvent;
import org.bukkit.inventory.ItemStack;
@ -16,6 +16,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.items.settings.IntRangeSetting;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
@ -37,7 +38,7 @@ public class WindStaff extends SimpleSlimefunItem<ItemUseHandler> {
}
@Override
public ItemUseHandler getItemHandler() {
public @Nonnull ItemUseHandler getItemHandler() {
return e -> {
Player p = e.getPlayer();
@ -53,7 +54,7 @@ public class WindStaff extends SimpleSlimefunItem<ItemUseHandler> {
}
p.setVelocity(p.getEyeLocation().getDirection().multiply(multiplier.getValue()));
p.getWorld().playSound(p.getLocation(), Sound.ENTITY_TNT_PRIMED, 1, 1);
SoundEffect.WIND_STAFF_USE_SOUND.playFor(p);
p.getWorld().playEffect(p.getLocation(), Effect.SMOKE, 1);
p.setFallDistance(0F);
} else {
@ -61,5 +62,4 @@ public class WindStaff extends SimpleSlimefunItem<ItemUseHandler> {
}
};
}
}

View File

@ -8,6 +8,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.handlers.ItemConsumptionHandler;
import io.github.thebusybiscuit.slimefun4.utils.RadiationUtils;
public class Medicine extends MedicalSupply<ItemConsumptionHandler> {
@ -21,6 +22,7 @@ public class Medicine extends MedicalSupply<ItemConsumptionHandler> {
return (e, p, item) -> {
p.setFireTicks(0);
clearNegativeEffects(p);
RadiationUtils.clearExposure(p);
heal(p);
};
}

View File

@ -1,9 +1,9 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.medical;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.GameMode;
import org.bukkit.Sound;
import org.bukkit.attribute.Attribute;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
@ -15,6 +15,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
public class Splint extends SimpleSlimefunItem<ItemUseHandler> {
@ -25,7 +26,7 @@ public class Splint extends SimpleSlimefunItem<ItemUseHandler> {
}
@Override
public ItemUseHandler getItemHandler() {
public @Nonnull ItemUseHandler getItemHandler() {
return e -> {
Player p = e.getPlayer();
@ -38,11 +39,10 @@ public class Splint extends SimpleSlimefunItem<ItemUseHandler> {
ItemUtils.consumeItem(e.getItem(), false);
}
p.getWorld().playSound(p.getLocation(), Sound.ENTITY_SKELETON_HURT, 1, 1);
SoundEffect.SPLINT_CONSUME_SOUND.playFor(p);
p.addPotionEffect(new PotionEffect(PotionEffectType.HEAL, 1, 0));
e.cancel();
};
}
}

View File

@ -1,9 +1,9 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.medical;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.GameMode;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
@ -12,6 +12,8 @@ import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
import io.github.thebusybiscuit.slimefun4.utils.RadiationUtils;
public class Vitamins extends MedicalSupply<ItemUseHandler> {
@ -21,10 +23,10 @@ public class Vitamins extends MedicalSupply<ItemUseHandler> {
}
@Override
public ItemUseHandler getItemHandler() {
public @Nonnull ItemUseHandler getItemHandler() {
return e -> {
Player p = e.getPlayer();
p.getWorld().playSound(p.getLocation(), Sound.ENTITY_GENERIC_EAT, 1, 1);
SoundEffect.VITAMINS_CONSUME_SOUND.playFor(p);
if (p.getGameMode() != GameMode.CREATIVE) {
ItemUtils.consumeItem(e.getItem(), false);
@ -33,8 +35,8 @@ public class Vitamins extends MedicalSupply<ItemUseHandler> {
e.cancel();
p.setFireTicks(0);
clearNegativeEffects(p);
RadiationUtils.clearExposure(p);
heal(p);
};
}
}

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