feat: 测试下来,1.21.1总体逻辑没问题
This commit is contained in:
parent
fbaeaf857b
commit
805d880ed9
|
|
@ -24,8 +24,8 @@ dependencies {
|
||||||
transitive = false
|
transitive = false
|
||||||
}
|
}
|
||||||
// fabric and neoforge both bundle mixinextras, so it is safe to use it in common
|
// 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'
|
implementation group: 'io.github.llamalad7', name: 'mixinextras-common', version: '0.4.1'
|
||||||
annotationProcessor group: 'io.github.llamalad7', name: 'mixinextras-common', version: '0.3.5'
|
annotationProcessor group: 'io.github.llamalad7', name: 'mixinextras-common', version: '0.4.1'
|
||||||
}
|
}
|
||||||
configurations {
|
configurations {
|
||||||
commonJava {
|
commonJava {
|
||||||
|
|
|
||||||
|
|
@ -587,6 +587,7 @@ public class WheelWidget extends AbstractWidget {
|
||||||
PoseStack poseStack = guiGraphics.pose();
|
PoseStack poseStack = guiGraphics.pose();
|
||||||
poseStack.pushPose();
|
poseStack.pushPose();
|
||||||
|
|
||||||
|
setupRingShader(centerX, centerY, innerRadius, outerRadius);
|
||||||
Tesselator tesselator = Tesselator.getInstance();
|
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, y2, -300).setColor(color);
|
||||||
buffer.addVertex(matrix, x2, y1, -300).setColor(color);
|
buffer.addVertex(matrix, x2, y1, -300).setColor(color);
|
||||||
|
|
||||||
setupRingShader(centerX, centerY, innerRadius, outerRadius);
|
|
||||||
|
|
||||||
BufferUploader.drawWithShader(buffer.build());
|
BufferUploader.drawWithShader(buffer.build());
|
||||||
|
RenderSystem.setShader(() -> null);
|
||||||
poseStack.popPose();
|
poseStack.popPose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -721,9 +721,6 @@ public class WheelWidget extends AbstractWidget {
|
||||||
Lib39Shaders.getSelectionShader()
|
Lib39Shaders.getSelectionShader()
|
||||||
.safeGetUniform("Radius")
|
.safeGetUniform("Radius")
|
||||||
.set(radius * guiScale);
|
.set(radius * guiScale);
|
||||||
Lib39Shaders.getSelectionShader()
|
|
||||||
.safeGetUniform("AntiAliasingRadius")
|
|
||||||
.set(guiScale); // 根据需要调整
|
|
||||||
RenderSystem.setShaderColor(1, 1, 1, 1);
|
RenderSystem.setShaderColor(1, 1, 1, 1);
|
||||||
BufferUploader.drawWithShader(Objects.requireNonNull(buffer.build()));
|
BufferUploader.drawWithShader(Objects.requireNonNull(buffer.build()));
|
||||||
RenderSystem.enableDepthTest();
|
RenderSystem.enableDepthTest();
|
||||||
|
|
|
||||||
|
|
@ -4,25 +4,32 @@ import com.mojang.authlib.GameProfile;
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||||
import com.mojang.math.Axis;
|
import com.mojang.math.Axis;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.renderer.MultiBufferSource;
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
import net.minecraft.client.renderer.RenderType;
|
import net.minecraft.client.renderer.RenderType;
|
||||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
|
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
|
||||||
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
||||||
import net.minecraft.client.renderer.texture.OverlayTexture;
|
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.core.Direction;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
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.SkullBlock;
|
||||||
import net.minecraft.world.level.block.WallSkullBlock;
|
import net.minecraft.world.level.block.WallSkullBlock;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.block.state.properties.RotationSegment;
|
import net.minecraft.world.level.block.state.properties.RotationSegment;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
import top.r3944realms.lib39.client.model.DollModel;
|
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.AbstractDollBlock;
|
||||||
import top.r3944realms.lib39.content.block.WallDollBlock;
|
import top.r3944realms.lib39.content.block.WallDollBlock;
|
||||||
import top.r3944realms.lib39.content.block.blockentity.DollBlockEntity;
|
import top.r3944realms.lib39.content.block.blockentity.DollBlockEntity;
|
||||||
import top.r3944realms.lib39.util.lang.Pair;
|
import top.r3944realms.lib39.util.lang.Pair;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type Doll block entity renderer.
|
* The type Doll block entity renderer.
|
||||||
*/
|
*/
|
||||||
|
|
@ -45,16 +52,43 @@ public class DollBlockEntityRenderer implements BlockEntityRenderer<DollBlockEnt
|
||||||
boolean isWall = dollBlock instanceof WallDollBlock;
|
boolean isWall = dollBlock instanceof WallDollBlock;
|
||||||
Direction direction = isWall ? blockState.getValue(WallSkullBlock.FACING) : null;
|
Direction direction = isWall ? blockState.getValue(WallSkullBlock.FACING) : null;
|
||||||
float rotation = isWall ? direction.toYRot() : RotationSegment.convertToDegrees(blockState.getValue(SkullBlock.ROTATION));
|
float rotation = isWall ? direction.toYRot() : RotationSegment.convertToDegrees(blockState.getValue(SkullBlock.ROTATION));
|
||||||
GameProfile profile = dollBlockEntity.getOwnerProfile();
|
Pair<PlayerSkin.Model, RenderType> modelAndRenderTypePair = getModelAndRenderTypePair(dollBlockEntity.getOwnerProfile());
|
||||||
Pair<ResourceLocation, Boolean> resourceLocationBooleanPair = DollItemRenderer.loadSkin(profile);
|
|
||||||
poseStack.pushPose();
|
poseStack.pushPose();
|
||||||
poseStack.translate(0.5, 1.5, 0.5);
|
poseStack.translate(0.5, 1.5, 0.5);
|
||||||
poseStack.scale(1.0F, -1.0F, -1.0F);
|
poseStack.scale(1.0F, -1.0F, -1.0F);
|
||||||
poseStack.mulPose(Axis.YP.rotationDegrees(rotation));
|
poseStack.mulPose(Axis.YP.rotationDegrees(rotation));
|
||||||
VertexConsumer vertexConsumer = buffer.getBuffer(RenderType.entityTranslucent(resourceLocationBooleanPair.first));
|
VertexConsumer vertexConsumer = buffer.getBuffer(modelAndRenderTypePair.second);
|
||||||
this.dollModel.slim = resourceLocationBooleanPair.second;
|
this.dollModel.slim = modelAndRenderTypePair.first == PlayerSkin.Model.SLIM;
|
||||||
this.dollModel.renderToBuffer(poseStack, vertexConsumer, packedLight, OverlayTexture.NO_OVERLAY,-1);
|
this.dollModel.renderToBuffer(poseStack, vertexConsumer, packedLight, OverlayTexture.NO_OVERLAY,-1);
|
||||||
poseStack.popPose();
|
poseStack.popPose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public static @NotNull Pair<PlayerSkin.Model, RenderType> 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<GameProfile> 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()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,11 @@ import net.minecraft.client.renderer.RenderType;
|
||||||
import net.minecraft.client.resources.DefaultPlayerSkin;
|
import net.minecraft.client.resources.DefaultPlayerSkin;
|
||||||
import net.minecraft.client.resources.PlayerSkin;
|
import net.minecraft.client.resources.PlayerSkin;
|
||||||
import net.minecraft.client.resources.SkinManager;
|
import net.minecraft.client.resources.SkinManager;
|
||||||
|
import net.minecraft.core.component.DataComponents;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.world.item.ItemDisplayContext;
|
import net.minecraft.world.item.ItemDisplayContext;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.component.ResolvableProfile;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import top.r3944realms.lib39.Lib39;
|
import top.r3944realms.lib39.Lib39;
|
||||||
import top.r3944realms.lib39.client.model.DollModel;
|
import top.r3944realms.lib39.client.model.DollModel;
|
||||||
|
|
@ -62,55 +64,44 @@ public class DollItemRenderer extends BlockEntityWithoutLevelRenderer {
|
||||||
}
|
}
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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)) {
|
if (!(stack.getItem() instanceof DollItem)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
lazyInit();
|
lazyInit();
|
||||||
GameProfile profile = GameProfileHelper.getProfileFromItemStack(stack);
|
|
||||||
Pair<ResourceLocation, Boolean> resourceLocationBooleanPair = loadSkin(profile);
|
// 直接从 DataComponents.PROFILE 获取 ResolvableProfile
|
||||||
ResourceLocation playerSkin = resourceLocationBooleanPair.first;
|
ResolvableProfile profile = stack.get(DataComponents.PROFILE);
|
||||||
boolean isSlim = resourceLocationBooleanPair.second;
|
Pair<ResourceLocation, PlayerSkin.Model> skinInfo = getSkinInfo(profile);
|
||||||
|
|
||||||
poseStack.pushPose();
|
poseStack.pushPose();
|
||||||
VertexConsumer vertexConsumer = buffer.getBuffer(
|
VertexConsumer vertexConsumer = buffer.getBuffer(RenderType.entityTranslucent(skinInfo.first));
|
||||||
RenderType.entityTranslucent(playerSkin)
|
|
||||||
);
|
|
||||||
|
|
||||||
poseStack.translate(0.5, 2.6, 0.8);
|
poseStack.translate(0.5, 2.6, 0.8);
|
||||||
poseStack.scale(1.8F, -1.8F, -1.8F);
|
poseStack.scale(1.8F, -1.8F, -1.8F);
|
||||||
poseStack.mulPose(Axis.YP.rotationDegrees(180));
|
poseStack.mulPose(Axis.YP.rotationDegrees(180));
|
||||||
this.dollModel.slim = isSlim;
|
|
||||||
this.dollModel.renderToBuffer(
|
this.dollModel.slim = skinInfo.second == PlayerSkin.Model.SLIM;
|
||||||
poseStack,
|
this.dollModel.renderToBuffer(poseStack, vertexConsumer, packedLight, packedOverlay, -1);
|
||||||
vertexConsumer,
|
|
||||||
packedLight,
|
|
||||||
packedOverlay,
|
|
||||||
-1
|
|
||||||
);
|
|
||||||
|
|
||||||
poseStack.popPose();
|
poseStack.popPose();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load skin pair.
|
* 获取皮肤纹理和模型类型(1.21+ 版本)
|
||||||
*
|
|
||||||
* @param profile the profile
|
|
||||||
* @return the pair
|
|
||||||
*/
|
*/
|
||||||
public static @NotNull Pair<ResourceLocation,Boolean> loadSkin(GameProfile profile) {
|
public static @NotNull Pair<ResourceLocation, PlayerSkin.Model> getSkinInfo(@NotNull ResolvableProfile profile) {
|
||||||
SkinManager skinManager = Minecraft.getInstance().getSkinManager();
|
SkinManager skinManager = Minecraft.getInstance().getSkinManager();
|
||||||
ResourceLocation playerSkin;
|
|
||||||
boolean isSlim;
|
if (profile != null && profile.gameProfile() != null) {
|
||||||
if (profile != null) {
|
PlayerSkin skin = skinManager.getInsecureSkin(profile.gameProfile());
|
||||||
PlayerSkin insecureSkin = skinManager.getInsecureSkin(profile);
|
return Pair.of(skin.texture(), skin.model());
|
||||||
playerSkin = insecureSkin.texture();
|
|
||||||
isSlim = GameProfileHelper.isSlimArms(profile);
|
|
||||||
} else {
|
|
||||||
playerSkin = Lib39.mrl("textures/entity/player/wide/steve.png");
|
|
||||||
isSlim = false;
|
|
||||||
}
|
}
|
||||||
return Pair.of(playerSkin, isSlim);
|
|
||||||
|
// 默认返回 Steve 皮肤
|
||||||
|
return Pair.of(DefaultPlayerSkin.getDefaultTexture(), PlayerSkin.Model.SLIM);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,16 @@ import com.mojang.authlib.GameProfile;
|
||||||
import com.mojang.serialization.MapCodec;
|
import com.mojang.serialization.MapCodec;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.core.component.DataComponents;
|
||||||
import net.minecraft.core.particles.ParticleTypes;
|
import net.minecraft.core.particles.ParticleTypes;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.sounds.SoundSource;
|
import net.minecraft.sounds.SoundSource;
|
||||||
import net.minecraft.world.InteractionHand;
|
import net.minecraft.world.InteractionHand;
|
||||||
import net.minecraft.world.InteractionResult;
|
import net.minecraft.world.InteractionResult;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.component.ResolvableProfile;
|
||||||
import net.minecraft.world.item.context.BlockPlaceContext;
|
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||||
import net.minecraft.world.level.BlockGetter;
|
import net.minecraft.world.level.BlockGetter;
|
||||||
import net.minecraft.world.level.Level;
|
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);
|
ItemStack stack = super.getCloneItemStack(level, pos, state);
|
||||||
BlockEntity blockEntity = level.getBlockEntity(pos);
|
BlockEntity blockEntity = level.getBlockEntity(pos);
|
||||||
if (blockEntity instanceof DollBlockEntity doll) {
|
if (blockEntity instanceof DollBlockEntity doll) {
|
||||||
GameProfile profile = doll.getOwnerProfile();
|
ResolvableProfile profile;
|
||||||
if (profile != null) {
|
if (doll.getOwnerProfile() != null) {
|
||||||
GameProfileHelper.saveProfileToItemStack(stack, profile);
|
profile = doll.getOwnerProfile();
|
||||||
|
if (profile != null) {
|
||||||
|
GameProfileHelper.saveProfileToItemStack(stack, profile);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return stack;
|
return stack;
|
||||||
|
|
@ -207,6 +213,19 @@ public abstract class AbstractDollBlock extends BaseEntityBlock implements Simpl
|
||||||
super.createBlockStateDefinition(builder);
|
super.createBlockStateDefinition(builder);
|
||||||
builder.add(WATERLOGGED, POSE);
|
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();
|
return List.of();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GameProfile profile = dollEntity.getOwnerProfile();
|
ResolvableProfile profile;
|
||||||
if (profile != null) {
|
if (dollEntity.getOwnerProfile() != null) {
|
||||||
ItemStack instance = Lib39Items.DOLL.get().getDefaultInstance();
|
profile = dollEntity.getOwnerProfile();
|
||||||
GameProfileHelper.saveProfileToItemStack(instance, profile);
|
if (profile != null) {
|
||||||
return List.of(instance);
|
ItemStack instance = Lib39Items.DOLL.get().getDefaultInstance();
|
||||||
|
GameProfileHelper.saveProfileToItemStack(instance, profile);
|
||||||
|
return List.of(instance);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,62 +1,137 @@
|
||||||
package top.r3944realms.lib39.content.block.blockentity;
|
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 com.mojang.authlib.GameProfile;
|
||||||
import net.minecraft.Util;
|
import net.minecraft.Util;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.HolderLookup;
|
import net.minecraft.core.HolderLookup;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.nbt.NbtOps;
|
||||||
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
|
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
|
||||||
|
import net.minecraft.server.Services;
|
||||||
import net.minecraft.world.item.component.ResolvableProfile;
|
import net.minecraft.world.item.component.ResolvableProfile;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import net.minecraft.world.level.block.entity.SkullBlockEntity;
|
import net.minecraft.world.level.block.entity.SkullBlockEntity;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import top.r3944realms.lib39.core.register.Lib39BlockEntities;
|
import top.r3944realms.lib39.core.register.Lib39BlockEntities;
|
||||||
import top.r3944realms.lib39.util.GameProfileHelper;
|
|
||||||
import top.r3944realms.lib39.util.nbt.NBTReader;
|
import java.time.Duration;
|
||||||
import top.r3944realms.lib39.util.nbt.NBTWriter;
|
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.
|
* The type Doll block entity.
|
||||||
|
* 参考 SkullBlockEntity 实现,添加缓存机制
|
||||||
*/
|
*/
|
||||||
public class DollBlockEntity extends BlockEntity {
|
public class DollBlockEntity extends BlockEntity {
|
||||||
@Nullable
|
|
||||||
private GameProfile owner;
|
|
||||||
|
|
||||||
/**
|
private static final String TAG_PROFILE = "profile";
|
||||||
* Instantiates a new Doll block entity.
|
|
||||||
*
|
// 静态缓存(与 SkullBlockEntity 共享或独立)
|
||||||
* @param pos the pos
|
@Nullable
|
||||||
* @param blockState the block state
|
private static Executor mainThreadExecutor;
|
||||||
*/
|
@Nullable
|
||||||
|
private static LoadingCache<String, CompletableFuture<Optional<GameProfile>>> profileCacheByName;
|
||||||
|
@Nullable
|
||||||
|
private static LoadingCache<UUID, CompletableFuture<Optional<GameProfile>>> 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) {
|
public DollBlockEntity(BlockPos pos, BlockState blockState) {
|
||||||
super(Lib39BlockEntities.DOLL_BLOCK_ENTITY.get(), pos, blockState);
|
super(Lib39BlockEntities.DOLL_BLOCK_ENTITY.get(), pos, blockState);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
protected void saveAdditional(CompoundTag tag, HolderLookup.Provider registries) {
|
* 初始化缓存(在 Mod 初始化或服务器启动时调用)
|
||||||
super.saveAdditional(tag, registries);
|
*/
|
||||||
NBTWriter.of(tag)
|
public static void setup(final Services services, Executor executor) {
|
||||||
.gameProfileIf(GameProfileHelper.TAG_OWN_PROFILE, owner != null, () -> owner);
|
mainThreadExecutor = executor;
|
||||||
|
final BooleanSupplier cacheUninitialized = () -> profileCacheById == null;
|
||||||
|
|
||||||
|
profileCacheByName = CacheBuilder.newBuilder()
|
||||||
|
.expireAfterAccess(Duration.ofMinutes(10L))
|
||||||
|
.maximumSize(256L)
|
||||||
|
.build(new CacheLoader<>() {
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<Optional<GameProfile>> load(String username) {
|
||||||
|
return fetchProfileByName(username, services);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
profileCacheById = CacheBuilder.newBuilder()
|
||||||
|
.expireAfterAccess(Duration.ofMinutes(10L))
|
||||||
|
.maximumSize(256L)
|
||||||
|
.build(new CacheLoader<>() {
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<Optional<GameProfile>> load(UUID uuid) {
|
||||||
|
return fetchProfileById(uuid, services, cacheUninitialized);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private static CompletableFuture<Optional<GameProfile>> fetchProfileByName(String name, Services services) {
|
||||||
protected void loadAdditional(CompoundTag tag, HolderLookup.Provider registries) {
|
return services.profileCache().getAsync(name).thenCompose(optional -> {
|
||||||
super.loadAdditional(tag, registries);
|
LoadingCache<UUID, CompletableFuture<Optional<GameProfile>>> cache = profileCacheById;
|
||||||
NBTReader.of(tag)
|
if (cache != null && optional.isPresent()) {
|
||||||
.gameProfile(GameProfileHelper.TAG_OWN_PROFILE, this::setOwner);
|
return cache.getUnchecked(optional.get().getId())
|
||||||
|
.thenApply(fullProfile -> fullProfile.or(() -> optional));
|
||||||
|
}
|
||||||
|
return CompletableFuture.completedFuture(Optional.empty());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CompletableFuture<Optional<GameProfile>> 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.
|
* 公开的静态方法:异步获取 GameProfile(复用 SkullBlockEntity 的缓存或使用自己的)
|
||||||
*
|
|
||||||
* @return the owner profile
|
|
||||||
*/
|
*/
|
||||||
@Nullable
|
public static CompletableFuture<Optional<GameProfile>> fetchGameProfile(String name) {
|
||||||
public GameProfile getOwnerProfile() {
|
if (profileCacheByName != null && name != null && !name.isEmpty()) {
|
||||||
return this.owner;
|
return profileCacheByName.getUnchecked(name);
|
||||||
|
}
|
||||||
|
// 回退到 SkullBlockEntity 的缓存
|
||||||
|
return SkullBlockEntity.fetchGameProfile(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static CompletableFuture<Optional<GameProfile>> 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
|
@Override
|
||||||
public ClientboundBlockEntityDataPacket getUpdatePacket() {
|
public ClientboundBlockEntityDataPacket getUpdatePacket() {
|
||||||
|
|
@ -65,47 +140,57 @@ public class DollBlockEntity extends BlockEntity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundTag getUpdateTag(HolderLookup.Provider registries) {
|
public CompoundTag getUpdateTag(HolderLookup.Provider registries) {
|
||||||
return super.getUpdateTag(registries);
|
CompoundTag tag = super.getUpdateTag(registries);
|
||||||
|
saveAdditional(tag, registries);
|
||||||
|
return tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public void setOwner(@Nullable ResolvableProfile owner) {
|
||||||
* Sets owner.
|
|
||||||
*
|
|
||||||
* @param owner the owner
|
|
||||||
*/
|
|
||||||
public void setOwner(@Nullable GameProfile owner) {
|
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateOwnerProfile();
|
this.updateOwnerProfile();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets owner.
|
|
||||||
*
|
|
||||||
* @param ownerName the owner name
|
|
||||||
*/
|
|
||||||
public void setOwner(@Nullable String ownerName) {
|
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() {
|
private void updateOwnerProfile() {
|
||||||
if (this.owner != null) {
|
if (this.owner != null && !this.owner.isResolved()) {
|
||||||
// 使用 ResolvableProfile 进行异步解析
|
this.owner.resolve().thenAcceptAsync(resolved -> {
|
||||||
ResolvableProfile resolvableProfile = new ResolvableProfile(this.owner);
|
this.owner = resolved;
|
||||||
if (!resolvableProfile.isResolved()) {
|
this.setChanged();
|
||||||
resolvableProfile.resolve().thenAcceptAsync(resolved -> {
|
// 通知客户端更新
|
||||||
// 从 ResolvableProfile 中获取 GameProfile
|
if (level != null && !level.isClientSide) {
|
||||||
this.owner = resolved.gameProfile();
|
level.sendBlockUpdated(worldPosition, getBlockState(), getBlockState(), 3);
|
||||||
this.setChanged();
|
}
|
||||||
if (this.level != null) {
|
}, CHECKED_MAIN_THREAD_EXECUTOR);
|
||||||
this.level.sendBlockUpdated(this.worldPosition, this.getBlockState(), this.getBlockState(), 3);
|
} else {
|
||||||
}
|
this.setChanged();
|
||||||
}, SkullBlockEntity.CHECKED_MAIN_THREAD_EXECUTOR);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,6 +8,7 @@ import net.minecraft.world.item.Equipable;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.item.StandingAndWallBlockItem;
|
import net.minecraft.world.item.StandingAndWallBlockItem;
|
||||||
import net.minecraft.world.item.TooltipFlag;
|
import net.minecraft.world.item.TooltipFlag;
|
||||||
|
import net.minecraft.world.item.component.ResolvableProfile;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
@ -32,9 +33,12 @@ public class DollItem extends StandingAndWallBlockItem implements Equipable {
|
||||||
@Override
|
@Override
|
||||||
public void appendHoverText(ItemStack stack, TooltipContext context, List<Component> tooltipComponents, TooltipFlag tooltipFlag) {
|
public void appendHoverText(ItemStack stack, TooltipContext context, List<Component> tooltipComponents, TooltipFlag tooltipFlag) {
|
||||||
super.appendHoverText(stack, context, tooltipComponents, tooltipFlag);
|
super.appendHoverText(stack, context, tooltipComponents, tooltipFlag);
|
||||||
GameProfile profileFromItemStack = GameProfileHelper.getProfileFromItemStack(stack);
|
ResolvableProfile profileFromItemStack = GameProfileHelper.getProfileFromItemStack(stack);
|
||||||
if (profileFromItemStack != null && profileFromItemStack.getName() != null) {
|
if (profileFromItemStack != null) {
|
||||||
tooltipComponents.add(Component.translatable("tooltip.lib39.content.doll.hover.1", profileFromItemStack.getName()));
|
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"));
|
tooltipComponents.add(Component.translatable("tooltip.lib39.content.doll.hover.2"));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import net.minecraft.nbt.Tag;
|
||||||
*
|
*
|
||||||
* @param <T> the type parameter
|
* @param <T> the type parameter
|
||||||
*/
|
*/
|
||||||
public interface INBTSerializable <T extends Tag>{
|
public interface INBTSerializable <T extends Tag> {
|
||||||
/**
|
/**
|
||||||
* Serialize nbt t.
|
* Serialize nbt t.
|
||||||
*
|
*
|
||||||
|
|
@ -18,7 +18,7 @@ public interface INBTSerializable <T extends Tag>{
|
||||||
/**
|
/**
|
||||||
* Deserialize nbt.
|
* Deserialize nbt.
|
||||||
*
|
*
|
||||||
* @param var1 the var 1
|
* @param t the var
|
||||||
*/
|
*/
|
||||||
void deserializeNBT(T var1);
|
void deserializeNBT(T t);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,23 +5,23 @@ import com.mojang.authlib.GameProfile;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.component.ResolvableProfile;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Pseudo;
|
import org.spongepowered.asm.mixin.Pseudo;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
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.content.item.DollItem;
|
||||||
import top.r3944realms.lib39.util.GameProfileHelper;
|
import top.r3944realms.lib39.util.GameProfileHelper;
|
||||||
import top.r3944realms.lib39.util.nbt.NBTReader;
|
import top.r3944realms.lib39.util.nbt.NBTReader;
|
||||||
import tschipp.carryon.client.render.CarriedObjectRender;
|
import tschipp.carryon.client.render.CarriedObjectRender;
|
||||||
import tschipp.carryon.common.carry.CarryOnDataManager;
|
import tschipp.carryon.common.carry.CarryOnDataManager;
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type Mixin carried object render.
|
* The type Mixin carried object render.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("DuplicatedCode")
|
||||||
@Pseudo
|
@Pseudo
|
||||||
@Mixin(value = CarriedObjectRender.class, remap = false)
|
@Mixin(value = CarriedObjectRender.class, remap = false)
|
||||||
public class MixinCarriedObjectRender {
|
public class MixinCarriedObjectRender {
|
||||||
|
|
@ -36,9 +36,9 @@ public class MixinCarriedObjectRender {
|
||||||
if (stack.getItem() instanceof DollItem) {
|
if (stack.getItem() instanceof DollItem) {
|
||||||
CompoundTag compound = CarryOnDataManager.getCarryData(player).getNbt().getCompound("tile");
|
CompoundTag compound = CarryOnDataManager.getCarryData(player).getNbt().getCompound("tile");
|
||||||
AtomicReference<GameProfile> gameProfileAtomicReference = new AtomicReference<>();
|
AtomicReference<GameProfile> gameProfileAtomicReference = new AtomicReference<>();
|
||||||
NBTReader.of(compound).gameProfile(GameProfileHelper.TAG_OWN_PROFILE, gameProfileAtomicReference::set);
|
NBTReader.of(compound).gameProfile("profile", gameProfileAtomicReference::set);
|
||||||
if (gameProfileAtomicReference.get() != null) {
|
if (gameProfileAtomicReference.get() != null) {
|
||||||
GameProfileHelper.saveProfileToItemStack(stack, gameProfileAtomicReference.get());
|
GameProfileHelper.saveProfileToItemStack(stack, new ResolvableProfile(gameProfileAtomicReference.get()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return stack;
|
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"
|
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) {
|
private static ItemStack warpDollItem$2(ItemStack tileItem, @Local(ordinal = 0) Player player) {
|
||||||
if (stack.getItem() instanceof DollItem) {
|
if (tileItem.getItem() instanceof DollItem) {
|
||||||
CompoundTag compound = CarryOnDataManager.getCarryData(player).getNbt().getCompound("tile");
|
CompoundTag compound = CarryOnDataManager.getCarryData(player).getNbt().getCompound("tile");
|
||||||
AtomicReference<GameProfile> gameProfileAtomicReference = new AtomicReference<>();
|
AtomicReference<GameProfile> gameProfileAtomicReference = new AtomicReference<>();
|
||||||
NBTReader.of(compound).gameProfile(GameProfileHelper.TAG_OWN_PROFILE, gameProfileAtomicReference::set);
|
NBTReader.of(compound).gameProfile("profile", gameProfileAtomicReference::set);
|
||||||
if (gameProfileAtomicReference.get() != null) {
|
if (gameProfileAtomicReference.get() != null) {
|
||||||
GameProfileHelper.saveProfileToItemStack(stack, gameProfileAtomicReference.get());
|
GameProfileHelper.saveProfileToItemStack(tileItem, new ResolvableProfile(gameProfileAtomicReference.get()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return stack;
|
return tileItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.wrapmethod.WrapMethod;
|
||||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
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.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
import org.spongepowered.asm.mixin.Unique;
|
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.ILib39SyncDataHolder;
|
||||||
import top.r3944realms.lib39.core.sync.ISyncData;
|
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;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
|
@ -45,7 +44,7 @@ public abstract class MixinEntity implements ILib39SyncDataHolder {
|
||||||
|
|
||||||
@WrapMethod(method = "saveWithoutId")
|
@WrapMethod(method = "saveWithoutId")
|
||||||
private CompoundTag wrapSave(CompoundTag compound, @NotNull Operation<CompoundTag> original) {
|
private CompoundTag wrapSave(CompoundTag compound, @NotNull Operation<CompoundTag> original) {
|
||||||
FabricCommonEventHandler.getSyncData2Manager().forEach((id, manager) -> {
|
Services.PLATFORM.getUtilHelper().getSyncData2Manager().forEach((id, manager) -> {
|
||||||
ISyncData<?> o = manager.getSyncMap().get(getUUID());
|
ISyncData<?> o = manager.getSyncMap().get(getUUID());
|
||||||
if (o instanceof NBTEntitySyncData syncData) {
|
if (o instanceof NBTEntitySyncData syncData) {
|
||||||
saveSyncData(syncData);
|
saveSyncData(syncData);
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package top.r3944realms.lib39.platform.services;
|
package top.r3944realms.lib39.platform.services;
|
||||||
|
|
||||||
|
import top.r3944realms.lib39.core.sync.SyncData2Manager;
|
||||||
import top.r3944realms.lib39.util.block.BlockRegistryBuilder;
|
import top.r3944realms.lib39.util.block.BlockRegistryBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -12,4 +13,6 @@ public interface IUtilHelper {
|
||||||
* @return the block registry builder
|
* @return the block registry builder
|
||||||
*/
|
*/
|
||||||
BlockRegistryBuilder getBlockRegistryBuilder();
|
BlockRegistryBuilder getBlockRegistryBuilder();
|
||||||
|
|
||||||
|
SyncData2Manager<?> getSyncData2Manager();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,11 @@ import net.minecraft.core.component.DataComponents;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.nbt.NbtUtils;
|
import net.minecraft.nbt.NbtUtils;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.Services;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.item.component.ResolvableProfile;
|
import net.minecraft.world.item.component.ResolvableProfile;
|
||||||
|
import net.minecraft.world.level.block.entity.SkullBlockEntity;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import top.r3944realms.lib39.Lib39;
|
import top.r3944realms.lib39.Lib39;
|
||||||
|
|
@ -22,15 +24,65 @@ import top.r3944realms.lib39.util.nbt.NBTReader;
|
||||||
import top.r3944realms.lib39.util.nbt.NBTWriter;
|
import top.r3944realms.lib39.util.nbt.NBTWriter;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Base64;
|
import java.util.*;
|
||||||
import java.util.Collection;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.Objects;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type GameProfile helper.
|
* The type GameProfile helper.
|
||||||
*/
|
*/
|
||||||
public class GameProfileHelper {
|
public class GameProfileHelper {
|
||||||
|
/**
|
||||||
|
* 异步获取 GameProfile(通过玩家名)
|
||||||
|
* 直接复用 SkullBlockEntity 的实现
|
||||||
|
*/
|
||||||
|
public static CompletableFuture<Optional<GameProfile>> fetchGameProfileByName(String name) {
|
||||||
|
return SkullBlockEntity.fetchGameProfile(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异步获取 GameProfile(通过 UUID)
|
||||||
|
* 直接复用 SkullBlockEntity 的实现
|
||||||
|
*/
|
||||||
|
public static CompletableFuture<Optional<GameProfile>> fetchGameProfileByUUID(UUID uuid) {
|
||||||
|
return SkullBlockEntity.fetchGameProfile(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异步获取 GameProfile(自动识别类型)
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static <T> CompletableFuture<Optional<GameProfile>> 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<Optional<GameProfile>> 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
|
* Client Only Class
|
||||||
*/
|
*/
|
||||||
|
|
@ -296,7 +348,7 @@ public class GameProfileHelper {
|
||||||
* @return the profile from item stack
|
* @return the profile from item stack
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public static GameProfile getProfileFromItemStack(ItemStack stack) {
|
public static ResolvableProfile getProfileFromItemStack(@NotNull ItemStack stack) {
|
||||||
if (stack.isEmpty()) {
|
if (stack.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
@ -304,7 +356,7 @@ public class GameProfileHelper {
|
||||||
if (stack.isEmpty()) return null;
|
if (stack.isEmpty()) return null;
|
||||||
|
|
||||||
ResolvableProfile profile = stack.get(DataComponents.PROFILE);
|
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 stack the stack
|
||||||
* @param profile the profile
|
* @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 (stack.isEmpty()) return;
|
||||||
|
|
||||||
if (profile == null) {
|
if (profile == null) {
|
||||||
stack.remove(DataComponents.PROFILE);
|
stack.remove(DataComponents.PROFILE);
|
||||||
} else {
|
} else {
|
||||||
stack.set(DataComponents.PROFILE, new ResolvableProfile(profile));
|
stack.set(DataComponents.PROFILE, profile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -430,31 +430,67 @@ public class NBTReader {
|
||||||
String name = null;
|
String name = null;
|
||||||
UUID uuid = null;
|
UUID uuid = null;
|
||||||
|
|
||||||
|
// 支持 "Name" 或 "name"
|
||||||
if (tag.contains("Name", CompoundTag.TAG_STRING)) {
|
if (tag.contains("Name", CompoundTag.TAG_STRING)) {
|
||||||
name = tag.getString("Name");
|
name = tag.getString("Name");
|
||||||
|
} else if (tag.contains("name", CompoundTag.TAG_STRING)) {
|
||||||
|
name = tag.getString("name");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 支持 "Id" 或 "id"
|
||||||
if (tag.hasUUID("Id")) {
|
if (tag.hasUUID("Id")) {
|
||||||
uuid = tag.getUUID("Id");
|
uuid = tag.getUUID("Id");
|
||||||
|
} else if (tag.hasUUID("id")) {
|
||||||
|
uuid = tag.getUUID("id");
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
GameProfile profile = new GameProfile(uuid, name);
|
GameProfile profile = new GameProfile(uuid, name);
|
||||||
|
|
||||||
if (tag.contains("Properties", CompoundTag.TAG_COMPOUND)) {
|
// 支持 "Properties" 或 "properties",支持 COMPOUND 或 LIST 格式
|
||||||
CompoundTag propertiesTag = tag.getCompound("Properties");
|
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()) {
|
for (String key : propertiesTag.getAllKeys()) {
|
||||||
ListTag listTag = propertiesTag.getList(key, CompoundTag.TAG_COMPOUND);
|
ListTag listTag = propertiesTag.getList(key, CompoundTag.TAG_COMPOUND);
|
||||||
for (int i = 0; i < listTag.size(); i++) {
|
for (int i = 0; i < listTag.size(); i++) {
|
||||||
CompoundTag propTag = listTag.getCompound(i);
|
CompoundTag propTag = listTag.getCompound(i);
|
||||||
String value = propTag.getString("Value");
|
String value = propTag.getString("Value");
|
||||||
if (propTag.contains("Signature", CompoundTag.TAG_STRING)) {
|
String signature = propTag.contains("Signature") ? propTag.getString("Signature") : null;
|
||||||
profile.getProperties().put(key, new Property(key, value, propTag.getString("Signature")));
|
if (signature != null) {
|
||||||
|
profile.getProperties().put(key, new Property(key, value, signature));
|
||||||
} else {
|
} else {
|
||||||
profile.getProperties().put(key, new Property(key, value));
|
profile.getProperties().put(key, new Property(key, value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return profile;
|
return profile;
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,7 @@ void main() {
|
||||||
|
|
||||||
// 确保内外半径合理
|
// 确保内外半径合理
|
||||||
if (OuterRadius <= InnerRadius) {
|
if (OuterRadius <= InnerRadius) {
|
||||||
vec4 color = vertexColor;
|
discard; // ✅ 直接丢弃片段,不需要设置颜色
|
||||||
color.a = 0;
|
|
||||||
fragColor = color;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 计算环形 alpha
|
// 计算环形 alpha
|
||||||
|
|
@ -28,20 +26,20 @@ void main() {
|
||||||
// 内边缘抗锯齿
|
// 内边缘抗锯齿
|
||||||
if (dist < InnerRadius + AntiAliasing) {
|
if (dist < InnerRadius + AntiAliasing) {
|
||||||
float fade = (dist - InnerRadius) / AntiAliasing;
|
float fade = (dist - InnerRadius) / AntiAliasing;
|
||||||
alpha *= fade;
|
alpha *= clamp(fade, 0.0, 1.0); // ✅ 确保值在 [0,1] 范围内
|
||||||
}
|
}
|
||||||
|
|
||||||
// 外边缘抗锯齿
|
// 外边缘抗锯齿
|
||||||
if (dist > OuterRadius - AntiAliasing) {
|
if (dist > OuterRadius - AntiAliasing) {
|
||||||
float fade = 1.0 - (dist - (OuterRadius - AntiAliasing)) / AntiAliasing;
|
float fade = 1.0 - (dist - (OuterRadius - AntiAliasing)) / AntiAliasing;
|
||||||
alpha *= fade;
|
alpha *= clamp(fade, 0.0, 1.0); // ✅ 确保值在 [0,1] 范围内
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vec4 color = vertexColor;
|
vec4 color = vertexColor;
|
||||||
color.a *= alpha;
|
color.a = color.a * alpha; // ✅ 修正语法
|
||||||
|
|
||||||
if (alpha > 0.0) {
|
if (color.a > 0.0) {
|
||||||
fragColor = color * ColorModulator;
|
fragColor = color * ColorModulator;
|
||||||
} else {
|
} else {
|
||||||
discard;
|
discard;
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ uniform vec4 ColorModulator;
|
||||||
uniform vec2 FramebufferSize;
|
uniform vec2 FramebufferSize;
|
||||||
uniform vec2 Center;
|
uniform vec2 Center;
|
||||||
uniform float Radius;
|
uniform float Radius;
|
||||||
uniform float AntiAliasingRadius;
|
|
||||||
|
|
||||||
out vec4 fragColor;
|
out vec4 fragColor;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,14 +32,6 @@
|
||||||
"values": [
|
"values": [
|
||||||
0.0
|
0.0
|
||||||
]
|
]
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "AntiAliasingRadius",
|
|
||||||
"type": "float",
|
|
||||||
"count": 1,
|
|
||||||
"values": [
|
|
||||||
1.5
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
"compatibilityLevel": "JAVA_21",
|
"compatibilityLevel": "JAVA_21",
|
||||||
"mixins": [
|
"mixins": [
|
||||||
"carryon.MixinCarriedObjectRender",
|
"carryon.MixinCarriedObjectRender",
|
||||||
|
"minecraft.MixinEntity",
|
||||||
"minecraft.CreativeModeTabsAccessor"
|
"minecraft.CreativeModeTabsAccessor"
|
||||||
],
|
],
|
||||||
"client": [
|
"client": [
|
||||||
|
|
|
||||||
|
|
@ -23,10 +23,14 @@ public class FabricDollComponentProvider implements IBlockComponentProvider {
|
||||||
@Override
|
@Override
|
||||||
public void appendTooltip(ITooltip iTooltip, @NotNull BlockAccessor blockAccessor, IPluginConfig iPluginConfig) {
|
public void appendTooltip(ITooltip iTooltip, @NotNull BlockAccessor blockAccessor, IPluginConfig iPluginConfig) {
|
||||||
if (blockAccessor.getBlockEntity() instanceof DollBlockEntity doll) {
|
if (blockAccessor.getBlockEntity() instanceof DollBlockEntity doll) {
|
||||||
GameProfile ownerProfile = doll.getOwnerProfile();
|
GameProfile ownerProfile;
|
||||||
if (ownerProfile != null) {
|
if (doll.getOwnerProfile() != null) {
|
||||||
iTooltip.add(Component.translatable("tooltip.lib39.content.doll.hover.1", ownerProfile.getName()));
|
ownerProfile = doll.getOwnerProfile().gameProfile();
|
||||||
|
if (ownerProfile != null) {
|
||||||
|
iTooltip.add(Component.translatable("tooltip.lib39.content.doll.hover.1", ownerProfile.getName()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.Services;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.item.CreativeModeTab;
|
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 net.minecraft.world.level.block.entity.SkullBlockEntity;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import top.r3944realms.lib39.Lib39;
|
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.AnvilUpdateCallback;
|
||||||
|
import top.r3944realms.lib39.api.callback.MinecraftSetUpServiceCallback;
|
||||||
import top.r3944realms.lib39.api.callback.SyncManagerRegisterCallback;
|
import top.r3944realms.lib39.api.callback.SyncManagerRegisterCallback;
|
||||||
import top.r3944realms.lib39.api.callback.client.ClientWorldCallback;
|
import top.r3944realms.lib39.api.callback.client.ClientWorldCallback;
|
||||||
import top.r3944realms.lib39.base.command.Lib39HelpCommand;
|
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.content.item.DollItem;
|
||||||
import top.r3944realms.lib39.core.register.Lib39Items;
|
import top.r3944realms.lib39.core.register.Lib39Items;
|
||||||
import top.r3944realms.lib39.core.sync.ISyncData;
|
import top.r3944realms.lib39.core.sync.ISyncData;
|
||||||
|
|
@ -44,6 +48,7 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -183,31 +188,35 @@ public class FabricCommonEventHandler {
|
||||||
for (Map.Entry<ResourceKey<CreativeModeTab>, List<Supplier<Block>>> resourceKeyListEntry : tabToItemsMap.entrySet()) {
|
for (Map.Entry<ResourceKey<CreativeModeTab>, List<Supplier<Block>>> resourceKeyListEntry : tabToItemsMap.entrySet()) {
|
||||||
ItemGroupEvents.modifyEntriesEvent(resourceKeyListEntry.getKey()).register(content -> resourceKeyListEntry.getValue().forEach(i -> content.accept(i.get())));
|
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) -> {
|
AnvilUpdateCallback.EVENT.register((left, right, outputSlot, name, baseCost, player) -> {
|
||||||
if (left.getItem() instanceof DollItem && name != null && name.length() < 15) {
|
if (left.getItem() instanceof DollItem && name != null && !name.isEmpty() && name.length() <= 16) {
|
||||||
// 创建 GameProfile(使用 NIL_UUID 临时占位)
|
ItemStack output = Lib39Items.DOLL.get().getDefaultInstance();
|
||||||
|
output.setCount(left.getCount());
|
||||||
|
|
||||||
|
// 创建 ResolvableProfile
|
||||||
GameProfile profile = new GameProfile(Util.NIL_UUID, name);
|
GameProfile profile = new GameProfile(Util.NIL_UUID, name);
|
||||||
ItemStack copied = Lib39Items.DOLL.get().getDefaultInstance();
|
|
||||||
copied.setCount(left.getCount());
|
|
||||||
|
|
||||||
// 使用 ResolvableProfile 进行异步解析
|
|
||||||
ResolvableProfile resolvableProfile = new ResolvableProfile(profile);
|
ResolvableProfile resolvableProfile = new ResolvableProfile(profile);
|
||||||
if (!resolvableProfile.isResolved()) {
|
output.set(DataComponents.PROFILE, resolvableProfile);
|
||||||
resolvableProfile.resolve().thenAcceptAsync(resolved -> {
|
|
||||||
// 解析完成后保存到 ItemStack
|
|
||||||
GameProfile resolvedProfile = resolved.gameProfile();
|
|
||||||
GameProfileHelper.saveProfileToItemStack(copied, resolvedProfile);
|
|
||||||
}, player.getServer());
|
|
||||||
} else {
|
|
||||||
GameProfileHelper.saveProfileToItemStack(copied, profile);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
} else {
|
||||||
ItemStack defaultInstance = Items.BARRIER.getDefaultInstance();
|
ItemStack errorOutput = Items.BARRIER.getDefaultInstance();
|
||||||
defaultInstance.set(DataComponents.CUSTOM_NAME,
|
errorOutput.set(DataComponents.CUSTOM_NAME,
|
||||||
Component.translatable("invalid.player_name.too_long"));
|
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)
|
EntityApiLookup.get(FabricTestSyncData.ID, AbstractedTestSyncData.class, Void.class)
|
||||||
|
|
|
||||||
|
|
@ -290,8 +290,8 @@ public class FabricTestSyncData extends AbstractedTestSyncData implements IFabri
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deserializeNBT(CompoundTag nbt) {
|
public void deserializeNBT(CompoundTag t) {
|
||||||
NBTReader.of(nbt)
|
NBTReader.of(t)
|
||||||
.intValue(NBT_KEY_INT, integer -> testInt = integer)
|
.intValue(NBT_KEY_INT, integer -> testInt = integer)
|
||||||
.string(NBT_KEY_STRING, string -> testString = string)
|
.string(NBT_KEY_STRING, string -> testString = string)
|
||||||
.booleanValue(NBT_KEY_BOOLEAN, bool -> testBoolean = bool)
|
.booleanValue(NBT_KEY_BOOLEAN, bool -> testBoolean = bool)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package top.r3944realms.lib39.example.core.network;
|
package top.r3944realms.lib39.example.core.network;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry;
|
||||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
|
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -10,6 +11,10 @@ public class FabricExNetworkHandler {
|
||||||
* 注册服务器接收的数据包
|
* 注册服务器接收的数据包
|
||||||
*/
|
*/
|
||||||
public static void registerServerReceivers() {
|
public static void registerServerReceivers() {
|
||||||
|
PayloadTypeRegistry.playC2S().register(
|
||||||
|
FabricClientDataPacket.TYPE,
|
||||||
|
FabricClientDataPacket.STREAM_CODEC
|
||||||
|
);
|
||||||
ServerPlayNetworking.registerGlobalReceiver(
|
ServerPlayNetworking.registerGlobalReceiver(
|
||||||
FabricClientDataPacket.TYPE,
|
FabricClientDataPacket.TYPE,
|
||||||
FabricClientDataPacket::handle
|
FabricClientDataPacket::handle
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
package top.r3944realms.lib39.platform;
|
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.platform.services.IUtilHelper;
|
||||||
import top.r3944realms.lib39.util.FabricBlockRegistryBuilder;
|
import top.r3944realms.lib39.util.FabricBlockRegistryBuilder;
|
||||||
import top.r3944realms.lib39.util.block.BlockRegistryBuilder;
|
import top.r3944realms.lib39.util.block.BlockRegistryBuilder;
|
||||||
|
|
@ -16,4 +18,9 @@ public enum FabricUtilHelper implements IUtilHelper {
|
||||||
public BlockRegistryBuilder getBlockRegistryBuilder() {
|
public BlockRegistryBuilder getBlockRegistryBuilder() {
|
||||||
return new FabricBlockRegistryBuilder();
|
return new FabricBlockRegistryBuilder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SyncData2Manager<?> getSyncData2Manager() {
|
||||||
|
return FabricCommonEventHandler.getSyncData2Manager();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@
|
||||||
"compatibilityLevel": "JAVA_18",
|
"compatibilityLevel": "JAVA_18",
|
||||||
"mixins": [
|
"mixins": [
|
||||||
"MixinApiLookUpImpl",
|
"MixinApiLookUpImpl",
|
||||||
"MixinEntity",
|
|
||||||
"callback.MixinAnvilMenu"
|
"callback.MixinAnvilMenu"
|
||||||
],
|
],
|
||||||
"client": [
|
"client": [
|
||||||
|
|
|
||||||
|
|
@ -65,13 +65,12 @@ sourceSets.main.resources.srcDir project(':common').file('src/generated/resource
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly project(":common")
|
compileOnly project(":common")
|
||||||
annotationProcessor("org.spongepowered:mixin:0.8.5-SNAPSHOT:processor")
|
|
||||||
implementation(annotationProcessor("io.github.llamalad7:mixinextras-common:0.2.0"))
|
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') {
|
implementation(group: 'tschipp.carryon', name: 'carryon-neoforge-1.21.1', version: '2.2.4.4') {
|
||||||
transitive = false
|
transitive = false
|
||||||
}
|
}
|
||||||
implementation "curse.maven:jade-324717:7545219"
|
implementation "curse.maven:jade-324717:7545219"
|
||||||
implementation(jarJar("io.github.llamalad7:mixinextras-forge:0.2.0"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 配置sourceJar任务
|
// 配置sourceJar任务
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,12 @@ public class NeoForgeDollComponentProvider implements IBlockComponentProvider {
|
||||||
@Override
|
@Override
|
||||||
public void appendTooltip(ITooltip iTooltip, @NotNull BlockAccessor blockAccessor, IPluginConfig iPluginConfig) {
|
public void appendTooltip(ITooltip iTooltip, @NotNull BlockAccessor blockAccessor, IPluginConfig iPluginConfig) {
|
||||||
if (blockAccessor.getBlockEntity() instanceof DollBlockEntity doll) {
|
if (blockAccessor.getBlockEntity() instanceof DollBlockEntity doll) {
|
||||||
GameProfile ownerProfile = doll.getOwnerProfile();
|
GameProfile ownerProfile;
|
||||||
if (ownerProfile != null) {
|
if (doll.getOwnerProfile() != null) {
|
||||||
iTooltip.add(Component.translatable("tooltip.lib39.content.doll.hover.1", ownerProfile.getName()));
|
ownerProfile = doll.getOwnerProfile().gameProfile();
|
||||||
|
if (ownerProfile != null) {
|
||||||
|
iTooltip.add(Component.translatable("tooltip.lib39.content.doll.hover.1", ownerProfile.getName()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@ import top.r3944realms.lib39.datagen.provider.SimpleLootTableProvider;
|
||||||
import top.r3944realms.lib39.datagen.provider.SubProvidersWrapper;
|
import top.r3944realms.lib39.datagen.provider.SubProvidersWrapper;
|
||||||
import top.r3944realms.lib39.datagen.value.McLocale;
|
import top.r3944realms.lib39.datagen.value.McLocale;
|
||||||
|
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type Lib 39 base data gen event.
|
* The type Lib 39 base data gen event.
|
||||||
*/
|
*/
|
||||||
|
|
@ -73,7 +75,14 @@ public class Lib39BaseDataGenEvent {
|
||||||
private static void LootTableDataGenerate(@NotNull GatherDataEvent event) {
|
private static void LootTableDataGenerate(@NotNull GatherDataEvent event) {
|
||||||
event.getGenerator().addProvider(
|
event.getGenerator().addProvider(
|
||||||
event.includeServer(),
|
event.includeServer(),
|
||||||
(DataProvider.Factory<SimpleLootTableProvider>) pOutput -> new SimpleLootTableProvider(pOutput, new SubProvidersWrapper().addBlockEntry(new Lib39BlockLootTable()), event.getLookupProvider())
|
(DataProvider.Factory<SimpleLootTableProvider>) 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) {
|
private static void RecipeGenerator(@NotNull GatherDataEvent event) {
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,13 @@
|
||||||
package top.r3944realms.lib39.base.datagen.provider;
|
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.NeoForgeLib39Blocks;
|
||||||
import top.r3944realms.lib39.core.register.Lib39Blocks;
|
import top.r3944realms.lib39.core.register.Lib39Blocks;
|
||||||
import top.r3944realms.lib39.datagen.provider.subprovider.BlockLootTables;
|
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.
|
* The type Lib 39 block loot table.
|
||||||
*/
|
*/
|
||||||
|
|
@ -11,8 +15,8 @@ public class Lib39BlockLootTable extends BlockLootTables {
|
||||||
/**
|
/**
|
||||||
* Instantiates a new Lib 39 block loot table.
|
* Instantiates a new Lib 39 block loot table.
|
||||||
*/
|
*/
|
||||||
public Lib39BlockLootTable() {
|
public Lib39BlockLootTable(CompletableFuture<HolderLookup.Provider> registries) throws ExecutionException, InterruptedException {
|
||||||
super(NeoForgeLib39Blocks.BLOCKS);
|
super(NeoForgeLib39Blocks.BLOCKS, registries.get());
|
||||||
dropSelf(Lib39Blocks.DOLL, Lib39Blocks.WALL_DOLL);
|
dropSelf(Lib39Blocks.DOLL, Lib39Blocks.WALL_DOLL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.entity.player.Player;
|
|
||||||
import net.minecraft.world.item.CreativeModeTab;
|
import net.minecraft.world.item.CreativeModeTab;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.item.Items;
|
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.Level;
|
||||||
import net.minecraft.world.level.LevelAccessor;
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.entity.SkullBlockEntity;
|
||||||
import net.neoforged.bus.api.SubscribeEvent;
|
import net.neoforged.bus.api.SubscribeEvent;
|
||||||
import net.neoforged.fml.common.EventBusSubscriber;
|
import net.neoforged.fml.common.EventBusSubscriber;
|
||||||
import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent;
|
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.level.LevelEvent;
|
||||||
import net.neoforged.neoforge.event.tick.ServerTickEvent;
|
import net.neoforged.neoforge.event.tick.ServerTickEvent;
|
||||||
import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent;
|
import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import top.r3944realms.lib39.Lib39;
|
import top.r3944realms.lib39.Lib39;
|
||||||
|
import top.r3944realms.lib39.api.event.MinecraftSetUpServiceEvent;
|
||||||
import top.r3944realms.lib39.api.event.SyncManagerRegisterEvent;
|
import top.r3944realms.lib39.api.event.SyncManagerRegisterEvent;
|
||||||
import top.r3944realms.lib39.base.command.Lib39HelpCommand;
|
import top.r3944realms.lib39.base.command.Lib39HelpCommand;
|
||||||
import top.r3944realms.lib39.base.datagen.Lib39BaseDataGenEvent;
|
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.content.item.DollItem;
|
||||||
import top.r3944realms.lib39.core.network.NetworkHandler;
|
import top.r3944realms.lib39.core.network.NetworkHandler;
|
||||||
import top.r3944realms.lib39.core.register.Lib39Items;
|
import top.r3944realms.lib39.core.register.Lib39Items;
|
||||||
|
|
@ -153,31 +156,45 @@ public class CommonEventHandler {
|
||||||
public static void onAnvilRename(AnvilUpdateEvent event) {
|
public static void onAnvilRename(AnvilUpdateEvent event) {
|
||||||
if (event.getLeft().getItem() instanceof DollItem) {
|
if (event.getLeft().getItem() instanceof DollItem) {
|
||||||
String name = event.getName();
|
String name = event.getName();
|
||||||
Player player = event.getPlayer();
|
|
||||||
if (name != null && name.length() < 15) {
|
if (name != null && !name.isEmpty()) {
|
||||||
GameProfile profile = new GameProfile(Util.NIL_UUID, name);
|
if (name.length() <= 16) {
|
||||||
ItemStack copied = Lib39Items.DOLL.get().getDefaultInstance();
|
ItemStack output = Lib39Items.DOLL.get().getDefaultInstance();
|
||||||
ResolvableProfile resolvableProfile = new ResolvableProfile(profile);
|
output.setCount(event.getLeft().getCount());
|
||||||
if (!resolvableProfile.isResolved()) {
|
|
||||||
resolvableProfile.resolve().thenAcceptAsync(resolved -> {
|
// 创建 ResolvableProfile
|
||||||
// 解析完成后保存到 ItemStack
|
GameProfile profile = new GameProfile(Util.NIL_UUID, name);
|
||||||
GameProfile resolvedProfile = resolved.gameProfile();
|
ResolvableProfile resolvableProfile = new ResolvableProfile(profile);
|
||||||
GameProfileHelper.saveProfileToItemStack(copied, resolvedProfile);
|
output.set(DataComponents.PROFILE, resolvableProfile);
|
||||||
}, player.getServer());
|
|
||||||
|
// 使用 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 {
|
} 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 {
|
} else {
|
||||||
ItemStack defaultInstance = Items.BARRIER.getDefaultInstance();
|
event.setOutput(ItemStack.EMPTY);
|
||||||
defaultInstance.set(DataComponents.CUSTOM_NAME,
|
event.setCost(0);
|
||||||
Component.translatable("invalid.player_name.too_long"));
|
|
||||||
event.setOutput(defaultInstance);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@SubscribeEvent
|
||||||
|
public static void onMinecraftSetUpService (@NotNull MinecraftSetUpServiceEvent event) {
|
||||||
|
DollBlockEntity.setup(event.services, event.mainThreadExecutor);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On entity join world.
|
* On entity join world.
|
||||||
|
|
|
||||||
|
|
@ -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 <T> 同步数据类型,必须继承 NBTEntitySyncData
|
||||||
|
*/
|
||||||
|
public abstract class SyncCapProvider<T extends NBTEntitySyncData> implements ICapabilityProvider<Entity, Void, T> {
|
||||||
|
/**
|
||||||
|
* 创建空的能力实例
|
||||||
|
* 当管理器中不存在数据时调用
|
||||||
|
*
|
||||||
|
* @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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -27,22 +27,23 @@ public class ExCapabilityHandler {
|
||||||
* @param event the event
|
* @param event the event
|
||||||
*/
|
*/
|
||||||
public static void registerCapability(@NotNull RegisterCapabilitiesEvent event) {
|
public static void registerCapability(@NotNull RegisterCapabilitiesEvent event) {
|
||||||
|
TestSyncCapProvider provider = new TestSyncCapProvider();
|
||||||
EntityCapabilityHelper.registerForEntityClass(
|
EntityCapabilityHelper.registerForEntityClass(
|
||||||
event,
|
event,
|
||||||
TEST_CAP,
|
TEST_CAP,
|
||||||
(entity, context) -> entity.getCapability(TEST_CAP),
|
provider,
|
||||||
LivingEntity.class
|
LivingEntity.class
|
||||||
);
|
);
|
||||||
EntityCapabilityHelper.registerForEntityClass(
|
EntityCapabilityHelper.registerForEntityClass(
|
||||||
event,
|
event,
|
||||||
TEST_CAP,
|
TEST_CAP,
|
||||||
(entity, context) -> entity.getCapability(TEST_CAP),
|
provider,
|
||||||
Boat.class
|
Boat.class
|
||||||
);
|
);
|
||||||
EntityCapabilityHelper.registerForEntityClass(
|
EntityCapabilityHelper.registerForEntityClass(
|
||||||
event,
|
event,
|
||||||
TEST_CAP,
|
TEST_CAP,
|
||||||
(entity, context) -> entity.getCapability(TEST_CAP),
|
provider,
|
||||||
Minecart.class
|
Minecart.class
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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<AbstractedTestSyncData> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected TestSyncData createEmptyCapability(Entity entity) {
|
||||||
|
return new TestSyncData(entity.getId(), entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ResourceLocation getId() {
|
||||||
|
return Lib39.rl("test_data");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -287,8 +287,8 @@ public class TestSyncData extends AbstractedTestSyncData implements INeoForgeUpd
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deserializeNBT(CompoundTag nbt) {
|
public void deserializeNBT(CompoundTag t) {
|
||||||
NBTReader.of(nbt)
|
NBTReader.of(t)
|
||||||
.intValue(NBT_KEY_INT, integer -> testInt = integer)
|
.intValue(NBT_KEY_INT, integer -> testInt = integer)
|
||||||
.string(NBT_KEY_STRING, string -> testString = string)
|
.string(NBT_KEY_STRING, string -> testString = string)
|
||||||
.booleanValue(NBT_KEY_BOOLEAN, bool -> testBoolean = bool)
|
.booleanValue(NBT_KEY_BOOLEAN, bool -> testBoolean = bool)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,9 @@
|
||||||
package top.r3944realms.lib39.platform;
|
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.platform.services.IUtilHelper;
|
||||||
import top.r3944realms.lib39.util.NeoForgeBlockRegistryBuilder;
|
import top.r3944realms.lib39.util.NeoForgeBlockRegistryBuilder;
|
||||||
import top.r3944realms.lib39.util.block.BlockRegistryBuilder;
|
import top.r3944realms.lib39.util.block.BlockRegistryBuilder;
|
||||||
|
|
@ -12,8 +16,14 @@ public enum NeoForgeUtilHelper implements IUtilHelper {
|
||||||
* Instance forge util helper.
|
* Instance forge util helper.
|
||||||
*/
|
*/
|
||||||
INSTANCE;
|
INSTANCE;
|
||||||
|
@Contract(value = " -> new", pure = true)
|
||||||
@Override
|
@Override
|
||||||
public BlockRegistryBuilder getBlockRegistryBuilder() {
|
public @NotNull BlockRegistryBuilder getBlockRegistryBuilder() {
|
||||||
return new NeoForgeBlockRegistryBuilder();
|
return new NeoForgeBlockRegistryBuilder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SyncData2Manager<?> getSyncData2Manager() {
|
||||||
|
return CommonEventHandler.Game.getSyncData2Manager();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user