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(); }