Compare commits

...

3 Commits

127 changed files with 2819 additions and 1624 deletions

View File

@ -1,4 +1,4 @@
plugins {
id 'fabric-loom' version '1.9-SNAPSHOT' apply(false)
id 'net.neoforged.moddev.legacyforge' version '2.0.103' apply(false)
id 'fabric-loom' version '1.9-SNAPSHOT' apply false
id 'net.neoforged.moddev' version '2.0.141' apply false
}

View File

@ -48,6 +48,9 @@ repositories {
name = 'BlameJared'
url = 'https://maven.blamejared.com'
}
repositories {
maven { url 'https://maven.covers1624.net/' }
}
}
// Declare capabilities on the outgoing configurations.
@ -101,24 +104,17 @@ processResources {
'mod_id' : mod_id,
'license' : license,
'description' : project.description,
"forge_version" : forge_version,
"forge_loader_version_range" : forge_loader_version_range,
'neoforge_version' : neoforge_version,
'neoforge_loader_version_range': neoforge_loader_version_range,
"neoforge_version": neoforge_version,
"neoforge_loader_version_range": neoforge_loader_version_range,
'credits' : credits,
'java_version' : java_version
]
var jsonExpandProps = expandProps.collectEntries {
key, value -> [(key): value instanceof String ? value.replace("\n", "\\\\n") : value]
}
filesMatching(['META-INF/mods.toml']) {
filesMatching(['pack.mcmeta', 'fabric.mod.json', 'META-INF/mods.toml', 'META-INF/neoforge.mods.toml', '*.mixins.json']) {
expand expandProps
}
filesMatching(['pack.mcmeta', 'fabric.mod.json', '*.mixins.json']) {
expand jsonExpandProps
}
inputs.properties(expandProps)
}
@ -130,19 +126,18 @@ publishing {
pom {
name = 'Lib39'
description = 'Lib39 is a general-purpose dependency library for Minecraft mods.'
url = 'https://github.com/3944Realms/lib39'
url = 'https://gitea.bot.leisuretimedock.top/R3944Realms/Lib39'
properties = [
'minecraft.version': project.minecraft_version,
'mod.version': project.version,
'forge.version': project.forge_version,
'java.version': '17'
'java.version': project.java_version
]
licenses {
license {
name = 'MIT'
url = 'https://raw.githubusercontent.com/3944Realms/lib39/refs/heads/main/LICENSE'
url = 'https://gitea.bot.leisuretimedock.top/R3944Realms/Lib39/raw/branch/MultiLoader_1_21_1/LICENSE'
distribution = 'repo'
}
}
@ -156,15 +151,15 @@ publishing {
}
scm {
connection = 'scm:git:https://github.com/3944Realms/lib39.git'
developerConnection = 'scm:git:ssh://git@github.com:3944Realms/lib39.git'
url = 'https://github.com/3944Realms/lib39'
connection = 'scm:git:git@bot.leisuretimedock.top:R3944Realms/Lib39.git'
developerConnection = 'scm:git:ssh://git@bot.leisuretimedock.top:R3944Realms/Lib39.git'
url = 'https://gitea.bot.leisuretimedock.top/R3944Realms/Lib39'
tag = 'main'
}
issueManagement {
system = 'GitHub'
url = 'https://github.com/3944Realms/lib39/issues'
system = 'Gitea'
url = 'https://gitea.bot.leisuretimedock.top/R3944Realms/Lib39/issues'
}
}
}

View File

@ -36,10 +36,11 @@ tasks.named('javadoc', Javadoc).configure {
source(configurations.commonJava)
options.encoding = 'UTF-8'
options.charSet = 'UTF-8'
options.links("https://docs.oracle.com/en/java/javase/17/docs/api/")
options.links("https://docs.oracle.com/en/java/javase/21/docs/api/")
options.memberLevel = JavadocMemberLevel.PUBLIC
options.addBooleanOption('Xdoclint:none', true)
options.addStringOption('doctitle', "${mod_id} ${minecraft_version} ${version} Javadoc")
}
tasks.named('sourcesJar', Jar) {

View File

@ -1,12 +1,14 @@
plugins {
id 'multiloader-common'
id 'net.neoforged.moddev.legacyforge'
id 'net.neoforged.moddev'
}
legacyForge {
mcpVersion = minecraft_version
if (file("src/main/resources/META-INF/accesstransformer.cfg").exists()) {
accessTransformers = ["src/main/resources/META-INF/accesstransformer.cfg"]
neoForge {
neoFormVersion = neo_form_version
// Automatically enable AccessTransformers if the file exists
def at = file('src/main/resources/META-INF/accesstransformer.cfg')
if (at.exists()) {
accessTransformers.from(at.absolutePath)
}
parchment {
minecraftVersion = parchment_minecraft
@ -14,13 +16,16 @@ legacyForge {
}
}
dependencies {
compileOnly(group: 'org.spongepowered', name: 'mixin', version: '0.8.5')
implementation(group: 'tschipp.carryon', name: 'carryon-common-1.20.1', version: '2.1.2') {
compileOnly group: 'org.spongepowered', name: 'mixin', version: '0.8.5'
implementation(group: 'tschipp.carryon', name: 'carryon-common-1.21.1', version: '2.2.4') {
transitive = false
}
implementation(annotationProcessor("io.github.llamalad7:mixinextras-common:0.2.0"))
implementation(group: 'com.google.code.findbugs', name: 'jsr305', version: '3.0.1')
// fabric and neoforge both bundle mixinextras, so it is safe to use it in common
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 {

View File

@ -49,7 +49,7 @@ public class Lib39 {
*/
@Contract("_ -> new")
public static @NotNull ResourceLocation rl(String path) {
return new ResourceLocation(Lib39.MOD_ID, path);
return ResourceLocation.fromNamespaceAndPath(Lib39.MOD_ID, path);
}
/**
@ -61,7 +61,7 @@ public class Lib39 {
*/
@Contract("_, _ -> new")
public static @NotNull ResourceLocation rl(String modId, String path) {
return new ResourceLocation(modId, path);
return ResourceLocation.fromNamespaceAndPath(modId, path);
}
/**
@ -72,7 +72,7 @@ public class Lib39 {
*/
@Contract("_ -> new")
public static @NotNull ResourceLocation mrl(String path) {
return new ResourceLocation(path);
return ResourceLocation.withDefaultNamespace(path);
}
/**

View File

@ -1,16 +1,13 @@
package top.r3944realms.lib39.base.datagen.provider;
import net.minecraft.core.HolderLookup;
import net.minecraft.data.PackOutput;
import net.minecraft.data.recipes.FinishedRecipe;
import net.minecraft.data.recipes.RecipeCategory;
import net.minecraft.data.recipes.RecipeProvider;
import net.minecraft.data.recipes.ShapelessRecipeBuilder;
import net.minecraft.data.recipes.*;
import net.minecraft.tags.ItemTags;
import net.minecraft.world.item.Items;
import org.jetbrains.annotations.NotNull;
import top.r3944realms.lib39.core.register.Lib39Items;
import java.util.function.Consumer;
import java.util.concurrent.CompletableFuture;
/**
* The type Lib 39 recipe provider.
@ -19,18 +16,19 @@ public class Lib39RecipeProvider extends RecipeProvider {
/**
* Instantiates a new Lib 39 recipe provider.
*
* @param output the output
* @param output the output
* @param registries the registries
*/
public Lib39RecipeProvider(PackOutput output) {
super(output);
public Lib39RecipeProvider(PackOutput output, CompletableFuture<HolderLookup.Provider> registries) {
super(output, registries);
}
@Override
public void buildRecipes(@NotNull Consumer<FinishedRecipe> consumer) {
public void buildRecipes(RecipeOutput recipeOutput) {
ShapelessRecipeBuilder.shapeless(RecipeCategory.MISC, Lib39Items.DOLL.get())
.requires(ItemTags.WOOL)
.requires(Items.ARMOR_STAND)
.unlockedBy("has_armor_stand",has(Items.ARMOR_STAND))
.save(consumer);
.save(recipeOutput);
}
}

View File

@ -17,18 +17,14 @@ import top.r3944realms.lib39.util.MathUtil;
import top.r3944realms.lib39.util.lang.FourConsumer;
import top.r3944realms.lib39.util.lang.Pair;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* The type Wheel widget.
*
* @author QiuShui1012
*/
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public class WheelWidget extends AbstractWidget {
/**
* The constant IGNORE_CURSOR_MOVE_LENGTH.
@ -78,6 +74,7 @@ public class WheelWidget extends AbstractWidget {
private Vector2f selectionEffectPos;
private boolean animationStarted = false;
/**
* Sets closing animation started.
*
@ -384,16 +381,15 @@ public class WheelWidget extends AbstractWidget {
return this.sections.size();
}
@Override
public boolean mouseScrolled(double mouseX, double mouseY, double delta) {
if (delta > 0) {
public boolean mouseScrolled(double mouseX, double mouseY, double scrollX, double scrollY) {
if (scrollY > 0) {
if (this.currentSectionIndex == this.getSectionSize() - 1) {
this.currentSectionIndex = 0;
} else {
this.currentSectionIndex++;
}
} else if (delta < 0) {
} else if (scrollY < 0) {
if (this.currentSectionIndex == 0) {
this.currentSectionIndex = this.getSectionSize() - 1;
} else {
@ -451,13 +447,8 @@ public class WheelWidget extends AbstractWidget {
}
@Override
public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) {
this.checkMousePos(mouseX, mouseY);
this.renderWidget(guiGraphics, mouseX, mouseY, partialTick);
}
@Override
protected void renderWidget(GuiGraphics guiGraphics, int i, int i1, float v) {
protected void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) {
checkMousePos(mouseX, mouseY);
RenderSystem.enableDepthTest();
RenderSystem.enableBlend();
this.renderClosingAnimation(guiGraphics);
@ -596,8 +587,8 @@ public class WheelWidget extends AbstractWidget {
PoseStack poseStack = guiGraphics.pose();
poseStack.pushPose();
setupRingShader(centerX, centerY, innerRadius, outerRadius);
Tesselator tesselator = Tesselator.getInstance();
BufferBuilder buffer = tesselator.getBuilder();
// 计算足够大的绘制区域来覆盖整个环形基于外半径
float margin = outerRadius + 100f; // 使用半径计算边距
@ -606,17 +597,16 @@ public class WheelWidget extends AbstractWidget {
float x2 = centerX + margin;
float y2 = centerY + margin;
buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR);
BufferBuilder buffer = tesselator.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR);
Matrix4f matrix = poseStack.last().pose();
buffer.vertex(matrix, x1, y1, -300).color(color).endVertex();
buffer.vertex(matrix, x1, y2, -300).color(color).endVertex();
buffer.vertex(matrix, x2, y2, -300).color(color).endVertex();
buffer.vertex(matrix, x2, y1, -300).color(color).endVertex();
buffer.addVertex(matrix, x1, y1, -300).setColor(color);
buffer.addVertex(matrix, x1, y2, -300).setColor(color);
buffer.addVertex(matrix, x2, y2, -300).setColor(color);
buffer.addVertex(matrix, x2, y1, -300).setColor(color);
setupRingShader(centerX, centerY, innerRadius, outerRadius);
BufferUploader.drawWithShader(buffer.end());
BufferUploader.drawWithShader(buffer.build());
RenderSystem.setShader(() -> null);
poseStack.popPose();
}
@ -703,17 +693,16 @@ public class WheelWidget extends AbstractWidget {
PoseStack poseStack = guiGraphics.pose();
Matrix4f matrix4f = poseStack.last().pose();
Tesselator tesselator = Tesselator.getInstance();
BufferBuilder buffer = tesselator.getBuilder();
buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR);
BufferBuilder buffer = tesselator.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR);
float x1 = centerX - radius - 5;
float y1 = centerY - radius - 5;
float x2 = centerX + radius + 5;
float y2 = centerY + radius + 5;
buffer.vertex(matrix4f, x1, y1, -200).color(color).endVertex();
buffer.vertex(matrix4f, x1, y2, -200).color(color).endVertex();
buffer.vertex(matrix4f, x2, y2, -200).color(color).endVertex();
buffer.vertex(matrix4f, x2, y1, -200).color(color).endVertex();
buffer.addVertex(matrix4f, x1, y1, -200).setColor(color);
buffer.addVertex(matrix4f, x1, y2, -200).setColor(color);
buffer.addVertex(matrix4f, x2, y2, -200).setColor(color);
buffer.addVertex(matrix4f, x2, y1, -200).setColor(color);
Window window = Minecraft.getInstance().getWindow();
float guiScale = (float) window.getGuiScale();
@ -732,11 +721,8 @@ 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.end()));
BufferUploader.drawWithShader(Objects.requireNonNull(buffer.build()));
RenderSystem.enableDepthTest();
}
@ -756,8 +742,15 @@ public class WheelWidget extends AbstractWidget {
protected void updateWidgetNarration(NarrationElementOutput narrationElementOutput) {
}
/**
* The type Wheel section.
* @param center 中心
* @param angle 角度
* @param angleStart 开始角度
* @param angleEnd 结束角度
* @param subTitle 副标题
* @param renderer 渲染操作
*/
public record WheelSection(
Vector2f center,

View File

@ -5,10 +5,10 @@ import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.model.Model;
import net.minecraft.client.model.geom.ModelLayerLocation;
import net.minecraft.client.model.geom.ModelPart;
import net.minecraft.client.model.geom.PartPose;
import net.minecraft.client.model.geom.builders.*;
import net.minecraft.client.renderer.RenderType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import top.r3944realms.lib39.Lib39;
/**
@ -31,13 +31,57 @@ public class DollModel extends Model {
private final ModelPart rightArmSlim;
private final ModelPart leftArmSlim;
private final ModelPart leftLeg;
@Nullable
private IDollPose currentPose;
/**
* Gets current pose.
*
* @return the current pose
*/
@Nullable
public IDollPose getCurrentPose() {
return currentPose;
}
/**
* Sets doll pose.
*
* @param dollPose the doll pose
*/
public void setDollPose(@NotNull IDollPose dollPose) {
this.currentPose = dollPose;
this.head.loadPose(dollPose.getHeadPose());
this.body.loadPose(dollPose.getBodyPose());
this.rightArm.loadPose(dollPose.getRightArmPose());
this.leftArm.loadPose(dollPose.getLeftArmPose());
this.rightArmSlim.loadPose(dollPose.getRightArmPose());
this.leftArmSlim.loadPose(dollPose.getLeftArmPose());
this.rightLeg.loadPose(dollPose.getRightLegPose());
this.leftLeg.loadPose(dollPose.getLeftLegPose());
}
/**
* Reset pose.
*/
public void resetPose() {
this.currentPose = DollPoses.DEFAULT;
this.head.resetPose();
this.body.resetPose();
this.rightArm.resetPose();
this.leftArm.resetPose();
this.rightArmSlim.resetPose();
this.leftArmSlim.resetPose();
this.rightLeg.resetPose();
this.leftLeg.resetPose();
}
/**
* Instantiates a new Doll model.
*
* @param root the root
*/
public DollModel(ModelPart root) {
public DollModel(@NotNull ModelPart root) {
super(RenderType::entityTranslucent);
this.head = root.getChild("head");
this.body = root.getChild("body");
@ -54,38 +98,118 @@ public class DollModel extends Model {
*
* @return the layer definition
*/
public static LayerDefinition createBodyLayer() {
public static @NotNull LayerDefinition createBodyLayer() {
return createBodyLayer(DollPoses.DEFAULT);
}
private static @NotNull LayerDefinition createBodyLayer(@NotNull IDollPose dollPoses) {
MeshDefinition meshdefinition = new MeshDefinition();
PartDefinition partdefinition = meshdefinition.getRoot();
partdefinition.addOrReplaceChild("head", CubeListBuilder.create().texOffs(0, 0).addBox(-4.0F, -8.0F, -4.0F, 8.0F, 8.0F, 8.0F, new CubeDeformation(0.0F)).texOffs(32, 0).addBox(-4.0F, -8.0F, -4.0F, 8.0F, 8.0F, 8.0F, new CubeDeformation(0.5F)), PartPose.offset(0.0F, 9.0F, 0.0F));
partdefinition.addOrReplaceChild("body", CubeListBuilder.create().texOffs(16, 16).addBox(-4.0F, 0.0F, -2.0F, 8.0F, 12.0F, 4.0F, new CubeDeformation(0.0F)).texOffs(16, 32).addBox(-4.0F, 0.0F, -2.0F, 8.0F, 12.0F, 4.0F, new CubeDeformation(0.25F)), PartPose.offset(0.0F, 9.0F, 0.0F));
partdefinition.addOrReplaceChild("right_arm", CubeListBuilder.create().texOffs(40, 16).addBox(-3.0F, -2.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.0F)).texOffs(40, 32).addBox(-3.0F, -2.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.25F)), PartPose.offsetAndRotation(-5.0F, 11.0F, 0.0F, 0.0F, 0.0F, 0.3927F));
partdefinition.addOrReplaceChild("right_arm_slim", CubeListBuilder.create().texOffs(40, 16).addBox(-2.0F, -2.0F, -2.0F, 3.0F, 12.0F, 4.0F, new CubeDeformation(0.0F)).texOffs(40, 32).addBox(-2.0F, -2.0F, -2.0F, 3.0F, 12.0F, 4.0F, new CubeDeformation(0.25F)), PartPose.offsetAndRotation(-5.0F, 11.0F, 0.0F, 0.0F, 0.0F, 0.3927F));
partdefinition.addOrReplaceChild("left_arm_slim", CubeListBuilder.create().texOffs(32, 48).addBox(-1.0F, -2.0F, -2.0F, 3.0F, 12.0F, 4.0F, new CubeDeformation(0.0F)).texOffs(48, 48).addBox(-1.0F, -2.0F, -2.0F, 3.0F, 12.0F, 4.0F, new CubeDeformation(0.25F)), PartPose.offsetAndRotation(5.0F, 11.0F, 0.0F, 0.0F, 0.0F, -0.3927F));
partdefinition.addOrReplaceChild("left_arm", CubeListBuilder.create().texOffs(32, 48).addBox(-1.0F, -2.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.0F)).texOffs(48, 48).addBox(-1.0F, -2.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.25F)), PartPose.offsetAndRotation(5.0F, 11.0F, 0.0F, 0.0F, 0.0F, -0.3927F));
partdefinition.addOrReplaceChild("right_leg", CubeListBuilder.create().texOffs(0, 16).addBox(-2.0F, 0.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.0F)).texOffs(0, 32).addBox(-2.0F, 0.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.25F)), PartPose.offsetAndRotation(-2.0F, 19.0F, -2.0F, -1.5708F, 0.3927F, 0.0F));
partdefinition.addOrReplaceChild("left_leg", CubeListBuilder.create().texOffs(16, 48).addBox(-2.0F, 0.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.0F)).texOffs(0, 48).addBox(-2.0F, 0.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.25F)), PartPose.offsetAndRotation(2.0F, 19.0F, -2.0F, -1.5708F, -0.3927F, 0.0F));
partdefinition.addOrReplaceChild(
"head",
CubeListBuilder.create()
.texOffs(0, 0)
.addBox(-4.0F, -8.0F, -4.0F, 8.0F, 8.0F, 8.0F, new CubeDeformation(0.0F))
.texOffs(32, 0)
.addBox(
-4.0F, -8.0F, -4.0F, 8.0F, 8.0F, 8.0F,
new CubeDeformation(0.5F)
), dollPoses.getHeadPose()
);
partdefinition.addOrReplaceChild(
"body",
CubeListBuilder.create()
.texOffs(16, 16)
.addBox(-4.0F, 0.0F, -2.0F, 8.0F, 12.0F, 4.0F, new CubeDeformation(0.0F))
.texOffs(16, 32)
.addBox(
-4.0F, 0.0F, -2.0F, 8.0F, 12.0F, 4.0F,
new CubeDeformation(0.25F)
), dollPoses.getBodyPose()
);
partdefinition.addOrReplaceChild(
"right_arm",
CubeListBuilder.create()
.texOffs(40, 16)
.addBox(-3.0F, -2.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.0F))
.texOffs(40, 32)
.addBox(
-3.0F, -2.0F, -2.0F, 4.0F, 12.0F, 4.0F,
new CubeDeformation(0.25F)
), dollPoses.getRightArmPose()
);
partdefinition.addOrReplaceChild(
"right_arm_slim",
CubeListBuilder.create()
.texOffs(40, 16)
.addBox(-2.0F, -2.0F, -2.0F, 3.0F, 12.0F, 4.0F, new CubeDeformation(0.0F))
.texOffs(40, 32)
.addBox(-2.0F, -2.0F, -2.0F, 3.0F, 12.0F, 4.0F,
new CubeDeformation(0.25F)
), dollPoses.getRightArmPose()
);
partdefinition.addOrReplaceChild(
"left_arm_slim",
CubeListBuilder.create()
.texOffs(32, 48)
.addBox(-1.0F, -2.0F, -2.0F, 3.0F, 12.0F, 4.0F, new CubeDeformation(0.0F))
.texOffs(48, 48)
.addBox(
-1.0F, -2.0F, -2.0F, 3.0F, 12.0F, 4.0F,
new CubeDeformation(0.25F)
), dollPoses.getLeftArmPose()
);
partdefinition.addOrReplaceChild(
"left_arm",
CubeListBuilder.create()
.texOffs(32, 48)
.addBox(-1.0F, -2.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.0F))
.texOffs(48, 48)
.addBox(
-1.0F, -2.0F, -2.0F, 4.0F, 12.0F, 4.0F,
new CubeDeformation(0.25F)
), dollPoses.getLeftArmPose()
);
partdefinition.addOrReplaceChild(
"right_leg",
CubeListBuilder.create()
.texOffs(0, 16)
.addBox(-2.0F, 0.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.0F))
.texOffs(0, 32)
.addBox(
-2.0F, 0.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.25F)
), dollPoses.getRightLegPose()
);
partdefinition.addOrReplaceChild(
"left_leg",
CubeListBuilder.create()
.texOffs(16, 48)
.addBox(-2.0F, 0.0F, -2.0F, 4.0F, 12.0F, 4.0F, new CubeDeformation(0.0F))
.texOffs(0, 48)
.addBox(
-2.0F, 0.0F, -2.0F, 4.0F, 12.0F, 4.0F,
new CubeDeformation(0.25F)
), dollPoses.getLeftLegPose()
);
return LayerDefinition.create(meshdefinition, 64, 64);
}
@Override
public void renderToBuffer(PoseStack poseStack, @NotNull VertexConsumer vertexConsumer, int packedLight, int packedOverlay, float red, float green, float blue, float alpha) {
public void renderToBuffer(@NotNull PoseStack poseStack, VertexConsumer vertexConsumer, int packedLight, int packedOverlay, int color) {
poseStack.pushPose();
poseStack.scale(0.5F, 0.5F, 0.5F);
poseStack.translate(0.0, 1.5010000467300415, 0.0);
this.head.render(poseStack, vertexConsumer, packedLight, packedOverlay, red, green, blue, alpha);
this.body.render(poseStack, vertexConsumer, packedLight, packedOverlay, red, green, blue, alpha);
this.head.render(poseStack, vertexConsumer, packedLight, packedOverlay, color);
this.body.render(poseStack, vertexConsumer, packedLight, packedOverlay, color);
if (this.slim) {
this.rightArmSlim.render(poseStack, vertexConsumer, packedLight, packedOverlay, red, green, blue, alpha);
this.leftArmSlim.render(poseStack, vertexConsumer, packedLight, packedOverlay, red, green, blue, alpha);
this.rightArmSlim.render(poseStack, vertexConsumer, packedLight, packedOverlay, color);
this.leftArmSlim.render(poseStack, vertexConsumer, packedLight, packedOverlay, color);
} else {
this.rightArm.render(poseStack, vertexConsumer, packedLight, packedOverlay, red, green, blue, alpha);
this.leftArm.render(poseStack, vertexConsumer, packedLight, packedOverlay, red, green, blue, alpha);
this.rightArm.render(poseStack, vertexConsumer, packedLight, packedOverlay, color);
this.leftArm.render(poseStack, vertexConsumer, packedLight, packedOverlay, color);
}
this.rightLeg.render(poseStack, vertexConsumer, packedLight, packedOverlay, red, green, blue, alpha);
this.leftLeg.render(poseStack, vertexConsumer, packedLight, packedOverlay, red, green, blue, alpha);
this.rightLeg.render(poseStack, vertexConsumer, packedLight, packedOverlay, color);
this.leftLeg.render(poseStack, vertexConsumer, packedLight, packedOverlay, color);
poseStack.popPose();
}
}

View File

@ -0,0 +1,93 @@
package top.r3944realms.lib39.client.model;
import net.minecraft.client.model.geom.PartPose;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.NotNull;
import top.r3944realms.lib39.Lib39;
/**
* The enum Doll poses.
*/
public enum DollPoses implements IDollPose{
/**
* Default doll poses.
*/
DEFAULT(
"default",
PartPose.offset(0.0F, 9.0F, 0.0F),
PartPose.offset(0.0F, 9.0F, 0.0F),
PartPose.offsetAndRotation(-5.0F, 11.0F, 0.0F, 0.0F, 0.0F, 0.3927F),
PartPose.offsetAndRotation(5.0F, 11.0F, 0.0F, 0.0F, 0.0F, -0.3927F),
PartPose.offsetAndRotation(-2.0F, 19.0F, -2.0F, -1.5708F, 0.3927F, 0.0F),
PartPose.offsetAndRotation(2.0F, 19.0F, -2.0F, -1.5708F, -0.3927F, 0.0F)
);
// 注册全局
private final ResourceLocation id;
private final Vec3 offset;
private final PartPose headPose;
private final PartPose bodyPose;
private final PartPose rightArmPose;
private final PartPose leftArmPose;
private final PartPose rightLegPose;
private final PartPose leftLegPose;
DollPoses(String name, PartPose headPose, PartPose bodyPose,
PartPose rightArmPose, PartPose leftArmPose,
PartPose rightLegPose, PartPose leftLegPose) {
this(name, Vec3.ZERO, headPose, bodyPose, rightArmPose, leftArmPose, rightLegPose, leftLegPose);
}
DollPoses(String name, Vec3 offset, PartPose headPose, PartPose bodyPose,
PartPose rightArmPose, PartPose leftArmPose,
PartPose rightLegPose, PartPose leftLegPose) {
this.id = Lib39.rl(name);
this.offset = offset;
this.headPose = headPose;
this.bodyPose = bodyPose;
this.rightArmPose = rightArmPose;
this.leftArmPose = leftArmPose;
this.rightLegPose = rightLegPose;
this.leftLegPose = leftLegPose;
}
@Override
public @NotNull ResourceLocation getId() {
return id;
}
@Override
public PartPose getHeadPose() {
return headPose;
}
@Override
public PartPose getBodyPose() {
return bodyPose;
}
@Override
public PartPose getRightArmPose() {
return rightArmPose;
}
@Override
public PartPose getLeftArmPose() {
return leftArmPose;
}
@Override
public PartPose getRightLegPose() {
return rightLegPose;
}
@Override
public PartPose getLeftLegPose() {
return leftLegPose;
}
@Override
public @NotNull Vec3 getTotalOffset() {
return offset;
}
}

View File

@ -0,0 +1,69 @@
package top.r3944realms.lib39.client.model;
import net.minecraft.client.model.geom.PartPose;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.NotNull;
/**
* The interface Doll pose.
*/
public interface IDollPose {
/**
* Gets id.
*
* @return the id
*/
@NotNull ResourceLocation getId();
/**
* Gets total offset.
*
* @return the total offset
*/
@NotNull default Vec3 getTotalOffset() {
return Vec3.ZERO;
}
/**
* Gets head pose.
*
* @return the head pose
*/
@NotNull PartPose getHeadPose();
/**
* Gets body pose.
*
* @return the body pose
*/
@NotNull PartPose getBodyPose();
/**
* Gets right arm pose.
*
* @return the right arm pose
*/
@NotNull PartPose getRightArmPose();
/**
* Gets left arm pose.
*
* @return the left arm pose
*/
@NotNull PartPose getLeftArmPose();
/**
* Gets right leg pose.
*
* @return the right leg pose
*/
@NotNull PartPose getRightLegPose();
/**
* Gets left leg pose.
*
* @return the left leg pose
*/
@NotNull PartPose getLeftLegPose();
}

View File

@ -254,8 +254,8 @@ public class RadialMenuRenderer<T> {
*/
private void drawSector(GuiGraphics guiGraphics, float startAngle, float angleSize,
float innerRadius, float outerRadius, float[] color) {
BufferBuilder buffer = Tesselator.getInstance().getBuilder();
buffer.begin(VertexFormat.Mode.TRIANGLE_STRIP, DefaultVertexFormat.POSITION_COLOR);
Tesselator instance = Tesselator.getInstance();
BufferBuilder buffer = instance.begin(VertexFormat.Mode.TRIANGLE_STRIP, DefaultVertexFormat.POSITION_COLOR);
Matrix4f matrix = guiGraphics.pose().last().pose();
float segments = Math.max(8, this.segments * (angleSize / 360f));
@ -269,14 +269,14 @@ public class RadialMenuRenderer<T> {
float sin = Mth.sin(rad);
// 外圈顶点
buffer.vertex(matrix, outerRadius * cos, outerRadius * sin, 0)
.color(color[0], color[1], color[2], color[3]).endVertex();
buffer.addVertex(matrix, outerRadius * cos, outerRadius * sin, 0)
.setColor(color[0], color[1], color[2], color[3]);
// 内圈顶点
buffer.vertex(matrix, innerRadius * cos, innerRadius * sin, 0)
.color(color[0], color[1], color[2], color[3] * 0.6f).endVertex();
buffer.addVertex(matrix, innerRadius * cos, innerRadius * sin, 0)
.setColor(color[0], color[1], color[2], color[3] * 0.6f);
}
BufferUploader.drawWithShader(buffer.end());
BufferUploader.drawWithShader(buffer.build());
}
/**

View File

@ -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<DollBlockEnt
boolean isWall = dollBlock instanceof WallDollBlock;
Direction direction = isWall ? blockState.getValue(WallSkullBlock.FACING) : null;
float rotation = isWall ? direction.toYRot() : RotationSegment.convertToDegrees(blockState.getValue(SkullBlock.ROTATION));
GameProfile profile = dollBlockEntity.getOwnerProfile();
Pair<ResourceLocation, Boolean> resourceLocationBooleanPair = DollItemRenderer.loadSkin(profile);
Pair<PlayerSkin.Model, RenderType> 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;
this.dollModel.renderToBuffer(poseStack, vertexConsumer, packedLight, OverlayTexture.NO_OVERLAY, 1.0F, 1.0F, 1.0F, 1.0F);
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<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()));
}
}

View File

@ -9,10 +9,13 @@ import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer;
import net.minecraft.client.renderer.MultiBufferSource;
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;
@ -61,54 +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<ResourceLocation, Boolean> resourceLocationBooleanPair = loadSkin(profile);
ResourceLocation playerSkin = resourceLocationBooleanPair.first;
boolean isSlim = resourceLocationBooleanPair.second;
// 直接从 DataComponents.PROFILE 获取 ResolvableProfile
ResolvableProfile profile = stack.get(DataComponents.PROFILE);
Pair<ResourceLocation, PlayerSkin.Model> 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.0F, 1.0F, 1.0F, 1.0F
);
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<ResourceLocation,Boolean> loadSkin(GameProfile profile) {
public static @NotNull Pair<ResourceLocation, PlayerSkin.Model> getSkinInfo(@NotNull ResolvableProfile profile) {
SkinManager skinManager = Minecraft.getInstance().getSkinManager();
ResourceLocation playerSkin;
boolean isSlim;
if (profile != null) {
playerSkin = skinManager.getInsecureSkinLocation(profile);
isSlim = GameProfileHelper.isSlimArms(profile);
} else {
playerSkin = DefaultPlayerSkin.getDefaultSkin(); //6 new SkinType("textures/entity/player/slim/steve.png", DefaultPlayerSkin.ModelType.SLIM),
isSlim = true;
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);
}
}

View File

@ -1,19 +1,24 @@
package top.r3944realms.lib39.content.block;
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;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.*;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
@ -34,6 +39,7 @@ import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import top.r3944realms.lib39.client.model.IDollPose;
import top.r3944realms.lib39.content.block.blockentity.DollBlockEntity;
import top.r3944realms.lib39.content.block.property.DollPose;
import top.r3944realms.lib39.core.register.Lib39BlockEntities;
@ -100,16 +106,16 @@ public abstract class AbstractDollBlock extends BaseEntityBlock implements Simpl
}
@Override
public @NotNull InteractionResult use(@NotNull BlockState blockState, @NotNull Level level, @NotNull BlockPos blockPos, @NotNull Player player,
@NotNull InteractionHand hand, @NotNull BlockHitResult hitResult) {
protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) {
if (level instanceof ServerLevel serverLevel) {
// 播放粒子效果
spawnNoteParticles(serverLevel, blockPos);
spawnNoteParticles(serverLevel, pos);
// 播放音效
playDollSound(serverLevel, blockPos);
playDollSound(serverLevel, pos);
}
return InteractionResult.SUCCESS;
}
/**
* 在玩偶位置生成音符粒子效果
*/
@ -171,13 +177,16 @@ public abstract class AbstractDollBlock extends BaseEntityBlock implements Simpl
}
@Override
public @NotNull ItemStack getCloneItemStack(@NotNull BlockGetter level, @NotNull BlockPos pos, @NotNull BlockState state) {
public ItemStack getCloneItemStack(LevelReader level, BlockPos pos, BlockState state) {
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;
@ -204,22 +213,38 @@ 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);
}
}
}
/**
* 生成自定义掉落物
*/
@Nullable
private List<ItemStack> getCustomDrops(DollBlockEntity dollEntity, LootParams.Builder params) {
private List<ItemStack> getCustomDrops(DollBlockEntity dollEntity, LootParams.@NotNull Builder params) {
if (params.getOptionalParameter(LootContextParams.THIS_ENTITY) instanceof Player player) {
if (player.isCreative()) {
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;
}

View File

@ -1,6 +1,8 @@
package top.r3944realms.lib39.content.block;
import com.mojang.serialization.MapCodec;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.block.BaseEntityBlock;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Mirror;
import net.minecraft.world.level.block.Rotation;
@ -17,7 +19,7 @@ import top.r3944realms.lib39.content.block.property.DollPose;
* The type Doll block.
*/
@SuppressWarnings("deprecation")
public class DollBlock extends AbstractDollBlock{
public class DollBlock extends AbstractDollBlock {
/**
* The constant MAX.
*/
@ -42,6 +44,10 @@ public class DollBlock extends AbstractDollBlock{
);
}
@Override
protected MapCodec<? extends BaseEntityBlock> codec() {
return simpleCodec(p -> new DollBlock());
}
@Override
public @Nullable BlockState getStateForPlacement(@NotNull BlockPlaceContext context) {
BlockState stateForPlacement = super.getStateForPlacement(context);
return stateForPlacement != null ? stateForPlacement.setValue(ROTATION, RotationSegment.convertToSegment((context.getRotation()+180) % 360)) : null;

View File

@ -1,11 +1,9 @@
package top.r3944realms.lib39.content.block;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.Direction;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.HorizontalDirectionalBlock;
import net.minecraft.world.level.block.Mirror;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.*;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.DirectionProperty;
@ -35,6 +33,12 @@ public class WallDollBlock extends AbstractDollBlock {
.setValue(FACING, Direction.NORTH)
);
}
@Override
protected MapCodec<? extends BaseEntityBlock> codec() {
return simpleCodec(p -> new WallDollBlock());
}
public @NotNull BlockState rotate(@NotNull BlockState state, @NotNull Rotation rotation) {
return state.setValue(FACING, rotation.rotate(state.getValue(FACING)));
}

View File

@ -1,98 +1,196 @@
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.NbtUtils;
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.NotNull;
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 javax.annotation.Nullable;
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;
private static final String TAG_PROFILE = "profile";
// 静态缓存 SkullBlockEntity 共享或独立
@Nullable
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;
/**
* Instantiates a new Doll block entity.
*
* @param pos the pos
* @param blockState the block state
*/
public DollBlockEntity(BlockPos pos, BlockState blockState) {
super(Lib39BlockEntities.DOLL_BLOCK_ENTITY.get(), pos, blockState);
}
protected void saveAdditional(@NotNull CompoundTag tag) {
super.saveAdditional(tag);
NBTWriter.of(tag)
.compoundIf(GameProfileHelper.TAG_OWN_PROFILE, owner != null, () -> NbtUtils.writeGameProfile(new CompoundTag(), this.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<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);
}
});
}
public void load(@NotNull CompoundTag tag) {
super.load(tag);
NBTReader.of(tag)
.compound(GameProfileHelper.TAG_OWN_PROFILE, compoundTag -> setOwner(NbtUtils.readGameProfile(compoundTag)));
private static CompletableFuture<Optional<GameProfile>> fetchProfileByName(String name, Services services) {
return services.profileCache().getAsync(name).thenCompose(optional -> {
LoadingCache<UUID, CompletableFuture<Optional<GameProfile>>> 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<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.
*
* @return the owner profile
* 公开的静态方法异步获取 GameProfile复用 SkullBlockEntity 的缓存或使用自己的
*/
public static CompletableFuture<Optional<GameProfile>> fetchGameProfile(String name) {
if (profileCacheByName != null && name != null && !name.isEmpty()) {
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 GameProfile getOwnerProfile() {
public ResolvableProfile getOwnerProfile() {
return this.owner;
}
@Override
public ClientboundBlockEntityDataPacket getUpdatePacket() {
return ClientboundBlockEntityDataPacket.create(this);
}
public @NotNull CompoundTag getUpdateTag() {
return this.saveWithoutMetadata();
@Override
public CompoundTag getUpdateTag(HolderLookup.Provider 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() {
SkullBlockEntity.updateGameprofile(this.owner, gameProfile -> {
this.owner = gameProfile;
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);
}
}
}
}
@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);
}
}
}

View File

@ -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;
@ -29,16 +30,20 @@ public class DollItem extends StandingAndWallBlockItem implements Equipable {
super(Lib39Blocks.DOLL.get(), Lib39Blocks.WALL_DOLL.get(), properties, Direction.DOWN);
}
@Override
public void appendHoverText(@NotNull ItemStack stack, @Nullable Level level, @NotNull List<Component> tooltip, @NotNull TooltipFlag flag) {
GameProfile profileFromItemStack = GameProfileHelper.getProfileFromItemStack(stack);
if (profileFromItemStack != null && profileFromItemStack.getName() != null) {
tooltip.add(Component.translatable("tooltip.lib39.content.doll.hover.1", profileFromItemStack.getName()));
public void appendHoverText(ItemStack stack, TooltipContext context, List<Component> tooltipComponents, TooltipFlag tooltipFlag) {
super.appendHoverText(stack, context, tooltipComponents, tooltipFlag);
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()));
}
}
tooltip.add(Component.translatable("tooltip.lib39.content.doll.hover.2"));
tooltipComponents.add(Component.translatable("tooltip.lib39.content.doll.hover.2"));
}
@Override
public @NotNull EquipmentSlot getEquipmentSlot() {
return EquipmentSlot.HEAD;

View File

@ -10,11 +10,10 @@ import net.minecraft.commands.Commands;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import top.r3944realms.lib39.base.datagen.value.Lib39LangKey;
import top.r3944realms.lib39.platform.Services;
import javax.annotation.Nullable;
/**
* The interface Help command.
*/

View File

@ -1109,6 +1109,8 @@ public class CommandNode {
/**
* 葉子節點配置記錄
* @param description 介绍
* @param parameters 参数列表
*/
public record LeafConfig(@NotNull MutableComponent description,
@Nullable List<Parameter> parameters) {

View File

@ -8,6 +8,8 @@ import java.util.List;
/**
* The type Parameter.
* @param name 参数名
* @param required 是否必须
*/
public record Parameter(String name, boolean required) {

View File

@ -11,14 +11,17 @@ import java.util.stream.Collectors;
/**
* The type Compat manager.
*
* @param <C> the type parameter
*/
@SuppressWarnings("unused")
public abstract class CompatManager {
public abstract class CompatManager<C extends ICompat> implements ICompatManager<C> {
/**
* Gets id.
*
* @return the id
*/
@Override
public ResourceLocation getId() {
return id;
}
@ -31,10 +34,7 @@ public abstract class CompatManager {
* The Id.
*/
protected final ResourceLocation id;
/**
* The Compats.
*/
protected final Map<ResourceLocation, ICompat> compats = new HashMap<>();
/**
* The Initialized.
*/
@ -47,6 +47,7 @@ public abstract class CompatManager {
/**
* Initialize.
*/
@Override
public void initialize() {
initializeAllCompat();
onLoadComplete();
@ -68,7 +69,8 @@ public abstract class CompatManager {
* @param id the id
* @param compat the compat
*/
public void registerCompat(ResourceLocation id, ICompat compat) {
@Override
public void registerCompat(ResourceLocation id, C compat) {
if (initialized) {
// 已初始化直接注册
doRegisterCompat(id, compat);
@ -85,12 +87,12 @@ public abstract class CompatManager {
* @param id the id
* @param compat the compat
*/
protected void doRegisterCompat(ResourceLocation id, ICompat compat) {
if (compats.containsKey(id)) {
protected void doRegisterCompat(ResourceLocation id, C compat) {
if (getCompatMap().containsKey(id)) {
logger.warn("Compat with id {} is already registered!", id);
return;
}
compats.put(id, compat);
getCompatMap().put(id, compat);
logger.debug("Registered compat: {}", id);
}
@ -101,7 +103,8 @@ public abstract class CompatManager {
* @param path the path
* @param compat the compat
*/
public void registerCompat(String namespace, String path, ICompat compat) {
@Override
public void registerCompat(String namespace, String path, C compat) {
registerCompat(Lib39.rl(namespace, path), compat);
}
@ -112,14 +115,14 @@ public abstract class CompatManager {
* 初始化所有兼容模块并应用事件监听器
*/
protected synchronized void initializeAllCompat() {
logger.info("Initializing {} compatibility modules", compats.size());
logger.info("Initializing {} compatibility modules", getCompatMap().size());
// 先处理所有缓存的注册
pendingTasks.forEach(Runnable::run);
pendingTasks.clear();
// 初始化所有兼容模块
for (Map.Entry<ResourceLocation, ICompat> entry : compats.entrySet()) {
for (Map.Entry<ResourceLocation, C> entry : getCompatMap().entrySet()) {
if (!entry.getValue().isInitialized() && entry.getValue().isModLoaded()) {
try {
entry.getValue().initialize();
@ -139,8 +142,9 @@ public abstract class CompatManager {
* @param id the id
* @return the compat
*/
public Optional<ICompat> getCompat(ResourceLocation id) {
return Optional.ofNullable(compats.get(id));
@Override
public Optional<C> getCompat(ResourceLocation id) {
return Optional.ofNullable(getCompatMap().get(id));
}
/**
@ -149,8 +153,9 @@ public abstract class CompatManager {
* @param id the id
* @return the boolean
*/
@Override
public boolean hasCompat(ResourceLocation id) {
return compats.containsKey(id);
return getCompatMap().containsKey(id);
}
/**
@ -158,8 +163,9 @@ public abstract class CompatManager {
*
* @param id the id
*/
@Override
public void unregisterCompat(ResourceLocation id) {
ICompat removed = compats.remove(id);
C removed = getCompatMap().remove(id);
if (removed != null) {
logger.debug("Unregistered compat: {}", id);
}
@ -170,9 +176,9 @@ public abstract class CompatManager {
*
* @return the loaded compats
*/
public List<ICompat> getLoadedCompats() {
return compats.values().stream()
.filter(ICompat::isModLoaded)
public List<C> getLoadedCompats() {
return getCompatMap().values().stream()
.filter(C::isModLoaded)
.collect(Collectors.toList());
}
@ -180,8 +186,8 @@ public abstract class CompatManager {
* On load complete.
*/
public void onLoadComplete() {
logger.info("Calling onLoadComplete for {} compatibility modules", compats.size());
for (Map.Entry<ResourceLocation, ICompat> entry : compats.entrySet()) {
logger.info("Calling onLoadComplete for {} compatibility modules", getCompatMap().size());
for (Map.Entry<ResourceLocation, C> entry : getCompatMap().entrySet()) {
try {
entry.getValue().onLoadComplete();
} catch (Exception e) {

View File

@ -0,0 +1,72 @@
package top.r3944realms.lib39.core.compat;
import net.minecraft.resources.ResourceLocation;
import java.util.Map;
import java.util.Optional;
/**
* The interface Compat manager.
*
* @param <C> the type parameter
*/
public interface ICompatManager<C extends ICompat> {
/**
* Gets id.
*
* @return the id
*/
ResourceLocation getId();
/**
* Gets compat map.
*
* @return the compat map
*/
Map<ResourceLocation, C> getCompatMap();
/**
* Initialize.
*/
void initialize();
/**
* Register compat.
*
* @param id the id
* @param compat the compat
*/
void registerCompat(ResourceLocation id, C compat);
/**
* Register compat.
*
* @param namespace the namespace
* @param path the path
* @param compat the compat
*/
void registerCompat(String namespace, String path, C compat);
/**
* Gets compat.
*
* @param id the id
* @return the compat
*/
Optional<C> getCompat(ResourceLocation id);
/**
* Has compat boolean.
*
* @param id the id
* @return the boolean
*/
boolean hasCompat(ResourceLocation id);
/**
* Unregister compat.
*
* @param id the id
*/
void unregisterCompat(ResourceLocation id);
}

View File

@ -0,0 +1,31 @@
package top.r3944realms.lib39.core.compat;
import net.minecraft.resources.ResourceLocation;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
/**
* The type Simple compat manager.
*/
public class SimpleCompatManager extends CompatManager<ICompat> {
/**
* The Compats.
*/
Map<ResourceLocation, ICompat> compats = new HashMap<>();
/**
* Instantiates a new Compat manager.
*
* @param id the id
*/
public SimpleCompatManager(@NotNull ResourceLocation id) {
super(id);
}
@Override
public Map<ResourceLocation, ICompat> getCompatMap() {
return compats;
}
}

View File

@ -7,7 +7,7 @@ import net.minecraft.nbt.Tag;
*
* @param <T> the type parameter
*/
public interface INBTSerializable <T extends Tag>{
public interface INBTSerializable <T extends Tag> {
/**
* Serialize nbt t.
*
@ -18,7 +18,7 @@ public interface INBTSerializable <T extends Tag>{
/**
* Deserialize nbt.
*
* @param var1 the var 1
* @param t the var
*/
void deserializeNBT(T var1);
void deserializeNBT(T t);
}

View File

@ -123,26 +123,6 @@ public abstract class LanguageProvider implements DataProvider {
this.add(key.getDescriptionId(), name);
}
/**
* Add enchantment.
*
* @param key the key
* @param name the name
*/
public void addEnchantment(@NotNull Supplier<? extends Enchantment> key, String name) {
this.add(key.get(), name);
}
/**
* Add.
*
* @param key the key
* @param name the name
*/
public void add(@NotNull Enchantment key, String name) {
this.add(key.getDescriptionId(), name);
}
/**
* Add effect.
*

View File

@ -530,29 +530,29 @@ public abstract class AbstractFabricItem extends Item {
}
@Override
public void appendHoverText(@NotNull ItemStack stack, @Nullable Level level,
@NotNull List<Component> tooltip, @NotNull TooltipFlag flag) {
super.appendHoverText(stack, level, tooltip, flag);
public void appendHoverText(ItemStack stack, TooltipContext context, List<Component> tooltipComponents, TooltipFlag tooltipFlag) {
super.appendHoverText(stack, context, tooltipComponents, tooltipFlag);
tooltip.add(Component.literal("§7右键点击在 3 秒后执行"));
tooltip.add(Component.literal("§7§e准星瞄准生物§7的数据查询"));
tooltip.add(Component.literal("§7§oShift + 右键§7进行§e客户端-服务器双端同步检查§7"));
tooltip.add(Component.literal(""));
tooltip.add(Component.literal("§6查询延迟: §e3秒"));
tooltip.add(Component.literal("§6瞄准距离: §e20格"));
tooltip.add(Component.literal("§6冷却时间: §e1秒"));
tooltip.add(Component.literal(""));
tooltip.add(Component.literal("§a单端查询内容:"));
tooltip.add(Component.literal("§7- 基础数据字段"));
tooltip.add(Component.literal("§7- 自定义数据结构"));
tooltip.add(Component.literal("§7- 数据验证状态"));
tooltip.add(Component.literal("§7- 同步状态信息"));
tooltip.add(Component.literal(""));
tooltip.add(Component.literal("§e双端同步检查:"));
tooltip.add(Component.literal("§7- 客户端和服务器同时查询"));
tooltip.add(Component.literal("§7- 字段级同步状态对比"));
tooltip.add(Component.literal("§7- 总体同步率计算"));
tooltip.add(Component.literal("§7- 双端数据状态差异"));
tooltip.add(Component.literal("§7- 同步建议"));
tooltipComponents.add(Component.literal("§7右键点击在 3 秒后执行"));
tooltipComponents.add(Component.literal("§7§e准星瞄准生物§7的数据查询"));
tooltipComponents.add(Component.literal("§7§oShift + 右键§7进行§e客户端-服务器双端同步检查§7"));
tooltipComponents.add(Component.literal(""));
tooltipComponents.add(Component.literal("§6查询延迟: §e3秒"));
tooltipComponents.add(Component.literal("§6瞄准距离: §e20格"));
tooltipComponents.add(Component.literal("§6冷却时间: §e1秒"));
tooltipComponents.add(Component.literal(""));
tooltipComponents.add(Component.literal("§a单端查询内容:"));
tooltipComponents.add(Component.literal("§7- 基础数据字段"));
tooltipComponents.add(Component.literal("§7- 自定义数据结构"));
tooltipComponents.add(Component.literal("§7- 数据验证状态"));
tooltipComponents.add(Component.literal("§7- 同步状态信息"));
tooltipComponents.add(Component.literal(""));
tooltipComponents.add(Component.literal("§e双端同步检查:"));
tooltipComponents.add(Component.literal("§7- 客户端和服务器同时查询"));
tooltipComponents.add(Component.literal("§7- 字段级同步状态对比"));
tooltipComponents.add(Component.literal("§7- 总体同步率计算"));
tooltipComponents.add(Component.literal("§7- 双端数据状态差异"));
tooltipComponents.add(Component.literal("§7- 同步建议"));
}
}

View File

@ -268,27 +268,27 @@ public abstract class AbstractNeoForgeItem extends Item {
}
@Override
public void appendHoverText(@NotNull ItemStack stack, @Nullable Level level,
@NotNull List<Component> tooltip, @NotNull TooltipFlag flag) {
super.appendHoverText(stack, level, tooltip, flag);
public void appendHoverText(ItemStack stack, TooltipContext context, List<Component> tooltipComponents, TooltipFlag tooltipFlag) {
super.appendHoverText(stack, context, tooltipComponents, tooltipFlag);
tooltip.add(Component.literal("§7右键点击触发§e准星瞄准生物§7的"));
tooltip.add(Component.literal("§7测试数据随机变换"));
tooltip.add(Component.literal("§7§oShift + 右键§7操作§e自身§7数据"));
tooltip.add(Component.literal(""));
tooltip.add(Component.literal("§6冷却时间: §e1秒"));
tooltip.add(Component.literal("§6瞄准距离: §e20格"));
tooltip.add(Component.literal(""));
tooltip.add(Component.literal("§a变换类型:"));
tooltip.add(Component.literal("§7- 完全随机数据"));
tooltip.add(Component.literal("§7- 字符串+计数器"));
tooltip.add(Component.literal("§7- 数值数据"));
tooltip.add(Component.literal("§7- 自定义数据"));
tooltip.add(Component.literal("§7- 重置默认值"));
tooltip.add(Component.literal("§7- 玩家专属数据"));
tooltip.add(Component.literal(""));
tooltip.add(Component.literal("§e自身操作特性:"));
tooltip.add(Component.literal("§7- 显示数据预览"));
tooltip.add(Component.literal("§7- 玩家专属数据变换"));
tooltipComponents.add(Component.literal("§7右键点击触发§e准星瞄准生物§7的"));
tooltipComponents.add(Component.literal("§7测试数据随机变换"));
tooltipComponents.add(Component.literal("§7§oShift + 右键§7操作§e自身§7数据"));
tooltipComponents.add(Component.literal(""));
tooltipComponents.add(Component.literal("§6冷却时间: §e1秒"));
tooltipComponents.add(Component.literal("§6瞄准距离: §e20格"));
tooltipComponents.add(Component.literal(""));
tooltipComponents.add(Component.literal("§a变换类型:"));
tooltipComponents.add(Component.literal("§7- 完全随机数据"));
tooltipComponents.add(Component.literal("§7- 字符串+计数器"));
tooltipComponents.add(Component.literal("§7- 数值数据"));
tooltipComponents.add(Component.literal("§7- 自定义数据"));
tooltipComponents.add(Component.literal("§7- 重置默认值"));
tooltipComponents.add(Component.literal("§7- 玩家专属数据"));
tooltipComponents.add(Component.literal(""));
tooltipComponents.add(Component.literal("§e自身操作特性:"));
tooltipComponents.add(Component.literal("§7- 显示数据预览"));
tooltipComponents.add(Component.literal("§7- 玩家专属数据变换"));
}
}

View File

@ -1,21 +1,27 @@
package top.r3944realms.lib39.mixin.carryon;
import com.llamalad7.mixinextras.sugar.Local;
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.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.AtomicReference;
/**
* The type Mixin carried object render.
*/
@SuppressWarnings("DuplicatedCode")
@Pseudo
@Mixin(value = CarriedObjectRender.class, remap = false)
public class MixinCarriedObjectRender {
@ -28,8 +34,12 @@ public class MixinCarriedObjectRender {
)
private static ItemStack warpDollItem$1(ItemStack stack, @Local(ordinal = 0, argsOnly = true) Player player) {
if (stack.getItem() instanceof DollItem) {
CompoundTag compound = CarryOnDataManager.getCarryData(player).getNbt().getCompound("tile").getCompound(GameProfileHelper.TAG_OWN_PROFILE);
stack.getOrCreateTag().put(GameProfileHelper.TAG_OWN_PROFILE, compound);
CompoundTag compound = CarryOnDataManager.getCarryData(player).getNbt().getCompound("tile");
AtomicReference<GameProfile> gameProfileAtomicReference = new AtomicReference<>();
NBTReader.of(compound).gameProfile("profile", gameProfileAtomicReference::set);
if (gameProfileAtomicReference.get() != null) {
GameProfileHelper.saveProfileToItemStack(stack, new ResolvableProfile(gameProfileAtomicReference.get()));
}
}
return stack;
}
@ -40,12 +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) {
CompoundTag compound = CarryOnDataManager.getCarryData(player).getNbt().getCompound("tile").getCompound(GameProfileHelper.TAG_OWN_PROFILE);
stack.getOrCreateTag().put(GameProfileHelper.TAG_OWN_PROFILE, compound);
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<GameProfile> gameProfileAtomicReference = new AtomicReference<>();
NBTReader.of(compound).gameProfile("profile", gameProfileAtomicReference::set);
if (gameProfileAtomicReference.get() != null) {
GameProfileHelper.saveProfileToItemStack(tileItem, new ResolvableProfile(gameProfileAtomicReference.get()));
}
}
return stack;
return tileItem;
}
}

View File

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

View File

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

View File

@ -8,26 +8,81 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.PlayerInfo;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.resources.DefaultPlayerSkin;
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;
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<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
*/
@ -41,7 +96,7 @@ public class GameProfileHelper {
public static @NotNull ResourceLocation resolveSkinTexture(@NotNull GameProfile gameProfile) {
return IClientOnly.check(() ->
Minecraft.getInstance().getSkinManager()
.getInsecureSkinLocation(gameProfile));
.getInsecureSkin(gameProfile)).texture();
}
/**
@ -53,7 +108,7 @@ public class GameProfileHelper {
public static ResourceLocation getSkinTexture(@Nullable GameProfile gameProfile) {
return IClientOnly.check(() -> {
if (gameProfile == null) {
return DefaultPlayerSkin.getDefaultSkin();
return Lib39.mrl("textures/entity/player/wide/steve.png");
}
return resolveSkinTexture(gameProfile);
});
@ -71,7 +126,7 @@ public class GameProfileHelper {
PlayerInfo playerInfo = Objects.requireNonNull(Minecraft.getInstance()
.getConnection())
.getPlayerInfo(clientPlayer.getUUID());
return playerInfo != null && "slim".equals(playerInfo.getModelName());
return playerInfo != null && "slim".equals(playerInfo.getSkin().model().id());
}
return false;
});
@ -88,7 +143,7 @@ public class GameProfileHelper {
if (player.level().isClientSide && player instanceof AbstractClientPlayer) {
PlayerInfo info = Objects.requireNonNull(Minecraft.getInstance().getConnection())
.getPlayerInfo(player.getUUID());
return info != null ? info.getModelName() : "default";
return info != null ? info.getSkin().model().id() : "default";
}
return "default";
});
@ -96,10 +151,6 @@ public class GameProfileHelper {
}
/**
* The constant TAG_BE.
*/
public static final String TAG_BE = "BlockEntityTag";
/**
* The constant TAG_OWN_PROFILE.
*/
@ -150,7 +201,7 @@ public class GameProfileHelper {
GameProfile profile = player.getGameProfile();
for (Property property : profile.getProperties().get("textures")) {
try {
String json = new String(Base64.getDecoder().decode(property.getValue()));
String json = new String(Base64.getDecoder().decode(property.value()));
JsonObject obj = JsonParser.parseString(json).getAsJsonObject();
JsonObject textures = obj.getAsJsonObject("textures");
JsonObject skin = textures.getAsJsonObject("SKIN");
@ -197,7 +248,7 @@ public class GameProfileHelper {
// 获取第一个texture属性通常是皮肤
Property textureProperty = textures.iterator().next();
String value = textureProperty.getValue();
String value = textureProperty.value();
try {
return isSlimFromTextureData(value);
@ -268,7 +319,7 @@ public class GameProfileHelper {
}
Property textureProperty = textures.iterator().next();
String value = textureProperty.getValue();
String value = textureProperty.value();
try {
byte[] decodedBytes = Base64.getDecoder().decode(value);
@ -291,64 +342,37 @@ public class GameProfileHelper {
}
/**
* 从ItemStack的NBT中读取GameProfile
* 从ItemStack的组件中读取GameProfile
*
* @param stack the stack
* @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;
}
CompoundTag tag = stack.getTag();
if (tag == null) {
return null;
}
AtomicReference<GameProfile> profileRef = new AtomicReference<>();
// 检查方块实体数据
NBTReader.of(tag)
.compound(TAG_BE, compoundTag ->
NBTReader.of(compoundTag)
.compound("OwnerProfile", ct -> profileRef.set(NbtUtils.readGameProfile(ct)))
)
.compound("OwnerProfile", ct -> {
if (profileRef.get() == null) { //兼容写法
profileRef.set(NbtUtils.readGameProfile(ct));
}
});
return profileRef.get();
if (stack.isEmpty()) return null;
ResolvableProfile profile = stack.get(DataComponents.PROFILE);
return profile != null ? profile : null;
}
/**
* 将GameProfile保存到ItemStack的NBT
* 将GameProfile保存到ItemStack的组件
*
* @param stack the stack
* @param profile the profile
*/
public static void saveProfileToItemStack(@NotNull ItemStack stack, @Nullable GameProfile profile) {
if (stack.isEmpty()) {
return;
}
CompoundTag tag = stack.getOrCreateTag();
public static void saveProfileToItemStack(@NotNull ItemStack stack, @Nullable ResolvableProfile profile) {
if (stack.isEmpty()) return;
if (profile == null) {
// 移除现有数据
NBTReader.of(tag)
.compound(TAG_BE, ct -> tag.remove(TAG_OWN_PROFILE));
tag.remove(TAG_BE);
tag.remove(TAG_OWN_PROFILE);
return;
stack.remove(DataComponents.PROFILE);
} else {
stack.set(DataComponents.PROFILE, profile);
}
// 创建方块实体数据
NBTWriter.of(tag)
.compound(TAG_BE, writer ->
writer
.compound(TAG_OWN_PROFILE, NbtUtils.writeGameProfile(new CompoundTag(), profile))
);
}
/**
@ -362,17 +386,7 @@ public class GameProfileHelper {
return false;
}
CompoundTag tag = stack.getTag();
if (tag == null) {
return false;
}
if (tag.contains(TAG_BE)) {
CompoundTag blockEntityTag = tag.getCompound(TAG_BE);
return blockEntityTag.contains(TAG_OWN_PROFILE);
}
return tag.contains(TAG_OWN_PROFILE);
return !stack.isEmpty() && stack.has(DataComponents.PROFILE);
}
}

View File

@ -15,6 +15,8 @@
package top.r3944realms.lib39.util.nbt;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.Property;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.world.phys.Vec3;
@ -378,6 +380,123 @@ public class NBTReader {
return this;
}
/**
* Game profile nbt reader.
*
* @param key the key
* @param setter the setter
* @return the nbt reader
*/
public NBTReader gameProfile(String key, Consumer<GameProfile> setter) {
if (nbt.contains(key, CompoundTag.TAG_COMPOUND)) {
CompoundTag tag = nbt.getCompound(key);
GameProfile profile = readGameProfileFromTag(tag);
if (profile != null) {
setter.accept(profile);
}
}
return this;
}
/**
* Game profile nbt reader with default value.
*
* @param key the key
* @param setter the setter
* @param defaultValue the default value
* @return the nbt reader
*/
public NBTReader gameProfile(String key, Consumer<GameProfile> setter, GameProfile defaultValue) {
if (nbt.contains(key, CompoundTag.TAG_COMPOUND)) {
CompoundTag tag = nbt.getCompound(key);
GameProfile profile = readGameProfileFromTag(tag);
if (profile != null) {
setter.accept(profile);
return this;
}
}
setter.accept(defaultValue);
return this;
}
/**
* Read GameProfile from CompoundTag.
*
* @param tag the tag
* @return the game profile, or null if invalid
*/
@Nullable
private static GameProfile readGameProfileFromTag(@NotNull CompoundTag tag) {
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);
// 支持 "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");
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;
}
}
/**
* Vec 3 nbt reader.
*
@ -469,6 +588,7 @@ public class NBTReader {
return this;
}
/**
* Nested nbt reader.
*

View File

@ -1,5 +1,8 @@
package top.r3944realms.lib39.util.nbt;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.Property;
import io.netty.util.internal.StringUtil;
import net.minecraft.nbt.*;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Contract;
@ -562,7 +565,6 @@ public class NBTWriter {
* @param tag the tag
* @return the nbt writer
*/
// 直接操作Tag
public NBTWriter tag(String key, Tag tag) {
if (tag != null) {
root.put(key, tag);
@ -570,6 +572,60 @@ public class NBTWriter {
return this;
}
/**
* Game profile nbt writer.
*
* @param key the key
* @param profile the profile
* @return the nbt writer
*/
public NBTWriter gameProfile(String key, @NotNull GameProfile profile) {
root.put(key, writeGameProfile(profile));
return this;
}
private CompoundTag writeGameProfile(@NotNull GameProfile profile) {
CompoundTag tag = new CompoundTag();
if (!StringUtil.isNullOrEmpty(profile.getName())) {
tag.putString("Name", profile.getName());
}
if (profile.getId() != null) {
tag.putUUID("Id", profile.getId());
}
if (!profile.getProperties().isEmpty()) {
CompoundTag compoundTag = new CompoundTag();
for(String keySet : profile.getProperties().keySet()) {
ListTag propListTag = new ListTag();
for(Property property : profile.getProperties().get(keySet)) {
CompoundTag propTag = new CompoundTag();
propTag.putString("Value", property.value());
if (property.hasSignature()) {
propTag.putString("Signature", property.signature());
}
propListTag.add(propTag);
}
compoundTag.put(keySet, propListTag);
}
tag.put("Properties", compoundTag);
}
return tag;
}
/**
* GameProfile if nbt writer.
*
* @param key the key
* @param condition the condition
* @param value the value
* @return the nbt writer
*/
public NBTWriter gameProfileIf(String key, boolean condition, Supplier<GameProfile> value) {
if (condition && value != null) {
root.put(key, writeGameProfile(value.get()));
}
return this;
}
/**
* String if nbt writer.
*
@ -578,7 +634,6 @@ public class NBTWriter {
* @param value the value
* @return the nbt writer
*/
// 条件添加方法
public NBTWriter stringIf(String key, boolean condition, Supplier<String> value) {
if (condition && value != null) {
root.putString(key, value.get());

View File

@ -2,9 +2,15 @@ package top.r3944realms.lib39.util.villager;
import com.google.common.collect.Lists;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.core.component.DataComponents;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.tags.EnchantmentTags;
import net.minecraft.tags.ItemTags;
import net.minecraft.tags.TagKey;
import net.minecraft.util.Mth;
import net.minecraft.util.RandomSource;
@ -16,15 +22,18 @@ import net.minecraft.world.entity.npc.VillagerType;
import net.minecraft.world.item.*;
import net.minecraft.world.item.alchemy.Potion;
import net.minecraft.world.item.alchemy.PotionBrewing;
import net.minecraft.world.item.alchemy.PotionUtils;
import net.minecraft.world.item.alchemy.PotionContents;
import net.minecraft.world.item.component.DyedItemColor;
import net.minecraft.world.item.component.SuspiciousStewEffects;
import net.minecraft.world.item.enchantment.Enchantment;
import net.minecraft.world.item.enchantment.EnchantmentHelper;
import net.minecraft.world.item.enchantment.EnchantmentInstance;
import net.minecraft.world.item.trading.ItemCost;
import net.minecraft.world.item.trading.MerchantOffer;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.levelgen.structure.Structure;
import net.minecraft.world.level.saveddata.maps.MapDecoration;
import net.minecraft.world.level.saveddata.maps.MapDecorationType;
import net.minecraft.world.level.saveddata.maps.MapItemSavedData;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
@ -32,6 +41,8 @@ import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* 村民交易构建器
@ -116,21 +127,22 @@ public class TradeBuilder {
/**
* 创建宝藏地图交易
*
* @param emeraldCost 绿宝石价格
* @param destination the destination
* @param displayName 显示名称
* @param destinationTyp the destination typ
* @param maxUses 最大使用次数
* @param villagerXp 村民获得的经验
* @param emeraldCost 绿宝石价格
* @param destination the destination
* @param displayName 显示名称
* @param destinationType the destination type
* @param maxUses 最大使用次数
* @param villagerXp 村民获得的经验
* @return 交易实例 treasure map for emeralds
*/
@Contract(pure = true)
public static @NotNull TreasureMapForEmeralds createTreasureMapTrade(
int emeraldCost, TagKey<Structure> destination, String displayName, MapDecoration.Type destinationTyp, int maxUses, int villagerXp) {
return new TreasureMapForEmeralds(emeraldCost, destination, displayName, destinationTyp, maxUses, villagerXp);
int emeraldCost, TagKey<Structure> destination, String displayName,
Holder<MapDecorationType> destinationType, int maxUses, int villagerXp) {
return new TreasureMapForEmeralds(emeraldCost, destination, displayName, destinationType, maxUses, villagerXp);
}
/**
* 创建染色盔甲交易
*
@ -173,8 +185,8 @@ public class TradeBuilder {
}
public MerchantOffer getOffer(@NotNull Entity trader, @NotNull RandomSource random) {
ItemStack itemstack = new ItemStack(this.item, this.cost);
return new MerchantOffer(itemstack, new ItemStack(Items.EMERALD), this.maxUses, this.villagerXp, this.priceMultiplier);
ItemCost itemCost = new ItemCost(this.item, this.cost);
return new MerchantOffer(itemCost, new ItemStack(Items.EMERALD), this.maxUses, this.villagerXp, this.priceMultiplier);
}
}
@ -260,7 +272,7 @@ public class TradeBuilder {
}
public MerchantOffer getOffer(@NotNull Entity trader, @NotNull RandomSource random) {
return new MerchantOffer(new ItemStack(Items.EMERALD, this.emeraldCost), new ItemStack(this.itemStack.getItem(), this.numberOfItems), this.maxUses, this.villagerXp, this.priceMultiplier);
return new MerchantOffer(new ItemCost(Items.EMERALD, this.emeraldCost), new ItemStack(this.itemStack.getItem(), this.numberOfItems), this.maxUses, this.villagerXp, this.priceMultiplier);
}
}
@ -271,7 +283,7 @@ public class TradeBuilder {
/**
* The Effect.
*/
final MobEffect effect;
private final Holder<MobEffect> effect;
/**
* The Duration.
*/
@ -289,7 +301,7 @@ public class TradeBuilder {
* @param duration the duration
* @param xp the xp
*/
public SuspiciousStewForEmerald(MobEffect effect, int duration, int xp) {
public SuspiciousStewForEmerald(Holder<MobEffect> effect, int duration, int xp) {
this.effect = effect;
this.duration = duration;
this.xp = xp;
@ -299,8 +311,9 @@ public class TradeBuilder {
@Nullable
public MerchantOffer getOffer(@NotNull Entity trader, @NotNull RandomSource random) {
ItemStack itemstack = new ItemStack(Items.SUSPICIOUS_STEW, 1);
SuspiciousStewItem.saveMobEffect(itemstack, this.effect, this.duration);
return new MerchantOffer(new ItemStack(Items.EMERALD, 1), itemstack, 12, this.xp, this.priceMultiplier);
itemstack.set(DataComponents.SUSPICIOUS_STEW_EFFECTS,
new SuspiciousStewEffects(List.of(new SuspiciousStewEffects.Entry(effect, this.duration))));
return new MerchantOffer(new ItemCost(Items.EMERALD, 1), itemstack, 12, this.xp, this.priceMultiplier);
}
}
@ -355,7 +368,7 @@ public class TradeBuilder {
@Nullable
public MerchantOffer getOffer(@NotNull Entity trader, @NotNull RandomSource random) {
return new MerchantOffer(new ItemStack(Items.EMERALD, this.emeraldCost), new ItemStack(this.fromItem.getItem(), this.fromCount), new ItemStack(this.toItem.getItem(), this.toCount), this.maxUses, this.villagerXp, this.priceMultiplier);
return new MerchantOffer(new ItemCost(Items.EMERALD, this.emeraldCost), Optional.of(new ItemCost(this.fromItem.getItem(), this.fromCount)), new ItemStack(this.toItem.getItem(), this.toCount), this.maxUses, this.villagerXp, this.priceMultiplier);
}
}
@ -400,9 +413,10 @@ public class TradeBuilder {
public MerchantOffer getOffer(@NotNull Entity trader, @NotNull RandomSource random) {
int i = 5 + random.nextInt(15);
ItemStack itemstack = EnchantmentHelper.enchantItem(random, new ItemStack(this.itemStack.getItem()), i, false);
ItemStack itemstack = EnchantmentHelper.enchantItem(random, new ItemStack(this.itemStack.getItem()), i ,
trader.level().registryAccess(), Optional.empty());
int j = Math.min(this.baseEmeraldCost + i, 64);
ItemStack itemstack1 = new ItemStack(Items.EMERALD, j);
ItemCost itemstack1 = new ItemCost(Items.EMERALD, j);
return new MerchantOffer(itemstack1, itemstack, this.maxUses, this.villagerXp, this.priceMultiplier);
}
}
@ -439,8 +453,8 @@ public class TradeBuilder {
@Nullable
public MerchantOffer getOffer(@NotNull Entity trader, @NotNull RandomSource random) {
if (trader instanceof VillagerDataHolder) {
ItemStack itemstack = new ItemStack(this.trades.get(((VillagerDataHolder)trader).getVillagerData().getType()), this.cost);
return new MerchantOffer(itemstack, new ItemStack(Items.EMERALD), this.maxUses, this.villagerXp, 0.05F);
ItemCost itemCost = new ItemCost(this.trades.get(((VillagerDataHolder)trader).getVillagerData().getType()), this.cost);
return new MerchantOffer(itemCost, new ItemStack(Items.EMERALD), this.maxUses, this.villagerXp, 0.05F);
} else {
return null;
}
@ -484,11 +498,15 @@ public class TradeBuilder {
}
public MerchantOffer getOffer(@NotNull Entity trader, @NotNull RandomSource random) {
ItemStack itemstack = new ItemStack(Items.EMERALD, this.emeraldCost);
List<Potion> list = BuiltInRegistries.POTION.stream().filter((effects) -> !effects.getEffects().isEmpty() && PotionBrewing.isBrewablePotion(effects)).toList();
Potion potion = list.get(random.nextInt(list.size()));
ItemStack itemstack1 = PotionUtils.setPotion(new ItemStack(this.toItem.getItem(), this.toCount), potion);
return new MerchantOffer(itemstack, new ItemStack(this.fromItem, this.fromCount), itemstack1, this.maxUses, this.villagerXp, this.priceMultiplier);
ItemCost itemcost = new ItemCost(Items.EMERALD, this.emeraldCost);
List<? extends Holder<Potion>> brewablePotions = BuiltInRegistries.POTION.holders()
.filter(potion -> !potion.value().getEffects().isEmpty())
.filter(trader.level().potionBrewing()::isBrewablePotion)
.toList();
Holder<Potion> potion = brewablePotions.get(random.nextInt(brewablePotions.size()));
ItemStack itemstack = new ItemStack(this.toItem.getItem(), this.toCount);
itemstack.set(DataComponents.POTION_CONTENTS, new PotionContents(potion));
return new MerchantOffer(itemcost, Optional.of(new ItemCost(this.fromItem, this.fromCount)), itemstack, this.maxUses, this.villagerXp, this.priceMultiplier);
}
}
@ -509,12 +527,17 @@ public class TradeBuilder {
}
public MerchantOffer getOffer(@NotNull Entity trader, @NotNull RandomSource random) {
List<Enchantment> list = BuiltInRegistries.ENCHANTMENT.stream().filter(Enchantment::isTradeable).toList();
Enchantment enchantment = list.get(random.nextInt(list.size()));
Registry<Enchantment> registry = trader.level().registryAccess().registryOrThrow(Registries.ENCHANTMENT);
List<? extends Holder<Enchantment>> list = registry.holders()
.filter(holder -> holder.is(EnchantmentTags.TRADEABLE))
.toList();
Holder<Enchantment> holder = list.get(random.nextInt(list.size()));
Enchantment enchantment = holder.value();
int i = Mth.nextInt(random, enchantment.getMinLevel(), enchantment.getMaxLevel());
ItemStack itemstack = EnchantedBookItem.createForEnchantment(new EnchantmentInstance(enchantment, i));
ItemStack itemstack = EnchantedBookItem.createForEnchantment(new EnchantmentInstance(holder, i));
int j = 2 + random.nextInt(5 + i * 10) + 3 * i;
if (enchantment.isTreasureOnly()) {
if (holder.is(EnchantmentTags.DOUBLE_TRADE_PRICE)) {
j *= 2;
}
@ -522,7 +545,7 @@ public class TradeBuilder {
j = 64;
}
return new MerchantOffer(new ItemStack(Items.EMERALD, j), new ItemStack(Items.BOOK), itemstack, 12, this.villagerXp, 0.2F);
return new MerchantOffer(new ItemCost(Items.EMERALD, j), Optional.of(new ItemCost(Items.BOOK)), itemstack, 12, this.villagerXp, 0.2F);
}
}
@ -533,7 +556,7 @@ public class TradeBuilder {
private final int emeraldCost;
private final TagKey<Structure> destination;
private final String displayName;
private final MapDecoration.Type destinationType;
private final Holder<MapDecorationType> destinationType;
private final int maxUses;
private final int villagerXp;
@ -547,7 +570,7 @@ public class TradeBuilder {
* @param maxUses the max uses
* @param villagerXp the villager xp
*/
public TreasureMapForEmeralds(int emeraldCost, TagKey<Structure> destination, String displayName, MapDecoration.Type destinationType, int maxUses, int villagerXp) {
public TreasureMapForEmeralds(int emeraldCost, TagKey<Structure> destination, String displayName, Holder<MapDecorationType> destinationType, int maxUses, int villagerXp) {
this.emeraldCost = emeraldCost;
this.destination = destination;
this.displayName = displayName;
@ -566,8 +589,10 @@ public class TradeBuilder {
ItemStack itemstack = MapItem.create(serverlevel, blockpos.getX(), blockpos.getZ(), (byte)2, true, true);
MapItem.renderBiomePreviewMap(serverlevel, itemstack);
MapItemSavedData.addTargetDecoration(itemstack, blockpos, "+", this.destinationType);
itemstack.setHoverName(Component.translatable(this.displayName));
return new MerchantOffer(new ItemStack(Items.EMERALD, this.emeraldCost), new ItemStack(Items.COMPASS), itemstack, this.maxUses, this.villagerXp, 0.2F);
MapItemSavedData.addTargetDecoration(itemstack, blockpos, "+", this.destinationType);
itemstack.set(DataComponents.ITEM_NAME, Component.translatable(this.displayName));
return new MerchantOffer(new ItemCost(Items.EMERALD, this.emeraldCost),
Optional.of(new ItemCost(Items.COMPASS)), itemstack, this.maxUses, this.villagerXp, 0.2F);
} else {
return null;
}
@ -610,23 +635,23 @@ public class TradeBuilder {
}
public MerchantOffer getOffer(@NotNull Entity trader, @NotNull RandomSource random) {
ItemStack itemstack = new ItemStack(Items.EMERALD, this.value);
ItemStack itemstack1 = new ItemStack(this.item);
if (this.item instanceof DyeableArmorItem) {
List<DyeItem> list = Lists.newArrayList();
list.add(getRandomDye(random));
ItemCost itemCost = new ItemCost(Items.EMERALD, this.value);
ItemStack armorStack = new ItemStack(this.item);
if (armorStack.is(ItemTags.DYEABLE)) {
List<DyeItem> dyes = Lists.newArrayList();
dyes.add(getRandomDye(random));
if (random.nextFloat() > 0.7F) {
list.add(getRandomDye(random));
dyes.add(getRandomDye(random));
}
if (random.nextFloat() > 0.8F) {
list.add(getRandomDye(random));
dyes.add(getRandomDye(random));
}
itemstack1 = DyeableLeatherItem.dyeArmor(itemstack1, list);
// 1.21.1: 使用 DYED_COLOR 组件设置颜色
armorStack = DyedItemColor.applyDyes(armorStack, dyes);
}
return new MerchantOffer(itemstack, itemstack1, this.maxUses, this.villagerXp, 0.2F);
return new MerchantOffer(itemCost, armorStack, this.maxUses, this.villagerXp, 0.2F);
}
private static @NotNull DyeItem getRandomDye(@NotNull RandomSource random) {

View File

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

View File

@ -6,7 +6,6 @@ uniform vec4 ColorModulator;
uniform vec2 FramebufferSize;
uniform vec2 Center;
uniform float Radius;
uniform float AntiAliasingRadius;
out vec4 fragColor;

View File

@ -32,14 +32,6 @@
"values": [
0.0
]
},
{
"name": "AntiAliasingRadius",
"type": "float",
"count": 1,
"values": [
1.5
]
}
]
}

View File

@ -3,9 +3,10 @@
"minVersion": "0.8",
"package": "top.r3944realms.lib39.mixin",
"refmap": "${mod_id}.refmap.json",
"compatibilityLevel": "JAVA_17",
"compatibilityLevel": "JAVA_21",
"mixins": [
"carryon.MixinCarriedObjectRender",
"minecraft.MixinEntity",
"minecraft.CreativeModeTabsAccessor"
],
"client": [

View File

@ -1,26 +1,20 @@
import net.fabricmc.loom.task.RemapJarTask
plugins {
id 'multiloader-loader'
id 'fabric-loom'
}
repositories {
maven { url 'https://maven.covers1624.net/' }
}
dependencies {
minecraft "com.mojang:minecraft:${minecraft_version}"
mappings loom.layered {
officialMojangMappings()
parchment("org.parchmentmc.data:parchment-${parchment_minecraft}:${parchment_version}@zip")
}
modImplementation(group: 'tschipp.carryon', name: 'carryon-fabric-1.20.1', version: '2.1.2.7') {
modImplementation(group: 'tschipp.carryon', name: 'carryon-fabric-1.21.1', version: '2.2.4.4') {
transitive = false
}
modImplementation "net.fabricmc:fabric-loader:${fabric_loader_version}"
modImplementation "net.fabricmc.fabric-api:fabric-api:${fabric_version}"
implementation group: 'com.google.code.findbugs', name: 'jsr305', version: '3.0.1'
implementation project(":common")
modImplementation "curse.maven:jade-324717:6291330"
modImplementation "curse.maven:jade-324717:7545228"
testImplementation "net.fabricmc:fabric-loader-junit:${fabric_loader_version}"
localRuntime 'net.covers1624:DevLogin:0.1.0.5'
}
@ -36,7 +30,7 @@ loom {
accessWidenerPath.set(project(":common").file("src/main/resources/${mod_id}.accesswidener"))
}
mixin {
defaultRefmapName.set("${mod_id}.refmap.json")
defaultRefmapName.set("${mod_id}.fabric.refmap.json")
}
runs {
client {
@ -102,7 +96,7 @@ tasks.named('javadoc', Javadoc) {
classpath += project(':common').sourceSets.main.compileClasspath
options.encoding = 'UTF-8'
options.charSet = 'UTF-8'
options.links("https://docs.oracle.com/en/java/javase/17/docs/api/")
options.links("https://docs.oracle.com/en/java/javase/21/docs/api/")
options.memberLevel = JavadocMemberLevel.PUBLIC
options.addBooleanOption('Xdoclint:none', true)
options.addStringOption('doctitle', "${mod_id} ${minecraft_version} ${version} Javadoc")
@ -136,13 +130,6 @@ remapSourcesJar {
inputFile.set(tasks.named('sourcesJar').get().archiveFile)
}
// javadocJar创建remap任务
tasks.register('remapJavadocJar', RemapJarTask) {
dependsOn tasks.named('javadocJar')
inputFile.set(tasks.named('javadocJar').get().archiveFile)
archiveClassifier.set('javadoc')
addNestedDependencies = false
}
// remapped artifacts添加到发布配置
publishing {
@ -159,61 +146,20 @@ publishing {
builtBy remapSourcesJar
classifier = 'sources'
}
artifact(remapJavadocJar) {
builtBy remapJavadocJar
artifact(javadocJar) {
builtBy javadocJar
classifier = 'javadoc'
}
pom {
name = 'Lib39'
description = 'Lib39 is a general-purpose dependency library for Minecraft mods.'
url = 'https://github.com/3944Realms/lib39'
properties = [
'minecraft.version': project.minecraft_version,
'mod.version': project.version,
'fabric.version': project.fabric_version,
'java.version': '17'
]
licenses {
license {
name = 'MIT'
url = 'https://raw.githubusercontent.com/3944Realms/lib39/refs/heads/main/LICENSE'
distribution = 'repo'
}
}
developers {
developer {
id = 'R3944Realms'
name = "${mod_author}"
email = 'f256198830@hotmail.com'
}
}
scm {
connection = 'scm:git:https://github.com/3944Realms/lib39.git'
developerConnection = 'scm:git:ssh://git@github.com:3944Realms/lib39.git'
url = 'https://github.com/3944Realms/lib39'
tag = 'main'
}
issueManagement {
system = 'GitHub'
url = 'https://github.com/3944Realms/lib39/issues'
}
}
}
}
}
test {
useJUnitPlatform()
}
test {
useJUnitPlatform()
}
tasks.named('generateMetadataFileForMavenJavaPublication') {
dependsOn tasks.named('remapJavadocJar')
dependsOn tasks.named('remapJar')
dependsOn tasks.named('remapSourcesJar')
}
tasks.named('generateMetadataFileForMavenJavaPublication') {
dependsOn tasks.named('remapJar')
dependsOn tasks.named('remapSourcesJar')
dependsOn tasks.named('javadocJar')
}
}

View File

@ -1,11 +1,13 @@
package top.r3944realms.lib39.base.compat.jade;
import net.minecraft.resources.ResourceLocation;
import org.jetbrains.annotations.NotNull;
import snownee.jade.api.IWailaClientRegistration;
import snownee.jade.api.IWailaPlugin;
import snownee.jade.api.WailaPlugin;
import top.r3944realms.lib39.Lib39;
import top.r3944realms.lib39.base.compat.jade.provider.FabricDollComponentProvider;
import top.r3944realms.lib39.content.block.AbstractDollBlock;
import top.r3944realms.lib39.content.block.DollBlock;
/**
@ -19,7 +21,7 @@ public class FabricJadePlugin implements IWailaPlugin {
public static final ResourceLocation UID = Lib39.rl("lib39");
@Override
public void registerClient(IWailaClientRegistration registration) {
registration.registerBlockComponent(new FabricDollComponentProvider(), DollBlock.class);
public void registerClient(@NotNull IWailaClientRegistration registration) {
registration.registerBlockComponent(new FabricDollComponentProvider(), AbstractDollBlock.class);
}
}

View File

@ -3,6 +3,7 @@ package top.r3944realms.lib39.base.compat.jade.provider;
import com.mojang.authlib.GameProfile;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import org.jetbrains.annotations.NotNull;
import snownee.jade.api.BlockAccessor;
import snownee.jade.api.IBlockComponentProvider;
import snownee.jade.api.ITooltip;
@ -20,12 +21,16 @@ public class FabricDollComponentProvider implements IBlockComponentProvider {
}
@Override
public void appendTooltip(ITooltip iTooltip, BlockAccessor blockAccessor, IPluginConfig iPluginConfig) {
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()));
}
}
}
}
}

View File

@ -9,24 +9,30 @@ import net.fabricmc.fabric.api.itemgroup.v1.ItemGroupEvents;
import net.fabricmc.fabric.api.lookup.v1.entity.EntityApiLookup;
import net.minecraft.Util;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.component.DataComponents;
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;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.component.ResolvableProfile;
import net.minecraft.world.level.Level;
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;
@ -42,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;
/**
@ -181,19 +188,35 @@ public class FabricCommonEventHandler {
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())));
}
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) {
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();
SkullBlockEntity.updateGameprofile(profile,
profile1 -> GameProfileHelper.saveProfileToItemStack(copied, profile1)
);
copied.setCount(left.getCount());
return AnvilUpdateCallback.AnvilUpdateResult.withOutput(copied, 1, 1);
ResolvableProfile resolvableProfile = new ResolvableProfile(profile);
output.set(DataComponents.PROFILE, resolvableProfile);
// 使用 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.setHoverName(Component.translatable("invalid.player_name.too_long"));
return AnvilUpdateCallback.AnvilUpdateResult.withOutput(defaultInstance, 0, 0);
ItemStack errorOutput = Items.BARRIER.getDefaultInstance();
errorOutput.set(DataComponents.CUSTOM_NAME,
Component.translatable("invalid.player_name.too_long"));
return AnvilUpdateCallback.AnvilUpdateResult.withOutput(errorOutput, 0, 0);
}
});
EntityApiLookup.get(FabricTestSyncData.ID, AbstractedTestSyncData.class, Void.class)

View File

@ -1,7 +1,8 @@
package top.r3944realms.lib39.core.network;
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
import top.r3944realms.lib39.core.network.toClient.SyncNBTLookupDataEntityS2CPacket;
import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry;
import top.r3944realms.lib39.core.network.toClient.SyncNBTLookupDataEntityS2CPayload;
/**
* The type Fabric network handler.
@ -12,10 +13,13 @@ public class FabricNetworkHandler {
* 注册客户端接收的数据包
*/
public static void registerClientReceivers() {
ClientPlayNetworking.registerGlobalReceiver(
SyncNBTLookupDataEntityS2CPacket.TYPE,
SyncNBTLookupDataEntityS2CPacket::receive
PayloadTypeRegistry.playS2C().register(
SyncNBTLookupDataEntityS2CPayload.TYPE,
SyncNBTLookupDataEntityS2CPayload.STREAM_CODEC
);
ClientPlayNetworking.registerGlobalReceiver(
SyncNBTLookupDataEntityS2CPayload.TYPE,
SyncNBTLookupDataEntityS2CPayload::handle
);
}
}

View File

@ -1,91 +0,0 @@
package top.r3944realms.lib39.core.network.toClient;
import net.fabricmc.fabric.api.networking.v1.FabricPacket;
import net.fabricmc.fabric.api.networking.v1.PacketSender;
import net.fabricmc.fabric.api.networking.v1.PacketType;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.Level;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import top.r3944realms.lib39.Lib39;
import top.r3944realms.lib39.core.event.FabricCommonEventHandler;
import top.r3944realms.lib39.core.sync.ISyncData;
import top.r3944realms.lib39.core.sync.NBTEntitySyncData;
import top.r3944realms.lib39.core.sync.SyncData2Manager;
import java.util.Optional;
/**
* The type Sync nbt lookup data entity s 2 c packet.
*/
public record SyncNBTLookupDataEntityS2CPacket(int entityId, ResourceLocation id, CompoundTag data) implements FabricPacket {
/**
* The constant SYNC_NBT_LOOKUP_PACKET_ID.
*/
public static final ResourceLocation SYNC_NBT_LOOKUP_PACKET_ID =
Lib39.rl("sync_nbt_lookup_data_entity");
/**
* The constant TYPE.
*/
public static final PacketType<SyncNBTLookupDataEntityS2CPacket> TYPE = PacketType.create(
SYNC_NBT_LOOKUP_PACKET_ID,
buf -> new SyncNBTLookupDataEntityS2CPacket(buf.readInt(), buf.readResourceLocation(), buf.readNbt())
);
/**
* Instantiates a new Sync nbt data s 2 c pack.
*
* @param entityId the entity id
* @param data the data
*/
public SyncNBTLookupDataEntityS2CPacket(int entityId, @NotNull NBTEntitySyncData data) {
this(entityId, data.id(), data.serializeNBT());
}
@Override
public void write(@NotNull FriendlyByteBuf friendlyByteBuf) {
friendlyByteBuf.writeInt(entityId);
friendlyByteBuf.writeResourceLocation(id);
friendlyByteBuf.writeNbt(data);
}
@Contract(value = " -> new", pure = true)
@Override
public @NotNull PacketType<?> getType() {
return TYPE;
}
/**
* Receive.
*
* @param packet the packet
* @param localPlayer the local player
* @param packetSender the packet sender
*/
public static void receive(@NotNull SyncNBTLookupDataEntityS2CPacket packet, @NotNull LocalPlayer localPlayer, PacketSender packetSender) {
Level level = localPlayer.level();
Entity entity = level.getEntity(packet.entityId);
if (entity != null) {
Optional<SyncData2Manager.DataProvider<Entity, ISyncData<?>>> lookupOpt =
FabricCommonEventHandler
.getSyncData2Manager()
.getDataProvider(packet.id);
lookupOpt.flatMap(dataProvider -> dataProvider.getData(entity))
.ifPresent(lookup -> {
if (lookup instanceof NBTEntitySyncData nbtLookup) {
CompoundTag current = nbtLookup.serializeNBT();
if (!current.equals(packet.data)) {
nbtLookup.deserializeNBT(packet.data);
}
} else Lib39.LOGGER.debug("Unhandled sync data: {}", packet.data);
}
);
}
}
}

View File

@ -0,0 +1,109 @@
package top.r3944realms.lib39.core.network.toClient;
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.Level;
import org.jetbrains.annotations.NotNull;
import top.r3944realms.lib39.Lib39;
import top.r3944realms.lib39.core.event.FabricCommonEventHandler;
import top.r3944realms.lib39.core.sync.ISyncData;
import top.r3944realms.lib39.core.sync.NBTEntitySyncData;
import top.r3944realms.lib39.core.sync.SyncData2Manager;
import java.util.Optional;
/**
* The type Sync nbt lookup data entity s 2 c payload.
*/
public record SyncNBTLookupDataEntityS2CPayload(int entityId, ResourceLocation id, CompoundTag data) implements CustomPacketPayload {
/**
* The constant SYNC_NBT_LOOKUP_PACKET_ID.
*/
public static final ResourceLocation SYNC_NBT_LOOKUP_PACKET_ID =
Lib39.rl("sync_nbt_lookup_data_entity");
/**
* The constant TYPE.
*/
public static final Type<SyncNBTLookupDataEntityS2CPayload> TYPE = new Type<>(SYNC_NBT_LOOKUP_PACKET_ID);
/**
* Stream codec for serializing/deserializing the packet.
*/
public static final StreamCodec<RegistryFriendlyByteBuf, SyncNBTLookupDataEntityS2CPayload> STREAM_CODEC =
StreamCodec.ofMember(SyncNBTLookupDataEntityS2CPayload::write, SyncNBTLookupDataEntityS2CPayload::new);
/**
* Instantiates a new Sync nbt data s 2 c pack.
*
* @param entityId the entity id
* @param data the data
*/
public SyncNBTLookupDataEntityS2CPayload(int entityId, @NotNull NBTEntitySyncData data) {
this(entityId, data.id(), data.serializeNBT());
}
/**
* Instantiates from buffer.
*
* @param buf the buffer
*/
public SyncNBTLookupDataEntityS2CPayload(RegistryFriendlyByteBuf buf) {
this(buf.readInt(), buf.readResourceLocation(), buf.readNbt());
}
/**
* Write.
*
* @param friendlyByteBuf the friendly byte buf
*/
public void write(@NotNull FriendlyByteBuf friendlyByteBuf) {
friendlyByteBuf.writeInt(entityId);
friendlyByteBuf.writeResourceLocation(id);
friendlyByteBuf.writeNbt(data);
}
/**
* Receive.
*
* @param payload the packet
* @param context the context
*/
public static void handle(@NotNull SyncNBTLookupDataEntityS2CPayload payload, ClientPlayNetworking.Context context) {
LocalPlayer localPlayer = context.player();
Level level = localPlayer.level();
Entity entity = level.getEntity(payload.entityId);
if (entity != null) {
Optional<SyncData2Manager.DataProvider<Entity, ISyncData<?>>> lookupOpt =
FabricCommonEventHandler
.getSyncData2Manager()
.getDataProvider(payload.id);
lookupOpt.flatMap(dataProvider -> dataProvider.getData(entity))
.ifPresent(lookup -> {
if (lookup instanceof NBTEntitySyncData nbtLookup) {
CompoundTag current = nbtLookup.serializeNBT();
if (!current.equals(payload.data)) {
nbtLookup.deserializeNBT(payload.data);
}
} else {
Lib39.LOGGER.debug("Unhandled sync data: {}", payload.data);
}
});
}
}
@Override
public Type<? extends CustomPacketPayload> type() {
return TYPE;
}
}

View File

@ -5,7 +5,7 @@ import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.players.PlayerList;
import top.r3944realms.lib39.core.event.FabricCommonEventHandler;
import top.r3944realms.lib39.core.network.toClient.SyncNBTLookupDataEntityS2CPacket;
import top.r3944realms.lib39.core.network.toClient.SyncNBTLookupDataEntityS2CPayload;
import java.util.List;
@ -19,8 +19,8 @@ public interface IFabricUpdate extends IUpdate {
PlayerList playerList = serverLevel.getServer().getPlayerList();
List<ServerPlayer> players = playerList.getPlayers();
for (ServerPlayer player : players) {
if (ServerPlayNetworking.canSend(player, SyncNBTLookupDataEntityS2CPacket.TYPE)) {
ServerPlayNetworking.send(player, new SyncNBTLookupDataEntityS2CPacket(getSyncData().entityId(), getSyncData()));
if (ServerPlayNetworking.canSend(player, SyncNBTLookupDataEntityS2CPayload.TYPE)) {
ServerPlayNetworking.send(player, new SyncNBTLookupDataEntityS2CPayload(getSyncData().entityId(), getSyncData()));
}
}
}

View File

@ -1,6 +1,6 @@
package top.r3944realms.lib39.example;
import top.r3944realms.lib39.core.compat.CompatManager;
import top.r3944realms.lib39.core.compat.ICompatManager;
import top.r3944realms.lib39.example.core.compat.FabricLib39Compat;
import top.r3944realms.lib39.example.core.event.FabricExCommonEventHandler;
import top.r3944realms.lib39.example.core.network.FabricExNetworkHandler;
@ -29,7 +29,7 @@ public class FabricLib39Example {
FabricExCommonEventHandler.init();
FabricExLib39Items.init();
FabricExNetworkHandler.registerServerReceivers();
CompatManager orCreateCompatManager = FabricExCommonEventHandler.getOrCreateCompatManager();
ICompatManager orCreateCompatManager = FabricExCommonEventHandler.getOrCreateCompatManager();
orCreateCompatManager.registerCompat(FabricLib39Compat.ID, FabricLib39Compat.INSTANCE);
}

View File

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

View File

@ -1,12 +1,19 @@
package top.r3944realms.lib39.example.core.compat;
import net.minecraft.resources.ResourceLocation;
import top.r3944realms.lib39.Lib39;
import top.r3944realms.lib39.core.compat.CompatManager;
import top.r3944realms.lib39.core.compat.ICompat;
import top.r3944realms.lib39.core.compat.SimpleCompatManager;
import java.util.HashMap;
import java.util.Map;
/**
* The type Fabric lib 39 compat manager.
*/
public class FabricLib39CompatManager extends CompatManager {
public class FabricLib39CompatManager extends SimpleCompatManager {
/**
* Instantiates a new Compat manager.
*

View File

@ -4,7 +4,7 @@ import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import top.r3944realms.lib39.api.callback.ActionResult;
import top.r3944realms.lib39.api.callback.SyncManagerRegisterCallback;
import top.r3944realms.lib39.core.compat.CompatManager;
import top.r3944realms.lib39.core.compat.ICompatManager;
import top.r3944realms.lib39.core.event.FabricCommonEventHandler;
import top.r3944realms.lib39.core.sync.CachedSyncManager;
import top.r3944realms.lib39.example.content.data.AbstractedTestSyncData;
@ -23,7 +23,7 @@ public class FabricExCommonEventHandler {
*
* @return the compat manager
*/
public static CompatManager getOrCreateCompatManager() {
public static ICompatManager getOrCreateCompatManager() {
if (compatManager == null) {
synchronized (FabricCommonEventHandler.class) {
if (compatManager == null) {
@ -37,7 +37,7 @@ public class FabricExCommonEventHandler {
/**
* The Compat manager.
*/
static volatile CompatManager compatManager;
static volatile ICompatManager compatManager;
/**
* Init.

View File

@ -1,9 +1,9 @@
package top.r3944realms.lib39.example.core.network;
import net.fabricmc.fabric.api.networking.v1.FabricPacket;
import net.fabricmc.fabric.api.networking.v1.PacketSender;
import net.fabricmc.fabric.api.networking.v1.PacketType;
import net.minecraft.network.FriendlyByteBuf;
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import org.jetbrains.annotations.NotNull;
@ -15,63 +15,59 @@ import top.r3944realms.lib39.example.content.item.FabricFabricItem;
/**
* The type Client data packet.
*/
public class FabricClientDataPacket implements FabricPacket {
public record FabricClientDataPacket(AbstractedTestSyncData clientData, int targetEntityId) implements CustomPacketPayload {
/**
* The constant CLIENT_TEST_DATA.
*/
public static final ResourceLocation CLIENT_TEST_DATA =
Lib39.rl("client_test_data");
/**
* The constant TYPE.
*/
public static final PacketType<FabricClientDataPacket> TYPE = PacketType.create(
CLIENT_TEST_DATA,
FabricClientDataPacket::new
);
private final AbstractedTestSyncData clientData;
private final int targetEntityId;
public static final CustomPacketPayload.Type<FabricClientDataPacket> TYPE =
new CustomPacketPayload.Type<>(CLIENT_TEST_DATA);
/**
* Instantiates a new Client data packet.
*
* @param clientData the client data
* @param targetEntityId the target entity id
* Stream codec for serializing/deserializing the packet.
*/
public FabricClientDataPacket(AbstractedTestSyncData clientData, int targetEntityId) {
this.clientData = clientData;
this.targetEntityId = targetEntityId;
public static final StreamCodec<RegistryFriendlyByteBuf, FabricClientDataPacket> STREAM_CODEC =
StreamCodec.ofMember(FabricClientDataPacket::write, FabricClientDataPacket::new);
/**
* Instantiates a new Client data packet from buffer.
*
* @param buf the buffer
*/
public FabricClientDataPacket(RegistryFriendlyByteBuf buf) {
this(FabricTestSyncData.staticFromBytes(buf), buf.readInt());
}
/**
* Instantiates a new Client data packet.
* Write packet data to buffer.
*
* @param buf the buf
* @param buf the buffer
*/
public FabricClientDataPacket(FriendlyByteBuf buf) {
this.clientData = FabricTestSyncData.staticFromBytes(buf);
this.targetEntityId = buf.readInt();
}
@Override
public void write(FriendlyByteBuf buf) {
public void write(RegistryFriendlyByteBuf buf) {
clientData.toBytes(buf);
buf.writeInt(targetEntityId);
}
@Override
public PacketType<?> getType() {
public @NotNull Type<? extends CustomPacketPayload> type() {
return TYPE;
}
/**
* Receive.
* Handle packet on server side.
* Register this with ServerPlayNetworking.registerGlobalReceiver
*
* @param packet the packet
* @param serverPlayer the server player
* @param packetSender the packet sender
* @param packet the packet
* @param context the context
*/
public static void receive(@NotNull FabricClientDataPacket packet, @NotNull ServerPlayer serverPlayer, PacketSender packetSender) {
public static void handle(FabricClientDataPacket packet, ServerPlayNetworking.Context context) {
ServerPlayer serverPlayer = context.player();
// PacketSender is no longer needed, use context.responseSender() if needed
FabricFabricItem.handleClientDataFromPacket(serverPlayer, packet.clientData, packet.targetEntityId);
}
}

View File

@ -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,9 +11,13 @@ public class FabricExNetworkHandler {
* 注册服务器接收的数据包
*/
public static void registerServerReceivers() {
PayloadTypeRegistry.playC2S().register(
FabricClientDataPacket.TYPE,
FabricClientDataPacket.STREAM_CODEC
);
ServerPlayNetworking.registerGlobalReceiver(
FabricClientDataPacket.TYPE,
FabricClientDataPacket::receive
FabricClientDataPacket::handle
);
}
}

View File

@ -5,12 +5,15 @@ import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.sugar.Local;
import com.mojang.blaze3d.platform.WindowEventHandler;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.ReceivingLevelScreen;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.server.Services;
import net.minecraft.server.WorldStem;
import net.minecraft.server.packs.repository.PackRepository;
import net.minecraft.util.thread.ReentrantBlockableEventLoop;
import net.minecraft.world.level.storage.LevelStorageSource;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
@ -19,8 +22,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import top.r3944realms.lib39.api.callback.MinecraftSetUpServiceCallback;
import top.r3944realms.lib39.api.callback.client.ClientWorldCallback;
import javax.annotation.Nullable;
/**
* The type Mixin minecraft.
*/
@ -29,7 +30,8 @@ public abstract class MixinMinecraft extends ReentrantBlockableEventLoop<Runnabl
/**
* The Level.
*/
@Shadow @Nullable public ClientLevel level;
@Shadow @Nullable
public ClientLevel level;
/**
* Instantiates a new Mixin minecraft.
@ -41,34 +43,37 @@ public abstract class MixinMinecraft extends ReentrantBlockableEventLoop<Runnabl
}
/**
* Set level callback.
* Set clientLevel callback.
*
* @param levelClient the level client
* @param clientLevel the clientLevel client
* @param reason the reason
* @param original the original
*/
@WrapMethod(method = "setLevel")
public void setLevel$callback(ClientLevel levelClient, Operation<Void> original) {
if (levelClient != null) ClientWorldCallback.UNLOAD.invoker().onWorldUnload(levelClient);
original.call(levelClient);
public void setLevel$callback(ClientLevel clientLevel, ReceivingLevelScreen.Reason reason, Operation<Void> original) {
if (clientLevel != null) ClientWorldCallback.UNLOAD.invoker().onWorldUnload(clientLevel);
original.call(clientLevel, reason);
}
/**
* Clear level callback.
*
* @param original the original
* @param nextScreen the next screen
* @param original the original
*/
@WrapMethod(method = "clearLevel()V")
public void clearLevel$callback(Operation<Void> original) {
@WrapMethod(method = "clearClientLevel")
public void clearLevel$callback(Screen nextScreen, Operation<Void> original) {
if (level != null) ClientWorldCallback.UNLOAD.invoker().onWorldUnload(level);
original.call();
original.call(nextScreen);
}
/**
* Set level setup.
*
* @param levelClient the level client
* @param ci the ci
* @param services the services
* @param level the level client
* @param reason the reason
* @param ci the ci
* @param services the services
*/
@Inject(
method = "setLevel",
@ -78,16 +83,14 @@ public abstract class MixinMinecraft extends ReentrantBlockableEventLoop<Runnabl
shift = At.Shift.AFTER
)
)
public void setLevel$setup(ClientLevel levelClient, CallbackInfo ci,
@Local(ordinal = 0) Services services) {
public void setLevel$setup(ClientLevel level, ReceivingLevelScreen.Reason reason, CallbackInfo ci, @Local(ordinal = 0) Services services) {
MinecraftSetUpServiceCallback.EVENT.invoker().load(services,this);
}
/**
* Do world load setup.
*
* @param levelId the level id
* @param level the level
* @param levelStorage the level id
* @param packRepository the pack repository
* @param worldStem the world stem
* @param newWorld the new world
@ -102,8 +105,7 @@ public abstract class MixinMinecraft extends ReentrantBlockableEventLoop<Runnabl
shift = At.Shift.AFTER
)
)
public void doWorldLoad$setup(String levelId, LevelStorageSource.LevelStorageAccess level, PackRepository packRepository, WorldStem worldStem, boolean newWorld, CallbackInfo ci,
@Local(ordinal = 0) Services services) {
public void doWorldLoad$setup(LevelStorageSource.LevelStorageAccess levelStorage, PackRepository packRepository, WorldStem worldStem, boolean newWorld, CallbackInfo ci, @Local(ordinal = 0) Services services) {
MinecraftSetUpServiceCallback.EVENT.invoker().load(services,this);
}
}

View File

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

View File

@ -8,8 +8,8 @@
"${mod_author}"
],
"contact": {
"homepage": "https://github.com/3944Realms",
"sources": "https://github.com/3944Realms/Lib39"
"homepage": "https://gitea.bot.leisuretimedock.top/3944Realms",
"sources": "https://gitea.bot.leisuretimedock.top/3944Realms/Lib39"
},
"license": "${license}",
"icon": "lib39_logo.png",

View File

@ -3,18 +3,17 @@
"minVersion": "0.8",
"package": "top.r3944realms.lib39.mixin",
"refmap": "${mod_id}.fabric.refmap.json",
"compatibilityLevel": "JAVA_17",
"compatibilityLevel": "JAVA_18",
"mixins": [
"MixinApiLookUpImpl",
"MixinEntity",
"callback.MixinAnvilMenu",
"callback.MixinDedicateServer"
"callback.MixinAnvilMenu"
],
"client": [
"callback.MixinMinecraft",
"callback.client.MixinClientLevel"
],
"server": [
"callback.MixinDedicateServer"
],
"injectors": {
"defaultRequire": 1

View File

@ -1,60 +0,0 @@
package top.r3944realms.lib39;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import top.r3944realms.lib39.core.network.NetworkHandler;
import top.r3944realms.lib39.core.register.ForgeLib39BlockEntities;
import top.r3944realms.lib39.core.register.ForgeLib39Blocks;
import top.r3944realms.lib39.core.register.ForgeLib39Items;
import top.r3944realms.lib39.core.register.ForgeLib39SoundEvents;
import top.r3944realms.lib39.example.ForgeLib39Example;
/**
* The type Lib 39.
*/
@Mod(Lib39.MOD_ID)
public class Lib39Forge {
/**
* Instantiates a new Lib 39.
*/
public Lib39Forge() {
Lib39.initialize();
initialize();
}
/**
* Initialize.
*/
public static void initialize() {
Lib39.LOGGER.info("[Lib39-Forge] Hello Forge");
IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus();
ForgeLib39Blocks.register(modEventBus);
ForgeLib39Items.register(modEventBus);
ForgeLib39BlockEntities.register(modEventBus);
ForgeLib39SoundEvents.register(modEventBus);
NetworkHandler.register();
if (Lib39.shouldRegisterExamples()) {
Lib39.LOGGER.info("[Lib39-Forge] Registering Examples");
registerExamples();
}
Lib39.LOGGER.info("[Lib39-Forge] Finished Initializing.");
}
/**
* Register examples.
*/
static void registerExamples() {
Lib39.LOGGER.info("[Lib39-Forge] Starting example demonstrations");
try {
// 创建示例实例并演示功能
ForgeLib39Example example = new ForgeLib39Example();
example.demonstrateFeature();
Lib39.LOGGER.info("[Lib39-Forge] Example demonstrations completed successfully");
} catch (Exception e) {
Lib39.LOGGER.error("[Lib39-Forge] Failed to demonstrate examples", e);
}
}
}

View File

@ -1,32 +0,0 @@
package top.r3944realms.lib39.base.compat.jade.provider;
import com.mojang.authlib.GameProfile;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import snownee.jade.api.BlockAccessor;
import snownee.jade.api.IBlockComponentProvider;
import snownee.jade.api.ITooltip;
import snownee.jade.api.config.IPluginConfig;
import top.r3944realms.lib39.base.compat.jade.ForgeJadePlugin;
import top.r3944realms.lib39.content.block.blockentity.DollBlockEntity;
/**
* The type Forge doll component provider.
*/
public class ForgeDollComponentProvider implements IBlockComponentProvider {
@Override
public ResourceLocation getUid() {
return ForgeJadePlugin.UID;
}
@Override
public void appendTooltip(ITooltip iTooltip, 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()));
}
}
}
}

View File

@ -1,32 +0,0 @@
package top.r3944realms.lib39.content.item;
import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer;
import net.minecraftforge.client.extensions.common.IClientItemExtensions;
import org.jetbrains.annotations.NotNull;
import top.r3944realms.lib39.client.renderer.item.DollItemRenderer;
import java.util.function.Consumer;
/**
* The type Forge doll item.
*/
public class ForgeDollItem extends DollItem {
/**
* Instantiates a new Forge doll item.
*
* @param properties the properties
*/
public ForgeDollItem(Properties properties) {
super(properties);
}
@Override
public void initializeClient(@NotNull Consumer<IClientItemExtensions> consumer) {
consumer.accept(new IClientItemExtensions() {
@Override
public BlockEntityWithoutLevelRenderer getCustomRenderer() {
return DollItemRenderer.getInstance();
}
});
}
}

View File

@ -1,72 +0,0 @@
package top.r3944realms.lib39.core.network;
import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.network.NetworkDirection;
import net.minecraftforge.network.NetworkRegistry;
import net.minecraftforge.network.PacketDistributor;
import net.minecraftforge.network.simple.SimpleChannel;
import org.jetbrains.annotations.NotNull;
import top.r3944realms.lib39.Lib39;
import top.r3944realms.lib39.core.network.toClient.SyncNBTCapDataEntityS2CPacket;
/**
* The type Network handler.
*/
@SuppressWarnings("unused")
public class NetworkHandler {
private static int cid = 0;
/**
* The constant INSTANCE.
*/
public static final SimpleChannel INSTANCE = NetworkRegistry.newSimpleChannel(
Lib39.rl(Lib39.MOD_ID, "main"),
() -> Lib39.ModInfo.VERSION,
Lib39.ModInfo.VERSION::equals,
Lib39.ModInfo.VERSION::equals
);
/**
* Register.
*/
public static void register() {
INSTANCE.messageBuilder(SyncNBTCapDataEntityS2CPacket.class, cid++, NetworkDirection.PLAY_TO_CLIENT)
.encoder(SyncNBTCapDataEntityS2CPacket::encode)
.decoder(SyncNBTCapDataEntityS2CPacket::decode)
.consumerNetworkThread(SyncNBTCapDataEntityS2CPacket::handle)
.add();
}
/**
* Send to player.
*
* @param <MSG> the type parameter
* @param message the message
* @param player the player
*/
public static <MSG> void sendToPlayer(MSG message, ServerPlayer player){
INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), message);
}
/**
* Send to player.
*
* @param <MSG> the type parameter
* @param <T> the type parameter
* @param message the message
* @param entity the entity
* @param packetDistributor the packet distributor
*/
public static <MSG, T> void sendToPlayer(MSG message, T entity, @NotNull PacketDistributor<T> packetDistributor){
INSTANCE.send(packetDistributor.with(() -> entity), message);
}
/**
* Send to player.
*
* @param <MSG> the type parameter
* @param message the message
*/
public static <MSG> void sendToAllPlayer(MSG message){
INSTANCE.send(PacketDistributor.ALL.noArg(), message);
}
}

View File

@ -1,13 +0,0 @@
package top.r3944realms.lib39.core.sync;
import top.r3944realms.lib39.core.network.NetworkHandler;
import top.r3944realms.lib39.core.network.toClient.SyncNBTCapDataEntityS2CPacket;
/**
* The interface Forge update.
*/
public interface IForgeUpdate extends IUpdate {
default void update() {
NetworkHandler.sendToAllPlayer(new SyncNBTCapDataEntityS2CPacket(getSyncData().entityId(), getSyncData().id, getSyncData().serializeNBT()));
}
}

View File

@ -1,61 +0,0 @@
package top.r3944realms.lib39.example;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import top.r3944realms.lib39.example.core.event.ExCommonEventHandler;
import top.r3944realms.lib39.example.core.network.ExNetworkHandler;
import top.r3944realms.lib39.example.core.register.ForgeExLib39Items;
/**
* The type Forge lib 39 example.
*/
public class ForgeLib39Example {
private static boolean registered = false;
/**
* Instantiates a new Lib 39 example.
*/
public ForgeLib39Example() {
if (!registered) {
init();
registerToEventBus();
registered = true;
}
}
/**
* Init.
*/
public void init() {
IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus();
ForgeExLib39Items.register(modEventBus);
ExNetworkHandler.register();
}
private void registerToEventBus() {
IEventBus modBus = FMLJavaModLoadingContext.get().getModEventBus();
IEventBus gameBus = MinecraftForge.EVENT_BUS;
// DistExecutor.unsafeCallWhenOn(Dist.CLIENT, () -> {
// modBus.register(ExClientEventHandler.Mod.class);
// gameBus.register(ExClientEventHandler.Game.class);
// return null;
// });
// DistExecutor.unsafeCallWhenOn(Dist.DEDICATED_SERVER, () -> {
// modBus.register(ExServerEventHandler.Mod.class);
// gameBus.register(ExServerEventHandler.Game.class);
// return null;
// });
modBus.register(ExCommonEventHandler.Mod.class);
gameBus.register(ExCommonEventHandler.Game.class);
}
/**
* Demonstrate feature.
*/
public void demonstrateFeature() {
}
}

View File

@ -1,40 +0,0 @@
package top.r3944realms.lib39.example.content.data;
import net.minecraft.world.entity.Entity;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.CapabilityManager;
import net.minecraftforge.common.capabilities.CapabilityToken;
import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent;
import net.minecraftforge.event.AttachCapabilitiesEvent;
import org.jetbrains.annotations.NotNull;
/**
* The type Ex capability handler.
*/
public class ExCapabilityHandler {
/**
* The constant TEST_CAP.
*/
public static final Capability<AbstractedTestSyncData> TEST_CAP = CapabilityManager.get(new CapabilityToken<>() {});
/**
* Register capability.
*
* @param event the event
*/
public static void registerCapability(@NotNull RegisterCapabilitiesEvent event) {
event.register(AbstractedTestSyncData.class);
}
/**
* Attach capability.
*
* @param event the event
*/
public static void attachCapability(@NotNull AttachCapabilitiesEvent<?> event) {
Object object = event.getObject();
if(object instanceof Entity entity) {
event.addCapability(TestSyncCapProvider.TEST_SYNC_REL, new TestSyncCapProvider(entity));
}
}
}

View File

@ -1,49 +0,0 @@
package top.r3944realms.lib39.example.content.data;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.Entity;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ICapabilitySerializable;
import net.minecraftforge.common.util.LazyOptional;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import top.r3944realms.lib39.Lib39;
/**
* The type Test sync cap provider.
*/
public class TestSyncCapProvider implements ICapabilitySerializable<CompoundTag> {
/**
* The constant TEST_SYNC_REL.
*/
public static final ResourceLocation TEST_SYNC_REL = Lib39.rl(Lib39.MOD_ID, "test_sync_data");
private final AbstractedTestSyncData instance;
private final LazyOptional<AbstractedTestSyncData> optional;
/**
* Instantiates a new Test sync cap provider.
*
* @param entity the entity
*/
public TestSyncCapProvider(Entity entity) {
this.instance = new TestSyncData(entity);
this.optional = LazyOptional.of(() -> instance);
}
@Override
public @NotNull <T> LazyOptional<T> getCapability(@NotNull Capability<T> cap, @Nullable Direction side) {
return ExCapabilityHandler.TEST_CAP.orEmpty(cap, optional);
}
@Override
public CompoundTag serializeNBT() {
return instance.serializeNBT();
}
@Override
public void deserializeNBT(CompoundTag nbt) {
instance.deserializeNBT(nbt);
}
}

View File

@ -1,70 +0,0 @@
package top.r3944realms.lib39.example.core.network;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.network.NetworkEvent;
import top.r3944realms.lib39.example.content.data.AbstractedTestSyncData;
import top.r3944realms.lib39.example.content.data.TestSyncData;
import top.r3944realms.lib39.example.content.item.ForgeFabricItem;
import java.util.function.Supplier;
/**
* The type Client data packet.
*/
public class ClientDataPacket {
private final AbstractedTestSyncData clientData;
private final int targetEntityId;
/**
* Instantiates a new Client data packet.
*
* @param clientData the client data
* @param targetEntityId the target entity id
*/
public ClientDataPacket(AbstractedTestSyncData clientData, int targetEntityId) {
this.clientData = clientData;
this.targetEntityId = targetEntityId;
}
/**
* Instantiates a new Client data packet.
*
* @param buf the buf
*/
public ClientDataPacket(FriendlyByteBuf buf) {
this.clientData = TestSyncData.staticFromBytes(buf);
this.targetEntityId = buf.readInt();
}
/**
* To bytes.
*
* @param buf the buf
*/
public void toBytes(FriendlyByteBuf buf) {
clientData.toBytes(buf);
buf.writeInt(targetEntityId);
}
/**
* Handle.
*
* @param supplier the supplier
*/
public void handle(Supplier<NetworkEvent.Context> supplier) {
NetworkEvent.Context context = supplier.get();
context.enqueueWork(() -> {
ServerPlayer player = context.getSender();
if (player != null) {
// 处理客户端发送的数据
handleClientData(player, clientData, targetEntityId);
}
});
context.setPacketHandled(true);
}
private void handleClientData(ServerPlayer player, AbstractedTestSyncData clientData, int targetEntityId) {
ForgeFabricItem.handleClientDataFromPacket(player, clientData, targetEntityId);
}
}

View File

@ -1,36 +0,0 @@
package top.r3944realms.lib39.example.core.network;
import net.minecraftforge.network.NetworkRegistry;
import net.minecraftforge.network.simple.SimpleChannel;
import top.r3944realms.lib39.Lib39;
/**
* The type Ex network handler.
*/
public class ExNetworkHandler {
/**
* The constant INSTANCE.
*/
public static final SimpleChannel INSTANCE;
private static int ID = 0;
static {
INSTANCE = NetworkRegistry.newSimpleChannel(
Lib39.rl(Lib39.MOD_ID, "test"),
() -> "1.0",
s -> true,
s -> true
);
}
/**
* Register.
*/
public static void register() {
// 注册数据包
INSTANCE.registerMessage(ID++, ClientDataPacket.class,
ClientDataPacket::toBytes,
ClientDataPacket::new,
ClientDataPacket::handle);
}
}

View File

@ -1,19 +0,0 @@
package top.r3944realms.lib39.platform;
import top.r3944realms.lib39.platform.services.IUtilHelper;
import top.r3944realms.lib39.util.ForgeBlockRegistryBuilder;
import top.r3944realms.lib39.util.block.BlockRegistryBuilder;
/**
* The enum Forge util helper.
*/
public enum ForgeUtilHelper implements IUtilHelper {
/**
* Instance forge util helper.
*/
INSTANCE;
@Override
public BlockRegistryBuilder getBlockRegistryBuilder() {
return new ForgeBlockRegistryBuilder();
}
}

View File

@ -1 +0,0 @@
top.r3944realms.lib39.platform.ForgePlatformHelper

View File

@ -3,12 +3,12 @@
# Every field you add must be added to buildSrc/src/main/groovy/multiloader-common.gradle expandProps map.
# Project
version=0.5.5
version=0.5.6
group=top.r3944realms.lib39
java_version=17
java_version=21
# Common
minecraft_version=1.20.1
minecraft_version=1.21.1
mod_name=3944Realms 's Lib Mod
mod_author=R3944Realms
mod_id=lib39
@ -17,17 +17,18 @@ credits=Logo created by Shanyi43, edited by R3944Realms
description=Lib39 is a general-purpose dependency library that provides utility methods and core functionality for other mods.
minecraft_version_range=[1.20.1, 1.22)
# The version of ParchmentMC that is used, see https://parchmentmc.org/docs/getting-started#choose-a-version for new versions
parchment_minecraft=1.20.1
parchment_version=2023.09.03
parchment_minecraft=1.21.1
parchment_version=2024.11.17
neo_form_version=1.21.1-20240808.144430
# NeoForge
neoforge_version=21.1.80
neoforge_loader_version_range=[4,)
# Fabric
fabric_version=0.92.1+1.20.1
fabric_version=0.109.0+1.21.1
fabric_loader_version=0.16.9
# Forge
forge_version=47.2.30
forge_loader_version_range=[47,)
# Gradle
org.gradle.jvmargs=-Xmx3G
org.gradle.daemon=false
@ -40,9 +41,9 @@ publish_curseforge=true
modrinth_id=n65Vs1Vk
curseforge_id=1445917
java_versions=21 17
java_versions=21
fabric_modrinth_dependencies=
forge_modrinth_dependencies=
neoforge_modrinth_dependencies=
fabric_curseforge_dependencies=
forge_curseforge_dependencies=
neoforge_curseforge_dependencies=

View File

@ -1,13 +1,6 @@
plugins {
id 'multiloader-loader'
id 'net.neoforged.moddev.legacyforge'
}
mixin {
add(sourceSets.main, "${mod_id}.refmap.json")
config("${mod_id}.mixins.json")
config("${mod_id}.forge.mixins.json")
id 'net.neoforged.moddev'
}
def commonResources = project(':common').file('src/main/resources/').getAbsolutePath()
@ -16,8 +9,8 @@ def forgeBuildResources = file('build/resources/main/').getAbsolutePath()
def commonBuildResources = project(':common').file('build/resources/main/').getAbsolutePath()
def generatedOutput = project(':common').file('src/generated/resources/').getAbsolutePath()
legacyForge {
version = "${minecraft_version}-${forge_version}"
neoForge {
version = neoforge_version
validateAccessTransformers = true
@ -72,20 +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"))
modImplementation(group: 'tschipp.carryon', name: 'carryon-forge-1.20.1', version: '2.1.2.7') {
implementation(group: 'tschipp.carryon', name: 'carryon-neoforge-1.21.1', version: '2.2.4.4') {
transitive = false
}
modImplementation ("curse.maven:jade-324717:6855440")
implementation(jarJar("io.github.llamalad7:mixinextras-forge:0.2.0"))
}
implementation "curse.maven:jade-324717:7545219"
jar {
finalizedBy('reobfJar')
manifest.attributes([
"MixinConfigs": "${mod_id}.mixins.json,${mod_id}.forge.mixins.json"
])
}
// sourceJar任务
@ -106,7 +91,7 @@ tasks.named('javadoc', Javadoc) {
classpath += project(':common').sourceSets.main.compileClasspath
options.encoding = 'UTF-8'
options.charSet = 'UTF-8'
options.links("https://docs.oracle.com/en/java/javase/17/docs/api/")
options.links("https://docs.oracle.com/en/java/javase/21/docs/api/")
options.memberLevel = JavadocMemberLevel.PUBLIC
options.addBooleanOption('Xdoclint:none', true)
options.addStringOption('doctitle', "${mod_id} ${minecraft_version} ${version} Javadoc")
@ -129,72 +114,6 @@ tasks.named('build') {
dependsOn tasks.named('javadocJar')
}
// reobf
tasks.named('reobfJar') {
dependsOn tasks.named('sourcesJar')
dependsOn tasks.named('javadocJar')
}
//
publishing {
publications {
mavenJava(MavenPublication) {
artifactId = "${mod_id}-forge-${minecraft_version}"
artifacts.clear()
artifact(tasks.named('reobfJar').get()) {
builtBy tasks.named('reobfJar')
}
artifact(tasks.named('sourcesJar').get()) {
builtBy tasks.named('sourcesJar')
classifier = 'sources'
}
artifact(tasks.named('javadocJar').get()) {
builtBy tasks.named('javadocJar')
classifier = 'javadoc'
}
pom {
name = 'Lib39'
description = 'Lib39 is a general-purpose dependency library for Minecraft mods.'
url = 'https://github.com/3944Realms/lib39'
properties = [
'minecraft.version': project.minecraft_version,
'mod.version': project.version,
'forge.version': project.forge_version,
'java.version': '17'
]
licenses {
license {
name = 'MIT'
url = 'https://raw.githubusercontent.com/3944Realms/lib39/refs/heads/main/LICENSE'
distribution = 'repo'
}
}
developers {
developer {
id = 'R3944Realms'
name = "${mod_author}"
email = 'f256198830@hotmail.com'
}
}
scm {
connection = 'scm:git:https://github.com/3944Realms/lib39.git'
developerConnection = 'scm:git:ssh://git@github.com:3944Realms/lib39.git'
url = 'https://github.com/3944Realms/lib39'
tag = 'main'
}
issueManagement {
system = 'GitHub'
url = 'https://github.com/3944Realms/lib39/issues'
}
}
}
}
}
test {
useJUnitPlatform()
}
@ -205,21 +124,23 @@ processResources {
inputs.property "version", project.version
inputs.property "minecraft_version", minecraft_version
inputs.property "forge_version", forge_version
inputs.property "neoforge_version", neoforge_version
inputs.property "mod_id", mod_id
inputs.property "mod_name", mod_name
inputs.property "description", description
inputs.property "mod_author", mod_author
inputs.property "credits", credits
filesMatching(['META-INF/mods.toml', 'pack.mcmeta', "*.mixins.json"]) {
expand([
version: project.version,
minecraft_version: minecraft_version,
forge_version: forge_version,
neoforge_version: neoforge_version,
mod_id: mod_id,
mod_name: mod_name,
description: description,
mod_author: mod_author
mod_author: mod_author,
"credits": credits
])
}
duplicatesStrategy = DuplicatesStrategy.EXCLUDE

View File

@ -0,0 +1,71 @@
package top.r3944realms.lib39;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.fml.common.Mod;
import top.r3944realms.lib39.core.network.NetworkHandler;
import top.r3944realms.lib39.core.register.NeoForgeLib39BlockEntities;
import top.r3944realms.lib39.core.register.NeoForgeLib39Blocks;
import top.r3944realms.lib39.core.register.NeoForgeLib39Items;
import top.r3944realms.lib39.core.register.NeoForgeLib39SoundEvents;
import top.r3944realms.lib39.example.NeoForgeLib39Example;
/**
* The type Lib 39.
*/
@Mod(Lib39.MOD_ID)
public class Lib39NeoForge {
/**
* The constant modEventBus.
*/
public static IEventBus modEventBus;
/**
* Instantiates a new Lib 39.
*
* @param modEventBus the mod event bus
*/
public Lib39NeoForge(IEventBus modEventBus) {
Lib39.initialize();
if(this.modEventBus == null) {
this.modEventBus = modEventBus;
}
initialize(modEventBus);
}
/**
* Initialize.
*
* @param modEventBus the mod event bus
*/
public static void initialize(IEventBus modEventBus) {
Lib39.LOGGER.info("[Lib39-NeoForge] Hello NeoForge");
NeoForgeLib39Blocks.register(modEventBus);
NeoForgeLib39Items.register(modEventBus);
NeoForgeLib39BlockEntities.register(modEventBus);
NeoForgeLib39SoundEvents.register(modEventBus);
if (Lib39.shouldRegisterExamples()) {
Lib39.LOGGER.info("[Lib39-NeoForge] Registering Examples");
registerExamples(modEventBus);
}
Lib39.LOGGER.info("[Lib39-NeoForge] Finished Initializing.");
}
/**
* Register examples.
*
* @param modEventBus the mod event bus
*/
static void registerExamples(IEventBus modEventBus) {
Lib39.LOGGER.info("[Lib39-NeoForge] Starting example demonstrations");
try {
// 创建示例实例并演示功能
NeoForgeLib39Example example = new NeoForgeLib39Example(modEventBus);
example.demonstrateFeature();
Lib39.LOGGER.info("[Lib39-NeoForge] Example demonstrations completed successfully");
} catch (Exception e) {
Lib39.LOGGER.error("[Lib39-NeoForge] Failed to demonstrate examples", e);
}
}
}

View File

@ -1,7 +1,7 @@
package top.r3944realms.lib39.api.event;
import net.minecraft.server.Services;
import net.minecraftforge.eventbus.api.Event;
import net.neoforged.bus.api.Event;
import java.util.concurrent.Executor;

View File

@ -5,7 +5,7 @@ import net.minecraft.commands.CommandBuildContext;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.eventbus.api.Event;
import net.neoforged.bus.api.Event;
import top.r3944realms.lib39.core.command.ICommandHelpManager;
import top.r3944realms.lib39.core.command.model.CommandNode;
import top.r3944realms.lib39.core.command.model.CommandPath;

View File

@ -1,8 +1,8 @@
package top.r3944realms.lib39.api.event;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.eventbus.api.Event;
import net.neoforged.bus.api.Event;
import net.neoforged.neoforge.capabilities.EntityCapability;
import top.r3944realms.lib39.core.sync.ISyncData;
import top.r3944realms.lib39.core.sync.ISyncManager;
import top.r3944realms.lib39.core.sync.SyncData2CapManager;
@ -46,8 +46,8 @@ public class SyncManagerRegisterEvent extends Event {
*/
public <K, T extends ISyncData<?>> void registerSyncManager(
ResourceLocation id,
ISyncManager<Capability<T>, T> syncManager,
Capability<T> capability
ISyncManager<EntityCapability<T, Void>, T> syncManager,
EntityCapability<T, Void> capability
) {
syncs2Manager.registerManager(id, syncManager, capability);
}
@ -88,7 +88,7 @@ public class SyncManagerRegisterEvent extends Event {
* @param id 必须先注册安全同步管理器再绑定Cap否则会抛出{@link IllegalStateException 未找到对应安全同步管理器}
* @param capability the capability
*/
public <T extends ISyncData<?>> void bindCapability(ResourceLocation id, Capability<T> capability) {
public <T extends ISyncData<?>> void bindCapability(ResourceLocation id, EntityCapability<T, Void> capability) {
syncs2Manager.bindCapability(id, capability);
}
@ -113,8 +113,8 @@ public class SyncManagerRegisterEvent extends Event {
*/
public <K, T extends ISyncData<?>> void registerComplete(
ResourceLocation id,
ISyncManager<Capability<T>, T> syncManager,
Capability<T> capability,
ISyncManager<EntityCapability<T, Void>, T> syncManager,
EntityCapability<T, Void> capability,
Class<?>... allowedEntityClasses
) {
registerSyncManager(id, syncManager, capability);

View File

@ -1,25 +1,26 @@
package top.r3944realms.lib39.base.compat.jade;
import net.minecraft.resources.ResourceLocation;
import org.jetbrains.annotations.NotNull;
import snownee.jade.api.IWailaClientRegistration;
import snownee.jade.api.IWailaPlugin;
import snownee.jade.api.WailaPlugin;
import top.r3944realms.lib39.Lib39;
import top.r3944realms.lib39.base.compat.jade.provider.ForgeDollComponentProvider;
import top.r3944realms.lib39.content.block.DollBlock;
import top.r3944realms.lib39.base.compat.jade.provider.NeoForgeDollComponentProvider;
import top.r3944realms.lib39.content.block.AbstractDollBlock;
/**
* The type Forge jade plugin.
*/
@WailaPlugin
public class ForgeJadePlugin implements IWailaPlugin {
public class NeoForgeJadePlugin implements IWailaPlugin {
/**
* The constant UID.
*/
public static final ResourceLocation UID = Lib39.rl("lib39");
@Override
public void registerClient(IWailaClientRegistration registration) {
registration.registerBlockComponent(new ForgeDollComponentProvider(), DollBlock.class);
public void registerClient(@NotNull IWailaClientRegistration registration) {
registration.registerBlockComponent(new NeoForgeDollComponentProvider(), AbstractDollBlock.class);
}
}

View File

@ -0,0 +1,36 @@
package top.r3944realms.lib39.base.compat.jade.provider;
import com.mojang.authlib.GameProfile;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import org.jetbrains.annotations.NotNull;
import snownee.jade.api.BlockAccessor;
import snownee.jade.api.IBlockComponentProvider;
import snownee.jade.api.ITooltip;
import snownee.jade.api.config.IPluginConfig;
import top.r3944realms.lib39.base.compat.jade.NeoForgeJadePlugin;
import top.r3944realms.lib39.content.block.blockentity.DollBlockEntity;
/**
* The type Forge doll component provider.
*/
public class NeoForgeDollComponentProvider implements IBlockComponentProvider {
@Override
public ResourceLocation getUid() {
return NeoForgeJadePlugin.UID;
}
@Override
public void appendTooltip(ITooltip iTooltip, @NotNull BlockAccessor blockAccessor, IPluginConfig iPluginConfig) {
if (blockAccessor.getBlockEntity() instanceof DollBlockEntity doll) {
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()));
}
}
}
}
}

View File

@ -1,7 +1,7 @@
package top.r3944realms.lib39.base.datagen;
import net.minecraft.data.DataProvider;
import net.minecraftforge.data.event.GatherDataEvent;
import net.neoforged.neoforge.data.event.GatherDataEvent;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -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,13 +75,20 @@ public class Lib39BaseDataGenEvent {
private static void LootTableDataGenerate(@NotNull GatherDataEvent event) {
event.getGenerator().addProvider(
event.includeServer(),
(DataProvider.Factory<SimpleLootTableProvider>) pOutput -> new SimpleLootTableProvider(pOutput, new SubProvidersWrapper().addBlockEntry(new Lib39BlockLootTable()))
(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) {
event.getGenerator().addProvider(
event.includeServer(),
(DataProvider.Factory<Lib39RecipeProvider>) Lib39RecipeProvider::new
(DataProvider.Factory<Lib39RecipeProvider>)pOutput -> new Lib39RecipeProvider(pOutput, event.getLookupProvider())
);
}
}

View File

@ -1,9 +1,13 @@
package top.r3944realms.lib39.base.datagen.provider;
import top.r3944realms.lib39.core.register.ForgeLib39Blocks;
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(ForgeLib39Blocks.BLOCKS);
public Lib39BlockLootTable(CompletableFuture<HolderLookup.Provider> registries) throws ExecutionException, InterruptedException {
super(NeoForgeLib39Blocks.BLOCKS, registries.get());
dropSelf(Lib39Blocks.DOLL, Lib39Blocks.WALL_DOLL);
}
}

View File

@ -2,8 +2,8 @@ package top.r3944realms.lib39.base.datagen.provider;
import net.minecraft.data.PackOutput;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.client.model.generators.BlockModelProvider;
import net.minecraftforge.common.data.ExistingFileHelper;
import net.neoforged.neoforge.client.model.generators.BlockModelProvider;
import net.neoforged.neoforge.common.data.ExistingFileHelper;
import top.r3944realms.lib39.Lib39;
import top.r3944realms.lib39.util.PlantHelper;

View File

@ -3,10 +3,10 @@ package top.r3944realms.lib39.base.datagen.provider;
import net.minecraft.core.Direction;
import net.minecraft.data.PackOutput;
import net.minecraft.world.level.block.Block;
import net.minecraftforge.client.model.generators.BlockStateProvider;
import net.minecraftforge.client.model.generators.ConfiguredModel;
import net.minecraftforge.client.model.generators.ModelFile;
import net.minecraftforge.common.data.ExistingFileHelper;
import net.neoforged.neoforge.client.model.generators.BlockStateProvider;
import net.neoforged.neoforge.client.model.generators.ConfiguredModel;
import net.neoforged.neoforge.client.model.generators.ModelFile;
import net.neoforged.neoforge.common.data.ExistingFileHelper;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import top.r3944realms.lib39.Lib39;

View File

@ -15,11 +15,12 @@
package top.r3944realms.lib39.base.datagen.provider;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.data.PackOutput;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.minecraftforge.common.data.ExistingFileHelper;
import net.minecraftforge.registries.ForgeRegistries;
import net.neoforged.neoforge.client.model.generators.ItemModelProvider;
import net.neoforged.neoforge.common.data.ExistingFileHelper;
import top.r3944realms.lib39.Lib39;
import top.r3944realms.lib39.base.datagen.value.Lib39LangKey;
import top.r3944realms.lib39.datagen.value.LangKeyValue;
@ -32,7 +33,7 @@ import java.util.Objects;
/**
* The type item model provider.
*/
public class Lib39ItemModelProvider extends net.minecraftforge.client.model.generators.ItemModelProvider {
public class Lib39ItemModelProvider extends ItemModelProvider {
private static List<Item> objectList;
/**
* The constant GENERATED.
@ -108,7 +109,7 @@ public class Lib39ItemModelProvider extends net.minecraftforge.client.model.gene
* @return the string
*/
public String itemName(Item item){
return Objects.requireNonNull(ForgeRegistries.ITEMS.getKey(item)).getPath();
return Objects.requireNonNull(BuiltInRegistries.ITEM.getKey(item)).getPath();
}
/**

View File

@ -1,9 +1,9 @@
package top.r3944realms.lib39.base.datagen.provider;
import net.minecraft.data.PackOutput;
import net.minecraftforge.common.data.ExistingFileHelper;
import net.minecraftforge.common.data.SoundDefinition;
import net.minecraftforge.common.data.SoundDefinitionsProvider;
import net.neoforged.neoforge.common.data.ExistingFileHelper;
import net.neoforged.neoforge.common.data.SoundDefinition;
import net.neoforged.neoforge.common.data.SoundDefinitionsProvider;
import top.r3944realms.lib39.Lib39;
import top.r3944realms.lib39.core.register.Lib39SoundEvents;

View File

@ -0,0 +1,40 @@
package top.r3944realms.lib39.content.item;
import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer;
import net.neoforged.neoforge.client.extensions.common.IClientItemExtensions;
import top.r3944realms.lib39.client.renderer.item.DollItemRenderer;
import top.r3944realms.lib39.util.IClientOnly;
/**
* The type Forge doll item.
*/
public class NeoForgeDollItem extends DollItem {
/**
* Instantiates a new Forge doll item.
*
* @param properties the properties
*/
public NeoForgeDollItem(Properties properties) {
super(properties);
}
/**
* The type Client opt.
*/
public static class ClientOpt implements IClientOnly {
/**
* Gets extensions.
*
* @return the extensions
*/
public static IClientItemExtensions getExtensions() {
return IClientOnly.check(() -> new IClientItemExtensions() {
@Override
public BlockEntityWithoutLevelRenderer getCustomRenderer() {
return DollItemRenderer.getInstance();
}
});
}
}
}

View File

@ -1,11 +1,12 @@
package top.r3944realms.lib39.core.compat;
import net.minecraftforge.eventbus.api.IEventBus;
import net.neoforged.bus.api.IEventBus;
/**
* The interface Compat.
*/
public interface IForgeCompat extends ICompat {
public interface INeoForgeCompat extends ICompat {
/**
* Add common game listener.
*

View File

@ -1,10 +1,10 @@
package top.r3944realms.lib39.core.compat;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fml.common.Mod;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.fml.loading.FMLEnvironment;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -18,24 +18,32 @@ import java.util.function.Consumer;
* The type Compat manager.
*/
@SuppressWarnings("unused")
public abstract class ForgeCompatManager extends CompatManager {
public abstract class NeoForgeCompatManager extends CompatManager<INeoForgeCompat> {
/**
* The Mod event bus.
*/
protected final IEventBus modEventBus, /**
protected final IEventBus modEventBus,
/**
* The Game event bus.
*/
gameEventBus;
/**
* The Compats.
*/
protected final Map<ResourceLocation, IForgeCompat> compats = new HashMap<>();
protected final Map<ResourceLocation, INeoForgeCompat> compats = new HashMap<>();
/**
* <pre>
* 存储事件监听器配置
* The Listener configs.
* </pre>
*/
// 存储事件监听器配置
protected final List<ListenerConfig> listenerConfigs = new ArrayList<>();
@Override
public Map<ResourceLocation, INeoForgeCompat> getCompatMap() {
return compats;
}
/**
* Instantiates a new Forge compat manager.
*
@ -43,18 +51,16 @@ public abstract class ForgeCompatManager extends CompatManager {
* @param modEventBus the mod event bus
* @param gameEventBus the game event bus
*/
public ForgeCompatManager(ResourceLocation id, IEventBus modEventBus, IEventBus gameEventBus) {
public NeoForgeCompatManager(ResourceLocation id, IEventBus modEventBus, IEventBus gameEventBus) {
super(id);
this.modEventBus = modEventBus;
this.gameEventBus = gameEventBus;
}
@Override
protected void doRegisterCompat(ResourceLocation id, ICompat compat) {
if (compat instanceof IForgeCompat) {
super.doRegisterCompat(id, compat);
addListenerForCompat(id);
} else throw new IllegalArgumentException("Can't register compat " + id + " of type " + compat.getClass());
protected void doRegisterCompat(ResourceLocation id, INeoForgeCompat compat) {
super.doRegisterCompat(id, compat);
addListenerForCompat(id);
}
/**
@ -63,7 +69,7 @@ public abstract class ForgeCompatManager extends CompatManager {
* @param dists the dists
* @param bus the bus
*/
public void addListenerForAll(@Nullable Dist dists, Mod.EventBusSubscriber.Bus bus) {
public void addListenerForAll(@Nullable Dist dists, EventBusSubscriber.Bus bus) {
listenerConfigs.add(new ListenerConfig(null, dists, bus));
}
@ -74,7 +80,7 @@ public abstract class ForgeCompatManager extends CompatManager {
* @param dists the dists
* @param bus the bus
*/
public void addListenerForCompat(ResourceLocation compatId, @Nullable Dist dists, Mod.EventBusSubscriber.Bus bus) {
public void addListenerForCompat(ResourceLocation compatId, @Nullable Dist dists, EventBusSubscriber.Bus bus) {
listenerConfigs.add(new ListenerConfig(compatId, dists, bus));
}
@ -84,14 +90,14 @@ public abstract class ForgeCompatManager extends CompatManager {
* @param compatId the compat id
*/
public void addListenerForCompat(ResourceLocation compatId) {
addListenerForCompat(compatId, null, Mod.EventBusSubscriber.Bus.FORGE);
addListenerForCompat(compatId, null, Mod.EventBusSubscriber.Bus.MOD);
addListenerForCompat(compatId, null, EventBusSubscriber.Bus.GAME);
addListenerForCompat(compatId, null, EventBusSubscriber.Bus.MOD);
addListenerForCompat(compatId, Dist.CLIENT, Mod.EventBusSubscriber.Bus.FORGE);
addListenerForCompat(compatId, Dist.CLIENT, Mod.EventBusSubscriber.Bus.MOD);
addListenerForCompat(compatId, Dist.CLIENT, EventBusSubscriber.Bus.GAME);
addListenerForCompat(compatId, Dist.CLIENT, EventBusSubscriber.Bus.MOD);
addListenerForCompat(compatId, Dist.DEDICATED_SERVER, Mod.EventBusSubscriber.Bus.FORGE);
addListenerForCompat(compatId, Dist.DEDICATED_SERVER, Mod.EventBusSubscriber.Bus.MOD);
addListenerForCompat(compatId, Dist.DEDICATED_SERVER, EventBusSubscriber.Bus.GAME);
addListenerForCompat(compatId, Dist.DEDICATED_SERVER, EventBusSubscriber.Bus.MOD);
}
/**
@ -101,10 +107,10 @@ public abstract class ForgeCompatManager extends CompatManager {
* @param bus the bus
* @param consumer the consumer
*/
public void addListenerForLoaded(@Nullable Dist dists, Mod.EventBusSubscriber.Bus bus, Consumer<IEventBus> consumer) {
public void addListenerForLoaded(@Nullable Dist dists, EventBusSubscriber.Bus bus, Consumer<IEventBus> consumer) {
listenerConfigs.add(new ListenerConfig(null, dists, bus) {
@Override
boolean shouldApply(@NotNull IForgeCompat compat) {
boolean shouldApply(@NotNull INeoForgeCompat compat) {
return super.shouldApply(compat);
}
});
@ -123,7 +129,7 @@ public abstract class ForgeCompatManager extends CompatManager {
pendingTasks.clear();
// 初始化所有兼容模块
for (Map.Entry<ResourceLocation, IForgeCompat> entry : compats.entrySet()) {
for (Map.Entry<ResourceLocation, INeoForgeCompat> entry : compats.entrySet()) {
if (!entry.getValue().isInitialized() && entry.getValue().isModLoaded()) {
try {
entry.getValue().initialize();
@ -160,7 +166,7 @@ public abstract class ForgeCompatManager extends CompatManager {
* 将监听器应用到所有兼容模块
*/
private void applyListenerToAllCompats(ListenerConfig config) {
for (IForgeCompat compat : compats.values()) {
for (INeoForgeCompat compat : compats.values()) {
if(!compat.isInitialized()) {
if (config.shouldApply(compat)) {
applyListenerToCompat(compat, config);
@ -173,7 +179,7 @@ public abstract class ForgeCompatManager extends CompatManager {
* 将监听器应用到特定兼容模块
*/
private void applyListenerToCompat(ResourceLocation compatId, ListenerConfig config) {
IForgeCompat compat = compats.get(compatId);
INeoForgeCompat compat = compats.get(compatId);
if (compat != null && config.shouldApply(compat)) {
applyListenerToCompat(compat, config);
}
@ -182,33 +188,22 @@ public abstract class ForgeCompatManager extends CompatManager {
/**
* 将监听器应用到具体的 ICompat 实例
*/
private void applyListenerToCompat(IForgeCompat compat, ListenerConfig config) {
private void applyListenerToCompat(INeoForgeCompat compat, ListenerConfig config) {
try {
// 根据配置调用对应的 ICompat 方法
if (config.dists != null) {
switch (config.dists) {
case CLIENT -> DistExecutor.unsafeRunWhenOn(Dist.CLIENT,() -> () -> {
if (config.bus == Mod.EventBusSubscriber.Bus.FORGE) {
compat.addClientGameListener(gameEventBus);
} else {
compat.addClientModListener(modEventBus);
}
});
case DEDICATED_SERVER -> DistExecutor.unsafeRunWhenOn(Dist.DEDICATED_SERVER,() -> () -> {
if (config.bus == Mod.EventBusSubscriber.Bus.FORGE) {
compat.addServerGameListener(gameEventBus);
} else {
compat.addServerModListener(modEventBus);
}
});
// 不再使用 DistExecutor改为在运行时判断环境
Dist currentDist = FMLEnvironment.dist;
if (config.dists == Dist.CLIENT && currentDist == Dist.CLIENT) {
applyClientListener(compat, config);
} else if (config.dists == Dist.DEDICATED_SERVER && currentDist == Dist.DEDICATED_SERVER) {
applyServerListener(compat, config);
}
// 如果环境不匹配什么都不做
} else {
// 通用监听器
if (config.bus == Mod.EventBusSubscriber.Bus.FORGE) {
compat.addCommonGameListener(gameEventBus);
} else {
compat.addCommonModListener(modEventBus);
}
// 通用监听器两边都执行
applyCommonListener(compat, config);
}
logger.debug("Applied {} listener to compat: {}",
@ -219,15 +214,39 @@ public abstract class ForgeCompatManager extends CompatManager {
}
}
private void applyClientListener(INeoForgeCompat compat, @NotNull ListenerConfig config) {
if (config.bus == EventBusSubscriber.Bus.GAME) {
compat.addClientGameListener(gameEventBus);
} else {
compat.addClientModListener(modEventBus);
}
}
private void applyServerListener(INeoForgeCompat compat, @NotNull ListenerConfig config) {
if (config.bus == EventBusSubscriber.Bus.GAME) {
compat.addServerGameListener(gameEventBus);
} else {
compat.addServerModListener(modEventBus);
}
}
private void applyCommonListener(INeoForgeCompat compat, @NotNull ListenerConfig config) {
if (config.bus == EventBusSubscriber.Bus.GAME) {
compat.addCommonGameListener(gameEventBus);
} else {
compat.addCommonModListener(modEventBus);
}
}
/**
* 获取监听器类型名称用于日志
*/
private @NotNull String getListenerTypeName(@NotNull ListenerConfig config) {
if (config.dists != null) {
return config.dists.name().toLowerCase() + " " +
(config.bus == Mod.EventBusSubscriber.Bus.FORGE ? "game" : "mod");
(config.bus == EventBusSubscriber.Bus.GAME ? "game" : "mod");
} else {
return "common " + (config.bus == Mod.EventBusSubscriber.Bus.FORGE ? "game" : "mod");
return "common " + (config.bus == EventBusSubscriber.Bus.GAME ? "game" : "mod");
}
}
@ -238,7 +257,7 @@ public abstract class ForgeCompatManager extends CompatManager {
* @param compatId the compat id
* @param bus the bus
*/
public void addListenerForCompat(ResourceLocation compatId, Mod.EventBusSubscriber.Bus bus) {
public void addListenerForCompat(ResourceLocation compatId, EventBusSubscriber.Bus bus) {
addListenerForCompat(compatId, null, bus);
}
@ -257,7 +276,7 @@ public abstract class ForgeCompatManager extends CompatManager {
/**
* The Bus.
*/
final Mod.EventBusSubscriber.Bus bus;
final EventBusSubscriber.Bus bus;
/**
* Instantiates a new Listener config.
@ -266,7 +285,7 @@ public abstract class ForgeCompatManager extends CompatManager {
* @param dists the dists
* @param bus the bus
*/
ListenerConfig(ResourceLocation compatId, Dist dists, Mod.EventBusSubscriber.Bus bus) {
ListenerConfig(ResourceLocation compatId, Dist dists, EventBusSubscriber.Bus bus) {
this.compatId = compatId;
this.dists = dists;
this.bus = bus;
@ -278,7 +297,7 @@ public abstract class ForgeCompatManager extends CompatManager {
* @param compat the compat
* @return the boolean
*/
boolean shouldApply(@NotNull IForgeCompat compat) {
boolean shouldApply(@NotNull INeoForgeCompat compat) {
return compat.isModLoaded();
}
}

View File

@ -1,18 +1,28 @@
package top.r3944realms.lib39.core.event;
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.ShaderInstance;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.EntityRenderersEvent;
import net.minecraftforge.client.event.RegisterShadersEvent;
import net.minecraftforge.event.level.LevelEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraft.client.renderer.entity.ItemRenderer;
import net.minecraft.client.renderer.item.ItemProperties;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent;
import net.neoforged.neoforge.client.event.EntityRenderersEvent;
import net.neoforged.neoforge.client.event.RegisterShadersEvent;
import net.neoforged.neoforge.client.extensions.common.IClientItemExtensions;
import net.neoforged.neoforge.client.extensions.common.RegisterClientExtensionsEvent;
import net.neoforged.neoforge.event.level.LevelEvent;
import org.jetbrains.annotations.NotNull;
import top.r3944realms.lib39.Lib39;
import top.r3944realms.lib39.client.model.DollModel;
import top.r3944realms.lib39.client.renderer.block.DollBlockEntityRenderer;
import top.r3944realms.lib39.client.shader.Lib39Shaders;
import top.r3944realms.lib39.content.item.NeoForgeDollItem;
import top.r3944realms.lib39.core.register.Lib39BlockEntities;
import top.r3944realms.lib39.core.register.Lib39Items;
import top.r3944realms.lib39.util.ILevelHelper;
import java.io.IOException;
@ -24,7 +34,7 @@ public class ClientEventHandler {
/**
* The type Mod.
*/
@net.minecraftforge.fml.common.Mod.EventBusSubscriber(value = Dist.CLIENT, bus = net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus.MOD, modid = Lib39.MOD_ID)
@EventBusSubscriber(value = Dist.CLIENT, bus = EventBusSubscriber.Bus.MOD, modid = Lib39.MOD_ID)
public static class Mod extends ClientEventHandler {
/**
* On register shaders.
@ -33,7 +43,7 @@ public class ClientEventHandler {
* @throws IOException the io exception
*/
@SubscribeEvent
public static void onRegisterShaders(RegisterShadersEvent event) throws IOException {
public static void onRegisterShaders(@NotNull RegisterShadersEvent event) throws IOException {
event.registerShader(new ShaderInstance(event.getResourceProvider(), Lib39.rl("ring"), DefaultVertexFormat.POSITION_COLOR), Lib39Shaders::setRingShader);
event.registerShader(new ShaderInstance(event.getResourceProvider(), Lib39.rl("selection"), DefaultVertexFormat.POSITION_COLOR), Lib39Shaders::setSelectionShader);
}
@ -44,7 +54,7 @@ public class ClientEventHandler {
* @param event the event
*/
@SubscribeEvent
public static void onRegisterRenderer (EntityRenderersEvent.RegisterRenderers event) {
public static void onRegisterRenderer (EntityRenderersEvent.@NotNull RegisterRenderers event) {
event.registerBlockEntityRenderer(Lib39BlockEntities.DOLL_BLOCK_ENTITY.get(),DollBlockEntityRenderer::new);
}
@ -54,16 +64,26 @@ public class ClientEventHandler {
* @param event the event
*/
@SubscribeEvent
public static void registerLayerDefinitions(EntityRenderersEvent.RegisterLayerDefinitions event) {
public static void registerLayerDefinitions(EntityRenderersEvent.@NotNull RegisterLayerDefinitions event) {
event.registerLayerDefinition(DollModel.LAYER_LOCATION, DollModel::createBodyLayer);
}
/**
* On register client ex.
*
* @param event the event
*/
@SubscribeEvent
public static void onRegisterClientEx (@NotNull RegisterClientExtensionsEvent event) {
event.registerItem(NeoForgeDollItem.ClientOpt.getExtensions(), Lib39Items.DOLL.get());
}
}
/**
* The type Game.
*/
@net.minecraftforge.fml.common.Mod.EventBusSubscriber(value = Dist.CLIENT, bus = net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus.FORGE, modid = Lib39.MOD_ID)
@EventBusSubscriber(value = Dist.CLIENT, bus = EventBusSubscriber.Bus.GAME, modid = Lib39.MOD_ID)
public static class Game extends ClientEventHandler {
/**
* Register layer definitions.
@ -71,7 +91,7 @@ public class ClientEventHandler {
* @param event the event
*/
@SubscribeEvent
public static void obClientUnload(LevelEvent.Load event) {
public static void obClientUnload(LevelEvent.@NotNull Load event) {
if (event.getLevel() != null && event.getLevel() instanceof ClientLevel level) {
ILevelHelper.LevelHelper.CLIENT.setLevel(level);
}
@ -83,7 +103,7 @@ public class ClientEventHandler {
* @param event the event
*/
@SubscribeEvent
public static void obClientUnload(LevelEvent.Unload event) {
public static void obClientUnload(LevelEvent.@NotNull Unload event) {
if (event.getLevel() != null && event.getLevel() instanceof ClientLevel level) {
ILevelHelper.LevelHelper.CLIENT.setLevel(null);
}

View File

@ -3,6 +3,7 @@ package top.r3944realms.lib39.core.event;
import com.mojang.authlib.GameProfile;
import net.minecraft.Util;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.component.DataComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
@ -11,26 +12,33 @@ import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
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.minecraftforge.common.MinecraftForge;
import net.minecraftforge.data.event.GatherDataEvent;
import net.minecraftforge.event.AnvilUpdateEvent;
import net.minecraftforge.event.BuildCreativeModeTabContentsEvent;
import net.minecraftforge.event.RegisterCommandsEvent;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.event.entity.EntityJoinLevelEvent;
import net.minecraftforge.event.entity.EntityLeaveLevelEvent;
import net.minecraftforge.event.level.LevelEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent;
import net.neoforged.neoforge.common.NeoForge;
import net.neoforged.neoforge.data.event.GatherDataEvent;
import net.neoforged.neoforge.event.AnvilUpdateEvent;
import net.neoforged.neoforge.event.BuildCreativeModeTabContentsEvent;
import net.neoforged.neoforge.event.RegisterCommandsEvent;
import net.neoforged.neoforge.event.entity.EntityJoinLevelEvent;
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;
import top.r3944realms.lib39.core.sync.ISyncData;
import top.r3944realms.lib39.core.sync.SyncData2CapManager;
@ -50,7 +58,7 @@ public class CommonEventHandler {
* The type Game.
*/
@SuppressWarnings("unused")
@net.minecraftforge.fml.common.Mod.EventBusSubscriber(modid = Lib39.MOD_ID, bus = net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus.FORGE)
@EventBusSubscriber(modid = Lib39.MOD_ID, bus = EventBusSubscriber.Bus.GAME)
public static class Game extends CommonEventHandler {
private static ServerLevel sl;
@ -92,7 +100,7 @@ public class CommonEventHandler {
synchronized (Game.class) {
if (!isSync2MInitialized) {
syncData2Manager = new SyncData2CapManager();
MinecraftForge.EVENT_BUS.post(new SyncManagerRegisterEvent(syncData2Manager));
NeoForge.EVENT_BUS.post(new SyncManagerRegisterEvent(syncData2Manager));
isSync2MInitialized = true;
sl = serverLevel;
Lib39.LOGGER.info("SyncData2Manager initialized on Sever load");
@ -104,7 +112,7 @@ public class CommonEventHandler {
if (!clientLevel.dimension().equals(Level.OVERWORLD)) return;
if (!isSync2MInitialized) {
syncData2Manager = new SyncData2CapManager();
MinecraftForge.EVENT_BUS.post(new SyncManagerRegisterEvent(syncData2Manager));
NeoForge.EVENT_BUS.post(new SyncManagerRegisterEvent(syncData2Manager));
Lib39.LOGGER.info("SyncData2Manager initialized on Client load");
}
}
@ -132,13 +140,11 @@ public class CommonEventHandler {
* @param event the event
*/
@SubscribeEvent
public static void onServerTick(TickEvent.ServerTickEvent event) {
if (event.phase == TickEvent.Phase.END) {
if (syncData2Manager == null) return;
if (event.getServer().getTickCount() % 10 == 0)
syncData2Manager.forEach(((resourceLocation, iSyncManager) -> iSyncManager.foreach(ISyncData::markDirty)));
syncData2Manager.forEach(((resourceLocation, iSyncManager) -> iSyncManager.foreach(ISyncData::checkIfDirtyThenUpdate)));
}
public static void onServerTick(ServerTickEvent.Post event) {
if (syncData2Manager == null) return;
if (event.getServer().getTickCount() % 10 == 0)
syncData2Manager.forEach(((resourceLocation, iSyncManager) -> iSyncManager.foreach(ISyncData::markDirty)));
syncData2Manager.forEach(((resourceLocation, iSyncManager) -> iSyncManager.foreach(ISyncData::checkIfDirtyThenUpdate)));
}
/**
@ -150,22 +156,45 @@ public class CommonEventHandler {
public static void onAnvilRename(AnvilUpdateEvent event) {
if (event.getLeft().getItem() instanceof DollItem) {
String name = event.getName();
if (name != null && name.length() < 15) {
GameProfile profile = new GameProfile(Util.NIL_UUID, name);
ItemStack copied = Lib39Items.DOLL.get().getDefaultInstance();
SkullBlockEntity.updateGameprofile(profile,
profile1 -> GameProfileHelper.saveProfileToItemStack(copied, profile1)
);
copied.setCount(event.getLeft().getCount());
event.setOutput(copied);
event.setCost(1);
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 {
ItemStack errorOutput = Items.BARRIER.getDefaultInstance();
errorOutput.set(DataComponents.CUSTOM_NAME,
Component.translatable("invalid.player_name.too_long"));
event.setOutput(errorOutput);
event.setCost(0);
}
} else {
ItemStack defaultInstance = Items.BARRIER.getDefaultInstance();
defaultInstance.setHoverName(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.
@ -216,7 +245,7 @@ public class CommonEventHandler {
* The type Mod.
*/
@SuppressWarnings("unused")
@net.minecraftforge.fml.common.Mod.EventBusSubscriber(modid = Lib39.MOD_ID, bus = net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus.MOD)
@EventBusSubscriber(modid = Lib39.MOD_ID, bus = EventBusSubscriber.Bus.MOD)
public static class Mod extends CommonEventHandler {
private static final Map<Supplier<Block>, ResourceKey<CreativeModeTab>[]> itemAddMap = new ConcurrentHashMap<>();
private static final Map<ResourceKey<CreativeModeTab>, List<Supplier<Block>>> tabToItemsMap = new ConcurrentHashMap<>();
@ -262,10 +291,20 @@ public class CommonEventHandler {
public static void onBuildCreativeTabContents(BuildCreativeModeTabContentsEvent event) {
List<Supplier<Block>> itemsForTab = tabToItemsMap.get(event.getTabKey());
if (itemsForTab != null) {
itemsForTab.forEach(event::accept);
itemsForTab.forEach(i -> event.accept(i.get()));
}
}
/**
* On register payload.
*
* @param event the event
*/
@SubscribeEvent
public static void onRegisterPayload (RegisterPayloadHandlersEvent event) {
NetworkHandler.register(event);
}
/**
* Gather data.
*

View File

@ -1,9 +1,10 @@
package top.r3944realms.lib39.core.event;
import net.minecraft.server.level.ServerLevel;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.event.level.LevelEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.neoforge.event.level.LevelEvent;
import top.r3944realms.lib39.Lib39;
import top.r3944realms.lib39.util.ILevelHelper;
@ -19,7 +20,7 @@ public class ServerEventHandler {
/**
* The type Game.
*/
@net.minecraftforge.fml.common.Mod.EventBusSubscriber(value = Dist.DEDICATED_SERVER, bus = net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus.FORGE, modid = Lib39.MOD_ID)
@EventBusSubscriber(value = Dist.DEDICATED_SERVER, bus = EventBusSubscriber.Bus.GAME, modid = Lib39.MOD_ID)
public static class Game extends ServerEventHandler {
/**
* Register layer definitions.

View File

@ -0,0 +1,28 @@
package top.r3944realms.lib39.core.network;
import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent;
import net.neoforged.neoforge.network.registration.PayloadRegistrar;
import org.jetbrains.annotations.NotNull;
import top.r3944realms.lib39.Lib39;
import top.r3944realms.lib39.core.network.toClient.SyncNBTCapDataEntityS2CPayload;
/**
* The type Network handler.
*/
@SuppressWarnings("unused")
public class NetworkHandler {
/**
* Register packets.
*
* @param event the event
*/
public static void register(@NotNull RegisterPayloadHandlersEvent event) {
PayloadRegistrar registrar = event.registrar(Lib39.ModInfo.VERSION);
registrar
.playToClient(
SyncNBTCapDataEntityS2CPayload.TYPE,
SyncNBTCapDataEntityS2CPayload.STREAM_CODEC,
SyncNBTCapDataEntityS2CPayload::handle
);
}
}

View File

@ -4,9 +4,12 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.Entity;
import net.minecraftforge.network.NetworkEvent;
import net.neoforged.neoforge.network.handling.IPayloadContext;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import top.r3944realms.lib39.Lib39;
@ -19,10 +22,25 @@ import java.util.Optional;
import java.util.function.Supplier;
/**
* The type Sync nbt data s 2 c pack.
* The type Sync nbt data s 2 c payload.
*/
@SuppressWarnings("unused")
public record SyncNBTCapDataEntityS2CPacket(int entityId, ResourceLocation id, CompoundTag data) {
public record SyncNBTCapDataEntityS2CPayload(int entityId, ResourceLocation id, CompoundTag data) implements CustomPacketPayload {
/**
* The constant SYNC_NBT_CAP_PACKET_ID.
*/
public static final ResourceLocation SYNC_NBT_CAP_PACKET_ID =
Lib39.rl("sync_nbt_cap_data_entity");
/**
* The constant TYPE.
*/
public static final Type<SyncNBTCapDataEntityS2CPayload> TYPE = new Type<>(SYNC_NBT_CAP_PACKET_ID);
/**
* The constant STREAM_CODEC.
*/
public static final StreamCodec<RegistryFriendlyByteBuf, SyncNBTCapDataEntityS2CPayload> STREAM_CODEC =
StreamCodec.ofMember(SyncNBTCapDataEntityS2CPayload::encode, SyncNBTCapDataEntityS2CPayload::decode);
/**
* Instantiates a new Sync nbt data s 2 c pack.
@ -30,7 +48,7 @@ public record SyncNBTCapDataEntityS2CPacket(int entityId, ResourceLocation id, C
* @param entityId the entity id
* @param data the data
*/
public SyncNBTCapDataEntityS2CPacket(int entityId, @NotNull NBTEntitySyncData data) {
public SyncNBTCapDataEntityS2CPayload(int entityId, @NotNull NBTEntitySyncData data) {
this(entityId, data.id(), data.serializeNBT());
}
@ -40,7 +58,7 @@ public record SyncNBTCapDataEntityS2CPacket(int entityId, ResourceLocation id, C
* @param msg the msg
* @param buffer the buffer
*/
public static void encode(@NotNull SyncNBTCapDataEntityS2CPacket msg, @NotNull FriendlyByteBuf buffer) {
public static void encode(@NotNull SyncNBTCapDataEntityS2CPayload msg, @NotNull FriendlyByteBuf buffer) {
buffer.writeInt(msg.entityId);
buffer.writeResourceLocation(msg.id);
buffer.writeNbt(msg.data);
@ -53,41 +71,43 @@ public record SyncNBTCapDataEntityS2CPacket(int entityId, ResourceLocation id, C
* @return the sync nbt data s 2 c pack
*/
@Contract("_ -> new")
public static @NotNull SyncNBTCapDataEntityS2CPacket decode(@NotNull FriendlyByteBuf buffer) {
return new SyncNBTCapDataEntityS2CPacket(buffer.readInt(), buffer.readResourceLocation(), buffer.readNbt());
public static @NotNull SyncNBTCapDataEntityS2CPayload decode(@NotNull FriendlyByteBuf buffer) {
return new SyncNBTCapDataEntityS2CPayload(buffer.readInt(), buffer.readResourceLocation(), buffer.readNbt());
}
/**
* Handle.
*
* @param msg the msg
* @param ctx the ctx
* @param payload the msg
* @param context the context
*/
public static void handle(SyncNBTCapDataEntityS2CPacket msg, @NotNull Supplier<NetworkEvent.Context> ctx) {
NetworkEvent.Context context = ctx.get();
public static void handle(SyncNBTCapDataEntityS2CPayload payload, @NotNull IPayloadContext context) {
context.enqueueWork(() -> {
ClientLevel level = Minecraft.getInstance().level;
if (level != null) {
Entity entity = level.getEntity(msg.entityId);
Entity entity = level.getEntity(payload.entityId);
if (entity != null) {
Optional<SyncData2Manager.DataProvider<Entity, ISyncData<?>>> capOpt =
CommonEventHandler.Game
.getSyncData2Manager()
.getDataProvider(msg.id);
.getDataProvider(payload.id);
capOpt.flatMap(dataProvider -> dataProvider.getData(entity))
.ifPresent(cap -> {
if (cap instanceof NBTEntitySyncData nbtCap) {
CompoundTag current = nbtCap.serializeNBT();
if (!current.equals(msg.data)) {
nbtCap.deserializeNBT(msg.data);
if (!current.equals(payload.data)) {
nbtCap.deserializeNBT(payload.data);
}
} else Lib39.LOGGER.debug("Unhandled sync data: {}", msg.data);
} else Lib39.LOGGER.debug("Unhandled sync data: {}", payload.data);
}
);
}
}
});
context.setPacketHandled(true);
}
@Override
public Type<? extends CustomPacketPayload> type() {
return TYPE;
}
}

View File

@ -1,20 +1,20 @@
package top.r3944realms.lib39.core.register;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.neoforge.registries.DeferredRegister;
import top.r3944realms.lib39.Lib39;
import top.r3944realms.lib39.content.block.blockentity.DollBlockEntity;
/**
* The type Lib 39 block entities.
*/
public class ForgeLib39BlockEntities {
public class NeoForgeLib39BlockEntities {
/**
* The constant BLOCK_ENTITY_TYPES.
*/
public static final DeferredRegister<BlockEntityType<?>> BLOCK_ENTITY_TYPES = DeferredRegister.create(ForgeRegistries.BLOCK_ENTITY_TYPES, Lib39.MOD_ID);
public static final DeferredRegister<BlockEntityType<?>> BLOCK_ENTITY_TYPES = DeferredRegister.create(BuiltInRegistries.BLOCK_ENTITY_TYPE, Lib39.MOD_ID);
static {
//noinspection DataFlowIssue

View File

@ -1,9 +1,9 @@
package top.r3944realms.lib39.core.register;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.world.level.block.Block;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.neoforge.registries.DeferredRegister;
import top.r3944realms.lib39.Lib39;
import top.r3944realms.lib39.content.block.DollBlock;
import top.r3944realms.lib39.content.block.WallDollBlock;
@ -12,11 +12,11 @@ import top.r3944realms.lib39.util.block.BlockRegistryBuilder;
/**
* The type Lib 39 blocks.
*/
public class ForgeLib39Blocks {
public class NeoForgeLib39Blocks {
/**
* The constant BLOCKS.
*/
public static final DeferredRegister<Block> BLOCKS = DeferredRegister.create(ForgeRegistries.BLOCKS, Lib39.MOD_ID);
public static final DeferredRegister<Block> BLOCKS = DeferredRegister.create(BuiltInRegistries.BLOCK, Lib39.MOD_ID);
static {
Lib39Blocks.DOLL = BlockRegistryBuilder

View File

@ -1,23 +1,23 @@
package top.r3944realms.lib39.core.register;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.world.item.Item;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.neoforge.registries.DeferredRegister;
import top.r3944realms.lib39.Lib39;
import top.r3944realms.lib39.content.item.ForgeDollItem;
import top.r3944realms.lib39.content.item.NeoForgeDollItem;
/**
* The type Ex lib 39 items.
*/
public class ForgeLib39Items {
public class NeoForgeLib39Items {
/**
* The constant ITEMS.
*/
public static final DeferredRegister<Item> ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, Lib39.MOD_ID);
public static final DeferredRegister<Item> ITEMS = DeferredRegister.create(BuiltInRegistries.ITEM, Lib39.MOD_ID);
static {
Lib39Items.DOLL = ITEMS.register("doll", () -> new ForgeDollItem(new Item.Properties()));
Lib39Items.DOLL = ITEMS.register("doll", () -> new NeoForgeDollItem(new Item.Properties()));
}
/**

View File

@ -1,19 +1,19 @@
package top.r3944realms.lib39.core.register;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.sounds.SoundEvent;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.neoforge.registries.DeferredRegister;
import top.r3944realms.lib39.Lib39;
/**
* The type Lib 39 sound events.
*/
public class ForgeLib39SoundEvents {
public class NeoForgeLib39SoundEvents {
/**
* The constant SOUND_EVENTS.
*/
public static final DeferredRegister<SoundEvent> SOUND_EVENTS = DeferredRegister.create(ForgeRegistries.SOUND_EVENTS, Lib39.MOD_ID);
public static final DeferredRegister<SoundEvent> SOUND_EVENTS = DeferredRegister.create(BuiltInRegistries.SOUND_EVENT, Lib39.MOD_ID);
static {
Lib39SoundEvents.DUCK_TOY = SOUND_EVENTS.register("duck_toy",

View File

@ -0,0 +1,14 @@
package top.r3944realms.lib39.core.sync;
import net.neoforged.neoforge.network.PacketDistributor;
import top.r3944realms.lib39.core.network.NetworkHandler;
import top.r3944realms.lib39.core.network.toClient.SyncNBTCapDataEntityS2CPayload;
/**
* The interface NeoForge update.
*/
public interface INeoForgeUpdate extends IUpdate {
default void update() {
PacketDistributor.sendToAllPlayers(new SyncNBTCapDataEntityS2CPayload(getSyncData().entityId(), getSyncData().id, getSyncData().serializeNBT()));
}
}

View File

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

View File

@ -2,7 +2,7 @@ package top.r3944realms.lib39.core.sync;
import com.google.common.collect.Maps;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.common.capabilities.Capability;
import net.neoforged.neoforge.capabilities.EntityCapability;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
@ -29,15 +29,15 @@ public class SyncData2CapManager extends SyncData2Manager<SyncData2CapManager.Ty
*
* @param <T> the type parameter
*/
protected static class TypedSyncEntry<T extends ISyncData<?>> extends SyncData2Manager.TypedSyncEntry<Capability<T>, T> {
protected static class TypedSyncEntry<T extends ISyncData<?>> extends SyncData2Manager.TypedSyncEntry<EntityCapability<T, Void>, T> {
/**
* Instantiates a new Typed sync entry.
*
* @param manager the manager
* @param capability the capability
*/
public TypedSyncEntry(ISyncManager<Capability<T>, T> manager,@Nullable Capability<T> capability) {
super(manager, key -> capability != null ? key.getCapability(capability).resolve() : Optional.empty());
public TypedSyncEntry(ISyncManager<EntityCapability<T, Void>, T> manager,@Nullable EntityCapability<T, Void> capability) {
super(manager, key -> capability != null ? Optional.ofNullable(key.getCapability(capability)) : Optional.empty());
}
}
@ -51,8 +51,8 @@ public class SyncData2CapManager extends SyncData2Manager<SyncData2CapManager.Ty
*/
public <T extends ISyncData<?>> void registerManager(
ResourceLocation key,
ISyncManager<Capability<T>, T> manager,
Capability<T> capability
ISyncManager<EntityCapability<T, Void>, T> manager,
EntityCapability<T, Void> capability
) {
Objects.requireNonNull(key, "ResourceLocation key cannot be null");
Objects.requireNonNull(manager, "Sync manager cannot be null");
@ -69,7 +69,7 @@ public class SyncData2CapManager extends SyncData2Manager<SyncData2CapManager.Ty
* @param key the key
* @param capability the capability
*/
public <T extends ISyncData<?>> void bindCapability(ResourceLocation key, Capability<T> capability) {
public <T extends ISyncData<?>> void bindCapability(ResourceLocation key, EntityCapability<T, Void> capability) {
Objects.requireNonNull(key, "ResourceLocation key cannot be null");
Objects.requireNonNull(capability, "Capability cannot be null");
@ -103,7 +103,7 @@ public class SyncData2CapManager extends SyncData2Manager<SyncData2CapManager.Ty
* @param entry the entry
* @param newCapability the new capability
*/
protected <T extends ISyncData<?>> void updateCapabilityInEntry(ResourceLocation id, TypedSyncEntry<?> entry, Capability<T> newCapability) {
updateDataProviderInEntry(id, entry, key -> newCapability != null ? key.getCapability(newCapability).resolve() : Optional.empty());
protected <T extends ISyncData<?>> void updateCapabilityInEntry(ResourceLocation id, TypedSyncEntry<?> entry, EntityCapability<T, Void> newCapability) {
updateDataProviderInEntry(id, entry, key -> newCapability != null ? Optional.ofNullable(key.getCapability(newCapability)) : Optional.empty());
}
}

View File

@ -1,14 +1,19 @@
package top.r3944realms.lib39.datagen.provider;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.WritableRegistry;
import net.minecraft.data.PackOutput;
import net.minecraft.data.loot.LootTableProvider;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.ProblemReporter;
import net.minecraft.world.level.storage.loot.LootTable;
import net.minecraft.world.level.storage.loot.ValidationContext;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
/**
* The type Simple loot table provider.
@ -19,9 +24,10 @@ public class SimpleLootTableProvider extends LootTableProvider {
*
* @param output the output
* @param subProvidersWrapper the sub providers wrapper
* @param registries the registries
*/
public SimpleLootTableProvider(PackOutput output, @NotNull SubProvidersWrapper subProvidersWrapper) {
super(output, Set.of(), subProvidersWrapper.entries);
public SimpleLootTableProvider(PackOutput output, @NotNull SubProvidersWrapper subProvidersWrapper, CompletableFuture<HolderLookup.Provider> registries) {
super(output, Set.of(), subProvidersWrapper.entries, registries);
}
/**
@ -30,13 +36,14 @@ public class SimpleLootTableProvider extends LootTableProvider {
* @param output the output
* @param requiredTables the required tables
* @param subProvidersWrapper the sub providers wrapper
* @param registries the registries
*/
public SimpleLootTableProvider(PackOutput output, Set<ResourceLocation> requiredTables, @NotNull SubProvidersWrapper subProvidersWrapper) {
super(output, requiredTables, subProvidersWrapper.entries);
public SimpleLootTableProvider(PackOutput output, Set<ResourceKey<LootTable>> requiredTables, @NotNull SubProvidersWrapper subProvidersWrapper, CompletableFuture<HolderLookup.Provider> registries) {
super(output, requiredTables, subProvidersWrapper.entries, registries);
}
@Override
protected void validate(@NotNull Map<ResourceLocation, LootTable> map, @NotNull ValidationContext validationcontext) {
map.forEach((id, table) -> table.validate(validationcontext));
protected void validate(WritableRegistry<LootTable> writableregistry, ValidationContext validationcontext, ProblemReporter.Collector problemreporter$collector) {
writableregistry.forEach(lootTable -> lootTable.validate(validationcontext));
}
}

Some files were not shown because too many files have changed in this diff Show More