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

Merge pull request #496 from Xiao-MoMi/dev

0.0.66.2
This commit is contained in:
XiaoMoMi
2025-12-09 16:50:57 +08:00
committed by GitHub
31 changed files with 304 additions and 30 deletions

View File

@@ -1,5 +1,5 @@
plugins {
id("com.gradleup.shadow") version "9.2.2"
id("com.gradleup.shadow") version "9.3.0"
id("maven-publish")
}
@@ -170,7 +170,7 @@ publishing {
tasks.register("publishRelease") {
group = "publishing"
description = "Publishes to the release repository"
dependsOn("publishMavenJavaPublicationToReleaseRepository")
dependsOn("publishMavenJavaPublicationToReleasesRepository")
}
tasks.register("publishSnapshot") {

View File

@@ -1,5 +1,5 @@
plugins {
id("com.gradleup.shadow") version "9.2.2"
id("com.gradleup.shadow") version "9.3.0"
}
repositories {

View File

@@ -1,5 +1,5 @@
plugins {
id("com.gradleup.shadow") version "9.2.2"
id("com.gradleup.shadow") version "9.3.0"
id("de.eldoria.plugin-yml.bukkit") version "0.7.1"
}

View File

@@ -4,7 +4,7 @@ import xyz.jpenilla.runtask.pluginsapi.DownloadPluginsSpec
import java.net.URI
plugins {
id("com.gradleup.shadow") version "9.2.2"
id("com.gradleup.shadow") version "9.3.0"
id("de.eldoria.plugin-yml.paper") version "0.7.1"
id("xyz.jpenilla.run-paper") version "3.0.2"
}
@@ -217,6 +217,9 @@ fun registerPaperTask(
languageVersion = JavaLanguageVersion.of(javaVersion)
}
systemProperties["com.mojang.eula.agree"] = true
systemProperties["net.momirealms.craftengine.dev"] = true
jvmArgs("-Dsun.stdout.encoding=UTF-8")
jvmArgs("-Dsun.stderr.encoding=UTF-8")
jvmArgs("-Ddisable.watchdog=true")
jvmArgs("-Xlog:redefine+class*=info")
jvmArgs("-XX:+AllowEnhancedClassRedefinition")

View File

@@ -1,8 +1,16 @@
package net.momirealms.craftengine.bukkit.entity.data;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
public class ArmorStandData<T> extends LivingEntityData<T> {
public static final ArmorStandData<Byte> ArmorStandFlags = new ArmorStandData<>(ArmorStandData.class, EntityDataValue.Serializers$BYTE, (byte) 0);
// rotations
public static final ArmorStandData<Object> HeadPose = new ArmorStandData<>(ArmorStandData.class, EntityDataValue.Serializers$ROTATIONS, CoreReflections.instance$ArmorStand$DEFAULT_HEAD_POSE);
public static final ArmorStandData<Object> BodyPose = new ArmorStandData<>(ArmorStandData.class, EntityDataValue.Serializers$ROTATIONS, CoreReflections.instance$ArmorStand$DEFAULT_BODY_POSE);
public static final ArmorStandData<Object> LeftArmPose = new ArmorStandData<>(ArmorStandData.class, EntityDataValue.Serializers$ROTATIONS, CoreReflections.instance$ArmorStand$DEFAULT_LEFT_ARM_POSE);
public static final ArmorStandData<Object> RightArmPose = new ArmorStandData<>(ArmorStandData.class, EntityDataValue.Serializers$ROTATIONS, CoreReflections.instance$ArmorStand$DEFAULT_RIGHT_ARM_POSE);
public static final ArmorStandData<Object> LeftLegPose = new ArmorStandData<>(ArmorStandData.class, EntityDataValue.Serializers$ROTATIONS, CoreReflections.instance$ArmorStand$DEFAULT_LEFT_LEG_POSE);
public static final ArmorStandData<Object> RightLegPose = new ArmorStandData<>(ArmorStandData.class, EntityDataValue.Serializers$ROTATIONS, CoreReflections.instance$ArmorStand$DEFAULT_RIGHT_LEG_POSE);
public ArmorStandData(Class<?> clazz, Object serializer, T defaultValue) {
super(clazz, serializer, defaultValue);

View File

@@ -178,4 +178,12 @@ public class BukkitFurniture extends Furniture {
public Entity getBukkitEntity() {
return this.metaEntity.get();
}
/**
* Use {@link #getBukkitEntity()} instead
*/
@Deprecated
public Entity baseEntity() {
return getBukkitEntity();
}
}

View File

@@ -60,6 +60,7 @@ public class BukkitCommandManager extends AbstractCommandManager<CommandSender>
new DebugIsSectionInjectedCommand(this, plugin),
new DebugMigrateTemplatesCommand(this, plugin),
new DebugIsChunkPersistentLoadedCommand(this, plugin),
new DebugOptimizeFurnitureStructureCommand(this, plugin),
new TotemAnimationCommand(this, plugin),
new EnableResourceCommand(this, plugin),
new DisableResourceCommand(this, plugin),

View File

@@ -0,0 +1,175 @@
package net.momirealms.craftengine.bukkit.plugin.command.feature;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager;
import net.momirealms.craftengine.core.plugin.command.sender.Sender;
import net.momirealms.craftengine.core.util.NBTUtils;
import net.momirealms.sparrow.nbt.CompoundTag;
import net.momirealms.sparrow.nbt.DoubleTag;
import net.momirealms.sparrow.nbt.ListTag;
import net.momirealms.sparrow.nbt.Tag;
import org.bukkit.NamespacedKey;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.Command;
import org.incendo.cloud.bukkit.parser.NamespacedKeyParser;
import org.incendo.cloud.bukkit.parser.WorldParser;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.context.CommandInput;
import org.incendo.cloud.parser.standard.DoubleParser;
import org.incendo.cloud.suggestion.Suggestion;
import org.incendo.cloud.suggestion.SuggestionProvider;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.FileVisitOption;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class DebugOptimizeFurnitureStructureCommand extends BukkitCommandFeature<CommandSender> {
public DebugOptimizeFurnitureStructureCommand(CraftEngineCommandManager<CommandSender> commandManager, CraftEngine plugin) {
super(commandManager, plugin);
}
@Override
public Command.Builder<? extends CommandSender> assembleCommand(org.incendo.cloud.CommandManager<CommandSender> manager, Command.Builder<CommandSender> builder) {
return builder
.required("world", WorldParser.worldParser())
.required("file", NamespacedKeyParser.namespacedKeyComponent().suggestionProvider(new SuggestionProvider<>() {
@Override
public @NonNull CompletableFuture<? extends @NonNull Iterable<? extends @NonNull Suggestion>> suggestionsFuture(@NonNull CommandContext<Object> context, @NonNull CommandInput input) {
World world = context.get("world");
Path generated = world.getWorldFolder().toPath().resolve("generated");
if (!Files.exists(generated)) {
return CompletableFuture.completedFuture(Collections.emptyList());
}
try {
return CompletableFuture.completedFuture(findStructures(generated).stream().map(Suggestion::suggestion).collect(Collectors.toList()));
} catch (IOException e) {
return CompletableFuture.completedFuture(Collections.emptyList());
}
}
}))
.optional("y-offset", DoubleParser.doubleParser())
.handler(context -> {
World world = context.get("world");
NamespacedKey file = context.get("file");
double offset = (double) context.optional("y-offset").orElse(0d);
Path filePath = world.getWorldFolder().toPath().resolve("generated").resolve(file.getNamespace()).resolve("structures").resolve(file.getKey() + ".nbt");
Sender sender = plugin().senderFactory().wrap(context.sender());
if (!Files.exists(filePath)) {
sender.sendMessage(Component.text("File not found", NamedTextColor.RED));
return;
}
try (InputStream is = Files.newInputStream(filePath)) {
CompoundTag structureTag = NBTUtils.readCompressed(is);
ListTag entitiesTag = structureTag.getList("entities");
if (entitiesTag == null) {
sender.sendMessage(Component.text("Entities not found", NamedTextColor.RED));
return;
}
int count = 0;
ListTag toSave = new ListTag();
for (Tag entityTag0 : entitiesTag) {
CompoundTag entityTag = (CompoundTag) entityTag0;
CompoundTag entityNBTTag = (CompoundTag) entityTag.get("nbt");
if (entityNBTTag != null) {
CompoundTag bukkitValuesTag = (CompoundTag) entityNBTTag.get("BukkitValues");
if (bukkitValuesTag != null) {
// 不保存碰撞实体
if (bukkitValuesTag.containsKey("craftengine:collision")) {
count++;
continue;
}
if (bukkitValuesTag.containsKey("craftengine:furniture_id")) {
if (offset != 0) {
ListTag pos = (ListTag) entityTag.get("pos");
double previousY = pos.getDouble(1);
pos.set(1, new DoubleTag(previousY + offset));
count++;
}
}
}
}
toSave.add(entityTag);
}
if (count == 0) {
sender.sendMessage(Component.text("Nothing changed", NamedTextColor.WHITE));
} else {
structureTag.put("entities", toSave);
try (OutputStream os = Files.newOutputStream(filePath)) {
NBTUtils.writeCompressed(structureTag, os);
} catch (IOException e) {
sender.sendMessage(Component.text("Internal error", NamedTextColor.RED));
plugin().logger().severe("Cannot write structure NBT file", e);
return;
}
sender.sendMessage(Component.text(count + " entities modified", NamedTextColor.WHITE));
}
} catch (IOException e) {
sender.sendMessage(Component.text("Internal error", NamedTextColor.RED));
plugin().logger().severe("Cannot read structure NBT file", e);
}
});
}
@Override
public String getFeatureID() {
return "debug_optimize_furniture_structure";
}
public static List<String> findStructures(Path startPath) throws IOException {
// 并行遍历文件树使用自定义的BiPredicate进行过滤
try (Stream<Path> stream = Files.walk(startPath, FileVisitOption.FOLLOW_LINKS)) {
return stream.filter(Files::isRegularFile)
.filter(path -> {
String filename = path.getFileName().toString();
return filename.endsWith(".nbt") &&
filename.length() > 4; // 确保有文件名(不只是.nbt
})
.map(path -> {
try {
return extractPair(startPath, path);
} catch (Exception e) {
return null;
}
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
}
private static String extractPair(Path basePath, Path nbtFile) {
try {
Path relativePath = basePath.relativize(nbtFile);
List<String> parts = new ArrayList<>();
for (Path part : relativePath) {
parts.add(part.toString());
}
// 检查是否符合 xxx/structures/xxx.nbt 模式
if (parts.size() >= 3 && "structures".equals(parts.get(parts.size() - 2))) {
String firstXxx = parts.get(parts.size() - 3);
String fileName = parts.getLast();
if (fileName.endsWith(".nbt")) {
String secondXxx = fileName.substring(0, fileName.length() - 4);
return firstXxx + ":" + secondXxx;
}
}
} catch (Exception ignored) {
}
return null;
}
}

View File

@@ -4644,4 +4644,35 @@ public final class CoreReflections {
"world.scores.PlayerTeam"
)
);
public static final Class<?> clazz$Rotations = requireNonNull(
BukkitReflectionUtils.findReobfOrMojmapClass(
"core.Vector3f",
"core.Rotations"
)
);
public static final Constructor<?> constructor$Rotations = requireNonNull(
ReflectionUtils.getConstructor(clazz$Rotations, float.class, float.class, float.class)
);
public static final Object instance$ArmorStand$DEFAULT_HEAD_POSE;
public static final Object instance$ArmorStand$DEFAULT_BODY_POSE;
public static final Object instance$ArmorStand$DEFAULT_LEFT_ARM_POSE;
public static final Object instance$ArmorStand$DEFAULT_RIGHT_ARM_POSE;
public static final Object instance$ArmorStand$DEFAULT_LEFT_LEG_POSE;
public static final Object instance$ArmorStand$DEFAULT_RIGHT_LEG_POSE;
static {
try {
instance$ArmorStand$DEFAULT_HEAD_POSE = constructor$Rotations.newInstance(0.0F, 0.0F, 0.0F);
instance$ArmorStand$DEFAULT_BODY_POSE = constructor$Rotations.newInstance(0.0F, 0.0F, 0.0F);
instance$ArmorStand$DEFAULT_LEFT_ARM_POSE = constructor$Rotations.newInstance(-10.0F, 0.0F, -10.0F);
instance$ArmorStand$DEFAULT_RIGHT_ARM_POSE = constructor$Rotations.newInstance(-15.0F, 0.0F, 10.0F);
instance$ArmorStand$DEFAULT_LEFT_LEG_POSE = constructor$Rotations.newInstance(-1.0F, 0.0F, -1.0F);
instance$ArmorStand$DEFAULT_RIGHT_LEG_POSE = constructor$Rotations.newInstance(1.0F, 0.0F, 1.0F);
} catch (ReflectiveOperationException e) {
throw new ReflectionInitException("Failed to init ArmorStand", e);
}
}
}

View File

@@ -168,6 +168,8 @@ public class BukkitServerPlayer extends Player {
private int lastHitFurnitureTick;
// 控制展示实体可见距离
private double displayEntityViewDistance;
// 是否是基岩版
private Tristate isBedrock = Tristate.UNDEFINED;
public BukkitServerPlayer(BukkitCraftEngine plugin, @Nullable Channel channel) {
this.channel = channel;
@@ -1517,6 +1519,14 @@ public class BukkitServerPlayer extends Player {
return FastNMS.INSTANCE.method$Inventory$clearOrCountMatchingItems(inventory, predicate, count, craftSlots);
}
@Override
public boolean isBedrock() {
if (this.isBedrock == Tristate.UNDEFINED) {
this.isBedrock = Tristate.of(this.plugin.compatibilityManager().isBedrockPlayer(this));
}
return this.isBedrock.asBoolean();
}
@Override
public void addTrackedFurniture(int entityId, Furniture furniture) {
this.trackedFurniture.put(entityId, new VirtualCullableObject(furniture));

View File

@@ -295,6 +295,7 @@ public class BukkitWorldManager implements WorldManager, Listener {
Object chunkSource = FastNMS.INSTANCE.method$ServerLevel$getChunkSource(worldServer);
Object levelChunk = FastNMS.INSTANCE.method$ServerChunkCache$getChunkAtIfLoadedMainThread(chunkSource, chunk.getX(), chunk.getZ());
Object[] sections = FastNMS.INSTANCE.method$ChunkAccess$getSections(levelChunk);
synchronized (sections) {
for (int i = 0; i < ceSections.length; i++) {
CESection ceSection = ceSections[i];
Object section = sections[i];
@@ -318,6 +319,7 @@ public class BukkitWorldManager implements WorldManager, Listener {
}
}
}
}
if (unsaved /*&& !FastNMS.INSTANCE.method$LevelChunk$isUnsaved(levelChunk)*/) {
FastNMS.INSTANCE.method$LevelChunk$markUnsaved(levelChunk);
}

View File

@@ -283,6 +283,13 @@ debug_furniture:
- /craftengine debug furniture
- /ce debug furniture
debug_optimize_furniture_structure:
enable: true
permission: ce.command.debug.optimize_furniture_structure
usage:
- /craftengine debug optimize-furniture-structure
- /ce debug optimize-furniture-structure
debug_test:
enable: true
permission: ce.command.debug.test

View File

@@ -562,7 +562,7 @@ chunk-system:
client-optimization:
# Requires a restart to fully apply.
entity-culling:
enable: false
enable: true
# Using server-side ray tracing algorithms to hide block entities/furniture and reduce client-side rendering pressure.
ray-tracing: true
# Cull entities based on distance

View File

@@ -46,7 +46,7 @@ info.resource_pack.validate: "Validated resource pack in <arg:0>ms"
info.resource_pack.optimize: "Optimized resource pack in <arg:0>ms"
info.resource_pack.optimize.json: "> Optimizing json files..."
info.resource_pack.optimize.texture: "> Optimizing textures..."
info.resource_pack.optimize.result: "□ Before/After/Ratio: <arg:0> KB/<arg:1> KB/<arg:2>%"
info.resource_pack.optimize.result: "□ Before/After/Ratio: <arg:0>/<arg:1>/<arg:2>%"
info.resource_pack.create: "Created resource pack zip in <arg:0>ms"
info.resource_pack.upload: "Completed uploading resource pack"
info.host.self.netty_server: "Netty HTTP server started on port: <arg:0>"

View File

@@ -46,7 +46,7 @@ info.resource_pack.validate: "验证资源包耗时 <arg:0>ms"
info.resource_pack.optimize: "优化资源包耗时 <arg:0>ms"
info.resource_pack.optimize.json: "> 正在优化json文件..."
info.resource_pack.optimize.texture: "> 正在优化贴图文件..."
info.resource_pack.optimize.result: "□ 优化前/优化后/比例: <arg:0> KB/<arg:1> KB/<arg:2>%"
info.resource_pack.optimize.result: "□ 优化前/优化后/比例: <arg:0>/<arg:1>/<arg:2>%"
info.resource_pack.create: "创建资源包文件耗时 <arg:0>ms"
info.resource_pack.upload: "资源包上传完成"
info.host.self.netty_server: "Netty HTTP 服务已在端口 <arg:0> 开启"

View File

@@ -1,5 +1,5 @@
plugins {
id("com.gradleup.shadow") version "9.2.2"
id("com.gradleup.shadow") version "9.3.0"
id("maven-publish")
}
@@ -175,7 +175,7 @@ publishing {
tasks.register("publishRelease") {
group = "publishing"
description = "Publishes to the release repository"
dependsOn("publishMavenJavaPublicationToReleaseRepository")
dependsOn("publishMavenJavaPublicationToReleasesRepository")
}
tasks.register("publishSnapshot") {

View File

@@ -232,6 +232,8 @@ public abstract class Player extends AbstractEntity implements NetWorkUser {
public abstract int clearOrCountMatchingInventoryItems(Key itemId, int count);
public abstract boolean isBedrock();
@Override
public void remove() {
}

View File

@@ -0,0 +1,26 @@
package net.momirealms.craftengine.core.util;
import net.momirealms.sparrow.nbt.CompoundTag;
import net.momirealms.sparrow.nbt.NBT;
import java.io.*;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
public final class NBTUtils {
private NBTUtils() {
}
public static void writeCompressed(CompoundTag nbt, OutputStream stream) throws IOException {
try (DataOutputStream dataoutputstream = new DataOutputStream(new BufferedOutputStream(new GZIPOutputStream(stream)))) {
NBT.writeCompound(nbt, dataoutputstream, true);
}
}
public static CompoundTag readCompressed(InputStream stream) throws IOException {
try (DataInputStream datainputstream = new DataInputStream(new BufferedInputStream(new GZIPInputStream(stream)))) {
return NBT.readCompound(datainputstream, true);
}
}
}

View File

@@ -8,6 +8,7 @@ import java.nio.charset.StandardCharsets;
import java.util.Objects;
public class VersionHelper {
public static final boolean IS_RUNNING_IN_DEV = Boolean.getBoolean("net.momirealms.craftengine.dev");
public static final boolean PREMIUM = false;
public static final MinecraftVersion MINECRAFT_VERSION;
public static final boolean COMPONENT_RELEASE;

View File

@@ -1,7 +1,7 @@
org.gradle.jvmargs=-Xmx1G
# Project settings
project_version=0.0.66
project_version=0.0.66.2
config_version=60
lang_version=43
project_group=net.momirealms
@@ -37,8 +37,8 @@ geantyref_version=1.3.16
zstd_version=1.5.7-6
commons_io_version=2.21.0
commons_lang3_version=3.20.0
sparrow_nbt_version=0.10.6
sparrow_util_version=0.68
sparrow_nbt_version=0.10.9
sparrow_util_version=0.69
fastutil_version=8.5.18
netty_version=4.1.128.Final
joml_version=1.10.8
@@ -48,7 +48,7 @@ byte_buddy_version=1.18.1
ahocorasick_version=0.6.3
snake_yaml_version=2.5
anti_grief_version=1.0.5
nms_helper_version=1.0.148
nms_helper_version=1.0.149
evalex_version=3.5.0
reactive_streams_version=1.0.4
amazon_awssdk_version=2.38.7

View File

@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists