From 805d880ed9a01c51e3865aa8fc9ccdc245d57eb4 Mon Sep 17 00:00:00 2001 From: 3944Realms Date: Mon, 11 May 2026 23:29:08 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B5=8B=E8=AF=95=E4=B8=8B=E6=9D=A5?= =?UTF-8?q?=EF=BC=8C1.21.1=E6=80=BB=E4=BD=93=E9=80=BB=E8=BE=91=E6=B2=A1?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/build.gradle | 4 +- .../client/gui/component/WheelWidget.java | 7 +- .../block/DollBlockEntityRenderer.java | 44 +++- .../renderer/item/DollItemRenderer.java | 55 +++-- .../content/block/AbstractDollBlock.java | 38 +++- .../block/blockentity/DollBlockEntity.java | 195 +++++++++++++----- .../lib39/content/item/DollItem.java | 10 +- .../lib39/core/sync/ILib39SyncDataHolder.java | 0 .../lib39/core/sync/INBTSerializable.java | 6 +- .../carryon/MixinCarriedObjectRender.java | 18 +- .../lib39/mixin/minecraft}/MixinEntity.java | 7 +- .../lib39/platform/services/IUtilHelper.java | 3 + .../lib39/util/GameProfileHelper.java | 66 +++++- .../r3944realms/lib39/util/nbt/NBTReader.java | 44 +++- .../assets/lib39/shaders/core/ring.fsh | 12 +- .../assets/lib39/shaders/core/selection.fsh | 1 - .../assets/lib39/shaders/core/selection.json | 8 - common/src/main/resources/lib39.mixins.json | 1 + .../provider/FabricDollComponentProvider.java | 10 +- .../core/event/FabricCommonEventHandler.java | 47 +++-- .../content/data/FabricTestSyncData.java | 4 +- .../core/network/FabricExNetworkHandler.java | 5 + .../lib39/platform/FabricUtilHelper.java | 7 + .../main/resources/lib39.fabric.mixins.json | 1 - neoforge/build.gradle | 3 +- .../NeoForgeDollComponentProvider.java | 9 +- .../base/datagen/Lib39BaseDataGenEvent.java | 11 +- .../datagen/provider/Lib39BlockLootTable.java | 8 +- .../lib39/core/event/CommonEventHandler.java | 57 +++-- .../lib39/core/sync/SyncCapProvider.java | 54 +++++ .../content/data/ExCapabilityHandler.java | 7 +- .../content/data/TestSyncCapProvider.java | 20 ++ .../example/content/data/TestSyncData.java | 4 +- .../lib39/platform/NeoForgeUtilHelper.java | 12 +- 34 files changed, 566 insertions(+), 212 deletions(-) rename {fabric => common}/src/main/java/top/r3944realms/lib39/core/sync/ILib39SyncDataHolder.java (100%) rename {fabric/src/main/java/top/r3944realms/lib39/mixin => common/src/main/java/top/r3944realms/lib39/mixin/minecraft}/MixinEntity.java (87%) create mode 100644 neoforge/src/main/java/top/r3944realms/lib39/core/sync/SyncCapProvider.java create mode 100644 neoforge/src/main/java/top/r3944realms/lib39/example/content/data/TestSyncCapProvider.java diff --git a/common/build.gradle b/common/build.gradle index f3da531..ea5de00 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -24,8 +24,8 @@ dependencies { transitive = false } // fabric and neoforge both bundle mixinextras, so it is safe to use it in common - compileOnly group: 'io.github.llamalad7', name: 'mixinextras-common', version: '0.3.5' - annotationProcessor group: 'io.github.llamalad7', name: 'mixinextras-common', version: '0.3.5' + implementation group: 'io.github.llamalad7', name: 'mixinextras-common', version: '0.4.1' + annotationProcessor group: 'io.github.llamalad7', name: 'mixinextras-common', version: '0.4.1' } configurations { commonJava { diff --git a/common/src/main/java/top/r3944realms/lib39/client/gui/component/WheelWidget.java b/common/src/main/java/top/r3944realms/lib39/client/gui/component/WheelWidget.java index 78f0125..f33acb9 100644 --- a/common/src/main/java/top/r3944realms/lib39/client/gui/component/WheelWidget.java +++ b/common/src/main/java/top/r3944realms/lib39/client/gui/component/WheelWidget.java @@ -587,6 +587,7 @@ public class WheelWidget extends AbstractWidget { PoseStack poseStack = guiGraphics.pose(); poseStack.pushPose(); + setupRingShader(centerX, centerY, innerRadius, outerRadius); Tesselator tesselator = Tesselator.getInstance(); // 计算足够大的绘制区域来覆盖整个环形(基于外半径) @@ -604,9 +605,8 @@ public class WheelWidget extends AbstractWidget { buffer.addVertex(matrix, x2, y2, -300).setColor(color); buffer.addVertex(matrix, x2, y1, -300).setColor(color); - setupRingShader(centerX, centerY, innerRadius, outerRadius); - BufferUploader.drawWithShader(buffer.build()); + RenderSystem.setShader(() -> null); poseStack.popPose(); } @@ -721,9 +721,6 @@ public class WheelWidget extends AbstractWidget { Lib39Shaders.getSelectionShader() .safeGetUniform("Radius") .set(radius * guiScale); - Lib39Shaders.getSelectionShader() - .safeGetUniform("AntiAliasingRadius") - .set(guiScale); // 根据需要调整 RenderSystem.setShaderColor(1, 1, 1, 1); BufferUploader.drawWithShader(Objects.requireNonNull(buffer.build())); RenderSystem.enableDepthTest(); diff --git a/common/src/main/java/top/r3944realms/lib39/client/renderer/block/DollBlockEntityRenderer.java b/common/src/main/java/top/r3944realms/lib39/client/renderer/block/DollBlockEntityRenderer.java index bf14fa4..78cae75 100644 --- a/common/src/main/java/top/r3944realms/lib39/client/renderer/block/DollBlockEntityRenderer.java +++ b/common/src/main/java/top/r3944realms/lib39/client/renderer/block/DollBlockEntityRenderer.java @@ -4,25 +4,32 @@ import com.mojang.authlib.GameProfile; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.math.Axis; +import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.client.resources.DefaultPlayerSkin; +import net.minecraft.client.resources.PlayerSkin; +import net.minecraft.client.resources.SkinManager; import net.minecraft.core.Direction; import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.component.ResolvableProfile; import net.minecraft.world.level.block.SkullBlock; import net.minecraft.world.level.block.WallSkullBlock; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.RotationSegment; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import top.r3944realms.lib39.client.model.DollModel; -import top.r3944realms.lib39.client.renderer.item.DollItemRenderer; import top.r3944realms.lib39.content.block.AbstractDollBlock; import top.r3944realms.lib39.content.block.WallDollBlock; import top.r3944realms.lib39.content.block.blockentity.DollBlockEntity; import top.r3944realms.lib39.util.lang.Pair; +import java.util.Optional; + /** * The type Doll block entity renderer. */ @@ -45,16 +52,43 @@ public class DollBlockEntityRenderer implements BlockEntityRenderer resourceLocationBooleanPair = DollItemRenderer.loadSkin(profile); + Pair modelAndRenderTypePair = getModelAndRenderTypePair(dollBlockEntity.getOwnerProfile()); poseStack.pushPose(); poseStack.translate(0.5, 1.5, 0.5); poseStack.scale(1.0F, -1.0F, -1.0F); poseStack.mulPose(Axis.YP.rotationDegrees(rotation)); - VertexConsumer vertexConsumer = buffer.getBuffer(RenderType.entityTranslucent(resourceLocationBooleanPair.first)); - this.dollModel.slim = resourceLocationBooleanPair.second; + VertexConsumer vertexConsumer = buffer.getBuffer(modelAndRenderTypePair.second); + this.dollModel.slim = modelAndRenderTypePair.first == PlayerSkin.Model.SLIM; this.dollModel.renderToBuffer(poseStack, vertexConsumer, packedLight, OverlayTexture.NO_OVERLAY,-1); poseStack.popPose(); } } + public static @NotNull Pair getModelAndRenderTypePair(@Nullable ResolvableProfile profile) { + SkinManager skinmanager = Minecraft.getInstance().getSkinManager(); + + if (profile == null) { + return Pair.of(PlayerSkin.Model.SLIM, + RenderType.entityTranslucent(DefaultPlayerSkin.getDefaultTexture())); + } + + GameProfile gameProfile = profile.gameProfile(); + + // 如果当前 Profile 没有纹理数据,尝试从 DollBlockEntity 缓存获取 + if (gameProfile != null && gameProfile.getProperties().isEmpty() + && gameProfile.getName() != null && !gameProfile.getName().isEmpty()) { + Optional cached = DollBlockEntity.fetchGameProfile(gameProfile.getName()) + .getNow(Optional.empty()); + if (cached.isPresent() && !cached.get().getProperties().isEmpty()) { + gameProfile = cached.get(); + } + } + + if (gameProfile != null && !gameProfile.getProperties().isEmpty()) { + PlayerSkin skin = skinmanager.getInsecureSkin(gameProfile); + return Pair.of(skin.model(), RenderType.entityTranslucent(skin.texture())); + } + + return Pair.of(PlayerSkin.Model.SLIM, + RenderType.entityTranslucent(DefaultPlayerSkin.getDefaultTexture())); + } } diff --git a/common/src/main/java/top/r3944realms/lib39/client/renderer/item/DollItemRenderer.java b/common/src/main/java/top/r3944realms/lib39/client/renderer/item/DollItemRenderer.java index 92c013e..ee3c9a8 100644 --- a/common/src/main/java/top/r3944realms/lib39/client/renderer/item/DollItemRenderer.java +++ b/common/src/main/java/top/r3944realms/lib39/client/renderer/item/DollItemRenderer.java @@ -11,9 +11,11 @@ import net.minecraft.client.renderer.RenderType; import net.minecraft.client.resources.DefaultPlayerSkin; import net.minecraft.client.resources.PlayerSkin; import net.minecraft.client.resources.SkinManager; +import net.minecraft.core.component.DataComponents; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemDisplayContext; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.component.ResolvableProfile; import org.jetbrains.annotations.NotNull; import top.r3944realms.lib39.Lib39; import top.r3944realms.lib39.client.model.DollModel; @@ -62,55 +64,44 @@ public class DollItemRenderer extends BlockEntityWithoutLevelRenderer { } return instance; } - @Override - public void renderByItem(@NotNull ItemStack stack, @NotNull ItemDisplayContext displayContext, @NotNull PoseStack poseStack, @NotNull MultiBufferSource buffer, int packedLight, int packedOverlay) { + public void renderByItem(@NotNull ItemStack stack, @NotNull ItemDisplayContext displayContext, + @NotNull PoseStack poseStack, @NotNull MultiBufferSource buffer, + int packedLight, int packedOverlay) { if (!(stack.getItem() instanceof DollItem)) { return; } lazyInit(); - GameProfile profile = GameProfileHelper.getProfileFromItemStack(stack); - Pair resourceLocationBooleanPair = loadSkin(profile); - ResourceLocation playerSkin = resourceLocationBooleanPair.first; - boolean isSlim = resourceLocationBooleanPair.second; + + // 直接从 DataComponents.PROFILE 获取 ResolvableProfile + ResolvableProfile profile = stack.get(DataComponents.PROFILE); + Pair skinInfo = getSkinInfo(profile); + poseStack.pushPose(); - VertexConsumer vertexConsumer = buffer.getBuffer( - RenderType.entityTranslucent(playerSkin) - ); + VertexConsumer vertexConsumer = buffer.getBuffer(RenderType.entityTranslucent(skinInfo.first)); poseStack.translate(0.5, 2.6, 0.8); poseStack.scale(1.8F, -1.8F, -1.8F); poseStack.mulPose(Axis.YP.rotationDegrees(180)); - this.dollModel.slim = isSlim; - this.dollModel.renderToBuffer( - poseStack, - vertexConsumer, - packedLight, - packedOverlay, - -1 - ); + + this.dollModel.slim = skinInfo.second == PlayerSkin.Model.SLIM; + this.dollModel.renderToBuffer(poseStack, vertexConsumer, packedLight, packedOverlay, -1); poseStack.popPose(); } /** - * Load skin pair. - * - * @param profile the profile - * @return the pair + * 获取皮肤纹理和模型类型(1.21+ 版本) */ - public static @NotNull Pair loadSkin(GameProfile profile) { + public static @NotNull Pair getSkinInfo(@NotNull ResolvableProfile profile) { SkinManager skinManager = Minecraft.getInstance().getSkinManager(); - ResourceLocation playerSkin; - boolean isSlim; - if (profile != null) { - PlayerSkin insecureSkin = skinManager.getInsecureSkin(profile); - playerSkin = insecureSkin.texture(); - isSlim = GameProfileHelper.isSlimArms(profile); - } else { - playerSkin = Lib39.mrl("textures/entity/player/wide/steve.png"); - isSlim = false; + + if (profile != null && profile.gameProfile() != null) { + PlayerSkin skin = skinManager.getInsecureSkin(profile.gameProfile()); + return Pair.of(skin.texture(), skin.model()); } - return Pair.of(playerSkin, isSlim); + + // 默认返回 Steve 皮肤 + return Pair.of(DefaultPlayerSkin.getDefaultTexture(), PlayerSkin.Model.SLIM); } } diff --git a/common/src/main/java/top/r3944realms/lib39/content/block/AbstractDollBlock.java b/common/src/main/java/top/r3944realms/lib39/content/block/AbstractDollBlock.java index 28afb4d..75f2ecf 100644 --- a/common/src/main/java/top/r3944realms/lib39/content/block/AbstractDollBlock.java +++ b/common/src/main/java/top/r3944realms/lib39/content/block/AbstractDollBlock.java @@ -4,13 +4,16 @@ import com.mojang.authlib.GameProfile; import com.mojang.serialization.MapCodec; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.core.component.DataComponents; import net.minecraft.core.particles.ParticleTypes; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundSource; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.component.ResolvableProfile; import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; @@ -178,9 +181,12 @@ public abstract class AbstractDollBlock extends BaseEntityBlock implements Simpl ItemStack stack = super.getCloneItemStack(level, pos, state); BlockEntity blockEntity = level.getBlockEntity(pos); if (blockEntity instanceof DollBlockEntity doll) { - GameProfile profile = doll.getOwnerProfile(); - if (profile != null) { - GameProfileHelper.saveProfileToItemStack(stack, profile); + ResolvableProfile profile; + if (doll.getOwnerProfile() != null) { + profile = doll.getOwnerProfile(); + if (profile != null) { + GameProfileHelper.saveProfileToItemStack(stack, profile); + } } } return stack; @@ -207,6 +213,19 @@ public abstract class AbstractDollBlock extends BaseEntityBlock implements Simpl super.createBlockStateDefinition(builder); builder.add(WATERLOGGED, POSE); } + @Override + public void setPlacedBy(@NotNull Level level, @NotNull BlockPos pos, @NotNull BlockState state, + @Nullable LivingEntity placer, @NotNull ItemStack stack) { + super.setPlacedBy(level, pos, state, placer, stack); + + BlockEntity blockEntity = level.getBlockEntity(pos); + if (blockEntity instanceof DollBlockEntity dollEntity) { + ResolvableProfile profile = GameProfileHelper.getProfileFromItemStack(stack); + if (profile != null) { + dollEntity.setOwner(profile); + } + } + } /** * 生成自定义掉落物 @@ -218,11 +237,14 @@ public abstract class AbstractDollBlock extends BaseEntityBlock implements Simpl return List.of(); } } - GameProfile profile = dollEntity.getOwnerProfile(); - if (profile != null) { - ItemStack instance = Lib39Items.DOLL.get().getDefaultInstance(); - GameProfileHelper.saveProfileToItemStack(instance, profile); - return List.of(instance); + ResolvableProfile profile; + if (dollEntity.getOwnerProfile() != null) { + profile = dollEntity.getOwnerProfile(); + if (profile != null) { + ItemStack instance = Lib39Items.DOLL.get().getDefaultInstance(); + GameProfileHelper.saveProfileToItemStack(instance, profile); + return List.of(instance); + } } return null; } diff --git a/common/src/main/java/top/r3944realms/lib39/content/block/blockentity/DollBlockEntity.java b/common/src/main/java/top/r3944realms/lib39/content/block/blockentity/DollBlockEntity.java index 27e04dd..6966917 100644 --- a/common/src/main/java/top/r3944realms/lib39/content/block/blockentity/DollBlockEntity.java +++ b/common/src/main/java/top/r3944realms/lib39/content/block/blockentity/DollBlockEntity.java @@ -1,62 +1,137 @@ package top.r3944realms.lib39.content.block.blockentity; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; import com.mojang.authlib.GameProfile; import net.minecraft.Util; import net.minecraft.core.BlockPos; import net.minecraft.core.HolderLookup; import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtOps; import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; +import net.minecraft.server.Services; import net.minecraft.world.item.component.ResolvableProfile; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SkullBlockEntity; import net.minecraft.world.level.block.state.BlockState; import org.jetbrains.annotations.Nullable; import top.r3944realms.lib39.core.register.Lib39BlockEntities; -import top.r3944realms.lib39.util.GameProfileHelper; -import top.r3944realms.lib39.util.nbt.NBTReader; -import top.r3944realms.lib39.util.nbt.NBTWriter; + +import java.time.Duration; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.function.BooleanSupplier; /** * The type Doll block entity. + * 参考 SkullBlockEntity 实现,添加缓存机制 */ public class DollBlockEntity extends BlockEntity { - @Nullable - private GameProfile owner; - /** - * Instantiates a new Doll block entity. - * - * @param pos the pos - * @param blockState the block state - */ + private static final String TAG_PROFILE = "profile"; + + // 静态缓存(与 SkullBlockEntity 共享或独立) + @Nullable + private static Executor mainThreadExecutor; + @Nullable + private static LoadingCache>> profileCacheByName; + @Nullable + private static LoadingCache>> profileCacheById; + + public static final Executor CHECKED_MAIN_THREAD_EXECUTOR = (runnable) -> { + Executor executor = mainThreadExecutor; + if (executor != null) { + executor.execute(runnable); + } + }; + + @Nullable + private ResolvableProfile owner; + public DollBlockEntity(BlockPos pos, BlockState blockState) { super(Lib39BlockEntities.DOLL_BLOCK_ENTITY.get(), pos, blockState); } - @Override - protected void saveAdditional(CompoundTag tag, HolderLookup.Provider registries) { - super.saveAdditional(tag, registries); - NBTWriter.of(tag) - .gameProfileIf(GameProfileHelper.TAG_OWN_PROFILE, owner != null, () -> owner); + /** + * 初始化缓存(在 Mod 初始化或服务器启动时调用) + */ + public static void setup(final Services services, Executor executor) { + mainThreadExecutor = executor; + final BooleanSupplier cacheUninitialized = () -> profileCacheById == null; + + profileCacheByName = CacheBuilder.newBuilder() + .expireAfterAccess(Duration.ofMinutes(10L)) + .maximumSize(256L) + .build(new CacheLoader<>() { + @Override + public CompletableFuture> load(String username) { + return fetchProfileByName(username, services); + } + }); + + profileCacheById = CacheBuilder.newBuilder() + .expireAfterAccess(Duration.ofMinutes(10L)) + .maximumSize(256L) + .build(new CacheLoader<>() { + @Override + public CompletableFuture> load(UUID uuid) { + return fetchProfileById(uuid, services, cacheUninitialized); + } + }); } - @Override - protected void loadAdditional(CompoundTag tag, HolderLookup.Provider registries) { - super.loadAdditional(tag, registries); - NBTReader.of(tag) - .gameProfile(GameProfileHelper.TAG_OWN_PROFILE, this::setOwner); + private static CompletableFuture> fetchProfileByName(String name, Services services) { + return services.profileCache().getAsync(name).thenCompose(optional -> { + LoadingCache>> cache = profileCacheById; + if (cache != null && optional.isPresent()) { + return cache.getUnchecked(optional.get().getId()) + .thenApply(fullProfile -> fullProfile.or(() -> optional)); + } + return CompletableFuture.completedFuture(Optional.empty()); + }); + } + + private static CompletableFuture> fetchProfileById(UUID uuid, Services services, BooleanSupplier cacheUninitialized) { + return CompletableFuture.supplyAsync(() -> { + if (cacheUninitialized.getAsBoolean()) { + return Optional.empty(); + } + var result = services.sessionService().fetchProfile(uuid, true); + return Optional.ofNullable(result).map(com.mojang.authlib.yggdrasil.ProfileResult::profile); + }, Util.backgroundExecutor()); } /** - * Gets owner profile. - * - * @return the owner profile + * 公开的静态方法:异步获取 GameProfile(复用 SkullBlockEntity 的缓存或使用自己的) */ - @Nullable - public GameProfile getOwnerProfile() { - return this.owner; + public static CompletableFuture> fetchGameProfile(String name) { + if (profileCacheByName != null && name != null && !name.isEmpty()) { + return profileCacheByName.getUnchecked(name); + } + // 回退到 SkullBlockEntity 的缓存 + return SkullBlockEntity.fetchGameProfile(name); } + public static CompletableFuture> fetchGameProfile(UUID uuid) { + if (profileCacheById != null && uuid != null) { + return profileCacheById.getUnchecked(uuid); + } + return SkullBlockEntity.fetchGameProfile(uuid); + } + + public static void clearCache() { + mainThreadExecutor = null; + profileCacheByName = null; + profileCacheById = null; + } + + @Nullable + public ResolvableProfile getOwnerProfile() { + return this.owner; + } @Override public ClientboundBlockEntityDataPacket getUpdatePacket() { @@ -65,47 +140,57 @@ public class DollBlockEntity extends BlockEntity { @Override public CompoundTag getUpdateTag(HolderLookup.Provider registries) { - return super.getUpdateTag(registries); + CompoundTag tag = super.getUpdateTag(registries); + saveAdditional(tag, registries); + return tag; } - /** - * Sets owner. - * - * @param owner the owner - */ - public void setOwner(@Nullable GameProfile owner) { + public void setOwner(@Nullable ResolvableProfile owner) { synchronized (this) { this.owner = owner; } - this.updateOwnerProfile(); } - /** - * Sets owner. - * - * @param ownerName the owner name - */ public void setOwner(@Nullable String ownerName) { - setOwner(new GameProfile(Util.NIL_UUID, ownerName)); + if (ownerName != null && !ownerName.isEmpty()) { + setOwner(new ResolvableProfile(new GameProfile(Util.NIL_UUID, ownerName))); + } } private void updateOwnerProfile() { - if (this.owner != null) { - // 使用 ResolvableProfile 进行异步解析 - ResolvableProfile resolvableProfile = new ResolvableProfile(this.owner); - if (!resolvableProfile.isResolved()) { - resolvableProfile.resolve().thenAcceptAsync(resolved -> { - // 从 ResolvableProfile 中获取 GameProfile - this.owner = resolved.gameProfile(); - this.setChanged(); - if (this.level != null) { - this.level.sendBlockUpdated(this.worldPosition, this.getBlockState(), this.getBlockState(), 3); - } - }, SkullBlockEntity.CHECKED_MAIN_THREAD_EXECUTOR); + if (this.owner != null && !this.owner.isResolved()) { + this.owner.resolve().thenAcceptAsync(resolved -> { + this.owner = resolved; + this.setChanged(); + // 通知客户端更新 + if (level != null && !level.isClientSide) { + level.sendBlockUpdated(worldPosition, getBlockState(), getBlockState(), 3); + } + }, CHECKED_MAIN_THREAD_EXECUTOR); + } else { + this.setChanged(); + if (level != null && !level.isClientSide && this.owner != null) { + level.sendBlockUpdated(worldPosition, getBlockState(), getBlockState(), 3); } } - this.setChanged(); } -} + @Override + protected void saveAdditional(CompoundTag tag, HolderLookup.Provider registries) { + super.saveAdditional(tag, registries); + if (this.owner != null) { + tag.put(TAG_PROFILE, ResolvableProfile.CODEC.encodeStart(NbtOps.INSTANCE, this.owner).getOrThrow()); + } + } + + @Override + protected void loadAdditional(CompoundTag tag, HolderLookup.Provider registries) { + super.loadAdditional(tag, registries); + if (tag.contains(TAG_PROFILE)) { + ResolvableProfile.CODEC.parse(NbtOps.INSTANCE, tag.get(TAG_PROFILE)) + .resultOrPartial(error -> {}) + .ifPresent(this::setOwner); + } + } +} \ No newline at end of file diff --git a/common/src/main/java/top/r3944realms/lib39/content/item/DollItem.java b/common/src/main/java/top/r3944realms/lib39/content/item/DollItem.java index 7fa4a27..9108b31 100644 --- a/common/src/main/java/top/r3944realms/lib39/content/item/DollItem.java +++ b/common/src/main/java/top/r3944realms/lib39/content/item/DollItem.java @@ -8,6 +8,7 @@ import net.minecraft.world.item.Equipable; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.StandingAndWallBlockItem; import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.item.component.ResolvableProfile; import net.minecraft.world.level.Level; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -32,9 +33,12 @@ public class DollItem extends StandingAndWallBlockItem implements Equipable { @Override public void appendHoverText(ItemStack stack, TooltipContext context, List tooltipComponents, TooltipFlag tooltipFlag) { super.appendHoverText(stack, context, tooltipComponents, tooltipFlag); - GameProfile profileFromItemStack = GameProfileHelper.getProfileFromItemStack(stack); - if (profileFromItemStack != null && profileFromItemStack.getName() != null) { - tooltipComponents.add(Component.translatable("tooltip.lib39.content.doll.hover.1", profileFromItemStack.getName())); + ResolvableProfile profileFromItemStack = GameProfileHelper.getProfileFromItemStack(stack); + if (profileFromItemStack != null) { + GameProfile gameProfile = profileFromItemStack.gameProfile(); + if (gameProfile != null && gameProfile.getName() != null) { + tooltipComponents.add(Component.translatable("tooltip.lib39.content.doll.hover.1", gameProfile.getName())); + } } tooltipComponents.add(Component.translatable("tooltip.lib39.content.doll.hover.2")); } diff --git a/fabric/src/main/java/top/r3944realms/lib39/core/sync/ILib39SyncDataHolder.java b/common/src/main/java/top/r3944realms/lib39/core/sync/ILib39SyncDataHolder.java similarity index 100% rename from fabric/src/main/java/top/r3944realms/lib39/core/sync/ILib39SyncDataHolder.java rename to common/src/main/java/top/r3944realms/lib39/core/sync/ILib39SyncDataHolder.java diff --git a/common/src/main/java/top/r3944realms/lib39/core/sync/INBTSerializable.java b/common/src/main/java/top/r3944realms/lib39/core/sync/INBTSerializable.java index 81f3729..100379a 100644 --- a/common/src/main/java/top/r3944realms/lib39/core/sync/INBTSerializable.java +++ b/common/src/main/java/top/r3944realms/lib39/core/sync/INBTSerializable.java @@ -7,7 +7,7 @@ import net.minecraft.nbt.Tag; * * @param the type parameter */ -public interface INBTSerializable { +public interface INBTSerializable { /** * Serialize nbt t. * @@ -18,7 +18,7 @@ public interface INBTSerializable { /** * Deserialize nbt. * - * @param var1 the var 1 + * @param t the var */ - void deserializeNBT(T var1); + void deserializeNBT(T t); } diff --git a/common/src/main/java/top/r3944realms/lib39/mixin/carryon/MixinCarriedObjectRender.java b/common/src/main/java/top/r3944realms/lib39/mixin/carryon/MixinCarriedObjectRender.java index afe2ea0..a076ba9 100644 --- a/common/src/main/java/top/r3944realms/lib39/mixin/carryon/MixinCarriedObjectRender.java +++ b/common/src/main/java/top/r3944realms/lib39/mixin/carryon/MixinCarriedObjectRender.java @@ -5,23 +5,23 @@ import com.mojang.authlib.GameProfile; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.component.ResolvableProfile; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Pseudo; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.ModifyVariable; -import top.r3944realms.lib39.content.block.AbstractDollBlock; import top.r3944realms.lib39.content.item.DollItem; import top.r3944realms.lib39.util.GameProfileHelper; import top.r3944realms.lib39.util.nbt.NBTReader; import tschipp.carryon.client.render.CarriedObjectRender; import tschipp.carryon.common.carry.CarryOnDataManager; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; /** * The type Mixin carried object render. */ +@SuppressWarnings("DuplicatedCode") @Pseudo @Mixin(value = CarriedObjectRender.class, remap = false) public class MixinCarriedObjectRender { @@ -36,9 +36,9 @@ public class MixinCarriedObjectRender { if (stack.getItem() instanceof DollItem) { CompoundTag compound = CarryOnDataManager.getCarryData(player).getNbt().getCompound("tile"); AtomicReference gameProfileAtomicReference = new AtomicReference<>(); - NBTReader.of(compound).gameProfile(GameProfileHelper.TAG_OWN_PROFILE, gameProfileAtomicReference::set); + NBTReader.of(compound).gameProfile("profile", gameProfileAtomicReference::set); if (gameProfileAtomicReference.get() != null) { - GameProfileHelper.saveProfileToItemStack(stack, gameProfileAtomicReference.get()); + GameProfileHelper.saveProfileToItemStack(stack, new ResolvableProfile(gameProfileAtomicReference.get())); } } return stack; @@ -50,16 +50,16 @@ public class MixinCarriedObjectRender { target = "Ltschipp/carryon/client/render/CarryRenderHelper;renderBakedModel(Lnet/minecraft/world/item/ItemStack;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;ILnet/minecraft/client/resources/model/BakedModel;)V" ) ) - private static ItemStack warpDollItem$2(ItemStack stack, @Local(ordinal = 0) Player player) { - if (stack.getItem() instanceof DollItem) { + private static ItemStack warpDollItem$2(ItemStack tileItem, @Local(ordinal = 0) Player player) { + if (tileItem.getItem() instanceof DollItem) { CompoundTag compound = CarryOnDataManager.getCarryData(player).getNbt().getCompound("tile"); AtomicReference gameProfileAtomicReference = new AtomicReference<>(); - NBTReader.of(compound).gameProfile(GameProfileHelper.TAG_OWN_PROFILE, gameProfileAtomicReference::set); + NBTReader.of(compound).gameProfile("profile", gameProfileAtomicReference::set); if (gameProfileAtomicReference.get() != null) { - GameProfileHelper.saveProfileToItemStack(stack, gameProfileAtomicReference.get()); + GameProfileHelper.saveProfileToItemStack(tileItem, new ResolvableProfile(gameProfileAtomicReference.get())); } } - return stack; + return tileItem; } } diff --git a/fabric/src/main/java/top/r3944realms/lib39/mixin/MixinEntity.java b/common/src/main/java/top/r3944realms/lib39/mixin/minecraft/MixinEntity.java similarity index 87% rename from fabric/src/main/java/top/r3944realms/lib39/mixin/MixinEntity.java rename to common/src/main/java/top/r3944realms/lib39/mixin/minecraft/MixinEntity.java index fb5d3c6..a6b04d8 100644 --- a/fabric/src/main/java/top/r3944realms/lib39/mixin/MixinEntity.java +++ b/common/src/main/java/top/r3944realms/lib39/mixin/minecraft/MixinEntity.java @@ -1,4 +1,4 @@ -package top.r3944realms.lib39.mixin; +package top.r3944realms.lib39.mixin.minecraft; import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; import com.llamalad7.mixinextras.injector.wrapoperation.Operation; @@ -8,10 +8,9 @@ import org.jetbrains.annotations.NotNull; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; -import top.r3944realms.lib39.core.event.FabricCommonEventHandler; import top.r3944realms.lib39.core.sync.ILib39SyncDataHolder; import top.r3944realms.lib39.core.sync.ISyncData; -import top.r3944realms.lib39.core.sync.NBTEntitySyncData; +import top.r3944realms.lib39.core.sync.NBTEntitySyncData;import top.r3944realms.lib39.platform.Services; import java.util.UUID; @@ -45,7 +44,7 @@ public abstract class MixinEntity implements ILib39SyncDataHolder { @WrapMethod(method = "saveWithoutId") private CompoundTag wrapSave(CompoundTag compound, @NotNull Operation original) { - FabricCommonEventHandler.getSyncData2Manager().forEach((id, manager) -> { + Services.PLATFORM.getUtilHelper().getSyncData2Manager().forEach((id, manager) -> { ISyncData o = manager.getSyncMap().get(getUUID()); if (o instanceof NBTEntitySyncData syncData) { saveSyncData(syncData); diff --git a/common/src/main/java/top/r3944realms/lib39/platform/services/IUtilHelper.java b/common/src/main/java/top/r3944realms/lib39/platform/services/IUtilHelper.java index acd5446..a4bbbb4 100644 --- a/common/src/main/java/top/r3944realms/lib39/platform/services/IUtilHelper.java +++ b/common/src/main/java/top/r3944realms/lib39/platform/services/IUtilHelper.java @@ -1,5 +1,6 @@ package top.r3944realms.lib39.platform.services; +import top.r3944realms.lib39.core.sync.SyncData2Manager; import top.r3944realms.lib39.util.block.BlockRegistryBuilder; /** @@ -12,4 +13,6 @@ public interface IUtilHelper { * @return the block registry builder */ BlockRegistryBuilder getBlockRegistryBuilder(); + + SyncData2Manager getSyncData2Manager(); } diff --git a/common/src/main/java/top/r3944realms/lib39/util/GameProfileHelper.java b/common/src/main/java/top/r3944realms/lib39/util/GameProfileHelper.java index 6fd77ab..6eb2c20 100644 --- a/common/src/main/java/top/r3944realms/lib39/util/GameProfileHelper.java +++ b/common/src/main/java/top/r3944realms/lib39/util/GameProfileHelper.java @@ -12,9 +12,11 @@ import net.minecraft.core.component.DataComponents; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtUtils; import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.Services; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.component.ResolvableProfile; +import net.minecraft.world.level.block.entity.SkullBlockEntity; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import top.r3944realms.lib39.Lib39; @@ -22,15 +24,65 @@ import top.r3944realms.lib39.util.nbt.NBTReader; import top.r3944realms.lib39.util.nbt.NBTWriter; import java.nio.charset.StandardCharsets; -import java.util.Base64; -import java.util.Collection; -import java.util.Objects; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicReference; /** * The type GameProfile helper. */ public class GameProfileHelper { + /** + * 异步获取 GameProfile(通过玩家名) + * 直接复用 SkullBlockEntity 的实现 + */ + public static CompletableFuture> fetchGameProfileByName(String name) { + return SkullBlockEntity.fetchGameProfile(name); + } + + /** + * 异步获取 GameProfile(通过 UUID) + * 直接复用 SkullBlockEntity 的实现 + */ + public static CompletableFuture> fetchGameProfileByUUID(UUID uuid) { + return SkullBlockEntity.fetchGameProfile(uuid); + } + + /** + * 异步获取 GameProfile(自动识别类型) + */ + @SuppressWarnings("unchecked") + public static CompletableFuture> fetchGameProfile(T identifier) { + if (identifier instanceof UUID uuid) { + return fetchGameProfileByUUID(uuid); + } else if (identifier instanceof String name) { + return fetchGameProfileByName(name); + } + return CompletableFuture.completedFuture(Optional.empty()); + } + + /** + * 从 ItemStack 异步获取完整的 GameProfile + * 需要配合 ResolvableProfile 使用 + */ + public static CompletableFuture> fetchProfileFromItemStack(@NotNull ItemStack stack) { + ResolvableProfile resolvable = stack.get(DataComponents.PROFILE); + if (resolvable == null) { + return CompletableFuture.completedFuture(Optional.empty()); + } + + // 如果已经有 UUID,直接用 SkullBlockEntity 的方法 + GameProfile profile = resolvable.gameProfile(); + if (profile != null && profile.getId() != null) { + return fetchGameProfileByUUID(profile.getId()); + } + + // 否则异步解析 + return resolvable.resolve().thenApply(resolved -> + Optional.ofNullable(resolved.gameProfile()) + ); + } /** * Client Only Class */ @@ -296,7 +348,7 @@ public class GameProfileHelper { * @return the profile from item stack */ @Nullable - public static GameProfile getProfileFromItemStack(ItemStack stack) { + public static ResolvableProfile getProfileFromItemStack(@NotNull ItemStack stack) { if (stack.isEmpty()) { return null; } @@ -304,7 +356,7 @@ public class GameProfileHelper { if (stack.isEmpty()) return null; ResolvableProfile profile = stack.get(DataComponents.PROFILE); - return profile != null ? profile.gameProfile() : null; + return profile != null ? profile : null; } /** @@ -313,13 +365,13 @@ public class GameProfileHelper { * @param stack the stack * @param profile the profile */ - public static void saveProfileToItemStack(@NotNull ItemStack stack, @Nullable GameProfile profile) { + public static void saveProfileToItemStack(@NotNull ItemStack stack, @Nullable ResolvableProfile profile) { if (stack.isEmpty()) return; if (profile == null) { stack.remove(DataComponents.PROFILE); } else { - stack.set(DataComponents.PROFILE, new ResolvableProfile(profile)); + stack.set(DataComponents.PROFILE, profile); } } diff --git a/common/src/main/java/top/r3944realms/lib39/util/nbt/NBTReader.java b/common/src/main/java/top/r3944realms/lib39/util/nbt/NBTReader.java index 1e24be4..4939fca 100644 --- a/common/src/main/java/top/r3944realms/lib39/util/nbt/NBTReader.java +++ b/common/src/main/java/top/r3944realms/lib39/util/nbt/NBTReader.java @@ -430,31 +430,67 @@ public class NBTReader { String name = null; UUID uuid = null; + // 支持 "Name" 或 "name" if (tag.contains("Name", CompoundTag.TAG_STRING)) { name = tag.getString("Name"); + } else if (tag.contains("name", CompoundTag.TAG_STRING)) { + name = tag.getString("name"); } + + // 支持 "Id" 或 "id" if (tag.hasUUID("Id")) { uuid = tag.getUUID("Id"); + } else if (tag.hasUUID("id")) { + uuid = tag.getUUID("id"); } try { GameProfile profile = new GameProfile(uuid, name); - if (tag.contains("Properties", CompoundTag.TAG_COMPOUND)) { - CompoundTag propertiesTag = tag.getCompound("Properties"); + // 支持 "Properties" 或 "properties",支持 COMPOUND 或 LIST 格式 + String propertiesKey = tag.contains("Properties", CompoundTag.TAG_COMPOUND) ? "Properties" + : (tag.contains("properties", CompoundTag.TAG_COMPOUND) ? "properties" : null); + + // 如果没有 COMPOUND,尝试 LIST 格式 + if (propertiesKey == null) { + String listKey = tag.contains("Properties", CompoundTag.TAG_LIST) ? "Properties" + : (tag.contains("properties", CompoundTag.TAG_LIST) ? "properties" : null); + if (listKey != null) { + ListTag propertiesList = tag.getList(listKey, CompoundTag.TAG_COMPOUND); + for (int i = 0; i < propertiesList.size(); i++) { + CompoundTag propTag = propertiesList.getCompound(i); + String propName = propTag.getString("name"); + String value = propTag.getString("value"); + String signature = propTag.contains("signature") ? propTag.getString("signature") : null; + + if (signature != null) { + profile.getProperties().put(propName, new Property(propName, value, signature)); + } else { + profile.getProperties().put(propName, new Property(propName, value)); + } + } + return profile; + } + } + + // COMPOUND 格式处理 + if (propertiesKey != null && tag.contains(propertiesKey, CompoundTag.TAG_COMPOUND)) { + CompoundTag propertiesTag = tag.getCompound(propertiesKey); for (String key : propertiesTag.getAllKeys()) { ListTag listTag = propertiesTag.getList(key, CompoundTag.TAG_COMPOUND); for (int i = 0; i < listTag.size(); i++) { CompoundTag propTag = listTag.getCompound(i); String value = propTag.getString("Value"); - if (propTag.contains("Signature", CompoundTag.TAG_STRING)) { - profile.getProperties().put(key, new Property(key, value, propTag.getString("Signature"))); + String signature = propTag.contains("Signature") ? propTag.getString("Signature") : null; + if (signature != null) { + profile.getProperties().put(key, new Property(key, value, signature)); } else { profile.getProperties().put(key, new Property(key, value)); } } } } + return profile; } catch (Throwable e) { return null; diff --git a/common/src/main/resources/assets/lib39/shaders/core/ring.fsh b/common/src/main/resources/assets/lib39/shaders/core/ring.fsh index 39aa703..ff40964 100644 --- a/common/src/main/resources/assets/lib39/shaders/core/ring.fsh +++ b/common/src/main/resources/assets/lib39/shaders/core/ring.fsh @@ -16,9 +16,7 @@ void main() { // 确保内外半径合理 if (OuterRadius <= InnerRadius) { - vec4 color = vertexColor; - color.a = 0; - fragColor = color; + discard; // ✅ 直接丢弃片段,不需要设置颜色 } // 计算环形 alpha @@ -28,20 +26,20 @@ void main() { // 内边缘抗锯齿 if (dist < InnerRadius + AntiAliasing) { float fade = (dist - InnerRadius) / AntiAliasing; - alpha *= fade; + alpha *= clamp(fade, 0.0, 1.0); // ✅ 确保值在 [0,1] 范围内 } // 外边缘抗锯齿 if (dist > OuterRadius - AntiAliasing) { float fade = 1.0 - (dist - (OuterRadius - AntiAliasing)) / AntiAliasing; - alpha *= fade; + alpha *= clamp(fade, 0.0, 1.0); // ✅ 确保值在 [0,1] 范围内 } } vec4 color = vertexColor; - color.a *= alpha; + color.a = color.a * alpha; // ✅ 修正语法 - if (alpha > 0.0) { + if (color.a > 0.0) { fragColor = color * ColorModulator; } else { discard; diff --git a/common/src/main/resources/assets/lib39/shaders/core/selection.fsh b/common/src/main/resources/assets/lib39/shaders/core/selection.fsh index 27e9904..057dab9 100644 --- a/common/src/main/resources/assets/lib39/shaders/core/selection.fsh +++ b/common/src/main/resources/assets/lib39/shaders/core/selection.fsh @@ -6,7 +6,6 @@ uniform vec4 ColorModulator; uniform vec2 FramebufferSize; uniform vec2 Center; uniform float Radius; -uniform float AntiAliasingRadius; out vec4 fragColor; diff --git a/common/src/main/resources/assets/lib39/shaders/core/selection.json b/common/src/main/resources/assets/lib39/shaders/core/selection.json index b9a2e52..b092bac 100644 --- a/common/src/main/resources/assets/lib39/shaders/core/selection.json +++ b/common/src/main/resources/assets/lib39/shaders/core/selection.json @@ -32,14 +32,6 @@ "values": [ 0.0 ] - }, - { - "name": "AntiAliasingRadius", - "type": "float", - "count": 1, - "values": [ - 1.5 - ] } ] } \ No newline at end of file diff --git a/common/src/main/resources/lib39.mixins.json b/common/src/main/resources/lib39.mixins.json index 8d7f422..3858be5 100644 --- a/common/src/main/resources/lib39.mixins.json +++ b/common/src/main/resources/lib39.mixins.json @@ -6,6 +6,7 @@ "compatibilityLevel": "JAVA_21", "mixins": [ "carryon.MixinCarriedObjectRender", + "minecraft.MixinEntity", "minecraft.CreativeModeTabsAccessor" ], "client": [ diff --git a/fabric/src/main/java/top/r3944realms/lib39/base/compat/jade/provider/FabricDollComponentProvider.java b/fabric/src/main/java/top/r3944realms/lib39/base/compat/jade/provider/FabricDollComponentProvider.java index ee4ce31..13135fb 100644 --- a/fabric/src/main/java/top/r3944realms/lib39/base/compat/jade/provider/FabricDollComponentProvider.java +++ b/fabric/src/main/java/top/r3944realms/lib39/base/compat/jade/provider/FabricDollComponentProvider.java @@ -23,10 +23,14 @@ public class FabricDollComponentProvider implements IBlockComponentProvider { @Override public void appendTooltip(ITooltip iTooltip, @NotNull BlockAccessor blockAccessor, IPluginConfig iPluginConfig) { if (blockAccessor.getBlockEntity() instanceof DollBlockEntity doll) { - GameProfile ownerProfile = doll.getOwnerProfile(); - if (ownerProfile != null) { - iTooltip.add(Component.translatable("tooltip.lib39.content.doll.hover.1", ownerProfile.getName())); + GameProfile ownerProfile; + if (doll.getOwnerProfile() != null) { + ownerProfile = doll.getOwnerProfile().gameProfile(); + if (ownerProfile != null) { + iTooltip.add(Component.translatable("tooltip.lib39.content.doll.hover.1", ownerProfile.getName())); + } } + } } } diff --git a/fabric/src/main/java/top/r3944realms/lib39/core/event/FabricCommonEventHandler.java b/fabric/src/main/java/top/r3944realms/lib39/core/event/FabricCommonEventHandler.java index f4a7f2e..aa448c6 100644 --- a/fabric/src/main/java/top/r3944realms/lib39/core/event/FabricCommonEventHandler.java +++ b/fabric/src/main/java/top/r3944realms/lib39/core/event/FabricCommonEventHandler.java @@ -14,6 +14,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; +import net.minecraft.server.Services; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; import net.minecraft.world.item.CreativeModeTab; @@ -25,10 +26,13 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.SkullBlockEntity; import org.jetbrains.annotations.NotNull; import top.r3944realms.lib39.Lib39; +import top.r3944realms.lib39.api.callback.ActionResult; import top.r3944realms.lib39.api.callback.AnvilUpdateCallback; +import top.r3944realms.lib39.api.callback.MinecraftSetUpServiceCallback; import top.r3944realms.lib39.api.callback.SyncManagerRegisterCallback; import top.r3944realms.lib39.api.callback.client.ClientWorldCallback; import top.r3944realms.lib39.base.command.Lib39HelpCommand; +import top.r3944realms.lib39.content.block.blockentity.DollBlockEntity; import top.r3944realms.lib39.content.item.DollItem; import top.r3944realms.lib39.core.register.Lib39Items; import top.r3944realms.lib39.core.sync.ISyncData; @@ -44,6 +48,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; import java.util.function.Supplier; /** @@ -183,31 +188,35 @@ public class FabricCommonEventHandler { for (Map.Entry, List>> resourceKeyListEntry : tabToItemsMap.entrySet()) { ItemGroupEvents.modifyEntriesEvent(resourceKeyListEntry.getKey()).register(content -> resourceKeyListEntry.getValue().forEach(i -> content.accept(i.get()))); } + MinecraftSetUpServiceCallback.EVENT.register((services, mainThreadExecutor) -> { + DollBlockEntity.setup(services, mainThreadExecutor); + return ActionResult.SUCCESS; + }); AnvilUpdateCallback.EVENT.register((left, right, outputSlot, name, baseCost, player) -> { - if (left.getItem() instanceof DollItem && name != null && name.length() < 15) { - // 创建 GameProfile(使用 NIL_UUID 临时占位) + if (left.getItem() instanceof DollItem && name != null && !name.isEmpty() && name.length() <= 16) { + ItemStack output = Lib39Items.DOLL.get().getDefaultInstance(); + output.setCount(left.getCount()); + + // 创建 ResolvableProfile GameProfile profile = new GameProfile(Util.NIL_UUID, name); - ItemStack copied = Lib39Items.DOLL.get().getDefaultInstance(); - copied.setCount(left.getCount()); - - // 使用 ResolvableProfile 进行异步解析 ResolvableProfile resolvableProfile = new ResolvableProfile(profile); - if (!resolvableProfile.isResolved()) { - resolvableProfile.resolve().thenAcceptAsync(resolved -> { - // 解析完成后保存到 ItemStack - GameProfile resolvedProfile = resolved.gameProfile(); - GameProfileHelper.saveProfileToItemStack(copied, resolvedProfile); - }, player.getServer()); - } else { - GameProfileHelper.saveProfileToItemStack(copied, profile); - } + output.set(DataComponents.PROFILE, resolvableProfile); - return AnvilUpdateCallback.AnvilUpdateResult.withOutput(copied, 1, 1); + // 使用 DollBlockEntity 的缓存异步获取完整档案 + DollBlockEntity.fetchGameProfile(name).thenAcceptAsync(optional -> { + optional.ifPresent(fullProfile -> { + output.set(DataComponents.PROFILE, new ResolvableProfile(fullProfile)); + }); + }, SkullBlockEntity.CHECKED_MAIN_THREAD_EXECUTOR); + + return AnvilUpdateCallback.AnvilUpdateResult.withOutput(output, 1, 1); + } else if (name == null || name.isEmpty()) { + return AnvilUpdateCallback.AnvilUpdateResult.withOutput(ItemStack.EMPTY, 0, 0); } else { - ItemStack defaultInstance = Items.BARRIER.getDefaultInstance(); - defaultInstance.set(DataComponents.CUSTOM_NAME, + ItemStack errorOutput = Items.BARRIER.getDefaultInstance(); + errorOutput.set(DataComponents.CUSTOM_NAME, Component.translatable("invalid.player_name.too_long")); - return AnvilUpdateCallback.AnvilUpdateResult.withOutput(defaultInstance, 0, 0); + return AnvilUpdateCallback.AnvilUpdateResult.withOutput(errorOutput, 0, 0); } }); EntityApiLookup.get(FabricTestSyncData.ID, AbstractedTestSyncData.class, Void.class) diff --git a/fabric/src/main/java/top/r3944realms/lib39/example/content/data/FabricTestSyncData.java b/fabric/src/main/java/top/r3944realms/lib39/example/content/data/FabricTestSyncData.java index ca3bcfc..a6006ce 100644 --- a/fabric/src/main/java/top/r3944realms/lib39/example/content/data/FabricTestSyncData.java +++ b/fabric/src/main/java/top/r3944realms/lib39/example/content/data/FabricTestSyncData.java @@ -290,8 +290,8 @@ public class FabricTestSyncData extends AbstractedTestSyncData implements IFabri } @Override - public void deserializeNBT(CompoundTag nbt) { - NBTReader.of(nbt) + public void deserializeNBT(CompoundTag t) { + NBTReader.of(t) .intValue(NBT_KEY_INT, integer -> testInt = integer) .string(NBT_KEY_STRING, string -> testString = string) .booleanValue(NBT_KEY_BOOLEAN, bool -> testBoolean = bool) diff --git a/fabric/src/main/java/top/r3944realms/lib39/example/core/network/FabricExNetworkHandler.java b/fabric/src/main/java/top/r3944realms/lib39/example/core/network/FabricExNetworkHandler.java index ac4f435..0a1d75e 100644 --- a/fabric/src/main/java/top/r3944realms/lib39/example/core/network/FabricExNetworkHandler.java +++ b/fabric/src/main/java/top/r3944realms/lib39/example/core/network/FabricExNetworkHandler.java @@ -1,5 +1,6 @@ package top.r3944realms.lib39.example.core.network; +import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; /** @@ -10,6 +11,10 @@ public class FabricExNetworkHandler { * 注册服务器接收的数据包 */ public static void registerServerReceivers() { + PayloadTypeRegistry.playC2S().register( + FabricClientDataPacket.TYPE, + FabricClientDataPacket.STREAM_CODEC + ); ServerPlayNetworking.registerGlobalReceiver( FabricClientDataPacket.TYPE, FabricClientDataPacket::handle diff --git a/fabric/src/main/java/top/r3944realms/lib39/platform/FabricUtilHelper.java b/fabric/src/main/java/top/r3944realms/lib39/platform/FabricUtilHelper.java index 810881c..a27dc9b 100644 --- a/fabric/src/main/java/top/r3944realms/lib39/platform/FabricUtilHelper.java +++ b/fabric/src/main/java/top/r3944realms/lib39/platform/FabricUtilHelper.java @@ -1,5 +1,7 @@ package top.r3944realms.lib39.platform; +import top.r3944realms.lib39.core.event.FabricCommonEventHandler; +import top.r3944realms.lib39.core.sync.SyncData2Manager; import top.r3944realms.lib39.platform.services.IUtilHelper; import top.r3944realms.lib39.util.FabricBlockRegistryBuilder; import top.r3944realms.lib39.util.block.BlockRegistryBuilder; @@ -16,4 +18,9 @@ public enum FabricUtilHelper implements IUtilHelper { public BlockRegistryBuilder getBlockRegistryBuilder() { return new FabricBlockRegistryBuilder(); } + + @Override + public SyncData2Manager getSyncData2Manager() { + return FabricCommonEventHandler.getSyncData2Manager(); + } } diff --git a/fabric/src/main/resources/lib39.fabric.mixins.json b/fabric/src/main/resources/lib39.fabric.mixins.json index 87d55de..6868856 100644 --- a/fabric/src/main/resources/lib39.fabric.mixins.json +++ b/fabric/src/main/resources/lib39.fabric.mixins.json @@ -6,7 +6,6 @@ "compatibilityLevel": "JAVA_18", "mixins": [ "MixinApiLookUpImpl", - "MixinEntity", "callback.MixinAnvilMenu" ], "client": [ diff --git a/neoforge/build.gradle b/neoforge/build.gradle index eb20fbc..a09104c 100644 --- a/neoforge/build.gradle +++ b/neoforge/build.gradle @@ -65,13 +65,12 @@ sourceSets.main.resources.srcDir project(':common').file('src/generated/resource dependencies { compileOnly project(":common") - annotationProcessor("org.spongepowered:mixin:0.8.5-SNAPSHOT:processor") implementation(annotationProcessor("io.github.llamalad7:mixinextras-common:0.2.0")) implementation(group: 'tschipp.carryon', name: 'carryon-neoforge-1.21.1', version: '2.2.4.4') { transitive = false } implementation "curse.maven:jade-324717:7545219" - implementation(jarJar("io.github.llamalad7:mixinextras-forge:0.2.0")) + } // 配置sourceJar任务 diff --git a/neoforge/src/main/java/top/r3944realms/lib39/base/compat/jade/provider/NeoForgeDollComponentProvider.java b/neoforge/src/main/java/top/r3944realms/lib39/base/compat/jade/provider/NeoForgeDollComponentProvider.java index 947fced..212722f 100644 --- a/neoforge/src/main/java/top/r3944realms/lib39/base/compat/jade/provider/NeoForgeDollComponentProvider.java +++ b/neoforge/src/main/java/top/r3944realms/lib39/base/compat/jade/provider/NeoForgeDollComponentProvider.java @@ -24,9 +24,12 @@ public class NeoForgeDollComponentProvider implements IBlockComponentProvider { @Override public void appendTooltip(ITooltip iTooltip, @NotNull BlockAccessor blockAccessor, IPluginConfig iPluginConfig) { if (blockAccessor.getBlockEntity() instanceof DollBlockEntity doll) { - GameProfile ownerProfile = doll.getOwnerProfile(); - if (ownerProfile != null) { - iTooltip.add(Component.translatable("tooltip.lib39.content.doll.hover.1", ownerProfile.getName())); + GameProfile ownerProfile; + if (doll.getOwnerProfile() != null) { + ownerProfile = doll.getOwnerProfile().gameProfile(); + if (ownerProfile != null) { + iTooltip.add(Component.translatable("tooltip.lib39.content.doll.hover.1", ownerProfile.getName())); + } } } } diff --git a/neoforge/src/main/java/top/r3944realms/lib39/base/datagen/Lib39BaseDataGenEvent.java b/neoforge/src/main/java/top/r3944realms/lib39/base/datagen/Lib39BaseDataGenEvent.java index a1bf089..aa5cb62 100644 --- a/neoforge/src/main/java/top/r3944realms/lib39/base/datagen/Lib39BaseDataGenEvent.java +++ b/neoforge/src/main/java/top/r3944realms/lib39/base/datagen/Lib39BaseDataGenEvent.java @@ -13,6 +13,8 @@ import top.r3944realms.lib39.datagen.provider.SimpleLootTableProvider; import top.r3944realms.lib39.datagen.provider.SubProvidersWrapper; import top.r3944realms.lib39.datagen.value.McLocale; +import java.util.concurrent.ExecutionException; + /** * The type Lib 39 base data gen event. */ @@ -73,7 +75,14 @@ public class Lib39BaseDataGenEvent { private static void LootTableDataGenerate(@NotNull GatherDataEvent event) { event.getGenerator().addProvider( event.includeServer(), - (DataProvider.Factory) pOutput -> new SimpleLootTableProvider(pOutput, new SubProvidersWrapper().addBlockEntry(new Lib39BlockLootTable()), event.getLookupProvider()) + (DataProvider.Factory) pOutput -> { + try { + return new SimpleLootTableProvider(pOutput, new SubProvidersWrapper().addBlockEntry(new Lib39BlockLootTable(event.getLookupProvider())), event.getLookupProvider()); + } catch (Exception e) { + logger.error("Failed to generate loot_table",e); + throw new RuntimeException(e); + } + } ); } private static void RecipeGenerator(@NotNull GatherDataEvent event) { diff --git a/neoforge/src/main/java/top/r3944realms/lib39/base/datagen/provider/Lib39BlockLootTable.java b/neoforge/src/main/java/top/r3944realms/lib39/base/datagen/provider/Lib39BlockLootTable.java index 33bb65c..841048f 100644 --- a/neoforge/src/main/java/top/r3944realms/lib39/base/datagen/provider/Lib39BlockLootTable.java +++ b/neoforge/src/main/java/top/r3944realms/lib39/base/datagen/provider/Lib39BlockLootTable.java @@ -1,9 +1,13 @@ package top.r3944realms.lib39.base.datagen.provider; +import net.minecraft.core.HolderLookup; import top.r3944realms.lib39.core.register.NeoForgeLib39Blocks; import top.r3944realms.lib39.core.register.Lib39Blocks; import top.r3944realms.lib39.datagen.provider.subprovider.BlockLootTables; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + /** * The type Lib 39 block loot table. */ @@ -11,8 +15,8 @@ public class Lib39BlockLootTable extends BlockLootTables { /** * Instantiates a new Lib 39 block loot table. */ - public Lib39BlockLootTable() { - super(NeoForgeLib39Blocks.BLOCKS); + public Lib39BlockLootTable(CompletableFuture registries) throws ExecutionException, InterruptedException { + super(NeoForgeLib39Blocks.BLOCKS, registries.get()); dropSelf(Lib39Blocks.DOLL, Lib39Blocks.WALL_DOLL); } } diff --git a/neoforge/src/main/java/top/r3944realms/lib39/core/event/CommonEventHandler.java b/neoforge/src/main/java/top/r3944realms/lib39/core/event/CommonEventHandler.java index 2c4395f..5532c17 100644 --- a/neoforge/src/main/java/top/r3944realms/lib39/core/event/CommonEventHandler.java +++ b/neoforge/src/main/java/top/r3944realms/lib39/core/event/CommonEventHandler.java @@ -9,7 +9,6 @@ import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; @@ -17,6 +16,7 @@ import net.minecraft.world.item.component.ResolvableProfile; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.SkullBlockEntity; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.common.EventBusSubscriber; import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent; @@ -30,10 +30,13 @@ import net.neoforged.neoforge.event.entity.EntityLeaveLevelEvent; import net.neoforged.neoforge.event.level.LevelEvent; import net.neoforged.neoforge.event.tick.ServerTickEvent; import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent; +import org.jetbrains.annotations.NotNull; import top.r3944realms.lib39.Lib39; +import top.r3944realms.lib39.api.event.MinecraftSetUpServiceEvent; import top.r3944realms.lib39.api.event.SyncManagerRegisterEvent; import top.r3944realms.lib39.base.command.Lib39HelpCommand; import top.r3944realms.lib39.base.datagen.Lib39BaseDataGenEvent; +import top.r3944realms.lib39.content.block.blockentity.DollBlockEntity; import top.r3944realms.lib39.content.item.DollItem; import top.r3944realms.lib39.core.network.NetworkHandler; import top.r3944realms.lib39.core.register.Lib39Items; @@ -153,31 +156,45 @@ public class CommonEventHandler { public static void onAnvilRename(AnvilUpdateEvent event) { if (event.getLeft().getItem() instanceof DollItem) { String name = event.getName(); - Player player = event.getPlayer(); - if (name != null && name.length() < 15) { - GameProfile profile = new GameProfile(Util.NIL_UUID, name); - ItemStack copied = Lib39Items.DOLL.get().getDefaultInstance(); - ResolvableProfile resolvableProfile = new ResolvableProfile(profile); - if (!resolvableProfile.isResolved()) { - resolvableProfile.resolve().thenAcceptAsync(resolved -> { - // 解析完成后保存到 ItemStack - GameProfile resolvedProfile = resolved.gameProfile(); - GameProfileHelper.saveProfileToItemStack(copied, resolvedProfile); - }, player.getServer()); + + if (name != null && !name.isEmpty()) { + if (name.length() <= 16) { + ItemStack output = Lib39Items.DOLL.get().getDefaultInstance(); + output.setCount(event.getLeft().getCount()); + + // 创建 ResolvableProfile + GameProfile profile = new GameProfile(Util.NIL_UUID, name); + ResolvableProfile resolvableProfile = new ResolvableProfile(profile); + output.set(DataComponents.PROFILE, resolvableProfile); + + // 使用 DollBlockEntity 的缓存异步获取完整档案 + DollBlockEntity.fetchGameProfile(name).thenAcceptAsync(optional -> { + optional.ifPresent(fullProfile -> { + // 更新为完整的 ResolvableProfile + output.set(DataComponents.PROFILE, new ResolvableProfile(fullProfile)); + }); + }, SkullBlockEntity.CHECKED_MAIN_THREAD_EXECUTOR); + + event.setOutput(output); + event.setCost(1); + event.setMaterialCost(1); } else { - GameProfileHelper.saveProfileToItemStack(copied, profile); + ItemStack errorOutput = Items.BARRIER.getDefaultInstance(); + errorOutput.set(DataComponents.CUSTOM_NAME, + Component.translatable("invalid.player_name.too_long")); + event.setOutput(errorOutput); + event.setCost(0); } - copied.setCount(event.getLeft().getCount()); - event.setOutput(copied); - event.setCost(1); } else { - ItemStack defaultInstance = Items.BARRIER.getDefaultInstance(); - defaultInstance.set(DataComponents.CUSTOM_NAME, - Component.translatable("invalid.player_name.too_long")); - event.setOutput(defaultInstance); + event.setOutput(ItemStack.EMPTY); + event.setCost(0); } } } + @SubscribeEvent + public static void onMinecraftSetUpService (@NotNull MinecraftSetUpServiceEvent event) { + DollBlockEntity.setup(event.services, event.mainThreadExecutor); + } /** * On entity join world. diff --git a/neoforge/src/main/java/top/r3944realms/lib39/core/sync/SyncCapProvider.java b/neoforge/src/main/java/top/r3944realms/lib39/core/sync/SyncCapProvider.java new file mode 100644 index 0000000..e69dcf8 --- /dev/null +++ b/neoforge/src/main/java/top/r3944realms/lib39/core/sync/SyncCapProvider.java @@ -0,0 +1,54 @@ +package top.r3944realms.lib39.core.sync; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.Entity; +import net.neoforged.neoforge.capabilities.ICapabilityProvider; +import org.jetbrains.annotations.Nullable; +import top.r3944realms.lib39.platform.Services; + +/** + * NeoForge 版本的能力提供者 + * + * @param 同步数据类型,必须继承 NBTEntitySyncData + */ +public abstract class SyncCapProvider implements ICapabilityProvider { + /** + * 创建空的能力实例 + * 当管理器中不存在数据时调用 + * + * @param entity 实体 + * @return 空的能力实例 + */ + protected abstract T createEmptyCapability(Entity entity); + + /** + * 获取能力对应的 ID + * + * @return 能力 ID + */ + protected abstract ResourceLocation getId(); + + @SuppressWarnings("unchecked") + @Override + public @Nullable T getCapability(Entity holder, Void context) { + // 从管理器中获取对应的管理器 + return Services.PLATFORM.getUtilHelper().getSyncData2Manager().getManager(getId()) + .map(manager -> { + // 从管理器的同步映射中获取数据 + ISyncData syncData = manager.getSyncMap().get(holder.getUUID()); + if (syncData instanceof NBTEntitySyncData nbtSyncData) { + return (T) nbtSyncData; + } + // 不存在则创建空实例 + T defaultCap = createEmptyCapability(holder); + // 加载已有的同步数据(如果有) + if (holder instanceof ILib39SyncDataHolder syncHolder) { + syncHolder.loadSyncData(defaultCap); + } + // 注册到管理器 + manager.getSyncMap().put(holder.getUUID(), defaultCap); + return defaultCap; + }) + .orElseGet(() -> createEmptyCapability(holder)); + } +} diff --git a/neoforge/src/main/java/top/r3944realms/lib39/example/content/data/ExCapabilityHandler.java b/neoforge/src/main/java/top/r3944realms/lib39/example/content/data/ExCapabilityHandler.java index 5528f5d..389159d 100644 --- a/neoforge/src/main/java/top/r3944realms/lib39/example/content/data/ExCapabilityHandler.java +++ b/neoforge/src/main/java/top/r3944realms/lib39/example/content/data/ExCapabilityHandler.java @@ -27,22 +27,23 @@ public class ExCapabilityHandler { * @param event the event */ public static void registerCapability(@NotNull RegisterCapabilitiesEvent event) { + TestSyncCapProvider provider = new TestSyncCapProvider(); EntityCapabilityHelper.registerForEntityClass( event, TEST_CAP, - (entity, context) -> entity.getCapability(TEST_CAP), + provider, LivingEntity.class ); EntityCapabilityHelper.registerForEntityClass( event, TEST_CAP, - (entity, context) -> entity.getCapability(TEST_CAP), + provider, Boat.class ); EntityCapabilityHelper.registerForEntityClass( event, TEST_CAP, - (entity, context) -> entity.getCapability(TEST_CAP), + provider, Minecart.class ); } diff --git a/neoforge/src/main/java/top/r3944realms/lib39/example/content/data/TestSyncCapProvider.java b/neoforge/src/main/java/top/r3944realms/lib39/example/content/data/TestSyncCapProvider.java new file mode 100644 index 0000000..cddef07 --- /dev/null +++ b/neoforge/src/main/java/top/r3944realms/lib39/example/content/data/TestSyncCapProvider.java @@ -0,0 +1,20 @@ +package top.r3944realms.lib39.example.content.data; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.Entity; +import top.r3944realms.lib39.Lib39; +import top.r3944realms.lib39.core.sync.SyncCapProvider; + +public class TestSyncCapProvider extends SyncCapProvider { + + @Override + protected TestSyncData createEmptyCapability(Entity entity) { + return new TestSyncData(entity.getId(), entity); + } + + @Override + protected ResourceLocation getId() { + return Lib39.rl("test_data"); + } + +} diff --git a/neoforge/src/main/java/top/r3944realms/lib39/example/content/data/TestSyncData.java b/neoforge/src/main/java/top/r3944realms/lib39/example/content/data/TestSyncData.java index 79e80f1..3feee00 100644 --- a/neoforge/src/main/java/top/r3944realms/lib39/example/content/data/TestSyncData.java +++ b/neoforge/src/main/java/top/r3944realms/lib39/example/content/data/TestSyncData.java @@ -287,8 +287,8 @@ public class TestSyncData extends AbstractedTestSyncData implements INeoForgeUpd } @Override - public void deserializeNBT(CompoundTag nbt) { - NBTReader.of(nbt) + public void deserializeNBT(CompoundTag t) { + NBTReader.of(t) .intValue(NBT_KEY_INT, integer -> testInt = integer) .string(NBT_KEY_STRING, string -> testString = string) .booleanValue(NBT_KEY_BOOLEAN, bool -> testBoolean = bool) diff --git a/neoforge/src/main/java/top/r3944realms/lib39/platform/NeoForgeUtilHelper.java b/neoforge/src/main/java/top/r3944realms/lib39/platform/NeoForgeUtilHelper.java index d9ffd02..b8dc4bf 100644 --- a/neoforge/src/main/java/top/r3944realms/lib39/platform/NeoForgeUtilHelper.java +++ b/neoforge/src/main/java/top/r3944realms/lib39/platform/NeoForgeUtilHelper.java @@ -1,5 +1,9 @@ package top.r3944realms.lib39.platform; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import top.r3944realms.lib39.core.event.CommonEventHandler; +import top.r3944realms.lib39.core.sync.SyncData2Manager; import top.r3944realms.lib39.platform.services.IUtilHelper; import top.r3944realms.lib39.util.NeoForgeBlockRegistryBuilder; import top.r3944realms.lib39.util.block.BlockRegistryBuilder; @@ -12,8 +16,14 @@ public enum NeoForgeUtilHelper implements IUtilHelper { * Instance forge util helper. */ INSTANCE; + @Contract(value = " -> new", pure = true) @Override - public BlockRegistryBuilder getBlockRegistryBuilder() { + public @NotNull BlockRegistryBuilder getBlockRegistryBuilder() { return new NeoForgeBlockRegistryBuilder(); } + + @Override + public SyncData2Manager getSyncData2Manager() { + return CommonEventHandler.Game.getSyncData2Manager(); + } }