diff --git a/.git-hooks/pre-commit b/.git-hooks/pre-commit
index 3c0c23770a..d1853bd821 100644
--- a/.git-hooks/pre-commit
+++ b/.git-hooks/pre-commit
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
echo "[pre-commit check]"
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 08f8025bfd..1c27c23107 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,10 +1,16 @@
-# 贡献代码指南
+# 贡献指南
-在向 Slimefun 汉化版提交代码前,你必须先阅读这个指南。
+在对 Slimefun 汉化版进行代码前,必须先阅读此贡献指南。
+
+# 设置环境
+
+我们提供了一个自动化格式检查系统,请使用 `mvn install` 进行初始化。
+
+本项目已经提供 `.editorconfig` 用于控制代码样式。如果你有自己的代码样式风格,请在对本仓库进行贡献前切换为当前仓库的风格配置。
# 提交信息规范
-本项目强制使用 [约定式提交](https://www.conventionalcommits.org/zh-hans/v1.0.0/) 的提交信息规范。
+本项目**强制使用** [约定式提交](https://www.conventionalcommits.org/zh-hans/v1.0.0/) 的提交信息规范。
> 简单来说, 你的提交信息需要包含以下内容:
>
@@ -18,6 +24,8 @@
如果是修复请在主提交消息上声明,不必重复声明。
+我们支持的类型前缀正则如下:`(feat(ure)?|fix|docs|style|refactor|ci|chore|perf|build|test|revert|trans)`
+
另外的, 如果是与翻译相关的提交,类型应为 trans。
# 代码规范
@@ -26,12 +34,10 @@
请不要过度缩减代码长度, 空格少了 Slimefun 也不会因此跑得更快.
-我们使用了 Spotless 作为代码格式化工具,你可以直接使用 `mvn spotless:check spotless:apply` 来自动格式化你的代码。
-
-如果你希望你的代码被合并至官方, 请遵守 Slimefun 主仓库的 [提交规范](https://github.com/Slimefun/Slimefun4/blob/master/CONTRIBUTING.md)
+我们使用了 Spotless 作为代码格式化工具,在提交前你**必须**使用 `mvn spotless:check spotless:apply` 来自动格式化你的代码,否则将会被格式检查器拦截 PR。
# 提交代码类型
你提交的代码可以是修复、新增内容和 API。
-下游代码现在支持提交 API 相关代码,开发者们可以通过 jitpack/GitHub Package 依赖汉化版的 Slimefun。
\ No newline at end of file
+下游代码现在支持提交 API 相关代码,开发者们可以通过 jitpack 依赖汉化版的 Slimefun。
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 9261301f1a..5ce886f565 100644
--- a/pom.xml
+++ b/pom.xml
@@ -309,33 +309,9 @@
org.postgresql
postgresql
- 42.7.2
+ 42.7.3
compile
-
- org.apache.logging.log4j
- log4j-api
- 2.19.0
- provided
-
-
- org.apache.logging.log4j
- log4j-core
- 2.19.0
- provided
-
-
- org.apache.logging.log4j
- log4j-slf4j-impl
- 2.19.0
- provided
-
-
- org.slf4j
- slf4j-api
- 2.0.7
- provided
-
diff --git a/src/main/java/city/norain/slimefun4/SlimefunExtended.java b/src/main/java/city/norain/slimefun4/SlimefunExtended.java
index a614f4f9a8..adacde99bb 100644
--- a/src/main/java/city/norain/slimefun4/SlimefunExtended.java
+++ b/src/main/java/city/norain/slimefun4/SlimefunExtended.java
@@ -1,7 +1,6 @@
package city.norain.slimefun4;
import city.norain.slimefun4.listener.SlimefunMigrateListener;
-import city.norain.slimefun4.utils.HikariLogFilter;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import java.util.logging.Level;
import javax.annotation.Nonnull;
@@ -16,7 +15,6 @@ public final class SlimefunExtended {
private static void checkDebug() {
if ("true".equals(System.getProperty("slimefun.database.debug"))) {
databaseDebugMode = true;
- HikariLogFilter.registerFilter(org.apache.logging.log4j.Level.DEBUG);
}
}
diff --git a/src/main/java/city/norain/slimefun4/utils/HikariLogFilter.java b/src/main/java/city/norain/slimefun4/utils/HikariLogFilter.java
deleted file mode 100644
index 582b1eba7a..0000000000
--- a/src/main/java/city/norain/slimefun4/utils/HikariLogFilter.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package city.norain.slimefun4.utils;
-
-import org.apache.logging.log4j.Level;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Marker;
-import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.core.Logger;
-import org.apache.logging.log4j.core.filter.AbstractFilter;
-import org.apache.logging.log4j.message.Message;
-
-public class HikariLogFilter extends AbstractFilter {
- private final Level level;
-
- public HikariLogFilter(Level level) {
- this.level = level;
- }
-
- public static void registerFilter(Level level) {
- Logger logger = (Logger) LogManager.getRootLogger();
- logger.addFilter(new HikariLogFilter(level));
- }
-
- @Override
- public Result filter(LogEvent event) {
- if (event == null) {
- return Result.NEUTRAL;
- }
-
- if (event.getLoggerName().contains("Hikari") && event.getLevel().isInRange(level, Level.FATAL)) {
- return Result.ACCEPT;
- }
-
- return Result.NEUTRAL;
- }
-
- @Override
- public Result filter(Logger logger, Level level, Marker marker, Message msg, Throwable t) {
- return Result.NEUTRAL;
- }
-
- @Override
- public Result filter(Logger logger, Level level, Marker marker, String msg, Object... params) {
- return Result.NEUTRAL;
- }
-
- @Override
- public Result filter(Logger logger, Level level, Marker marker, Object msg, Throwable t) {
- return Result.NEUTRAL;
- }
-}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/geo/ResourceManager.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/geo/ResourceManager.java
index 8d8701a429..e4b9e25b12 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/geo/ResourceManager.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/geo/ResourceManager.java
@@ -15,8 +15,10 @@
import io.github.thebusybiscuit.slimefun4.utils.HeadTexture;
import java.util.ArrayList;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.List;
import java.util.Locale;
+import java.util.Map;
import java.util.OptionalInt;
import java.util.concurrent.ThreadLocalRandom;
import javax.annotation.Nonnull;
@@ -246,7 +248,7 @@ private int generate(@Nonnull GEOResource resource, @Nonnull World world, int x,
* @param block
* The {@link Block} which the scan starts at
* @param page
- * The page to display
+ * The zero-based page to display
*/
public void scan(@Nonnull Player p, @Nonnull Block block, int page) {
if (Slimefun.getGPSNetwork().getNetworkComplexity(p.getUniqueId()) < 600) {
@@ -282,12 +284,20 @@ public void scan(@Nonnull Player p, @Nonnull Block block, int page) {
resources.sort(Comparator.comparing(a -> a.getName(p).toLowerCase(Locale.ROOT)));
int index = 10;
- int pages = (resources.size() - 1) / 36 + 1;
+ int pages = (int) (Math.ceil((double) resources.size() / 36) + 1);
- for (int i = page * 28; i < resources.size() && i < (page + 1) * 28; i++) {
- GEOResource resource = resources.get(i);
+ Map supplyMap = new HashMap<>();
+
+ // if resource is not generated, generate the first
+ resources.forEach(resource -> {
OptionalInt optional = getSupplies(resource, block.getWorld(), x, z);
int supplies = optional.orElseGet(() -> generate(resource, block.getWorld(), x, block.getY(), z));
+ supplyMap.put(resource, supplies);
+ });
+
+ for (int i = page * 28; i < resources.size() && i < (page + 1) * 28; i++) {
+ GEOResource resource = resources.get(i);
+ int supplies = supplyMap.get(resource);
String suffix = Slimefun.getLocalization()
.getResourceString(p, ChatUtils.checkPlurality("tooltips.unit", supplies));
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/items/SlimefunItem.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/items/SlimefunItem.java
index 3593dfa8d5..f9e23e222a 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/items/SlimefunItem.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/items/SlimefunItem.java
@@ -1233,6 +1233,17 @@ public final int hashCode() {
return Slimefun.getRegistry().getSlimefunItemIds().get(id);
}
+ /**
+ * Retrieve a {@link Optional} {@link SlimefunItem} by its id.
+ *
+ * @param id
+ * The id of the {@link SlimefunItem}
+ * @return The {@link Optional} {@link SlimefunItem} associated with that id. Empty if non-existent
+ */
+ public static @Nonnull Optional getOptionalById(@Nonnull String id) {
+ return Optional.ofNullable(getById(id));
+ }
+
/**
* Retrieve a {@link SlimefunItem} from an {@link ItemStack}.
*
@@ -1258,6 +1269,17 @@ public final int hashCode() {
return null;
}
+ /**
+ * Retrieve a {@link Optional} {@link SlimefunItem} from an {@link ItemStack}.
+ *
+ * @param item
+ * The {@link ItemStack} to check
+ * @return The {@link Optional} {@link SlimefunItem} associated with this {@link ItemStack} if present, otherwise empty
+ */
+ public static @Nonnull Optional getOptionalByItem(@Nullable ItemStack item) {
+ return Optional.ofNullable(getByItem(item));
+ }
+
/**
* Should load the {@link SlimefunBlockData} by default.
* If return false, only the item with {@link BlockTicker} will be loaded with {@link ChunkLoadEvent}.
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/GEOMiner.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/GEOMiner.java
index c100c8aca7..38e3f193c6 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/GEOMiner.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/GEOMiner.java
@@ -343,16 +343,16 @@ public void onResult(SlimefunChunkData result) {
}
private void start(@Nonnull Block b, @Nonnull BlockMenu inv) {
+ boolean success = Slimefun.getRegistry().getGEOResources().values().isEmpty();
for (GEOResource resource : Slimefun.getRegistry().getGEOResources().values()) {
if (resource.isObtainableFromGEOMiner()) {
OptionalInt optional = Slimefun.getGPSNetwork()
.getResourceManager()
.getSupplies(resource, b.getWorld(), b.getX() >> 4, b.getZ() >> 4);
- if (!optional.isPresent()) {
- updateHologram(b, "&4需要先进行地形扫描!");
- return;
- }
+ if (optional.isEmpty()) continue;
+
+ success = true;
int supplies = optional.getAsInt();
if (supplies > 0) {
@@ -370,6 +370,11 @@ private void start(@Nonnull Block b, @Nonnull BlockMenu inv) {
}
}
+ if (!success) {
+ updateHologram(b, "&4需要先进行地形扫描!");
+ return;
+ }
+
updateHologram(b, "&7开采完成");
}
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/ExplosiveTool.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/ExplosiveTool.java
index 8894b6b924..05a459a23b 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/ExplosiveTool.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/ExplosiveTool.java
@@ -18,12 +18,18 @@
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicBoolean;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import org.bukkit.Bukkit;
import org.bukkit.Effect;
+import org.bukkit.Location;
import org.bukkit.Material;
+import org.bukkit.Tag;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.block.BlockBreakEvent;
@@ -34,10 +40,8 @@
* This {@link SlimefunItem} is a super class for items like the {@link ExplosivePickaxe} or {@link ExplosiveShovel}.
*
* @author TheBusyBiscuit
- *
* @see ExplosivePickaxe
* @see ExplosiveShovel
- *
*/
public class ExplosiveTool extends SimpleSlimefunItem implements NotPlaceable, DamageableItem {
@@ -104,6 +108,17 @@ private void breakBlocks(
ExplosiveToolBreakBlocksEvent event = new ExplosiveToolBreakBlocksEvent(p, b, blocksToDestroy, item, this);
Bukkit.getServer().getPluginManager().callEvent(event);
+ /*
+ * 修复: https://github.com/SlimefunGuguProject/Slimefun4/issues/853
+ *
+ * 为了修复该问题应该对该列表进行排序,确保头颅先被处理,具体为什么可以看下方 breakBlock 方法。
+ */
+ if (Bukkit.getPluginManager().isPluginEnabled("ExoticGarden")) {
+ blocksToDestroy.sort((block1, block2) -> Boolean.compare(
+ block2.getType().equals(Material.PLAYER_HEAD),
+ block1.getType().equals(Material.PLAYER_HEAD)));
+ }
+
if (!event.isCancelled()) {
for (Block block : blocksToDestroy) {
breakBlock(e, p, item, block, drops);
@@ -149,38 +164,87 @@ protected boolean canBreak(@Nonnull Player p, @Nonnull Block b) {
}
@ParametersAreNonnullByDefault
- private void breakBlock(BlockBreakEvent e, Player p, ItemStack item, Block b, List drops) {
- Slimefun.getProtectionManager().logAction(p, b, Interaction.BREAK_BLOCK);
- Material material = b.getType();
-
- b.getWorld().playEffect(b.getLocation(), Effect.STEP_SOUND, material);
- var loc = b.getLocation();
- SlimefunItem sfItem = StorageCacheUtils.getSfItem(loc);
-
- if (sfItem != null && !sfItem.useVanillaBlockBreaking()) {
- /*
- * Fixes #2989
- * We create a dummy here to pass onto the BlockBreakHandler.
- * This will set the correct block context.
- */
- BlockBreakEvent dummyEvent = new BlockBreakEvent(b, e.getPlayer());
-
- /*
- * Fixes #3036 and handling in general.
- * Call the BlockBreakHandler if the block has one to allow for proper handling.
- */
- sfItem.callItemHandler(BlockBreakHandler.class, handler -> handler.onPlayerBreak(dummyEvent, item, drops));
-
- // Make sure the event wasn't cancelled by the BlockBreakHandler.
- if (!dummyEvent.isCancelled()) {
- drops.addAll(sfItem.getDrops(p));
- b.setType(Material.AIR);
- Slimefun.getDatabaseManager().getBlockDataController().removeBlock(loc);
+ private void breakBlock(BlockBreakEvent event, Player player, ItemStack item, Block block, List drops) {
+ Slimefun.getProtectionManager().logAction(player, block, Interaction.BREAK_BLOCK);
+ Material material = block.getType();
+
+ block.getWorld().playEffect(block.getLocation(), Effect.STEP_SOUND, material);
+ Location blockLocation = block.getLocation();
+
+ Optional optionalBlockSfItem = Optional.ofNullable(StorageCacheUtils.getSfItem(blockLocation));
+
+ /*
+ * 修复: https://github.com/SlimefunGuguProject/Slimefun4/issues/853
+ *
+ * 该问题源于 ExoticGarden MagicalEssence/ExoticGardenFruit useVanillaBlockBreaking 为 true,
+ * 将调用 breakNaturally 方法而非将其作为 SlimefunItem 进行处理。
+ *
+ * 此前将 blocks 进行排序,以确保头颅为最先处理的对象,检查头颅的 Y - 1 方块是否为叶子,
+ * 若为叶子则尝试获取该处的 SlimefunItem,若能获取得到则此处应为异域花园植物,将叶子处直接设置为 AIR 并移除该处 Slimefun 方块数据。
+ */
+ AtomicBoolean isUseVanillaBlockBreaking = new AtomicBoolean(true);
+
+ if (Bukkit.getPluginManager().isPluginEnabled("ExoticGarden")
+ && block.getType().equals(Material.PLAYER_HEAD)) {
+ Location leavesLocation = blockLocation.clone();
+ leavesLocation.setY(leavesLocation.getY() - 1);
+
+ Block leaveBlock = leavesLocation.getBlock();
+ Material leaveBlockType = leaveBlock.getType();
+
+ if (Tag.LEAVES.isTagged(leaveBlockType)) {
+ Optional optionalLeavesBlockSfItem =
+ Optional.ofNullable(StorageCacheUtils.getSfItem(leavesLocation));
+
+ optionalBlockSfItem.ifPresent(blockSfItem -> optionalLeavesBlockSfItem.ifPresent(leavesSfItem -> {
+ Collection sfItemDrops = blockSfItem.getDrops();
+ Collection leavesSfItemDrops = leavesSfItem.getDrops();
+
+ if (Arrays.equals(sfItemDrops.toArray(), leavesSfItemDrops.toArray())) {
+ leaveBlock.setType(Material.AIR);
+ Slimefun.getDatabaseManager().getBlockDataController().removeBlock(leavesLocation);
+
+ isUseVanillaBlockBreaking.set(false);
+ }
+ }));
}
- } else {
- b.breakNaturally(item);
}
- damageItem(p, item);
+ optionalBlockSfItem.ifPresent(sfItem -> {
+ if (isUseVanillaBlockBreaking.get()) {
+ isUseVanillaBlockBreaking.set(sfItem.useVanillaBlockBreaking());
+ }
+
+ if (isUseVanillaBlockBreaking.get()) {
+ block.breakNaturally(item);
+ } else {
+ /*
+ * Fixes #2989
+ * We create a dummy here to pass onto the BlockBreakHandler.
+ * This will set the correct block context.
+ */
+ BlockBreakEvent dummyEvent = new BlockBreakEvent(block, event.getPlayer());
+
+ /*
+ * Fixes #3036 and handling in general.
+ * Call the BlockBreakHandler if the block has one to allow for proper handling.
+ */
+ sfItem.callItemHandler(
+ BlockBreakHandler.class, handler -> handler.onPlayerBreak(dummyEvent, item, drops));
+
+ // Make sure the event wasn't cancelled by the BlockBreakHandler.
+ if (!dummyEvent.isCancelled()) {
+ drops.addAll(sfItem.getDrops(player));
+ block.setType(Material.AIR);
+ Slimefun.getDatabaseManager().getBlockDataController().removeBlock(blockLocation);
+ }
+ }
+ });
+
+ if (optionalBlockSfItem.isEmpty()) {
+ block.breakNaturally(item);
+ }
+
+ damageItem(player, item);
}
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/armor/RadiationTask.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/armor/RadiationTask.java
index eda9bd5e1c..63ac21bf24 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/armor/RadiationTask.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/armor/RadiationTask.java
@@ -7,7 +7,6 @@
import io.github.thebusybiscuit.slimefun4.core.attributes.RadiationSymptom;
import io.github.thebusybiscuit.slimefun4.core.attributes.Radioactive;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
-import io.github.thebusybiscuit.slimefun4.implementation.items.RadioactiveItem;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.RadioactivityListener;
import io.github.thebusybiscuit.slimefun4.utils.RadiationUtils;
import java.util.HashMap;
@@ -52,7 +51,7 @@ protected void onPlayerTick(Player p, PlayerProfile profile) {
continue;
}
SlimefunItem sfItem = SlimefunItem.getByItem(item);
- if (sfItem instanceof RadioactiveItem radioactiveItem) {
+ if (sfItem instanceof Radioactive radioactiveItem) {
exposureTotal += item.getAmount()
* radioactiveItem.getRadioactivity().getExposureModifier();
}