From e2170f54ba5a20b0348ee928db158b37ee7d8783 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Sat, 6 Dec 2025 19:03:07 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=9F=BA=E5=B2=A9=E7=89=88?= =?UTF-8?q?=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bukkit/compatibility/build.gradle.kts | 5 +++ .../BukkitCompatibilityManager.java | 22 ++++++++++ .../compatibility/bedrock/FloodgateUtils.java | 14 +++++++ .../compatibility/bedrock/GeyserUtils.java | 14 +++++++ .../compatibility/item/MMOItemsSource.java | 4 +- .../worldedit/WorldEditBlockRegister.java | 3 +- bukkit/paper-loader/build.gradle.kts | 4 ++ .../advancement/BukkitAdvancementManager.java | 5 ++- .../block/behavior/BukkitBlockBehavior.java | 3 +- .../element/ItemBlockEntityElementConfig.java | 5 +++ .../ItemDisplayBlockEntityElementConfig.java | 37 +++++++++++++++- .../TextDisplayBlockEntityElementConfig.java | 42 ++++++++++++++++--- .../entity/furniture/BukkitFurniture.java | 5 ++- .../element/ItemDisplayFurnitureElement.java | 2 +- .../ItemDisplayFurnitureElementConfig.java | 38 +++++++++-------- .../hitbox/CustomFurnitureHitbox.java | 3 +- .../hitbox/InteractionFurnitureHitbox.java | 3 +- .../DebugGenerateInternalAssetsCommand.java | 3 +- .../plugin/injector/BlockStateGenerator.java | 2 +- .../bukkit/util/InteractUtils.java | 8 ++-- .../core/block/parser/BlockStateParser.java | 13 +++--- .../core/pack/AbstractPackManager.java | 12 +++--- .../core/pack/host/impl/AlistHost.java | 2 +- .../core/pack/host/impl/DropboxHost.java | 2 +- .../core/pack/host/impl/ExternalHost.java | 3 +- .../core/pack/host/impl/GitLabHost.java | 8 ++-- .../core/pack/host/impl/LobFileHost.java | 15 +++---- .../core/pack/host/impl/OneDriveHost.java | 11 ++--- .../pack/host/impl/SelfHostHttpServer.java | 16 +++++-- .../model/special/ShulkerBoxSpecialModel.java | 2 +- .../core/pack/obfuscation/ObfB.java | 3 +- .../compatibility/CompatibilityManager.java | 2 + .../entityculling/EntityCullingThread.java | 4 +- .../core/util/MarkedArrayList.java | 3 ++ .../craftengine/core/util/MarkedHashMap.java | 3 ++ .../craftengine/core/util/SkullUtils.java | 3 +- 36 files changed, 241 insertions(+), 83 deletions(-) create mode 100644 bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/bedrock/FloodgateUtils.java create mode 100644 bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/bedrock/GeyserUtils.java diff --git a/bukkit/compatibility/build.gradle.kts b/bukkit/compatibility/build.gradle.kts index 13d93e5cd..af75e84e9 100644 --- a/bukkit/compatibility/build.gradle.kts +++ b/bukkit/compatibility/build.gradle.kts @@ -18,6 +18,7 @@ repositories { maven("https://jitpack.io") // sxitem slimefun maven("https://repo.codemc.io/repository/maven-public/") // quickshop maven("https://repo.nexomc.com/releases/") // nexo + maven("https://repo.opencollab.dev/main/") // geyser } dependencies { @@ -88,6 +89,10 @@ dependencies { compileOnly("io.github.Slimefun:Slimefun4:RC-32") // QuickShop compileOnly("com.ghostchu:quickshop-api:6.2.0.10") + // Geyser + compileOnly("org.geysermc.geyser:api:2.9.0-SNAPSHOT") + // Floodgate + compileOnly("org.geysermc.floodgate:api:2.2.4-SNAPSHOT") } java { diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/BukkitCompatibilityManager.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/BukkitCompatibilityManager.java index c56a998aa..35e2717f0 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/BukkitCompatibilityManager.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/BukkitCompatibilityManager.java @@ -3,6 +3,8 @@ package net.momirealms.craftengine.bukkit.compatibility; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.block.entity.renderer.element.BukkitBlockEntityElementConfigs; +import net.momirealms.craftengine.bukkit.compatibility.bedrock.FloodgateUtils; +import net.momirealms.craftengine.bukkit.compatibility.bedrock.GeyserUtils; import net.momirealms.craftengine.bukkit.compatibility.item.*; import net.momirealms.craftengine.bukkit.compatibility.legacy.slimeworld.LegacySlimeFormatStorageAdaptor; import net.momirealms.craftengine.bukkit.compatibility.leveler.*; @@ -55,6 +57,8 @@ public class BukkitCompatibilityManager implements CompatibilityManager { private final Map tagResolverProviders; private TagResolverProvider[] tagResolverProviderArray = null; private boolean hasPlaceholderAPI; + private boolean hasGeyser; + private boolean hasFloodgate; public BukkitCompatibilityManager(BukkitCraftEngine plugin) { this.plugin = plugin; @@ -110,6 +114,12 @@ public class BukkitCompatibilityManager implements CompatibilityManager { EventConditions.register(worldGuardRegion, new AlwaysFalseCondition.FactoryImpl<>()); LootConditions.register(worldGuardRegion, new AlwaysFalseCondition.FactoryImpl<>()); } + if (this.isPluginEnabled("Geyser-Spigot")) { + this.hasGeyser = true; + } + if (this.isPluginEnabled("floodgate")) { + this.hasFloodgate = true; + } } @Override @@ -368,4 +378,16 @@ public class BukkitCompatibilityManager implements CompatibilityManager { } return resolvers; } + + @Override + public boolean isBedrockPlayer(Player player) { + UUID uuid = player.uuid(); + if (this.hasFloodgate) { + return FloodgateUtils.isFloodgatePlayer(uuid); + } + if (this.hasGeyser) { + return GeyserUtils.isGeyserPlayer(uuid); + } + return uuid.version() == 0; + } } diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/bedrock/FloodgateUtils.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/bedrock/FloodgateUtils.java new file mode 100644 index 000000000..57969e68d --- /dev/null +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/bedrock/FloodgateUtils.java @@ -0,0 +1,14 @@ +package net.momirealms.craftengine.bukkit.compatibility.bedrock; + +import org.geysermc.floodgate.api.FloodgateApi; + +import java.util.UUID; + +public final class FloodgateUtils { + + private FloodgateUtils() {} + + public static boolean isFloodgatePlayer(UUID uuid) { + return FloodgateApi.getInstance().isFloodgatePlayer(uuid); + } +} diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/bedrock/GeyserUtils.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/bedrock/GeyserUtils.java new file mode 100644 index 000000000..f62bfc243 --- /dev/null +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/bedrock/GeyserUtils.java @@ -0,0 +1,14 @@ +package net.momirealms.craftengine.bukkit.compatibility.bedrock; + +import org.geysermc.api.Geyser; + +import java.util.UUID; + +public final class GeyserUtils { + + private GeyserUtils() {} + + public static boolean isGeyserPlayer(UUID uuid) { + return Geyser.api().isBedrockPlayer(uuid); + } +} diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/item/MMOItemsSource.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/item/MMOItemsSource.java index b22e5595a..02ec55ab3 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/item/MMOItemsSource.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/item/MMOItemsSource.java @@ -9,6 +9,8 @@ import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Nullable; +import java.util.Locale; + import static java.util.Objects.requireNonNull; public class MMOItemsSource implements ExternalItemSource { @@ -25,7 +27,7 @@ public class MMOItemsSource implements ExternalItemSource { split = split[0].split("_", 2); } if (split.length == 1) return new ItemStack(Material.AIR); - MMOItem mmoItem = MMOItems.plugin.getMMOItem(Type.get(split[0]), split[1].toUpperCase()); + MMOItem mmoItem = MMOItems.plugin.getMMOItem(Type.get(split[0]), split[1].toUpperCase(Locale.ROOT)); return mmoItem == null ? new ItemStack(Material.AIR) : requireNonNull(mmoItem.newBuilder().build()); } diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/WorldEditBlockRegister.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/WorldEditBlockRegister.java index be5b1f2ed..fdbfbeb8f 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/WorldEditBlockRegister.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/WorldEditBlockRegister.java @@ -16,6 +16,7 @@ import net.momirealms.craftengine.core.util.ReflectionUtils; import org.bukkit.Material; import java.lang.reflect.Field; +import java.util.Locale; import java.util.Set; import java.util.stream.Stream; @@ -63,7 +64,7 @@ public class WorldEditBlockRegister { } if (!input.contains(":")) { - String lowerSearch = input.toLowerCase(); + String lowerSearch = input.toLowerCase(Locale.ROOT); return Stream.concat( namespacesInUse.stream().filter(n -> n.startsWith(lowerSearch)).map(n -> n + ":"), BlockStateParser.fillSuggestions(input).stream() diff --git a/bukkit/paper-loader/build.gradle.kts b/bukkit/paper-loader/build.gradle.kts index ce8513840..aba556f45 100644 --- a/bukkit/paper-loader/build.gradle.kts +++ b/bukkit/paper-loader/build.gradle.kts @@ -77,6 +77,10 @@ paper { register("ViaVersion") { required = false } register("QuickShop-Hikari") { required = false } + // Geyser + register("Geyser-Spigot") { required = false } + register("floodgate") { required = false } + // AdvancedSlimePaper register("SlimeWorldPlugin") { required = false } register("SlimeWorldManager") { required = false } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/advancement/BukkitAdvancementManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/advancement/BukkitAdvancementManager.java index 5d98d2130..9421777da 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/advancement/BukkitAdvancementManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/advancement/BukkitAdvancementManager.java @@ -17,6 +17,7 @@ import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.plugin.config.IdSectionConfigParser; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.VersionHelper; import java.nio.file.Path; @@ -98,8 +99,8 @@ public final class BukkitAdvancementManager extends AbstractAdvancementManager { NetworkReflections.constructor$ClientboundUpdateAdvancementsPacket.newInstance(false, Arrays.asList(advancement), new HashSet<>(), advancementsToGrant, true) : NetworkReflections.constructor$ClientboundUpdateAdvancementsPacket.newInstance(false, Arrays.asList(advancement), new HashSet<>(), advancementsToGrant); Object removePacket = VersionHelper.isOrAbove1_21_5() ? - NetworkReflections.constructor$ClientboundUpdateAdvancementsPacket.newInstance(false, new ArrayList<>(), new HashSet<>() {{add(resourceLocation);}}, new HashMap<>(), true) : - NetworkReflections.constructor$ClientboundUpdateAdvancementsPacket.newInstance(false, new ArrayList<>(), new HashSet<>() {{add(resourceLocation);}}, new HashMap<>()); + NetworkReflections.constructor$ClientboundUpdateAdvancementsPacket.newInstance(false, new ArrayList<>(), MiscUtils.init(new HashSet<>(), s -> s.add(resourceLocation)), new HashMap<>(), true) : + NetworkReflections.constructor$ClientboundUpdateAdvancementsPacket.newInstance(false, new ArrayList<>(), MiscUtils.init(new HashSet<>(), s -> s.add(resourceLocation)), new HashMap<>()); player.sendPackets(List.of(grantPacket, removePacket), false); } catch (ReflectiveOperationException e) { this.plugin.logger().warn("Failed to send toast for player " + player.name(), e); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehavior.java index 9bc29f2da..79f31a798 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehavior.java @@ -13,6 +13,7 @@ import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.behavior.AbstractBlockBehavior; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.util.*; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.HashMap; @@ -22,7 +23,7 @@ import java.util.concurrent.Callable; import java.util.function.BiConsumer; public class BukkitBlockBehavior extends AbstractBlockBehavior { - private static final Map>> HARD_CODED_PROPERTY_DATA = new HashMap<>(); + private static final Map>> HARD_CODED_PROPERTY_DATA = new HashMap<>(); static { HARD_CODED_PROPERTY_DATA.put("axis", (behavior, property) -> { @SuppressWarnings("unchecked") diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/renderer/element/ItemBlockEntityElementConfig.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/renderer/element/ItemBlockEntityElementConfig.java index fc6ca3df7..51c9c661e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/renderer/element/ItemBlockEntityElementConfig.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/renderer/element/ItemBlockEntityElementConfig.java @@ -75,6 +75,11 @@ public class ItemBlockEntityElementConfig implements BlockEntityElementConfig { @Override diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/renderer/element/ItemDisplayBlockEntityElementConfig.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/renderer/element/ItemDisplayBlockEntityElementConfig.java index a8b02c0b0..426d71406 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/renderer/element/ItemDisplayBlockEntityElementConfig.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/renderer/element/ItemDisplayBlockEntityElementConfig.java @@ -9,16 +9,19 @@ import net.momirealms.craftengine.core.entity.display.Billboard; import net.momirealms.craftengine.core.entity.display.ItemDisplayContext; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.util.Color; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.World; +import org.jetbrains.annotations.Nullable; import org.joml.Quaternionf; import org.joml.Vector3f; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.function.Function; public class ItemDisplayBlockEntityElementConfig implements BlockEntityElementConfig { @@ -35,6 +38,10 @@ public class ItemDisplayBlockEntityElementConfig implements BlockEntityElementCo private final Billboard billboard; private final float shadowRadius; private final float shadowStrength; + private final Color glowColor; + private final int blockLight; + private final int skyLight; + private final float viewRange; public ItemDisplayBlockEntityElementConfig(Function> item, Vector3f scale, @@ -46,7 +53,11 @@ public class ItemDisplayBlockEntityElementConfig implements BlockEntityElementCo ItemDisplayContext displayContext, Billboard billboard, float shadowRadius, - float shadowStrength) { + float shadowStrength, + @Nullable Color glowColor, + int blockLight, + int skyLight, + float viewRange) { this.item = item; this.scale = scale; this.position = position; @@ -58,8 +69,16 @@ public class ItemDisplayBlockEntityElementConfig implements BlockEntityElementCo this.billboard = billboard; this.shadowRadius = shadowRadius; this.shadowStrength = shadowStrength; + this.glowColor = glowColor; + this.blockLight = blockLight; + this.skyLight = skyLight; + this.viewRange = viewRange; this.lazyMetadataPacket = player -> { List dataValues = new ArrayList<>(); + if (glowColor != null) { + ItemDisplayEntityData.SharedFlags.addEntityData((byte) 0x40, dataValues); + ItemDisplayEntityData.GlowColorOverride.addEntityData(glowColor.color(), dataValues); + } ItemDisplayEntityData.DisplayedItem.addEntityData(item.apply(player).getLiteralObject(), dataValues); ItemDisplayEntityData.Scale.addEntityData(this.scale, dataValues); ItemDisplayEntityData.RotationLeft.addEntityData(this.rotation, dataValues); @@ -68,6 +87,10 @@ public class ItemDisplayBlockEntityElementConfig implements BlockEntityElementCo ItemDisplayEntityData.DisplayType.addEntityData(this.displayContext.id(), dataValues); ItemDisplayEntityData.ShadowRadius.addEntityData(this.shadowRadius, dataValues); ItemDisplayEntityData.ShadowStrength.addEntityData(this.shadowStrength, dataValues); + if (this.blockLight != -1 && this.skyLight != -1) { + ItemDisplayEntityData.BrightnessOverride.addEntityData(this.blockLight << 4 | this.skyLight << 20, dataValues); + } + ItemDisplayEntityData.ViewRange.addEntityData(this.viewRange, dataValues); return dataValues; }; } @@ -157,11 +180,17 @@ public class ItemDisplayBlockEntityElementConfig implements BlockEntityElementCo Objects.equal(rotation, that.rotation); } + @Override + public int hashCode() { + return Objects.hashCode(xRot, yRot, position, translation, rotation); + } + public static class Factory implements BlockEntityElementConfigFactory { @Override public ItemDisplayBlockEntityElementConfig create(Map arguments) { Key itemId = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("item"), "warning.config.block.state.entity_renderer.item_display.missing_item")); + Map brightness = ResourceConfigUtils.getAsMap(arguments.getOrDefault("brightness", Map.of()), "brightness"); return new ItemDisplayBlockEntityElementConfig( player -> BukkitItemManager.instance().createWrappedItem(itemId, player), ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("scale", 1f), "scale"), @@ -173,7 +202,11 @@ public class ItemDisplayBlockEntityElementConfig implements BlockEntityElementCo ResourceConfigUtils.getAsEnum(ResourceConfigUtils.get(arguments, "display-context", "display-transform"), ItemDisplayContext.class, ItemDisplayContext.NONE), ResourceConfigUtils.getAsEnum(arguments.get("billboard"), Billboard.class, Billboard.FIXED), ResourceConfigUtils.getAsFloat(arguments.getOrDefault("shadow-radius", 0f), "shadow-radius"), - ResourceConfigUtils.getAsFloat(arguments.getOrDefault("shadow-strength", 1f), "shadow-strength") + ResourceConfigUtils.getAsFloat(arguments.getOrDefault("shadow-strength", 1f), "shadow-strength"), + Optional.ofNullable(arguments.get("glow-color")).map(it -> Color.fromStrings(it.toString().split(","))).orElse(null), + ResourceConfigUtils.getAsInt(brightness.getOrDefault("block-light", -1), "block-light"), + ResourceConfigUtils.getAsInt(brightness.getOrDefault("sky-light", -1), "sky-light"), + ResourceConfigUtils.getAsFloat(arguments.getOrDefault("view-range", 1f), "view-range") ); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/renderer/element/TextDisplayBlockEntityElementConfig.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/renderer/element/TextDisplayBlockEntityElementConfig.java index 5b96a9611..9f3075164 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/renderer/element/TextDisplayBlockEntityElementConfig.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/renderer/element/TextDisplayBlockEntityElementConfig.java @@ -2,6 +2,7 @@ package net.momirealms.craftengine.bukkit.block.entity.renderer.element; import com.google.common.base.Objects; import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.bukkit.entity.data.ItemDisplayEntityData; import net.momirealms.craftengine.bukkit.entity.data.TextDisplayEntityData; import net.momirealms.craftengine.bukkit.util.ComponentUtils; import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfig; @@ -10,16 +11,15 @@ import net.momirealms.craftengine.core.entity.display.Billboard; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.util.AdventureHelper; +import net.momirealms.craftengine.core.util.Color; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.World; +import org.jetbrains.annotations.Nullable; import org.joml.Quaternionf; import org.joml.Vector3f; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -import java.util.Map; +import java.util.*; import java.util.function.Function; public class TextDisplayBlockEntityElementConfig implements BlockEntityElementConfig { @@ -33,6 +33,10 @@ public class TextDisplayBlockEntityElementConfig implements BlockEntityElementCo private final float yRot; private final Quaternionf rotation; private final Billboard billboard; + public final Color glowColor; + public final int blockLight; + public final int skyLight; + public final float viewRange; public TextDisplayBlockEntityElementConfig(String text, Vector3f scale, @@ -41,7 +45,11 @@ public class TextDisplayBlockEntityElementConfig implements BlockEntityElementCo float xRot, float yRot, Quaternionf rotation, - Billboard billboard) { + Billboard billboard, + @Nullable Color glowColor, + int blockLight, + int skyLight, + float viewRange) { this.text = text; this.scale = scale; this.position = position; @@ -50,13 +58,25 @@ public class TextDisplayBlockEntityElementConfig implements BlockEntityElementCo this.yRot = yRot; this.rotation = rotation; this.billboard = billboard; + this.glowColor = glowColor; + this.blockLight = blockLight; + this.skyLight = skyLight; + this.viewRange = viewRange; this.lazyMetadataPacket = player -> { List dataValues = new ArrayList<>(); + if (glowColor != null) { + ItemDisplayEntityData.SharedFlags.addEntityData((byte) 0x40, dataValues); + ItemDisplayEntityData.GlowColorOverride.addEntityData(glowColor.color(), dataValues); + } TextDisplayEntityData.Text.addEntityData(ComponentUtils.adventureToMinecraft(text(player)), dataValues); TextDisplayEntityData.Scale.addEntityData(this.scale, dataValues); TextDisplayEntityData.RotationLeft.addEntityData(this.rotation, dataValues); TextDisplayEntityData.BillboardConstraints.addEntityData(this.billboard.id(), dataValues); TextDisplayEntityData.Translation.addEntityData(this.translation, dataValues); + if (this.blockLight != -1 && this.skyLight != -1) { + ItemDisplayEntityData.BrightnessOverride.addEntityData(this.blockLight << 4 | this.skyLight << 20, dataValues); + } + ItemDisplayEntityData.ViewRange.addEntityData(this.viewRange, dataValues); return dataValues; }; } @@ -134,11 +154,17 @@ public class TextDisplayBlockEntityElementConfig implements BlockEntityElementCo Objects.equal(rotation, that.rotation); } + @Override + public int hashCode() { + return Objects.hashCode(xRot, yRot, position, translation, rotation); + } + public static class Factory implements BlockEntityElementConfigFactory { @Override public TextDisplayBlockEntityElementConfig create(Map arguments) { String text = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("text"), "warning.config.block.state.entity_renderer.text_display.missing_text"); + Map brightness = ResourceConfigUtils.getAsMap(arguments.getOrDefault("brightness", Map.of()), "brightness"); return new TextDisplayBlockEntityElementConfig( text, ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("scale", 1f), "scale"), @@ -147,7 +173,11 @@ public class TextDisplayBlockEntityElementConfig implements BlockEntityElementCo ResourceConfigUtils.getAsFloat(arguments.getOrDefault("pitch", 0f), "pitch"), ResourceConfigUtils.getAsFloat(arguments.getOrDefault("yaw", 0f), "yaw"), ResourceConfigUtils.getAsQuaternionf(arguments.getOrDefault("rotation", 0f), "rotation"), - Billboard.valueOf(arguments.getOrDefault("billboard", "fixed").toString().toUpperCase(Locale.ROOT)) + Billboard.valueOf(arguments.getOrDefault("billboard", "fixed").toString().toUpperCase(Locale.ROOT)), + Optional.ofNullable(arguments.get("glow-color")).map(it -> Color.fromStrings(it.toString().split(","))).orElse(null), + ResourceConfigUtils.getAsInt(brightness.getOrDefault("block-light", -1), "block-light"), + ResourceConfigUtils.getAsInt(brightness.getOrDefault("sky-light", -1), "sky-light"), + ResourceConfigUtils.getAsFloat(arguments.getOrDefault("view-range", 1f), "view-range") ); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurniture.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurniture.java index ab51b86ff..237f8de2a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurniture.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurniture.java @@ -9,6 +9,7 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityType import net.momirealms.craftengine.bukkit.util.LocationUtils; import net.momirealms.craftengine.core.entity.furniture.*; import net.momirealms.craftengine.core.entity.furniture.hitbox.FurnitureHitBoxConfig; +import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.QuaternionUtils; import net.momirealms.craftengine.core.world.WorldPosition; import net.momirealms.craftengine.core.world.collision.AABB; @@ -115,7 +116,7 @@ public class BukkitFurniture extends Furniture { BukkitFurnitureManager.instance().invalidateFurniture(this); super.clearColliders(); this.location = LocationUtils.toLocation(position); - Object removePacket = FastNMS.INSTANCE.constructor$ClientboundRemoveEntitiesPacket(new IntArrayList() {{ add(itemDisplay.getEntityId()); }}); + Object removePacket = FastNMS.INSTANCE.constructor$ClientboundRemoveEntitiesPacket(MiscUtils.init(new IntArrayList(), l -> l.add(itemDisplay.getEntityId()))); for (Player player : itemDisplay.getTrackedPlayers()) { BukkitAdaptors.adapt(player).sendPacket(removePacket, false); } @@ -142,7 +143,7 @@ public class BukkitFurniture extends Furniture { protected void refresh() { ItemDisplay itemDisplay = this.metaEntity.get(); if (itemDisplay == null) return; - Object removePacket = FastNMS.INSTANCE.constructor$ClientboundRemoveEntitiesPacket(new IntArrayList() {{ add(itemDisplay.getEntityId()); }}); + Object removePacket = FastNMS.INSTANCE.constructor$ClientboundRemoveEntitiesPacket(MiscUtils.init(new IntArrayList(), l -> l.add(itemDisplay.getEntityId()))); Object addPacket = FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(itemDisplay.getEntityId(), itemDisplay.getUniqueId(), itemDisplay.getX(), itemDisplay.getY(), itemDisplay.getZ(), itemDisplay.getPitch(), itemDisplay.getYaw(), MEntityTypes.ITEM_DISPLAY, 0, CoreReflections.instance$Vec3$Zero, 0); for (Player player : itemDisplay.getTrackedPlayers()) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/element/ItemDisplayFurnitureElement.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/element/ItemDisplayFurnitureElement.java index b63daf007..dd30f8c02 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/element/ItemDisplayFurnitureElement.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/element/ItemDisplayFurnitureElement.java @@ -43,7 +43,7 @@ public class ItemDisplayFurnitureElement implements FurnitureElement { this.position.x, this.position.y, this.position.z, 0, this.position.yRot, MEntityTypes.ITEM_DISPLAY, 0, CoreReflections.instance$Vec3$Zero, 0 ), - FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(this.entityId, this.config.metadata.apply(player, this.colorSource)) + FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(this.entityId, this.config.metadata().apply(player, this.colorSource)) )), false); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/element/ItemDisplayFurnitureElementConfig.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/element/ItemDisplayFurnitureElementConfig.java index 00ec59e3c..51addbc7b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/element/ItemDisplayFurnitureElementConfig.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/element/ItemDisplayFurnitureElementConfig.java @@ -31,23 +31,23 @@ import java.util.function.BiFunction; public class ItemDisplayFurnitureElementConfig implements FurnitureElementConfig { public static final Factory FACTORY = new Factory(); - public final BiFunction> metadata; - public final Key itemId; - public final Vector3f scale; - public final Vector3f position; - public final Vector3f translation; - public final float xRot; - public final float yRot; - public final Quaternionf rotation; - public final ItemDisplayContext displayContext; - public final Billboard billboard; - public final float shadowRadius; - public final float shadowStrength; - public final boolean applyDyedColor; - public final Color glowColor; - public final int blockLight; - public final int skyLight; - public final float viewRange; + private final BiFunction> metadata; + private final Key itemId; + private final Vector3f scale; + private final Vector3f position; + private final Vector3f translation; + private final float xRot; + private final float yRot; + private final Quaternionf rotation; + private final ItemDisplayContext displayContext; + private final Billboard billboard; + private final float shadowRadius; + private final float shadowStrength; + private final boolean applyDyedColor; + private final Color glowColor; + private final int blockLight; + private final int skyLight; + private final float viewRange; public ItemDisplayFurnitureElementConfig(Key itemId, Vector3f scale, @@ -161,6 +161,10 @@ public class ItemDisplayFurnitureElementConfig implements FurnitureElementConfig return this.applyDyedColor; } + public BiFunction> metadata() { + return this.metadata; + } + public Key itemId() { return this.itemId; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/CustomFurnitureHitbox.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/CustomFurnitureHitbox.java index 900909794..da193062f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/CustomFurnitureHitbox.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/CustomFurnitureHitbox.java @@ -10,6 +10,7 @@ import net.momirealms.craftengine.core.entity.furniture.Furniture; import net.momirealms.craftengine.core.entity.furniture.hitbox.FurnitureHitboxPart; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.WorldPosition; @@ -54,7 +55,7 @@ public class CustomFurnitureHitbox extends AbstractFurnitureHitBox { } this.spawnPacket = FastNMS.INSTANCE.constructor$ClientboundBundlePacket(packets); this.part = new FurnitureHitboxPart(entityId, aabb, pos, false); - this.despawnPacket = FastNMS.INSTANCE.constructor$ClientboundRemoveEntitiesPacket(new IntArrayList() {{ add(entityId); }}); + this.despawnPacket = FastNMS.INSTANCE.constructor$ClientboundRemoveEntitiesPacket(MiscUtils.init(new IntArrayList(), l -> l.add(entityId))); this.entityId = entityId; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/InteractionFurnitureHitbox.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/InteractionFurnitureHitbox.java index 4b4a34110..454b2eb59 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/InteractionFurnitureHitbox.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/InteractionFurnitureHitbox.java @@ -8,6 +8,7 @@ import net.momirealms.craftengine.core.entity.furniture.Collider; import net.momirealms.craftengine.core.entity.furniture.Furniture; import net.momirealms.craftengine.core.entity.furniture.hitbox.FurnitureHitboxPart; import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.WorldPosition; import net.momirealms.craftengine.core.world.collision.AABB; @@ -40,7 +41,7 @@ public class InteractionFurnitureHitbox extends AbstractFurnitureHitBox { FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(interactionId, config.cachedValues()) )); this.part = new FurnitureHitboxPart(interactionId, aabb, pos, config.responsive()); - this.despawnPacket = FastNMS.INSTANCE.constructor$ClientboundRemoveEntitiesPacket(new IntArrayList() {{ add(interactionId); }}); + this.despawnPacket = FastNMS.INSTANCE.constructor$ClientboundRemoveEntitiesPacket(MiscUtils.init(new IntArrayList(), l -> l.add(interactionId))); this.entityId = interactionId; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugGenerateInternalAssetsCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugGenerateInternalAssetsCommand.java index c92fcea03..70201e12f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugGenerateInternalAssetsCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugGenerateInternalAssetsCommand.java @@ -13,6 +13,7 @@ import org.incendo.cloud.parser.standard.StringParser; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; @@ -139,7 +140,7 @@ public class DebugGenerateInternalAssetsCommand extends BukkitCommandFeature callback) { try (InputStream inputStream = Files.newInputStream(folder.resolve("_list.json"))) { String s = prefix.isEmpty() ? "" : (prefix + "/"); - JsonObject listJson = JsonParser.parseReader(new InputStreamReader(inputStream)).getAsJsonObject(); + JsonObject listJson = JsonParser.parseReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).getAsJsonObject(); JsonArray fileList = listJson.getAsJsonArray("files"); for (JsonElement element : fileList) { if (element instanceof JsonPrimitive primitive) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockStateGenerator.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockStateGenerator.java index 2c2e4d036..bad247fea 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockStateGenerator.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockStateGenerator.java @@ -181,7 +181,7 @@ public final class BlockStateGenerator { if (state == null) return thisObj; Property waterloggedProperty = (Property) state.owner().value().getProperty("waterlogged"); if (waterloggedProperty == null) return thisObj; - return state.with(waterloggedProperty, (boolean) args[1]).customBlockState().literalObject(); + return state.with(waterloggedProperty, (Boolean) args[1]).customBlockState().literalObject(); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InteractUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InteractUtils.java index dc44ac1a9..ca2d08ad8 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InteractUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InteractUtils.java @@ -38,15 +38,13 @@ import org.bukkit.block.data.Directional; import org.bukkit.block.data.Levelled; import org.bukkit.block.data.Lightable; import org.bukkit.block.data.type.*; +import org.bukkit.block.data.type.Observer; import org.bukkit.entity.*; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Nullable; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; +import java.util.*; public final class InteractUtils { private static final Map, BlockData, BlockHitResult, Boolean>> INTERACTIONS = new HashMap<>(); @@ -806,7 +804,7 @@ public final class InteractUtils { if (entity instanceof Sheep sheep && sheep.readyToBeSheared() && ArrayUtils.contains(ItemKeys.DYES, item)) { DyeColor sheepColor = sheep.getColor(); if (sheepColor != null) { - String color = sheepColor.name().toLowerCase(); + String color = sheepColor.name().toLowerCase(Locale.ROOT); return !Key.of(color + "_dye").equals(id); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/parser/BlockStateParser.java b/core/src/main/java/net/momirealms/craftengine/core/block/parser/BlockStateParser.java index fd6cdd6dd..bc544e428 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/parser/BlockStateParser.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/parser/BlockStateParser.java @@ -10,10 +10,7 @@ import net.momirealms.craftengine.core.util.StringReader; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Collection; -import java.util.HashSet; -import java.util.Optional; -import java.util.Set; +import java.util.*; public final class BlockStateParser { private static final char START = '['; @@ -33,7 +30,7 @@ public final class BlockStateParser { private Property property; public BlockStateParser(String data, int cursor) { - this.reader = StringReader.simple(data.toLowerCase()); + this.reader = StringReader.simple(data.toLowerCase(Locale.ROOT)); this.reader.setCursor(cursor); this.cursor = cursor; this.replaceCursor = cursor; @@ -116,7 +113,7 @@ public final class BlockStateParser { suggestPropertyName(); return; } - if (used.contains(property.name().toLowerCase())) return; + if (used.contains(property.name().toLowerCase(Locale.ROOT))) return; used.add(input); reader.skipWhitespace(); @@ -159,7 +156,7 @@ public final class BlockStateParser { if (!reader.getRemaining().isEmpty()) return; String front = readPrefix(); for (Property p : properties) { - if (!used.contains(p.name().toLowerCase()) && p.name().toLowerCase().startsWith(input)) { + if (!used.contains(p.name().toLowerCase(Locale.ROOT)) && p.name().toLowerCase(Locale.ROOT).startsWith(input)) { this.suggestions.add(front + p.name() + EQUAL); } } @@ -172,7 +169,7 @@ public final class BlockStateParser { private void suggestValue() { for (Object val : property.possibleValues()) { - this.suggestions.add(readPrefix() + val.toString().toLowerCase()); + this.suggestions.add(readPrefix() + val.toString().toLowerCase(Locale.ROOT)); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java index 4508ceaa0..fc211d329 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java @@ -167,7 +167,7 @@ public abstract class AbstractPackManager implements PackManager { } this.initInternalData(); try (InputStream inputStream = plugin.resourceStream("internal/atlases/blocks.json")) { - this.vanillaAtlas = JsonParser.parseReader(new InputStreamReader(inputStream)).getAsJsonObject(); + this.vanillaAtlas = JsonParser.parseReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).getAsJsonObject(); } catch (IOException e) { throw new RuntimeException("Failed to read internal/atlases/blocks.json", e); } @@ -221,7 +221,7 @@ public abstract class AbstractPackManager implements PackManager { private void loadModernItemModel(String path, BiConsumer callback) { try (InputStream inputStream = this.plugin.resourceStream(path)) { if (inputStream != null) { - JsonObject allModelsItems = JsonParser.parseReader(new InputStreamReader(inputStream)).getAsJsonObject(); + JsonObject allModelsItems = JsonParser.parseReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).getAsJsonObject(); for (Map.Entry entry : allModelsItems.entrySet()) { if (entry.getValue() instanceof JsonObject modelJson) { callback.accept(Key.of(entry.getKey()), ModernItemModel.fromJson(modelJson)); @@ -236,7 +236,7 @@ public abstract class AbstractPackManager implements PackManager { private void loadInternalData(String path, BiConsumer callback) { try (InputStream inputStream = this.plugin.resourceStream(path)) { if (inputStream != null) { - JsonObject allModelsItems = JsonParser.parseReader(new InputStreamReader(inputStream)).getAsJsonObject(); + JsonObject allModelsItems = JsonParser.parseReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).getAsJsonObject(); for (Map.Entry entry : allModelsItems.entrySet()) { if (entry.getValue() instanceof JsonObject modelJson) { callback.accept(Key.of(entry.getKey()), modelJson); @@ -251,7 +251,7 @@ public abstract class AbstractPackManager implements PackManager { private void loadInternalList(String path, Consumer callback) { try (InputStream inputStream = this.plugin.resourceStream(path)) { if (inputStream != null) { - JsonArray listJson = JsonParser.parseReader(new InputStreamReader(inputStream)).getAsJsonArray(); + JsonArray listJson = JsonParser.parseReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).getAsJsonArray(); for (JsonElement element : listJson) { if (element instanceof JsonPrimitive primitiveJson) { callback.accept(Key.of("minecraft", primitiveJson.getAsString())); @@ -1777,7 +1777,7 @@ public abstract class AbstractPackManager implements PackManager { if (Files.exists(atlasPath) && Files.isRegularFile(atlasPath)) { try { previousAtlasSources = GsonHelper.readJsonFile(atlasPath).getAsJsonObject().getAsJsonArray("sources"); - } catch (Exception ignored) { + } catch (ClassCastException | IllegalStateException | IOException | JsonParseException ignored) { } } @@ -2241,7 +2241,7 @@ public abstract class AbstractPackManager implements PackManager { plugin.logger().warn("Failed to load internal/sounds.json"); return; } - soundTemplate = JsonParser.parseReader(new InputStreamReader(inputStream)).getAsJsonObject(); + soundTemplate = JsonParser.parseReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).getAsJsonObject(); } catch (IOException e) { plugin.logger().warn("Failed to load internal/sounds.json", e); return; diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/AlistHost.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/AlistHost.java index 8b36730a6..ecd57bc95 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/AlistHost.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/AlistHost.java @@ -82,7 +82,7 @@ public class AlistHost implements ResourcePackHost { if (!Files.exists(cachePath) || !Files.isRegularFile(cachePath)) return; try (InputStream is = Files.newInputStream(cachePath)) { Map cache = GsonHelper.get().fromJson( - new InputStreamReader(is), + new InputStreamReader(is, StandardCharsets.UTF_8), new TypeToken>(){}.getType() ); this.cachedSha1 = cache.get("sha1"); diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/DropboxHost.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/DropboxHost.java index 98b65751b..ccafa796a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/DropboxHost.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/DropboxHost.java @@ -219,7 +219,7 @@ public class DropboxHost implements ResourcePackHost { } String credentials = this.appKey + ":" + this.appSecret; - String authHeader = "Basic " + Base64.getEncoder().encodeToString(credentials.getBytes()); + String authHeader = "Basic " + Base64.getEncoder().encodeToString(credentials.getBytes(StandardCharsets.UTF_8)); try (HttpClient client = HttpClient.newBuilder().proxy(this.proxy).build()) { HttpRequest request = HttpRequest.newBuilder() diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/ExternalHost.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/ExternalHost.java index dec6095cd..9d59c88ac 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/ExternalHost.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/ExternalHost.java @@ -7,6 +7,7 @@ import net.momirealms.craftengine.core.pack.host.ResourcePackHosts; import net.momirealms.craftengine.core.plugin.locale.LocalizedException; import net.momirealms.craftengine.core.util.Key; +import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.util.List; import java.util.Map; @@ -52,7 +53,7 @@ public class ExternalHost implements ResourcePackHost { } String uuid = Optional.ofNullable(arguments.get("uuid")).map(String::valueOf).orElse(null); if (uuid == null || uuid.isEmpty()) { - uuid = UUID.nameUUIDFromBytes(url.getBytes()).toString(); + uuid = UUID.nameUUIDFromBytes(url.getBytes(StandardCharsets.UTF_8)).toString(); } UUID hostUUID = UUID.fromString(uuid); String sha1 = arguments.getOrDefault("sha1", "").toString(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/GitLabHost.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/GitLabHost.java index d2e4fd58b..4f8211779 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/GitLabHost.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/GitLabHost.java @@ -50,7 +50,7 @@ public class GitLabHost implements ResourcePackHost { if (!Files.exists(cachePath) || !Files.isRegularFile(cachePath)) return; try (InputStream is = Files.newInputStream(cachePath)) { Map cache = GsonHelper.get().fromJson( - new InputStreamReader(is), + new InputStreamReader(is, StandardCharsets.UTF_8), new TypeToken>(){}.getType() ); this.url = cache.get("url"); @@ -155,13 +155,13 @@ public class GitLabHost implements ResourcePackHost { String filePartHeader = "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"file\"; filename=\"" + filePath.getFileName() + "\"\r\n" + "Content-Type: application/octet-stream\r\n\r\n"; - parts.add(filePartHeader.getBytes()); + parts.add(filePartHeader.getBytes(StandardCharsets.UTF_8)); parts.add(Files.readAllBytes(filePath)); - parts.add("\r\n".getBytes()); + parts.add("\r\n".getBytes(StandardCharsets.UTF_8)); String endBoundary = "--" + boundary + "--\r\n"; - parts.add(endBoundary.getBytes()); + parts.add(endBoundary.getBytes(StandardCharsets.UTF_8)); return HttpRequest.BodyPublishers.ofByteArrays(parts); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/LobFileHost.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/LobFileHost.java index 89db7002d..88d3d6c36 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/LobFileHost.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/LobFileHost.java @@ -22,6 +22,7 @@ import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; @@ -62,7 +63,7 @@ public class LobFileHost implements ResourcePackHost { if (!Files.exists(cachePath) || !Files.isRegularFile(cachePath)) return; try (InputStream is = Files.newInputStream(cachePath)) { Map cache = GsonHelper.get().fromJson( - new InputStreamReader(is), + new InputStreamReader(is, StandardCharsets.UTF_8), new TypeToken>(){}.getType() ); this.url = cache.get("url"); @@ -191,8 +192,8 @@ public class LobFileHost implements ResourcePackHost { MessageDigest sha256Digest = MessageDigest.getInstance("SHA-256"); try (InputStream is = Files.newInputStream(path); - DigestInputStream dis = new DigestInputStream(is, sha1Digest)) { - DigestInputStream dis2 = new DigestInputStream(dis, sha256Digest); + DigestInputStream dis = new DigestInputStream(is, sha1Digest); + DigestInputStream dis2 = new DigestInputStream(dis, sha256Digest)) { while (dis2.read() != -1) ; @@ -207,18 +208,18 @@ public class LobFileHost implements ResourcePackHost { String filePartHeader = "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"file\"; filename=\"" + filePath.getFileName() + "\"\r\n" + "Content-Type: application/octet-stream\r\n\r\n"; - parts.add(filePartHeader.getBytes()); + parts.add(filePartHeader.getBytes(StandardCharsets.UTF_8)); parts.add(Files.readAllBytes(filePath)); - parts.add("\r\n".getBytes()); + parts.add("\r\n".getBytes(StandardCharsets.UTF_8)); String sha256Part = "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"sha_256\"\r\n\r\n" + sha256Hash + "\r\n"; - parts.add(sha256Part.getBytes()); + parts.add(sha256Part.getBytes(StandardCharsets.UTF_8)); String endBoundary = "--" + boundary + "--\r\n"; - parts.add(endBoundary.getBytes()); + parts.add(endBoundary.getBytes(StandardCharsets.UTF_8)); return HttpRequest.BodyPublishers.ofByteArrays(parts); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/OneDriveHost.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/OneDriveHost.java index 3fb95aa92..2665818ac 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/OneDriveHost.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/OneDriveHost.java @@ -10,6 +10,7 @@ import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.locale.LocalizedException; import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.util.*; +import org.jetbrains.annotations.NotNull; import java.io.FileNotFoundException; import java.io.IOException; @@ -34,7 +35,7 @@ public class OneDriveHost implements ResourcePackHost { private final String clientSecret; private final ProxySelector proxy; private final String uploadPath; - private Tuple refreshToken; + private Tuple<@NotNull String, @NotNull String, @NotNull Date> refreshToken; private String sha1; private String fileId; @@ -66,13 +67,13 @@ public class OneDriveHost implements ResourcePackHost { if (!Files.exists(cachePath) || !Files.isRegularFile(cachePath)) return; try (InputStream is = Files.newInputStream(cachePath)) { Map cache = GsonHelper.get().fromJson( - new InputStreamReader(is), + new InputStreamReader(is, StandardCharsets.UTF_8), new TypeToken>(){}.getType() ); this.refreshToken = Tuple.of( - cache.get("refresh-token"), - cache.get("access-token"), + Objects.requireNonNull(cache.get("refresh-token")), + Objects.requireNonNull(cache.get("access-token")), new Date(Long.parseLong(cache.get("refresh-token-expires-in")))); this.sha1 = cache.get("sha1"); this.fileId = cache.get("file-id"); @@ -188,7 +189,7 @@ public class OneDriveHost implements ResourcePackHost { if (this.refreshToken == null || this.refreshToken.mid().isEmpty() || this.refreshToken.right().before(new Date())) { try (HttpClient client = HttpClient.newBuilder().proxy(this.proxy).build()) { String formData = "client_id=" + URLEncoder.encode(this.clientId, StandardCharsets.UTF_8) + - "&client_secret=" + URLEncoder.encode(this.clientSecret, StandardCharsets.UTF_8) + + "&client_secret=" + URLEncoder.encode(Objects.requireNonNull(this.clientSecret), StandardCharsets.UTF_8) + "&refresh_token=" + URLEncoder.encode(this.refreshToken.left(), StandardCharsets.UTF_8) + "&grant_type=refresh_token" + "&scope=Files.ReadWrite.All+offline_access"; diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java index 29563b49c..925a9dcdf 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java @@ -42,8 +42,8 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; -public class SelfHostHttpServer { - private static SelfHostHttpServer instance; +public final class SelfHostHttpServer { + private static volatile SelfHostHttpServer instance; private final Cache oneTimePackUrls = Caffeine.newBuilder() .maximumSize(1024) .scheduler(Scheduler.systemScheduler()) @@ -86,9 +86,19 @@ public class SelfHostHttpServer { private EventLoopGroup workerGroup; private Channel serverChannel; + private SelfHostHttpServer() { + if (instance != null) { + throw new IllegalStateException("SelfHostHttpServer is already initialized."); + } + } + public static SelfHostHttpServer instance() { if (instance == null) { - instance = new SelfHostHttpServer(); + synchronized (SelfHostHttpServer.class) { + if (instance == null) { + instance = new SelfHostHttpServer(); + } + } } return instance; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/special/ShulkerBoxSpecialModel.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/special/ShulkerBoxSpecialModel.java index 7df3f9449..20e67ca70 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/special/ShulkerBoxSpecialModel.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/special/ShulkerBoxSpecialModel.java @@ -54,7 +54,7 @@ public class ShulkerBoxSpecialModel implements SpecialModel { public SpecialModel create(Map arguments) { float openness = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("openness", 0), "openness"); String texture = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("texture"), "warning.config.item.model.special.shulker_box.missing_texture"); - Direction orientation = Optional.ofNullable(arguments.get("orientation")).map(String::valueOf).map(String::toUpperCase).map(Direction::valueOf).orElse(null); + Direction orientation = Optional.ofNullable(arguments.get("orientation")).map(String::valueOf).map(s -> s.toUpperCase(Locale.ROOT)).map(Direction::valueOf).orElse(null); if (openness > 1 || openness < 0) { throw new LocalizedResourceConfigException("warning.config.item.model.special.shulker_box.invalid_openness", String.valueOf(openness)); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/obfuscation/ObfB.java b/core/src/main/java/net/momirealms/craftengine/core/pack/obfuscation/ObfB.java index eb1fc463e..19e5ba0f3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/obfuscation/ObfB.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/obfuscation/ObfB.java @@ -6,6 +6,7 @@ import org.jetbrains.annotations.Nullable; import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; +import java.util.Locale; import java.util.Objects; import java.util.concurrent.ThreadLocalRandom; @@ -81,7 +82,7 @@ public final class ObfB { } private static String 雷雷宝宝打肚肚(String input) { - return input.replace('\\', '/').toLowerCase(); + return input.replace('\\', '/').toLowerCase(Locale.ROOT); } private static String[] 因为都叫你小学生(String path) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/compatibility/CompatibilityManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/compatibility/CompatibilityManager.java index 0c0c82726..1a89da040 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/compatibility/CompatibilityManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/compatibility/CompatibilityManager.java @@ -42,4 +42,6 @@ public interface CompatibilityManager { void executeMMSkill(String skill, float power, Player player); TagResolver[] createExternalTagResolvers(Context context); + + boolean isBedrockPlayer(Player player); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/entityculling/EntityCullingThread.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/entityculling/EntityCullingThread.java index 5586bc51d..f0d52c08c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/entityculling/EntityCullingThread.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/entityculling/EntityCullingThread.java @@ -40,8 +40,8 @@ public class EntityCullingThread { long startTime = System.nanoTime(); for (Player player : CraftEngine.instance().networkManager().onlineUsers()) { - // 使用绝对值确保非负,使用 threads 而不是 threads-1 确保均匀分布 - if (Math.abs(player.uuid().hashCode()) % this.threads == this.id) { + // 使用位运算确保非负,使用 threads 而不是 threads-1 确保均匀分布 + if ((player.uuid().hashCode() & 0x7FFFFFFF) % this.threads == this.id) { player.entityCullingTick(); processed++; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/MarkedArrayList.java b/core/src/main/java/net/momirealms/craftengine/core/util/MarkedArrayList.java index 1d1e57d24..fa1a87226 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/MarkedArrayList.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/MarkedArrayList.java @@ -2,10 +2,13 @@ package net.momirealms.craftengine.core.util; import org.jetbrains.annotations.NotNull; +import java.io.Serial; import java.util.ArrayList; import java.util.Collection; public class MarkedArrayList extends ArrayList { + @Serial + private static final long serialVersionUID = 1L; public MarkedArrayList() { } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/MarkedHashMap.java b/core/src/main/java/net/momirealms/craftengine/core/util/MarkedHashMap.java index 5acda9dda..29128754e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/MarkedHashMap.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/MarkedHashMap.java @@ -1,6 +1,9 @@ package net.momirealms.craftengine.core.util; +import java.io.Serial; import java.util.HashMap; public class MarkedHashMap extends HashMap { + @Serial + private static final long serialVersionUID = 1L; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/SkullUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/SkullUtils.java index a74d6273f..e1d753c86 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/SkullUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/SkullUtils.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.core.util; +import java.nio.charset.StandardCharsets; import java.util.Base64; public final class SkullUtils { @@ -8,7 +9,7 @@ public final class SkullUtils { public static String identifierFromBase64(String base64) { byte[] decodedBytes = Base64.getDecoder().decode(base64); - String decodedString = new String(decodedBytes); + String decodedString = new String(decodedBytes, StandardCharsets.UTF_8); int urlStartIndex = decodedString.indexOf("\"url\":\"") + 7; int urlEndIndex = decodedString.indexOf("\"", urlStartIndex); String textureUrl = decodedString.substring(urlStartIndex, urlEndIndex);