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

Merge pull request #493 from jhqwqmc/dev

添加基岩版判断
This commit is contained in:
XiaoMoMi
2025-12-06 19:43:31 +08:00
committed by GitHub
32 changed files with 224 additions and 62 deletions

View File

@@ -18,6 +18,7 @@ repositories {
maven("https://jitpack.io") // sxitem slimefun maven("https://jitpack.io") // sxitem slimefun
maven("https://repo.codemc.io/repository/maven-public/") // quickshop maven("https://repo.codemc.io/repository/maven-public/") // quickshop
maven("https://repo.nexomc.com/releases/") // nexo maven("https://repo.nexomc.com/releases/") // nexo
maven("https://repo.opencollab.dev/main/") // geyser
} }
dependencies { dependencies {
@@ -88,6 +89,10 @@ dependencies {
compileOnly("io.github.Slimefun:Slimefun4:RC-32") compileOnly("io.github.Slimefun:Slimefun4:RC-32")
// QuickShop // QuickShop
compileOnly("com.ghostchu:quickshop-api:6.2.0.10") 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 { java {

View File

@@ -3,6 +3,8 @@ package net.momirealms.craftengine.bukkit.compatibility;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
import net.momirealms.craftengine.bukkit.block.entity.renderer.element.BukkitBlockEntityElementConfigs; 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.item.*;
import net.momirealms.craftengine.bukkit.compatibility.legacy.slimeworld.LegacySlimeFormatStorageAdaptor; import net.momirealms.craftengine.bukkit.compatibility.legacy.slimeworld.LegacySlimeFormatStorageAdaptor;
import net.momirealms.craftengine.bukkit.compatibility.leveler.*; import net.momirealms.craftengine.bukkit.compatibility.leveler.*;
@@ -55,6 +57,8 @@ public class BukkitCompatibilityManager implements CompatibilityManager {
private final Map<String, TagResolverProvider> tagResolverProviders; private final Map<String, TagResolverProvider> tagResolverProviders;
private TagResolverProvider[] tagResolverProviderArray = null; private TagResolverProvider[] tagResolverProviderArray = null;
private boolean hasPlaceholderAPI; private boolean hasPlaceholderAPI;
private boolean hasGeyser;
private boolean hasFloodgate;
public BukkitCompatibilityManager(BukkitCraftEngine plugin) { public BukkitCompatibilityManager(BukkitCraftEngine plugin) {
this.plugin = plugin; this.plugin = plugin;
@@ -110,6 +114,12 @@ public class BukkitCompatibilityManager implements CompatibilityManager {
EventConditions.register(worldGuardRegion, new AlwaysFalseCondition.FactoryImpl<>()); EventConditions.register(worldGuardRegion, new AlwaysFalseCondition.FactoryImpl<>());
LootConditions.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 @Override
@@ -368,4 +378,16 @@ public class BukkitCompatibilityManager implements CompatibilityManager {
} }
return resolvers; 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.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.Locale;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
public class MMOItemsSource implements ExternalItemSource<ItemStack> { public class MMOItemsSource implements ExternalItemSource<ItemStack> {
@@ -25,7 +27,9 @@ public class MMOItemsSource implements ExternalItemSource<ItemStack> {
split = split[0].split("_", 2); split = split[0].split("_", 2);
} }
if (split.length == 1) return new ItemStack(Material.AIR); if (split.length == 1) return new ItemStack(Material.AIR);
MMOItem mmoItem = MMOItems.plugin.getMMOItem(Type.get(split[0]), split[1].toUpperCase()); // 这里与使用和mmoitems相同的转换id方法
String mmoItemId = split[1].toUpperCase().replace("-", "_").replace(" ", "_");
MMOItem mmoItem = MMOItems.plugin.getMMOItem(Type.get(split[0]), mmoItemId);
return mmoItem == null ? new ItemStack(Material.AIR) : requireNonNull(mmoItem.newBuilder().build()); 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 org.bukkit.Material;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.Locale;
import java.util.Set; import java.util.Set;
import java.util.stream.Stream; import java.util.stream.Stream;
@@ -63,7 +64,7 @@ public class WorldEditBlockRegister {
} }
if (!input.contains(":")) { if (!input.contains(":")) {
String lowerSearch = input.toLowerCase(); String lowerSearch = input.toLowerCase(Locale.ROOT);
return Stream.concat( return Stream.concat(
namespacesInUse.stream().filter(n -> n.startsWith(lowerSearch)).map(n -> n + ":"), namespacesInUse.stream().filter(n -> n.startsWith(lowerSearch)).map(n -> n + ":"),
BlockStateParser.fillSuggestions(input).stream() BlockStateParser.fillSuggestions(input).stream()

View File

@@ -77,6 +77,10 @@ paper {
register("ViaVersion") { required = false } register("ViaVersion") { required = false }
register("QuickShop-Hikari") { required = false } register("QuickShop-Hikari") { required = false }
// Geyser
register("Geyser-Spigot") { required = false }
register("floodgate") { required = false }
// AdvancedSlimePaper // AdvancedSlimePaper
register("SlimeWorldPlugin") { required = false } register("SlimeWorldPlugin") { required = false }
register("SlimeWorldManager") { 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.config.IdSectionConfigParser;
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.MiscUtils;
import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.util.VersionHelper;
import java.nio.file.Path; 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, true) :
NetworkReflections.constructor$ClientboundUpdateAdvancementsPacket.newInstance(false, Arrays.asList(advancement), new HashSet<>(), advancementsToGrant); NetworkReflections.constructor$ClientboundUpdateAdvancementsPacket.newInstance(false, Arrays.asList(advancement), new HashSet<>(), advancementsToGrant);
Object removePacket = VersionHelper.isOrAbove1_21_5() ? 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<>(), MiscUtils.init(new HashSet<>(), s -> s.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<>());
player.sendPackets(List.of(grantPacket, removePacket), false); player.sendPackets(List.of(grantPacket, removePacket), false);
} catch (ReflectiveOperationException e) { } catch (ReflectiveOperationException e) {
this.plugin.logger().warn("Failed to send toast for player " + player.name(), 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.behavior.AbstractBlockBehavior;
import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.block.properties.Property;
import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.util.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.HashMap; import java.util.HashMap;
@@ -22,7 +23,7 @@ import java.util.concurrent.Callable;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
public class BukkitBlockBehavior extends AbstractBlockBehavior { 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 { static {
HARD_CODED_PROPERTY_DATA.put("axis", (behavior, property) -> { HARD_CODED_PROPERTY_DATA.put("axis", (behavior, property) -> {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")

View File

@@ -75,6 +75,11 @@ public class ItemBlockEntityElementConfig implements BlockEntityElementConfig<It
return this.position.equals(that.position); return this.position.equals(that.position);
} }
@Override
public int hashCode() {
return this.position.hashCode();
}
public static class Factory implements BlockEntityElementConfigFactory<ItemBlockEntityElement> { public static class Factory implements BlockEntityElementConfigFactory<ItemBlockEntityElement> {
@Override @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.display.ItemDisplayContext;
import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.item.Item; 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.Key;
import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.BlockPos;
import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.core.world.World;
import org.jetbrains.annotations.Nullable;
import org.joml.Quaternionf; import org.joml.Quaternionf;
import org.joml.Vector3f; import org.joml.Vector3f;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.function.Function; import java.util.function.Function;
public class ItemDisplayBlockEntityElementConfig implements BlockEntityElementConfig<ItemDisplayBlockEntityElement> { public class ItemDisplayBlockEntityElementConfig implements BlockEntityElementConfig<ItemDisplayBlockEntityElement> {
@@ -35,6 +38,10 @@ public class ItemDisplayBlockEntityElementConfig implements BlockEntityElementCo
private final Billboard billboard; private final Billboard billboard;
private final float shadowRadius; private final float shadowRadius;
private final float shadowStrength; 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, public ItemDisplayBlockEntityElementConfig(Function<Player, Item<?>> item,
Vector3f scale, Vector3f scale,
@@ -46,7 +53,11 @@ public class ItemDisplayBlockEntityElementConfig implements BlockEntityElementCo
ItemDisplayContext displayContext, ItemDisplayContext displayContext,
Billboard billboard, Billboard billboard,
float shadowRadius, float shadowRadius,
float shadowStrength) { float shadowStrength,
@Nullable Color glowColor,
int blockLight,
int skyLight,
float viewRange) {
this.item = item; this.item = item;
this.scale = scale; this.scale = scale;
this.position = position; this.position = position;
@@ -58,8 +69,16 @@ public class ItemDisplayBlockEntityElementConfig implements BlockEntityElementCo
this.billboard = billboard; this.billboard = billboard;
this.shadowRadius = shadowRadius; this.shadowRadius = shadowRadius;
this.shadowStrength = shadowStrength; this.shadowStrength = shadowStrength;
this.glowColor = glowColor;
this.blockLight = blockLight;
this.skyLight = skyLight;
this.viewRange = viewRange;
this.lazyMetadataPacket = player -> { this.lazyMetadataPacket = player -> {
List<Object> dataValues = new ArrayList<>(); 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.DisplayedItem.addEntityData(item.apply(player).getLiteralObject(), dataValues);
ItemDisplayEntityData.Scale.addEntityData(this.scale, dataValues); ItemDisplayEntityData.Scale.addEntityData(this.scale, dataValues);
ItemDisplayEntityData.RotationLeft.addEntityData(this.rotation, dataValues); ItemDisplayEntityData.RotationLeft.addEntityData(this.rotation, dataValues);
@@ -68,6 +87,10 @@ public class ItemDisplayBlockEntityElementConfig implements BlockEntityElementCo
ItemDisplayEntityData.DisplayType.addEntityData(this.displayContext.id(), dataValues); ItemDisplayEntityData.DisplayType.addEntityData(this.displayContext.id(), dataValues);
ItemDisplayEntityData.ShadowRadius.addEntityData(this.shadowRadius, dataValues); ItemDisplayEntityData.ShadowRadius.addEntityData(this.shadowRadius, dataValues);
ItemDisplayEntityData.ShadowStrength.addEntityData(this.shadowStrength, 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; return dataValues;
}; };
} }
@@ -157,11 +180,23 @@ public class ItemDisplayBlockEntityElementConfig implements BlockEntityElementCo
Objects.equal(rotation, that.rotation); Objects.equal(rotation, that.rotation);
} }
@Override
public int hashCode() {
int result = 17;
result = 31 * result + Double.hashCode(xRot);
result = 31 * result + Double.hashCode(yRot);
result = 31 * result + (position != null ? position.hashCode() : 0);
result = 31 * result + (translation != null ? translation.hashCode() : 0);
result = 31 * result + (rotation != null ? rotation.hashCode() : 0);
return result;
}
public static class Factory implements BlockEntityElementConfigFactory<ItemDisplayBlockEntityElement> { public static class Factory implements BlockEntityElementConfigFactory<ItemDisplayBlockEntityElement> {
@Override @Override
public ItemDisplayBlockEntityElementConfig create(Map<String, Object> arguments) { 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")); 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( return new ItemDisplayBlockEntityElementConfig(
player -> BukkitItemManager.instance().createWrappedItem(itemId, player), player -> BukkitItemManager.instance().createWrappedItem(itemId, player),
ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("scale", 1f), "scale"), ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("scale", 1f), "scale"),
@@ -173,7 +208,11 @@ public class ItemDisplayBlockEntityElementConfig implements BlockEntityElementCo
ResourceConfigUtils.getAsEnum(ResourceConfigUtils.get(arguments, "display-context", "display-transform"), ItemDisplayContext.class, ItemDisplayContext.NONE), ResourceConfigUtils.getAsEnum(ResourceConfigUtils.get(arguments, "display-context", "display-transform"), ItemDisplayContext.class, ItemDisplayContext.NONE),
ResourceConfigUtils.getAsEnum(arguments.get("billboard"), Billboard.class, Billboard.FIXED), ResourceConfigUtils.getAsEnum(arguments.get("billboard"), Billboard.class, Billboard.FIXED),
ResourceConfigUtils.getAsFloat(arguments.getOrDefault("shadow-radius", 0f), "shadow-radius"), 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 com.google.common.base.Objects;
import net.kyori.adventure.text.Component; 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.entity.data.TextDisplayEntityData;
import net.momirealms.craftengine.bukkit.util.ComponentUtils; import net.momirealms.craftengine.bukkit.util.ComponentUtils;
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfig; 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.entity.player.Player;
import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext;
import net.momirealms.craftengine.core.util.AdventureHelper; 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.util.ResourceConfigUtils;
import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.BlockPos;
import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.core.world.World;
import org.jetbrains.annotations.Nullable;
import org.joml.Quaternionf; import org.joml.Quaternionf;
import org.joml.Vector3f; import org.joml.Vector3f;
import java.util.ArrayList; import java.util.*;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.function.Function; import java.util.function.Function;
public class TextDisplayBlockEntityElementConfig implements BlockEntityElementConfig<TextDisplayBlockEntityElement> { public class TextDisplayBlockEntityElementConfig implements BlockEntityElementConfig<TextDisplayBlockEntityElement> {
@@ -33,6 +33,10 @@ public class TextDisplayBlockEntityElementConfig implements BlockEntityElementCo
private final float yRot; private final float yRot;
private final Quaternionf rotation; private final Quaternionf rotation;
private final Billboard billboard; private final Billboard billboard;
public final Color glowColor;
public final int blockLight;
public final int skyLight;
public final float viewRange;
public TextDisplayBlockEntityElementConfig(String text, public TextDisplayBlockEntityElementConfig(String text,
Vector3f scale, Vector3f scale,
@@ -41,7 +45,11 @@ public class TextDisplayBlockEntityElementConfig implements BlockEntityElementCo
float xRot, float xRot,
float yRot, float yRot,
Quaternionf rotation, Quaternionf rotation,
Billboard billboard) { Billboard billboard,
@Nullable Color glowColor,
int blockLight,
int skyLight,
float viewRange) {
this.text = text; this.text = text;
this.scale = scale; this.scale = scale;
this.position = position; this.position = position;
@@ -50,13 +58,25 @@ public class TextDisplayBlockEntityElementConfig implements BlockEntityElementCo
this.yRot = yRot; this.yRot = yRot;
this.rotation = rotation; this.rotation = rotation;
this.billboard = billboard; this.billboard = billboard;
this.glowColor = glowColor;
this.blockLight = blockLight;
this.skyLight = skyLight;
this.viewRange = viewRange;
this.lazyMetadataPacket = player -> { this.lazyMetadataPacket = player -> {
List<Object> dataValues = new ArrayList<>(); 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.Text.addEntityData(ComponentUtils.adventureToMinecraft(text(player)), dataValues);
TextDisplayEntityData.Scale.addEntityData(this.scale, dataValues); TextDisplayEntityData.Scale.addEntityData(this.scale, dataValues);
TextDisplayEntityData.RotationLeft.addEntityData(this.rotation, dataValues); TextDisplayEntityData.RotationLeft.addEntityData(this.rotation, dataValues);
TextDisplayEntityData.BillboardConstraints.addEntityData(this.billboard.id(), dataValues); TextDisplayEntityData.BillboardConstraints.addEntityData(this.billboard.id(), dataValues);
TextDisplayEntityData.Translation.addEntityData(this.translation, 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; return dataValues;
}; };
} }
@@ -134,11 +154,23 @@ public class TextDisplayBlockEntityElementConfig implements BlockEntityElementCo
Objects.equal(rotation, that.rotation); Objects.equal(rotation, that.rotation);
} }
@Override
public int hashCode() {
int result = 17;
result = 31 * result + Double.hashCode(xRot);
result = 31 * result + Double.hashCode(yRot);
result = 31 * result + (position != null ? position.hashCode() : 0);
result = 31 * result + (translation != null ? translation.hashCode() : 0);
result = 31 * result + (rotation != null ? rotation.hashCode() : 0);
return result;
}
public static class Factory implements BlockEntityElementConfigFactory<TextDisplayBlockEntityElement> { public static class Factory implements BlockEntityElementConfigFactory<TextDisplayBlockEntityElement> {
@Override @Override
public TextDisplayBlockEntityElementConfig create(Map<String, Object> arguments) { public TextDisplayBlockEntityElementConfig create(Map<String, Object> arguments) {
String text = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("text"), "warning.config.block.state.entity_renderer.text_display.missing_text"); 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( return new TextDisplayBlockEntityElementConfig(
text, text,
ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("scale", 1f), "scale"), ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("scale", 1f), "scale"),
@@ -147,7 +179,11 @@ public class TextDisplayBlockEntityElementConfig implements BlockEntityElementCo
ResourceConfigUtils.getAsFloat(arguments.getOrDefault("pitch", 0f), "pitch"), ResourceConfigUtils.getAsFloat(arguments.getOrDefault("pitch", 0f), "pitch"),
ResourceConfigUtils.getAsFloat(arguments.getOrDefault("yaw", 0f), "yaw"), ResourceConfigUtils.getAsFloat(arguments.getOrDefault("yaw", 0f), "yaw"),
ResourceConfigUtils.getAsQuaternionf(arguments.getOrDefault("rotation", 0f), "rotation"), 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.bukkit.util.LocationUtils;
import net.momirealms.craftengine.core.entity.furniture.*; import net.momirealms.craftengine.core.entity.furniture.*;
import net.momirealms.craftengine.core.entity.furniture.hitbox.FurnitureHitBoxConfig; 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.util.QuaternionUtils;
import net.momirealms.craftengine.core.world.WorldPosition; import net.momirealms.craftengine.core.world.WorldPosition;
import net.momirealms.craftengine.core.world.collision.AABB; import net.momirealms.craftengine.core.world.collision.AABB;
@@ -115,7 +116,7 @@ public class BukkitFurniture extends Furniture {
BukkitFurnitureManager.instance().invalidateFurniture(this); BukkitFurnitureManager.instance().invalidateFurniture(this);
super.clearColliders(); super.clearColliders();
this.location = LocationUtils.toLocation(position); 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()) { for (Player player : itemDisplay.getTrackedPlayers()) {
BukkitAdaptors.adapt(player).sendPacket(removePacket, false); BukkitAdaptors.adapt(player).sendPacket(removePacket, false);
} }
@@ -142,7 +143,7 @@ public class BukkitFurniture extends Furniture {
protected void refresh() { protected void refresh() {
ItemDisplay itemDisplay = this.metaEntity.get(); ItemDisplay itemDisplay = this.metaEntity.get();
if (itemDisplay == null) return; 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(), 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); itemDisplay.getX(), itemDisplay.getY(), itemDisplay.getZ(), itemDisplay.getPitch(), itemDisplay.getYaw(), MEntityTypes.ITEM_DISPLAY, 0, CoreReflections.instance$Vec3$Zero, 0);
for (Player player : itemDisplay.getTrackedPlayers()) { for (Player player : itemDisplay.getTrackedPlayers()) {

View File

@@ -161,6 +161,10 @@ public class ItemDisplayFurnitureElementConfig implements FurnitureElementConfig
return this.applyDyedColor; return this.applyDyedColor;
} }
public BiFunction<Player, FurnitureColorSource, List<Object>> metadata() {
return this.metadata;
}
public Key itemId() { public Key itemId() {
return this.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.furniture.hitbox.FurnitureHitboxPart;
import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.plugin.CraftEngine; 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.util.VersionHelper;
import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.Vec3d;
import net.momirealms.craftengine.core.world.WorldPosition; import net.momirealms.craftengine.core.world.WorldPosition;
@@ -54,7 +55,7 @@ public class CustomFurnitureHitbox extends AbstractFurnitureHitBox {
} }
this.spawnPacket = FastNMS.INSTANCE.constructor$ClientboundBundlePacket(packets); this.spawnPacket = FastNMS.INSTANCE.constructor$ClientboundBundlePacket(packets);
this.part = new FurnitureHitboxPart(entityId, aabb, pos, false); 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; 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.Furniture;
import net.momirealms.craftengine.core.entity.furniture.hitbox.FurnitureHitboxPart; import net.momirealms.craftengine.core.entity.furniture.hitbox.FurnitureHitboxPart;
import net.momirealms.craftengine.core.entity.player.Player; 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.Vec3d;
import net.momirealms.craftengine.core.world.WorldPosition; import net.momirealms.craftengine.core.world.WorldPosition;
import net.momirealms.craftengine.core.world.collision.AABB; import net.momirealms.craftengine.core.world.collision.AABB;
@@ -40,7 +41,7 @@ public class InteractionFurnitureHitbox extends AbstractFurnitureHitBox {
FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(interactionId, config.cachedValues()) FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(interactionId, config.cachedValues())
)); ));
this.part = new FurnitureHitboxPart(interactionId, aabb, pos, config.responsive()); 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; this.entityId = interactionId;
} }

View File

@@ -13,6 +13,7 @@ import org.incendo.cloud.parser.standard.StringParser;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.StandardCopyOption; 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) { private void collectListJson(Path folder, String prefix, Consumer<String> callback) {
try (InputStream inputStream = Files.newInputStream(folder.resolve("_list.json"))) { try (InputStream inputStream = Files.newInputStream(folder.resolve("_list.json"))) {
String s = prefix.isEmpty() ? "" : (prefix + "/"); 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"); JsonArray fileList = listJson.getAsJsonArray("files");
for (JsonElement element : fileList) { for (JsonElement element : fileList) {
if (element instanceof JsonPrimitive primitive) { if (element instanceof JsonPrimitive primitive) {

View File

@@ -38,15 +38,13 @@ import org.bukkit.block.data.Directional;
import org.bukkit.block.data.Levelled; import org.bukkit.block.data.Levelled;
import org.bukkit.block.data.Lightable; import org.bukkit.block.data.Lightable;
import org.bukkit.block.data.type.*; import org.bukkit.block.data.type.*;
import org.bukkit.block.data.type.Observer;
import org.bukkit.entity.*; import org.bukkit.entity.*;
import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.HashMap; import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.Optional;
public final class InteractUtils { public final class InteractUtils {
private static final Map<Key, QuadFunction<Player, Item<ItemStack>, BlockData, BlockHitResult, Boolean>> INTERACTIONS = new HashMap<>(); 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)) { if (entity instanceof Sheep sheep && sheep.readyToBeSheared() && ArrayUtils.contains(ItemKeys.DYES, item)) {
DyeColor sheepColor = sheep.getColor(); DyeColor sheepColor = sheep.getColor();
if (sheepColor != null) { if (sheepColor != null) {
String color = sheepColor.name().toLowerCase(); String color = sheepColor.name().toLowerCase(Locale.ROOT);
return !Key.of(color + "_dye").equals(id); 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.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.Collection; import java.util.*;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
public final class BlockStateParser { public final class BlockStateParser {
private static final char START = '['; private static final char START = '[';
@@ -33,7 +30,7 @@ public final class BlockStateParser {
private Property<?> property; private Property<?> property;
public BlockStateParser(String data, int cursor) { 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.reader.setCursor(cursor);
this.cursor = cursor; this.cursor = cursor;
this.replaceCursor = cursor; this.replaceCursor = cursor;
@@ -116,7 +113,7 @@ public final class BlockStateParser {
suggestPropertyName(); suggestPropertyName();
return; return;
} }
if (used.contains(property.name().toLowerCase())) return; if (used.contains(property.name().toLowerCase(Locale.ROOT))) return;
used.add(input); used.add(input);
reader.skipWhitespace(); reader.skipWhitespace();
@@ -159,7 +156,7 @@ public final class BlockStateParser {
if (!reader.getRemaining().isEmpty()) return; if (!reader.getRemaining().isEmpty()) return;
String front = readPrefix(); String front = readPrefix();
for (Property<?> p : properties) { 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); this.suggestions.add(front + p.name() + EQUAL);
} }
} }
@@ -172,7 +169,7 @@ public final class BlockStateParser {
private void suggestValue() { private void suggestValue() {
for (Object val : property.possibleValues()) { 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(); this.initInternalData();
try (InputStream inputStream = plugin.resourceStream("internal/atlases/blocks.json")) { 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) { } catch (IOException e) {
throw new RuntimeException("Failed to read internal/atlases/blocks.json", 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) { private void loadModernItemModel(String path, BiConsumer<Key, ModernItemModel> callback) {
try (InputStream inputStream = this.plugin.resourceStream(path)) { try (InputStream inputStream = this.plugin.resourceStream(path)) {
if (inputStream != null) { 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()) { for (Map.Entry<String, JsonElement> entry : allModelsItems.entrySet()) {
if (entry.getValue() instanceof JsonObject modelJson) { if (entry.getValue() instanceof JsonObject modelJson) {
callback.accept(Key.of(entry.getKey()), ModernItemModel.fromJson(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) { private void loadInternalData(String path, BiConsumer<Key, JsonObject> callback) {
try (InputStream inputStream = this.plugin.resourceStream(path)) { try (InputStream inputStream = this.plugin.resourceStream(path)) {
if (inputStream != null) { 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()) { for (Map.Entry<String, JsonElement> entry : allModelsItems.entrySet()) {
if (entry.getValue() instanceof JsonObject modelJson) { if (entry.getValue() instanceof JsonObject modelJson) {
callback.accept(Key.of(entry.getKey()), 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) { private void loadInternalList(String path, Consumer<Key> callback) {
try (InputStream inputStream = this.plugin.resourceStream(path)) { try (InputStream inputStream = this.plugin.resourceStream(path)) {
if (inputStream != null) { 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) { for (JsonElement element : listJson) {
if (element instanceof JsonPrimitive primitiveJson) { if (element instanceof JsonPrimitive primitiveJson) {
callback.accept(Key.of("minecraft", primitiveJson.getAsString())); callback.accept(Key.of("minecraft", primitiveJson.getAsString()));
@@ -1777,7 +1777,7 @@ public abstract class AbstractPackManager implements PackManager {
if (Files.exists(atlasPath) && Files.isRegularFile(atlasPath)) { if (Files.exists(atlasPath) && Files.isRegularFile(atlasPath)) {
try { try {
previousAtlasSources = GsonHelper.readJsonFile(atlasPath).getAsJsonObject().getAsJsonArray("sources"); 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"); plugin.logger().warn("Failed to load internal/sounds.json");
return; return;
} }
soundTemplate = JsonParser.parseReader(new InputStreamReader(inputStream)).getAsJsonObject(); soundTemplate = JsonParser.parseReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).getAsJsonObject();
} catch (IOException e) { } catch (IOException e) {
plugin.logger().warn("Failed to load internal/sounds.json", e); plugin.logger().warn("Failed to load internal/sounds.json", e);
return; return;

View File

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

View File

@@ -219,7 +219,7 @@ public class DropboxHost implements ResourcePackHost {
} }
String credentials = this.appKey + ":" + this.appSecret; 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()) { try (HttpClient client = HttpClient.newBuilder().proxy(this.proxy).build()) {
HttpRequest request = HttpRequest.newBuilder() 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.plugin.locale.LocalizedException;
import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.Key;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.List; import java.util.List;
import java.util.Map; 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); String uuid = Optional.ofNullable(arguments.get("uuid")).map(String::valueOf).orElse(null);
if (uuid == null || uuid.isEmpty()) { 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); UUID hostUUID = UUID.fromString(uuid);
String sha1 = arguments.getOrDefault("sha1", "").toString(); 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; if (!Files.exists(cachePath) || !Files.isRegularFile(cachePath)) return;
try (InputStream is = Files.newInputStream(cachePath)) { try (InputStream is = Files.newInputStream(cachePath)) {
Map<String, String> cache = GsonHelper.get().fromJson( Map<String, String> cache = GsonHelper.get().fromJson(
new InputStreamReader(is), new InputStreamReader(is, StandardCharsets.UTF_8),
new TypeToken<Map<String, String>>(){}.getType() new TypeToken<Map<String, String>>(){}.getType()
); );
this.url = cache.get("url"); this.url = cache.get("url");
@@ -155,13 +155,13 @@ public class GitLabHost implements ResourcePackHost {
String filePartHeader = "--" + boundary + "\r\n" + String filePartHeader = "--" + boundary + "\r\n" +
"Content-Disposition: form-data; name=\"file\"; filename=\"" + filePath.getFileName() + "\"\r\n" + "Content-Disposition: form-data; name=\"file\"; filename=\"" + filePath.getFileName() + "\"\r\n" +
"Content-Type: application/octet-stream\r\n\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(Files.readAllBytes(filePath));
parts.add("\r\n".getBytes()); parts.add("\r\n".getBytes(StandardCharsets.UTF_8));
String endBoundary = "--" + boundary + "--\r\n"; String endBoundary = "--" + boundary + "--\r\n";
parts.add(endBoundary.getBytes()); parts.add(endBoundary.getBytes(StandardCharsets.UTF_8));
return HttpRequest.BodyPublishers.ofByteArrays(parts); return HttpRequest.BodyPublishers.ofByteArrays(parts);
} }

View File

@@ -22,6 +22,7 @@ import java.net.URI;
import java.net.http.HttpClient; import java.net.http.HttpClient;
import java.net.http.HttpRequest; import java.net.http.HttpRequest;
import java.net.http.HttpResponse; import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.StandardOpenOption; import java.nio.file.StandardOpenOption;
@@ -62,7 +63,7 @@ public class LobFileHost implements ResourcePackHost {
if (!Files.exists(cachePath) || !Files.isRegularFile(cachePath)) return; if (!Files.exists(cachePath) || !Files.isRegularFile(cachePath)) return;
try (InputStream is = Files.newInputStream(cachePath)) { try (InputStream is = Files.newInputStream(cachePath)) {
Map<String, String> cache = GsonHelper.get().fromJson( Map<String, String> cache = GsonHelper.get().fromJson(
new InputStreamReader(is), new InputStreamReader(is, StandardCharsets.UTF_8),
new TypeToken<Map<String, String>>(){}.getType() new TypeToken<Map<String, String>>(){}.getType()
); );
this.url = cache.get("url"); this.url = cache.get("url");
@@ -191,8 +192,8 @@ public class LobFileHost implements ResourcePackHost {
MessageDigest sha256Digest = MessageDigest.getInstance("SHA-256"); MessageDigest sha256Digest = MessageDigest.getInstance("SHA-256");
try (InputStream is = Files.newInputStream(path); try (InputStream is = Files.newInputStream(path);
DigestInputStream dis = new DigestInputStream(is, sha1Digest)) { DigestInputStream dis = new DigestInputStream(is, sha1Digest);
DigestInputStream dis2 = new DigestInputStream(dis, sha256Digest); DigestInputStream dis2 = new DigestInputStream(dis, sha256Digest)) {
while (dis2.read() != -1) ; while (dis2.read() != -1) ;
@@ -207,18 +208,18 @@ public class LobFileHost implements ResourcePackHost {
String filePartHeader = "--" + boundary + "\r\n" + String filePartHeader = "--" + boundary + "\r\n" +
"Content-Disposition: form-data; name=\"file\"; filename=\"" + filePath.getFileName() + "\"\r\n" + "Content-Disposition: form-data; name=\"file\"; filename=\"" + filePath.getFileName() + "\"\r\n" +
"Content-Type: application/octet-stream\r\n\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(Files.readAllBytes(filePath));
parts.add("\r\n".getBytes()); parts.add("\r\n".getBytes(StandardCharsets.UTF_8));
String sha256Part = "--" + boundary + "\r\n" + String sha256Part = "--" + boundary + "\r\n" +
"Content-Disposition: form-data; name=\"sha_256\"\r\n\r\n" + "Content-Disposition: form-data; name=\"sha_256\"\r\n\r\n" +
sha256Hash + "\r\n"; sha256Hash + "\r\n";
parts.add(sha256Part.getBytes()); parts.add(sha256Part.getBytes(StandardCharsets.UTF_8));
String endBoundary = "--" + boundary + "--\r\n"; String endBoundary = "--" + boundary + "--\r\n";
parts.add(endBoundary.getBytes()); parts.add(endBoundary.getBytes(StandardCharsets.UTF_8));
return HttpRequest.BodyPublishers.ofByteArrays(parts); 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.LocalizedException;
import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.plugin.locale.TranslationManager;
import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.util.*;
import org.jetbrains.annotations.NotNull;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
@@ -34,7 +35,7 @@ public class OneDriveHost implements ResourcePackHost {
private final String clientSecret; private final String clientSecret;
private final ProxySelector proxy; private final ProxySelector proxy;
private final String uploadPath; private final String uploadPath;
private Tuple<String, String, Date> refreshToken; private Tuple<@NotNull String, @NotNull String, @NotNull Date> refreshToken;
private String sha1; private String sha1;
private String fileId; private String fileId;
@@ -66,13 +67,13 @@ public class OneDriveHost implements ResourcePackHost {
if (!Files.exists(cachePath) || !Files.isRegularFile(cachePath)) return; if (!Files.exists(cachePath) || !Files.isRegularFile(cachePath)) return;
try (InputStream is = Files.newInputStream(cachePath)) { try (InputStream is = Files.newInputStream(cachePath)) {
Map<String, String> cache = GsonHelper.get().fromJson( Map<String, String> cache = GsonHelper.get().fromJson(
new InputStreamReader(is), new InputStreamReader(is, StandardCharsets.UTF_8),
new TypeToken<Map<String, String>>(){}.getType() new TypeToken<Map<String, String>>(){}.getType()
); );
this.refreshToken = Tuple.of( this.refreshToken = Tuple.of(
cache.get("refresh-token"), Objects.requireNonNull(cache.get("refresh-token")),
cache.get("access-token"), Objects.requireNonNull(cache.get("access-token")),
new Date(Long.parseLong(cache.get("refresh-token-expires-in")))); new Date(Long.parseLong(cache.get("refresh-token-expires-in"))));
this.sha1 = cache.get("sha1"); this.sha1 = cache.get("sha1");
this.fileId = cache.get("file-id"); 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())) { if (this.refreshToken == null || this.refreshToken.mid().isEmpty() || this.refreshToken.right().before(new Date())) {
try (HttpClient client = HttpClient.newBuilder().proxy(this.proxy).build()) { try (HttpClient client = HttpClient.newBuilder().proxy(this.proxy).build()) {
String formData = "client_id=" + URLEncoder.encode(this.clientId, StandardCharsets.UTF_8) + 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) + "&refresh_token=" + URLEncoder.encode(this.refreshToken.left(), StandardCharsets.UTF_8) +
"&grant_type=refresh_token" + "&grant_type=refresh_token" +
"&scope=Files.ReadWrite.All+offline_access"; "&scope=Files.ReadWrite.All+offline_access";

View File

@@ -42,7 +42,7 @@ import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
public class SelfHostHttpServer { public final class SelfHostHttpServer {
private static SelfHostHttpServer instance; private static SelfHostHttpServer instance;
private final Cache<String, String> oneTimePackUrls = Caffeine.newBuilder() private final Cache<String, String> oneTimePackUrls = Caffeine.newBuilder()
.maximumSize(1024) .maximumSize(1024)
@@ -86,6 +86,12 @@ public class SelfHostHttpServer {
private EventLoopGroup workerGroup; private EventLoopGroup workerGroup;
private Channel serverChannel; private Channel serverChannel;
private SelfHostHttpServer() {
if (instance != null) {
throw new IllegalStateException("SelfHostHttpServer is already initialized.");
}
}
public static SelfHostHttpServer instance() { public static SelfHostHttpServer instance() {
if (instance == null) { if (instance == null) {
instance = new SelfHostHttpServer(); instance = new SelfHostHttpServer();

View File

@@ -54,7 +54,7 @@ public class ShulkerBoxSpecialModel implements SpecialModel {
public SpecialModel create(Map<String, Object> arguments) { public SpecialModel create(Map<String, Object> arguments) {
float openness = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("openness", 0), "openness"); 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"); 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) { if (openness > 1 || openness < 0) {
throw new LocalizedResourceConfigException("warning.config.item.model.special.shulker_box.invalid_openness", String.valueOf(openness)); 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.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Arrays; import java.util.Arrays;
import java.util.Locale;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
@@ -81,7 +82,7 @@ public final class ObfB {
} }
private static String 雷雷宝宝打肚肚(String input) { private static String 雷雷宝宝打肚肚(String input) {
return input.replace('\\', '/').toLowerCase(); return input.replace('\\', '/').toLowerCase(Locale.ROOT);
} }
private static String[] 因为都叫你小学生(String path) { private static String[] 因为都叫你小学生(String path) {

View File

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

View File

@@ -40,8 +40,8 @@ public class EntityCullingThread {
long startTime = System.nanoTime(); long startTime = System.nanoTime();
for (Player player : CraftEngine.instance().networkManager().onlineUsers()) { for (Player player : CraftEngine.instance().networkManager().onlineUsers()) {
// 使用绝对值确保非负,使用 threads 而不是 threads-1 确保均匀分布 // 使用位运算确保非负,使用 threads 而不是 threads-1 确保均匀分布
if (Math.abs(player.uuid().hashCode()) % this.threads == this.id) { if ((player.uuid().hashCode() & 0x7FFFFFFF) % this.threads == this.id) {
player.entityCullingTick(); player.entityCullingTick();
processed++; processed++;
} }

View File

@@ -1,5 +1,6 @@
package net.momirealms.craftengine.core.util; package net.momirealms.craftengine.core.util;
import java.nio.charset.StandardCharsets;
import java.util.Base64; import java.util.Base64;
public final class SkullUtils { public final class SkullUtils {
@@ -8,7 +9,7 @@ public final class SkullUtils {
public static String identifierFromBase64(String base64) { public static String identifierFromBase64(String base64) {
byte[] decodedBytes = Base64.getDecoder().decode(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 urlStartIndex = decodedString.indexOf("\"url\":\"") + 7;
int urlEndIndex = decodedString.indexOf("\"", urlStartIndex); int urlEndIndex = decodedString.indexOf("\"", urlStartIndex);
String textureUrl = decodedString.substring(urlStartIndex, urlEndIndex); String textureUrl = decodedString.substring(urlStartIndex, urlEndIndex);