mirror of
https://github.com/StarWishsama/Slimefun4.git
synced 2024-09-20 03:35:51 +00:00
Merge branch 'master' into master
This commit is contained in:
commit
4019b9612d
14
.github/CODEOWNERS
vendored
14
.github/CODEOWNERS
vendored
@ -1,7 +1,13 @@
|
||||
# Modifications to the source code should be handled by the review team
|
||||
*.java @Slimefun/code-reviewers
|
||||
*.java @Slimefun/code-reviewers
|
||||
|
||||
# Modifications to sensitive files should be reviewed by maintainers
|
||||
/.github/ @Slimefun/slimefun4-maintainers
|
||||
pom.xml @Slimefun/slimefun4-maintainers
|
||||
CONTRIBUTING.md @Slimefun/slimefun4-maintainers
|
||||
/.github/ @Slimefun/slimefun4-maintainers
|
||||
pom.xml @Slimefun/slimefun4-maintainers
|
||||
CONTRIBUTING.md @Slimefun/slimefun4-maintainers
|
||||
|
||||
# Changes to the Issue templates need to be checked by the triage team
|
||||
/.github/ISSUE_TEMPLATE/ @Slimefun/bug-testers
|
||||
|
||||
# This file is handled by TheBusyBiscuit (admins have overwrite access anyway)
|
||||
/.github/CODEOWNERS @TheBusyBiscuit
|
||||
|
5
.github/ISSUE_TEMPLATE/bug-report.md
vendored
5
.github/ISSUE_TEMPLATE/bug-report.md
vendored
@ -2,7 +2,7 @@
|
||||
name: Bug Report
|
||||
about: Report a Bug or an Issue with Slimefun 4.
|
||||
title: ''
|
||||
labels: '🐞 Bug Report'
|
||||
labels: "\U0001F3AF Needs testing, \U0001F41E Bug Report"
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
@ -42,7 +42,7 @@ assignees: ''
|
||||
|
||||
|
||||
## :compass: Environment (REQUIRED)
|
||||
<!-- Any info without the exact version numbers will be closed! -->
|
||||
<!-- Any issue without the exact version numbers will be closed! -->
|
||||
<!-- "latest" IS NOT A VERSION NUMBER. -->
|
||||
<!-- We recommend running "/sf versions" and showing us a screenshot of that. -->
|
||||
<!-- Make sure that the screenshot covers the entire output of that command. -->
|
||||
@ -51,4 +51,3 @@ assignees: ''
|
||||
- Server Software:
|
||||
- Minecraft Version:
|
||||
- Slimefun Version:
|
||||
- CS-CoreLib Version:
|
||||
|
3
.github/TRIAGE_WORKFLOW.svg
vendored
Normal file
3
.github/TRIAGE_WORKFLOW.svg
vendored
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 41 KiB |
23
.github/workflows/url-checker.yml
vendored
23
.github/workflows/url-checker.yml
vendored
@ -1,23 +0,0 @@
|
||||
name: URL Validator
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
check:
|
||||
|
||||
name: URL Checker
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: URL-checker
|
||||
uses: SuperKogito/URLs-checker@0.2.1
|
||||
with:
|
||||
git_path: https://github.com/Slimefun/Slimefun4
|
||||
file_types: .md,.java,.yml
|
||||
print_all: false
|
||||
retry_count: 2
|
||||
## These URLs will always be correct, even if their services may be offline right now
|
||||
white_listed_patterns: http://textures.minecraft.net/texture/,https://pastebin.com/,https://www.spigotmc.org/threads/spigot-bungeecord-1-16-1.447405/#post-3852349,https://gitlocalize.com/repo/3841
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -4,10 +4,12 @@
|
||||
/sonar/
|
||||
/.settings/
|
||||
/.idea/
|
||||
/.vscode/
|
||||
|
||||
dependency-reduced-pom.xml
|
||||
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
*.iml
|
||||
.DS_Store
|
38
CHANGELOG.md
38
CHANGELOG.md
@ -2,7 +2,7 @@
|
||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
**Table of contents**
|
||||
|
||||
- [Release Candidate 19 (TBD)](#release-candidate-19-tbd)
|
||||
- [Release Candidate 19 (11 Jan 2021)](#release-candidate-19-11-jan-2021)
|
||||
- [Release Candidate 18 (03 Dec 2020)](#release-candidate-18-03-dec-2020)
|
||||
- [Release Candidate 17 (17 Oct 2020)](#release-candidate-17-17-oct-2020)
|
||||
- [Release Candidate 16 (07 Sep 2020)](#release-candidate-16-07-sep-2020)
|
||||
@ -24,14 +24,46 @@
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
|
||||
## Release Candidate 19 (TBD)
|
||||
## Release Candidate 20 (TBD)
|
||||
|
||||
#### Additions
|
||||
* Added a new language: Bulgarian
|
||||
* Added a new language: Hebrew
|
||||
* (API) Added AsyncProfileLoadEvent
|
||||
* Added Talisman of the Wise
|
||||
|
||||
#### Changes
|
||||
* Massive performance improvements to holograms/armorstands
|
||||
* Slimefun no longer requires CS-CoreLib to be installed
|
||||
|
||||
#### Fixes
|
||||
* Fixed elevator floor order
|
||||
* Fixed #2449
|
||||
* Fixed #2511
|
||||
* Fixed #2636
|
||||
* Fixed a threading issue related to BlockStates and persistent data
|
||||
* Fixed an error when the server was shutting down
|
||||
* Fixed #2721
|
||||
* Fixed #2662
|
||||
* Fixed #2728
|
||||
* Fixed some backpack opening issues
|
||||
* Fixed Infused Hopper picking up items with a max pickup delay
|
||||
* Fixed duplication issues related to holograms/armorstands
|
||||
* Fixed #2754
|
||||
|
||||
## Release Candidate 19 (11 Jan 2021)
|
||||
|
||||
#### Additions
|
||||
* Added Bee Armor (1.15+ only)
|
||||
* (API) Added AndroidFarmEvent
|
||||
|
||||
#### Changes
|
||||
* Performance optimizations for Cargo networks
|
||||
* Removed an old version of bStats
|
||||
* CraftBukkit is officially no longer supported, Slimefun will now be disabled on old builds of CraftBukkit
|
||||
* Removed the deprecated ItemManipulationAPI for BlockMenus
|
||||
* Removed the "Written Book" variant of the Slimefun Guide
|
||||
* The Elevator has an Inventory menu now
|
||||
|
||||
#### Fixes
|
||||
* Fixed a couple of compatibility issues with ItemsAdder
|
||||
@ -41,6 +73,8 @@
|
||||
* Fixed #2647
|
||||
* Fixed #2664
|
||||
* Fixed #2655
|
||||
* Fixed /sf timings --verbose not working correctly
|
||||
* Fixed #2675
|
||||
|
||||
## Release Candidate 18 (03 Dec 2020)
|
||||
|
||||
|
50
pom.xml
50
pom.xml
@ -9,10 +9,11 @@
|
||||
|
||||
<!-- Our default version will be UNOFFICIAL, this will prevent auto updates -->
|
||||
<!-- from overriding our local test file -->
|
||||
<version>4.8-UNOFFICIAL</version>
|
||||
<version>4.9-UNOFFICIAL</version>
|
||||
<inceptionYear>2013</inceptionYear>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<!-- Project Info -->
|
||||
<description>Slimefun is a Spigot/Paper plugin that simulates a modpack-like atmosphere by adding over 500 new items and recipes to your Minecraft Server.</description>
|
||||
<url>https://github.com/Slimefun/Slimefun4</url>
|
||||
|
||||
@ -22,7 +23,7 @@
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
|
||||
<!-- Spigot properties -->
|
||||
<spigot.version>1.16.4</spigot.version>
|
||||
<spigot.version>1.16.5</spigot.version>
|
||||
<spigot.javadocs>https://hub.spigotmc.org/javadocs/spigot/</spigot.javadocs>
|
||||
|
||||
<!-- Default settings for sonarcloud.io -->
|
||||
@ -33,11 +34,13 @@
|
||||
<sonar.coverage.jacoco.xmlReportPaths>target/site/jacoco/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>
|
||||
</properties>
|
||||
|
||||
<!-- Bug Tracker -->
|
||||
<issueManagement>
|
||||
<system>GitHub Issues</system>
|
||||
<url>https://github.com/Slimefun/Slimefun4/issues</url>
|
||||
</issueManagement>
|
||||
|
||||
<!-- License -->
|
||||
<licenses>
|
||||
<license>
|
||||
<name>GNU General Public License v3.0</name>
|
||||
@ -46,6 +49,7 @@
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<!-- The repositories which host our dependencies -->
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spigot-repo</id>
|
||||
@ -77,11 +81,13 @@
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<!-- Build settings -->
|
||||
<build>
|
||||
<sourceDirectory>${project.basedir}/src/main/java</sourceDirectory>
|
||||
<testSourceDirectory>${project.basedir}/src/test/java</testSourceDirectory>
|
||||
<defaultGoal>clean package</defaultGoal>
|
||||
|
||||
<!-- The name of the final jar -->
|
||||
<finalName>${project.name} v${project.version}</finalName>
|
||||
|
||||
<plugins>
|
||||
@ -104,6 +110,7 @@
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>3.2.1</version>
|
||||
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-sources</id>
|
||||
@ -119,13 +126,18 @@
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>3.0.0-M5</version>
|
||||
|
||||
<configuration>
|
||||
<junitArtifactName>org.junit.jupiter:junit-jupiter</junitArtifactName>
|
||||
<trimStackTrace>false</trimStackTrace>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<!-- Sonarcloud Scanner -->
|
||||
<plugin>
|
||||
<groupId>org.sonarsource.scanner.maven</groupId>
|
||||
<artifactId>sonar-maven-plugin</artifactId>
|
||||
<version>3.7.0.1746</version>
|
||||
<version>3.8.0.2131</version>
|
||||
</plugin>
|
||||
|
||||
<!-- Code Coverage Reports -->
|
||||
@ -137,6 +149,7 @@
|
||||
<executions>
|
||||
<execution>
|
||||
<id>prepare</id>
|
||||
|
||||
<goals>
|
||||
<goal>prepare-agent</goal>
|
||||
</goals>
|
||||
@ -145,6 +158,7 @@
|
||||
<execution>
|
||||
<id>report</id>
|
||||
<phase>test</phase>
|
||||
|
||||
<goals>
|
||||
<goal>report</goal>
|
||||
</goals>
|
||||
@ -159,8 +173,7 @@
|
||||
<version>3.2.4</version>
|
||||
|
||||
<configuration>
|
||||
|
||||
<!-- Shade dependencies into the output jar -->
|
||||
<!-- Relocate these to avoid clashes and conflicts -->
|
||||
<relocations>
|
||||
<relocation>
|
||||
<pattern>io.github.thebusybiscuit.cscorelib2</pattern>
|
||||
@ -289,12 +302,6 @@
|
||||
<version>${spigot.version}-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.TheBusyBiscuit</groupId>
|
||||
<artifactId>CS-CoreLib</artifactId>
|
||||
<version>1.7</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Development dependencies -->
|
||||
<dependency>
|
||||
@ -314,7 +321,7 @@
|
||||
<dependency>
|
||||
<groupId>com.github.seeseemelk</groupId>
|
||||
<artifactId>MockBukkit-v1.16</artifactId>
|
||||
<version>0.20.0</version>
|
||||
<version>0.21.0</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
@ -328,7 +335,7 @@
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>3.6.28</version>
|
||||
<version>3.7.7</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@ -336,7 +343,7 @@
|
||||
<dependency>
|
||||
<groupId>com.github.TheBusyBiscuit</groupId>
|
||||
<artifactId>CS-CoreLib2</artifactId>
|
||||
<version>0.27.4</version>
|
||||
<version>0.29.6</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@ -348,7 +355,7 @@
|
||||
<dependency>
|
||||
<groupId>com.konghq</groupId>
|
||||
<artifactId>unirest-java</artifactId>
|
||||
<version>3.11.09</version>
|
||||
<version>3.11.10</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
@ -362,7 +369,7 @@
|
||||
<dependency>
|
||||
<groupId>com.sk89q.worldedit</groupId>
|
||||
<artifactId>worldedit-bukkit</artifactId>
|
||||
<version>7.2.0</version>
|
||||
<version>7.2.2</version>
|
||||
<scope>provided</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
@ -380,7 +387,7 @@
|
||||
<dependency>
|
||||
<groupId>com.gmail.nossr50.mcMMO</groupId>
|
||||
<artifactId>mcMMO</artifactId>
|
||||
<version>2.1.167</version>
|
||||
<version>2.1.172</version>
|
||||
<scope>provided</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
@ -397,6 +404,13 @@
|
||||
<groupId>com.sk89q.worldguard</groupId>
|
||||
<artifactId>worldguard-legacy</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<!-- We do not want to use the wrong TextComponents by -->
|
||||
<!-- accident. If we use adventure, then we will add -->
|
||||
<!-- it ourselves. -->
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>*</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@ -422,7 +436,7 @@
|
||||
<dependency>
|
||||
<groupId>com.github.LoneDev6</groupId>
|
||||
<artifactId>itemsadder-api</artifactId>
|
||||
<version>0.1.2</version>
|
||||
<version>2.1.25</version>
|
||||
<scope>provided</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
|
@ -35,6 +35,9 @@ import me.mrCookieSlime.Slimefun.api.BlockStorage;
|
||||
* an {@link ErrorReport} instead.
|
||||
* Error reports get saved in the plugin folder.
|
||||
*
|
||||
* @param <T>
|
||||
* The type of {@link Throwable} which has spawned this {@link ErrorReport}
|
||||
*
|
||||
* @author TheBusyBiscuit
|
||||
*
|
||||
*/
|
||||
@ -146,7 +149,6 @@ public class ErrorReport<T extends Throwable> {
|
||||
stream.println();
|
||||
|
||||
stream.println("Slimefun Environment:");
|
||||
stream.println(" CS-CoreLib v" + SlimefunPlugin.getCSCoreLibVersion());
|
||||
stream.println(" Slimefun v" + SlimefunPlugin.getVersion());
|
||||
stream.println(" Caused by: " + addon.getName() + " v" + addon.getPluginVersion());
|
||||
stream.println();
|
||||
@ -222,6 +224,16 @@ public class ErrorReport<T extends Throwable> {
|
||||
return newFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* This helper method wraps the given {@link Runnable} into a try-catch block.
|
||||
* When an {@link Exception} occurs, a new {@link ErrorReport} will be generated using
|
||||
* the provided {@link Function}.
|
||||
*
|
||||
* @param function
|
||||
* The {@link Function} to generate a new {@link ErrorReport}
|
||||
* @param runnable
|
||||
* The code to execute
|
||||
*/
|
||||
public static void tryCatch(@Nonnull Function<Exception, ErrorReport<Exception>> function, @Nonnull Runnable runnable) {
|
||||
try {
|
||||
runnable.run();
|
||||
|
@ -6,6 +6,7 @@ import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.Server;
|
||||
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
import io.papermc.lib.PaperLib;
|
||||
|
||||
/**
|
||||
* This enum holds all versions of Minecraft that we currently support.
|
||||
@ -21,19 +22,19 @@ public enum MinecraftVersion {
|
||||
* This constant represents Minecraft (Java Edition) Version 1.14
|
||||
* (The "Village & Pillage" Update)
|
||||
*/
|
||||
MINECRAFT_1_14("1.14.x"),
|
||||
MINECRAFT_1_14(14, "1.14.x"),
|
||||
|
||||
/**
|
||||
* This constant represents Minecraft (Java Edition) Version 1.15
|
||||
* (The "Buzzy Bees" Update)
|
||||
*/
|
||||
MINECRAFT_1_15("1.15.x"),
|
||||
MINECRAFT_1_15(15, "1.15.x"),
|
||||
|
||||
/**
|
||||
* This constant represents Minecraft (Java Edition) Version 1.16
|
||||
* (The "Nether Update")
|
||||
*/
|
||||
MINECRAFT_1_16("1.16.x"),
|
||||
MINECRAFT_1_16(16, "1.16.x"),
|
||||
|
||||
/**
|
||||
* This constant represents an exceptional state in which we were unable
|
||||
@ -47,22 +48,24 @@ public enum MinecraftVersion {
|
||||
*/
|
||||
UNIT_TEST("Unit Test Environment", true);
|
||||
|
||||
public static final MinecraftVersion[] valuesCache = values();
|
||||
|
||||
private final String name;
|
||||
private final boolean virtual;
|
||||
private final String prefix;
|
||||
private final int majorVersion;
|
||||
|
||||
/**
|
||||
* This constructs a new {@link MinecraftVersion} with the given name.
|
||||
* This constructor forces the {@link MinecraftVersion} to be real.
|
||||
* It must be a real version of Minecraft.
|
||||
*
|
||||
* @param majorVersion
|
||||
* The major version of minecraft as an {@link Integer}
|
||||
* @param name
|
||||
* The display name of this {@link MinecraftVersion}
|
||||
*/
|
||||
MinecraftVersion(@Nonnull String name) {
|
||||
this(name, false);
|
||||
MinecraftVersion(int majorVersion, @Nonnull String name) {
|
||||
this.name = name;
|
||||
this.majorVersion = majorVersion;
|
||||
this.virtual = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -77,8 +80,8 @@ public enum MinecraftVersion {
|
||||
*/
|
||||
MinecraftVersion(@Nonnull String name, boolean virtual) {
|
||||
this.name = name;
|
||||
this.majorVersion = 0;
|
||||
this.virtual = virtual;
|
||||
this.prefix = name().replace("MINECRAFT_", "v") + '_';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -105,18 +108,21 @@ public enum MinecraftVersion {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method checks whether the given version matches with this
|
||||
* This tests if the given minecraft version number matches with this
|
||||
* {@link MinecraftVersion}.
|
||||
* <p>
|
||||
* You can obtain the version number by doing {@link PaperLib#getMinecraftVersion()}.
|
||||
* It is equivalent to the "major" version
|
||||
* <p>
|
||||
* Example: {@literal "1.13"} returns {@literal 13}
|
||||
*
|
||||
* @param version
|
||||
* The version to compare
|
||||
* @param minecraftVersion
|
||||
* The {@link Integer} version to match
|
||||
*
|
||||
* @return Whether the version matches with this one
|
||||
* @return Whether this {@link MinecraftVersion} matches the specified version id
|
||||
*/
|
||||
public boolean matches(@Nonnull String version) {
|
||||
Validate.notNull(version, "The input version must not be null!");
|
||||
|
||||
return version.startsWith(prefix);
|
||||
public boolean isMinecraftVersion(int minecraftVersion) {
|
||||
return !isVirtual() && this.majorVersion == minecraftVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,21 +1,15 @@
|
||||
package io.github.thebusybiscuit.slimefun4.api;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Locale;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
import me.mrCookieSlime.Slimefun.Objects.Category;
|
||||
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||
|
||||
/**
|
||||
@ -106,16 +100,4 @@ public interface SlimefunAddon {
|
||||
return description.getDepend().contains(dependency) || description.getSoftDepend().contains(dependency);
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns a {@link Collection} holding every {@link Category} that can be directly
|
||||
* linked to this {@link SlimefunAddon} based on its {@link NamespacedKey}.
|
||||
*
|
||||
* @return A {@link Collection} of every {@link Category} from this addon
|
||||
*/
|
||||
@Nonnull
|
||||
default Collection<Category> getCategories() {
|
||||
String namespace = getJavaPlugin().getName().toLowerCase(Locale.ROOT);
|
||||
return SlimefunPlugin.getRegistry().getCategories().stream().filter(cat -> cat.getKey().getNamespace().equals(namespace)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -46,6 +46,7 @@ public enum SlimefunBranch {
|
||||
|
||||
SlimefunBranch(@Nonnull String name, boolean official) {
|
||||
Validate.notNull(name, "The branch name cannot be null");
|
||||
|
||||
this.name = name;
|
||||
this.official = official;
|
||||
|
||||
|
@ -34,10 +34,10 @@ public class AncientAltarCraftEvent extends PlayerEvent implements Cancellable {
|
||||
private boolean cancelled;
|
||||
|
||||
/**
|
||||
* @param block
|
||||
* The altar {@link Block}
|
||||
* @param output
|
||||
* The {@link ItemStack} that would be dropped by the ritual
|
||||
* @param block
|
||||
* The altar {@link Block}
|
||||
* @param player
|
||||
* The {@link Player} that started the ritual.
|
||||
*/
|
||||
|
@ -0,0 +1,122 @@
|
||||
package io.github.thebusybiscuit.slimefun4.api.events;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.bukkit.block.Block;
|
||||
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.implementation.items.androids.AndroidInstance;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.items.androids.FarmerAndroid;
|
||||
|
||||
/**
|
||||
* This {@link Event} is fired before a {@link FarmerAndroid} harvests a {@link Block}.
|
||||
* If this {@link Event} is cancelled, the {@link Block} will not be harvested.
|
||||
* <p>
|
||||
* The {@link Event} will still be fired for non-harvestable blocks.
|
||||
*
|
||||
* @author TheBusyBiscuit
|
||||
*
|
||||
*/
|
||||
public class AndroidFarmEvent extends Event implements Cancellable {
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
|
||||
private final Block block;
|
||||
private final AndroidInstance android;
|
||||
private final boolean isAdvanced;
|
||||
private ItemStack drop;
|
||||
private boolean cancelled;
|
||||
|
||||
/**
|
||||
* @param block
|
||||
* The harvested {@link Block}
|
||||
* @param android
|
||||
* The {@link AndroidInstance} that triggered this {@link Event}
|
||||
* @param isAdvanced
|
||||
* Whether this is an advanced farming action
|
||||
* @param drop
|
||||
* The item to be dropped or null
|
||||
*/
|
||||
public AndroidFarmEvent(@Nonnull Block block, @Nonnull AndroidInstance android, boolean isAdvanced, @Nullable ItemStack drop) {
|
||||
this.block = block;
|
||||
this.android = android;
|
||||
this.isAdvanced = isAdvanced;
|
||||
this.drop = drop;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the mined {@link Block}
|
||||
*
|
||||
* @return the mined {@link Block}
|
||||
*/
|
||||
@Nonnull
|
||||
public Block getBlock() {
|
||||
return block;
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the harvested item or null.
|
||||
*
|
||||
* @return The harvested item or null
|
||||
*/
|
||||
@Nullable
|
||||
public ItemStack getDrop() {
|
||||
return drop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this was invoked via an advanced farming action
|
||||
*
|
||||
* @return Whether it is advanced
|
||||
*/
|
||||
public boolean isAdvanced() {
|
||||
return isAdvanced;
|
||||
}
|
||||
|
||||
/**
|
||||
* This will set the {@link ItemStack} result.
|
||||
*
|
||||
* @param drop
|
||||
* The result or null
|
||||
*/
|
||||
public void setDrop(@Nullable ItemStack drop) {
|
||||
this.drop = drop;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the {@link AndroidInstance} who
|
||||
* triggered this {@link Event}
|
||||
*
|
||||
* @return the involved {@link AndroidInstance}
|
||||
*/
|
||||
@Nonnull
|
||||
public AndroidInstance getAndroid() {
|
||||
return android;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return cancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancelled(boolean cancel) {
|
||||
cancelled = cancel;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return getHandlerList();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
package io.github.thebusybiscuit.slimefun4.api.events;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
|
||||
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
|
||||
|
||||
/**
|
||||
* This {@link Event} is called when the {@link PlayerProfile} of a {@link Player}
|
||||
* is loaded into memory.
|
||||
* The {@link AsyncProfileLoadEvent} is called asynchronously and can be used to "inject"
|
||||
* a custom {@link PlayerProfile} if necessary.
|
||||
*
|
||||
* @author TheBusyBiscuit
|
||||
*
|
||||
* @see PlayerProfile
|
||||
*
|
||||
*/
|
||||
public class AsyncProfileLoadEvent extends Event {
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
|
||||
private final UUID uniqueId;
|
||||
private PlayerProfile profile;
|
||||
|
||||
public AsyncProfileLoadEvent(@Nonnull PlayerProfile profile) {
|
||||
super(true);
|
||||
|
||||
Validate.notNull(profile, "The Profile cannot be null");
|
||||
|
||||
this.uniqueId = profile.getUUID();
|
||||
this.profile = profile;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public UUID getPlayerUUID() {
|
||||
return uniqueId;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public PlayerProfile getProfile() {
|
||||
return profile;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method can be used to inject your custom {@link PlayerProfile} implementations.
|
||||
* However, the passed {@link PlayerProfile} must have the same {@link UUID} as the original one!
|
||||
*
|
||||
* @param profile
|
||||
* The {@link PlayerProfile}
|
||||
*/
|
||||
public void setProfile(@Nonnull PlayerProfile profile) {
|
||||
Validate.notNull(profile, "The PlayerProfile cannot be null!");
|
||||
Validate.isTrue(profile.getUUID().equals(uniqueId), "Cannot inject a PlayerProfile with a different UUID");
|
||||
|
||||
this.profile = profile;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return getHandlerList();
|
||||
}
|
||||
}
|
@ -3,16 +3,16 @@ package io.github.thebusybiscuit.slimefun4.api.events;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.apache.commons.lang.Validate;
|
||||
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||
|
||||
import io.github.thebusybiscuit.slimefun4.core.researching.Research;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.guide.BookSlimefunGuide;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.guide.ChestSlimefunGuide;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.guide.CheatSheetSlimefunGuide;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.guide.SurvivalSlimefunGuide;
|
||||
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||
|
||||
/**
|
||||
* This {@link Event} is called whenever a {@link Player} clicks to unlock a {@link Research}.
|
||||
@ -21,8 +21,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.guide.CheatSheetSlimefu
|
||||
*
|
||||
* @author uiytt
|
||||
*
|
||||
* @see ChestSlimefunGuide
|
||||
* @see BookSlimefunGuide
|
||||
* @see SurvivalSlimefunGuide
|
||||
*
|
||||
*/
|
||||
public class PlayerPreResearchEvent extends Event implements Cancellable {
|
||||
|
@ -16,7 +16,7 @@ import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import io.github.thebusybiscuit.cscorelib2.data.ComputedOptional;
|
||||
import io.github.thebusybiscuit.cscorelib2.data.TriStateOptional;
|
||||
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||
import me.mrCookieSlime.Slimefun.api.BlockStorage;
|
||||
|
||||
@ -46,8 +46,8 @@ public class PlayerRightClickEvent extends PlayerEvent {
|
||||
private final EquipmentSlot hand;
|
||||
private final BlockFace face;
|
||||
|
||||
private ComputedOptional<SlimefunItem> slimefunItem = ComputedOptional.createNew();
|
||||
private ComputedOptional<SlimefunItem> slimefunBlock = ComputedOptional.createNew();
|
||||
private TriStateOptional<SlimefunItem> slimefunItem = TriStateOptional.createNew();
|
||||
private TriStateOptional<SlimefunItem> slimefunBlock = TriStateOptional.createNew();
|
||||
|
||||
private Result itemResult;
|
||||
private Result blockResult;
|
||||
@ -127,7 +127,7 @@ public class PlayerRightClickEvent extends PlayerEvent {
|
||||
if (itemStack.isPresent()) {
|
||||
slimefunItem.compute(SlimefunItem.getByItem(itemStack.get()));
|
||||
} else {
|
||||
slimefunItem = ComputedOptional.empty();
|
||||
slimefunItem = TriStateOptional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@ -140,7 +140,7 @@ public class PlayerRightClickEvent extends PlayerEvent {
|
||||
if (clickedBlock.isPresent()) {
|
||||
slimefunBlock.compute(BlockStorage.check(clickedBlock.get()));
|
||||
} else {
|
||||
slimefunBlock = ComputedOptional.empty();
|
||||
slimefunBlock = TriStateOptional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ package io.github.thebusybiscuit.slimefun4.api.events;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.Event;
|
||||
@ -27,8 +28,11 @@ public class ResearchUnlockEvent extends Event implements Cancellable {
|
||||
private boolean cancelled;
|
||||
|
||||
public ResearchUnlockEvent(@Nonnull Player p, @Nonnull Research research) {
|
||||
super(!Bukkit.isPrimaryThread());
|
||||
|
||||
Validate.notNull(p, "The Player cannot be null");
|
||||
Validate.notNull(research, "Research cannot be null");
|
||||
|
||||
this.player = p;
|
||||
this.research = research;
|
||||
}
|
||||
|
@ -9,14 +9,14 @@ import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideLayout;
|
||||
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideMode;
|
||||
|
||||
/**
|
||||
* This {@link Event} is called whenever a {@link Player} tries to open the Slimefun Guide book.
|
||||
*
|
||||
* @author Linox
|
||||
*
|
||||
* @see SlimefunGuideLayout
|
||||
* @see SlimefunGuideMode
|
||||
*/
|
||||
public class SlimefunGuideOpenEvent extends Event implements Cancellable {
|
||||
|
||||
@ -24,10 +24,10 @@ public class SlimefunGuideOpenEvent extends Event implements Cancellable {
|
||||
|
||||
private final Player player;
|
||||
private final ItemStack guide;
|
||||
private SlimefunGuideLayout layout;
|
||||
private SlimefunGuideMode layout;
|
||||
private boolean cancelled;
|
||||
|
||||
public SlimefunGuideOpenEvent(@Nonnull Player p, @Nonnull ItemStack guide, @Nonnull SlimefunGuideLayout layout) {
|
||||
public SlimefunGuideOpenEvent(@Nonnull Player p, @Nonnull ItemStack guide, @Nonnull SlimefunGuideMode layout) {
|
||||
Validate.notNull(p, "The Player cannot be null");
|
||||
Validate.notNull(guide, "Guide cannot be null");
|
||||
Validate.notNull(layout, "Layout cannot be null");
|
||||
@ -59,23 +59,23 @@ public class SlimefunGuideOpenEvent extends Event implements Cancellable {
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the {@link SlimefunGuideLayout} of the Slimefun Guide
|
||||
* This returns the {@link SlimefunGuideMode} of the Slimefun Guide
|
||||
* that {@link Player} tries to open.
|
||||
*
|
||||
* @return The {@link SlimefunGuideLayout}
|
||||
* @return The {@link SlimefunGuideMode}
|
||||
*/
|
||||
@Nonnull
|
||||
public SlimefunGuideLayout getGuideLayout() {
|
||||
public SlimefunGuideMode getGuideLayout() {
|
||||
return layout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the {@link SlimefunGuideLayout} that was tried to be opened with.
|
||||
* Changes the {@link SlimefunGuideMode} that was tried to be opened with.
|
||||
*
|
||||
* @param layout
|
||||
* The new {@link SlimefunGuideLayout}
|
||||
* The new {@link SlimefunGuideMode}
|
||||
*/
|
||||
public void setGuideLayout(@Nonnull SlimefunGuideLayout layout) {
|
||||
public void setGuideLayout(@Nonnull SlimefunGuideMode layout) {
|
||||
Validate.notNull(layout, "You must specify a layout that is not-null!");
|
||||
this.layout = layout;
|
||||
}
|
||||
|
@ -23,7 +23,6 @@ import org.bukkit.inventory.ItemStack;
|
||||
import io.github.thebusybiscuit.cscorelib2.chat.ChatColors;
|
||||
import io.github.thebusybiscuit.cscorelib2.chat.ChatInput;
|
||||
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
|
||||
import io.github.thebusybiscuit.cscorelib2.math.DoubleHandler;
|
||||
import io.github.thebusybiscuit.slimefun4.api.events.WaypointCreateEvent;
|
||||
import io.github.thebusybiscuit.slimefun4.api.geo.GEOResource;
|
||||
import io.github.thebusybiscuit.slimefun4.api.geo.ResourceManager;
|
||||
@ -34,6 +33,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.gps.GPSTransmitte
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.items.gps.Teleporter;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.HeadTexture;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
|
||||
import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu;
|
||||
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||
import me.mrCookieSlime.Slimefun.api.BlockStorage;
|
||||
@ -56,7 +56,11 @@ public class GPSNetwork {
|
||||
|
||||
private final Map<UUID, Set<Location>> transmitters = new HashMap<>();
|
||||
private final TeleportationManager teleportation = new TeleportationManager();
|
||||
private final ResourceManager resourceManager = new ResourceManager(SlimefunPlugin.instance());
|
||||
private final ResourceManager resourceManager;
|
||||
|
||||
public GPSNetwork(@Nonnull SlimefunPlugin plugin) {
|
||||
resourceManager = new ResourceManager(plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method updates the status of a {@link GPSTransmitter}.
|
||||
@ -89,12 +93,14 @@ public class GPSNetwork {
|
||||
* @return The network complexity for that {@link UUID}
|
||||
*/
|
||||
public int getNetworkComplexity(@Nonnull UUID uuid) {
|
||||
if (!transmitters.containsKey(uuid)) {
|
||||
Set<Location> locations = transmitters.get(uuid);
|
||||
|
||||
if (locations == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int level = 0;
|
||||
for (Location l : transmitters.get(uuid)) {
|
||||
for (Location l : locations) {
|
||||
SlimefunItem item = BlockStorage.check(l);
|
||||
|
||||
if (item instanceof GPSTransmitter) {
|
||||
@ -115,11 +121,8 @@ public class GPSNetwork {
|
||||
* @return The amount of transmitters
|
||||
*/
|
||||
public int countTransmitters(@Nonnull UUID uuid) {
|
||||
if (!transmitters.containsKey(uuid)) {
|
||||
return 0;
|
||||
} else {
|
||||
return transmitters.get(uuid).size();
|
||||
}
|
||||
Set<Location> locations = transmitters.get(uuid);
|
||||
return locations == null ? 0 : locations.size();
|
||||
}
|
||||
|
||||
public void openTransmitterControlPanel(@Nonnull Player p) {
|
||||
@ -157,7 +160,7 @@ public class GPSNetwork {
|
||||
if (sfi instanceof GPSTransmitter) {
|
||||
int slot = inventory[index];
|
||||
|
||||
menu.addItem(slot, new CustomItem(SlimefunItems.GPS_TRANSMITTER, "&bGPS Transmitter", "&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 &7Signal Strength: &f" + ((GPSTransmitter) sfi).getMultiplier(l.getBlockY()), "&8\u21E8 &7Ping: &f" + DoubleHandler.fixDouble(1000D / l.getY()) + "ms"));
|
||||
menu.addItem(slot, new CustomItem(SlimefunItems.GPS_TRANSMITTER, "&bGPS Transmitter", "&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 &7Signal Strength: &f" + ((GPSTransmitter) sfi).getMultiplier(l.getBlockY()), "&8\u21E8 &7Ping: &f" + NumberUtils.roundDecimalNumber(1000D / l.getY()) + "ms"));
|
||||
menu.addMenuClickHandler(slot, ChestMenuUtils.getEmptyClickHandler());
|
||||
|
||||
index++;
|
||||
|
@ -8,6 +8,7 @@ import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Location;
|
||||
@ -20,66 +21,90 @@ import org.bukkit.potion.PotionEffectType;
|
||||
|
||||
import io.github.thebusybiscuit.cscorelib2.chat.ChatColors;
|
||||
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
|
||||
import io.github.thebusybiscuit.cscorelib2.math.DoubleHandler;
|
||||
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.items.gps.Teleporter;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.HeadTexture;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu;
|
||||
|
||||
/**
|
||||
* The {@link TeleportationManager} handles the process of teleportation for a {@link Player}
|
||||
* who is using a {@link Teleporter}.
|
||||
*
|
||||
* @author TheBusyBiscuit
|
||||
*
|
||||
* @see GPSNetwork
|
||||
* @see Teleporter
|
||||
*
|
||||
*/
|
||||
public final class TeleportationManager {
|
||||
|
||||
private final Set<UUID> teleporterUsers = new HashSet<>();
|
||||
private final int[] teleporterBorder = { 0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 26, 27, 35, 36, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53 };
|
||||
private final int[] teleporterInventory = { 19, 20, 21, 22, 23, 24, 25, 28, 29, 30, 31, 32, 33, 34, 37, 38, 39, 40, 41, 42, 43 };
|
||||
|
||||
/**
|
||||
* This {@link Set} holds the {@link UUID} of all Players that are
|
||||
* teleporting right now.
|
||||
*/
|
||||
private final Set<UUID> teleporterUsers = new HashSet<>();
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
public void openTeleporterGUI(Player p, UUID uuid, Block b, int complexity) {
|
||||
if (teleporterUsers.contains(p.getUniqueId())) {
|
||||
return;
|
||||
}
|
||||
if (teleporterUsers.add(p.getUniqueId())) {
|
||||
p.playSound(p.getLocation(), Sound.UI_BUTTON_CLICK, 1F, 1F);
|
||||
|
||||
p.playSound(p.getLocation(), Sound.UI_BUTTON_CLICK, 1F, 1F);
|
||||
teleporterUsers.add(p.getUniqueId());
|
||||
PlayerProfile.fromUUID(uuid, profile -> {
|
||||
ChestMenu menu = new ChestMenu("&3Teleporter");
|
||||
menu.addMenuCloseHandler(pl -> teleporterUsers.remove(pl.getUniqueId()));
|
||||
|
||||
PlayerProfile.fromUUID(uuid, profile -> {
|
||||
ChestMenu menu = new ChestMenu("&3Teleporter");
|
||||
menu.addMenuCloseHandler(pl -> teleporterUsers.remove(pl.getUniqueId()));
|
||||
|
||||
for (int slot : teleporterBorder) {
|
||||
menu.addItem(slot, ChestMenuUtils.getBackground(), ChestMenuUtils.getEmptyClickHandler());
|
||||
}
|
||||
|
||||
menu.addItem(4, new CustomItem(HeadTexture.GLOBE_OVERWORLD.getAsItemStack(), ChatColor.YELLOW + SlimefunPlugin.getLocalization().getMessage(p, "machines.TELEPORTER.gui.title")));
|
||||
menu.addMenuClickHandler(4, ChestMenuUtils.getEmptyClickHandler());
|
||||
|
||||
Location source = new Location(b.getWorld(), b.getX() + 0.5D, b.getY() + 2D, b.getZ() + 0.5D);
|
||||
int index = 0;
|
||||
|
||||
for (Waypoint waypoint : profile.getWaypoints()) {
|
||||
if (index >= teleporterInventory.length) {
|
||||
break;
|
||||
for (int slot : teleporterBorder) {
|
||||
menu.addItem(slot, ChestMenuUtils.getBackground(), ChestMenuUtils.getEmptyClickHandler());
|
||||
}
|
||||
|
||||
int slot = teleporterInventory[index];
|
||||
Location l = waypoint.getLocation();
|
||||
double time = DoubleHandler.fixDouble(0.5 * getTeleportationTime(complexity, source, l));
|
||||
menu.addItem(4, new CustomItem(HeadTexture.GLOBE_OVERWORLD.getAsItemStack(), ChatColor.YELLOW + SlimefunPlugin.getLocalization().getMessage(p, "machines.TELEPORTER.gui.title")));
|
||||
menu.addMenuClickHandler(4, ChestMenuUtils.getEmptyClickHandler());
|
||||
|
||||
String[] lore = { "", "&8\u21E8 &7" + SlimefunPlugin.getLocalization().getResourceString(p, "tooltips.world") + ": &f" + l.getWorld().getName(), "&8\u21E8 &7X: &f" + l.getX(), "&8\u21E8 &7Y: &f" + l.getY(), "&8\u21E8 &7Z: &f" + l.getZ(), "&8\u21E8 &7" + SlimefunPlugin.getLocalization().getMessage(p, "machines.TELEPORTER.gui.time") + ": &f" + time + "s", "", "&8\u21E8 &c" + SlimefunPlugin.getLocalization().getMessage(p, "machines.TELEPORTER.gui.tooltip") };
|
||||
Location source = new Location(b.getWorld(), b.getX() + 0.5D, b.getY() + 2D, b.getZ() + 0.5D);
|
||||
int index = 0;
|
||||
|
||||
menu.addItem(slot, new CustomItem(waypoint.getIcon(), waypoint.getName().replace("player:death ", ""), lore));
|
||||
menu.addMenuClickHandler(slot, (pl, s, item, action) -> {
|
||||
pl.closeInventory();
|
||||
teleport(pl.getUniqueId(), complexity, source, l, false);
|
||||
return false;
|
||||
});
|
||||
for (Waypoint waypoint : profile.getWaypoints()) {
|
||||
if (index >= teleporterInventory.length) {
|
||||
break;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
int slot = teleporterInventory[index];
|
||||
Location l = waypoint.getLocation();
|
||||
double time = NumberUtils.reparseDouble(0.5 * getTeleportationTime(complexity, source, l));
|
||||
|
||||
SlimefunPlugin.runSync(() -> menu.open(p));
|
||||
});
|
||||
// @formatter:off
|
||||
String[] lore = {
|
||||
"",
|
||||
"&8\u21E8 &7" + SlimefunPlugin.getLocalization().getResourceString(p, "tooltips.world") + ": &f" + l.getWorld().getName(),
|
||||
"&8\u21E8 &7X: &f" + l.getX(),
|
||||
"&8\u21E8 &7Y: &f" + l.getY(),
|
||||
"&8\u21E8 &7Z: &f" + l.getZ(),
|
||||
"&8\u21E8 &7" + SlimefunPlugin.getLocalization().getMessage(p, "machines.TELEPORTER.gui.time") + ": &f" + time + "s",
|
||||
"",
|
||||
"&8\u21E8 &c" + SlimefunPlugin.getLocalization().getMessage(p, "machines.TELEPORTER.gui.tooltip")
|
||||
};
|
||||
// @formatter:on
|
||||
|
||||
menu.addItem(slot, new CustomItem(waypoint.getIcon(), waypoint.getName().replace("player:death ", ""), lore));
|
||||
menu.addMenuClickHandler(slot, (pl, s, item, action) -> {
|
||||
pl.closeInventory();
|
||||
teleport(pl.getUniqueId(), complexity, source, l, false);
|
||||
return false;
|
||||
});
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
SlimefunPlugin.runSync(() -> menu.open(p));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
@ -90,8 +115,32 @@ public final class TeleportationManager {
|
||||
updateProgress(uuid, Math.max(1, 100 / time), 0, source, destination, resistance);
|
||||
}
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
public int getTeleportationTime(int complexity, Location source, Location destination) {
|
||||
/**
|
||||
* This returns the amount of time it will take to teleport from the source {@link Location}
|
||||
* to the destination {@link Location}, given the specified complexity.
|
||||
* <p>
|
||||
* The returned time will be measured in 500ms intervals.
|
||||
*
|
||||
* <ul>
|
||||
* <li>A returned time of {@literal 100} will mean 50,000ms (50s) of real-life time.</li>
|
||||
* <li>A returned time of {@literal 10} will mean 5,000ms (5s) of real-life time.</li>
|
||||
* <li>A returned time of {@literal 2} will mean 1,000ms (1s) of real-life time.</li>
|
||||
* <li>and so on...</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param complexity
|
||||
* The complexity of the {@link GPSNetwork}
|
||||
* @param source
|
||||
* The source {@link Location}
|
||||
* @param destination
|
||||
* The destination {@link Location}
|
||||
*
|
||||
* @return The amount of time the teleportation will take
|
||||
*/
|
||||
public int getTeleportationTime(int complexity, @Nonnull Location source, @Nonnull Location destination) {
|
||||
Validate.notNull(source, "Source cannot be null");
|
||||
Validate.notNull(source, "Destination cannot be null");
|
||||
|
||||
if (complexity < 100) {
|
||||
return 100;
|
||||
}
|
||||
@ -145,8 +194,10 @@ public final class TeleportationManager {
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
private void onTeleport(Player p, Location destination, boolean success, boolean resistance) {
|
||||
// This needs to run on the main Thread so we force it, as the
|
||||
// async teleportation might happen on a separate Thread.
|
||||
/*
|
||||
* This needs to run on the main Thread so we force it, as
|
||||
* the async teleportation might happen on a separate Thread.
|
||||
*/
|
||||
SlimefunPlugin.runSync(() -> {
|
||||
if (success) {
|
||||
// Apply Resistance Effect, if enabled
|
||||
@ -161,8 +212,10 @@ public final class TeleportationManager {
|
||||
destination.getWorld().playSound(destination, Sound.BLOCK_BEACON_ACTIVATE, 1F, 1F);
|
||||
teleporterUsers.remove(p.getUniqueId());
|
||||
} else {
|
||||
// Make sure the Player is removed from the actively teleporting users
|
||||
// and notified about the failed teleportation
|
||||
/*
|
||||
* Make sure the Player is removed from the actively teleporting
|
||||
* users and notified about the failed teleportation
|
||||
*/
|
||||
cancel(p.getUniqueId(), p);
|
||||
}
|
||||
});
|
||||
|
@ -1,7 +1,5 @@
|
||||
package io.github.thebusybiscuit.slimefun4.api.items;
|
||||
|
||||
import java.util.logging.Level;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
@ -10,7 +8,6 @@ import org.apache.commons.lang.Validate;
|
||||
import io.github.thebusybiscuit.cscorelib2.config.Config;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||
import me.mrCookieSlime.Slimefun.api.Slimefun;
|
||||
|
||||
/**
|
||||
* This class represents a Setting for a {@link SlimefunItem} that can be modified via
|
||||
@ -93,7 +90,7 @@ public class ItemSetting<T> {
|
||||
*/
|
||||
@Nonnull
|
||||
public T getValue() {
|
||||
Validate.notNull(value, "An ItemSetting was invoked but was not initialized yet.");
|
||||
Validate.notNull(value, "ItemSetting '" + key + "' was invoked but was not initialized yet.");
|
||||
|
||||
return value;
|
||||
}
|
||||
@ -138,6 +135,7 @@ public class ItemSetting<T> {
|
||||
* @param item
|
||||
* The {@link SlimefunItem} who called this method
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void load(@Nonnull SlimefunItem item) {
|
||||
Validate.notNull(item, "Cannot apply settings for a non-existing SlimefunItem");
|
||||
|
||||
@ -145,26 +143,33 @@ public class ItemSetting<T> {
|
||||
Object configuredValue = SlimefunPlugin.getItemCfg().getValue(item.getId() + '.' + getKey());
|
||||
|
||||
if (defaultValue.getClass().isInstance(configuredValue)) {
|
||||
// We can suppress the warning here, we did an isInstance(...) check before!
|
||||
@SuppressWarnings("unchecked")
|
||||
// We can unsafe cast here, we did an isInstance(...) check before!
|
||||
T newValue = (T) configuredValue;
|
||||
|
||||
if (validateInput(newValue)) {
|
||||
this.value = newValue;
|
||||
} else {
|
||||
Slimefun.getLogger().log(Level.WARNING, "Slimefun has found an invalid config setting in your Items.yml!");
|
||||
Slimefun.getLogger().log(Level.WARNING, " at \"{0}.{1}\"", new Object[] { item.getId(), getKey() });
|
||||
Slimefun.getLogger().log(Level.WARNING, "{0} is not a valid input!", configuredValue);
|
||||
Slimefun.getLogger().log(Level.WARNING, getErrorMessage());
|
||||
// @formatter:off
|
||||
item.warn(
|
||||
"We have found an invalid config setting in your Items.yml!" +
|
||||
"\n at \"" + item.getId() + "." + getKey() + "\"" +
|
||||
"\n " + configuredValue + " is not a valid input!" +
|
||||
"\n" + getErrorMessage()
|
||||
);
|
||||
// @formatter:on
|
||||
}
|
||||
} else {
|
||||
this.value = defaultValue;
|
||||
String found = configuredValue == null ? "null" : configuredValue.getClass().getSimpleName();
|
||||
|
||||
Slimefun.getLogger().log(Level.WARNING, "Slimefun has found an invalid config setting in your Items.yml!");
|
||||
Slimefun.getLogger().log(Level.WARNING, "Please only use settings that are valid.");
|
||||
Slimefun.getLogger().log(Level.WARNING, " at \"{0}.{1}\"", new Object[] { item.getId(), getKey() });
|
||||
Slimefun.getLogger().log(Level.WARNING, "Expected \"{0}\" but found: \"{1}\"", new Object[] { defaultValue.getClass().getSimpleName(), found });
|
||||
// @formatter:off
|
||||
item.warn(
|
||||
"We have found an invalid config setting in your Items.yml!" +
|
||||
"\nPlease only use settings that are valid." +
|
||||
"\n at \"" + item.getId() + "." + getKey() + "\"" +
|
||||
"\n Expected \"" + defaultValue.getClass().getSimpleName() + "\" but found: \"" + found + "\""
|
||||
);
|
||||
// @formatter:on
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,9 @@ import io.github.thebusybiscuit.slimefun4.api.items.ItemSetting;
|
||||
* This variation of {@link ItemSetting} allows you to allow {@link Enum} constants to be
|
||||
* used for {@link ItemSetting} validation.
|
||||
*
|
||||
* @param <T>
|
||||
* The {@link Enum} type
|
||||
*
|
||||
* @author TheBusyBiscuit
|
||||
*
|
||||
* @see ItemSetting
|
||||
@ -41,6 +44,7 @@ public class EnumSetting<T extends Enum<T>> extends ItemSetting<String> {
|
||||
*
|
||||
* @return An array of allowed {@link Enum} constants
|
||||
*/
|
||||
@Nonnull
|
||||
public T[] getAllowedValues() {
|
||||
return enumClass.getEnumConstants();
|
||||
}
|
||||
@ -50,6 +54,7 @@ public class EnumSetting<T extends Enum<T>> extends ItemSetting<String> {
|
||||
*
|
||||
* @return The value as an {@link Enum} constant
|
||||
*/
|
||||
@Nonnull
|
||||
public T getAsEnumConstant() {
|
||||
return Enum.valueOf(enumClass, getValue());
|
||||
}
|
||||
|
@ -27,10 +27,17 @@ import io.github.thebusybiscuit.slimefun4.implementation.listeners.NetworkListen
|
||||
*/
|
||||
public abstract class Network {
|
||||
|
||||
/**
|
||||
* Our {@link NetworkManager} instance.
|
||||
*/
|
||||
private final NetworkManager manager;
|
||||
protected Location regulator;
|
||||
private final Queue<Location> nodeQueue = new ArrayDeque<>();
|
||||
|
||||
/**
|
||||
* The {@link Location} of the regulator of this {@link Network}.
|
||||
*/
|
||||
protected Location regulator;
|
||||
|
||||
private final Queue<Location> nodeQueue = new ArrayDeque<>();
|
||||
protected final Set<Location> connectedLocations = new HashSet<>();
|
||||
protected final Set<Location> regulatorNodes = new HashSet<>();
|
||||
protected final Set<Location> connectorNodes = new HashSet<>();
|
||||
@ -231,6 +238,10 @@ public abstract class Network {
|
||||
return regulator;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method updates this {@link Network} and serves as the starting point
|
||||
* for any running operations.
|
||||
*/
|
||||
public void tick() {
|
||||
discoverStep();
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
package io.github.thebusybiscuit.slimefun4.api.player;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
@ -33,6 +32,7 @@ import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import io.github.thebusybiscuit.cscorelib2.chat.ChatColors;
|
||||
import io.github.thebusybiscuit.cscorelib2.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.core.attributes.ProtectionType;
|
||||
@ -43,7 +43,6 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.items.armor.SlimefunArmorPiece;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.PatternUtils;
|
||||
import me.mrCookieSlime.Slimefun.api.Slimefun;
|
||||
|
||||
/**
|
||||
* A class that can store a Player's {@link Research} progress for caching purposes.
|
||||
@ -57,7 +56,7 @@ import me.mrCookieSlime.Slimefun.api.Slimefun;
|
||||
* @see HashedArmorpiece
|
||||
*
|
||||
*/
|
||||
public final class PlayerProfile {
|
||||
public class PlayerProfile {
|
||||
|
||||
private final UUID uuid;
|
||||
private final String name;
|
||||
@ -75,13 +74,17 @@ public final class PlayerProfile {
|
||||
|
||||
private final HashedArmorpiece[] armor = { new HashedArmorpiece(), new HashedArmorpiece(), new HashedArmorpiece(), new HashedArmorpiece() };
|
||||
|
||||
private PlayerProfile(@Nonnull OfflinePlayer p) {
|
||||
protected PlayerProfile(@Nonnull OfflinePlayer p) {
|
||||
this.uuid = p.getUniqueId();
|
||||
this.name = p.getName();
|
||||
|
||||
configFile = new Config(new File("data-storage/Slimefun/Players/" + uuid.toString() + ".yml"));
|
||||
configFile = new Config("data-storage/Slimefun/Players/" + uuid.toString() + ".yml");
|
||||
waypointsFile = new Config("data-storage/Slimefun/waypoints/" + uuid.toString() + ".yml");
|
||||
|
||||
loadProfileData();
|
||||
}
|
||||
|
||||
private void loadProfileData() {
|
||||
for (Research research : SlimefunPlugin.getRegistry().getResearches()) {
|
||||
if (configFile.contains("researches." + research.getID())) {
|
||||
researches.add(research);
|
||||
@ -96,7 +99,7 @@ public final class PlayerProfile {
|
||||
waypoints.add(new Waypoint(this, key, loc, waypointName));
|
||||
}
|
||||
} catch (Exception x) {
|
||||
Slimefun.getLogger().log(Level.WARNING, x, () -> "Could not load Waypoint \"" + key + "\" for Player \"" + p.getName() + '"');
|
||||
SlimefunPlugin.logger().log(Level.WARNING, x, () -> "Could not load Waypoint \"" + key + "\" for Player \"" + name + '"');
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -269,14 +272,14 @@ public final class PlayerProfile {
|
||||
* Call this method if the Player has left.
|
||||
* The profile can then be removed from RAM.
|
||||
*/
|
||||
public void markForDeletion() {
|
||||
public final void markForDeletion() {
|
||||
markedForDeletion = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this method if this Profile has unsaved changes.
|
||||
*/
|
||||
public void markDirty() {
|
||||
public final void markDirty() {
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
@ -383,9 +386,11 @@ public final class PlayerProfile {
|
||||
}
|
||||
|
||||
Bukkit.getScheduler().runTaskAsynchronously(SlimefunPlugin.instance(), () -> {
|
||||
PlayerProfile pp = new PlayerProfile(p);
|
||||
SlimefunPlugin.getRegistry().getPlayerProfiles().put(uuid, pp);
|
||||
callback.accept(pp);
|
||||
AsyncProfileLoadEvent event = new AsyncProfileLoadEvent(new PlayerProfile(p));
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
|
||||
SlimefunPlugin.getRegistry().getPlayerProfiles().put(uuid, event.getProfile());
|
||||
callback.accept(event.getProfile());
|
||||
});
|
||||
|
||||
return false;
|
||||
@ -457,9 +462,9 @@ public final class PlayerProfile {
|
||||
|
||||
if (id.isPresent()) {
|
||||
int number = id.getAsInt();
|
||||
|
||||
fromUUID(UUID.fromString(uuid), profile -> {
|
||||
Optional<PlayerBackpack> backpack = profile.getBackpack(number);
|
||||
|
||||
backpack.ifPresent(callback);
|
||||
});
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package io.github.thebusybiscuit.slimefun4.core;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
@ -14,23 +15,26 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Piglin;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import io.github.thebusybiscuit.cscorelib2.collections.KeyMap;
|
||||
import io.github.thebusybiscuit.cscorelib2.config.Config;
|
||||
import io.github.thebusybiscuit.slimefun4.api.geo.GEOResource;
|
||||
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
|
||||
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuide;
|
||||
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideImplementation;
|
||||
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideLayout;
|
||||
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideMode;
|
||||
import io.github.thebusybiscuit.slimefun4.core.multiblocks.MultiBlock;
|
||||
import io.github.thebusybiscuit.slimefun4.core.researching.Research;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.guide.BookSlimefunGuide;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.guide.CheatSheetSlimefunGuide;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.guide.ChestSlimefunGuide;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.guide.SurvivalSlimefunGuide;
|
||||
import me.mrCookieSlime.Slimefun.Objects.Category;
|
||||
import me.mrCookieSlime.Slimefun.Objects.SlimefunBlockHandler;
|
||||
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||
@ -58,7 +62,7 @@ public final class SlimefunRegistry {
|
||||
|
||||
private final List<Research> researches = new LinkedList<>();
|
||||
private final List<String> researchRanks = new ArrayList<>();
|
||||
private final Set<UUID> researchingPlayers = new HashSet<>();
|
||||
private final Set<UUID> researchingPlayers = Collections.synchronizedSet(new HashSet<>());
|
||||
|
||||
private boolean backwardsCompatibility;
|
||||
private boolean automaticallyLoadItems;
|
||||
@ -71,12 +75,16 @@ public final class SlimefunRegistry {
|
||||
private final Set<SlimefunItem> radioactive = new HashSet<>();
|
||||
private final Set<ItemStack> barterDrops = new HashSet<>();
|
||||
|
||||
private NamespacedKey soulboundKey;
|
||||
private NamespacedKey itemChargeKey;
|
||||
private NamespacedKey guideKey;
|
||||
|
||||
private final KeyMap<GEOResource> geoResources = new KeyMap<>();
|
||||
|
||||
private final Map<UUID, PlayerProfile> profiles = new ConcurrentHashMap<>();
|
||||
private final Map<String, BlockStorage> worlds = new ConcurrentHashMap<>();
|
||||
private final Map<String, BlockInfoConfig> chunks = new HashMap<>();
|
||||
private final Map<SlimefunGuideLayout, SlimefunGuideImplementation> layouts = new EnumMap<>(SlimefunGuideLayout.class);
|
||||
private final Map<SlimefunGuideMode, SlimefunGuideImplementation> guides = new EnumMap<>(SlimefunGuideMode.class);
|
||||
private final Map<EntityType, Set<ItemStack>> mobDrops = new EnumMap<>(EntityType.class);
|
||||
|
||||
private final Map<String, BlockMenuPreset> blockMenuPresets = new HashMap<>();
|
||||
@ -84,14 +92,17 @@ public final class SlimefunRegistry {
|
||||
private final Map<Class<? extends ItemHandler>, Set<ItemHandler>> globalItemHandlers = new HashMap<>();
|
||||
private final Map<String, SlimefunBlockHandler> blockHandlers = new HashMap<>();
|
||||
|
||||
public void load(@Nonnull Config cfg) {
|
||||
public void load(@Nonnull SlimefunPlugin plugin, @Nonnull Config cfg) {
|
||||
Validate.notNull(plugin, "The Plugin cannot be null!");
|
||||
Validate.notNull(cfg, "The Config cannot be null!");
|
||||
|
||||
boolean showVanillaRecipes = cfg.getBoolean("guide.show-vanilla-recipes");
|
||||
soulboundKey = new NamespacedKey(plugin, "soulbound");
|
||||
itemChargeKey = new NamespacedKey(plugin, "item_charge");
|
||||
guideKey = new NamespacedKey(plugin, "slimefun_guide_mode");
|
||||
|
||||
layouts.put(SlimefunGuideLayout.CHEST, new ChestSlimefunGuide(showVanillaRecipes));
|
||||
layouts.put(SlimefunGuideLayout.CHEAT_SHEET, new CheatSheetSlimefunGuide());
|
||||
layouts.put(SlimefunGuideLayout.BOOK, new BookSlimefunGuide());
|
||||
boolean showVanillaRecipes = cfg.getBoolean("guide.show-vanilla-recipes");
|
||||
guides.put(SlimefunGuideMode.SURVIVAL_MODE, new SurvivalSlimefunGuide(showVanillaRecipes));
|
||||
guides.put(SlimefunGuideMode.CHEAT_MODE, new CheatSheetSlimefunGuide());
|
||||
|
||||
researchRanks.addAll(cfg.getStringList("research-ranks"));
|
||||
|
||||
@ -124,14 +135,37 @@ public final class SlimefunRegistry {
|
||||
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()}.
|
||||
* Normally this method call is delayed but when the {@link Server} is already running,
|
||||
* the method can be called instantaneously.
|
||||
*
|
||||
* @param mode
|
||||
* Whether auto-loading should be enabled
|
||||
*/
|
||||
public void setAutoLoadingMode(boolean mode) {
|
||||
automaticallyLoadItems = mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns a {@link List} containing every enabled {@link Category}.
|
||||
*
|
||||
* @return {@link List} containing every enabled {@link Category}
|
||||
*/
|
||||
@Nonnull
|
||||
public List<Category> getCategories() {
|
||||
return categories;
|
||||
}
|
||||
@ -141,6 +175,7 @@ public final class SlimefunRegistry {
|
||||
*
|
||||
* @return A {@link List} containing every {@link SlimefunItem}
|
||||
*/
|
||||
@Nonnull
|
||||
public List<SlimefunItem> getAllSlimefunItems() {
|
||||
return slimefunItems;
|
||||
}
|
||||
@ -150,18 +185,34 @@ public final class SlimefunRegistry {
|
||||
*
|
||||
* @return A {@link List} containing every enabled {@link SlimefunItem}
|
||||
*/
|
||||
@Nonnull
|
||||
public List<SlimefunItem> getEnabledSlimefunItems() {
|
||||
return enabledItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns a {@link List} containing every enabled {@link Research}.
|
||||
*
|
||||
* @return A {@link List} containing every enabled {@link Research}
|
||||
*/
|
||||
@Nonnull
|
||||
public List<Research> getResearches() {
|
||||
return researches;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns a {@link Set} containing the {@link UUID} of every
|
||||
* {@link Player} who is currently unlocking a {@link Research}.
|
||||
*
|
||||
* @return A {@link Set} holding the {@link UUID} from every {@link Player}
|
||||
* who is currently unlocking a {@link Research}
|
||||
*/
|
||||
@Nonnull
|
||||
public Set<UUID> getCurrentlyResearchingPlayers() {
|
||||
return researchingPlayers;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<String> getResearchRanks() {
|
||||
return researchRanks;
|
||||
}
|
||||
@ -186,12 +237,40 @@ public final class SlimefunRegistry {
|
||||
return researchFireworks;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns a {@link List} of every enabled {@link MultiBlock}.
|
||||
*
|
||||
* @return A {@link List} containing every enabled {@link MultiBlock}
|
||||
*/
|
||||
@Nonnull
|
||||
public List<MultiBlock> getMultiBlocks() {
|
||||
return multiblocks;
|
||||
}
|
||||
|
||||
public SlimefunGuideImplementation getGuideLayout(SlimefunGuideLayout layout) {
|
||||
return layouts.get(layout);
|
||||
/**
|
||||
* This returns the corresponding {@link SlimefunGuideImplementation} for a certain
|
||||
* {@link SlimefunGuideMode}.
|
||||
* <p>
|
||||
* This mainly only exists for internal purposes, if you want to open a certain section
|
||||
* using the {@link SlimefunGuide}, then please use the static methods provided in the
|
||||
* {@link SlimefunGuide} class.
|
||||
*
|
||||
* @param mode
|
||||
* The {@link SlimefunGuideMode}
|
||||
*
|
||||
* @return The corresponding {@link SlimefunGuideImplementation}
|
||||
*/
|
||||
@Nonnull
|
||||
public SlimefunGuideImplementation getSlimefunGuide(@Nonnull SlimefunGuideMode mode) {
|
||||
Validate.notNull(mode, "The Guide mode cannot be null");
|
||||
|
||||
SlimefunGuideImplementation guide = guides.get(mode);
|
||||
|
||||
if (guide == null) {
|
||||
throw new IllegalStateException("Slimefun Guide '" + mode + "' has no registered implementation.");
|
||||
}
|
||||
|
||||
return guide;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -200,6 +279,7 @@ public final class SlimefunRegistry {
|
||||
*
|
||||
* @return The {@link Map} of custom mob drops
|
||||
*/
|
||||
@Nonnull
|
||||
public Map<EntityType, Set<ItemStack>> getMobDrops() {
|
||||
return mobDrops;
|
||||
}
|
||||
@ -210,50 +290,62 @@ public final class SlimefunRegistry {
|
||||
*
|
||||
* @return A {@link Set} of bartering drops
|
||||
*/
|
||||
@Nonnull
|
||||
public Set<ItemStack> getBarteringDrops() {
|
||||
return barterDrops;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public Set<SlimefunItem> getRadioactiveItems() {
|
||||
return radioactive;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public Set<String> getTickerBlocks() {
|
||||
return tickers;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public Map<String, SlimefunItem> getSlimefunItemIds() {
|
||||
return slimefunIds;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public Map<String, BlockMenuPreset> getMenuPresets() {
|
||||
return blockMenuPresets;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public Map<String, UniversalBlockMenu> getUniversalInventories() {
|
||||
return universalInventories;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public Map<UUID, PlayerProfile> getPlayerProfiles() {
|
||||
return profiles;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public Map<Class<? extends ItemHandler>, Set<ItemHandler>> getPublicItemHandlers() {
|
||||
return globalItemHandlers;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public Map<String, SlimefunBlockHandler> getBlockHandlers() {
|
||||
return blockHandlers;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public Map<String, BlockStorage> getWorlds() {
|
||||
return worlds;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public Map<String, BlockInfoConfig> getChunks() {
|
||||
return chunks;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public KeyMap<GEOResource> getGEOResources() {
|
||||
return geoResources;
|
||||
}
|
||||
@ -262,4 +354,19 @@ public final class SlimefunRegistry {
|
||||
return logDuplicateBlockEntries;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public NamespacedKey getSoulboundDataKey() {
|
||||
return soulboundKey;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public NamespacedKey getItemChargeDataKey() {
|
||||
return itemChargeKey;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public NamespacedKey getGuideDataKey() {
|
||||
return guideKey;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -24,7 +24,6 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||
* @author TheBusyBiscuit
|
||||
*
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface DamageableItem extends ItemAttribute {
|
||||
|
||||
/**
|
||||
|
@ -1,12 +1,16 @@
|
||||
package io.github.thebusybiscuit.slimefun4.core.attributes;
|
||||
|
||||
import java.util.logging.Level;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.Location;
|
||||
|
||||
import io.github.thebusybiscuit.cscorelib2.blocks.BlockPosition;
|
||||
import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNet;
|
||||
import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNetComponentType;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.items.electric.Capacitor;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
|
||||
@ -117,65 +121,80 @@ public interface EnergyNetComponent extends ItemAttribute {
|
||||
default void setCharge(@Nonnull Location l, int charge) {
|
||||
Validate.notNull(l, "Location was null!");
|
||||
Validate.isTrue(charge >= 0, "You can only set a charge of zero or more!");
|
||||
int capacity = getCapacity();
|
||||
|
||||
// This method only makes sense if we can actually store energy
|
||||
if (capacity > 0) {
|
||||
charge = NumberUtils.clamp(0, charge, capacity);
|
||||
try {
|
||||
int capacity = getCapacity();
|
||||
|
||||
// Do we even need to update the value?
|
||||
if (charge != getCharge(l)) {
|
||||
BlockStorage.addBlockInfo(l, "energy-charge", String.valueOf(charge), false);
|
||||
// This method only makes sense if we can actually store energy
|
||||
if (capacity > 0) {
|
||||
charge = NumberUtils.clamp(0, charge, capacity);
|
||||
|
||||
// Update the capacitor texture
|
||||
if (getEnergyComponentType() == EnergyNetComponentType.CAPACITOR) {
|
||||
SlimefunUtils.updateCapacitorTexture(l, charge, capacity);
|
||||
// Do we even need to update the value?
|
||||
if (charge != getCharge(l)) {
|
||||
BlockStorage.addBlockInfo(l, "energy-charge", String.valueOf(charge), false);
|
||||
|
||||
// Update the capacitor texture
|
||||
if (getEnergyComponentType() == EnergyNetComponentType.CAPACITOR) {
|
||||
SlimefunUtils.updateCapacitorTexture(l, charge, capacity);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception | LinkageError x) {
|
||||
SlimefunPlugin.logger().log(Level.SEVERE, x, () -> "Exception while trying to set the energy-charge for \"" + getId() + "\" at " + new BlockPosition(l));
|
||||
}
|
||||
}
|
||||
|
||||
default void addCharge(@Nonnull Location l, int charge) {
|
||||
Validate.notNull(l, "Location was null!");
|
||||
Validate.isTrue(charge > 0, "You can only add a positive charge!");
|
||||
int capacity = getCapacity();
|
||||
|
||||
// This method only makes sense if we can actually store energy
|
||||
if (capacity > 0) {
|
||||
int currentCharge = getCharge(l);
|
||||
try {
|
||||
int capacity = getCapacity();
|
||||
|
||||
// Check if there is even space for new energy
|
||||
if (currentCharge < capacity) {
|
||||
int newCharge = Math.min(capacity, currentCharge + charge);
|
||||
BlockStorage.addBlockInfo(l, "energy-charge", String.valueOf(newCharge), false);
|
||||
// This method only makes sense if we can actually store energy
|
||||
if (capacity > 0) {
|
||||
int currentCharge = getCharge(l);
|
||||
|
||||
// Update the capacitor texture
|
||||
if (getEnergyComponentType() == EnergyNetComponentType.CAPACITOR) {
|
||||
SlimefunUtils.updateCapacitorTexture(l, charge, capacity);
|
||||
// Check if there is even space for new energy
|
||||
if (currentCharge < capacity) {
|
||||
int newCharge = Math.min(capacity, currentCharge + charge);
|
||||
BlockStorage.addBlockInfo(l, "energy-charge", String.valueOf(newCharge), false);
|
||||
|
||||
// Update the capacitor texture
|
||||
if (getEnergyComponentType() == EnergyNetComponentType.CAPACITOR) {
|
||||
SlimefunUtils.updateCapacitorTexture(l, charge, capacity);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception | LinkageError x) {
|
||||
SlimefunPlugin.logger().log(Level.SEVERE, x, () -> "Exception while trying to add an energy-charge for \"" + getId() + "\" at " + new BlockPosition(l));
|
||||
}
|
||||
}
|
||||
|
||||
default void removeCharge(@Nonnull Location l, int charge) {
|
||||
Validate.notNull(l, "Location was null!");
|
||||
Validate.isTrue(charge > 0, "The charge to remove must be greater than zero!");
|
||||
int capacity = getCapacity();
|
||||
|
||||
// This method only makes sense if we can actually store energy
|
||||
if (capacity > 0) {
|
||||
int currentCharge = getCharge(l);
|
||||
try {
|
||||
int capacity = getCapacity();
|
||||
|
||||
// Check if there is even energy stored
|
||||
if (currentCharge > 0) {
|
||||
int newCharge = Math.max(0, currentCharge - charge);
|
||||
BlockStorage.addBlockInfo(l, "energy-charge", String.valueOf(newCharge), false);
|
||||
// This method only makes sense if we can actually store energy
|
||||
if (capacity > 0) {
|
||||
int currentCharge = getCharge(l);
|
||||
|
||||
// Update the capacitor texture
|
||||
if (getEnergyComponentType() == EnergyNetComponentType.CAPACITOR) {
|
||||
SlimefunUtils.updateCapacitorTexture(l, charge, capacity);
|
||||
// Check if there is even energy stored
|
||||
if (currentCharge > 0) {
|
||||
int newCharge = Math.max(0, currentCharge - charge);
|
||||
BlockStorage.addBlockInfo(l, "energy-charge", String.valueOf(newCharge), false);
|
||||
|
||||
// Update the capacitor texture
|
||||
if (getEnergyComponentType() == EnergyNetComponentType.CAPACITOR) {
|
||||
SlimefunUtils.updateCapacitorTexture(l, charge, capacity);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception | LinkageError x) {
|
||||
SlimefunPlugin.logger().log(Level.SEVERE, x, () -> "Exception while trying to remove an energy-charge for \"" + getId() + "\" at " + new BlockPosition(l));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,65 @@
|
||||
package io.github.thebusybiscuit.slimefun4.core.attributes;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import io.github.thebusybiscuit.cscorelib2.chat.ChatColors;
|
||||
import io.github.thebusybiscuit.slimefun4.core.services.holograms.HologramsService;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.HologramProjector;
|
||||
|
||||
/**
|
||||
* This {@link ItemAttribute} manages holograms.
|
||||
*
|
||||
* @author TheBusyBiscuit
|
||||
*
|
||||
* @see HologramProjector
|
||||
* @see HologramsService
|
||||
*
|
||||
*/
|
||||
public interface HologramOwner extends ItemAttribute {
|
||||
|
||||
/**
|
||||
* This will update the hologram text for the given {@link Block}.
|
||||
*
|
||||
* @param b
|
||||
* The {@link Block} to which the hologram belongs
|
||||
*
|
||||
* @param text
|
||||
* The nametag for the hologram
|
||||
*/
|
||||
default void updateHologram(@Nonnull Block b, @Nonnull String text) {
|
||||
Location loc = b.getLocation().add(getHologramOffset(b));
|
||||
SlimefunPlugin.getHologramsService().setHologramLabel(loc, ChatColors.color(text));
|
||||
}
|
||||
|
||||
/**
|
||||
* This will remove the hologram for the given {@link Block}.
|
||||
*
|
||||
* @param b
|
||||
* The {@link Block} to which the hologram blocks
|
||||
*/
|
||||
default void removeHologram(@Nonnull Block b) {
|
||||
Location loc = b.getLocation().add(getHologramOffset(b));
|
||||
SlimefunPlugin.getHologramsService().removeHologram(loc);
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the offset of the hologram as a {@link Vector}.
|
||||
* This offset is applied to {@link Block#getLocation()} when spawning
|
||||
* the hologram.
|
||||
*
|
||||
* @param block
|
||||
* The {@link Block} which serves as the origin point
|
||||
*
|
||||
* @return The hologram offset
|
||||
*/
|
||||
@Nonnull
|
||||
default Vector getHologramOffset(@Nonnull Block block) {
|
||||
return SlimefunPlugin.getHologramsService().getDefaultOffset();
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
package io.github.thebusybiscuit.slimefun4.core.attributes;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||
import me.mrCookieSlime.Slimefun.Objects.handlers.ItemHandler;
|
||||
|
||||
@ -17,4 +19,12 @@ import me.mrCookieSlime.Slimefun.Objects.handlers.ItemHandler;
|
||||
*/
|
||||
public interface ItemAttribute {
|
||||
|
||||
/**
|
||||
* Returns the identifier of the associated {@link SlimefunItem}.
|
||||
*
|
||||
* @return the identifier of the {@link SlimefunItem}
|
||||
*/
|
||||
@Nonnull
|
||||
String getId();
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,14 @@
|
||||
package io.github.thebusybiscuit.slimefun4.core.attributes;
|
||||
|
||||
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AContainer;
|
||||
|
||||
/**
|
||||
* Implement this interface for any {@link AContainer} to prevent
|
||||
* that {@link AContainer} from being hopperable.
|
||||
*
|
||||
* @author CURVX
|
||||
*
|
||||
*/
|
||||
public interface NotHopperable extends ItemAttribute {
|
||||
|
||||
}
|
@ -17,7 +17,6 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||
* @see RandomMobDrop
|
||||
*
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface PiglinBarterDrop extends ItemAttribute {
|
||||
|
||||
/**
|
||||
|
@ -14,7 +14,6 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||
* @author TheBusyBiscuit
|
||||
*
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface Radioactive extends ItemAttribute {
|
||||
|
||||
/**
|
||||
|
@ -21,7 +21,6 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||
* @see PiglinBarterDrop
|
||||
*
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface RandomMobDrop extends ItemAttribute {
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,6 @@
|
||||
package io.github.thebusybiscuit.slimefun4.core.attributes;
|
||||
|
||||
import io.github.thebusybiscuit.slimefun4.utils.ChargeUtils;
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
@ -15,24 +16,23 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||
* A {@link Rechargeable} {@link SlimefunItem} can hold energy and is able to
|
||||
* be recharged using a {@link ChargingBench}.
|
||||
* Any {@link SlimefunItem} which is supposed to be chargeable <b>must</b> implement this interface.
|
||||
*
|
||||
*
|
||||
* @author TheBusyBiscuit
|
||||
*
|
||||
*
|
||||
* @see ChargingBench
|
||||
* @see EnergyNet
|
||||
* @see Jetpack
|
||||
* @see MultiTool
|
||||
*
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface Rechargeable extends ItemAttribute {
|
||||
|
||||
/**
|
||||
* This method returns the maximum charge the given {@link ItemStack} is capable of holding.
|
||||
*
|
||||
*
|
||||
* @param item
|
||||
* The {@link ItemStack} for which to determine the maximum charge
|
||||
*
|
||||
*
|
||||
* @return The maximum energy charge for this {@link ItemStack}
|
||||
*/
|
||||
float getMaxItemCharge(ItemStack item);
|
||||
@ -40,7 +40,7 @@ public interface Rechargeable extends ItemAttribute {
|
||||
/**
|
||||
* This method sets the stored energy charge for a given {@link ItemStack}.
|
||||
* The charge must be at least zero and at most {@link #getMaxItemCharge(ItemStack)}.
|
||||
*
|
||||
*
|
||||
* @param item
|
||||
* The {@link ItemStack} to charge
|
||||
* @param charge
|
||||
@ -58,16 +58,16 @@ public interface Rechargeable extends ItemAttribute {
|
||||
}
|
||||
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
RechargeableHelper.setCharge(meta, charge, maximum);
|
||||
ChargeUtils.setCharge(meta, charge, maximum);
|
||||
item.setItemMeta(meta);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the currently stored energy charge on the provided {@link ItemStack}.
|
||||
*
|
||||
*
|
||||
* @param item
|
||||
* The {@link ItemStack} to get the charge from
|
||||
*
|
||||
*
|
||||
* @return The charge stored on this {@link ItemStack}
|
||||
*/
|
||||
default float getItemCharge(ItemStack item) {
|
||||
@ -75,19 +75,19 @@ public interface Rechargeable extends ItemAttribute {
|
||||
throw new IllegalArgumentException("Cannot get Item charge for null or AIR");
|
||||
}
|
||||
|
||||
return RechargeableHelper.getCharge(item.getItemMeta());
|
||||
return ChargeUtils.getCharge(item.getItemMeta());
|
||||
}
|
||||
|
||||
/**
|
||||
* This method adds the given charge to the provided {@link ItemStack}.
|
||||
* The method will also return whether this operation was successful.
|
||||
* If the {@link ItemStack} is already at maximum charge, the method will return <code>false</code>.
|
||||
*
|
||||
*
|
||||
* @param item
|
||||
* The {@link ItemStack} to charge
|
||||
* @param charge
|
||||
* The amount of charge to add
|
||||
*
|
||||
*
|
||||
* @return Whether the given charge could be added successfully
|
||||
*/
|
||||
default boolean addItemCharge(ItemStack item, float charge) {
|
||||
@ -98,7 +98,7 @@ public interface Rechargeable extends ItemAttribute {
|
||||
}
|
||||
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
float currentCharge = RechargeableHelper.getCharge(meta);
|
||||
float currentCharge = ChargeUtils.getCharge(meta);
|
||||
float maximum = getMaxItemCharge(item);
|
||||
|
||||
// If the item is already fully charged, we abort.
|
||||
@ -107,7 +107,7 @@ public interface Rechargeable extends ItemAttribute {
|
||||
}
|
||||
|
||||
float newCharge = Math.min(currentCharge + charge, maximum);
|
||||
RechargeableHelper.setCharge(meta, newCharge, maximum);
|
||||
ChargeUtils.setCharge(meta, newCharge, maximum);
|
||||
|
||||
item.setItemMeta(meta);
|
||||
return true;
|
||||
@ -117,12 +117,12 @@ public interface Rechargeable extends ItemAttribute {
|
||||
* This method removes the given charge to the provided {@link ItemStack}.
|
||||
* The method will also return whether this operation was successful.
|
||||
* If the {@link ItemStack} does not have enough charge, the method will return <code>false</code>.
|
||||
*
|
||||
*
|
||||
* @param item
|
||||
* The {@link ItemStack} to remove the charge from
|
||||
* @param charge
|
||||
* The amount of charge to remove
|
||||
*
|
||||
*
|
||||
* @return Whether the given charge could be removed successfully
|
||||
*/
|
||||
default boolean removeItemCharge(ItemStack item, float charge) {
|
||||
@ -133,7 +133,7 @@ public interface Rechargeable extends ItemAttribute {
|
||||
}
|
||||
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
float currentCharge = RechargeableHelper.getCharge(meta);
|
||||
float currentCharge = ChargeUtils.getCharge(meta);
|
||||
|
||||
// If the item does not have enough charge, we abort
|
||||
if (currentCharge < charge) {
|
||||
@ -141,7 +141,7 @@ public interface Rechargeable extends ItemAttribute {
|
||||
}
|
||||
|
||||
float newCharge = Math.max(currentCharge - charge, 0);
|
||||
RechargeableHelper.setCharge(meta, newCharge, getMaxItemCharge(item));
|
||||
ChargeUtils.setCharge(meta, newCharge, getMaxItemCharge(item));
|
||||
|
||||
item.setItemMeta(meta);
|
||||
return true;
|
||||
|
@ -29,7 +29,6 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AGenerator;
|
||||
* @see AGenerator
|
||||
*
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface RecipeDisplayItem extends ItemAttribute {
|
||||
|
||||
/**
|
||||
|
@ -18,7 +18,6 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||
* @see WitherProofBlock
|
||||
*
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface WitherProof extends ItemAttribute {
|
||||
|
||||
/**
|
||||
|
@ -11,7 +11,7 @@ import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
|
||||
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuide;
|
||||
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideLayout;
|
||||
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideMode;
|
||||
import me.mrCookieSlime.Slimefun.Objects.Category;
|
||||
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||
|
||||
@ -45,12 +45,12 @@ public abstract class FlexCategory extends Category {
|
||||
* @param profile
|
||||
* The {@link PlayerProfile} of the {@link Player}
|
||||
* @param layout
|
||||
* The {@link SlimefunGuideLayout} in which this {@link FlexCategory} is viewed
|
||||
* The {@link SlimefunGuideMode} in which this {@link FlexCategory} is viewed
|
||||
*
|
||||
* @return Whether to display this {@link FlexCategory}
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
public abstract boolean isVisible(Player p, PlayerProfile profile, SlimefunGuideLayout layout);
|
||||
public abstract boolean isVisible(Player p, PlayerProfile profile, SlimefunGuideMode layout);
|
||||
|
||||
/**
|
||||
* This method is called when a {@link Player} opens this {@link FlexCategory}.
|
||||
@ -62,13 +62,13 @@ public abstract class FlexCategory extends Category {
|
||||
* @param profile
|
||||
* The corresponding {@link PlayerProfile} for that {@link Player}
|
||||
* @param layout
|
||||
* The current {@link SlimefunGuideLayout}
|
||||
* The current {@link SlimefunGuideMode}
|
||||
*/
|
||||
public abstract void open(Player p, PlayerProfile profile, SlimefunGuideLayout layout);
|
||||
public abstract void open(Player p, PlayerProfile profile, SlimefunGuideMode layout);
|
||||
|
||||
@Override
|
||||
public final boolean isHidden(@Nonnull Player p) {
|
||||
/**
|
||||
/*
|
||||
* We can stop this method right here.
|
||||
* We provide a custom method with more parameters for this.
|
||||
* See isVisible(...)
|
||||
|
@ -14,6 +14,7 @@ import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon;
|
||||
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
import me.mrCookieSlime.Slimefun.Objects.Category;
|
||||
@ -76,8 +77,8 @@ public class LockedCategory extends Category {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register() {
|
||||
super.register();
|
||||
public void register(@Nonnull SlimefunAddon addon) {
|
||||
super.register(addon);
|
||||
|
||||
List<NamespacedKey> namespacedKeys = new ArrayList<>();
|
||||
|
||||
@ -94,7 +95,7 @@ public class LockedCategory extends Category {
|
||||
}
|
||||
|
||||
for (NamespacedKey key : namespacedKeys) {
|
||||
Slimefun.getLogger().log(Level.INFO, "Parent \"{0}\" for Category \"{1}\" was not found, probably just disabled.", new Object[] { key, getKey() });
|
||||
SlimefunPlugin.logger().log(Level.INFO, "Parent \"{0}\" for Category \"{1}\" was not found, probably just disabled.", new Object[] { key, getKey() });
|
||||
}
|
||||
}
|
||||
|
||||
@ -148,12 +149,13 @@ public class LockedCategory extends Category {
|
||||
* The {@link Player} to check
|
||||
* @param profile
|
||||
* The {@link PlayerProfile} that belongs to the given {@link Player}
|
||||
*
|
||||
* @return Whether the {@link Player} has fully completed all parent categories, otherwise false
|
||||
*/
|
||||
public boolean hasUnlocked(@Nonnull Player p, @Nonnull PlayerProfile profile) {
|
||||
for (Category category : parents) {
|
||||
for (SlimefunItem item : category.getItems()) {
|
||||
/**
|
||||
/*
|
||||
* Should probably be replaced with Slimefun.hasUnlocked(...)
|
||||
* However this will result in better performance because we don't
|
||||
* request the PlayerProfile everytime
|
||||
|
@ -83,7 +83,7 @@ public class SlimefunCommand implements CommandExecutor, Listener {
|
||||
|
||||
sendHelp(sender);
|
||||
|
||||
/**
|
||||
/*
|
||||
* We could just return true here, but if there's no subcommands,
|
||||
* then something went horribly wrong anyway.
|
||||
* This will also stop sonarcloud from nagging about
|
||||
|
@ -6,7 +6,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.guide.SlimefunGuide;
|
||||
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideLayout;
|
||||
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideMode;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
|
||||
class GuideCommand extends SubCommand {
|
||||
@ -19,7 +19,7 @@ class GuideCommand extends SubCommand {
|
||||
public void onExecute(CommandSender sender, String[] args) {
|
||||
if (sender instanceof Player) {
|
||||
if (sender.hasPermission("slimefun.command.guide")) {
|
||||
SlimefunGuideLayout design = SlimefunGuide.getDefaultLayout();
|
||||
SlimefunGuideMode design = SlimefunGuide.getDefaultMode();
|
||||
((Player) sender).getInventory().addItem(SlimefunGuide.getItem(design).clone());
|
||||
} else {
|
||||
SlimefunPlugin.getLocalization().sendMessage(sender, "messages.no-permission", true);
|
||||
|
@ -1,12 +1,14 @@
|
||||
package io.github.thebusybiscuit.slimefun4.core.commands.subcommands;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
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.guide.SlimefunGuide;
|
||||
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideLayout;
|
||||
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideMode;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
|
||||
class OpenGuideCommand extends SubCommand {
|
||||
@ -16,11 +18,11 @@ class OpenGuideCommand extends SubCommand {
|
||||
}
|
||||
|
||||
@Override
|
||||
@ParametersAreNonnullByDefault
|
||||
public void onExecute(CommandSender sender, String[] args) {
|
||||
if (sender instanceof Player) {
|
||||
if (sender.hasPermission("slimefun.command.open_guide")) {
|
||||
boolean book = SlimefunPlugin.getCfg().getBoolean("guide.default-view-book");
|
||||
SlimefunGuide.openGuide((Player) sender, book ? SlimefunGuideLayout.BOOK : SlimefunGuideLayout.CHEST);
|
||||
SlimefunGuide.openGuide((Player) sender, SlimefunGuideMode.SURVIVAL_MODE);
|
||||
} else {
|
||||
SlimefunPlugin.getLocalization().sendMessage(sender, "messages.no-permission", true);
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
|
||||
import io.github.thebusybiscuit.slimefun4.core.commands.SlimefunCommand;
|
||||
import io.github.thebusybiscuit.slimefun4.core.commands.SubCommand;
|
||||
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuide;
|
||||
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideMode;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
|
||||
class SearchCommand extends SubCommand {
|
||||
@ -23,7 +24,7 @@ class SearchCommand extends SubCommand {
|
||||
if (sender.hasPermission("slimefun.command.search")) {
|
||||
if (args.length > 1) {
|
||||
String query = String.join(" ", Arrays.copyOfRange(args, 1, args.length));
|
||||
PlayerProfile.get((Player) sender, profile -> SlimefunGuide.openSearch(profile, query, true, true));
|
||||
PlayerProfile.get((Player) sender, profile -> SlimefunGuide.openSearch(profile, query, SlimefunGuideMode.SURVIVAL_MODE, true));
|
||||
} else {
|
||||
SlimefunPlugin.getLocalization().sendMessage(sender, "messages.usage", true, msg -> msg.replace("%usage%", "/sf search <SearchTerm>"));
|
||||
}
|
||||
|
@ -1,26 +1,97 @@
|
||||
package io.github.thebusybiscuit.slimefun4.core.commands.subcommands;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.ConsoleCommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import io.github.thebusybiscuit.slimefun4.core.commands.SlimefunCommand;
|
||||
import io.github.thebusybiscuit.slimefun4.core.commands.SubCommand;
|
||||
import io.github.thebusybiscuit.slimefun4.core.services.profiler.PerformanceInspector;
|
||||
import io.github.thebusybiscuit.slimefun4.core.services.profiler.inspectors.ConsolePerformanceInspector;
|
||||
import io.github.thebusybiscuit.slimefun4.core.services.profiler.inspectors.PlayerPerformanceInspector;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
|
||||
class TimingsCommand extends SubCommand {
|
||||
|
||||
private static final String FLAG_PREFIX = "--";
|
||||
private final Set<String> flags = new HashSet<>(Arrays.asList("verbose"));
|
||||
|
||||
TimingsCommand(SlimefunPlugin plugin, SlimefunCommand cmd) {
|
||||
super(plugin, cmd, "timings", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDescription() {
|
||||
return "commands.timings.description";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExecute(CommandSender sender, String[] args) {
|
||||
if (sender.hasPermission("slimefun.command.timings") || sender instanceof ConsoleCommandSender) {
|
||||
sender.sendMessage("Please wait a second... The results are coming in!");
|
||||
SlimefunPlugin.getProfiler().requestSummary(sender);
|
||||
if (hasInvalidFlags(sender, args)) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean verbose = hasFlag(args, "verbose");
|
||||
|
||||
if (verbose && sender instanceof Player) {
|
||||
SlimefunPlugin.getLocalization().sendMessage(sender, "commands.timings.verbose-player", true);
|
||||
return;
|
||||
}
|
||||
|
||||
SlimefunPlugin.getLocalization().sendMessage(sender, "commands.timings.please-wait", true);
|
||||
|
||||
PerformanceInspector inspector = inspectorOf(sender, verbose);
|
||||
SlimefunPlugin.getProfiler().requestSummary(inspector);
|
||||
} else {
|
||||
SlimefunPlugin.getLocalization().sendMessage(sender, "messages.no-permission", true);
|
||||
}
|
||||
}
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
private boolean hasInvalidFlags(CommandSender sender, String[] args) {
|
||||
boolean hasInvalidFlags = false;
|
||||
|
||||
// We start at 1 because args[0] will be "timings".
|
||||
for (int i = 1; i < args.length; i++) {
|
||||
String argument = args[i].toLowerCase(Locale.ROOT);
|
||||
|
||||
if (argument.startsWith(FLAG_PREFIX) && !flags.contains(argument.substring(2))) {
|
||||
hasInvalidFlags = true;
|
||||
SlimefunPlugin.getLocalization().sendMessage(sender, "commands.timings.unknown-flag", true, msg -> msg.replace("%flag%", argument));
|
||||
}
|
||||
}
|
||||
|
||||
return hasInvalidFlags;
|
||||
}
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
private boolean hasFlag(String[] args, String flag) {
|
||||
// We start at 1 because args[0] will be "timings".
|
||||
for (int i = 1; i < args.length; i++) {
|
||||
if (args[i].equalsIgnoreCase(FLAG_PREFIX + flag)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private PerformanceInspector inspectorOf(@Nonnull CommandSender sender, boolean verbose) {
|
||||
if (sender instanceof Player) {
|
||||
return new PlayerPerformanceInspector((Player) sender);
|
||||
} else {
|
||||
return new ConsolePerformanceInspector(sender, verbose);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package io.github.thebusybiscuit.slimefun4.core.commands.subcommands;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
@ -9,7 +10,6 @@ import org.bukkit.command.ConsoleCommandSender;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import io.github.thebusybiscuit.cscorelib2.chat.ChatColors;
|
||||
import io.github.thebusybiscuit.cscorelib2.reflection.ReflectionUtils;
|
||||
import io.github.thebusybiscuit.slimefun4.core.commands.SlimefunCommand;
|
||||
import io.github.thebusybiscuit.slimefun4.core.commands.SubCommand;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
@ -22,15 +22,14 @@ class VersionsCommand extends SubCommand {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExecute(CommandSender sender, String[] args) {
|
||||
public void onExecute(@Nonnull CommandSender sender, @Nonnull String[] args) {
|
||||
if (sender.hasPermission("slimefun.command.versions") || sender instanceof ConsoleCommandSender) {
|
||||
// After all these years... Spigot still displays as "CraftBukkit"
|
||||
// so we will just fix this inconsistency for them :)
|
||||
String serverSoftware = PaperLib.isSpigot() && !PaperLib.isPaper() ? "Spigot" : Bukkit.getName();
|
||||
|
||||
sender.sendMessage(ChatColor.GRAY + "This Server uses the following setup of Slimefun:");
|
||||
sender.sendMessage(ChatColors.color("&a" + serverSoftware + " &2" + ReflectionUtils.getVersion()));
|
||||
sender.sendMessage(ChatColors.color("&aCS-CoreLib &2v" + SlimefunPlugin.getCSCoreLibVersion()));
|
||||
sender.sendMessage(ChatColors.color("&a" + serverSoftware + " &2" + Bukkit.getVersion()));
|
||||
sender.sendMessage(ChatColors.color("&aSlimefun &2v" + SlimefunPlugin.getVersion()));
|
||||
|
||||
if (SlimefunPlugin.getMetricsService().getVersion() != null) {
|
||||
|
@ -3,15 +3,19 @@ package io.github.thebusybiscuit.slimefun4.core.guide;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.guide.BookSlimefunGuide;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.guide.ChestSlimefunGuide;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.guide.SurvivalSlimefunGuide;
|
||||
|
||||
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.itemstack.SlimefunGuideItem;
|
||||
import me.mrCookieSlime.Slimefun.Objects.Category;
|
||||
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||
|
||||
@ -22,36 +26,35 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||
* @author TheBusyBiscuit
|
||||
*
|
||||
* @see SlimefunGuideImplementation
|
||||
* @see ChestSlimefunGuide
|
||||
* @see BookSlimefunGuide
|
||||
* @see SurvivalSlimefunGuide
|
||||
*
|
||||
*/
|
||||
public final class SlimefunGuide {
|
||||
|
||||
private SlimefunGuide() {}
|
||||
|
||||
public static ItemStack getItem(@Nonnull SlimefunGuideLayout design) {
|
||||
return SlimefunPlugin.getRegistry().getGuideLayout(design).getItem();
|
||||
@Nonnull
|
||||
public static ItemStack getItem(@Nonnull SlimefunGuideMode design) {
|
||||
return SlimefunPlugin.getRegistry().getSlimefunGuide(design).getItem();
|
||||
}
|
||||
|
||||
public static void openCheatMenu(Player p) {
|
||||
openMainMenuAsync(p, SlimefunGuideLayout.CHEAT_SHEET, 1);
|
||||
public static void openCheatMenu(@Nonnull Player p) {
|
||||
openMainMenuAsync(p, SlimefunGuideMode.CHEAT_MODE, 1);
|
||||
}
|
||||
|
||||
public static void openGuide(Player p, ItemStack guide) {
|
||||
if (SlimefunUtils.isItemSimilar(guide, getItem(SlimefunGuideLayout.CHEST), true)) {
|
||||
openGuide(p, SlimefunGuideLayout.CHEST);
|
||||
} else if (SlimefunUtils.isItemSimilar(guide, getItem(SlimefunGuideLayout.BOOK), true)) {
|
||||
openGuide(p, SlimefunGuideLayout.BOOK);
|
||||
} else if (SlimefunUtils.isItemSimilar(guide, getItem(SlimefunGuideLayout.CHEAT_SHEET), true)) {
|
||||
openGuide(p, SlimefunGuideLayout.CHEAT_SHEET);
|
||||
public static void openGuide(@Nonnull Player p, @Nullable ItemStack guide) {
|
||||
if (getItem(SlimefunGuideMode.CHEAT_MODE).equals(guide)) {
|
||||
openGuide(p, SlimefunGuideMode.CHEAT_MODE);
|
||||
} else {
|
||||
// When using /sf cheat or /sf open_guide, ItemStack is null.
|
||||
openGuide(p, SlimefunGuideLayout.CHEST);
|
||||
/*
|
||||
* When using /sf cheat or /sf open_guide the ItemStack is null anyway,
|
||||
* so we don't even need to check here at this point.
|
||||
*/
|
||||
openGuide(p, SlimefunGuideMode.SURVIVAL_MODE);
|
||||
}
|
||||
}
|
||||
|
||||
public static void openGuide(Player p, SlimefunGuideLayout layout) {
|
||||
public static void openGuide(@Nonnull Player p, @Nonnull SlimefunGuideMode mode) {
|
||||
if (!SlimefunPlugin.getWorldSettingsService().isWorldEnabled(p.getWorld())) {
|
||||
return;
|
||||
}
|
||||
@ -60,58 +63,72 @@ public final class SlimefunGuide {
|
||||
|
||||
if (optional.isPresent()) {
|
||||
PlayerProfile profile = optional.get();
|
||||
SlimefunGuideImplementation guide = SlimefunPlugin.getRegistry().getGuideLayout(layout);
|
||||
SlimefunGuideImplementation guide = SlimefunPlugin.getRegistry().getSlimefunGuide(mode);
|
||||
profile.getGuideHistory().openLastEntry(guide);
|
||||
} else {
|
||||
openMainMenuAsync(p, layout, 1);
|
||||
openMainMenuAsync(p, mode, 1);
|
||||
}
|
||||
}
|
||||
|
||||
private static void openMainMenuAsync(Player player, SlimefunGuideLayout layout, int selectedPage) {
|
||||
if (!PlayerProfile.get(player, profile -> SlimefunPlugin.runSync(() -> openMainMenu(profile, layout, selectedPage)))) {
|
||||
@ParametersAreNonnullByDefault
|
||||
private static void openMainMenuAsync(Player player, SlimefunGuideMode mode, int selectedPage) {
|
||||
if (!PlayerProfile.get(player, profile -> SlimefunPlugin.runSync(() -> openMainMenu(profile, mode, selectedPage)))) {
|
||||
SlimefunPlugin.getLocalization().sendMessage(player, "messages.opening-guide");
|
||||
}
|
||||
}
|
||||
|
||||
public static void openMainMenu(PlayerProfile profile, SlimefunGuideLayout layout, int selectedPage) {
|
||||
SlimefunPlugin.getRegistry().getGuideLayout(layout).openMainMenu(profile, selectedPage);
|
||||
@ParametersAreNonnullByDefault
|
||||
public static void openMainMenu(PlayerProfile profile, SlimefunGuideMode mode, int selectedPage) {
|
||||
SlimefunPlugin.getRegistry().getSlimefunGuide(mode).openMainMenu(profile, selectedPage);
|
||||
}
|
||||
|
||||
public static void openCategory(PlayerProfile profile, Category category, SlimefunGuideLayout layout, int selectedPage) {
|
||||
if (category == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
SlimefunPlugin.getRegistry().getGuideLayout(layout).openCategory(profile, category, selectedPage);
|
||||
@ParametersAreNonnullByDefault
|
||||
public static void openCategory(PlayerProfile profile, Category category, SlimefunGuideMode mode, int selectedPage) {
|
||||
SlimefunPlugin.getRegistry().getSlimefunGuide(mode).openCategory(profile, category, selectedPage);
|
||||
}
|
||||
|
||||
public static void openSearch(PlayerProfile profile, String input, boolean survival, boolean addToHistory) {
|
||||
SlimefunGuideImplementation layout = SlimefunPlugin.getRegistry().getGuideLayout(SlimefunGuideLayout.CHEST);
|
||||
|
||||
if (!survival) {
|
||||
layout = SlimefunPlugin.getRegistry().getGuideLayout(SlimefunGuideLayout.CHEAT_SHEET);
|
||||
}
|
||||
|
||||
layout.openSearch(profile, input, addToHistory);
|
||||
@ParametersAreNonnullByDefault
|
||||
public static void openSearch(PlayerProfile profile, String input, SlimefunGuideMode mode, boolean addToHistory) {
|
||||
SlimefunGuideImplementation guide = SlimefunPlugin.getRegistry().getSlimefunGuide(mode);
|
||||
guide.openSearch(profile, input, addToHistory);
|
||||
}
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
public static void displayItem(PlayerProfile profile, ItemStack item, boolean addToHistory) {
|
||||
SlimefunPlugin.getRegistry().getGuideLayout(SlimefunGuideLayout.CHEST).displayItem(profile, item, 0, addToHistory);
|
||||
SlimefunPlugin.getRegistry().getSlimefunGuide(SlimefunGuideMode.SURVIVAL_MODE).displayItem(profile, item, 0, addToHistory);
|
||||
}
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
public static void displayItem(PlayerProfile profile, SlimefunItem item, boolean addToHistory) {
|
||||
SlimefunPlugin.getRegistry().getGuideLayout(SlimefunGuideLayout.CHEST).displayItem(profile, item, addToHistory);
|
||||
SlimefunPlugin.getRegistry().getSlimefunGuide(SlimefunGuideMode.SURVIVAL_MODE).displayItem(profile, item, addToHistory);
|
||||
}
|
||||
|
||||
public static boolean isGuideItem(ItemStack item) {
|
||||
return SlimefunUtils.isItemSimilar(item, getItem(SlimefunGuideLayout.CHEST), true) || SlimefunUtils.isItemSimilar(item, getItem(SlimefunGuideLayout.BOOK), true) || SlimefunUtils.isItemSimilar(item, getItem(SlimefunGuideLayout.CHEAT_SHEET), true);
|
||||
}
|
||||
|
||||
public static SlimefunGuideLayout getDefaultLayout() {
|
||||
if (SlimefunPlugin.getCfg().getBoolean("guide.default-view-book")) {
|
||||
return SlimefunGuideLayout.BOOK;
|
||||
/**
|
||||
* This method checks if a given {@link ItemStack} is a {@link SlimefunGuide}.
|
||||
*
|
||||
* @param item
|
||||
* The {@link ItemStack} to check
|
||||
*
|
||||
* @return Whether this {@link ItemStack} represents a {@link SlimefunGuide}
|
||||
*/
|
||||
public static boolean isGuideItem(@Nullable ItemStack item) {
|
||||
if (item == null || item.getType() != Material.ENCHANTED_BOOK) {
|
||||
return false;
|
||||
} else if (item instanceof SlimefunGuideItem) {
|
||||
return true;
|
||||
} else {
|
||||
return SlimefunGuideLayout.CHEST;
|
||||
return SlimefunUtils.isItemSimilar(item, getItem(SlimefunGuideMode.SURVIVAL_MODE), true) || SlimefunUtils.isItemSimilar(item, getItem(SlimefunGuideMode.CHEAT_MODE), true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default mode for the Slimefun guide.
|
||||
* Currently this is only {@link SlimefunGuideMode#SURVIVAL_MODE}.
|
||||
*
|
||||
* @return The default {@link SlimefunGuideMode}.
|
||||
*/
|
||||
@Nonnull
|
||||
public static SlimefunGuideMode getDefaultMode() {
|
||||
return SlimefunGuideMode.SURVIVAL_MODE;
|
||||
}
|
||||
}
|
||||
|
@ -11,8 +11,7 @@ import org.bukkit.inventory.ItemStack;
|
||||
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
|
||||
import io.github.thebusybiscuit.slimefun4.core.researching.Research;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.guide.BookSlimefunGuide;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.guide.ChestSlimefunGuide;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.guide.SurvivalSlimefunGuide;
|
||||
import me.mrCookieSlime.Slimefun.Objects.Category;
|
||||
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||
|
||||
@ -22,21 +21,20 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||
*
|
||||
* @author TheBusyBiscuit
|
||||
*
|
||||
* @see SlimefunGuideLayout
|
||||
* @see ChestSlimefunGuide
|
||||
* @see BookSlimefunGuide
|
||||
* @see SlimefunGuideMode
|
||||
* @see SurvivalSlimefunGuide
|
||||
*
|
||||
*/
|
||||
public interface SlimefunGuideImplementation {
|
||||
|
||||
/**
|
||||
* Every {@link SlimefunGuideImplementation} can be associated with a
|
||||
* {@link SlimefunGuideLayout}.
|
||||
* {@link SlimefunGuideMode}.
|
||||
*
|
||||
* @return The layout this {@link SlimefunGuideImplementation} represents
|
||||
* @return The mode this {@link SlimefunGuideImplementation} represents
|
||||
*/
|
||||
@Nonnull
|
||||
SlimefunGuideLayout getLayout();
|
||||
SlimefunGuideMode getMode();
|
||||
|
||||
/**
|
||||
* Returns the {@link ItemStack} representation for this {@link SlimefunGuideImplementation}.
|
||||
@ -48,14 +46,6 @@ public interface SlimefunGuideImplementation {
|
||||
@Nonnull
|
||||
ItemStack getItem();
|
||||
|
||||
/**
|
||||
* This method returns whether this {@link SlimefunGuideImplementation} is meant
|
||||
* for Survival Mode.
|
||||
*
|
||||
* @return Whether this is a survival mode implementation
|
||||
*/
|
||||
boolean isSurvivalMode();
|
||||
|
||||
void openMainMenu(PlayerProfile profile, int page);
|
||||
|
||||
void openCategory(PlayerProfile profile, Category category, int page);
|
||||
|
@ -13,24 +13,17 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||
* @see SlimefunGuideImplementation
|
||||
*
|
||||
*/
|
||||
public enum SlimefunGuideLayout {
|
||||
|
||||
/**
|
||||
* This design is a book representation of the {@link SlimefunGuide}
|
||||
*/
|
||||
BOOK,
|
||||
public enum SlimefunGuideMode {
|
||||
|
||||
/**
|
||||
* This design is the standard layout, it uses a {@link ChestMenu}
|
||||
*/
|
||||
CHEST,
|
||||
SURVIVAL_MODE,
|
||||
|
||||
/**
|
||||
* This is an admin-only design which creates a {@link SlimefunGuide} that allows
|
||||
* you to spawn in any {@link SlimefunItem}
|
||||
*/
|
||||
CHEAT_SHEET;
|
||||
|
||||
public static final SlimefunGuideLayout[] valuesCache = values();
|
||||
CHEAT_MODE;
|
||||
|
||||
}
|
@ -4,6 +4,9 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
@ -13,35 +16,41 @@ import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon;
|
||||
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuide;
|
||||
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideLayout;
|
||||
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideMode;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.ChatUtils;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
|
||||
|
||||
class GuideLayoutOption implements SlimefunGuideOption<SlimefunGuideLayout> {
|
||||
class GuideModeOption implements SlimefunGuideOption<SlimefunGuideMode> {
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public SlimefunAddon getAddon() {
|
||||
return SlimefunPlugin.instance();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public NamespacedKey getKey() {
|
||||
return new NamespacedKey(SlimefunPlugin.instance(), "guide_layout");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Optional<ItemStack> getDisplayItem(Player p, ItemStack guide) {
|
||||
Optional<SlimefunGuideLayout> current = getSelectedOption(p, guide);
|
||||
if (!p.hasPermission("slimefun.cheat.items")) {
|
||||
// Only Players with the appropriate permission can access the cheat sheet
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
Optional<SlimefunGuideMode> current = getSelectedOption(p, guide);
|
||||
|
||||
if (current.isPresent()) {
|
||||
SlimefunGuideLayout layout = current.get();
|
||||
SlimefunGuideMode layout = current.get();
|
||||
ItemStack item = new ItemStack(Material.AIR);
|
||||
|
||||
if (layout == SlimefunGuideLayout.CHEST) {
|
||||
if (layout == SlimefunGuideMode.SURVIVAL_MODE) {
|
||||
item.setType(Material.CHEST);
|
||||
} else if (layout == SlimefunGuideLayout.BOOK) {
|
||||
item.setType(Material.BOOK);
|
||||
} else {
|
||||
item.setType(Material.COMMAND_BLOCK);
|
||||
}
|
||||
@ -50,12 +59,9 @@ class GuideLayoutOption implements SlimefunGuideOption<SlimefunGuideLayout> {
|
||||
meta.setDisplayName(ChatColor.GRAY + "Slimefun Guide Design: " + ChatColor.YELLOW + ChatUtils.humanize(layout.name()));
|
||||
List<String> lore = new ArrayList<>();
|
||||
lore.add("");
|
||||
lore.add((layout == SlimefunGuideLayout.CHEST ? ChatColor.GREEN : ChatColor.GRAY) + "Chest");
|
||||
lore.add((layout == SlimefunGuideLayout.BOOK ? ChatColor.GREEN : ChatColor.GRAY) + "Book");
|
||||
lore.add((layout == SlimefunGuideMode.SURVIVAL_MODE ? ChatColor.GREEN : ChatColor.GRAY) + "Chest");
|
||||
|
||||
if (p.hasPermission("slimefun.cheat.items")) {
|
||||
lore.add((layout == SlimefunGuideLayout.CHEAT_SHEET ? ChatColor.GREEN : ChatColor.GRAY) + "Cheat Sheet");
|
||||
}
|
||||
lore.add((layout == SlimefunGuideMode.CHEAT_MODE ? ChatColor.GREEN : ChatColor.GRAY) + "Cheat Sheet");
|
||||
|
||||
lore.add("");
|
||||
lore.add(ChatColor.GRAY + "\u21E8 " + ChatColor.YELLOW + "Click to change your layout");
|
||||
@ -69,47 +75,44 @@ class GuideLayoutOption implements SlimefunGuideOption<SlimefunGuideLayout> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(Player p, ItemStack guide) {
|
||||
Optional<SlimefunGuideLayout> current = getSelectedOption(p, guide);
|
||||
public void onClick(@Nonnull Player p, @Nonnull ItemStack guide) {
|
||||
Optional<SlimefunGuideMode> current = getSelectedOption(p, guide);
|
||||
|
||||
if (current.isPresent()) {
|
||||
SlimefunGuideLayout next = getNextLayout(p, current.get());
|
||||
SlimefunGuideMode next = getNextMode(p, current.get());
|
||||
setSelectedOption(p, guide, next);
|
||||
}
|
||||
|
||||
SlimefunGuideSettings.openSettings(p, guide);
|
||||
}
|
||||
|
||||
private SlimefunGuideLayout getNextLayout(Player p, SlimefunGuideLayout layout) {
|
||||
@Nonnull
|
||||
private SlimefunGuideMode getNextMode(@Nonnull Player p, @Nonnull SlimefunGuideMode mode) {
|
||||
if (p.hasPermission("slimefun.cheat.items")) {
|
||||
if (layout == SlimefunGuideLayout.CHEST) {
|
||||
return SlimefunGuideLayout.BOOK;
|
||||
if (mode == SlimefunGuideMode.SURVIVAL_MODE) {
|
||||
return SlimefunGuideMode.CHEAT_MODE;
|
||||
} else {
|
||||
return SlimefunGuideMode.SURVIVAL_MODE;
|
||||
}
|
||||
|
||||
if (layout == SlimefunGuideLayout.BOOK) {
|
||||
return SlimefunGuideLayout.CHEAT_SHEET;
|
||||
}
|
||||
|
||||
return SlimefunGuideLayout.CHEST;
|
||||
} else {
|
||||
return layout == SlimefunGuideLayout.CHEST ? SlimefunGuideLayout.BOOK : SlimefunGuideLayout.CHEST;
|
||||
return SlimefunGuideMode.SURVIVAL_MODE;
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Optional<SlimefunGuideMode> getSelectedOption(@Nonnull Player p, @Nonnull ItemStack guide) {
|
||||
if (SlimefunUtils.isItemSimilar(guide, SlimefunGuide.getItem(SlimefunGuideMode.CHEAT_MODE), true, false)) {
|
||||
return Optional.of(SlimefunGuideMode.CHEAT_MODE);
|
||||
} else {
|
||||
return Optional.of(SlimefunGuideMode.SURVIVAL_MODE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<SlimefunGuideLayout> getSelectedOption(Player p, ItemStack guide) {
|
||||
for (SlimefunGuideLayout layout : SlimefunGuideLayout.valuesCache) {
|
||||
if (SlimefunUtils.isItemSimilar(guide, SlimefunGuide.getItem(layout), true, false)) {
|
||||
return Optional.of(layout);
|
||||
}
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelectedOption(Player p, ItemStack guide, SlimefunGuideLayout value) {
|
||||
@ParametersAreNonnullByDefault
|
||||
public void setSelectedOption(Player p, ItemStack guide, SlimefunGuideMode value) {
|
||||
guide.setItemMeta(SlimefunGuide.getItem(value).getItemMeta());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -4,6 +4,9 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
@ -13,7 +16,8 @@ import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
|
||||
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuide;
|
||||
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideLayout;
|
||||
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideMode;
|
||||
import io.github.thebusybiscuit.slimefun4.core.researching.Research;
|
||||
import io.github.thebusybiscuit.slimefun4.core.services.localization.Language;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.ChatUtils;
|
||||
@ -39,17 +43,18 @@ public final class SlimefunGuideSettings {
|
||||
private static final List<SlimefunGuideOption<?>> options = new ArrayList<>();
|
||||
|
||||
static {
|
||||
options.add(new GuideLayoutOption());
|
||||
options.add(new GuideModeOption());
|
||||
options.add(new FireworksOption());
|
||||
options.add(new PlayerLanguageOption());
|
||||
}
|
||||
|
||||
private SlimefunGuideSettings() {}
|
||||
|
||||
public static <T> void addOption(SlimefunGuideOption<T> option) {
|
||||
public static <T> void addOption(@Nonnull SlimefunGuideOption<T> option) {
|
||||
options.add(option);
|
||||
}
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
public static void openSettings(Player p, ItemStack guide) {
|
||||
ChestMenu menu = new ChestMenu(SlimefunPlugin.getLocalization().getMessage(p, "guide.title.settings"));
|
||||
|
||||
@ -64,8 +69,9 @@ public final class SlimefunGuideSettings {
|
||||
menu.open(p);
|
||||
}
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
private static void addHeader(Player p, ChestMenu menu, ItemStack guide) {
|
||||
menu.addItem(0, new CustomItem(SlimefunGuide.getItem(SlimefunGuideLayout.CHEST), "&e\u21E6 " + SlimefunPlugin.getLocalization().getMessage(p, "guide.back.title"), "", "&7" + SlimefunPlugin.getLocalization().getMessage(p, "guide.back.guide")), (pl, slot, item, action) -> {
|
||||
menu.addItem(0, new CustomItem(SlimefunGuide.getItem(SlimefunGuideMode.SURVIVAL_MODE), "&e\u21E6 " + SlimefunPlugin.getLocalization().getMessage(p, "guide.back.title"), "", "&7" + SlimefunPlugin.getLocalization().getMessage(p, "guide.back.guide")), (pl, slot, item, action) -> {
|
||||
SlimefunGuide.openGuide(pl, guide);
|
||||
return false;
|
||||
});
|
||||
@ -81,7 +87,7 @@ public final class SlimefunGuideSettings {
|
||||
return false;
|
||||
});
|
||||
|
||||
menu.addItem(4, new CustomItem(Material.WRITABLE_BOOK, ChatColor.GREEN + SlimefunPlugin.getLocalization().getMessage(p, "guide.title.versions"), "&7&o" + SlimefunPlugin.getLocalization().getMessage(p, "guide.tooltips.versions-notice"), "", "&fMinecraft: &a" + Bukkit.getBukkitVersion(), "&fSlimefun: &a" + SlimefunPlugin.getVersion(), "&fCS-CoreLib: &a" + SlimefunPlugin.getCSCoreLibVersion()), ChestMenuUtils.getEmptyClickHandler());
|
||||
menu.addItem(4, new CustomItem(Material.WRITABLE_BOOK, ChatColor.GREEN + SlimefunPlugin.getLocalization().getMessage(p, "guide.title.versions"), "&7&o" + SlimefunPlugin.getLocalization().getMessage(p, "guide.tooltips.versions-notice"), "", "&fMinecraft: &a" + Bukkit.getBukkitVersion(), "&fSlimefun: &a" + SlimefunPlugin.getVersion()), ChestMenuUtils.getEmptyClickHandler());
|
||||
|
||||
menu.addItem(6,
|
||||
new CustomItem(Material.COMPARATOR, "&e" + SlimefunPlugin.getLocalization().getMessage(p, "guide.title.source"), "", "&7Last Activity: &a" + NumberUtils.getElapsedTime(SlimefunPlugin.getGitHubService().getLastUpdate()) + " ago", "&7Forks: &e" + SlimefunPlugin.getGitHubService().getForks(), "&7Stars: &e" + SlimefunPlugin.getGitHubService().getStars(), "", "&7&oSlimefun 4 is a community project,", "&7&othe source code is available on GitHub", "&7&oand if you want to keep this Plugin alive,", "&7&othen please consider contributing to it", "", "&7\u21E8 &eClick to go to GitHub"));
|
||||
@ -119,6 +125,7 @@ public final class SlimefunGuideSettings {
|
||||
});
|
||||
}
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
private static void addConfigurableOptions(Player p, ChestMenu menu, ItemStack guide) {
|
||||
int i = 19;
|
||||
|
||||
@ -137,11 +144,21 @@ public final class SlimefunGuideSettings {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean hasFireworksEnabled(Player p) {
|
||||
/**
|
||||
* This method checks if the given {@link Player} has enabled the {@link FireworksOption}
|
||||
* in their {@link SlimefunGuide}.
|
||||
* If they enabled this setting, they will see fireworks when they unlock a {@link Research}.
|
||||
*
|
||||
* @param p
|
||||
* The {@link Player}
|
||||
*
|
||||
* @return Whether this {@link Player} wants to see fireworks when unlocking a {@link Research}
|
||||
*/
|
||||
public static boolean hasFireworksEnabled(@Nonnull Player p) {
|
||||
for (SlimefunGuideOption<?> option : options) {
|
||||
if (option instanceof FireworksOption) {
|
||||
FireworksOption fireworks = (FireworksOption) option;
|
||||
return fireworks.getSelectedOption(p, SlimefunGuide.getItem(SlimefunGuideLayout.CHEST)).orElse(true);
|
||||
return fireworks.getSelectedOption(p, SlimefunGuide.getItem(SlimefunGuideMode.SURVIVAL_MODE)).orElse(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,6 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
@ -32,16 +31,14 @@ import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import io.github.thebusybiscuit.cscorelib2.chat.ChatColors;
|
||||
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
|
||||
import io.github.thebusybiscuit.cscorelib2.math.DoubleHandler;
|
||||
import io.github.thebusybiscuit.slimefun4.api.network.Network;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
|
||||
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||
import me.mrCookieSlime.Slimefun.api.BlockStorage;
|
||||
import me.mrCookieSlime.Slimefun.api.Slimefun;
|
||||
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
|
||||
import me.mrCookieSlime.Slimefun.api.inventory.DirtyChestMenu;
|
||||
import me.mrCookieSlime.Slimefun.api.inventory.UniversalBlockMenu;
|
||||
@ -368,7 +365,7 @@ abstract class AbstractItemNetwork extends Network {
|
||||
ItemMeta im = stack.getItemMeta();
|
||||
List<String> lore = new ArrayList<>();
|
||||
lore.add("");
|
||||
lore.add(ChatColors.color("&7Stored Items: &f" + DoubleHandler.getFancyDouble(item.getInt())));
|
||||
lore.add(ChatColors.color("&7Stored Items: &f" + NumberUtils.getCompactDouble(item.getInt())));
|
||||
|
||||
if (stack.getMaxStackSize() > 1) {
|
||||
int amount = item.getInt() > stack.getMaxStackSize() ? stack.getMaxStackSize() : item.getInt();
|
||||
@ -426,12 +423,7 @@ abstract class AbstractItemNetwork extends Network {
|
||||
}
|
||||
} else if (BlockStorage.hasInventory(target)) {
|
||||
BlockMenu blockMenu = BlockStorage.getInventory(target);
|
||||
|
||||
if (blockMenu.getPreset().getID().startsWith("BARREL_")) {
|
||||
gatherItemsFromBarrel(l, blockMenu, items);
|
||||
} else {
|
||||
handleWithdraw(blockMenu, items, l);
|
||||
}
|
||||
handleWithdraw(blockMenu, items, l);
|
||||
} else if (CargoUtils.hasInventory(target)) {
|
||||
BlockState state = PaperLib.getBlockState(target, false).getState();
|
||||
|
||||
@ -445,41 +437,6 @@ abstract class AbstractItemNetwork extends Network {
|
||||
}
|
||||
}
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
private void gatherItemsFromBarrel(Location l, BlockMenu blockMenu, List<ItemStackAndInteger> items) {
|
||||
try {
|
||||
Config cfg = BlockStorage.getLocationInfo(blockMenu.getLocation());
|
||||
String data = cfg.getString("storedItems");
|
||||
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int stored = Integer.parseInt(data);
|
||||
|
||||
for (int slot : blockMenu.getPreset().getSlotsAccessedByItemTransport((DirtyChestMenu) blockMenu, ItemTransportFlow.WITHDRAW, null)) {
|
||||
ItemStack stack = blockMenu.getItemInSlot(slot);
|
||||
|
||||
if (stack != null && CargoUtils.matchesFilter(this, l.getBlock(), stack)) {
|
||||
boolean add = true;
|
||||
|
||||
for (ItemStackAndInteger item : items) {
|
||||
if (SlimefunUtils.isItemSimilar(stack, item.getItemStackWrapper(), true, false)) {
|
||||
add = false;
|
||||
item.add(stack.getAmount() + stored);
|
||||
}
|
||||
}
|
||||
|
||||
if (add) {
|
||||
items.add(new ItemStackAndInteger(stack, stack.getAmount() + stored));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception x) {
|
||||
Slimefun.getLogger().log(Level.SEVERE, "An Exception occurred while trying to read data from a Barrel", x);
|
||||
}
|
||||
}
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
private void handleWithdraw(DirtyChestMenu menu, List<ItemStackAndInteger> items, Location l) {
|
||||
for (int slot : menu.getPreset().getSlotsAccessedByItemTransport(menu, ItemTransportFlow.WITHDRAW, null)) {
|
||||
|
@ -17,10 +17,9 @@ import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import io.github.thebusybiscuit.slimefun4.api.network.Network;
|
||||
import io.github.thebusybiscuit.slimefun4.api.network.NetworkComponent;
|
||||
import io.github.thebusybiscuit.slimefun4.core.attributes.HologramOwner;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.holograms.SimpleHologram;
|
||||
import me.mrCookieSlime.Slimefun.api.BlockStorage;
|
||||
import me.mrCookieSlime.Slimefun.api.Slimefun;
|
||||
|
||||
/**
|
||||
* The {@link CargoNet} is a type of {@link Network} which deals with {@link ItemStack} transportation.
|
||||
@ -37,7 +36,7 @@ import me.mrCookieSlime.Slimefun.api.Slimefun;
|
||||
* @author DNx5
|
||||
*
|
||||
*/
|
||||
public class CargoNet extends AbstractItemNetwork {
|
||||
public class CargoNet extends AbstractItemNetwork implements HologramOwner {
|
||||
|
||||
private static final int RANGE = 5;
|
||||
private static final int TICK_DELAY = SlimefunPlugin.getCfg().getInt("networks.cargo-ticker-delay");
|
||||
@ -74,6 +73,11 @@ public class CargoNet extends AbstractItemNetwork {
|
||||
super(l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "CARGO_NETWORK";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRange() {
|
||||
return RANGE;
|
||||
@ -143,16 +147,16 @@ public class CargoNet extends AbstractItemNetwork {
|
||||
|
||||
public void tick(Block b) {
|
||||
if (!regulator.equals(b.getLocation())) {
|
||||
SimpleHologram.update(b, "&4Multiple Cargo Regulators connected");
|
||||
updateHologram(b, "&4Multiple Cargo Regulators connected");
|
||||
return;
|
||||
}
|
||||
|
||||
super.tick();
|
||||
|
||||
if (connectorNodes.isEmpty() && terminusNodes.isEmpty()) {
|
||||
SimpleHologram.update(b, "&cNo Cargo Nodes found");
|
||||
updateHologram(b, "&cNo Cargo Nodes found");
|
||||
} else {
|
||||
SimpleHologram.update(b, "&7Status: &a&lONLINE");
|
||||
updateHologram(b, "&7Status: &a&lONLINE");
|
||||
|
||||
// Skip ticking if the threshold is not reached. The delay is not same as minecraft tick,
|
||||
// but it's based on 'custom-ticker-delay' config.
|
||||
@ -250,7 +254,7 @@ public class CargoNet extends AbstractItemNetwork {
|
||||
String str = BlockStorage.getLocationInfo(node).getString("frequency");
|
||||
return str == null ? 0 : Integer.parseInt(str);
|
||||
} catch (Exception x) {
|
||||
Slimefun.getLogger().log(Level.SEVERE, x, () -> "An Error occurred while parsing a Cargo Node Frequency (" + node.getWorld().getName() + " - " + node.getBlockX() + "," + node.getBlockY() + "," + +node.getBlockZ() + ")");
|
||||
SlimefunPlugin.logger().log(Level.SEVERE, x, () -> "An Error occurred while parsing a Cargo Node Frequency (" + node.getWorld().getName() + " - " + node.getBlockX() + "," + node.getBlockY() + "," + +node.getBlockZ() + ")");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -16,15 +16,27 @@ import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.InventoryHolder;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import io.github.thebusybiscuit.cscorelib2.inventory.InvUtils;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.itemstack.ItemStackWrapper;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import me.mrCookieSlime.Slimefun.api.BlockStorage;
|
||||
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
|
||||
import me.mrCookieSlime.Slimefun.api.inventory.DirtyChestMenu;
|
||||
import me.mrCookieSlime.Slimefun.api.item_transport.ItemTransportFlow;
|
||||
|
||||
/**
|
||||
* This is a helper class for the {@link CargoNet} which provides
|
||||
* a free static utility methods to let the {@link CargoNet} interact with
|
||||
* an {@link Inventory} or {@link BlockMenu}.
|
||||
*
|
||||
* @author TheBusyBiscuit
|
||||
* @author Walshy
|
||||
* @author DNx5
|
||||
*
|
||||
*/
|
||||
final class CargoUtils {
|
||||
|
||||
/**
|
||||
@ -32,6 +44,10 @@ final class CargoUtils {
|
||||
*/
|
||||
private static final int[] FILTER_SLOTS = { 19, 20, 21, 28, 29, 30, 37, 38, 39 };
|
||||
|
||||
/**
|
||||
* This is a utility class and should not be instantiated.
|
||||
* Therefore we just hide the public constructor.
|
||||
*/
|
||||
private CargoUtils() {}
|
||||
|
||||
/**
|
||||
@ -51,10 +67,6 @@ final class CargoUtils {
|
||||
|
||||
Material type = block.getType();
|
||||
|
||||
if (SlimefunTag.SHULKER_BOXES.isTagged(type)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case CHEST:
|
||||
case TRAPPED_CHEST:
|
||||
@ -68,10 +80,11 @@ final class CargoUtils {
|
||||
case SMOKER:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
return SlimefunTag.SHULKER_BOXES.isTagged(type);
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
static int[] getInputSlotRange(@Nonnull Inventory inv, @Nullable ItemStack item) {
|
||||
if (inv instanceof FurnaceInventory) {
|
||||
if (item != null && item.getType().isFuel()) {
|
||||
@ -101,7 +114,8 @@ final class CargoUtils {
|
||||
}
|
||||
}
|
||||
|
||||
static int[] getOutputSlotRange(Inventory inv) {
|
||||
@Nonnull
|
||||
static int[] getOutputSlotRange(@Nonnull Inventory inv) {
|
||||
if (inv instanceof FurnaceInventory) {
|
||||
// Slot 2-3
|
||||
return new int[] { 2, 3 };
|
||||
@ -114,6 +128,7 @@ final class CargoUtils {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static ItemStack withdraw(AbstractItemNetwork network, Map<Location, Inventory> inventories, Block node, Block target, ItemStack template) {
|
||||
DirtyChestMenu menu = getChestMenu(target);
|
||||
|
||||
@ -145,7 +160,7 @@ final class CargoUtils {
|
||||
if (SlimefunUtils.isItemSimilar(is, wrapper, true) && matchesFilter(network, node, is)) {
|
||||
if (is.getAmount() > template.getAmount()) {
|
||||
is.setAmount(is.getAmount() - template.getAmount());
|
||||
menu.replaceExistingItem(slot, is.clone());
|
||||
menu.replaceExistingItem(slot, is);
|
||||
return template;
|
||||
} else {
|
||||
menu.replaceExistingItem(slot, null);
|
||||
@ -157,6 +172,7 @@ final class CargoUtils {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static ItemStack withdrawFromVanillaInventory(AbstractItemNetwork network, Block node, ItemStack template, Inventory inv) {
|
||||
ItemStack[] contents = inv.getContents();
|
||||
int[] range = getOutputSlotRange(inv);
|
||||
@ -184,6 +200,7 @@ final class CargoUtils {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static ItemStackAndInteger withdraw(AbstractItemNetwork network, Map<Location, Inventory> inventories, Block node, Block target) {
|
||||
DirtyChestMenu menu = getChestMenu(target);
|
||||
|
||||
@ -215,6 +232,7 @@ final class CargoUtils {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static ItemStackAndInteger withdrawFromVanillaInventory(AbstractItemNetwork network, Block node, Inventory inv) {
|
||||
ItemStack[] contents = inv.getContents();
|
||||
int[] range = getOutputSlotRange(inv);
|
||||
@ -233,6 +251,7 @@ final class CargoUtils {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static ItemStack insert(AbstractItemNetwork network, Map<Location, Inventory> inventories, Block node, Block target, ItemStack stack) {
|
||||
if (!matchesFilter(network, node, stack)) {
|
||||
return stack;
|
||||
@ -273,7 +292,7 @@ final class CargoUtils {
|
||||
int maxStackSize = itemInSlot.getType().getMaxStackSize();
|
||||
int currentAmount = itemInSlot.getAmount();
|
||||
|
||||
if (SlimefunUtils.isItemSimilar(itemInSlot, wrapper, true, false) && currentAmount < maxStackSize) {
|
||||
if (currentAmount < maxStackSize && SlimefunUtils.isItemSimilar(itemInSlot, wrapper, true, false)) {
|
||||
int amount = currentAmount + stack.getAmount();
|
||||
|
||||
itemInSlot.setAmount(Math.min(amount, maxStackSize));
|
||||
@ -291,7 +310,16 @@ final class CargoUtils {
|
||||
return stack;
|
||||
}
|
||||
|
||||
private static ItemStack insertIntoVanillaInventory(ItemStack stack, Inventory inv) {
|
||||
@Nullable
|
||||
private static ItemStack insertIntoVanillaInventory(@Nonnull ItemStack stack, @Nonnull Inventory inv) {
|
||||
/*
|
||||
* If the Inventory does not accept this Item Type, bounce the item back.
|
||||
* Example: Shulker boxes within shulker boxes (fixes #2662)
|
||||
*/
|
||||
if (!InvUtils.isItemAllowed(stack.getType(), inv.getType())) {
|
||||
return stack;
|
||||
}
|
||||
|
||||
ItemStack[] contents = inv.getContents();
|
||||
int[] range = getInputSlotRange(inv, stack);
|
||||
int minSlot = range[0];
|
||||
@ -309,17 +337,17 @@ final class CargoUtils {
|
||||
} else {
|
||||
int maxStackSize = itemInSlot.getType().getMaxStackSize();
|
||||
|
||||
if (SlimefunUtils.isItemSimilar(itemInSlot, wrapper, true, false) && itemInSlot.getAmount() < maxStackSize) {
|
||||
if (itemInSlot.getAmount() < maxStackSize && SlimefunUtils.isItemSimilar(itemInSlot, wrapper, true, false)) {
|
||||
int amount = itemInSlot.getAmount() + stack.getAmount();
|
||||
|
||||
if (amount > maxStackSize) {
|
||||
stack.setAmount(amount - maxStackSize);
|
||||
itemInSlot.setAmount(Math.min(amount, maxStackSize));
|
||||
return stack;
|
||||
} else {
|
||||
stack = null;
|
||||
itemInSlot.setAmount(Math.min(amount, maxStackSize));
|
||||
return null;
|
||||
}
|
||||
|
||||
itemInSlot.setAmount(Math.min(amount, maxStackSize));
|
||||
return stack;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -327,12 +355,13 @@ final class CargoUtils {
|
||||
return stack;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static DirtyChestMenu getChestMenu(@Nonnull Block block) {
|
||||
if (BlockStorage.hasInventory(block)) {
|
||||
return BlockStorage.getInventory(block);
|
||||
} else {
|
||||
return BlockStorage.getUniversalInventory(block);
|
||||
}
|
||||
|
||||
return BlockStorage.getUniversalInventory(block);
|
||||
}
|
||||
|
||||
static boolean matchesFilter(@Nonnull AbstractItemNetwork network, @Nonnull Block node, @Nullable ItemStack item) {
|
||||
@ -365,20 +394,12 @@ final class CargoUtils {
|
||||
}
|
||||
|
||||
private static boolean isPotion(@Nullable ItemStack item) {
|
||||
return item != null && (item.getType() == Material.POTION || item.getType() == Material.SPLASH_POTION || item.getType() == Material.LINGERING_POTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the whitelist/blacklist slots in a Cargo Input Node. If you wish to access the items
|
||||
* in the cargo (without hardcoding the slots in case of change) then you can use this method.
|
||||
*
|
||||
* @deprecated Renamed to {@link #getFilteringSlots()}
|
||||
*
|
||||
* @return The slot indexes for the whitelist/blacklist section.
|
||||
*/
|
||||
@Deprecated
|
||||
public static int[] getWhitelistBlacklistSlots() {
|
||||
return FILTER_SLOTS;
|
||||
if (item != null) {
|
||||
Material type = item.getType();
|
||||
return type == Material.POTION || type == Material.SPLASH_POTION || type == Material.LINGERING_POTION;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -387,6 +408,7 @@ final class CargoUtils {
|
||||
*
|
||||
* @return The slots where the {@link ItemFilter} section for a cargo node sits
|
||||
*/
|
||||
@Nonnull
|
||||
public static int[] getFilteringSlots() {
|
||||
return FILTER_SLOTS;
|
||||
}
|
||||
|
@ -20,10 +20,10 @@ import io.github.thebusybiscuit.slimefun4.api.network.Network;
|
||||
import io.github.thebusybiscuit.slimefun4.api.network.NetworkComponent;
|
||||
import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent;
|
||||
import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetProvider;
|
||||
import io.github.thebusybiscuit.slimefun4.core.attributes.HologramOwner;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.holograms.SimpleHologram;
|
||||
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
|
||||
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||
import me.mrCookieSlime.Slimefun.api.BlockStorage;
|
||||
@ -41,7 +41,7 @@ import me.mrCookieSlime.Slimefun.api.BlockStorage;
|
||||
* @see EnergyNetComponentType
|
||||
*
|
||||
*/
|
||||
public class EnergyNet extends Network {
|
||||
public class EnergyNet extends Network implements HologramOwner {
|
||||
|
||||
private static final int RANGE = 6;
|
||||
|
||||
@ -58,6 +58,11 @@ public class EnergyNet extends Network {
|
||||
return RANGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "ENERGY_NETWORK";
|
||||
}
|
||||
|
||||
@Override
|
||||
public NetworkComponent classifyLocation(@Nonnull Location l) {
|
||||
if (regulator.equals(l)) {
|
||||
@ -116,7 +121,7 @@ public class EnergyNet extends Network {
|
||||
AtomicLong timestamp = new AtomicLong(SlimefunPlugin.getProfiler().newEntry());
|
||||
|
||||
if (!regulator.equals(b.getLocation())) {
|
||||
SimpleHologram.update(b, "&4Multiple Energy Regulators connected");
|
||||
updateHologram(b, "&4Multiple Energy Regulators connected");
|
||||
SlimefunPlugin.getProfiler().closeEntry(b.getLocation(), SlimefunItems.ENERGY_REGULATOR.getItem(), timestamp.get());
|
||||
return;
|
||||
}
|
||||
@ -124,7 +129,7 @@ public class EnergyNet extends Network {
|
||||
super.tick();
|
||||
|
||||
if (connectorNodes.isEmpty() && terminusNodes.isEmpty()) {
|
||||
SimpleHologram.update(b, "&4No Energy Network found");
|
||||
updateHologram(b, "&4No Energy Network found");
|
||||
} else {
|
||||
int supply = tickAllGenerators(timestamp::getAndAdd) + tickAllCapacitors();
|
||||
int remainingEnergy = supply;
|
||||
@ -258,10 +263,10 @@ public class EnergyNet extends Network {
|
||||
private void updateHologram(@Nonnull Block b, double supply, double demand) {
|
||||
if (demand > supply) {
|
||||
String netLoss = NumberUtils.getCompactDouble(demand - supply);
|
||||
SimpleHologram.update(b, "&4&l- &c" + netLoss + " &7J &e\u26A1");
|
||||
updateHologram(b, "&4&l- &c" + netLoss + " &7J &e\u26A1");
|
||||
} else {
|
||||
String netGain = NumberUtils.getCompactDouble(supply - demand);
|
||||
SimpleHologram.update(b, "&2&l+ &a" + netGain + " &7J &e\u26A1");
|
||||
updateHologram(b, "&2&l+ &a" + netGain + " &7J &e\u26A1");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,129 @@
|
||||
package io.github.thebusybiscuit.slimefun4.core.researching;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
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.implementation.SlimefunPlugin;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.FireworkUtils;
|
||||
|
||||
/**
|
||||
* A {@link PlayerResearchTask} is run when a {@link Player} unlocks a {@link Research}.
|
||||
*
|
||||
* @author TheBusyBiscuit
|
||||
*
|
||||
* @see Research
|
||||
* @see ResearchUnlockEvent
|
||||
* @see PlayerProfile
|
||||
*
|
||||
*/
|
||||
public class PlayerResearchTask implements Consumer<PlayerProfile> {
|
||||
|
||||
private static final int[] RESEARCH_PROGRESS = { 23, 44, 57, 92 };
|
||||
private static final String PLACEHOLDER = "%research%";
|
||||
|
||||
private final Research research;
|
||||
private final boolean isInstant;
|
||||
private final Consumer<Player> callback;
|
||||
|
||||
/**
|
||||
* This constructs a new {@link PlayerResearchTask}.
|
||||
*
|
||||
* @param research
|
||||
* The {@link Research} to unlock
|
||||
* @param isInstant
|
||||
* Whether to unlock this {@link Research} instantaneously
|
||||
* @param callback
|
||||
* The callback to run when the task has completed
|
||||
*/
|
||||
PlayerResearchTask(@Nonnull Research research, boolean isInstant, @Nullable Consumer<Player> callback) {
|
||||
Validate.notNull(research, "The Research must not be null");
|
||||
|
||||
this.research = research;
|
||||
this.isInstant = isInstant;
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(PlayerProfile profile) {
|
||||
if (!profile.hasUnlocked(research)) {
|
||||
Player p = profile.getPlayer();
|
||||
|
||||
if (p == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isInstant) {
|
||||
SlimefunPlugin.runSync(() -> {
|
||||
p.playSound(p.getLocation(), Sound.ENTITY_BAT_TAKEOFF, 0.7F, 1F);
|
||||
SlimefunPlugin.getLocalization().sendMessage(p, "messages.research.progress", true, msg -> msg.replace(PLACEHOLDER, research.getName(p)).replace("%progress%", "0%"));
|
||||
}, 5L);
|
||||
}
|
||||
|
||||
ResearchUnlockEvent event = new ResearchUnlockEvent(p, research);
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
|
||||
if (!event.isCancelled()) {
|
||||
if (isInstant) {
|
||||
SlimefunPlugin.runSync(() -> unlockResearch(p, profile));
|
||||
} else if (SlimefunPlugin.getRegistry().getCurrentlyResearchingPlayers().add(p.getUniqueId())) {
|
||||
SlimefunPlugin.getLocalization().sendMessage(p, "messages.research.start", true, msg -> msg.replace(PLACEHOLDER, research.getName(p)));
|
||||
sendUpdateMessage(p);
|
||||
|
||||
SlimefunPlugin.runSync(() -> {
|
||||
unlockResearch(p, profile);
|
||||
SlimefunPlugin.getRegistry().getCurrentlyResearchingPlayers().remove(p.getUniqueId());
|
||||
}, (RESEARCH_PROGRESS.length + 1) * 20L);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void sendUpdateMessage(@Nonnull Player p) {
|
||||
for (int i = 1; i < RESEARCH_PROGRESS.length + 1; i++) {
|
||||
int index = i;
|
||||
|
||||
SlimefunPlugin.runSync(() -> {
|
||||
p.playSound(p.getLocation(), Sound.ENTITY_BAT_TAKEOFF, 0.7F, 1);
|
||||
|
||||
SlimefunPlugin.getLocalization().sendMessage(p, "messages.research.progress", true, msg -> {
|
||||
String progress = RESEARCH_PROGRESS[index - 1] + "%";
|
||||
return msg.replace(PLACEHOLDER, research.getName(p)).replace("%progress%", progress);
|
||||
});
|
||||
}, i * 20L);
|
||||
}
|
||||
}
|
||||
|
||||
private void unlockResearch(@Nonnull Player p, @Nonnull PlayerProfile profile) {
|
||||
profile.setResearched(research, true);
|
||||
SlimefunPlugin.getLocalization().sendMessage(p, "messages.unlocked", true, msg -> msg.replace(PLACEHOLDER, research.getName(p)));
|
||||
onFinish(p);
|
||||
|
||||
// Check if the Server and the Player have enabled fireworks for researches
|
||||
if (SlimefunPlugin.getRegistry().isResearchFireworkEnabled() && SlimefunGuideSettings.hasFireworksEnabled(p)) {
|
||||
FireworkUtils.launchRandom(p, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called when the {@link Research} successfully finished to unlock.
|
||||
*
|
||||
* @param p
|
||||
* The {@link Player} who has unlocked this {@link Research}
|
||||
*/
|
||||
private void onFinish(@Nonnull Player p) {
|
||||
if (callback != null) {
|
||||
callback.accept(p);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -15,19 +15,16 @@ import org.bukkit.Bukkit;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Keyed;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import io.github.thebusybiscuit.slimefun4.api.events.PlayerPreResearchEvent;
|
||||
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.guide.SlimefunGuideImplementation;
|
||||
import io.github.thebusybiscuit.slimefun4.core.services.localization.Language;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.setup.ResearchSetup;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.FireworkUtils;
|
||||
import io.github.thebusybiscuit.slimefun4.api.events.PlayerPreResearchEvent;
|
||||
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideImplementation;
|
||||
import me.mrCookieSlime.Slimefun.Objects.Category;
|
||||
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||
|
||||
@ -43,9 +40,6 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||
*/
|
||||
public class Research implements Keyed {
|
||||
|
||||
private static final int[] RESEARCH_PROGRESS = { 23, 44, 57, 92 };
|
||||
private static final String PLACEHOLDER_RESEARCH = "%research%";
|
||||
|
||||
private final NamespacedKey key;
|
||||
private final int id;
|
||||
private final String name;
|
||||
@ -258,7 +252,7 @@ public class Research implements Keyed {
|
||||
* Whether to unlock it instantly
|
||||
*/
|
||||
public void unlock(@Nonnull Player p, boolean instant) {
|
||||
unlock(p, instant, pl -> {});
|
||||
unlock(p, instant, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -266,62 +260,13 @@ public class Research implements Keyed {
|
||||
*
|
||||
* @param p
|
||||
* The {@link Player} for which to unlock this {@link Research}
|
||||
* @param instant
|
||||
* @param isInstant
|
||||
* Whether to unlock this {@link Research} instantly
|
||||
* @param callback
|
||||
* A callback which will be run when the {@link Research} animation completed
|
||||
*/
|
||||
public void unlock(@Nonnull Player p, boolean instant, @Nonnull Consumer<Player> callback) {
|
||||
if (!instant) {
|
||||
SlimefunPlugin.runSync(() -> {
|
||||
p.playSound(p.getLocation(), Sound.ENTITY_BAT_TAKEOFF, 0.7F, 1F);
|
||||
SlimefunPlugin.getLocalization().sendMessage(p, "messages.research.progress", true, msg -> msg.replace(PLACEHOLDER_RESEARCH, getName(p)).replace("%progress%", "0%"));
|
||||
}, 10L);
|
||||
}
|
||||
|
||||
PlayerProfile.get(p, profile -> {
|
||||
if (!profile.hasUnlocked(this)) {
|
||||
SlimefunPlugin.runSync(() -> {
|
||||
ResearchUnlockEvent event = new ResearchUnlockEvent(p, this);
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
|
||||
if (!event.isCancelled()) {
|
||||
if (instant) {
|
||||
finishResearch(p, profile, callback);
|
||||
} else if (SlimefunPlugin.getRegistry().getCurrentlyResearchingPlayers().add(p.getUniqueId())) {
|
||||
SlimefunPlugin.getLocalization().sendMessage(p, "messages.research.start", true, msg -> msg.replace(PLACEHOLDER_RESEARCH, getName(p)));
|
||||
playResearchAnimation(p);
|
||||
|
||||
SlimefunPlugin.runSync(() -> {
|
||||
finishResearch(p, profile, callback);
|
||||
SlimefunPlugin.getRegistry().getCurrentlyResearchingPlayers().remove(p.getUniqueId());
|
||||
}, (RESEARCH_PROGRESS.length + 1) * 20L);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void finishResearch(@Nonnull Player p, @Nonnull PlayerProfile profile, @Nonnull Consumer<Player> callback) {
|
||||
profile.setResearched(this, true);
|
||||
SlimefunPlugin.getLocalization().sendMessage(p, "messages.unlocked", true, msg -> msg.replace(PLACEHOLDER_RESEARCH, getName(p)));
|
||||
callback.accept(p);
|
||||
|
||||
if (SlimefunPlugin.getRegistry().isResearchFireworkEnabled() && SlimefunGuideSettings.hasFireworksEnabled(p)) {
|
||||
FireworkUtils.launchRandom(p, 1);
|
||||
}
|
||||
}
|
||||
|
||||
private void playResearchAnimation(@Nonnull Player p) {
|
||||
for (int i = 1; i < RESEARCH_PROGRESS.length + 1; i++) {
|
||||
int j = i;
|
||||
|
||||
SlimefunPlugin.runSync(() -> {
|
||||
p.playSound(p.getLocation(), Sound.ENTITY_BAT_TAKEOFF, 0.7F, 1F);
|
||||
SlimefunPlugin.getLocalization().sendMessage(p, "messages.research.progress", true, msg -> msg.replace(PLACEHOLDER_RESEARCH, getName(p)).replace("%progress%", RESEARCH_PROGRESS[j - 1] + "%"));
|
||||
}, i * 20L);
|
||||
}
|
||||
public void unlock(@Nonnull Player p, boolean isInstant, @Nullable Consumer<Player> callback) {
|
||||
PlayerProfile.get(p, new PlayerResearchTask(this, isInstant, callback));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -329,7 +274,6 @@ public class Research implements Keyed {
|
||||
*/
|
||||
public void register() {
|
||||
SlimefunPlugin.getResearchCfg().setDefaultValue("enable-researching", true);
|
||||
|
||||
String path = key.getNamespace() + '.' + key.getKey();
|
||||
|
||||
if (SlimefunPlugin.getResearchCfg().contains(path + ".enabled") && !SlimefunPlugin.getResearchCfg().getBoolean(path + ".enabled")) {
|
||||
|
@ -15,7 +15,6 @@ import org.bukkit.entity.Player;
|
||||
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
import me.mrCookieSlime.Slimefun.api.BlockStorage;
|
||||
import me.mrCookieSlime.Slimefun.api.Slimefun;
|
||||
|
||||
/**
|
||||
* This Service is responsible for automatically saving {@link Player} and {@link Block}
|
||||
@ -66,7 +65,7 @@ public class AutoSavingService {
|
||||
}
|
||||
|
||||
if (players > 0) {
|
||||
Slimefun.getLogger().log(Level.INFO, "Auto-saved all player data for {0} player(s)!", players);
|
||||
SlimefunPlugin.logger().log(Level.INFO, "Auto-saved all player data for {0} player(s)!", players);
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,7 +88,7 @@ public class AutoSavingService {
|
||||
}
|
||||
|
||||
if (!worlds.isEmpty()) {
|
||||
Slimefun.getLogger().log(Level.INFO, "Auto-saving block data... (Next auto-save: {0}m)", interval);
|
||||
SlimefunPlugin.logger().log(Level.INFO, "Auto-saving block data... (Next auto-save: {0}m)", interval);
|
||||
|
||||
for (BlockStorage storage : worlds) {
|
||||
storage.save();
|
||||
|
@ -20,7 +20,6 @@ import javax.annotation.Nonnull;
|
||||
import org.apache.commons.lang.Validate;
|
||||
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
import me.mrCookieSlime.Slimefun.api.Slimefun;
|
||||
|
||||
/**
|
||||
* This Service creates a Backup of your Slimefun world data on every server shutdown.
|
||||
@ -43,7 +42,7 @@ public class BackupService implements Runnable {
|
||||
try {
|
||||
purgeBackups(backups);
|
||||
} catch (IOException e) {
|
||||
Slimefun.getLogger().log(Level.WARNING, "Could not delete an old backup", e);
|
||||
SlimefunPlugin.logger().log(Level.WARNING, "Could not delete an old backup", e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,12 +55,12 @@ public class BackupService implements Runnable {
|
||||
createBackup(output);
|
||||
}
|
||||
|
||||
Slimefun.getLogger().log(Level.INFO, "Backed up Slimefun data to: {0}", file.getName());
|
||||
SlimefunPlugin.logger().log(Level.INFO, "Backed up Slimefun data to: {0}", file.getName());
|
||||
} else {
|
||||
Slimefun.getLogger().log(Level.WARNING, "Could not create backup-file: {0}", file.getName());
|
||||
SlimefunPlugin.logger().log(Level.WARNING, "Could not create backup-file: {0}", file.getName());
|
||||
}
|
||||
} catch (IOException x) {
|
||||
Slimefun.getLogger().log(Level.SEVERE, x, () -> "An Error occurred while creating a backup for Slimefun " + SlimefunPlugin.getVersion());
|
||||
SlimefunPlugin.logger().log(Level.SEVERE, x, () -> "An Error occurred while creating a backup for Slimefun " + SlimefunPlugin.getVersion());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,8 +19,8 @@ import org.bukkit.persistence.PersistentDataHolder;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import me.mrCookieSlime.Slimefun.api.Slimefun;
|
||||
|
||||
/**
|
||||
* The {@link BlockDataService} is similar to the {@link CustomItemDataService},
|
||||
@ -78,12 +78,12 @@ public class BlockDataService implements Keyed {
|
||||
container.set(namespacedKey, PersistentDataType.STRING, value);
|
||||
state.update();
|
||||
} catch (Exception x) {
|
||||
Slimefun.getLogger().log(Level.SEVERE, "Please check if your Server Software is up to date!");
|
||||
SlimefunPlugin.logger().log(Level.SEVERE, "Please check if your Server Software is up to date!");
|
||||
|
||||
String serverSoftware = PaperLib.isSpigot() && !PaperLib.isPaper() ? "Spigot" : Bukkit.getName();
|
||||
Slimefun.getLogger().log(Level.SEVERE, () -> serverSoftware + " | " + Bukkit.getVersion() + " | " + Bukkit.getBukkitVersion());
|
||||
SlimefunPlugin.logger().log(Level.SEVERE, () -> serverSoftware + " | " + Bukkit.getVersion() + " | " + Bukkit.getBukkitVersion());
|
||||
|
||||
Slimefun.getLogger().log(Level.SEVERE, "An Exception was thrown while trying to set Persistent Data for a Block", x);
|
||||
SlimefunPlugin.logger().log(Level.SEVERE, "An Exception was thrown while trying to set Persistent Data for a Block", x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,9 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
|
||||
*/
|
||||
public class CustomItemDataService implements Keyed {
|
||||
|
||||
/**
|
||||
* This is the {@link NamespacedKey} used to store/read data.
|
||||
*/
|
||||
private final NamespacedKey namespacedKey;
|
||||
|
||||
/**
|
||||
|
@ -23,11 +23,10 @@ import org.bukkit.entity.Player;
|
||||
import org.bukkit.persistence.PersistentDataContainer;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
|
||||
import io.github.thebusybiscuit.cscorelib2.math.DoubleHandler;
|
||||
import io.github.thebusybiscuit.slimefun4.core.services.localization.Language;
|
||||
import io.github.thebusybiscuit.slimefun4.core.services.localization.SlimefunLocalization;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
import me.mrCookieSlime.Slimefun.api.Slimefun;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
|
||||
|
||||
/**
|
||||
* As the name suggests, this Service is responsible for Localization.
|
||||
@ -78,7 +77,7 @@ public class LocalizationService extends SlimefunLocalization {
|
||||
plugin.getLogger().log(Level.WARNING, "Could not recognize the given language: \"{0}\"", serverDefaultLanguage);
|
||||
}
|
||||
|
||||
Slimefun.getLogger().log(Level.INFO, "Available languages: {0}", String.join(", ", languages.keySet()));
|
||||
SlimefunPlugin.logger().log(Level.INFO, "Available languages: {0}", String.join(", ", languages.keySet()));
|
||||
save();
|
||||
} else {
|
||||
translationsEnabled = false;
|
||||
@ -178,7 +177,7 @@ public class LocalizationService extends SlimefunLocalization {
|
||||
defaultLanguage.setCategoriesFile(streamConfigFile("categories_" + language + ".yml", null));
|
||||
defaultLanguage.setRecipeTypesFile(streamConfigFile("recipes_" + language + ".yml", null));
|
||||
|
||||
Slimefun.getLogger().log(Level.INFO, "Loaded language \"{0}\"", language);
|
||||
SlimefunPlugin.logger().log(Level.INFO, "Loaded language \"{0}\"", language);
|
||||
getConfig().setValue(LANGUAGE_PATH, language);
|
||||
|
||||
// Loading in the defaults from our resources folder
|
||||
@ -188,7 +187,7 @@ public class LocalizationService extends SlimefunLocalization {
|
||||
FileConfiguration config = YamlConfiguration.loadConfiguration(reader);
|
||||
getConfig().getConfiguration().setDefaults(config);
|
||||
} catch (IOException e) {
|
||||
Slimefun.getLogger().log(Level.SEVERE, e, () -> "Failed to load language file: \"" + path + "\"");
|
||||
SlimefunPlugin.logger().log(Level.SEVERE, e, () -> "Failed to load language file: \"" + path + "\"");
|
||||
}
|
||||
|
||||
save();
|
||||
@ -245,13 +244,15 @@ public class LocalizationService extends SlimefunLocalization {
|
||||
}
|
||||
}
|
||||
|
||||
return Math.min(DoubleHandler.fixDouble(100.0 * (matches / (double) defaultKeys.size())), 100.0);
|
||||
return Math.min(NumberUtils.reparseDouble(100.0 * (matches / (double) defaultKeys.size())), 100.0);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private Set<String> getTotalKeys(@Nonnull Language lang) {
|
||||
return getKeys(lang.getFiles());
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private Set<String> getKeys(FileConfiguration... files) {
|
||||
Set<String> keys = new HashSet<>();
|
||||
|
||||
@ -278,7 +279,7 @@ public class LocalizationService extends SlimefunLocalization {
|
||||
|
||||
return config;
|
||||
} catch (IOException e) {
|
||||
Slimefun.getLogger().log(Level.SEVERE, e, () -> "Failed to load language file into memory: \"" + path + "\"");
|
||||
SlimefunPlugin.logger().log(Level.SEVERE, e, () -> "Failed to load language file into memory: \"" + path + "\"");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -20,14 +20,14 @@ import org.bukkit.plugin.Plugin;
|
||||
|
||||
import io.github.thebusybiscuit.cscorelib2.recipes.MinecraftRecipe;
|
||||
import io.github.thebusybiscuit.cscorelib2.recipes.RecipeSnapshot;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.guide.ChestSlimefunGuide;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.guide.SurvivalSlimefunGuide;
|
||||
|
||||
/**
|
||||
* This Service is responsible for accessing a {@link RecipeSnapshot}.
|
||||
* This snapshot contains a compiled list of all recipes that could be found on the
|
||||
* Server at the time the Service was loaded.
|
||||
*
|
||||
* This Service is primarily used by the {@link ChestSlimefunGuide}.
|
||||
* This Service is primarily used by the {@link SurvivalSlimefunGuide}.
|
||||
*
|
||||
* @author TheBusyBiscuit
|
||||
*
|
||||
|
@ -1,6 +1,6 @@
|
||||
package io.github.thebusybiscuit.slimefun4.core.services.github;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -9,49 +9,23 @@ import java.util.logging.Level;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
import kong.unirest.JsonNode;
|
||||
import kong.unirest.json.JSONArray;
|
||||
import kong.unirest.json.JSONObject;
|
||||
import me.mrCookieSlime.Slimefun.api.Slimefun;
|
||||
|
||||
class ContributionsConnector extends GitHubConnector {
|
||||
|
||||
/*
|
||||
* @formatter:off
|
||||
/**
|
||||
* GitHub Bots that do not count as Contributors
|
||||
* (includes "invalid-email-address" because it is an invalid contributor)
|
||||
*/
|
||||
private static final List<String> blacklist = Arrays.asList(
|
||||
"invalid-email-address",
|
||||
"renovate-bot",
|
||||
"TheBusyBot",
|
||||
"ImgBotApp",
|
||||
"imgbot",
|
||||
"imgbot[bot]",
|
||||
"github-actions[bot]",
|
||||
"gitlocalize-app",
|
||||
"gitlocalize-app[bot]",
|
||||
"mt-gitlocalize"
|
||||
);
|
||||
private final List<String> ignoredAccounts = new ArrayList<>();
|
||||
|
||||
/*
|
||||
* @formatter:on
|
||||
/**
|
||||
* Matches a GitHub name with a Minecraft name.
|
||||
*/
|
||||
private static final Map<String, String> aliases = new HashMap<>();
|
||||
|
||||
// Should probably be switched to UUIDs at some point...
|
||||
static {
|
||||
aliases.put("WalshyDev", "HumanRightsAct");
|
||||
aliases.put("J3fftw1", "_lagpc_");
|
||||
aliases.put("ajan-12", "ajan_12");
|
||||
aliases.put("mrcoffee1026", "mr_coffee1026");
|
||||
aliases.put("Cyber-MC", "CyberPatriot");
|
||||
aliases.put("BurningBrimstone", "Bluedevil74");
|
||||
aliases.put("bverhoeven", "soczol");
|
||||
aliases.put("ramdon-person", "ramdon_person");
|
||||
aliases.put("NCBPFluffyBear", "FluffyBear_");
|
||||
}
|
||||
private final Map<String, String> aliases = new HashMap<>();
|
||||
|
||||
private final String prefix;
|
||||
private final String role;
|
||||
@ -66,6 +40,36 @@ class ContributionsConnector extends GitHubConnector {
|
||||
this.prefix = prefix;
|
||||
this.page = page;
|
||||
this.role = role;
|
||||
|
||||
loadConfiguration();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method loads all aliases.
|
||||
* This mapping matches a GitHub username with a Minecraft username.
|
||||
* These people are... "special cases".
|
||||
*/
|
||||
private void loadConfiguration() {
|
||||
ignoredAccounts.add("invalid-email-address");
|
||||
ignoredAccounts.add("renovate-bot");
|
||||
ignoredAccounts.add("TheBusyBot");
|
||||
ignoredAccounts.add("ImgBotApp");
|
||||
ignoredAccounts.add("imgbot");
|
||||
ignoredAccounts.add("imgbot[bot]");
|
||||
ignoredAccounts.add("github-actions[bot]");
|
||||
ignoredAccounts.add("gitlocalize-app");
|
||||
ignoredAccounts.add("gitlocalize-app[bot]");
|
||||
ignoredAccounts.add("mt-gitlocalize");
|
||||
|
||||
aliases.put("WalshyDev", "HumanRightsAct");
|
||||
aliases.put("J3fftw1", "_lagpc_");
|
||||
aliases.put("ajan-12", "ajan_12");
|
||||
aliases.put("mrcoffee1026", "mr_coffee1026");
|
||||
aliases.put("Cyber-MC", "CyberPatriot");
|
||||
aliases.put("BurningBrimstone", "Bluedevil74");
|
||||
aliases.put("bverhoeven", "soczol");
|
||||
aliases.put("ramdon-person", "ramdon_person");
|
||||
aliases.put("NCBPFluffyBear", "FluffyBear_");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -84,7 +88,7 @@ class ContributionsConnector extends GitHubConnector {
|
||||
if (response.isArray()) {
|
||||
computeContributors(response.getArray());
|
||||
} else {
|
||||
Slimefun.getLogger().log(Level.WARNING, "Received an unusual answer from GitHub, possibly a timeout? ({0})", response);
|
||||
SlimefunPlugin.logger().log(Level.WARNING, "Received an unusual answer from GitHub, possibly a timeout? ({0})", response);
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,7 +123,7 @@ class ContributionsConnector extends GitHubConnector {
|
||||
int commits = object.getInt("contributions");
|
||||
String profile = object.getString("html_url");
|
||||
|
||||
if (!blacklist.contains(name)) {
|
||||
if (!ignoredAccounts.contains(name)) {
|
||||
String username = aliases.getOrDefault(name, name);
|
||||
github.addContributor(username, profile, role, commits);
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ import javax.annotation.Nullable;
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.ChatColor;
|
||||
|
||||
import io.github.thebusybiscuit.cscorelib2.data.ComputedOptional;
|
||||
import io.github.thebusybiscuit.cscorelib2.data.TriStateOptional;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.HeadTexture;
|
||||
|
||||
@ -35,7 +35,7 @@ public class Contributor {
|
||||
private final String profileLink;
|
||||
|
||||
private final ConcurrentMap<String, Integer> contributions = new ConcurrentHashMap<>();
|
||||
private final ComputedOptional<String> headTexture = ComputedOptional.createNew();
|
||||
private final TriStateOptional<String> headTexture = TriStateOptional.createNew();
|
||||
|
||||
private Optional<UUID> uuid = Optional.empty();
|
||||
private boolean immutable = false;
|
||||
@ -179,12 +179,26 @@ public class Contributor {
|
||||
*/
|
||||
@Nonnull
|
||||
public String getTexture() {
|
||||
if (!headTexture.isComputed() || !headTexture.isPresent()) {
|
||||
GitHubService github = SlimefunPlugin.getGitHubService();
|
||||
return getTexture(SlimefunPlugin.getGitHubService());
|
||||
}
|
||||
|
||||
if (github != null) {
|
||||
String cached = github.getCachedTexture(githubUsername);
|
||||
return cached != null ? cached : HeadTexture.UNKNOWN.getTexture();
|
||||
/**
|
||||
* Returns this contributor's head texture.
|
||||
* If no texture could be found, or it hasn't been pulled yet,
|
||||
* then it will return a placeholder texture.
|
||||
*
|
||||
* @param github
|
||||
* Our {@link GitHubService} instance
|
||||
*
|
||||
* @return A Base64-Head Texture
|
||||
*/
|
||||
@Nonnull
|
||||
protected String getTexture(@Nonnull GitHubService github) {
|
||||
if (!headTexture.isComputed() || !headTexture.isPresent()) {
|
||||
String cached = github.getCachedTexture(githubUsername);
|
||||
|
||||
if (cached != null) {
|
||||
return cached;
|
||||
} else {
|
||||
return HeadTexture.UNKNOWN.getTexture();
|
||||
}
|
||||
|
@ -14,12 +14,12 @@ import java.util.logging.Level;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
import kong.unirest.HttpResponse;
|
||||
import kong.unirest.JsonNode;
|
||||
import kong.unirest.Unirest;
|
||||
import kong.unirest.UnirestException;
|
||||
import kong.unirest.json.JSONException;
|
||||
import me.mrCookieSlime.Slimefun.api.Slimefun;
|
||||
|
||||
/**
|
||||
* The {@link GitHubConnector} is used to connect to the GitHub API service.
|
||||
@ -100,7 +100,7 @@ abstract class GitHubConnector {
|
||||
file = new File("plugins/Slimefun/cache/github/" + getFileName() + ".json");
|
||||
|
||||
if (github.isLoggingEnabled()) {
|
||||
Slimefun.getLogger().log(Level.INFO, "Retrieving {0}.json from GitHub...", getFileName());
|
||||
SlimefunPlugin.logger().log(Level.INFO, "Retrieving {0}.json from GitHub...", getFileName());
|
||||
}
|
||||
|
||||
try {
|
||||
@ -116,7 +116,7 @@ abstract class GitHubConnector {
|
||||
writeCacheFile(response.getBody());
|
||||
} else {
|
||||
if (github.isLoggingEnabled()) {
|
||||
Slimefun.getLogger().log(Level.WARNING, "Failed to fetch {0}: {1} - {2}", new Object[] { url, response.getStatus(), response.getBody() });
|
||||
SlimefunPlugin.logger().log(Level.WARNING, "Failed to fetch {0}: {1} - {2}", new Object[] { url, response.getStatus(), response.getBody() });
|
||||
}
|
||||
|
||||
// It has the cached file, let's just read that then
|
||||
@ -130,7 +130,7 @@ abstract class GitHubConnector {
|
||||
}
|
||||
} catch (UnirestException e) {
|
||||
if (github.isLoggingEnabled()) {
|
||||
Slimefun.getLogger().log(Level.WARNING, "Could not connect to GitHub in time.", e);
|
||||
SlimefunPlugin.logger().log(Level.WARNING, "Could not connect to GitHub in time.", e);
|
||||
}
|
||||
|
||||
// It has the cached file, let's just read that then
|
||||
@ -153,7 +153,7 @@ abstract class GitHubConnector {
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8))) {
|
||||
return new JsonNode(reader.readLine());
|
||||
} catch (IOException | JSONException e) {
|
||||
Slimefun.getLogger().log(Level.WARNING, "Failed to read Github cache file: {0} - {1}: {2}", new Object[] { file.getName(), e.getClass().getSimpleName(), e.getMessage() });
|
||||
SlimefunPlugin.logger().log(Level.WARNING, "Failed to read Github cache file: {0} - {1}: {2}", new Object[] { file.getName(), e.getClass().getSimpleName(), e.getMessage() });
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -162,7 +162,7 @@ abstract class GitHubConnector {
|
||||
try (FileOutputStream output = new FileOutputStream(file)) {
|
||||
output.write(node.toString().getBytes(StandardCharsets.UTF_8));
|
||||
} catch (IOException e) {
|
||||
Slimefun.getLogger().log(Level.WARNING, "Failed to populate GitHub cache: {0} - {1}", new Object[] { e.getClass().getSimpleName(), e.getMessage() });
|
||||
SlimefunPlugin.logger().log(Level.WARNING, "Failed to populate GitHub cache: {0} - {1}", new Object[] { e.getClass().getSimpleName(), e.getMessage() });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,10 +7,10 @@ import java.util.logging.Level;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
import kong.unirest.JsonNode;
|
||||
import kong.unirest.json.JSONArray;
|
||||
import kong.unirest.json.JSONObject;
|
||||
import me.mrCookieSlime.Slimefun.api.Slimefun;
|
||||
|
||||
class GitHubIssuesConnector extends GitHubConnector {
|
||||
|
||||
@ -42,7 +42,7 @@ class GitHubIssuesConnector extends GitHubConnector {
|
||||
|
||||
callback.accept(issues, pullRequests);
|
||||
} else {
|
||||
Slimefun.getLogger().log(Level.WARNING, "Received an unusual answer from GitHub, possibly a timeout? ({0})", response);
|
||||
SlimefunPlugin.logger().log(Level.WARNING, "Received an unusual answer from GitHub, possibly a timeout? ({0})", response);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -214,7 +214,7 @@ public class GitHubService {
|
||||
uuid.ifPresent(value -> uuidCache.setValue(contributor.getName(), value));
|
||||
|
||||
if (contributor.hasTexture()) {
|
||||
String texture = contributor.getTexture();
|
||||
String texture = contributor.getTexture(this);
|
||||
|
||||
if (!texture.equals(HeadTexture.UNKNOWN.getTexture())) {
|
||||
texturesCache.setValue(contributor.getName(), texture);
|
||||
|
@ -14,9 +14,8 @@ import javax.annotation.Nullable;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import io.github.thebusybiscuit.cscorelib2.players.MinecraftAccount;
|
||||
import io.github.thebusybiscuit.cscorelib2.players.MinecraftAccount.TooManyRequestsException;
|
||||
import io.github.thebusybiscuit.cscorelib2.players.TooManyRequestsException;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
import me.mrCookieSlime.Slimefun.api.Slimefun;
|
||||
|
||||
/**
|
||||
* This {@link GitHubTask} represents a {@link Runnable} that is run every X minutes.
|
||||
@ -101,8 +100,8 @@ class GitHubTask implements Runnable {
|
||||
contributor.setTexture(null);
|
||||
} catch (IOException x) {
|
||||
// Too many requests
|
||||
Slimefun.getLogger().log(Level.WARNING, "Attempted to connect to mojang.com, got this response: {0}: {1}", new Object[] { x.getClass().getSimpleName(), x.getMessage() });
|
||||
Slimefun.getLogger().log(Level.WARNING, "This usually means mojang.com is temporarily down or started to rate-limit this connection, this is not an error message!");
|
||||
SlimefunPlugin.logger().log(Level.WARNING, "Attempted to connect to mojang.com, got this response: {0}: {1}", new Object[] { x.getClass().getSimpleName(), x.getMessage() });
|
||||
SlimefunPlugin.logger().log(Level.WARNING, "This usually means mojang.com is temporarily down or started to rate-limit this connection, this is not an error message!");
|
||||
|
||||
// Retry after 5 minutes if it was rate-limiting
|
||||
if (x.getMessage().contains("429")) {
|
||||
@ -111,7 +110,7 @@ class GitHubTask implements Runnable {
|
||||
|
||||
return -1;
|
||||
} catch (TooManyRequestsException x) {
|
||||
Slimefun.getLogger().log(Level.WARNING, "Received a rate-limit from mojang.com, retrying in 4 minutes");
|
||||
SlimefunPlugin.logger().log(Level.WARNING, "Received a rate-limit from mojang.com, retrying in 4 minutes");
|
||||
Bukkit.getScheduler().runTaskLaterAsynchronously(SlimefunPlugin.instance(), this::grabTextures, 4 * 60 * 20L);
|
||||
|
||||
return -1;
|
||||
|
@ -0,0 +1,135 @@
|
||||
package io.github.thebusybiscuit.slimefun4.core.services.holograms;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.ArmorStand;
|
||||
import org.bukkit.entity.Entity;
|
||||
|
||||
/**
|
||||
* This represents an {@link ArmorStand} that can expire and be renamed.
|
||||
*
|
||||
* @author TheBusyBiscuit
|
||||
*
|
||||
*/
|
||||
class Hologram {
|
||||
|
||||
/**
|
||||
* This is the minimum duration after which the {@link Hologram} will expire.
|
||||
*/
|
||||
private static final long EXPIRES_AFTER = TimeUnit.MINUTES.toMillis(10);
|
||||
|
||||
/**
|
||||
* The {@link UUID} of the {@link ArmorStand}.
|
||||
*/
|
||||
private final UUID uniqueId;
|
||||
|
||||
/**
|
||||
* The timestamp of when the {@link ArmorStand} was last accessed.
|
||||
*/
|
||||
private long lastAccess;
|
||||
|
||||
/**
|
||||
* The label of this {@link Hologram}.
|
||||
*/
|
||||
private String label;
|
||||
|
||||
/**
|
||||
* This creates a new {@link Hologram} for the given {@link UUID}.
|
||||
*
|
||||
* @param uniqueId
|
||||
* The {@link UUID} of the corresponding {@link ArmorStand}
|
||||
*/
|
||||
Hologram(@Nonnull UUID uniqueId) {
|
||||
this.uniqueId = uniqueId;
|
||||
this.lastAccess = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the corresponding {@link ArmorStand}
|
||||
* and also updates the "lastAccess" timestamp.
|
||||
* <p>
|
||||
* If the {@link ArmorStand} was removed, it will return null.
|
||||
*
|
||||
* @return The {@link ArmorStand} or null.
|
||||
*/
|
||||
@Nullable
|
||||
ArmorStand getArmorStand() {
|
||||
Entity n = Bukkit.getEntity(uniqueId);
|
||||
|
||||
if (n instanceof ArmorStand && n.isValid()) {
|
||||
this.lastAccess = System.currentTimeMillis();
|
||||
return (ArmorStand) n;
|
||||
} else {
|
||||
this.lastAccess = 0;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This checks if the associated {@link ArmorStand} has despawned.
|
||||
*
|
||||
* @return Whether the {@link ArmorStand} despawned
|
||||
*/
|
||||
boolean hasDespawned() {
|
||||
return getArmorStand() == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns whether this {@link Hologram} has expired.
|
||||
* The armorstand will expire if the last access has been more than 10
|
||||
* minutes ago.
|
||||
*
|
||||
* @return Whether this {@link Hologram} has expired
|
||||
*/
|
||||
boolean hasExpired() {
|
||||
return System.currentTimeMillis() - lastAccess > EXPIRES_AFTER;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets the label of this {@link Hologram}.
|
||||
*
|
||||
* @param label
|
||||
* The label to set
|
||||
*/
|
||||
void setLabel(@Nullable String label) {
|
||||
if (Objects.equals(this.label, label)) {
|
||||
/*
|
||||
* Label is already set, no need to cause an entity
|
||||
* update. But we can update the lastAccess flag.
|
||||
*/
|
||||
this.lastAccess = System.currentTimeMillis();
|
||||
} else {
|
||||
this.label = label;
|
||||
ArmorStand entity = getArmorStand();
|
||||
|
||||
if (entity != null) {
|
||||
if (label != null) {
|
||||
entity.setCustomNameVisible(true);
|
||||
entity.setCustomName(label);
|
||||
} else {
|
||||
entity.setCustomNameVisible(false);
|
||||
entity.setCustomName(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This will remove the {@link ArmorStand} and expire this {@link Hologram}.
|
||||
*/
|
||||
void remove() {
|
||||
ArmorStand armorstand = getArmorStand();
|
||||
|
||||
if (armorstand != null) {
|
||||
lastAccess = 0;
|
||||
armorstand.remove();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,313 @@
|
||||
package io.github.thebusybiscuit.slimefun4.core.services.holograms;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.entity.ArmorStand;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.persistence.PersistentDataContainer;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import io.github.thebusybiscuit.cscorelib2.blocks.BlockPosition;
|
||||
import io.github.thebusybiscuit.slimefun4.core.attributes.HologramOwner;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
|
||||
/**
|
||||
* This service is responsible for handling holograms.
|
||||
*
|
||||
* @author TheBusyBiscuit
|
||||
*
|
||||
* @see HologramOwner
|
||||
*/
|
||||
public class HologramsService {
|
||||
|
||||
/**
|
||||
* The radius in which we scan for holograms
|
||||
*/
|
||||
private static final double RADIUS = 0.45;
|
||||
|
||||
/**
|
||||
* The frequency at which to purge.
|
||||
* Every 45 seconds.
|
||||
*/
|
||||
private static final long PURGE_RATE = 45L * 20L;
|
||||
|
||||
/**
|
||||
* Our {@link Plugin} instance
|
||||
*/
|
||||
private final Plugin plugin;
|
||||
|
||||
/**
|
||||
* The default hologram offset
|
||||
*/
|
||||
private final Vector defaultOffset = new Vector(0.5, 0.75, 0.5);
|
||||
|
||||
/**
|
||||
* The {@link NamespacedKey} used to store data on a hologram
|
||||
*/
|
||||
private final NamespacedKey persistentDataKey;
|
||||
|
||||
/**
|
||||
* Our cache to save {@link Entity} lookups
|
||||
*/
|
||||
private final Map<BlockPosition, Hologram> cache = new HashMap<>();
|
||||
|
||||
/**
|
||||
* This constructs a new {@link HologramsService}.
|
||||
*
|
||||
* @param plugin
|
||||
* Our {@link Plugin} instance
|
||||
*/
|
||||
public HologramsService(@Nonnull Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
|
||||
// Null-Validation is performed in the NamespacedKey constructor
|
||||
persistentDataKey = new NamespacedKey(plugin, "hologram_id");
|
||||
}
|
||||
|
||||
/**
|
||||
* This will start the {@link HologramsService} and schedule a repeating
|
||||
* purge-task.
|
||||
*/
|
||||
public void start() {
|
||||
plugin.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, this::purge, PURGE_RATE, PURGE_RATE);
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the default {@link Hologram} offset.
|
||||
*
|
||||
* @return The default offset
|
||||
*/
|
||||
@Nonnull
|
||||
public Vector getDefaultOffset() {
|
||||
return defaultOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* This purges any expired {@link Hologram}.
|
||||
*/
|
||||
private void purge() {
|
||||
Iterator<Hologram> iterator = cache.values().iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
if (iterator.next().hasExpired()) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the {@link Hologram} associated with the given {@link Location}.
|
||||
* If createIfNoneExists is set to true a new {@link ArmorStand} will be spawned
|
||||
* if no existing one could be found.
|
||||
*
|
||||
* @param loc
|
||||
* The {@link Location}
|
||||
* @param createIfNoneExists
|
||||
* Whether to create a new {@link ArmorStand} if none was found
|
||||
*
|
||||
* @return The existing (or newly created) hologram
|
||||
*/
|
||||
@Nullable
|
||||
private Hologram getHologram(@Nonnull Location loc, boolean createIfNoneExists) {
|
||||
Validate.notNull(loc, "Location cannot be null");
|
||||
|
||||
BlockPosition position = new BlockPosition(loc);
|
||||
Hologram hologram = cache.get(position);
|
||||
|
||||
// Check if the ArmorStand was cached and still exists
|
||||
if (hologram != null && !hologram.hasDespawned()) {
|
||||
return hologram;
|
||||
}
|
||||
|
||||
// Scan all nearby entities which could be possible holograms
|
||||
Collection<Entity> holograms = loc.getWorld().getNearbyEntities(loc, RADIUS, RADIUS, RADIUS, this::isHologram);
|
||||
|
||||
for (Entity n : holograms) {
|
||||
if (n instanceof ArmorStand) {
|
||||
PersistentDataContainer container = n.getPersistentDataContainer();
|
||||
|
||||
if (container.has(persistentDataKey, PersistentDataType.LONG)) {
|
||||
// Check if it is ours or a different one.
|
||||
if (container.get(persistentDataKey, PersistentDataType.LONG).equals(position.getPosition())) {
|
||||
return getAsHologram(position, n, container);
|
||||
}
|
||||
} else {
|
||||
// Set a persistent tag to re-identify the correct hologram later
|
||||
container.set(persistentDataKey, PersistentDataType.LONG, position.getPosition());
|
||||
return getAsHologram(position, n, container);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (createIfNoneExists) {
|
||||
// Spawn a new ArmorStand
|
||||
ArmorStand armorstand = (ArmorStand) loc.getWorld().spawnEntity(loc, EntityType.ARMOR_STAND);
|
||||
PersistentDataContainer container = armorstand.getPersistentDataContainer();
|
||||
|
||||
return getAsHologram(position, armorstand, container);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This checks if a given {@link Entity} is an {@link ArmorStand}
|
||||
* and whether it has the correct attributes to be considered a {@link Hologram}.
|
||||
*
|
||||
* @param n
|
||||
* The {@link Entity} to check
|
||||
*
|
||||
* @return Whether this could be a hologram
|
||||
*/
|
||||
private boolean isHologram(@Nonnull Entity n) {
|
||||
if (n instanceof ArmorStand) {
|
||||
ArmorStand armorstand = (ArmorStand) n;
|
||||
|
||||
// The absolute minimum requirements to count as a hologram
|
||||
return !armorstand.isVisible() && armorstand.isSilent() && !armorstand.hasGravity();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This will cast the {@link Entity} to an {@link ArmorStand} and it will apply
|
||||
* all necessary attributes to the {@link ArmorStand}, then return a {@link Hologram}.
|
||||
*
|
||||
* @param position
|
||||
* The {@link BlockPosition} of this hologram
|
||||
* @param entity
|
||||
* The {@link Entity}
|
||||
* @param container
|
||||
* The {@link PersistentDataContainer} of the given {@link Entity}
|
||||
*
|
||||
* @return The {@link Hologram}
|
||||
*/
|
||||
@Nullable
|
||||
private Hologram getAsHologram(@Nonnull BlockPosition position, @Nonnull Entity entity, @Nonnull PersistentDataContainer container) {
|
||||
if (entity instanceof ArmorStand) {
|
||||
ArmorStand armorstand = (ArmorStand) entity;
|
||||
|
||||
armorstand.setVisible(false);
|
||||
armorstand.setInvulnerable(true);
|
||||
armorstand.setSilent(true);
|
||||
armorstand.setMarker(true);
|
||||
armorstand.setAI(false);
|
||||
armorstand.setGravity(false);
|
||||
armorstand.setRemoveWhenFarAway(false);
|
||||
|
||||
// Set a persistent tag to re-identify the correct hologram later
|
||||
container.set(persistentDataKey, PersistentDataType.LONG, position.getPosition());
|
||||
|
||||
// Store in cache for faster access
|
||||
Hologram hologram = new Hologram(armorstand.getUniqueId());
|
||||
cache.put(position, hologram);
|
||||
|
||||
return hologram;
|
||||
} else {
|
||||
// This should never be reached
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This updates the {@link Hologram}.
|
||||
* You can use it to set the nametag or other properties.
|
||||
* <p>
|
||||
* <strong>This method must be executed on the main {@link Server} {@link Thread}.</strong>
|
||||
*
|
||||
* @param loc
|
||||
* The {@link Location}
|
||||
* @param consumer
|
||||
* The callback to run
|
||||
*/
|
||||
private void updateHologram(@Nonnull Location loc, @Nonnull Consumer<Hologram> consumer) {
|
||||
Validate.notNull(loc, "Location must not be null");
|
||||
Validate.notNull(consumer, "Callbacks must not be null");
|
||||
|
||||
Runnable runnable = () -> {
|
||||
try {
|
||||
Hologram hologram = getHologram(loc, true);
|
||||
|
||||
if (hologram != null) {
|
||||
consumer.accept(hologram);
|
||||
}
|
||||
} catch (Exception | LinkageError x) {
|
||||
SlimefunPlugin.logger().log(Level.SEVERE, "Hologram located at {0}", new BlockPosition(loc));
|
||||
SlimefunPlugin.logger().log(Level.SEVERE, "Something went wrong while trying to update this hologram", x);
|
||||
}
|
||||
};
|
||||
|
||||
if (Bukkit.isPrimaryThread()) {
|
||||
runnable.run();
|
||||
} else {
|
||||
SlimefunPlugin.runSync(runnable);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This removes the {@link Hologram} at that given {@link Location}.
|
||||
* <p>
|
||||
* <strong>This method must be executed on the main {@link Server} {@link Thread}.</strong>
|
||||
*
|
||||
* @param loc
|
||||
* The {@link Location}
|
||||
*
|
||||
* @return Whether the {@link Hologram} could be removed, false if the {@link Hologram} does not
|
||||
* exist or was already removed
|
||||
*/
|
||||
public boolean removeHologram(@Nonnull Location loc) {
|
||||
Validate.notNull(loc, "Location cannot be null");
|
||||
|
||||
if (Bukkit.isPrimaryThread()) {
|
||||
try {
|
||||
Hologram hologram = getHologram(loc, false);
|
||||
|
||||
if (hologram != null) {
|
||||
cache.remove(new BlockPosition(loc));
|
||||
hologram.remove();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (Exception | LinkageError x) {
|
||||
SlimefunPlugin.logger().log(Level.SEVERE, "Hologram located at {0}", new BlockPosition(loc));
|
||||
SlimefunPlugin.logger().log(Level.SEVERE, "Something went wrong while trying to remove this hologram", x);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
throw new UnsupportedOperationException("You cannot remove a hologram asynchronously.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This will update the label of the {@link Hologram}.
|
||||
*
|
||||
* @param loc
|
||||
* The {@link Location} of this {@link Hologram}
|
||||
* @param label
|
||||
* The label to set, can be null
|
||||
*/
|
||||
public void setHologramLabel(@Nonnull Location loc, @Nullable String label) {
|
||||
Validate.notNull(loc, "Location must not be null");
|
||||
|
||||
updateHologram(loc, hologram -> hologram.setLabel(label));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
/**
|
||||
* This package contains everything related to the
|
||||
* {@link io.github.thebusybiscuit.slimefun4.core.services.holograms.HologramsService}.
|
||||
*/
|
||||
package io.github.thebusybiscuit.slimefun4.core.services.holograms;
|
@ -33,7 +33,7 @@ enum SupportedLanguage {
|
||||
NORWEGIAN("no", false, "e0596e165ec3f389b59cfdda93dd6e363e97d9c6456e7c2e123973fa6c5fda"),
|
||||
CZECH("cs", true, "48152b7334d7ecf335e47a4f35defbd2eb6957fc7bfe94212642d62f46e61e"),
|
||||
ROMANIAN("ro", false, "dceb1708d5404ef326103e7b60559c9178f3dce729007ac9a0b498bdebe46107"),
|
||||
BULGARIAN("bg", false, "19039e1fd88c78d9d7adc5aad5ab16e356be13464934ed9e2b0cef2051c5b534"),
|
||||
BULGARIAN("bg", true, "19039e1fd88c78d9d7adc5aad5ab16e356be13464934ed9e2b0cef2051c5b534"),
|
||||
PORTUGUESE_PORTUGAL("pt", false, "ebd51f4693af174e6fe1979233d23a40bb987398e3891665fafd2ba567b5a53a"),
|
||||
PORTUGUESE_BRAZIL("pt-BR", true, "9a46475d5dcc815f6c5f2859edbb10611f3e861c0eb14f088161b3c0ccb2b0d9"),
|
||||
HUNGARIAN("hu", true, "4a9c3c4b6c5031332dd2bfece5e31e999f8deff55474065cc86993d7bdcdbd0"),
|
||||
@ -47,11 +47,11 @@ enum SupportedLanguage {
|
||||
CHINESE_TAIWAN("zh-TW", true, "702a4afb2e1e2e3a1894a8b74272f95cfa994ce53907f9ac140bd3c932f9f"),
|
||||
JAPANESE("ja", true, "d640ae466162a47d3ee33c4076df1cab96f11860f07edb1f0832c525a9e33323"),
|
||||
KOREAN("ko", true, "fc1be5f12f45e413eda56f3de94e08d90ede8e339c7b1e8f32797390e9a5f"),
|
||||
HEBREW("he", false, "1ba086a2cc7272cf5ba49c80248546c22e5ef1bab54120e8a8e5d9e75b6a"),
|
||||
HEBREW("he", true, "1ba086a2cc7272cf5ba49c80248546c22e5ef1bab54120e8a8e5d9e75b6a"),
|
||||
ARABIC("ar", true, "a4be759a9cf7f0a19a7e8e62f23789ad1d21cebae38af9d9541676a3db001572"),
|
||||
TURKISH("tr", true, "9852b9aba3482348514c1034d0affe73545c9de679ae4647f99562b5e5f47d09"),
|
||||
PERSIAN("fa", false, "5cd9badf1972583b663b44b1e027255de8f275aa1e89defcf77782ba6fcc652"),
|
||||
SERBIA("sr", false, "5b0483a4f0ddf4fbbc977b127b3d294d7a869f995366e3f50f6b05a70f522510"),
|
||||
SERBIAN("sr", false, "5b0483a4f0ddf4fbbc977b127b3d294d7a869f995366e3f50f6b05a70f522510"),
|
||||
AFRIKAANS("af", false, "961a1eacc10524d1f45f23b0e487bb2fc33948d9676b418b19a3da0b109d0e3c"),
|
||||
MALAY("ms", false, "754b9041dea6db6db44750f1385a743adf653767b4b8802cad4c585dd3f5be46"),
|
||||
THAI("th", true, "2a7916e4a852f7e6f3f3de19c7fb57686a37bce834bd54684a7dbef8d53fb"),
|
||||
@ -89,6 +89,14 @@ enum SupportedLanguage {
|
||||
return releaseReady;
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the texture hash for this language.
|
||||
* This will be the flag of the corresponding country.
|
||||
* (Not accurate I know, but better than having all languages
|
||||
* look the same by using the same items)
|
||||
*
|
||||
* @return The texture hash of this language
|
||||
*/
|
||||
@Nonnull
|
||||
public String getTexture() {
|
||||
return textureHash;
|
||||
|
@ -52,6 +52,8 @@ public class Translators {
|
||||
|
||||
// Translators - Hungarian
|
||||
addTranslator("andris155", SupportedLanguage.HUNGARIAN, true);
|
||||
addTranslator("KingDeadZ", SupportedLanguage.HUNGARIAN, true);
|
||||
addTranslator("poma123", SupportedLanguage.HUNGARIAN, false);
|
||||
|
||||
// Translators - Vietnamese
|
||||
addTranslator("HSGamer", SupportedLanguage.VIETNAMESE, false);
|
||||
@ -131,8 +133,12 @@ public class Translators {
|
||||
addTranslator("mohkamfer", "AgentBabbie", SupportedLanguage.ARABIC, false);
|
||||
|
||||
// Translators - Hebrew
|
||||
addTranslator("dhtdht020", SupportedLanguage.HEBREW, false);
|
||||
addTranslator("Eylonnn", SupportedLanguage.HEBREW, false);
|
||||
addTranslator("dhtdht020", SupportedLanguage.HEBREW, true);
|
||||
addTranslator("Eylonnn", SupportedLanguage.HEBREW, true);
|
||||
addTranslator("sarhatabaot", SupportedLanguage.HEBREW, false);
|
||||
addTranslator("Timotiyadeyhakesem", SupportedLanguage.HEBREW, true);
|
||||
addTranslator("Molioron", SupportedLanguage.HEBREW, true);
|
||||
addTranslator("McAlmog", SupportedLanguage.HEBREW, true);
|
||||
|
||||
// Translators - Japanese
|
||||
addTranslator("bito-blosh", "Bloshop", SupportedLanguage.JAPANESE, false);
|
||||
@ -180,8 +186,10 @@ public class Translators {
|
||||
addTranslator("Sakanas", SupportedLanguage.PORTUGUESE_BRAZIL, true);
|
||||
addTranslator("krazybeat", SupportedLanguage.PORTUGUESE_BRAZIL, true);
|
||||
addTranslator("FaolanMalcadh", SupportedLanguage.PORTUGUESE_BRAZIL, true);
|
||||
addTranslator("G4stavoM1ster", SupportedLanguage.PORTUGUESE_BRAZIL, true);
|
||||
addTranslator("Gusstavo", SupportedLanguage.PORTUGUESE_BRAZIL, true);
|
||||
addTranslator("Day-OS", SupportedLanguage.PORTUGUESE_BRAZIL, true);
|
||||
addTranslator("ooicram", SupportedLanguage.PORTUGUESE_BRAZIL, true);
|
||||
addTranslator("Sxigames", SupportedLanguage.PORTUGUESE_BRAZIL, true);
|
||||
}
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
|
@ -1,60 +0,0 @@
|
||||
package io.github.thebusybiscuit.slimefun4.core.services.plugins;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
import io.github.thebusybiscuit.slimefun4.integrations.IntegrationsManager;
|
||||
|
||||
/**
|
||||
* This Service holds all interactions and hooks with third-party {@link Plugin Plugins}
|
||||
* that are not necessarily a dependency or a {@link SlimefunAddon}.
|
||||
*
|
||||
* Integration with these plugins happens inside Slimefun itself.
|
||||
*
|
||||
* @author TheBusyBiscuit
|
||||
*
|
||||
* @deprecated Renamed to {@link IntegrationsManager}
|
||||
*
|
||||
* @see SlimefunPlugin
|
||||
*
|
||||
*/
|
||||
@Deprecated
|
||||
public class ThirdPartyPluginService extends IntegrationsManager {
|
||||
|
||||
/**
|
||||
* This gets overridden if ExoticGarden is loaded
|
||||
*/
|
||||
private Function<Block, Optional<ItemStack>> exoticGardenIntegration = b -> Optional.empty();
|
||||
|
||||
/**
|
||||
* This initializes the {@link ThirdPartyPluginService}
|
||||
*
|
||||
* @param plugin
|
||||
* Our instance of {@link SlimefunPlugin}
|
||||
*/
|
||||
public ThirdPartyPluginService(@Nonnull SlimefunPlugin plugin) {
|
||||
super(plugin);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void loadExoticGarden(Plugin plugin, Function<Block, Optional<ItemStack>> method) {
|
||||
// TODO: Move this method to IntegrationsManager and think of a better way to handle this
|
||||
if (plugin.getName().equals("ExoticGarden")) {
|
||||
exoticGardenIntegration = method;
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public Optional<ItemStack> harvestExoticGardenPlant(Block block) {
|
||||
return exoticGardenIntegration.apply(block);
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
/**
|
||||
* This package contains all hooks to external plugins
|
||||
*/
|
||||
package io.github.thebusybiscuit.slimefun4.core.services.plugins;
|
@ -0,0 +1,41 @@
|
||||
package io.github.thebusybiscuit.slimefun4.core.services.profiler;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.bukkit.Server;
|
||||
|
||||
/**
|
||||
* This interface is used to identify someone as a {@link PerformanceInspector}.
|
||||
* A {@link PerformanceInspector} can query the {@link SlimefunProfiler} and get the
|
||||
* results send to them as a {@link PerformanceSummary}.
|
||||
*
|
||||
* @author TheBusyBiscuit
|
||||
*
|
||||
*/
|
||||
public interface PerformanceInspector {
|
||||
|
||||
/**
|
||||
* This returns whether this {@link PerformanceInspector} is still valid.
|
||||
* An inspector will become invalid if they leave the {@link Server}.
|
||||
*
|
||||
* @return Whether this inspector is still valid
|
||||
*/
|
||||
boolean isValid();
|
||||
|
||||
/**
|
||||
* This will send a text message to the {@link PerformanceInspector}.
|
||||
*
|
||||
* @param msg
|
||||
* The message to send
|
||||
*/
|
||||
void sendMessage(@Nonnull String msg);
|
||||
|
||||
/**
|
||||
* This determines whether the {@link PerformanceInspector} will get the full view
|
||||
* or a trimmed version which only shows the most urgent samples.
|
||||
*
|
||||
* @return Whether to send the full {@link PerformanceSummary} or a trimmed version
|
||||
*/
|
||||
boolean isVerbose();
|
||||
|
||||
}
|
@ -31,8 +31,6 @@ public enum PerformanceRating implements Predicate<Float> {
|
||||
HURTFUL(ChatColor.DARK_RED, 500),
|
||||
BAD(ChatColor.DARK_RED, Float.MAX_VALUE);
|
||||
|
||||
public static final PerformanceRating[] valuesCache = values();
|
||||
|
||||
private final ChatColor color;
|
||||
private final float threshold;
|
||||
|
||||
|
@ -11,10 +11,8 @@ import java.util.stream.Stream;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import io.github.thebusybiscuit.cscorelib2.chat.ChatColors;
|
||||
import io.github.thebusybiscuit.slimefun4.core.services.profiler.inspectors.PlayerPerformanceInspector;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.ChatUtils;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
@ -54,7 +52,7 @@ class PerformanceSummary {
|
||||
items = profiler.getByItem();
|
||||
}
|
||||
|
||||
public void send(@Nonnull CommandSender sender) {
|
||||
public void send(@Nonnull PerformanceInspector sender) {
|
||||
sender.sendMessage("");
|
||||
sender.sendMessage(ChatColor.GREEN + "===== Slimefun Lag Profiler =====");
|
||||
sender.sendMessage(ChatColor.GOLD + "Total time: " + ChatColor.YELLOW + NumberUtils.getAsMillis(totalElapsedTime));
|
||||
@ -91,17 +89,17 @@ class PerformanceSummary {
|
||||
}
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
private void summarizeTimings(int count, String name, CommandSender sender, Map<String, Long> map, Function<Map.Entry<String, Long>, String> formatter) {
|
||||
private void summarizeTimings(int count, String name, PerformanceInspector inspector, Map<String, Long> map, Function<Map.Entry<String, Long>, String> formatter) {
|
||||
Stream<Map.Entry<String, Long>> stream = map.entrySet().stream();
|
||||
List<Entry<String, Long>> results = stream.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())).collect(Collectors.toList());
|
||||
String prefix = count + " " + name + (count != 1 ? 's' : "");
|
||||
|
||||
if (sender instanceof Player) {
|
||||
if (inspector instanceof PlayerPerformanceInspector) {
|
||||
TextComponent component = summarizeAsTextComponent(count, prefix, results, formatter);
|
||||
sender.spigot().sendMessage(component);
|
||||
((PlayerPerformanceInspector) inspector).sendMessage(component);
|
||||
} else {
|
||||
String text = summarizeAsString(count, prefix, results, formatter);
|
||||
sender.sendMessage(text);
|
||||
String text = summarizeAsString(inspector, count, prefix, results, formatter);
|
||||
inspector.sendMessage(text);
|
||||
}
|
||||
}
|
||||
|
||||
@ -143,7 +141,7 @@ class PerformanceSummary {
|
||||
|
||||
@Nonnull
|
||||
@ParametersAreNonnullByDefault
|
||||
private String summarizeAsString(int count, String prefix, List<Entry<String, Long>> results, Function<Entry<String, Long>, String> formatter) {
|
||||
private String summarizeAsString(PerformanceInspector inspector, int count, String prefix, List<Entry<String, Long>> results, Function<Entry<String, Long>, String> formatter) {
|
||||
int shownEntries = 0;
|
||||
int hiddenEntries = 0;
|
||||
|
||||
@ -154,7 +152,7 @@ class PerformanceSummary {
|
||||
builder.append(ChatColor.YELLOW);
|
||||
|
||||
for (Map.Entry<String, Long> entry : results) {
|
||||
if (shownEntries < MAX_ITEMS && (shownEntries < MIN_ITEMS || entry.getValue() > VISIBILITY_THRESHOLD)) {
|
||||
if (inspector.isVerbose() || (shownEntries < MAX_ITEMS && (shownEntries < MIN_ITEMS || entry.getValue() > VISIBILITY_THRESHOLD))) {
|
||||
builder.append("\n ");
|
||||
builder.append(ChatColor.stripColor(formatter.apply(entry)));
|
||||
shownEntries++;
|
||||
|
@ -8,7 +8,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.logging.Level;
|
||||
|
||||
@ -19,7 +18,6 @@ import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
|
||||
import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon;
|
||||
@ -27,7 +25,6 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.tasks.TickerTask;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
|
||||
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||
import me.mrCookieSlime.Slimefun.api.Slimefun;
|
||||
|
||||
/**
|
||||
* The {@link SlimefunProfiler} works closely to the {@link TickerTask} and is
|
||||
@ -63,13 +60,28 @@ public class SlimefunProfiler {
|
||||
*/
|
||||
private final ExecutorService executor = Executors.newFixedThreadPool(threadFactory.getThreadCount(), threadFactory);
|
||||
|
||||
private final AtomicBoolean isProfiling = new AtomicBoolean(false);
|
||||
/**
|
||||
* All possible values of {@link PerformanceRating}.
|
||||
* We cache these for fast access since Enum#values() creates
|
||||
* an array everytime it is called.
|
||||
*/
|
||||
private final PerformanceRating[] performanceRatings = PerformanceRating.values();
|
||||
|
||||
/**
|
||||
* This boolean marks whether we are currently profiling or not.
|
||||
*/
|
||||
private volatile boolean isProfiling = false;
|
||||
|
||||
/**
|
||||
* This {@link AtomicInteger} holds the amount of blocks that still need to be
|
||||
* profiled.
|
||||
*/
|
||||
private final AtomicInteger queued = new AtomicInteger(0);
|
||||
|
||||
private long totalElapsedTime;
|
||||
|
||||
private final Map<ProfiledBlock, Long> timings = new ConcurrentHashMap<>();
|
||||
private final Queue<CommandSender> requests = new ConcurrentLinkedQueue<>();
|
||||
private final Queue<PerformanceInspector> requests = new ConcurrentLinkedQueue<>();
|
||||
|
||||
/**
|
||||
* This method terminates the {@link SlimefunProfiler}.
|
||||
@ -84,7 +96,7 @@ public class SlimefunProfiler {
|
||||
* This method starts the profiling, data from previous runs will be cleared.
|
||||
*/
|
||||
public void start() {
|
||||
isProfiling.set(true);
|
||||
isProfiling = true;
|
||||
queued.set(0);
|
||||
timings.clear();
|
||||
}
|
||||
@ -95,7 +107,7 @@ public class SlimefunProfiler {
|
||||
* @return A timestamp, best fed back into {@link #closeEntry(Location, SlimefunItem, long)}
|
||||
*/
|
||||
public long newEntry() {
|
||||
if (!isProfiling.get()) {
|
||||
if (!isProfiling) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -114,7 +126,7 @@ public class SlimefunProfiler {
|
||||
* The amount of entries that should be scheduled. Can be negative
|
||||
*/
|
||||
public void scheduleEntries(int amount) {
|
||||
if (isProfiling.get()) {
|
||||
if (isProfiling) {
|
||||
queued.getAndAdd(amount);
|
||||
}
|
||||
}
|
||||
@ -157,7 +169,7 @@ public class SlimefunProfiler {
|
||||
* This stops the profiling.
|
||||
*/
|
||||
public void stop() {
|
||||
isProfiling.set(false);
|
||||
isProfiling = false;
|
||||
|
||||
if (SlimefunPlugin.instance() == null || !SlimefunPlugin.instance().isEnabled()) {
|
||||
// Slimefun has been disabled
|
||||
@ -172,7 +184,7 @@ public class SlimefunProfiler {
|
||||
int iterations = 4000;
|
||||
|
||||
// Wait for all timing results to come in
|
||||
while (!isProfiling.get() && queued.get() > 0) {
|
||||
while (!isProfiling && queued.get() > 0) {
|
||||
try {
|
||||
/**
|
||||
* Since we got more than one Thread in our pool,
|
||||
@ -183,7 +195,7 @@ public class SlimefunProfiler {
|
||||
|
||||
// If we waited for too long, then we should just abort
|
||||
if (iterations <= 0) {
|
||||
Iterator<CommandSender> iterator = requests.iterator();
|
||||
Iterator<PerformanceInspector> iterator = requests.iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
iterator.next().sendMessage("Your timings report has timed out, we were still waiting for " + queued.get() + " samples to be collected :/");
|
||||
@ -193,12 +205,12 @@ public class SlimefunProfiler {
|
||||
return;
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
Slimefun.getLogger().log(Level.SEVERE, "A Profiler Thread was interrupted", e);
|
||||
SlimefunPlugin.logger().log(Level.SEVERE, "A Profiler Thread was interrupted", e);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
if (isProfiling.get() && queued.get() > 0) {
|
||||
if (isProfiling && queued.get() > 0) {
|
||||
// Looks like the next profiling has already started, abort!
|
||||
return;
|
||||
}
|
||||
@ -207,7 +219,7 @@ public class SlimefunProfiler {
|
||||
|
||||
if (!requests.isEmpty()) {
|
||||
PerformanceSummary summary = new PerformanceSummary(this, totalElapsedTime, timings.size());
|
||||
Iterator<CommandSender> iterator = requests.iterator();
|
||||
Iterator<PerformanceInspector> iterator = requests.iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
summary.send(iterator.next());
|
||||
@ -217,16 +229,16 @@ public class SlimefunProfiler {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method requests a summary for the given {@link CommandSender}.
|
||||
* This method requests a summary for the given {@link PerformanceInspector}.
|
||||
* The summary will be sent upon the next available moment in time.
|
||||
*
|
||||
* @param sender
|
||||
* The {@link CommandSender} who shall receive this summary.
|
||||
* @param inspector
|
||||
* The {@link PerformanceInspector} who shall receive this summary.
|
||||
*/
|
||||
public void requestSummary(@Nonnull CommandSender sender) {
|
||||
Validate.notNull(sender, "Cannot request a summary for null");
|
||||
public void requestSummary(@Nonnull PerformanceInspector inspector) {
|
||||
Validate.notNull(inspector, "Cannot request a summary for null");
|
||||
|
||||
requests.add(sender);
|
||||
requests.add(inspector);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@ -326,7 +338,7 @@ public class SlimefunProfiler {
|
||||
public PerformanceRating getPerformance() {
|
||||
float percentage = getPercentageOfTick();
|
||||
|
||||
for (PerformanceRating rating : PerformanceRating.valuesCache) {
|
||||
for (PerformanceRating rating : performanceRatings) {
|
||||
if (rating.test(percentage)) {
|
||||
return rating;
|
||||
}
|
||||
|
@ -0,0 +1,62 @@
|
||||
package io.github.thebusybiscuit.slimefun4.core.services.profiler.inspectors;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.ConsoleCommandSender;
|
||||
|
||||
import io.github.thebusybiscuit.slimefun4.core.services.profiler.PerformanceInspector;
|
||||
|
||||
/**
|
||||
* This implementation of {@link PerformanceInspector} refers to a {@link CommandSender}
|
||||
* which is preferabbly a {@link ConsoleCommandSender}.
|
||||
* But it can theoretically be used for any type of {@link CommandSender} as it uses uncolored texts.
|
||||
*
|
||||
* @author TheBusyBiscuit
|
||||
*
|
||||
*/
|
||||
public class ConsolePerformanceInspector implements PerformanceInspector {
|
||||
|
||||
/**
|
||||
* Our reference to the actual underlying {@link CommandSender}.
|
||||
*/
|
||||
private final CommandSender console;
|
||||
|
||||
/**
|
||||
* Whether a summary will be verbose or trimmed of.
|
||||
*/
|
||||
private final boolean verbose;
|
||||
|
||||
/**
|
||||
* This creates a new {@link ConsolePerformanceInspector} for the given {@link CommandSender}.
|
||||
*
|
||||
* @param console
|
||||
* The {@link CommandSender}, preferabbly a {@link ConsoleCommandSender}
|
||||
* @param verbose
|
||||
* Whether the summary will be verbose or not
|
||||
*/
|
||||
public ConsolePerformanceInspector(@Nonnull CommandSender console, boolean verbose) {
|
||||
Validate.notNull(console, "CommandSender cannot be null");
|
||||
|
||||
this.console = console;
|
||||
this.verbose = verbose;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
// The console is always "online".
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVerbose() {
|
||||
return verbose;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(@Nonnull String msg) {
|
||||
console.sendMessage(msg);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
package io.github.thebusybiscuit.slimefun4.core.services.profiler.inspectors;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import io.github.thebusybiscuit.slimefun4.core.services.profiler.PerformanceInspector;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
|
||||
/**
|
||||
* This implementation of {@link PerformanceInspector} refers to a {@link Player}.
|
||||
* It also supports {@link TextComponent TextComponents} for rich text messages.
|
||||
*
|
||||
* @author TheBusyBiscuit
|
||||
*
|
||||
*/
|
||||
public class PlayerPerformanceInspector implements PerformanceInspector {
|
||||
|
||||
/**
|
||||
* Our reference to the {@link UUID} of the {@link Player}.
|
||||
*/
|
||||
private final UUID uuid;
|
||||
|
||||
/**
|
||||
* This creates a new {@link PlayerPerformanceInspector} for the given {@link Player}.
|
||||
*
|
||||
* @param player
|
||||
* The {@link Player}
|
||||
*/
|
||||
public PlayerPerformanceInspector(@Nonnull Player player) {
|
||||
Validate.notNull(player, "Player cannot be null");
|
||||
|
||||
this.uuid = player.getUniqueId();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Player getPlayer() {
|
||||
return Bukkit.getPlayer(uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
Player player = getPlayer();
|
||||
return player != null && player.isOnline();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVerbose() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(@Nonnull String msg) {
|
||||
Player player = getPlayer();
|
||||
|
||||
if (player != null) {
|
||||
player.sendMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendMessage(@Nonnull TextComponent component) {
|
||||
Player player = getPlayer();
|
||||
|
||||
if (player != null) {
|
||||
player.spigot().sendMessage(component);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
/**
|
||||
* This package holds the different implementations of
|
||||
* {@link io.github.thebusybiscuit.slimefun4.core.services.profiler.PerformanceInspector}.
|
||||
*/
|
||||
package io.github.thebusybiscuit.slimefun4.core.services.profiler.inspectors;
|
@ -562,6 +562,7 @@ public final class SlimefunItems {
|
||||
public static final SlimefunItemStack TALISMAN_WHIRLWIND = new SlimefunItemStack("WHIRLWIND_TALISMAN", Material.EMERALD, "&aTalisman of the Whirlwind", "", "&fHaving this Talisman", "&fin your Inventory will reflect", "&f60% of any projectiles fired at you.", "&e&oOnly a thrown Trident can pierce", "&e&othrough this layer of protection");
|
||||
public static final SlimefunItemStack TALISMAN_WIZARD = new SlimefunItemStack("WIZARD_TALISMAN", Material.EMERALD, "&aTalisman of the Wizard", "", "&fWhile you have this Talisman", "&fin your Inventory it allows you to", "&fobtain Fortune Level 4/5 however", "&fit also has a chance to lower the", "&fLevel of some Enchantments on your Item");
|
||||
public static final SlimefunItemStack TALISMAN_CAVEMAN = new SlimefunItemStack("CAVEMAN_TALISMAN", Material.EMERALD, "&aTalisman of the Caveman", "", "&fWhile you have this Talisman", "&fin your inventory it gives", "&fyou a 50% chance for a decent", "&fHaste buff when you mine any ore");
|
||||
public static final SlimefunItemStack TALISMAN_WISE = new SlimefunItemStack("WISE_TALISMAN", Material.EMERALD, "&aTalisman of the Wise", "", "&fWhile you have this Talisman", "&fin your inventory it gives", "&fyou a 20% chance of doubling", "&fany experience you obtain");
|
||||
|
||||
/* Staves */
|
||||
public static final SlimefunItemStack STAFF_ELEMENTAL = new SlimefunItemStack("STAFF_ELEMENTAL", Material.STICK, "&6Elemental Staff");
|
||||
|
@ -8,6 +8,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
@ -20,6 +21,7 @@ import org.bukkit.Server;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.inventory.Recipe;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
@ -27,9 +29,7 @@ import org.bukkit.plugin.java.JavaPluginLoader;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
import io.github.thebusybiscuit.cscorelib2.config.Config;
|
||||
import io.github.thebusybiscuit.cscorelib2.math.DoubleHandler;
|
||||
import io.github.thebusybiscuit.cscorelib2.protection.ProtectionManager;
|
||||
import io.github.thebusybiscuit.cscorelib2.reflection.ReflectionUtils;
|
||||
import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion;
|
||||
import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon;
|
||||
import io.github.thebusybiscuit.slimefun4.api.exceptions.TagMisconfigurationException;
|
||||
@ -50,7 +50,7 @@ import io.github.thebusybiscuit.slimefun4.core.services.PerWorldSettingsService;
|
||||
import io.github.thebusybiscuit.slimefun4.core.services.PermissionsService;
|
||||
import io.github.thebusybiscuit.slimefun4.core.services.UpdaterService;
|
||||
import io.github.thebusybiscuit.slimefun4.core.services.github.GitHubService;
|
||||
import io.github.thebusybiscuit.slimefun4.core.services.plugins.ThirdPartyPluginService;
|
||||
import io.github.thebusybiscuit.slimefun4.core.services.holograms.HologramsService;
|
||||
import io.github.thebusybiscuit.slimefun4.core.services.profiler.SlimefunProfiler;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.items.altar.AncientAltar;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.items.altar.AncientPedestal;
|
||||
@ -76,6 +76,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.listeners.EnhancedFurna
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.listeners.ExplosionsListener;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.listeners.GadgetsListener;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.listeners.GrapplingHookListener;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.listeners.HopperListener;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.listeners.ItemDropListener;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.listeners.ItemPickupListener;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.listeners.MultiBlockListener;
|
||||
@ -113,8 +114,10 @@ import io.github.thebusybiscuit.slimefun4.implementation.tasks.ArmorTask;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.tasks.SlimefunStartupTask;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.tasks.TickerTask;
|
||||
import io.github.thebusybiscuit.slimefun4.integrations.IntegrationsManager;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.MenuListener;
|
||||
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AContainer;
|
||||
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AGenerator;
|
||||
import me.mrCookieSlime.Slimefun.api.BlockStorage;
|
||||
@ -148,14 +151,15 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
|
||||
private final BackupService backupService = new BackupService();
|
||||
private final PermissionsService permissionsService = new PermissionsService(this);
|
||||
private final PerWorldSettingsService worldSettingsService = new PerWorldSettingsService(this);
|
||||
private final ThirdPartyPluginService thirdPartySupportService = new ThirdPartyPluginService(this);
|
||||
private final MinecraftRecipeService recipeService = new MinecraftRecipeService(this);
|
||||
private final SlimefunProfiler profiler = new SlimefunProfiler();
|
||||
private LocalizationService local;
|
||||
private final HologramsService hologramsService = new HologramsService(this);
|
||||
|
||||
private final IntegrationsManager integrations = new IntegrationsManager(this);
|
||||
private final SlimefunProfiler profiler = new SlimefunProfiler();
|
||||
private final GPSNetwork gpsNetwork = new GPSNetwork(this);
|
||||
|
||||
private GPSNetwork gpsNetwork;
|
||||
private NetworkManager networkManager;
|
||||
private ProtectionManager protections;
|
||||
private LocalizationService local;
|
||||
|
||||
// Important config files for Slimefun
|
||||
private final Config config = new Config(this);
|
||||
@ -199,133 +203,17 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
|
||||
*/
|
||||
@Override
|
||||
public void onEnable() {
|
||||
instance = this;
|
||||
setInstance(this);
|
||||
|
||||
if (minecraftVersion == MinecraftVersion.UNIT_TEST) {
|
||||
if (isUnitTest()) {
|
||||
// We handle Unit Tests seperately.
|
||||
onUnitTestStart();
|
||||
} else if (getServer().getPluginManager().isPluginEnabled("CS-CoreLib")) {
|
||||
getLogger().log(Level.INFO, "CS-CoreLib was detected!");
|
||||
long timestamp = System.nanoTime();
|
||||
PaperLib.suggestPaper(this);
|
||||
|
||||
if (PaperLib.isPaper()) {
|
||||
getLogger().log(Level.INFO, "Paper was detected! Performance optimizations have been applied.");
|
||||
}
|
||||
|
||||
// We wanna ensure that the Server uses a compatible version of Minecraft
|
||||
if (isVersionUnsupported()) {
|
||||
getServer().getPluginManager().disablePlugin(this);
|
||||
return;
|
||||
}
|
||||
|
||||
// Disabling backwards-compatibility for fresh Slimefun installs
|
||||
if (!new File("data-storage/Slimefun").exists()) {
|
||||
config.setValue("options.backwards-compatibility", false);
|
||||
config.save();
|
||||
|
||||
isNewlyInstalled = true;
|
||||
}
|
||||
|
||||
// Creating all necessary Folders
|
||||
getLogger().log(Level.INFO, "Creating directories...");
|
||||
createDirectories();
|
||||
registry.load(config);
|
||||
|
||||
// Set up localization
|
||||
getLogger().log(Level.INFO, "Loading language files...");
|
||||
local = new LocalizationService(this, config.getString("options.chat-prefix"), config.getString("options.language"));
|
||||
|
||||
// Setting up Networks
|
||||
gpsNetwork = new GPSNetwork();
|
||||
|
||||
int networkSize = config.getInt("networks.max-size");
|
||||
|
||||
if (networkSize < 1) {
|
||||
getLogger().log(Level.WARNING, "Your 'networks.max-size' setting is misconfigured! It must be at least 1, it was set to: {0}", networkSize);
|
||||
networkSize = 1;
|
||||
}
|
||||
|
||||
networkManager = new NetworkManager(networkSize, config.getBoolean("networks.enable-visualizer"), config.getBoolean("networks.delete-excess-items"));
|
||||
|
||||
// Setting up bStats
|
||||
new Thread(metricsService::start, "Slimefun Metrics").start();
|
||||
|
||||
// Starting the Auto-Updater
|
||||
if (config.getBoolean("options.auto-update")) {
|
||||
getLogger().log(Level.INFO, "Starting Auto-Updater...");
|
||||
updaterService.start();
|
||||
} else {
|
||||
updaterService.disable();
|
||||
}
|
||||
|
||||
// Registering all GEO Resources
|
||||
getLogger().log(Level.INFO, "Loading GEO-Resources...");
|
||||
GEOResourcesSetup.setup();
|
||||
|
||||
getLogger().log(Level.INFO, "Loading Tags...");
|
||||
loadTags();
|
||||
|
||||
getLogger().log(Level.INFO, "Loading items...");
|
||||
loadItems();
|
||||
|
||||
getLogger().log(Level.INFO, "Loading researches...");
|
||||
loadResearches();
|
||||
|
||||
registry.setResearchingEnabled(getResearchCfg().getBoolean("enable-researching"));
|
||||
PostSetup.setupWiki();
|
||||
|
||||
getLogger().log(Level.INFO, "Registering listeners...");
|
||||
registerListeners();
|
||||
|
||||
// Initiating various Stuff and all items with a slight delay (0ms after the Server finished loading)
|
||||
runSync(new SlimefunStartupTask(this, () -> {
|
||||
protections = new ProtectionManager(getServer());
|
||||
textureService.register(registry.getAllSlimefunItems(), true);
|
||||
permissionsService.register(registry.getAllSlimefunItems(), true);
|
||||
|
||||
// This try/catch should prevent buggy Spigot builds from blocking item loading
|
||||
try {
|
||||
recipeService.refresh();
|
||||
} catch (Exception | LinkageError x) {
|
||||
getLogger().log(Level.SEVERE, x, () -> "An Exception occurred while iterating through the Recipe list on Minecraft Version " + minecraftVersion.getName() + " (Slimefun v" + getVersion() + ")");
|
||||
}
|
||||
|
||||
}), 0);
|
||||
|
||||
// Setting up the command /sf and all subcommands
|
||||
command.register();
|
||||
|
||||
// Armor Update Task
|
||||
if (config.getBoolean("options.enable-armor-effects")) {
|
||||
boolean radioactiveFire = config.getBoolean("options.burn-players-when-radioactive");
|
||||
getServer().getScheduler().runTaskTimerAsynchronously(this, new ArmorTask(radioactiveFire), 0L, config.getInt("options.armor-update-interval") * 20L);
|
||||
}
|
||||
|
||||
autoSavingService.start(this, config.getInt("options.auto-save-delay-in-minutes"));
|
||||
ticker.start(this);
|
||||
|
||||
getLogger().log(Level.INFO, "Loading Third-Party plugin integrations...");
|
||||
thirdPartySupportService.start();
|
||||
|
||||
gitHubService.start(this);
|
||||
|
||||
// Hooray!
|
||||
getLogger().log(Level.INFO, "Slimefun has finished loading in {0}", getStartupTime(timestamp));
|
||||
} else if (isVersionUnsupported()) {
|
||||
// We wanna ensure that the Server uses a compatible version of Minecraft.
|
||||
getServer().getPluginManager().disablePlugin(this);
|
||||
} else {
|
||||
instance = null;
|
||||
|
||||
getLogger().log(Level.INFO, "#################### - INFO - ####################");
|
||||
getLogger().log(Level.INFO, " ");
|
||||
getLogger().log(Level.INFO, "Slimefun could not be loaded (yet).");
|
||||
getLogger().log(Level.INFO, "It appears that you have not installed CS-CoreLib.");
|
||||
getLogger().log(Level.INFO, "Please download and install CS-CoreLib manually:");
|
||||
getLogger().log(Level.INFO, "https://thebusybiscuit.github.io/builds/TheBusyBiscuit/CS-CoreLib/master/");
|
||||
|
||||
getCommand("slimefun").setExecutor((sender, cmd, label, args) -> {
|
||||
sender.sendMessage("You have forgotten to install CS-CoreLib! Slimefun is disabled.");
|
||||
sender.sendMessage("https://thebusybiscuit.github.io/builds/TheBusyBiscuit/CS-CoreLib/master/");
|
||||
return true;
|
||||
});
|
||||
// The Environment has been validated.
|
||||
onPluginStart();
|
||||
}
|
||||
}
|
||||
|
||||
@ -334,13 +222,131 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
|
||||
*/
|
||||
private void onUnitTestStart() {
|
||||
local = new LocalizationService(this, "", null);
|
||||
gpsNetwork = new GPSNetwork();
|
||||
networkManager = new NetworkManager(200);
|
||||
command.register();
|
||||
registry.load(config);
|
||||
registry.load(this, config);
|
||||
loadTags();
|
||||
}
|
||||
|
||||
/**
|
||||
* This is our start method for a correct Slimefun installation.
|
||||
*/
|
||||
private void onPluginStart() {
|
||||
long timestamp = System.nanoTime();
|
||||
|
||||
if (PaperLib.isPaper()) {
|
||||
getLogger().log(Level.INFO, "Paper was detected! Performance optimizations have been applied.");
|
||||
} else {
|
||||
PaperLib.suggestPaper(this);
|
||||
}
|
||||
|
||||
// Disabling backwards-compatibility for fresh Slimefun installs
|
||||
if (!new File("data-storage/Slimefun").exists()) {
|
||||
config.setValue("options.backwards-compatibility", false);
|
||||
config.save();
|
||||
|
||||
isNewlyInstalled = true;
|
||||
}
|
||||
|
||||
// Creating all necessary Folders
|
||||
getLogger().log(Level.INFO, "Creating directories...");
|
||||
createDirectories();
|
||||
registry.load(this, config);
|
||||
|
||||
// Set up localization
|
||||
getLogger().log(Level.INFO, "Loading language files...");
|
||||
local = new LocalizationService(this, config.getString("options.chat-prefix"), config.getString("options.language"));
|
||||
|
||||
int networkSize = config.getInt("networks.max-size");
|
||||
|
||||
if (networkSize < 1) {
|
||||
getLogger().log(Level.WARNING, "Your 'networks.max-size' setting is misconfigured! It must be at least 1, it was set to: {0}", networkSize);
|
||||
networkSize = 1;
|
||||
}
|
||||
|
||||
networkManager = new NetworkManager(networkSize, config.getBoolean("networks.enable-visualizer"), config.getBoolean("networks.delete-excess-items"));
|
||||
|
||||
// Setting up bStats
|
||||
new Thread(metricsService::start, "Slimefun Metrics").start();
|
||||
|
||||
// Starting the Auto-Updater
|
||||
if (config.getBoolean("options.auto-update")) {
|
||||
getLogger().log(Level.INFO, "Starting Auto-Updater...");
|
||||
updaterService.start();
|
||||
} else {
|
||||
updaterService.disable();
|
||||
}
|
||||
|
||||
// Registering all GEO Resources
|
||||
getLogger().log(Level.INFO, "Loading GEO-Resources...");
|
||||
GEOResourcesSetup.setup();
|
||||
|
||||
getLogger().log(Level.INFO, "Loading Tags...");
|
||||
loadTags();
|
||||
|
||||
getLogger().log(Level.INFO, "Loading items...");
|
||||
loadItems();
|
||||
|
||||
getLogger().log(Level.INFO, "Loading researches...");
|
||||
loadResearches();
|
||||
|
||||
registry.setResearchingEnabled(getResearchCfg().getBoolean("enable-researching"));
|
||||
PostSetup.setupWiki();
|
||||
|
||||
getLogger().log(Level.INFO, "Registering listeners...");
|
||||
registerListeners();
|
||||
|
||||
// Initiating various Stuff and all items with a slight delay (0ms after the Server finished loading)
|
||||
runSync(new SlimefunStartupTask(this, () -> {
|
||||
textureService.register(registry.getAllSlimefunItems(), true);
|
||||
permissionsService.register(registry.getAllSlimefunItems(), true);
|
||||
|
||||
// This try/catch should prevent buggy Spigot builds from blocking item loading
|
||||
try {
|
||||
recipeService.refresh();
|
||||
} catch (Exception | LinkageError x) {
|
||||
getLogger().log(Level.SEVERE, x, () -> "An Exception occurred while iterating through the Recipe list on Minecraft Version " + minecraftVersion.getName() + " (Slimefun v" + getVersion() + ")");
|
||||
}
|
||||
|
||||
}), 0);
|
||||
|
||||
// Setting up our commands
|
||||
try {
|
||||
command.register();
|
||||
} catch (Exception | LinkageError x) {
|
||||
getLogger().log(Level.SEVERE, "An Exception occurred while registering the /slimefun command", x);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// Starting our tasks
|
||||
autoSavingService.start(this, config.getInt("options.auto-save-delay-in-minutes"));
|
||||
hologramsService.start();
|
||||
ticker.start(this);
|
||||
|
||||
// Loading integrations
|
||||
getLogger().log(Level.INFO, "Loading Third-Party plugin integrations...");
|
||||
integrations.start();
|
||||
gitHubService.start(this);
|
||||
|
||||
// Hooray!
|
||||
getLogger().log(Level.INFO, "Slimefun has finished loading in {0}", getStartupTime(timestamp));
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaPlugin getJavaPlugin() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBugTrackerURL() {
|
||||
return "https://github.com/Slimefun/Slimefun4/issues";
|
||||
}
|
||||
|
||||
/**
|
||||
* This method gets called when the {@link Plugin} gets disabled.
|
||||
* Most often it is called when the {@link Server} is shutting down or reloading.
|
||||
@ -378,6 +384,7 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
|
||||
}
|
||||
}
|
||||
|
||||
// Save all "universal" inventories (ender chests for example)
|
||||
for (UniversalBlockMenu menu : registry.getUniversalInventories().values()) {
|
||||
menu.save();
|
||||
}
|
||||
@ -388,20 +395,11 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
|
||||
// Close and unload any resources from our Metrics Service
|
||||
metricsService.cleanUp();
|
||||
|
||||
/**
|
||||
* Prevent Memory Leaks for reloads...
|
||||
* These static Maps should really be removed at some point...
|
||||
*/
|
||||
AContainer.processing = null;
|
||||
AContainer.progress = null;
|
||||
// Terminate our Plugin instance
|
||||
setInstance(null);
|
||||
|
||||
AGenerator.processing = null;
|
||||
AGenerator.progress = null;
|
||||
|
||||
Reactor.processing = null;
|
||||
Reactor.progress = null;
|
||||
|
||||
instance = null;
|
||||
// Clean up any static fields
|
||||
cleanUp();
|
||||
|
||||
/**
|
||||
* Close all inventories on the server to prevent item dupes
|
||||
@ -412,17 +410,65 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a private internal method to set the de-facto instance of {@link SlimefunPlugin}.
|
||||
* Having this as a seperate method ensures the seperation between static and non-static fields.
|
||||
* It also makes sonarcloud happy :)
|
||||
* Only ever use it during {@link #onEnable()} or {@link #onDisable()}.
|
||||
*
|
||||
* @param pluginInstance
|
||||
* Our instance of {@link SlimefunPlugin} or null
|
||||
*/
|
||||
private static void setInstance(@Nullable SlimefunPlugin pluginInstance) {
|
||||
instance = pluginInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the time it took to load Slimefun (given a starting point).
|
||||
*
|
||||
* @param timestamp
|
||||
* The time at which we started to load Slimefun.
|
||||
*
|
||||
* @return The total time it took to load Slimefun (in ms or s)
|
||||
*/
|
||||
@Nonnull
|
||||
private String getStartupTime(long timestamp) {
|
||||
long ms = (System.nanoTime() - timestamp) / 1000000;
|
||||
|
||||
if (ms > 1000) {
|
||||
return DoubleHandler.fixDouble(ms / 1000.0) + "s";
|
||||
return NumberUtils.roundDecimalNumber(ms / 1000.0) + 's';
|
||||
} else {
|
||||
return DoubleHandler.fixDouble(ms) + "ms";
|
||||
return NumberUtils.roundDecimalNumber(ms) + "ms";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleaning up our static fields prevents memory leaks from a reload.
|
||||
*
|
||||
* @deprecated These static Maps should really be removed at some point...
|
||||
*/
|
||||
@Deprecated
|
||||
private static void cleanUp() {
|
||||
AContainer.processing = null;
|
||||
AContainer.progress = null;
|
||||
|
||||
AGenerator.processing = null;
|
||||
AGenerator.progress = null;
|
||||
|
||||
Reactor.processing = null;
|
||||
Reactor.progress = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method checks if this is currently running in a unit test
|
||||
* environment.
|
||||
*
|
||||
* @return Whether we are inside a unit test
|
||||
*/
|
||||
public boolean isUnitTest() {
|
||||
return minecraftVersion == MinecraftVersion.UNIT_TEST;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method checks for the {@link MinecraftVersion} of the {@link Server}.
|
||||
* If the version is unsupported, a warning will be printed to the console.
|
||||
@ -430,37 +476,79 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
|
||||
* @return Whether the {@link MinecraftVersion} is unsupported
|
||||
*/
|
||||
private boolean isVersionUnsupported() {
|
||||
String currentVersion = ReflectionUtils.getVersion();
|
||||
try {
|
||||
// First check if they still use the unsupported CraftBukkit software.
|
||||
if (!PaperLib.isSpigot() && Bukkit.getName().equals("CraftBukkit")) {
|
||||
getLogger().log(Level.SEVERE, "###############################################");
|
||||
getLogger().log(Level.SEVERE, "### Slimefun was not installed correctly!");
|
||||
getLogger().log(Level.SEVERE, "### CraftBukkit is no longer supported!");
|
||||
getLogger().log(Level.SEVERE, "###");
|
||||
getLogger().log(Level.SEVERE, "### Slimefun requires you to use Spigot, Paper or");
|
||||
getLogger().log(Level.SEVERE, "### any supported fork of Spigot or Paper.");
|
||||
getLogger().log(Level.SEVERE, "### (We recommend Paper)");
|
||||
getLogger().log(Level.SEVERE, "###############################################");
|
||||
|
||||
if (currentVersion.startsWith("v")) {
|
||||
for (MinecraftVersion version : MinecraftVersion.valuesCache) {
|
||||
if (version.matches(currentVersion)) {
|
||||
minecraftVersion = version;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Looks like you are using an unsupported Minecraft Version
|
||||
getLogger().log(Level.SEVERE, "#############################################");
|
||||
getLogger().log(Level.SEVERE, "### Slimefun was not installed correctly!");
|
||||
getLogger().log(Level.SEVERE, "### You are using the wrong version of Minecraft!");
|
||||
getLogger().log(Level.SEVERE, "###");
|
||||
getLogger().log(Level.SEVERE, "### You are using Minecraft {0}", currentVersion);
|
||||
getLogger().log(Level.SEVERE, "### but Slimefun {0} requires you to be using", getDescription().getVersion());
|
||||
getLogger().log(Level.SEVERE, "### Minecraft {0}", String.join(" / ", getSupportedVersions()));
|
||||
getLogger().log(Level.SEVERE, "#############################################");
|
||||
// Now check the actual Version of Minecraft
|
||||
int version = PaperLib.getMinecraftVersion();
|
||||
|
||||
if (version > 0) {
|
||||
// Check all supported versions of Minecraft
|
||||
for (MinecraftVersion supportedVersion : MinecraftVersion.values()) {
|
||||
if (supportedVersion.isMinecraftVersion(version)) {
|
||||
minecraftVersion = supportedVersion;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Looks like you are using an unsupported Minecraft Version
|
||||
getLogger().log(Level.SEVERE, "#############################################");
|
||||
getLogger().log(Level.SEVERE, "### Slimefun was not installed correctly!");
|
||||
getLogger().log(Level.SEVERE, "### You are using the wrong version of Minecraft!");
|
||||
getLogger().log(Level.SEVERE, "###");
|
||||
getLogger().log(Level.SEVERE, "### You are using Minecraft 1.{0}.x", version);
|
||||
getLogger().log(Level.SEVERE, "### but Slimefun {0} requires you to be using", getDescription().getVersion());
|
||||
getLogger().log(Level.SEVERE, "### Minecraft {0}", String.join(" / ", getSupportedVersions()));
|
||||
getLogger().log(Level.SEVERE, "#############################################");
|
||||
return true;
|
||||
} else {
|
||||
getLogger().log(Level.WARNING, "We could not determine the version of Minecraft you were using? ({0})", Bukkit.getVersion());
|
||||
|
||||
/*
|
||||
* If we are unsure about it, we will assume "supported".
|
||||
* They could be using a non-Bukkit based Software which still
|
||||
* might support Bukkit-based plugins.
|
||||
* Use at your own risk in this case.
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
} catch (Exception | LinkageError x) {
|
||||
getLogger().log(Level.SEVERE, x, () -> "Error: Could not determine Environment or version of Minecraft for Slimefun v" + getDescription().getVersion());
|
||||
|
||||
// We assume "unsupported" if something went wrong.
|
||||
return true;
|
||||
}
|
||||
|
||||
getLogger().log(Level.WARNING, "We could not determine the version of Minecraft you were using ({0})", currentVersion);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This private method gives us a {@link Collection} of every {@link MinecraftVersion}
|
||||
* that Slimefun is compatible with (as a {@link String} representation).
|
||||
* <p>
|
||||
* Example:
|
||||
*
|
||||
* <pre>
|
||||
* { 1.14.x, 1.15.x, 1.16.x }
|
||||
* </pre>
|
||||
*
|
||||
* @return A {@link Collection} of all compatible minecraft versions as strings
|
||||
*/
|
||||
@Nonnull
|
||||
private Collection<String> getSupportedVersions() {
|
||||
List<String> list = new ArrayList<>();
|
||||
|
||||
for (MinecraftVersion version : MinecraftVersion.valuesCache) {
|
||||
for (MinecraftVersion version : MinecraftVersion.values()) {
|
||||
if (!version.isVirtual()) {
|
||||
list.add(version.getName());
|
||||
}
|
||||
@ -469,6 +557,9 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates all necessary directories (and sub directories) for Slimefun.
|
||||
*/
|
||||
private void createDirectories() {
|
||||
String[] storageFolders = { "Players", "blocks", "stored-blocks", "stored-inventories", "stored-chunks", "universal-inventories", "waypoints", "block-backups" };
|
||||
String[] pluginFolders = { "scripts", "error-reports", "cache/github", "world-settings" };
|
||||
@ -494,6 +585,9 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
|
||||
* This method registers all of our {@link Listener Listeners}.
|
||||
*/
|
||||
private void registerListeners() {
|
||||
// Old deprecated CS-CoreLib Listener
|
||||
new MenuListener(this);
|
||||
|
||||
new SlimefunBootsListener(this);
|
||||
new SlimefunItemInteractListener(this);
|
||||
new SlimefunItemConsumeListener(this);
|
||||
@ -524,6 +618,7 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
|
||||
new CartographyTableListener(this);
|
||||
new ButcherAndroidListener(this);
|
||||
new NetworkListener(this, networkManager);
|
||||
new HopperListener(this);
|
||||
|
||||
// Bees were added in 1.15
|
||||
if (minecraftVersion.isAtLeast(MinecraftVersion.MINECRAFT_1_15)) {
|
||||
@ -564,6 +659,9 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
|
||||
new PlayerProfileListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* This (re)loads every {@link SlimefunTag}.
|
||||
*/
|
||||
private void loadTags() {
|
||||
for (SlimefunTag tag : SlimefunTag.valuesCache) {
|
||||
try {
|
||||
@ -577,6 +675,9 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This loads all of our items.
|
||||
*/
|
||||
private void loadItems() {
|
||||
try {
|
||||
SlimefunItemSetup.setup(this);
|
||||
@ -585,6 +686,9 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This loads our researches.
|
||||
*/
|
||||
private void loadResearches() {
|
||||
try {
|
||||
ResearchSetup.setupResearches();
|
||||
@ -593,6 +697,19 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This private static method allows us to throw a proper {@link Exception}
|
||||
* whenever someone tries to access a static method while the instance is null.
|
||||
* This happens when the method is invoked before {@link #onEnable()} or after {@link #onDisable()}.
|
||||
* <p>
|
||||
* Use it whenever a null check is needed to avoid a non-descriptive {@link NullPointerException}.
|
||||
*/
|
||||
private static void validateInstance() {
|
||||
if (instance == null) {
|
||||
throw new IllegalStateException("Cannot invoke static method, Slimefun instance is null.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the global instance of {@link SlimefunPlugin}.
|
||||
* This may return null if the {@link Plugin} was disabled.
|
||||
@ -604,24 +721,17 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static Config getCfg() {
|
||||
return instance.config;
|
||||
}
|
||||
|
||||
public static Config getResearchCfg() {
|
||||
return instance.researches;
|
||||
}
|
||||
|
||||
public static Config getItemCfg() {
|
||||
return instance.items;
|
||||
}
|
||||
|
||||
public static GPSNetwork getGPSNetwork() {
|
||||
return instance.gpsNetwork;
|
||||
}
|
||||
|
||||
public static TickerTask getTickerTask() {
|
||||
return instance.ticker;
|
||||
/**
|
||||
* This returns the {@link Logger} instance that Slimefun uses.
|
||||
* <p>
|
||||
* <strong>Any {@link SlimefunAddon} should use their own {@link Logger} instance!</strong>
|
||||
*
|
||||
* @return Our {@link Logger} instance
|
||||
*/
|
||||
@Nonnull
|
||||
public static Logger logger() {
|
||||
validateInstance();
|
||||
return instance.getLogger();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -629,57 +739,100 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
|
||||
*
|
||||
* @return The currently installed version of Slimefun
|
||||
*/
|
||||
@Nonnull
|
||||
public static String getVersion() {
|
||||
validateInstance();
|
||||
return instance.getDescription().getVersion();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static Config getCfg() {
|
||||
validateInstance();
|
||||
return instance.config;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static Config getResearchCfg() {
|
||||
validateInstance();
|
||||
return instance.researches;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static Config getItemCfg() {
|
||||
validateInstance();
|
||||
return instance.items;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static GPSNetwork getGPSNetwork() {
|
||||
validateInstance();
|
||||
return instance.gpsNetwork;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static TickerTask getTickerTask() {
|
||||
validateInstance();
|
||||
return instance.ticker;
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the {@link LocalizationService} of Slimefun.
|
||||
*
|
||||
* @return The {@link LocalizationService} of Slimefun
|
||||
*/
|
||||
@Nonnull
|
||||
public static LocalizationService getLocalization() {
|
||||
validateInstance();
|
||||
return instance.local;
|
||||
}
|
||||
|
||||
public static ProtectionManager getProtectionManager() {
|
||||
return instance.protections;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns out {@link MinecraftRecipeService} for Slimefun.
|
||||
* This service is responsible for finding/identifying {@link Recipe Recipes}
|
||||
* from vanilla Minecraft.
|
||||
*
|
||||
* @return Slimefun's {@link MinecraftRecipeService} instance
|
||||
*/
|
||||
@Nonnull
|
||||
public static MinecraftRecipeService getMinecraftRecipeService() {
|
||||
validateInstance();
|
||||
return instance.recipeService;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static CustomItemDataService getItemDataService() {
|
||||
validateInstance();
|
||||
return instance.itemDataService;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static CustomTextureService getItemTextureService() {
|
||||
validateInstance();
|
||||
return instance.textureService;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static PermissionsService getPermissionsService() {
|
||||
validateInstance();
|
||||
return instance.permissionsService;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static BlockDataService getBlockDataService() {
|
||||
validateInstance();
|
||||
return instance.blockDataService;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static PerWorldSettingsService getWorldSettingsService() {
|
||||
validateInstance();
|
||||
return instance.worldSettingsService;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method has been renamed.
|
||||
*
|
||||
* @deprecated Please use {@link #getIntegrations()} instead.
|
||||
*
|
||||
* @return the {@link ThirdPartyPluginService}
|
||||
*/
|
||||
@Deprecated
|
||||
public static ThirdPartyPluginService getThirdPartySupportService() {
|
||||
return instance.thirdPartySupportService;
|
||||
@Nonnull
|
||||
public static HologramsService getHologramsService() {
|
||||
validateInstance();
|
||||
return instance.hologramsService;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -690,7 +843,19 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
|
||||
*/
|
||||
@Nonnull
|
||||
public static IntegrationsManager getIntegrations() {
|
||||
return instance.thirdPartySupportService;
|
||||
validateInstance();
|
||||
return instance.integrations;
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns out instance of the {@link ProtectionManager}.
|
||||
* This bridge is used to hook into any third-party protection {@link Plugin}.
|
||||
*
|
||||
* @return Our instanceof of the {@link ProtectionManager}
|
||||
*/
|
||||
@Nonnull
|
||||
public static ProtectionManager getProtectionManager() {
|
||||
return getIntegrations().getProtectionManager();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -699,7 +864,9 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
|
||||
*
|
||||
* @return The {@link UpdaterService} for Slimefun
|
||||
*/
|
||||
@Nonnull
|
||||
public static UpdaterService getUpdater() {
|
||||
validateInstance();
|
||||
return instance.updaterService;
|
||||
}
|
||||
|
||||
@ -709,7 +876,9 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
|
||||
*
|
||||
* @return The {@link MetricsService} for Slimefun
|
||||
*/
|
||||
@Nonnull
|
||||
public static MetricsService getMetricsService() {
|
||||
validateInstance();
|
||||
return instance.metricsService;
|
||||
}
|
||||
|
||||
@ -719,30 +888,93 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
|
||||
*
|
||||
* @return The {@link GitHubService} for Slimefun
|
||||
*/
|
||||
@Nonnull
|
||||
public static GitHubService getGitHubService() {
|
||||
validateInstance();
|
||||
return instance.gitHubService;
|
||||
}
|
||||
|
||||
public static SlimefunRegistry getRegistry() {
|
||||
return instance.registry;
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns our {@link NetworkManager} which is responsible
|
||||
* for handling the Cargo and Energy networks.
|
||||
*
|
||||
* @return Our {@link NetworkManager} instance
|
||||
*/
|
||||
@Nonnull
|
||||
public static NetworkManager getNetworkManager() {
|
||||
validateInstance();
|
||||
return instance.networkManager;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static SlimefunRegistry getRegistry() {
|
||||
validateInstance();
|
||||
return instance.registry;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static GrapplingHookListener getGrapplingHookListener() {
|
||||
validateInstance();
|
||||
return instance.grapplingHookListener;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static BackpackListener getBackpackListener() {
|
||||
validateInstance();
|
||||
return instance.backpackListener;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static SlimefunBowListener getBowListener() {
|
||||
validateInstance();
|
||||
return instance.bowListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link Command} that was added by Slimefun.
|
||||
*
|
||||
* @return Slimefun's command
|
||||
*/
|
||||
@Nonnull
|
||||
public static SlimefunCommand getCommand() {
|
||||
validateInstance();
|
||||
return instance.command;
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns our instance of the {@link SlimefunProfiler}, a tool that is used
|
||||
* to analyse performance and lag.
|
||||
*
|
||||
* @return The {@link SlimefunProfiler}
|
||||
*/
|
||||
@Nonnull
|
||||
public static SlimefunProfiler getProfiler() {
|
||||
validateInstance();
|
||||
return instance.profiler;
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the currently installed version of Minecraft.
|
||||
*
|
||||
* @return The current version of Minecraft
|
||||
*/
|
||||
@Nonnull
|
||||
public static MinecraftVersion getMinecraftVersion() {
|
||||
validateInstance();
|
||||
return instance.minecraftVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns whether this version of Slimefun was newly installed.
|
||||
* It will return true if this {@link Server} uses Slimefun for the very first time.
|
||||
*
|
||||
* @return Whether this is a new installation of Slimefun
|
||||
*/
|
||||
public static boolean isNewlyInstalled() {
|
||||
validateInstance();
|
||||
return instance.isNewlyInstalled;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns a {@link Set} of every {@link Plugin} that lists Slimefun
|
||||
* as a required or optional dependency.
|
||||
@ -753,66 +985,17 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
|
||||
*/
|
||||
@Nonnull
|
||||
public static Set<Plugin> getInstalledAddons() {
|
||||
return Arrays.stream(instance.getServer().getPluginManager().getPlugins()).filter(plugin -> plugin.getDescription().getDepend().contains(instance.getName()) || plugin.getDescription().getSoftDepend().contains(instance.getName())).collect(Collectors.toSet());
|
||||
}
|
||||
validateInstance();
|
||||
|
||||
/**
|
||||
* The {@link Command} that was added by Slimefun.
|
||||
*
|
||||
* @return Slimefun's command
|
||||
*/
|
||||
public static SlimefunCommand getCommand() {
|
||||
return instance.command;
|
||||
}
|
||||
String pluginName = instance.getName();
|
||||
|
||||
/**
|
||||
* This returns our instance of the {@link SlimefunProfiler}, a tool that is used
|
||||
* to analyse performance and lag.
|
||||
*
|
||||
* @return The {@link SlimefunProfiler}
|
||||
*/
|
||||
public static SlimefunProfiler getProfiler() {
|
||||
return instance.profiler;
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the currently installed version of Minecraft.
|
||||
*
|
||||
* @return The current version of Minecraft
|
||||
*/
|
||||
public static MinecraftVersion getMinecraftVersion() {
|
||||
return instance.minecraftVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns whether this version of Slimefun was newly installed.
|
||||
* It will return true if this {@link Server} uses Slimefun for the very first time.
|
||||
*
|
||||
* @return Whether this is a new installation of Slimefun
|
||||
*/
|
||||
public static boolean isNewlyInstalled() {
|
||||
return instance.isNewlyInstalled;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static String getCSCoreLibVersion() {
|
||||
Plugin cscorelib = instance.getServer().getPluginManager().getPlugin("CS-CoreLib");
|
||||
|
||||
if (cscorelib == null) {
|
||||
throw new IllegalStateException("CS-CoreLib is not installed.");
|
||||
} else {
|
||||
return cscorelib.getDescription().getVersion();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaPlugin getJavaPlugin() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBugTrackerURL() {
|
||||
return "https://github.com/Slimefun/Slimefun4/issues";
|
||||
// @formatter:off
|
||||
return Arrays.stream(instance.getServer().getPluginManager().getPlugins())
|
||||
.filter(plugin -> {
|
||||
PluginDescriptionFile description = plugin.getDescription();
|
||||
return description.getDepend().contains(pluginName) || description.getSoftDepend().contains(pluginName);
|
||||
}).collect(Collectors.toSet());
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
/**
|
||||
@ -874,4 +1057,4 @@ public final class SlimefunPlugin extends JavaPlugin implements SlimefunAddon {
|
||||
return instance.getServer().getScheduler().runTask(instance, runnable);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,253 +0,0 @@
|
||||
package io.github.thebusybiscuit.slimefun4.implementation.guide;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import io.github.thebusybiscuit.cscorelib2.chat.ChatColors;
|
||||
import io.github.thebusybiscuit.cscorelib2.chat.ChatInput;
|
||||
import io.github.thebusybiscuit.cscorelib2.chat.json.ChatComponent;
|
||||
import io.github.thebusybiscuit.cscorelib2.chat.json.ClickEvent;
|
||||
import io.github.thebusybiscuit.cscorelib2.chat.json.CustomBookInterface;
|
||||
import io.github.thebusybiscuit.cscorelib2.chat.json.HoverEvent;
|
||||
import io.github.thebusybiscuit.cscorelib2.inventory.ItemUtils;
|
||||
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
|
||||
import io.github.thebusybiscuit.slimefun4.core.categories.FlexCategory;
|
||||
import io.github.thebusybiscuit.slimefun4.core.categories.LockedCategory;
|
||||
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuide;
|
||||
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideImplementation;
|
||||
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideLayout;
|
||||
import io.github.thebusybiscuit.slimefun4.core.researching.Research;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.ChatUtils;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.itemstack.SlimefunGuideItem;
|
||||
import me.mrCookieSlime.Slimefun.Objects.Category;
|
||||
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||
import me.mrCookieSlime.Slimefun.api.Slimefun;
|
||||
|
||||
/**
|
||||
* The {@link BookSlimefunGuide} is a {@link SlimefunGuideImplementation} which
|
||||
* uses a {@link CustomBookInterface} to display the contents of the {@link SlimefunGuide}.
|
||||
* {@link Player Players} have the option to choose this Written Book layout over the
|
||||
* standard {@link Inventory} variant.
|
||||
*
|
||||
* @author TheBusyBiscuit
|
||||
*
|
||||
* @see SlimefunGuide
|
||||
* @see SlimefunGuideImplementation
|
||||
* @see ChestSlimefunGuide
|
||||
* @see CheatSheetSlimefunGuide
|
||||
*
|
||||
*/
|
||||
public class BookSlimefunGuide implements SlimefunGuideImplementation {
|
||||
|
||||
private final NamespacedKey guideSearch = new NamespacedKey(SlimefunPlugin.instance(), "search");
|
||||
private final ItemStack item;
|
||||
|
||||
public BookSlimefunGuide() {
|
||||
item = new SlimefunGuideItem(this, "&aSlimefun Guide &7(Book GUI)");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SlimefunGuideLayout getLayout() {
|
||||
return SlimefunGuideLayout.BOOK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSurvivalMode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItem() {
|
||||
return item;
|
||||
}
|
||||
|
||||
private void openBook(Player p, PlayerProfile profile, List<ChatComponent> lines, boolean backButton) {
|
||||
CustomBookInterface book = new CustomBookInterface(SlimefunPlugin.instance());
|
||||
book.setTitle(SlimefunPlugin.getLocalization().getMessage(p, "guide.title.main"));
|
||||
|
||||
for (int i = 0; i < lines.size(); i = i + 10) {
|
||||
ChatComponent page = new ChatComponent("");
|
||||
ChatComponent header = new ChatComponent(ChatColors.color("&b&l- " + SlimefunPlugin.getLocalization().getMessage(p, "guide.title.main") + " -\n\n"));
|
||||
header.setHoverEvent(new HoverEvent(ChestMenuUtils.getSearchButton(p)));
|
||||
|
||||
header.setClickEvent(new ClickEvent(guideSearch, player -> SlimefunPlugin.runSync(() -> {
|
||||
SlimefunPlugin.getLocalization().sendMessage(player, "guide.search.message");
|
||||
ChatInput.waitForPlayer(SlimefunPlugin.instance(), player, msg -> SlimefunGuide.openSearch(profile, msg, true, true));
|
||||
}, 1)));
|
||||
|
||||
page.append(header);
|
||||
|
||||
for (int j = i; j < lines.size() && j < i + 10; j++) {
|
||||
page.append(lines.get(j));
|
||||
}
|
||||
|
||||
page.append(new ChatComponent("\n"));
|
||||
|
||||
if (backButton) {
|
||||
ChatComponent button = new ChatComponent(ChatColor.DARK_BLUE + "\u21E6 " + SlimefunPlugin.getLocalization().getMessage(p, "guide.back.title"));
|
||||
button.setHoverEvent(new HoverEvent(ChatColor.DARK_BLUE + "\u21E6 " + SlimefunPlugin.getLocalization().getMessage(p, "guide.back.title"), "", ChatColor.GRAY + SlimefunPlugin.getLocalization().getMessage(p, "guide.back.guide")));
|
||||
button.setClickEvent(new ClickEvent(new NamespacedKey(SlimefunPlugin.instance(), "slimefun_guide"), pl -> openMainMenu(profile, 1)));
|
||||
page.append(button);
|
||||
}
|
||||
|
||||
book.addPage(page);
|
||||
}
|
||||
|
||||
book.open(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openMainMenu(PlayerProfile profile, int page) {
|
||||
Player p = profile.getPlayer();
|
||||
|
||||
if (p == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<ChatComponent> lines = new LinkedList<>();
|
||||
int tier = 0;
|
||||
|
||||
for (Category category : SlimefunPlugin.getRegistry().getCategories()) {
|
||||
if (!category.isHidden(p) && (!(category instanceof FlexCategory) || ((FlexCategory) category).isVisible(p, profile, getLayout()))) {
|
||||
if (tier < category.getTier()) {
|
||||
tier = category.getTier();
|
||||
|
||||
if (tier > 1) {
|
||||
for (int i = 0; i < 10 && lines.size() % 10 != 0; i++) {
|
||||
lines.add(new ChatComponent("\n"));
|
||||
}
|
||||
}
|
||||
|
||||
lines.add(new ChatComponent(ChatColor.DARK_GRAY + "\u21E8" + ChatColor.DARK_BLUE + " Tier " + tier + "\n"));
|
||||
}
|
||||
|
||||
addCategory(p, profile, category, lines);
|
||||
}
|
||||
}
|
||||
|
||||
openBook(p, profile, lines, false);
|
||||
}
|
||||
|
||||
private void addCategory(Player p, PlayerProfile profile, Category category, List<ChatComponent> lines) {
|
||||
if (category instanceof LockedCategory && !((LockedCategory) category).hasUnlocked(p, profile)) {
|
||||
List<String> lore = new LinkedList<>();
|
||||
lore.add(ChatColor.DARK_RED + SlimefunPlugin.getLocalization().getMessage(p, "guide.locked") + " " + ChatColor.GRAY + "- " + ChatColor.RESET + category.getItem(p).getItemMeta().getDisplayName());
|
||||
lore.add("");
|
||||
|
||||
for (String line : SlimefunPlugin.getLocalization().getMessages(p, "guide.locked-category")) {
|
||||
lore.add(ChatColor.RESET + line);
|
||||
}
|
||||
|
||||
lore.add("");
|
||||
|
||||
for (Category parent : ((LockedCategory) category).getParents()) {
|
||||
lore.add(parent.getItem(p).getItemMeta().getDisplayName());
|
||||
}
|
||||
|
||||
ChatComponent chatComponent = new ChatComponent(ChatUtils.crop(ChatColor.RED, ItemUtils.getItemName(category.getItem(p))) + "\n");
|
||||
chatComponent.setHoverEvent(new HoverEvent(lore));
|
||||
lines.add(chatComponent);
|
||||
} else {
|
||||
ChatComponent chatComponent = new ChatComponent(ChatUtils.crop(ChatColor.DARK_GREEN, ItemUtils.getItemName(category.getItem(p))) + "\n");
|
||||
chatComponent.setHoverEvent(new HoverEvent(ItemUtils.getItemName(category.getItem(p)), "", ChatColor.GRAY + "\u21E8 " + ChatColor.GREEN + SlimefunPlugin.getLocalization().getMessage(p, "guide.tooltips.open-category")));
|
||||
chatComponent.setClickEvent(new ClickEvent(category.getKey(), pl -> openCategory(profile, category, 1)));
|
||||
lines.add(chatComponent);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openCategory(PlayerProfile profile, Category category, int page) {
|
||||
Player p = profile.getPlayer();
|
||||
|
||||
if (p == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (category instanceof FlexCategory) {
|
||||
((FlexCategory) category).open(p, profile, getLayout());
|
||||
} else if (category.getItems().size() < 250) {
|
||||
profile.getGuideHistory().add(category, page);
|
||||
|
||||
List<ChatComponent> items = new LinkedList<>();
|
||||
|
||||
for (SlimefunItem slimefunItem : category.getItems()) {
|
||||
if (Slimefun.hasPermission(p, slimefunItem, false)) {
|
||||
if (Slimefun.isEnabled(p, slimefunItem, false)) {
|
||||
addSlimefunItem(category, page, p, profile, slimefunItem, items);
|
||||
}
|
||||
} else {
|
||||
ChatComponent component = new ChatComponent(ChatUtils.crop(ChatColor.DARK_RED, ItemUtils.getItemName(slimefunItem.getItem())) + "\n");
|
||||
|
||||
List<String> lore = new ArrayList<>();
|
||||
lore.add(ChatColor.DARK_RED + ChatColor.stripColor(ItemUtils.getItemName(slimefunItem.getItem())));
|
||||
lore.add("");
|
||||
|
||||
for (String line : SlimefunPlugin.getPermissionsService().getLore(slimefunItem)) {
|
||||
lore.add(ChatColors.color(line));
|
||||
}
|
||||
|
||||
component.setHoverEvent(new HoverEvent(lore));
|
||||
items.add(component);
|
||||
}
|
||||
}
|
||||
|
||||
openBook(p, profile, items, true);
|
||||
} else {
|
||||
p.sendMessage(ChatColor.RED + "That Category is too big to open :/");
|
||||
}
|
||||
}
|
||||
|
||||
private void addSlimefunItem(Category category, int page, Player p, PlayerProfile profile, SlimefunItem item, List<ChatComponent> items) {
|
||||
NamespacedKey key = new NamespacedKey(SlimefunPlugin.instance(), item.getId().toLowerCase(Locale.ROOT));
|
||||
|
||||
if (!Slimefun.hasUnlocked(p, item, false) && item.getResearch() != null) {
|
||||
Research research = item.getResearch();
|
||||
|
||||
ChatComponent component = new ChatComponent(ChatUtils.crop(ChatColor.RED, item.getItemName()) + "\n");
|
||||
component.setHoverEvent(new HoverEvent(ChatColor.RESET + item.getItemName(), ChatColor.DARK_RED.toString() + ChatColor.BOLD + SlimefunPlugin.getLocalization().getMessage(p, "guide.locked"), "", ChatColor.GREEN + "> Click to unlock", "", ChatColor.GRAY + "Cost: " + ChatColor.AQUA.toString() + research.getCost() + " Level(s)"));
|
||||
component.setClickEvent(new ClickEvent(key, player -> SlimefunPlugin.runSync(() -> research.unlockFromGuide(this, player, profile, item, category, page))));
|
||||
|
||||
items.add(component);
|
||||
} else {
|
||||
ChatComponent component = new ChatComponent(ChatUtils.crop(ChatColor.DARK_GREEN, item.getItemName()) + "\n");
|
||||
|
||||
List<String> lore = new ArrayList<>();
|
||||
lore.add(item.getItemName());
|
||||
|
||||
if (item.getItem().hasItemMeta() && item.getItem().getItemMeta().hasLore()) {
|
||||
lore.addAll(item.getItem().getItemMeta().getLore());
|
||||
}
|
||||
|
||||
component.setHoverEvent(new HoverEvent(lore));
|
||||
component.setClickEvent(new ClickEvent(key, player -> SlimefunPlugin.runSync(() -> displayItem(profile, item, true))));
|
||||
items.add(component);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openSearch(PlayerProfile profile, String input, boolean addToHistory) {
|
||||
// We need to write a book implementation for this at some point
|
||||
SlimefunGuide.openSearch(profile, input, true, addToHistory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayItem(PlayerProfile profile, ItemStack item, int index, boolean addToHistory) {
|
||||
SlimefunGuide.displayItem(profile, item, addToHistory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayItem(PlayerProfile profile, SlimefunItem item, boolean addToHistory) {
|
||||
SlimefunGuide.displayItem(profile, item, addToHistory);
|
||||
}
|
||||
|
||||
}
|
@ -12,7 +12,7 @@ import org.bukkit.inventory.Recipe;
|
||||
|
||||
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
|
||||
import io.github.thebusybiscuit.slimefun4.core.categories.FlexCategory;
|
||||
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideLayout;
|
||||
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideMode;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.itemstack.SlimefunGuideItem;
|
||||
@ -21,13 +21,13 @@ import me.mrCookieSlime.Slimefun.Objects.Category;
|
||||
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||
|
||||
/**
|
||||
* This is an admin-variant of the {@link ChestSlimefunGuide} which allows a {@link Player}
|
||||
* This is an admin-variant of the {@link SurvivalSlimefunGuide} which allows a {@link Player}
|
||||
* to spawn in a {@link SlimefunItem} via click rather than showing their {@link Recipe}.
|
||||
*
|
||||
* @author TheBusyBiscuit
|
||||
*
|
||||
*/
|
||||
public class CheatSheetSlimefunGuide extends ChestSlimefunGuide {
|
||||
public class CheatSheetSlimefunGuide extends SurvivalSlimefunGuide {
|
||||
|
||||
private final ItemStack item;
|
||||
|
||||
@ -37,11 +37,6 @@ public class CheatSheetSlimefunGuide extends ChestSlimefunGuide {
|
||||
item = new SlimefunGuideItem(this, "&cSlimefun Guide &4(Cheat Sheet)");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSurvivalMode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link List} of visible {@link Category} instances that the {@link SlimefunGuide} would display.
|
||||
*
|
||||
@ -65,11 +60,13 @@ public class CheatSheetSlimefunGuide extends ChestSlimefunGuide {
|
||||
return categories;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public SlimefunGuideLayout getLayout() {
|
||||
return SlimefunGuideLayout.CHEAT_SHEET;
|
||||
public SlimefunGuideMode getMode() {
|
||||
return SlimefunGuideMode.CHEAT_MODE;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public ItemStack getItem() {
|
||||
return item;
|
||||
|
@ -21,7 +21,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
* A {@link RecipeChoiceTask} is an asynchronously repeating task that cycles
|
||||
* through the different variants of {@link Material} that a {@link MaterialChoice} or {@link Tag} can represent.
|
||||
*
|
||||
* It is used in the {@link ChestSlimefunGuide} for any {@link ItemStack} from Minecraft
|
||||
* It is used in the {@link SurvivalSlimefunGuide} for any {@link ItemStack} from Minecraft
|
||||
* that accepts more than one {@link Material} in its {@link Recipe}.
|
||||
*
|
||||
* @author TheBusyBiscuit
|
||||
|
@ -27,6 +27,7 @@ import io.github.thebusybiscuit.cscorelib2.chat.ChatInput;
|
||||
import io.github.thebusybiscuit.cscorelib2.inventory.ItemUtils;
|
||||
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
|
||||
import io.github.thebusybiscuit.cscorelib2.recipes.MinecraftRecipe;
|
||||
import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon;
|
||||
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
|
||||
import io.github.thebusybiscuit.slimefun4.core.attributes.RecipeDisplayItem;
|
||||
import io.github.thebusybiscuit.slimefun4.core.categories.FlexCategory;
|
||||
@ -34,7 +35,7 @@ import io.github.thebusybiscuit.slimefun4.core.categories.LockedCategory;
|
||||
import io.github.thebusybiscuit.slimefun4.core.guide.GuideHistory;
|
||||
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuide;
|
||||
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideImplementation;
|
||||
import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideLayout;
|
||||
import io.github.thebusybiscuit.slimefun4.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;
|
||||
@ -51,18 +52,17 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||
import me.mrCookieSlime.Slimefun.api.Slimefun;
|
||||
|
||||
/**
|
||||
* The {@link ChestSlimefunGuide} is the standard version of our {@link SlimefunGuide}.
|
||||
* The {@link SurvivalSlimefunGuide} is the standard version of our {@link SlimefunGuide}.
|
||||
* It uses an {@link Inventory} to display {@link SlimefunGuide} contents.
|
||||
*
|
||||
* @author TheBusyBiscuit
|
||||
*
|
||||
* @see SlimefunGuide
|
||||
* @see SlimefunGuideImplementation
|
||||
* @see BookSlimefunGuide
|
||||
* @see CheatSheetSlimefunGuide
|
||||
*
|
||||
*/
|
||||
public class ChestSlimefunGuide implements SlimefunGuideImplementation {
|
||||
public class SurvivalSlimefunGuide implements SlimefunGuideImplementation {
|
||||
|
||||
private static final int CATEGORY_SIZE = 36;
|
||||
private static final Sound sound = Sound.ITEM_BOOK_PAGE_TURN;
|
||||
@ -71,14 +71,14 @@ public class ChestSlimefunGuide implements SlimefunGuideImplementation {
|
||||
private final ItemStack item;
|
||||
private final boolean showVanillaRecipes;
|
||||
|
||||
public ChestSlimefunGuide(boolean showVanillaRecipes) {
|
||||
public SurvivalSlimefunGuide(boolean showVanillaRecipes) {
|
||||
this.showVanillaRecipes = showVanillaRecipes;
|
||||
item = new SlimefunGuideItem(this, "&aSlimefun Guide &7(Chest GUI)");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SlimefunGuideLayout getLayout() {
|
||||
return SlimefunGuideLayout.CHEST;
|
||||
public SlimefunGuideMode getMode() {
|
||||
return SlimefunGuideMode.SURVIVAL_MODE;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -86,9 +86,8 @@ public class ChestSlimefunGuide implements SlimefunGuideImplementation {
|
||||
return item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSurvivalMode() {
|
||||
return true;
|
||||
protected final boolean isSurvivalMode() {
|
||||
return getMode() != SlimefunGuideMode.CHEAT_MODE;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -105,8 +104,18 @@ public class ChestSlimefunGuide implements SlimefunGuideImplementation {
|
||||
List<Category> categories = new LinkedList<>();
|
||||
|
||||
for (Category category : SlimefunPlugin.getRegistry().getCategories()) {
|
||||
if (!category.isHidden(p) && (!(category instanceof FlexCategory) || ((FlexCategory) category).isVisible(p, profile, getLayout()))) {
|
||||
categories.add(category);
|
||||
try {
|
||||
if (!category.isHidden(p) && (!(category instanceof FlexCategory) || ((FlexCategory) category).isVisible(p, profile, getMode()))) {
|
||||
categories.add(category);
|
||||
}
|
||||
} catch (Exception | LinkageError x) {
|
||||
SlimefunAddon addon = category.getAddon();
|
||||
|
||||
if (addon != null) {
|
||||
addon.getLogger().log(Level.SEVERE, x, () -> "Could not display Category: " + category);
|
||||
} else {
|
||||
SlimefunPlugin.logger().log(Level.SEVERE, x, () -> "Could not display Category: " + category);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -204,7 +213,7 @@ public class ChestSlimefunGuide implements SlimefunGuideImplementation {
|
||||
}
|
||||
|
||||
if (category instanceof FlexCategory) {
|
||||
((FlexCategory) category).open(p, profile, getLayout());
|
||||
((FlexCategory) category).open(p, profile, getMode());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -561,7 +570,7 @@ public class ChestSlimefunGuide implements SlimefunGuideImplementation {
|
||||
pl.closeInventory();
|
||||
|
||||
SlimefunPlugin.getLocalization().sendMessage(pl, "guide.search.message");
|
||||
ChatInput.waitForPlayer(SlimefunPlugin.instance(), pl, msg -> SlimefunGuide.openSearch(profile, msg, isSurvivalMode(), isSurvivalMode()));
|
||||
ChatInput.waitForPlayer(SlimefunPlugin.instance(), pl, msg -> SlimefunGuide.openSearch(profile, msg, getMode(), isSurvivalMode()));
|
||||
|
||||
return false;
|
||||
});
|
||||
@ -698,7 +707,7 @@ public class ChestSlimefunGuide implements SlimefunGuideImplementation {
|
||||
|
||||
private void printErrorMessage(Player p, Throwable x) {
|
||||
p.sendMessage(ChatColor.DARK_RED + "An internal server error has occurred. Please inform an admin, check the console for further info.");
|
||||
Slimefun.getLogger().log(Level.SEVERE, "An error has occurred while trying to open a SlimefunItem in the guide!", x);
|
||||
SlimefunPlugin.logger().log(Level.SEVERE, "An error has occurred while trying to open a SlimefunItem in the guide!", x);
|
||||
}
|
||||
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package io.github.thebusybiscuit.slimefun4.implementation.items;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
@ -36,7 +37,7 @@ public abstract class SimpleSlimefunItem<T extends ItemHandler> extends Slimefun
|
||||
}
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
public SimpleSlimefunItem(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, ItemStack recipeOutput) {
|
||||
public SimpleSlimefunItem(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, @Nullable ItemStack recipeOutput) {
|
||||
super(category, item, recipeType, recipe, recipeOutput);
|
||||
}
|
||||
|
||||
|
@ -1,55 +0,0 @@
|
||||
package io.github.thebusybiscuit.slimefun4.implementation.items.androids;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
import org.bukkit.Effect;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
|
||||
import me.mrCookieSlime.Slimefun.Objects.Category;
|
||||
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
|
||||
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
|
||||
|
||||
/**
|
||||
* The {@link AdvancedFarmerAndroid} is an extension of the {@link FarmerAndroid}.
|
||||
* It also allows the {@link Player} to harvest plants from the addon ExoticGarden.
|
||||
*
|
||||
* @author John000708
|
||||
* @author TheBusyBiscuit
|
||||
*
|
||||
* @see FarmerAndroid
|
||||
*
|
||||
*/
|
||||
public class AdvancedFarmerAndroid extends FarmerAndroid {
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
public AdvancedFarmerAndroid(Category category, int tier, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
|
||||
super(category, tier, item, recipeType, recipe);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AndroidType getAndroidType() {
|
||||
return AndroidType.ADVANCED_FARMER;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void exoticFarm(BlockMenu menu, Block block) {
|
||||
farm(menu, block);
|
||||
|
||||
if (SlimefunPlugin.getIntegrations().isExoticGardenInstalled()) {
|
||||
Optional<ItemStack> result = SlimefunPlugin.getThirdPartySupportService().harvestExoticGardenPlant(block);
|
||||
|
||||
if (result.isPresent()) {
|
||||
ItemStack drop = result.get();
|
||||
menu.pushItem(drop, getOutputSlots());
|
||||
block.getWorld().playEffect(block.getLocation(), Effect.STEP_SOUND, block.getType());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -29,7 +29,7 @@ public enum AndroidType {
|
||||
FARMER,
|
||||
|
||||
/**
|
||||
* The {@link AdvancedFarmerAndroid} is an extension of the {@link FarmerAndroid},
|
||||
* The Advanced Farmer is an extension of the {@link FarmerAndroid},
|
||||
* it can also harvest plants from ExoticGarden.
|
||||
*/
|
||||
ADVANCED_FARMER,
|
||||
|
@ -3,6 +3,9 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.androids;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Effect;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
@ -10,6 +13,7 @@ import org.bukkit.block.data.Ageable;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import io.github.thebusybiscuit.slimefun4.api.events.AndroidFarmEvent;
|
||||
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
|
||||
import me.mrCookieSlime.Slimefun.Objects.Category;
|
||||
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
|
||||
@ -17,37 +21,41 @@ import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
|
||||
|
||||
public class FarmerAndroid extends ProgrammableAndroid {
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
public FarmerAndroid(Category category, int tier, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
|
||||
super(category, tier, item, recipeType, recipe);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AndroidType getAndroidType() {
|
||||
return AndroidType.FARMER;
|
||||
}
|
||||
|
||||
private boolean isFullGrown(Block block) {
|
||||
BlockData data = block.getBlockData();
|
||||
|
||||
if (!(data instanceof Ageable)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Ageable ageable = (Ageable) data;
|
||||
return ageable.getAge() >= ageable.getMaximumAge();
|
||||
return getTier() == 1 ? AndroidType.FARMER : AndroidType.ADVANCED_FARMER;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void farm(BlockMenu menu, Block block) {
|
||||
if (isFullGrown(block)) {
|
||||
ItemStack drop = getDropFromCrop(block.getType());
|
||||
protected void farm(Block b, BlockMenu menu, Block block, boolean isAdvanced) {
|
||||
Material blockType = block.getType();
|
||||
BlockData data = block.getBlockData();
|
||||
ItemStack drop = null;
|
||||
|
||||
if (drop != null && menu.fits(drop, getOutputSlots())) {
|
||||
menu.pushItem(drop, getOutputSlots());
|
||||
Ageable ageable = (Ageable) block.getBlockData();
|
||||
ageable.setAge(0);
|
||||
block.setBlockData(ageable);
|
||||
block.getWorld().playEffect(block.getLocation(), Effect.STEP_SOUND, block.getType());
|
||||
if (data instanceof Ageable && ((Ageable) data).getAge() >= ((Ageable) data).getMaximumAge()) {
|
||||
drop = getDropFromCrop(blockType);
|
||||
}
|
||||
|
||||
AndroidInstance instance = new AndroidInstance(this, b);
|
||||
|
||||
AndroidFarmEvent event = new AndroidFarmEvent(block, instance, isAdvanced, drop);
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
|
||||
if (!event.isCancelled()) {
|
||||
drop = event.getDrop();
|
||||
|
||||
if (drop != null && menu.pushItem(drop, getOutputSlots()) == null) {
|
||||
block.getWorld().playEffect(block.getLocation(), Effect.STEP_SOUND, blockType);
|
||||
|
||||
if (data instanceof Ageable) {
|
||||
((Ageable) data).setAge(0);
|
||||
block.setBlockData(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,12 @@
|
||||
package io.github.thebusybiscuit.slimefun4.implementation.items.androids;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.Location;
|
||||
@ -191,7 +192,7 @@ public enum Instruction {
|
||||
*/
|
||||
FARM_FORWARD(AndroidType.FARMER, HeadTexture.SCRIPT_FARM_FORWARD, (android, b, inv, face) -> {
|
||||
Block target = b.getRelative(face);
|
||||
android.farm(inv, target);
|
||||
android.farm(b, inv, target, false);
|
||||
}),
|
||||
|
||||
/**
|
||||
@ -200,7 +201,7 @@ public enum Instruction {
|
||||
*/
|
||||
FARM_DOWN(AndroidType.FARMER, HeadTexture.SCRIPT_FARM_DOWN, (android, b, inv, face) -> {
|
||||
Block target = b.getRelative(BlockFace.DOWN);
|
||||
android.farm(inv, target);
|
||||
android.farm(b, inv, target, false);
|
||||
}),
|
||||
|
||||
/**
|
||||
@ -211,7 +212,7 @@ public enum Instruction {
|
||||
*/
|
||||
FARM_EXOTIC_FORWARD(AndroidType.ADVANCED_FARMER, HeadTexture.SCRIPT_FARM_FORWARD, (android, b, inv, face) -> {
|
||||
Block target = b.getRelative(face);
|
||||
android.exoticFarm(inv, target);
|
||||
android.farm(b, inv, target, true);
|
||||
}),
|
||||
|
||||
/**
|
||||
@ -222,7 +223,7 @@ public enum Instruction {
|
||||
*/
|
||||
FARM_EXOTIC_DOWN(AndroidType.ADVANCED_FARMER, HeadTexture.SCRIPT_FARM_DOWN, (android, b, inv, face) -> {
|
||||
Block target = b.getRelative(BlockFace.DOWN);
|
||||
android.exoticFarm(inv, target);
|
||||
android.farm(b, inv, target, true);
|
||||
}),
|
||||
|
||||
/**
|
||||
|
@ -58,7 +58,6 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.interfaces.InventoryBlock;
|
||||
import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker;
|
||||
import me.mrCookieSlime.Slimefun.Objects.handlers.ItemHandler;
|
||||
import me.mrCookieSlime.Slimefun.api.BlockStorage;
|
||||
import me.mrCookieSlime.Slimefun.api.Slimefun;
|
||||
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
|
||||
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
|
||||
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenuPreset;
|
||||
@ -76,6 +75,7 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock,
|
||||
protected final String texture;
|
||||
private final int tier;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
public ProgrammableAndroid(Category category, int tier, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
|
||||
super(category, item, recipeType, recipe);
|
||||
|
||||
@ -425,7 +425,7 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock,
|
||||
openScriptEditor(player, b);
|
||||
}
|
||||
} catch (Exception x) {
|
||||
Slimefun.getLogger().log(Level.SEVERE, "An Exception was thrown when a User tried to download a Script!", x);
|
||||
SlimefunPlugin.logger().log(Level.SEVERE, "An Exception was thrown when a User tried to download a Script!", x);
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -471,7 +471,12 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock,
|
||||
|
||||
menu.addItem(1, new CustomItem(HeadTexture.SCRIPT_FORWARD.getAsItemStack(), "&2> Edit Script", "", "&aEdits your current Script"));
|
||||
menu.addMenuClickHandler(1, (pl, slot, item, action) -> {
|
||||
openScript(pl, b, getScript(b.getLocation()));
|
||||
if (PatternUtils.DASH.split(BlockStorage.getLocationInfo(b.getLocation()).getString("script")).length <= MAX_SCRIPT_LENGTH) {
|
||||
openScript(pl, b, getScript(b.getLocation()));
|
||||
} else {
|
||||
pl.closeInventory();
|
||||
SlimefunPlugin.getLocalization().sendMessage(pl, "android.scripts.too-long");
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
@ -844,6 +849,7 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock,
|
||||
}
|
||||
}
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
protected void move(Block b, BlockFace face, Block block) {
|
||||
if (block.getY() > 0 && block.getY() < block.getWorld().getMaxHeight() && block.isEmpty()) {
|
||||
BlockData blockData = Material.PLAYER_HEAD.createBlockData(data -> {
|
||||
@ -881,11 +887,7 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock,
|
||||
throw new UnsupportedOperationException("Non-woodcutter Android tried to chop a Tree!");
|
||||
}
|
||||
|
||||
protected void farm(BlockMenu menu, Block block) {
|
||||
throw new UnsupportedOperationException("Non-farming Android tried to farm!");
|
||||
}
|
||||
|
||||
protected void exoticFarm(BlockMenu menu, Block block) {
|
||||
protected void farm(Block b, BlockMenu menu, Block block, boolean isAdvanced) {
|
||||
throw new UnsupportedOperationException("Non-farming Android tried to farm!");
|
||||
}
|
||||
|
||||
|
@ -21,9 +21,9 @@ import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import io.github.thebusybiscuit.cscorelib2.config.Config;
|
||||
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.ChatUtils;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
|
||||
import me.mrCookieSlime.Slimefun.api.Slimefun;
|
||||
|
||||
/**
|
||||
* A {@link Script} represents runnable code for a {@link ProgrammableAndroid}.
|
||||
@ -244,7 +244,7 @@ public final class Script {
|
||||
scripts.add(new Script(config));
|
||||
}
|
||||
} catch (Exception x) {
|
||||
Slimefun.getLogger().log(Level.SEVERE, x, () -> "An Exception occurred while trying to load Android Script '" + file.getName() + "'");
|
||||
SlimefunPlugin.logger().log(Level.SEVERE, x, () -> "An Exception occurred while trying to load Android Script '" + file.getName() + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -105,7 +105,6 @@ public class StomperBoots extends SlimefunItem {
|
||||
* @return If the entity can move.
|
||||
*/
|
||||
protected boolean canPush(@Nonnull Player player, @Nonnull LivingEntity entity) {
|
||||
return entity.isValid() && !entity.getUniqueId().equals(player.getUniqueId())
|
||||
&& entity.isCollidable() && entity.hasGravity();
|
||||
return entity.isValid() && !entity.getUniqueId().equals(player.getUniqueId()) && entity.isCollidable() && entity.hasGravity();
|
||||
}
|
||||
}
|
||||
|
@ -11,12 +11,13 @@ import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import io.github.thebusybiscuit.cscorelib2.chat.ChatColors;
|
||||
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
|
||||
import io.github.thebusybiscuit.cscorelib2.math.DoubleHandler;
|
||||
import io.github.thebusybiscuit.slimefun4.core.attributes.HologramOwner;
|
||||
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
|
||||
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler;
|
||||
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockUseHandler;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.ChatUtils;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.holograms.SimpleHologram;
|
||||
import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu;
|
||||
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
|
||||
@ -25,7 +26,7 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||
import me.mrCookieSlime.Slimefun.api.BlockStorage;
|
||||
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
|
||||
|
||||
public class HologramProjector extends SlimefunItem {
|
||||
public class HologramProjector extends SlimefunItem implements HologramOwner {
|
||||
|
||||
private static final String OFFSET_PARAMETER = "offset";
|
||||
|
||||
@ -89,9 +90,9 @@ public class HologramProjector extends SlimefunItem {
|
||||
return false;
|
||||
});
|
||||
|
||||
menu.addItem(1, new CustomItem(Material.CLOCK, "&7Offset: &e" + DoubleHandler.fixDouble(Double.valueOf(BlockStorage.getLocationInfo(projector.getLocation(), OFFSET_PARAMETER)) + 1.0D), "", "&rLeft Click: &7+0.1", "&rRight Click: &7-0.1"));
|
||||
menu.addItem(1, new CustomItem(Material.CLOCK, "&7Offset: &e" + NumberUtils.roundDecimalNumber(Double.valueOf(BlockStorage.getLocationInfo(projector.getLocation(), OFFSET_PARAMETER)) + 1.0D), "", "&rLeft Click: &7+0.1", "&rRight Click: &7-0.1"));
|
||||
menu.addMenuClickHandler(1, (pl, slot, item, action) -> {
|
||||
double offset = DoubleHandler.fixDouble(Double.valueOf(BlockStorage.getLocationInfo(projector.getLocation(), OFFSET_PARAMETER)) + (action.isRightClicked() ? -0.1F : 0.1F));
|
||||
double offset = NumberUtils.reparseDouble(Double.valueOf(BlockStorage.getLocationInfo(projector.getLocation(), OFFSET_PARAMETER)) + (action.isRightClicked() ? -0.1F : 0.1F));
|
||||
ArmorStand hologram = getArmorStand(projector, true);
|
||||
Location l = new Location(projector.getWorld(), projector.getX() + 0.5, projector.getY() + offset, projector.getZ() + 0.5);
|
||||
hologram.teleport(l);
|
||||
|
@ -1,8 +1,10 @@
|
||||
package io.github.thebusybiscuit.slimefun4.implementation.items.cargo;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
@ -33,12 +35,12 @@ import me.mrCookieSlime.Slimefun.api.item_transport.ItemTransportFlow;
|
||||
* @author TheBusyBiscuit
|
||||
*
|
||||
*/
|
||||
abstract class AbstractCargoNode extends SimpleSlimefunItem<BlockPlaceHandler> {
|
||||
abstract class AbstractCargoNode extends SimpleSlimefunItem<BlockPlaceHandler> implements CargoNode {
|
||||
|
||||
protected static final String FREQUENCY = "frequency";
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
public AbstractCargoNode(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, ItemStack recipeOutput) {
|
||||
AbstractCargoNode(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, @Nullable ItemStack recipeOutput) {
|
||||
super(category, item, recipeType, recipe, recipeOutput);
|
||||
|
||||
new BlockMenuPreset(getId(), ChatUtils.removeColorCodes(item.getItemMeta().getDisplayName())) {
|
||||
@ -132,7 +134,10 @@ abstract class AbstractCargoNode extends SimpleSlimefunItem<BlockPlaceHandler> {
|
||||
});
|
||||
}
|
||||
|
||||
private int getSelectedChannel(@Nonnull Block b) {
|
||||
@Override
|
||||
public int getSelectedChannel(@Nonnull Block b) {
|
||||
Validate.notNull(b, "Block must not be null");
|
||||
|
||||
if (!BlockStorage.hasBlockInfo(b)) {
|
||||
return 0;
|
||||
} else {
|
||||
@ -147,12 +152,12 @@ abstract class AbstractCargoNode extends SimpleSlimefunItem<BlockPlaceHandler> {
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void onPlace(@Nonnull BlockPlaceEvent e);
|
||||
abstract void onPlace(@Nonnull BlockPlaceEvent e);
|
||||
|
||||
protected abstract void createBorder(@Nonnull BlockMenuPreset preset);
|
||||
abstract void createBorder(@Nonnull BlockMenuPreset preset);
|
||||
|
||||
protected abstract void updateBlockMenu(@Nonnull BlockMenu menu, @Nonnull Block b);
|
||||
abstract void updateBlockMenu(@Nonnull BlockMenu menu, @Nonnull Block b);
|
||||
|
||||
protected abstract void markDirty(@Nonnull Location loc);
|
||||
abstract void markDirty(@Nonnull Location loc);
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
package io.github.thebusybiscuit.slimefun4.implementation.items.cargo;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
@ -33,7 +35,8 @@ abstract class AbstractFilterNode extends AbstractCargoNode {
|
||||
private static final String FILTER_TYPE = "filter-type";
|
||||
private static final String FILTER_LORE = "filter-lore";
|
||||
|
||||
public AbstractFilterNode(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, ItemStack recipeOutput) {
|
||||
@ParametersAreNonnullByDefault
|
||||
public AbstractFilterNode(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, @Nullable ItemStack recipeOutput) {
|
||||
super(category, item, recipeType, recipe, recipeOutput);
|
||||
|
||||
registerBlockHandler(getId(), (p, b, stack, reason) -> {
|
||||
@ -47,6 +50,7 @@ abstract class AbstractFilterNode extends AbstractCargoNode {
|
||||
});
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
protected abstract int[] getBorder();
|
||||
|
||||
@Override
|
||||
|
@ -1,15 +1,25 @@
|
||||
package io.github.thebusybiscuit.slimefun4.implementation.items.cargo;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
|
||||
import me.mrCookieSlime.Slimefun.Objects.Category;
|
||||
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
|
||||
|
||||
/**
|
||||
* The {@link AdvancedCargoOutputNode} is the advanced version of the
|
||||
* {@link CargoOutputNode}. It comes with the option to filter items.
|
||||
*
|
||||
* @author TheBusyBiscuit
|
||||
*
|
||||
*/
|
||||
public class AdvancedCargoOutputNode extends AbstractFilterNode {
|
||||
|
||||
private static final int[] BORDER = { 0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 18, 22, 23, 24, 26, 27, 31, 32, 33, 34, 35, 36, 40, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53 };
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
public AdvancedCargoOutputNode(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
|
||||
super(category, item, recipeType, recipe, null);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package io.github.thebusybiscuit.slimefun4.implementation.items.cargo;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
@ -14,8 +15,19 @@ import me.mrCookieSlime.Slimefun.Lists.RecipeType;
|
||||
import me.mrCookieSlime.Slimefun.Objects.Category;
|
||||
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
|
||||
|
||||
/**
|
||||
* The {@link CargoConnectorNode} connects a {@link CargoNode} with a {@link CargoNet}.
|
||||
* It has no further functionality.
|
||||
*
|
||||
* @author TheBusyBiscuit
|
||||
*
|
||||
* @see CargoNode
|
||||
* @see CargoNet
|
||||
*
|
||||
*/
|
||||
public class CargoConnectorNode extends SimpleSlimefunItem<BlockUseHandler> {
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
public CargoConnectorNode(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, ItemStack recipeOutput) {
|
||||
super(category, item, recipeType, recipe, recipeOutput);
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user