9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-19 15:09:15 +00:00

添加基岩版判断

This commit is contained in:
jhqwqmc
2025-12-06 19:03:07 +08:00
parent aab16be43c
commit e2170f54ba
36 changed files with 241 additions and 83 deletions

View File

@@ -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 {

View File

@@ -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<String, TagResolverProvider> 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;
}
}

View File

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

View File

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

View File

@@ -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<ItemStack> {
@@ -25,7 +27,7 @@ public class MMOItemsSource implements ExternalItemSource<ItemStack> {
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());
}

View File

@@ -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()

View File

@@ -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 }

View File

@@ -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);

View File

@@ -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<String, BiConsumer<BukkitBlockBehavior, Property<?>>> HARD_CODED_PROPERTY_DATA = new HashMap<>();
private static final Map<String, BiConsumer<@NotNull BukkitBlockBehavior, Property<?>>> HARD_CODED_PROPERTY_DATA = new HashMap<>();
static {
HARD_CODED_PROPERTY_DATA.put("axis", (behavior, property) -> {
@SuppressWarnings("unchecked")

View File

@@ -75,6 +75,11 @@ public class ItemBlockEntityElementConfig implements BlockEntityElementConfig<It
return this.position.equals(that.position);
}
@Override
public int hashCode() {
return this.position.hashCode();
}
public static class Factory implements BlockEntityElementConfigFactory<ItemBlockEntityElement> {
@Override

View File

@@ -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<ItemDisplayBlockEntityElement> {
@@ -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<Player, Item<?>> 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<Object> 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<ItemDisplayBlockEntityElement> {
@Override
public ItemDisplayBlockEntityElementConfig create(Map<String, Object> arguments) {
Key itemId = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("item"), "warning.config.block.state.entity_renderer.item_display.missing_item"));
Map<String, Object> 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")
);
}
}

View File

@@ -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<TextDisplayBlockEntityElement> {
@@ -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<Object> 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<TextDisplayBlockEntityElement> {
@Override
public TextDisplayBlockEntityElementConfig create(Map<String, Object> arguments) {
String text = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("text"), "warning.config.block.state.entity_renderer.text_display.missing_text");
Map<String, Object> 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")
);
}
}

View File

@@ -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()) {

View File

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

View File

@@ -31,23 +31,23 @@ import java.util.function.BiFunction;
public class ItemDisplayFurnitureElementConfig implements FurnitureElementConfig<ItemDisplayFurnitureElement> {
public static final Factory FACTORY = new Factory();
public final BiFunction<Player, FurnitureColorSource, List<Object>> 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<Player, FurnitureColorSource, List<Object>> 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<Player, FurnitureColorSource, List<Object>> metadata() {
return this.metadata;
}
public Key itemId() {
return this.itemId;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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<Com
private void collectListJson(Path folder, String prefix, Consumer<String> 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) {

View File

@@ -181,7 +181,7 @@ public final class BlockStateGenerator {
if (state == null) return thisObj;
Property<Boolean> waterloggedProperty = (Property<Boolean>) 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();
}
}

View File

@@ -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<Key, QuadFunction<Player, Item<ItemStack>, 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);
}
}

View File

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

View File

@@ -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<Key, ModernItemModel> 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<String, JsonElement> 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<Key, JsonObject> 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<String, JsonElement> 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<Key> 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;

View File

@@ -82,7 +82,7 @@ public class AlistHost implements ResourcePackHost {
if (!Files.exists(cachePath) || !Files.isRegularFile(cachePath)) return;
try (InputStream is = Files.newInputStream(cachePath)) {
Map<String, String> cache = GsonHelper.get().fromJson(
new InputStreamReader(is),
new InputStreamReader(is, StandardCharsets.UTF_8),
new TypeToken<Map<String, String>>(){}.getType()
);
this.cachedSha1 = cache.get("sha1");

View File

@@ -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()

View File

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

View File

@@ -50,7 +50,7 @@ public class GitLabHost implements ResourcePackHost {
if (!Files.exists(cachePath) || !Files.isRegularFile(cachePath)) return;
try (InputStream is = Files.newInputStream(cachePath)) {
Map<String, String> cache = GsonHelper.get().fromJson(
new InputStreamReader(is),
new InputStreamReader(is, StandardCharsets.UTF_8),
new TypeToken<Map<String, String>>(){}.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);
}

View File

@@ -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<String, String> cache = GsonHelper.get().fromJson(
new InputStreamReader(is),
new InputStreamReader(is, StandardCharsets.UTF_8),
new TypeToken<Map<String, String>>(){}.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);
}

View File

@@ -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<String, String, Date> 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<String, String> cache = GsonHelper.get().fromJson(
new InputStreamReader(is),
new InputStreamReader(is, StandardCharsets.UTF_8),
new TypeToken<Map<String, String>>(){}.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";

View File

@@ -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<String, String> oneTimePackUrls = Caffeine.newBuilder()
.maximumSize(1024)
.scheduler(Scheduler.systemScheduler())
@@ -86,10 +86,20 @@ 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) {
synchronized (SelfHostHttpServer.class) {
if (instance == null) {
instance = new SelfHostHttpServer();
}
}
}
return instance;
}

View File

@@ -54,7 +54,7 @@ public class ShulkerBoxSpecialModel implements SpecialModel {
public SpecialModel create(Map<String, Object> 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));
}

View File

@@ -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) {

View File

@@ -42,4 +42,6 @@ public interface CompatibilityManager {
void executeMMSkill(String skill, float power, Player player);
TagResolver[] createExternalTagResolvers(Context context);
boolean isBedrockPlayer(Player player);
}

View File

@@ -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++;
}

View File

@@ -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<T> extends ArrayList<T> {
@Serial
private static final long serialVersionUID = 1L;
public MarkedArrayList() {
}

View File

@@ -1,6 +1,9 @@
package net.momirealms.craftengine.core.util;
import java.io.Serial;
import java.util.HashMap;
public class MarkedHashMap<K, V> extends HashMap<K, V> {
@Serial
private static final long serialVersionUID = 1L;
}

View File

@@ -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);