mirror of
https://github.com/StarWishsama/Slimefun4.git
synced 2024-09-20 11:45:51 +00:00
Merge branch 'master' of https://github.com/Slimefun/Slimefun4 into master
This commit is contained in:
commit
8324f5d830
11
.github/configs/yaml-linter.yml
vendored
11
.github/configs/yaml-linter.yml
vendored
@ -6,10 +6,13 @@ yaml-files:
|
||||
|
||||
rules:
|
||||
|
||||
## A warning is sufficient here
|
||||
line-length:
|
||||
max: 180
|
||||
level: warning
|
||||
## Don't warn for line lengths
|
||||
line-length: disable
|
||||
|
||||
truthy:
|
||||
allowed-values: ['true', 'false']
|
||||
## We don't want it to trigger for the 'on' in our workflows
|
||||
check-keys: false
|
||||
|
||||
## We don't need indentation warnings
|
||||
indentation: disable
|
||||
|
4
.github/workflows/url-checker.yml
vendored
4
.github/workflows/url-checker.yml
vendored
@ -6,7 +6,7 @@ on:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build:
|
||||
check:
|
||||
|
||||
name: URL Checker
|
||||
runs-on: ubuntu-latest
|
||||
@ -17,7 +17,7 @@ jobs:
|
||||
with:
|
||||
git_path: https://github.com/Slimefun/Slimefun4
|
||||
file_types: .md,.java,.yml
|
||||
print_all: False
|
||||
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
.github/workflows/yaml-linter.yml
vendored
2
.github/workflows/yaml-linter.yml
vendored
@ -18,6 +18,6 @@ jobs:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
- name: YAML Linter
|
||||
uses: ibiqlik/action-yamllint@v1.0.0
|
||||
uses: ibiqlik/action-yamllint@v2.0.0
|
||||
with:
|
||||
config_file: '.github/configs/yaml-linter.yml'
|
||||
|
11
CHANGELOG.md
11
CHANGELOG.md
@ -29,6 +29,12 @@
|
||||
|
||||
#### Changes
|
||||
* Removed 1.13 support
|
||||
* Cooling Units can no longer be placed down
|
||||
* Heating Coils can no longer be placed down
|
||||
* Electric Motors can no longer be placed down
|
||||
* Cargo Motors can no longer be placed down
|
||||
* Magnets can no longer be placed down
|
||||
* Electromagnets can no longer be placed down
|
||||
|
||||
#### Fixes
|
||||
* Fixed #2448
|
||||
@ -36,6 +42,11 @@
|
||||
* Fixed #2478
|
||||
* Fixed #2493
|
||||
* Fixed a missing slot in the contributors menu
|
||||
* Fixed color codes in script downloading screen
|
||||
* Fixed #2505
|
||||
* Fixed contributors not showing correctly
|
||||
* Fixed #2469
|
||||
* Fixed #2509
|
||||
|
||||
## Release Candidate 17 (17 Oct 2020)
|
||||
|
||||
|
4
pom.xml
4
pom.xml
@ -329,7 +329,7 @@
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>3.5.15</version>
|
||||
<version>3.6.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@ -381,7 +381,7 @@
|
||||
<dependency>
|
||||
<groupId>com.gmail.nossr50.mcMMO</groupId>
|
||||
<artifactId>mcMMO</artifactId>
|
||||
<version>2.1.149</version>
|
||||
<version>2.1.150</version>
|
||||
<scope>provided</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
|
@ -2,6 +2,9 @@ package io.github.thebusybiscuit.slimefun4.core.services;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.bukkit.Keyed;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
@ -11,6 +14,9 @@ import org.bukkit.block.TileState;
|
||||
import org.bukkit.persistence.PersistentDataHolder;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import io.papermc.lib.PaperLib;
|
||||
import io.papermc.lib.features.blockstatesnapshot.BlockStateSnapshotResult;
|
||||
|
||||
/**
|
||||
* The {@link BlockDataService} is similar to the {@link CustomItemDataService},
|
||||
* it is responsible for storing NBT data inside a {@link TileState}.
|
||||
@ -24,7 +30,17 @@ public class BlockDataService implements PersistentDataService, Keyed {
|
||||
|
||||
private final NamespacedKey namespacedKey;
|
||||
|
||||
public BlockDataService(Plugin plugin, String key) {
|
||||
/**
|
||||
* This creates a new {@link BlockDataService} for the given {@link Plugin}.
|
||||
* The {@link Plugin} and key will together form a {@link NamespacedKey} used to store
|
||||
* data on a {@link TileState}.
|
||||
*
|
||||
* @param plugin
|
||||
* The {@link Plugin} responsible for this service
|
||||
* @param key
|
||||
* The key under which to store data
|
||||
*/
|
||||
public BlockDataService(@Nonnull Plugin plugin, @Nonnull String key) {
|
||||
namespacedKey = new NamespacedKey(plugin, key);
|
||||
}
|
||||
|
||||
@ -41,12 +57,16 @@ public class BlockDataService implements PersistentDataService, Keyed {
|
||||
* @param value
|
||||
* The value to store
|
||||
*/
|
||||
public void setBlockData(Block b, String value) {
|
||||
BlockState state = b.getState();
|
||||
public void setBlockData(@Nonnull Block b, @Nonnull String value) {
|
||||
BlockStateSnapshotResult result = PaperLib.getBlockState(b, false);
|
||||
BlockState state = result.getState();
|
||||
|
||||
if (state instanceof TileState) {
|
||||
setString((TileState) state, namespacedKey, value);
|
||||
state.update();
|
||||
|
||||
if (result.isSnapshot()) {
|
||||
state.update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,8 +77,8 @@ public class BlockDataService implements PersistentDataService, Keyed {
|
||||
* The {@link Block} to retrieve data from
|
||||
* @return The stored value
|
||||
*/
|
||||
public Optional<String> getBlockData(Block b) {
|
||||
BlockState state = b.getState();
|
||||
public Optional<String> getBlockData(@Nonnull Block b) {
|
||||
BlockState state = PaperLib.getBlockState(b, false).getState();
|
||||
|
||||
if (state instanceof TileState) {
|
||||
return getString((TileState) state, namespacedKey);
|
||||
@ -77,9 +97,10 @@ public class BlockDataService implements PersistentDataService, Keyed {
|
||||
*
|
||||
* @param type
|
||||
* The {@link Material} to check for
|
||||
*
|
||||
* @return Whether the given {@link Material} is considered a Tile Entity
|
||||
*/
|
||||
public boolean isTileEntity(Material type) {
|
||||
public boolean isTileEntity(@Nullable Material type) {
|
||||
if (type == null || type.isAir()) {
|
||||
// Cannot store data on air
|
||||
return false;
|
||||
@ -104,8 +125,10 @@ public class BlockDataService implements PersistentDataService, Keyed {
|
||||
case BARREL:
|
||||
case SPAWNER:
|
||||
case BEACON:
|
||||
// All of the above Materials are Tile Entities
|
||||
return true;
|
||||
default:
|
||||
// Otherwise we assume they're not Tile Entities
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,10 @@ package io.github.thebusybiscuit.slimefun4.core.services;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.Keyed;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
@ -35,7 +39,7 @@ public class CustomItemDataService implements PersistentDataService, Keyed {
|
||||
* @param key
|
||||
* The key under which to store data
|
||||
*/
|
||||
public CustomItemDataService(Plugin plugin, String key) {
|
||||
public CustomItemDataService(@Nonnull Plugin plugin, @Nonnull String key) {
|
||||
// Null-Validation is performed in the NamespacedKey constructor
|
||||
namespacedKey = new NamespacedKey(plugin, key);
|
||||
}
|
||||
@ -45,13 +49,37 @@ public class CustomItemDataService implements PersistentDataService, Keyed {
|
||||
return namespacedKey;
|
||||
}
|
||||
|
||||
public void setItemData(ItemStack item, String id) {
|
||||
/**
|
||||
* This method stores the given id on the provided {@link ItemStack} via
|
||||
* persistent data.
|
||||
*
|
||||
* @param item
|
||||
* The {@link ItemStack} to store data on
|
||||
* @param id
|
||||
* The id to store on the {@link ItemStack}
|
||||
*/
|
||||
public void setItemData(@Nonnull ItemStack item, @Nonnull String id) {
|
||||
Validate.notNull(item, "The Item cannot be null!");
|
||||
Validate.notNull(id, "Cannot store null on an Item!");
|
||||
|
||||
ItemMeta im = item.getItemMeta();
|
||||
setItemData(im, id);
|
||||
item.setItemMeta(im);
|
||||
}
|
||||
|
||||
public void setItemData(ItemMeta im, String id) {
|
||||
/**
|
||||
* This method stores the given id on the provided {@link ItemMeta} via
|
||||
* persistent data.
|
||||
*
|
||||
* @param im
|
||||
* The {@link ItemMeta} to store data on
|
||||
* @param id
|
||||
* The id to store on the {@link ItemMeta}
|
||||
*/
|
||||
public void setItemData(@Nonnull ItemMeta im, @Nonnull String id) {
|
||||
Validate.notNull(im, "The ItemMeta cannot be null!");
|
||||
Validate.notNull(id, "Cannot store null on an ItemMeta!");
|
||||
|
||||
setString(im, namespacedKey, id);
|
||||
}
|
||||
|
||||
@ -65,7 +93,8 @@ public class CustomItemDataService implements PersistentDataService, Keyed {
|
||||
*
|
||||
* @return An {@link Optional} describing the result
|
||||
*/
|
||||
public Optional<String> getItemData(ItemStack item) {
|
||||
@Nonnull
|
||||
public Optional<String> getItemData(@Nullable ItemStack item) {
|
||||
if (item == null || item.getType() == Material.AIR || !item.hasItemMeta()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
@ -82,7 +111,10 @@ public class CustomItemDataService implements PersistentDataService, Keyed {
|
||||
*
|
||||
* @return An {@link Optional} describing the result
|
||||
*/
|
||||
public Optional<String> getItemData(ItemMeta meta) {
|
||||
@Nonnull
|
||||
public Optional<String> getItemData(@Nonnull ItemMeta meta) {
|
||||
Validate.notNull(meta, "Cannot read data from null!");
|
||||
|
||||
return getString(meta, namespacedKey);
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,12 @@ public class CustomTextureService {
|
||||
private String version = null;
|
||||
private boolean modified = false;
|
||||
|
||||
/**
|
||||
* This creates a new {@link CustomTextureService} for the provided {@link Config}
|
||||
*
|
||||
* @param config
|
||||
* The {@link Config} to read custom model data from
|
||||
*/
|
||||
public CustomTextureService(@Nonnull Config config) {
|
||||
this.config = config;
|
||||
config.getConfiguration().options().header("This file is used to assign items from Slimefun or any of its addons\n" + "the 'CustomModelData' NBT tag. This can be used in conjunction with a custom resource pack\n" + "to give items custom textures.\n0 means there is no data assigned to that item.\n\n" + "There is no official Slimefun resource pack at the moment.");
|
||||
@ -49,6 +55,8 @@ public class CustomTextureService {
|
||||
config.setDefaultValue("SLIMEFUN_GUIDE", 0);
|
||||
|
||||
config.setDefaultValue("_UI_BACKGROUND", 0);
|
||||
config.setDefaultValue("_UI_NO_PERMISSION", 0);
|
||||
config.setDefaultValue("_UI_NOT_RESEARCHED", 0);
|
||||
config.setDefaultValue("_UI_INPUT_SLOT", 0);
|
||||
config.setDefaultValue("_UI_OUTPUT_SLOT", 0);
|
||||
config.setDefaultValue("_UI_BACK", 0);
|
||||
@ -82,22 +90,60 @@ public class CustomTextureService {
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns true if any custom model data was configured.
|
||||
* If every item id has no configured custom model data, it will return false.
|
||||
*
|
||||
* @return Whether any custom model data was configured
|
||||
*/
|
||||
public boolean isActive() {
|
||||
return modified;
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the configured custom model data for a given id.
|
||||
*
|
||||
* @param id
|
||||
* The id to get the data for
|
||||
*
|
||||
* @return The configured custom model data
|
||||
*/
|
||||
public int getModelData(@Nonnull String id) {
|
||||
Validate.notNull(id, "Cannot get the ModelData for 'null'");
|
||||
return config.getInt(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets the custom model data for this {@link ItemStack}
|
||||
* to the value configured for the provided item id.
|
||||
*
|
||||
* @param item
|
||||
* The {@link ItemStack} to set the custom model data for
|
||||
* @param id
|
||||
* The id for which to get the configured model data
|
||||
*/
|
||||
public void setTexture(@Nonnull ItemStack item, @Nonnull String id) {
|
||||
Validate.notNull(item, "The Item cannot be null!");
|
||||
Validate.notNull(id, "Cannot store null on an Item!");
|
||||
|
||||
ItemMeta im = item.getItemMeta();
|
||||
setTexture(im, id);
|
||||
item.setItemMeta(im);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets the custom model data for this {@link ItemMeta}
|
||||
* to the value configured for the provided item id.
|
||||
*
|
||||
* @param im
|
||||
* The {@link ItemMeta} to set the custom model data for
|
||||
* @param id
|
||||
* The id for which to get the configured model data
|
||||
*/
|
||||
public void setTexture(@Nonnull ItemMeta im, @Nonnull String id) {
|
||||
Validate.notNull(im, "The ItemMeta cannot be null!");
|
||||
Validate.notNull(id, "Cannot store null on an ItemMeta!");
|
||||
|
||||
int data = getModelData(id);
|
||||
im.setCustomModelData(data == 0 ? null : data);
|
||||
}
|
||||
|
@ -34,9 +34,26 @@ import kong.unirest.UnirestException;
|
||||
*/
|
||||
public class MetricsService {
|
||||
|
||||
/**
|
||||
* The URL pointing towards the GitHub API.
|
||||
*/
|
||||
private static final String API_URL = "https://api.github.com/";
|
||||
|
||||
/**
|
||||
* The Name of our repository
|
||||
*/
|
||||
private static final String REPO_NAME = "MetricsModule";
|
||||
|
||||
/**
|
||||
* The URL pointing towards the /releases/ endpoint of our
|
||||
* Metrics repository
|
||||
*/
|
||||
private static final String RELEASES_URL = API_URL + "repos/Slimefun/" + REPO_NAME + "/releases/latest";
|
||||
|
||||
/**
|
||||
* The URL pointing towards the download location for a
|
||||
* GitHub release of our Metrics repository
|
||||
*/
|
||||
private static final String DOWNLOAD_URL = "https://github.com/Slimefun/" + REPO_NAME + "/releases/download";
|
||||
|
||||
private final SlimefunPlugin plugin;
|
||||
@ -48,9 +65,22 @@ public class MetricsService {
|
||||
private boolean hasDownloadedUpdate = false;
|
||||
|
||||
static {
|
||||
Unirest.config().concurrency(2, 1).setDefaultHeader("User-Agent", "MetricsModule Auto-Updater").setDefaultHeader("Accept", "application/vnd.github.v3+json").enableCookieManagement(false).cookieSpec("ignoreCookies");
|
||||
// @formatter:off (We want this to stay this nicely aligned :D )
|
||||
Unirest.config()
|
||||
.concurrency(2, 1)
|
||||
.setDefaultHeader("User-Agent", "MetricsModule Auto-Updater")
|
||||
.setDefaultHeader("Accept", "application/vnd.github.v3+json")
|
||||
.enableCookieManagement(false)
|
||||
.cookieSpec("ignoreCookies");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
/**
|
||||
* This constructs a new instance of our {@link MetricsService}.
|
||||
*
|
||||
* @param plugin
|
||||
* Our {@link SlimefunPlugin} instance
|
||||
*/
|
||||
public MetricsService(@Nonnull SlimefunPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
this.parentFolder = new File(plugin.getDataFolder(), "cache" + File.separatorChar + "modules");
|
||||
|
@ -16,11 +16,28 @@ import me.mrCookieSlime.Slimefun.api.Slimefun;
|
||||
|
||||
class ContributionsConnector extends GitHubConnector {
|
||||
|
||||
// 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");
|
||||
/*
|
||||
* @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"
|
||||
);
|
||||
|
||||
// Matches a GitHub name with a Minecraft name.
|
||||
/*
|
||||
* @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...
|
||||
@ -82,8 +99,16 @@ class ContributionsConnector extends GitHubConnector {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getURLSuffix() {
|
||||
return "/contributors?per_page=100&page=" + page;
|
||||
public String getEndpoint() {
|
||||
return "/contributors";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getParameters() {
|
||||
Map<String, Object> parameters = new HashMap<>();
|
||||
parameters.put("per_page", 100);
|
||||
parameters.put("page", page);
|
||||
return parameters;
|
||||
}
|
||||
|
||||
private void computeContributors(@Nonnull JSONArray array) {
|
||||
|
@ -1,6 +1,8 @@
|
||||
package io.github.thebusybiscuit.slimefun4.core.services.github;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
@ -35,8 +37,13 @@ class GitHubActivityConnector extends GitHubConnector {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getURLSuffix() {
|
||||
public String getEndpoint() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getParameters() {
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,12 +6,13 @@ import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
import kong.unirest.HttpResponse;
|
||||
import kong.unirest.JsonNode;
|
||||
@ -31,22 +32,49 @@ import me.mrCookieSlime.Slimefun.api.Slimefun;
|
||||
abstract class GitHubConnector {
|
||||
|
||||
private static final String API_URL = "https://api.github.com/";
|
||||
private static final String USER_AGENT = "Slimefun4 (https://github.com/Slimefun)";
|
||||
|
||||
protected File file;
|
||||
protected String repository;
|
||||
protected final GitHubService github;
|
||||
private final String url;
|
||||
private File file;
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
public GitHubConnector(GitHubService github, String repository) {
|
||||
/**
|
||||
* This creates a new {@link GitHubConnector} for the given repository.
|
||||
*
|
||||
* @param github
|
||||
* Our instance of {@link GitHubService}
|
||||
* @param repository
|
||||
* The repository we want to connect to
|
||||
*/
|
||||
GitHubConnector(@Nonnull GitHubService github, @Nonnull String repository) {
|
||||
this.github = github;
|
||||
this.repository = repository;
|
||||
this.url = API_URL + "repos/" + repository + getEndpoint();
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the name of our cache {@link File}.
|
||||
*
|
||||
* @return The cache {@link File} name
|
||||
*/
|
||||
@Nonnull
|
||||
public abstract String getFileName();
|
||||
|
||||
/**
|
||||
* This is our {@link URL} endpoint.
|
||||
* It is the suffix of the {@link URL} we want to connect to.
|
||||
*
|
||||
* @return Our endpoint
|
||||
*/
|
||||
@Nonnull
|
||||
public abstract String getURLSuffix();
|
||||
public abstract String getEndpoint();
|
||||
|
||||
/**
|
||||
* This {@link Map} contains the query parameters for our {@link URL}.
|
||||
*
|
||||
* @return A {@link Map} with our query parameters
|
||||
*/
|
||||
@Nonnull
|
||||
public abstract Map<String, Object> getParameters();
|
||||
|
||||
/**
|
||||
* This method is called when the connection finished successfully.
|
||||
@ -63,7 +91,12 @@ abstract class GitHubConnector {
|
||||
// Don't do anything by default
|
||||
}
|
||||
|
||||
public void pullFile() {
|
||||
/**
|
||||
* This method will connect to GitHub and store the received data inside a local
|
||||
* cache {@link File}.
|
||||
* Make sure to call this method asynchronously!
|
||||
*/
|
||||
void download() {
|
||||
file = new File("plugins/Slimefun/cache/github/" + getFileName() + ".json");
|
||||
|
||||
if (github.isLoggingEnabled()) {
|
||||
@ -71,16 +104,19 @@ abstract class GitHubConnector {
|
||||
}
|
||||
|
||||
try {
|
||||
HttpResponse<JsonNode> resp = Unirest.get(API_URL + "repos/" + repository + getURLSuffix())
|
||||
.header("User-Agent", "Slimefun4 (https://github.com/Slimefun)")
|
||||
// @formatter:off
|
||||
HttpResponse<JsonNode> response = Unirest.get(url)
|
||||
.queryString(getParameters())
|
||||
.header("User-Agent", USER_AGENT)
|
||||
.asJson();
|
||||
// @formatter:on
|
||||
|
||||
if (resp.isSuccess()) {
|
||||
onSuccess(resp.getBody());
|
||||
writeCacheFile(resp.getBody());
|
||||
if (response.isSuccess()) {
|
||||
onSuccess(response.getBody());
|
||||
writeCacheFile(response.getBody());
|
||||
} else {
|
||||
if (github.isLoggingEnabled()) {
|
||||
Slimefun.getLogger().log(Level.WARNING, "Failed to fetch {0}: {1} - {2}", new Object[] { repository + getURLSuffix(), resp.getStatus(), resp.getBody() });
|
||||
Slimefun.getLogger().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
|
||||
|
@ -1,5 +1,7 @@
|
||||
package io.github.thebusybiscuit.slimefun4.core.services.github;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
@ -50,8 +52,15 @@ class GitHubIssuesConnector extends GitHubConnector {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getURLSuffix() {
|
||||
return "/issues?per_page=100";
|
||||
public String getEndpoint() {
|
||||
return "/issues";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getParameters() {
|
||||
Map<String, Object> parameters = new HashMap<>();
|
||||
parameters.put("per_page", 100);
|
||||
return parameters;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -57,7 +57,8 @@ public class GitHubService {
|
||||
}
|
||||
|
||||
public void start(@Nonnull SlimefunPlugin plugin) {
|
||||
plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, new GitHubTask(this), 80L, 60 * 60 * 20L);
|
||||
GitHubTask task = new GitHubTask(this);
|
||||
plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, task, 80L, 60 * 60 * 20L);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,6 @@
|
||||
package io.github.thebusybiscuit.slimefun4.core.services.github;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@ -38,10 +39,14 @@ class GitHubTask implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
gitHubService.getConnectors().forEach(GitHubConnector::pullFile);
|
||||
gitHubService.getConnectors().forEach(GitHubConnector::download);
|
||||
grabTextures();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will pull the skin textures for every {@link Contributor} and store
|
||||
* the {@link UUID} and received skin inside a local cache {@link File}.
|
||||
*/
|
||||
private void grabTextures() {
|
||||
// Store all queried usernames to prevent 429 responses for pinging the
|
||||
// same URL twice in one run.
|
||||
|
@ -271,10 +271,10 @@ public class ChestSlimefunGuide implements SlimefunGuideImplementation {
|
||||
|
||||
if (isSurvivalMode() && !Slimefun.hasPermission(p, sfitem, false)) {
|
||||
List<String> message = SlimefunPlugin.getPermissionsService().getLore(sfitem);
|
||||
menu.addItem(index, new CustomItem(Material.BARRIER, sfitem.getItemName(), message.toArray(new String[0])));
|
||||
menu.addItem(index, new CustomItem(ChestMenuUtils.getNoPermissionItem(), sfitem.getItemName(), message.toArray(new String[0])));
|
||||
menu.addMenuClickHandler(index, ChestMenuUtils.getEmptyClickHandler());
|
||||
} else if (isSurvivalMode() && research != null && !profile.hasUnlocked(research)) {
|
||||
menu.addItem(index, new CustomItem(Material.BARRIER, ChatColor.WHITE + ItemUtils.getItemName(sfitem.getItem()), "&4&l" + SlimefunPlugin.getLocalization().getMessage(p, "guide.locked"), "", "&a> Click to unlock", "", "&7Cost: &b" + research.getCost() + " Level(s)"));
|
||||
menu.addItem(index, new CustomItem(ChestMenuUtils.getNotResearchedItem(), ChatColor.WHITE + ItemUtils.getItemName(sfitem.getItem()), "&4&l" + SlimefunPlugin.getLocalization().getMessage(p, "guide.locked"), "", "&a> Click to unlock", "", "&7Cost: &b" + research.getCost() + " Level(s)"));
|
||||
menu.addMenuClickHandler(index, (pl, slot, item, action) -> {
|
||||
if (!SlimefunPlugin.getRegistry().getCurrentlyResearchingPlayers().contains(pl.getUniqueId())) {
|
||||
if (research.canUnlock(pl)) {
|
||||
|
@ -1,5 +1,7 @@
|
||||
package io.github.thebusybiscuit.slimefun4.implementation.items.androids;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* This enum holds all the different types a {@link ProgrammableAndroid} can represent.
|
||||
*
|
||||
@ -55,7 +57,7 @@ public enum AndroidType {
|
||||
*/
|
||||
NON_FIGHTER;
|
||||
|
||||
boolean isType(AndroidType type) {
|
||||
boolean isType(@Nonnull AndroidType type) {
|
||||
return type == NONE || type == this || (type == NON_FIGHTER && this != FIGHTER);
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@ import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.entity.Ageable;
|
||||
@ -20,126 +21,223 @@ import io.github.thebusybiscuit.slimefun4.utils.HeadTexture;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
|
||||
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
|
||||
|
||||
enum Instruction {
|
||||
/**
|
||||
* This enum holds every {@link Instruction} for the {@link ProgrammableAndroid}
|
||||
* added by Slimefun itself.
|
||||
*
|
||||
* @author TheBusyBiscuit
|
||||
*
|
||||
*/
|
||||
public enum Instruction {
|
||||
|
||||
// Start and End Parts
|
||||
/**
|
||||
* This {@link Instruction} is the starting point of a {@link Script}.
|
||||
*/
|
||||
START(AndroidType.NONE, HeadTexture.SCRIPT_START),
|
||||
|
||||
/**
|
||||
* This {@link Instruction} is the end token of a {@link Script}.
|
||||
* Once this {@link Instruction} is reached, the {@link Script} will start again.
|
||||
*/
|
||||
REPEAT(AndroidType.NONE, HeadTexture.SCRIPT_REPEAT),
|
||||
|
||||
/**
|
||||
* This {@link Instruction} will make the {@link ProgrammableAndroid} wait
|
||||
* for one Slimefun tick.
|
||||
*/
|
||||
WAIT(AndroidType.NONE, HeadTexture.SCRIPT_WAIT),
|
||||
|
||||
// Movement
|
||||
/**
|
||||
* This will make the {@link ProgrammableAndroid} go forward.
|
||||
*/
|
||||
GO_FORWARD(AndroidType.NON_FIGHTER, HeadTexture.SCRIPT_FORWARD, (android, b, inv, face) -> {
|
||||
Block target = b.getRelative(face);
|
||||
android.move(b, face, target);
|
||||
}),
|
||||
|
||||
/**
|
||||
* This will make the {@link ProgrammableAndroid} go up.
|
||||
*/
|
||||
GO_UP(AndroidType.NON_FIGHTER, HeadTexture.SCRIPT_UP, (android, b, inv, face) -> {
|
||||
Block target = b.getRelative(BlockFace.UP);
|
||||
android.move(b, face, target);
|
||||
}),
|
||||
|
||||
/**
|
||||
* This will make the {@link ProgrammableAndroid} go down.
|
||||
*/
|
||||
GO_DOWN(AndroidType.NON_FIGHTER, HeadTexture.SCRIPT_DOWN, (android, b, inv, face) -> {
|
||||
Block target = b.getRelative(BlockFace.DOWN);
|
||||
android.move(b, face, target);
|
||||
}),
|
||||
|
||||
// Directions
|
||||
/**
|
||||
* This will make the {@link ProgrammableAndroid} rotate to the left side.
|
||||
*/
|
||||
TURN_LEFT(AndroidType.NONE, HeadTexture.SCRIPT_LEFT, (android, b, inv, face) -> {
|
||||
int mod = -1;
|
||||
android.rotate(b, face, mod);
|
||||
}),
|
||||
|
||||
/**
|
||||
* This will make the {@link ProgrammableAndroid} rotate to the right side.
|
||||
*/
|
||||
TURN_RIGHT(AndroidType.NONE, HeadTexture.SCRIPT_RIGHT, (android, b, inv, face) -> {
|
||||
int mod = 1;
|
||||
android.rotate(b, face, mod);
|
||||
}),
|
||||
|
||||
// Action - Pickaxe
|
||||
/**
|
||||
* This will make a {@link MinerAndroid} dig the {@link Block} above.
|
||||
*/
|
||||
DIG_UP(AndroidType.MINER, HeadTexture.SCRIPT_DIG_UP, (android, b, inv, face) -> {
|
||||
Block target = b.getRelative(BlockFace.UP);
|
||||
android.dig(b, inv, target);
|
||||
}),
|
||||
|
||||
/**
|
||||
* This will make a {@link MinerAndroid} dig the {@link Block} ahead.
|
||||
*/
|
||||
DIG_FORWARD(AndroidType.MINER, HeadTexture.SCRIPT_DIG_FORWARD, (android, b, inv, face) -> {
|
||||
Block target = b.getRelative(face);
|
||||
android.dig(b, inv, target);
|
||||
}),
|
||||
|
||||
/**
|
||||
* This will make a {@link MinerAndroid} dig the {@link Block} below.
|
||||
*/
|
||||
DIG_DOWN(AndroidType.MINER, HeadTexture.SCRIPT_DIG_DOWN, (android, b, inv, face) -> {
|
||||
Block target = b.getRelative(BlockFace.DOWN);
|
||||
android.dig(b, inv, target);
|
||||
}),
|
||||
|
||||
/**
|
||||
* This will make a {@link MinerAndroid} dig the {@link Block} above
|
||||
* and then move itself to that new {@link Location}.
|
||||
*/
|
||||
MOVE_AND_DIG_UP(AndroidType.MINER, HeadTexture.SCRIPT_DIG_UP, (android, b, inv, face) -> {
|
||||
Block target = b.getRelative(BlockFace.UP);
|
||||
android.moveAndDig(b, inv, face, target);
|
||||
}),
|
||||
|
||||
/**
|
||||
* This will make a {@link MinerAndroid} dig the {@link Block} ahead
|
||||
* and then move itself to that new {@link Location}.
|
||||
*/
|
||||
MOVE_AND_DIG_FORWARD(AndroidType.MINER, HeadTexture.SCRIPT_DIG_FORWARD, (android, b, inv, face) -> {
|
||||
Block target = b.getRelative(face);
|
||||
android.moveAndDig(b, inv, face, target);
|
||||
}),
|
||||
|
||||
/**
|
||||
* This will make a {@link MinerAndroid} dig the {@link Block} below
|
||||
* and then move itself to that new {@link Location}.
|
||||
*/
|
||||
MOVE_AND_DIG_DOWN(AndroidType.MINER, HeadTexture.SCRIPT_DIG_DOWN, (android, b, inv, face) -> {
|
||||
Block target = b.getRelative(BlockFace.DOWN);
|
||||
android.moveAndDig(b, inv, face, target);
|
||||
}),
|
||||
|
||||
// Action - Sword
|
||||
/**
|
||||
* This will make a {@link ButcherAndroid} attack any {@link LivingEntity}
|
||||
* ahead of them.
|
||||
*/
|
||||
ATTACK_MOBS_ANIMALS(AndroidType.FIGHTER, HeadTexture.SCRIPT_ATTACK, (android, b, inv, face) -> {
|
||||
Predicate<LivingEntity> predicate = e -> true;
|
||||
android.attack(b, face, predicate);
|
||||
}),
|
||||
|
||||
/**
|
||||
* This will make a {@link ButcherAndroid} attack any {@link Monster}
|
||||
* ahead of them.
|
||||
*/
|
||||
ATTACK_MOBS(AndroidType.FIGHTER, HeadTexture.SCRIPT_ATTACK, (android, b, inv, face) -> {
|
||||
Predicate<LivingEntity> predicate = e -> e instanceof Monster;
|
||||
android.attack(b, face, predicate);
|
||||
}),
|
||||
|
||||
/**
|
||||
* This will make a {@link ButcherAndroid} attack any {@link Animals Animal}
|
||||
* ahead of them.
|
||||
*/
|
||||
ATTACK_ANIMALS(AndroidType.FIGHTER, HeadTexture.SCRIPT_ATTACK, (android, b, inv, face) -> {
|
||||
Predicate<LivingEntity> predicate = e -> e instanceof Animals;
|
||||
android.attack(b, face, predicate);
|
||||
}),
|
||||
|
||||
/**
|
||||
* This will make a {@link ButcherAndroid} attack any <strong>adult</strong>
|
||||
* {@link Animals Animal} ahead of them.
|
||||
*/
|
||||
ATTACK_ANIMALS_ADULT(AndroidType.FIGHTER, HeadTexture.SCRIPT_ATTACK, (android, b, inv, face) -> {
|
||||
Predicate<LivingEntity> predicate = e -> e instanceof Animals && e instanceof Ageable && ((Ageable) e).isAdult();
|
||||
Predicate<LivingEntity> predicate = e -> e instanceof Animals && ((Ageable) e).isAdult();
|
||||
android.attack(b, face, predicate);
|
||||
}),
|
||||
|
||||
// Action - Axe
|
||||
/**
|
||||
* This will make a {@link WoodcutterAndroid} chop down the tree in front of them.
|
||||
*/
|
||||
CHOP_TREE(AndroidType.WOODCUTTER, HeadTexture.SCRIPT_CHOP_TREE),
|
||||
|
||||
// Action - Fishing Rod
|
||||
/**
|
||||
* This {@link Instruction} makes a {@link FisherAndroid} try to catch fish from
|
||||
* the water below.
|
||||
*/
|
||||
CATCH_FISH(AndroidType.FISHERMAN, HeadTexture.SCRIPT_FISH, (android, b, inv, face) -> android.fish(b, inv)),
|
||||
|
||||
// Action - Hoe
|
||||
/**
|
||||
* This {@link Instruction} will make a {@link FarmerAndroid} try to harvest
|
||||
* the {@link Block} in front of them.
|
||||
*/
|
||||
FARM_FORWARD(AndroidType.FARMER, HeadTexture.SCRIPT_FARM_FORWARD, (android, b, inv, face) -> {
|
||||
Block target = b.getRelative(face);
|
||||
android.farm(inv, target);
|
||||
}),
|
||||
|
||||
/**
|
||||
* This {@link Instruction} will make a {@link FarmerAndroid} try to harvest
|
||||
* the {@link Block} below.
|
||||
*/
|
||||
FARM_DOWN(AndroidType.FARMER, HeadTexture.SCRIPT_FARM_DOWN, (android, b, inv, face) -> {
|
||||
Block target = b.getRelative(BlockFace.DOWN);
|
||||
android.farm(inv, target);
|
||||
}),
|
||||
|
||||
// Action - ExoticGarden
|
||||
/**
|
||||
* This {@link Instruction} will make a {@link FarmerAndroid} try to harvest
|
||||
* the {@link Block} in front of them.
|
||||
*
|
||||
* <strong>This includes plants from ExoticGarden.</strong>
|
||||
*/
|
||||
FARM_EXOTIC_FORWARD(AndroidType.ADVANCED_FARMER, HeadTexture.SCRIPT_FARM_FORWARD, (android, b, inv, face) -> {
|
||||
Block target = b.getRelative(face);
|
||||
android.exoticFarm(inv, target);
|
||||
}),
|
||||
|
||||
/**
|
||||
* This {@link Instruction} will make a {@link FarmerAndroid} try to harvest
|
||||
* the {@link Block} below.
|
||||
*
|
||||
* <strong>This includes plants from ExoticGarden.</strong>
|
||||
*/
|
||||
FARM_EXOTIC_DOWN(AndroidType.ADVANCED_FARMER, HeadTexture.SCRIPT_FARM_DOWN, (android, b, inv, face) -> {
|
||||
Block target = b.getRelative(BlockFace.DOWN);
|
||||
android.exoticFarm(inv, target);
|
||||
}),
|
||||
|
||||
// Action - Interface
|
||||
/**
|
||||
* This {@link Instruction} will force the {@link ProgrammableAndroid} to push their
|
||||
* items into an {@link AndroidInterface} ahead of them.
|
||||
*/
|
||||
INTERFACE_ITEMS(AndroidType.NONE, HeadTexture.SCRIPT_PUSH_ITEMS, (android, b, inv, face) -> {
|
||||
Block target = b.getRelative(face);
|
||||
android.depositItems(inv, target);
|
||||
}),
|
||||
|
||||
/**
|
||||
* This {@link Instruction} will force the {@link ProgrammableAndroid} to pull
|
||||
* fuel from an {@link AndroidInterface} ahead of them.
|
||||
*/
|
||||
INTERFACE_FUEL(AndroidType.NONE, HeadTexture.SCRIPT_PULL_FUEL, (android, b, inv, face) -> {
|
||||
Block target = b.getRelative(face);
|
||||
android.refuel(inv, target);
|
||||
|
@ -58,6 +58,7 @@ 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;
|
||||
@ -69,6 +70,7 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock,
|
||||
private static final int[] BORDER = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 18, 24, 25, 26, 27, 33, 35, 36, 42, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53 };
|
||||
private static final int[] OUTPUT_BORDER = { 10, 11, 12, 13, 14, 19, 23, 28, 32, 37, 38, 39, 40, 41 };
|
||||
private static final String DEFAULT_SCRIPT = "START-TURN_LEFT-REPEAT";
|
||||
private static final int MAX_SCRIPT_LENGTH = 54;
|
||||
|
||||
protected final List<MachineFuel> fuelTypes = new ArrayList<>();
|
||||
protected final String texture;
|
||||
@ -407,19 +409,23 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock,
|
||||
} else {
|
||||
Script script = scripts.get(target);
|
||||
menu.addItem(index, script.getAsItemStack(this, p), (player, slot, stack, action) -> {
|
||||
if (action.isShiftClicked()) {
|
||||
if (script.isAuthor(player)) {
|
||||
SlimefunPlugin.getLocalization().sendMessage(player, "android.scripts.rating.own", true);
|
||||
} else if (script.canRate(player)) {
|
||||
script.rate(player, !action.isRightClicked());
|
||||
openScriptDownloader(player, b, page);
|
||||
} else {
|
||||
SlimefunPlugin.getLocalization().sendMessage(player, "android.scripts.rating.already", true);
|
||||
try {
|
||||
if (action.isShiftClicked()) {
|
||||
if (script.isAuthor(player)) {
|
||||
SlimefunPlugin.getLocalization().sendMessage(player, "android.scripts.rating.own", true);
|
||||
} else if (script.canRate(player)) {
|
||||
script.rate(player, !action.isRightClicked());
|
||||
openScriptDownloader(player, b, page);
|
||||
} else {
|
||||
SlimefunPlugin.getLocalization().sendMessage(player, "android.scripts.rating.already", true);
|
||||
}
|
||||
} else if (!action.isRightClicked()) {
|
||||
script.download();
|
||||
setScript(b.getLocation(), script.getSourceCode());
|
||||
openScriptEditor(player, b);
|
||||
}
|
||||
} else if (!action.isRightClicked()) {
|
||||
script.download();
|
||||
setScript(b.getLocation(), script.getSourceCode());
|
||||
openScriptEditor(player, b);
|
||||
} catch (Exception x) {
|
||||
Slimefun.getLogger().log(Level.SEVERE, "An Exception was thrown when a User tried to download a Script!", x);
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -534,12 +540,19 @@ public class ProgrammableAndroid extends SlimefunItem implements InventoryBlock,
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
protected String getScript(@Nonnull Location l) {
|
||||
public String getScript(@Nonnull Location l) {
|
||||
Validate.notNull(l, "Location for android not specified");
|
||||
String script = BlockStorage.getLocationInfo(l, "script");
|
||||
return script != null ? script : DEFAULT_SCRIPT;
|
||||
}
|
||||
|
||||
protected void setScript(@Nonnull Location l, @Nonnull String script) {
|
||||
public void setScript(@Nonnull Location l, @Nonnull String script) {
|
||||
Validate.notNull(l, "Location for android not specified");
|
||||
Validate.notNull(script, "No script given");
|
||||
Validate.isTrue(script.startsWith(Instruction.START.name() + '-'), "A script must begin with a 'START' token.");
|
||||
Validate.isTrue(script.endsWith('-' + Instruction.REPEAT.name()), "A script must end with a 'REPEAT' token.");
|
||||
Validate.isTrue(PatternUtils.DASH.split(script).length <= MAX_SCRIPT_LENGTH, "Scripts may not have more than " + MAX_SCRIPT_LENGTH + " segments");
|
||||
|
||||
BlockStorage.addBlockInfo(l, "script", script);
|
||||
}
|
||||
|
||||
|
@ -130,18 +130,19 @@ public final class Script {
|
||||
@Nonnull
|
||||
ItemStack getAsItemStack(@Nonnull ProgrammableAndroid android, @Nonnull Player p) {
|
||||
List<String> lore = new LinkedList<>();
|
||||
lore.add("&7by &r" + getAuthor());
|
||||
lore.add("&7by &f" + getAuthor());
|
||||
lore.add("");
|
||||
lore.add("&7Downloads: &r" + getDownloads());
|
||||
lore.add("&7Downloads: &f" + getDownloads());
|
||||
lore.add("&7Rating: " + getScriptRatingPercentage());
|
||||
lore.add("&a" + getUpvotes() + " \u263A &7| &4\u2639 " + getDownvotes());
|
||||
lore.add("");
|
||||
lore.add("&eLeft Click &rto download this Script");
|
||||
lore.add("&eLeft Click &fto download this Script");
|
||||
lore.add("&4(This will override your current Script)");
|
||||
|
||||
if (canRate(p)) {
|
||||
lore.add("&eShift + Left Click &rto leave a positive Rating");
|
||||
lore.add("&eShift + Right Click &rto leave a negative Rating");
|
||||
lore.add("");
|
||||
lore.add("&eShift + Left Click &fto leave a positive Rating");
|
||||
lore.add("&eShift + Right Click &fto leave a negative Rating");
|
||||
}
|
||||
|
||||
return new CustomItem(android.getItem(), "&b" + getName(), lore.toArray(new String[0]));
|
||||
|
@ -2,6 +2,8 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.block.Block;
|
||||
@ -14,7 +16,6 @@ import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import io.github.thebusybiscuit.cscorelib2.inventory.ItemUtils;
|
||||
import io.github.thebusybiscuit.cscorelib2.item.CustomItem;
|
||||
import io.github.thebusybiscuit.slimefun4.core.multiblocks.MultiBlockMachine;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
|
||||
import io.papermc.lib.PaperLib;
|
||||
@ -23,7 +24,7 @@ import me.mrCookieSlime.Slimefun.Objects.Category;
|
||||
import me.mrCookieSlime.Slimefun.api.Slimefun;
|
||||
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
|
||||
|
||||
public class ArmorForge extends MultiBlockMachine {
|
||||
public class ArmorForge extends BackpackCrafter {
|
||||
|
||||
public ArmorForge(Category category, SlimefunItemStack item) {
|
||||
super(category, item, new ItemStack[] { null, null, null, null, new ItemStack(Material.ANVIL), null, null, new CustomItem(Material.DISPENSER, "Dispenser (Facing up)"), null }, BlockFace.SELF);
|
||||
@ -31,8 +32,8 @@ public class ArmorForge extends MultiBlockMachine {
|
||||
|
||||
@Override
|
||||
public void onInteract(Player p, Block b) {
|
||||
Block dispBlock = b.getRelative(BlockFace.DOWN);
|
||||
BlockState state = PaperLib.getBlockState(dispBlock, false).getState();
|
||||
Block dispenser = b.getRelative(BlockFace.DOWN);
|
||||
BlockState state = PaperLib.getBlockState(dispenser, false).getState();
|
||||
|
||||
if (state instanceof Dispenser) {
|
||||
Dispenser disp = (Dispenser) state;
|
||||
@ -44,13 +45,7 @@ public class ArmorForge extends MultiBlockMachine {
|
||||
ItemStack output = RecipeType.getRecipeOutputList(this, inputs.get(i)).clone();
|
||||
|
||||
if (Slimefun.hasUnlocked(p, output, true)) {
|
||||
Inventory outputInv = findOutputInventory(output, dispBlock, inv);
|
||||
|
||||
if (outputInv != null) {
|
||||
craft(p, output, inv, outputInv);
|
||||
} else {
|
||||
SlimefunPlugin.getLocalization().sendMessage(p, "machines.full-inventory", true);
|
||||
}
|
||||
craft(p, output, inv, dispenser);
|
||||
}
|
||||
|
||||
return;
|
||||
@ -71,26 +66,35 @@ public class ArmorForge extends MultiBlockMachine {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void craft(Player p, ItemStack output, Inventory inv, Inventory outputInv) {
|
||||
for (int j = 0; j < 9; j++) {
|
||||
ItemStack item = inv.getContents()[j];
|
||||
@ParametersAreNonnullByDefault
|
||||
private void craft(Player p, ItemStack output, Inventory inv, Block dispenser) {
|
||||
Inventory fakeInv = createVirtualInventory(inv);
|
||||
Inventory outputInv = findOutputInventory(output, dispenser, inv, fakeInv);
|
||||
|
||||
if (item != null && item.getType() != Material.AIR) {
|
||||
ItemUtils.consumeItem(item, true);
|
||||
}
|
||||
}
|
||||
if (outputInv != null) {
|
||||
for (int j = 0; j < 9; j++) {
|
||||
ItemStack item = inv.getContents()[j];
|
||||
|
||||
for (int j = 0; j < 4; j++) {
|
||||
int current = j;
|
||||
|
||||
SlimefunPlugin.runSync(() -> {
|
||||
if (current < 3) {
|
||||
p.getWorld().playSound(p.getLocation(), Sound.BLOCK_ANVIL_USE, 1F, 2F);
|
||||
} else {
|
||||
p.getWorld().playSound(p.getLocation(), Sound.ENTITY_ARROW_HIT_PLAYER, 1F, 1F);
|
||||
outputInv.addItem(output);
|
||||
if (item != null && item.getType() != Material.AIR) {
|
||||
ItemUtils.consumeItem(item, true);
|
||||
}
|
||||
}, j * 20L);
|
||||
}
|
||||
|
||||
for (int j = 0; j < 4; j++) {
|
||||
int current = j;
|
||||
|
||||
SlimefunPlugin.runSync(() -> {
|
||||
if (current < 3) {
|
||||
p.getWorld().playSound(p.getLocation(), Sound.BLOCK_ANVIL_USE, 1F, 2F);
|
||||
} else {
|
||||
p.getWorld().playSound(p.getLocation(), Sound.ENTITY_ARROW_HIT_PLAYER, 1F, 1F);
|
||||
outputInv.addItem(output);
|
||||
}
|
||||
}, j * 20L);
|
||||
}
|
||||
|
||||
} else {
|
||||
SlimefunPlugin.getLocalization().sendMessage(p, "machines.full-inventory", true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,7 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
|
||||
*
|
||||
* @see EnhancedCraftingTable
|
||||
* @see MagicWorkbench
|
||||
* @see ArmorForge
|
||||
*
|
||||
*/
|
||||
abstract class BackpackCrafter extends MultiBlockMachine {
|
||||
|
@ -40,7 +40,7 @@ public class SlimefunBootsListener implements Listener {
|
||||
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
|
||||
public void onDamage(EntityDamageEvent e) {
|
||||
if (e.getEntity() instanceof Player && e.getCause() == DamageCause.FALL) {
|
||||
onFallDamage(e);
|
||||
onFallDamage(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -219,6 +219,7 @@ public final class SlimefunItemSetup {
|
||||
registeredItems = true;
|
||||
DefaultCategories categories = new DefaultCategories();
|
||||
|
||||
// @formatter:off (We will need to refactor this one day)
|
||||
new SlimefunItem(categories.weapons, SlimefunItems.GRANDMAS_WALKING_STICK, RecipeType.ENHANCED_CRAFTING_TABLE,
|
||||
new ItemStack[] {null, new ItemStack(Material.OAK_LOG), null, null, new ItemStack(Material.OAK_LOG), null, null, new ItemStack(Material.OAK_LOG), null})
|
||||
.register(plugin);
|
||||
@ -1092,7 +1093,7 @@ public final class SlimefunItemSetup {
|
||||
|
||||
new RestoredBackpack(categories.usefulItems).register(plugin);
|
||||
|
||||
new SlimefunItem(categories.technicalComponents, SlimefunItems.MAGNET, RecipeType.SMELTERY,
|
||||
new UnplaceableBlock(categories.technicalComponents, SlimefunItems.MAGNET, RecipeType.SMELTERY,
|
||||
new ItemStack[] {SlimefunItems.NICKEL_INGOT, SlimefunItems.ALUMINUM_DUST, SlimefunItems.IRON_DUST, SlimefunItems.COBALT_INGOT, null, null, null, null, null})
|
||||
.register(plugin);
|
||||
|
||||
@ -1303,15 +1304,15 @@ public final class SlimefunItemSetup {
|
||||
new ItemStack[] {SlimefunItems.CARBONADO, SlimefunItems.BASIC_CIRCUIT_BOARD, SlimefunItems.CARBONADO, SlimefunItems.HEATING_COIL, SlimefunItems.REINFORCED_FURNACE, SlimefunItems.HEATING_COIL, SlimefunItems.CARBONADO, SlimefunItems.ELECTRIC_MOTOR, SlimefunItems.CARBONADO})
|
||||
.register(plugin);
|
||||
|
||||
new SlimefunItem(categories.technicalComponents, SlimefunItems.ELECTRO_MAGNET, RecipeType.ENHANCED_CRAFTING_TABLE,
|
||||
new UnplaceableBlock(categories.technicalComponents, SlimefunItems.ELECTRO_MAGNET, RecipeType.ENHANCED_CRAFTING_TABLE,
|
||||
new ItemStack[] {SlimefunItems.NICKEL_INGOT, SlimefunItems.MAGNET, SlimefunItems.COBALT_INGOT, null, SlimefunItems.BATTERY, null, null, null, null})
|
||||
.register(plugin);
|
||||
|
||||
new SlimefunItem(categories.technicalComponents, SlimefunItems.ELECTRIC_MOTOR, RecipeType.ENHANCED_CRAFTING_TABLE,
|
||||
new UnplaceableBlock(categories.technicalComponents, SlimefunItems.ELECTRIC_MOTOR, RecipeType.ENHANCED_CRAFTING_TABLE,
|
||||
new ItemStack[] {SlimefunItems.COPPER_WIRE, SlimefunItems.COPPER_WIRE, SlimefunItems.COPPER_WIRE, null, SlimefunItems.ELECTRO_MAGNET, null, SlimefunItems.COPPER_WIRE, SlimefunItems.COPPER_WIRE, SlimefunItems.COPPER_WIRE})
|
||||
.register(plugin);
|
||||
|
||||
new SlimefunItem(categories.technicalComponents, SlimefunItems.HEATING_COIL, RecipeType.ENHANCED_CRAFTING_TABLE,
|
||||
new UnplaceableBlock(categories.technicalComponents, SlimefunItems.HEATING_COIL, RecipeType.ENHANCED_CRAFTING_TABLE,
|
||||
new ItemStack[] {SlimefunItems.COPPER_WIRE, SlimefunItems.COPPER_WIRE, SlimefunItems.COPPER_WIRE, SlimefunItems.COPPER_WIRE, SlimefunItems.ELECTRIC_MOTOR, SlimefunItems.COPPER_WIRE, SlimefunItems.COPPER_WIRE, SlimefunItems.COPPER_WIRE, SlimefunItems.COPPER_WIRE})
|
||||
.register(plugin);
|
||||
|
||||
@ -1455,7 +1456,7 @@ public final class SlimefunItemSetup {
|
||||
new SlimefunItemStack(SlimefunItems.HARDENED_GLASS, 16))
|
||||
.register(plugin);
|
||||
|
||||
new SlimefunItem(categories.technicalComponents, SlimefunItems.COOLING_UNIT, RecipeType.ENHANCED_CRAFTING_TABLE,
|
||||
new UnplaceableBlock(categories.technicalComponents, SlimefunItems.COOLING_UNIT, RecipeType.ENHANCED_CRAFTING_TABLE,
|
||||
new ItemStack[] {new ItemStack(Material.ICE), new ItemStack(Material.ICE), new ItemStack(Material.ICE), SlimefunItems.ALUMINUM_INGOT, SlimefunItems.ELECTRIC_MOTOR, SlimefunItems.ALUMINUM_INGOT, new ItemStack(Material.ICE), new ItemStack(Material.ICE), new ItemStack(Material.ICE)})
|
||||
.register(plugin);
|
||||
|
||||
@ -2867,7 +2868,7 @@ public final class SlimefunItemSetup {
|
||||
|
||||
}.register(plugin);
|
||||
|
||||
new SlimefunItem(categories.cargo, SlimefunItems.CARGO_MOTOR, RecipeType.ENHANCED_CRAFTING_TABLE,
|
||||
new UnplaceableBlock(categories.cargo, SlimefunItems.CARGO_MOTOR, RecipeType.ENHANCED_CRAFTING_TABLE,
|
||||
new ItemStack[] {SlimefunItems.HARDENED_GLASS, SlimefunItems.ELECTRO_MAGNET, SlimefunItems.HARDENED_GLASS, SlimefunItems.SILVER_INGOT, SlimefunItems.ELECTRIC_MOTOR, SlimefunItems.SILVER_INGOT, SlimefunItems.HARDENED_GLASS, SlimefunItems.ELECTRO_MAGNET, SlimefunItems.HARDENED_GLASS},
|
||||
new SlimefunItemStack(SlimefunItems.CARGO_MOTOR, 4))
|
||||
.register(plugin);
|
||||
@ -3048,6 +3049,8 @@ public final class SlimefunItemSetup {
|
||||
new ElytraCap(categories.magicalArmor, SlimefunItems.ELYTRA_CAP, RecipeType.ARMOR_FORGE,
|
||||
new ItemStack[]{new ItemStack(Material.SLIME_BALL), new ItemStack(Material.SLIME_BALL), new ItemStack(Material.SLIME_BALL), SlimefunItems.ELYTRA_SCALE, SlimefunItems.ELYTRA_SCALE, SlimefunItems.ELYTRA_SCALE, new ItemStack(Material.SLIME_BALL), new ItemStack(Material.LEATHER_HELMET), new ItemStack(Material.SLIME_BALL)})
|
||||
.register(plugin);
|
||||
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private static void registerArmorSet(Category category, ItemStack baseComponent, ItemStack[] items, String idSyntax, boolean vanilla, PotionEffect[][] effects, SlimefunAddon addon) {
|
||||
|
@ -29,6 +29,9 @@ public final class ChestMenuUtils {
|
||||
private static final ItemStack INPUT_SLOT = new SlimefunItemStack("_UI_INPUT_SLOT", Material.CYAN_STAINED_GLASS_PANE, " ");
|
||||
private static final ItemStack OUTPUT_SLOT = new SlimefunItemStack("_UI_OUTPUT_SLOT", Material.ORANGE_STAINED_GLASS_PANE, " ");
|
||||
|
||||
private static final ItemStack NO_PERMISSION = new SlimefunItemStack("_UI_NO_PERMISSION", Material.BARRIER, "No Permission");
|
||||
private static final ItemStack NOT_RESEARCHED = new SlimefunItemStack("_UI_NOT_RESEARCHED", Material.BARRIER, "Not researched");
|
||||
|
||||
private static final ItemStack BACK_BUTTON = new SlimefunItemStack("_UI_BACK", Material.ENCHANTED_BOOK, "&7\u21E6 Back", meta -> meta.addItemFlags(ItemFlag.HIDE_ENCHANTS));
|
||||
private static final ItemStack MENU_BUTTON = new SlimefunItemStack("_UI_MENU", Material.COMPARATOR, "&eSettings / Info", "", "&7\u21E8 Click to see more");
|
||||
private static final ItemStack SEARCH_BUTTON = new SlimefunItemStack("_UI_SEARCH", Material.NAME_TAG, "&bSearch");
|
||||
@ -46,6 +49,16 @@ public final class ChestMenuUtils {
|
||||
return UI_BACKGROUND;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static ItemStack getNoPermissionItem() {
|
||||
return NO_PERMISSION;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static ItemStack getNotResearchedItem() {
|
||||
return NOT_RESEARCHED;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static ItemStack getInputSlotTexture() {
|
||||
return INPUT_SLOT;
|
||||
|
@ -4,6 +4,9 @@ import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.Material;
|
||||
|
||||
import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag;
|
||||
@ -25,10 +28,12 @@ public final class ColoredMaterials {
|
||||
*/
|
||||
private ColoredMaterials() {}
|
||||
|
||||
// @formatter:off (We want this to stay formatted like this)
|
||||
|
||||
/**
|
||||
* This {@link List} contains all wool colors ordered by their appearance ingame.
|
||||
*/
|
||||
public static final List<Material> WOOL = Collections.unmodifiableList(Arrays.asList(
|
||||
public static final List<Material> WOOL = asList(new Material[] {
|
||||
Material.WHITE_WOOL,
|
||||
Material.ORANGE_WOOL,
|
||||
Material.MAGENTA_WOOL,
|
||||
@ -45,12 +50,12 @@ public final class ColoredMaterials {
|
||||
Material.GREEN_WOOL,
|
||||
Material.RED_WOOL,
|
||||
Material.BLACK_WOOL
|
||||
));
|
||||
});
|
||||
|
||||
/**
|
||||
* This {@link List} contains all stained glass colors ordered by their appearance ingame.
|
||||
*/
|
||||
public static final List<Material> STAINED_GLASS = Collections.unmodifiableList(Arrays.asList(
|
||||
public static final List<Material> STAINED_GLASS = asList(new Material[] {
|
||||
Material.WHITE_STAINED_GLASS,
|
||||
Material.ORANGE_STAINED_GLASS,
|
||||
Material.MAGENTA_STAINED_GLASS,
|
||||
@ -67,12 +72,12 @@ public final class ColoredMaterials {
|
||||
Material.GREEN_STAINED_GLASS,
|
||||
Material.RED_STAINED_GLASS,
|
||||
Material.BLACK_STAINED_GLASS
|
||||
));
|
||||
});
|
||||
|
||||
/**
|
||||
* This {@link List} contains all stained glass pane colors ordered by their appearance ingame.
|
||||
*/
|
||||
public static final List<Material> STAINED_GLASS_PANE = Collections.unmodifiableList(Arrays.asList(
|
||||
public static final List<Material> STAINED_GLASS_PANE = asList(new Material[] {
|
||||
Material.WHITE_STAINED_GLASS_PANE,
|
||||
Material.ORANGE_STAINED_GLASS_PANE,
|
||||
Material.MAGENTA_STAINED_GLASS_PANE,
|
||||
@ -89,12 +94,12 @@ public final class ColoredMaterials {
|
||||
Material.GREEN_STAINED_GLASS_PANE,
|
||||
Material.RED_STAINED_GLASS_PANE,
|
||||
Material.BLACK_STAINED_GLASS_PANE
|
||||
));
|
||||
});
|
||||
|
||||
/**
|
||||
* This {@link List} contains all terracotta colors ordered by their appearance ingame.
|
||||
*/
|
||||
public static final List<Material> TERRACOTTA = Collections.unmodifiableList(Arrays.asList(
|
||||
public static final List<Material> TERRACOTTA = asList(new Material[] {
|
||||
Material.WHITE_TERRACOTTA,
|
||||
Material.ORANGE_TERRACOTTA,
|
||||
Material.MAGENTA_TERRACOTTA,
|
||||
@ -111,12 +116,12 @@ public final class ColoredMaterials {
|
||||
Material.GREEN_TERRACOTTA,
|
||||
Material.RED_TERRACOTTA,
|
||||
Material.BLACK_TERRACOTTA
|
||||
));
|
||||
});
|
||||
|
||||
/**
|
||||
* This {@link List} contains all glazed terracotta colors ordered by their appearance ingame.
|
||||
*/
|
||||
public static final List<Material> GLAZED_TERRACOTTA = Collections.unmodifiableList(Arrays.asList(
|
||||
public static final List<Material> GLAZED_TERRACOTTA = asList(new Material[] {
|
||||
Material.WHITE_GLAZED_TERRACOTTA,
|
||||
Material.ORANGE_GLAZED_TERRACOTTA,
|
||||
Material.MAGENTA_GLAZED_TERRACOTTA,
|
||||
@ -133,12 +138,12 @@ public final class ColoredMaterials {
|
||||
Material.GREEN_GLAZED_TERRACOTTA,
|
||||
Material.RED_GLAZED_TERRACOTTA,
|
||||
Material.BLACK_GLAZED_TERRACOTTA
|
||||
));
|
||||
});
|
||||
|
||||
/**
|
||||
* This {@link List} contains all concrete colors ordered by their appearance ingame.
|
||||
*/
|
||||
public static final List<Material> CONCRETE = Collections.unmodifiableList(Arrays.asList(
|
||||
public static final List<Material> CONCRETE = asList(new Material[] {
|
||||
Material.WHITE_CONCRETE,
|
||||
Material.ORANGE_CONCRETE,
|
||||
Material.MAGENTA_CONCRETE,
|
||||
@ -155,6 +160,16 @@ public final class ColoredMaterials {
|
||||
Material.GREEN_CONCRETE,
|
||||
Material.RED_CONCRETE,
|
||||
Material.BLACK_CONCRETE
|
||||
));
|
||||
});
|
||||
|
||||
// @formatter:on
|
||||
|
||||
@Nonnull
|
||||
private static List<Material> asList(@Nonnull Material[] materials) {
|
||||
Validate.noNullElements(materials, "The List cannot contain any null elements");
|
||||
Validate.isTrue(materials.length == 16, "Expected 16, received: " + materials.length + ". Did you miss a color?");
|
||||
|
||||
return Collections.unmodifiableList(Arrays.asList(materials));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package io.github.thebusybiscuit.slimefun4.utils;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.text.NumberFormat;
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDateTime;
|
||||
@ -24,7 +25,7 @@ public final class NumberUtils {
|
||||
/**
|
||||
* This is our {@link DecimalFormat} for decimal values.
|
||||
*/
|
||||
private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#.##");
|
||||
private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#.##", DecimalFormatSymbols.getInstance(Locale.ROOT));
|
||||
|
||||
/**
|
||||
* We do not want any instance of this to be created.
|
||||
@ -105,8 +106,31 @@ public final class NumberUtils {
|
||||
*/
|
||||
@Nonnull
|
||||
public static String getElapsedTime(@Nonnull LocalDateTime date) {
|
||||
Validate.notNull(date, "Provided date was null");
|
||||
long hours = Duration.between(date, LocalDateTime.now()).toHours();
|
||||
return getElapsedTime(LocalDateTime.now(), date);
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the elapsed time between the two given {@link LocalDateTime LocalDateTimes}.
|
||||
* The output will be nicely formatted based on the elapsed hours or days between the
|
||||
* given {@link LocalDateTime LocalDateTime}.
|
||||
*
|
||||
* If a {@link LocalDateTime} from today and yesterday (exactly 24h apart) was passed it
|
||||
* will return {@code "1d"}.
|
||||
* One hour later it will read {@code "1d 1h"}. For values smaller than an hour {@code "< 1h"}
|
||||
* will be returned instead.
|
||||
*
|
||||
* @param start
|
||||
* The starting {@link LocalDateTime}.
|
||||
* @param end
|
||||
* The ending {@link LocalDateTime}.
|
||||
*
|
||||
* @return The elapsed time as a {@link String}
|
||||
*/
|
||||
@Nonnull
|
||||
public static String getElapsedTime(@Nonnull LocalDateTime start, @Nonnull LocalDateTime end) {
|
||||
Validate.notNull(start, "Provided start was null");
|
||||
Validate.notNull(end, "Provided end was null");
|
||||
long hours = Duration.between(start, end).toHours();
|
||||
|
||||
if (hours == 0) {
|
||||
return "< 1h";
|
||||
@ -133,12 +157,24 @@ public final class NumberUtils {
|
||||
return timeleft + seconds + "s";
|
||||
}
|
||||
|
||||
/**
|
||||
* This method parses a {@link String} into an {@link Integer}.
|
||||
* If the {@link String} could not be parsed correctly, the provided
|
||||
* default value will be returned instead.
|
||||
*
|
||||
* @param str
|
||||
* The {@link String} to parse
|
||||
* @param defaultValue
|
||||
* The default value for when the {@link String} could not be parsed
|
||||
*
|
||||
* @return The resulting {@link Integer}
|
||||
*/
|
||||
public static int getInt(@Nonnull String str, int defaultValue) {
|
||||
if (PatternUtils.NUMERIC.matcher(str).matches()) {
|
||||
return Integer.parseInt(str);
|
||||
} else {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@ -183,6 +219,8 @@ public final class NumberUtils {
|
||||
* The value to clamp
|
||||
* @param max
|
||||
* The maximum value
|
||||
*
|
||||
* @return The clamped value
|
||||
*/
|
||||
public static int clamp(int min, int value, int max) {
|
||||
if (value < min) {
|
||||
|
@ -5,9 +5,12 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
@ -238,31 +241,30 @@ public abstract class AContainer extends SlimefunItem implements InventoryBlock,
|
||||
BlockMenu inv = BlockStorage.getInventory(b);
|
||||
|
||||
if (isProcessing(b)) {
|
||||
int timeleft = progress.get(b);
|
||||
|
||||
if (timeleft > 0) {
|
||||
ChestMenuUtils.updateProgressbar(inv, 22, timeleft, processing.get(b).getTicks(), getProgressBar());
|
||||
if (takeCharge(b.getLocation())) {
|
||||
|
||||
if (isChargeable()) {
|
||||
if (getCharge(b.getLocation()) < getEnergyConsumption()) {
|
||||
return;
|
||||
int timeleft = progress.get(b);
|
||||
|
||||
if (timeleft > 0) {
|
||||
ChestMenuUtils.updateProgressbar(inv, 22, timeleft, processing.get(b).getTicks(), getProgressBar());
|
||||
|
||||
progress.put(b, timeleft - 1);
|
||||
} else {
|
||||
|
||||
inv.replaceExistingItem(22, new CustomItem(Material.BLACK_STAINED_GLASS_PANE, " "));
|
||||
|
||||
for (ItemStack output : processing.get(b).getOutput()) {
|
||||
inv.pushItem(output.clone(), getOutputSlots());
|
||||
}
|
||||
|
||||
removeCharge(b.getLocation(), getEnergyConsumption());
|
||||
Bukkit.getPluginManager().callEvent(new AsyncMachineProcessCompleteEvent(b.getLocation(), AContainer.this, getProcessing(b)));
|
||||
|
||||
progress.remove(b);
|
||||
processing.remove(b);
|
||||
}
|
||||
progress.put(b, timeleft - 1);
|
||||
} else {
|
||||
inv.replaceExistingItem(22, new CustomItem(Material.BLACK_STAINED_GLASS_PANE, " "));
|
||||
|
||||
for (ItemStack output : processing.get(b).getOutput()) {
|
||||
inv.pushItem(output.clone(), getOutputSlots());
|
||||
}
|
||||
|
||||
Bukkit.getPluginManager().callEvent(new AsyncMachineProcessCompleteEvent(b.getLocation(), AContainer.this, getProcessing(b)));
|
||||
|
||||
progress.remove(b);
|
||||
processing.remove(b);
|
||||
}
|
||||
|
||||
} else {
|
||||
MachineRecipe next = findNextRecipe(inv);
|
||||
|
||||
@ -273,6 +275,26 @@ public abstract class AContainer extends SlimefunItem implements InventoryBlock,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will remove charge from a location if it is chargeable.
|
||||
*
|
||||
* @param l
|
||||
* location to try to remove charge from
|
||||
* @return Whether charge was taken if its chargeable
|
||||
*/
|
||||
protected boolean takeCharge(@Nonnull Location l) {
|
||||
Validate.notNull(l, "Can't attempt to take charge from a null location!");
|
||||
|
||||
if (isChargeable()) {
|
||||
if (getCharge(l) < getEnergyConsumption()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
removeCharge(l, getEnergyConsumption());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected MachineRecipe findNextRecipe(BlockMenu inv) {
|
||||
Map<Integer, ItemStack> inventory = new HashMap<>();
|
||||
|
||||
|
@ -244,6 +244,7 @@ machines:
|
||||
finished: Az Industrial Miner-ed kész! Összesen %ores% ércet szerzett!
|
||||
anvil:
|
||||
not-working: "&4Nem használhatsz Slimefun tárgyakat az üllőben!"
|
||||
mcmmo-salvaging: "&4Nem hasznosíthatsz újra Slimefun tárgyakat!"
|
||||
backpack:
|
||||
already-open: "&cSajnáljuk, ez a hátizsák valahol máshol már nyitva van!"
|
||||
no-stack: "&cNem halmozhatsz hátizsákokat"
|
||||
@ -306,7 +307,7 @@ android:
|
||||
rating:
|
||||
own: "&4Nem értékelheted a saját szkriptedet!"
|
||||
already: "&4Ezt a szkriptet már értékelted!"
|
||||
editor: Szkript Szerkesztő
|
||||
editor: Szkript szerkesztő
|
||||
languages:
|
||||
default: Szerver-alapértelmezett
|
||||
en: Angol
|
||||
@ -328,7 +329,6 @@ languages:
|
||||
zh-CN: Kínai (Kína)
|
||||
el: Görög
|
||||
he: Héber
|
||||
pt-BR: Portugál (Brazília)
|
||||
ar: Arab
|
||||
af: Afrikaans
|
||||
da: Dán
|
||||
@ -341,6 +341,7 @@ languages:
|
||||
th: Thai
|
||||
ro: Román
|
||||
pt: Portugál (Portugália)
|
||||
pt-BR: Portugál (Brazília)
|
||||
bg: Bolgár
|
||||
ko: Koreai
|
||||
tr: Török
|
||||
@ -355,5 +356,7 @@ villagers:
|
||||
no-trading: "&4Nem cserélhetsz Slimefun tárgyakat falusiakkal!"
|
||||
cartography_table:
|
||||
not-working: "&4Nem használhatsz Slimefun tárgyakat térképasztalban."
|
||||
cauldron:
|
||||
no-discoloring: "&4Nem színteleníthetsz Slimefun páncélt!"
|
||||
miner:
|
||||
no-ores: "&eSajnálom, nem találtam semmilyen ércet a közelben!"
|
||||
|
@ -246,3 +246,4 @@ slimefun:
|
||||
caveman_talisman: Az Ősember talizmánja
|
||||
even_higher_tier_capacitors: 3. szintű kondenzátorok
|
||||
elytra_cap: Ütközésvédelem
|
||||
energy_connectors: Vezetékes csatlakozás
|
||||
|
@ -0,0 +1,78 @@
|
||||
package io.github.thebusybiscuit.slimefun4.testing.tests.utils;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
|
||||
|
||||
class TestNumberUtils {
|
||||
|
||||
@Test
|
||||
@DisplayName("Test NumberUtils.clamp(...)")
|
||||
void testHumanize() {
|
||||
// Below minimum
|
||||
Assertions.assertEquals(2, NumberUtils.clamp(2, 0, 5));
|
||||
|
||||
// Normal
|
||||
Assertions.assertEquals(3, NumberUtils.clamp(0, 3, 5));
|
||||
|
||||
// Above maximum
|
||||
Assertions.assertEquals(20, NumberUtils.clamp(1, 100, 20));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Test elapsed time string")
|
||||
void testElapsedTime() {
|
||||
LocalDateTime start = LocalDateTime.now();
|
||||
|
||||
LocalDateTime a = start.plusDays(1);
|
||||
Assertions.assertEquals("1d", NumberUtils.getElapsedTime(start, a));
|
||||
|
||||
LocalDateTime b = start.plusHours(25);
|
||||
Assertions.assertEquals("1d 1h", NumberUtils.getElapsedTime(start, b));
|
||||
|
||||
LocalDateTime c = start.plusHours(1);
|
||||
Assertions.assertEquals("1h", NumberUtils.getElapsedTime(start, c));
|
||||
|
||||
LocalDateTime d = start.plusMinutes(12);
|
||||
Assertions.assertEquals("< 1h", NumberUtils.getElapsedTime(start, d));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Test Integer parsing")
|
||||
void testIntegerParsing() {
|
||||
Assertions.assertEquals(6, NumberUtils.getInt("6", 0));
|
||||
Assertions.assertEquals(12, NumberUtils.getInt("I am a String", 12));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Test nullable Long")
|
||||
void testNullableLong() {
|
||||
Assertions.assertEquals(10, NumberUtils.getLong(10L, 20L));
|
||||
Assertions.assertEquals(20, NumberUtils.getLong(null, 20L));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Test nullable Int")
|
||||
void testNullableInt() {
|
||||
Assertions.assertEquals(10, NumberUtils.getInt(10, 20));
|
||||
Assertions.assertEquals(20, NumberUtils.getInt((Integer) null, 20));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Test nullable Float")
|
||||
void testNullableFloat() {
|
||||
Assertions.assertEquals(10, NumberUtils.getFloat(10F, 20F));
|
||||
Assertions.assertEquals(20, NumberUtils.getFloat(null, 20F));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Test decimal rounding")
|
||||
void testRounding() {
|
||||
Assertions.assertEquals("5.25", NumberUtils.roundDecimalNumber(5.249999999999));
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user