feat: 跨版本化,第二部分,未完成

This commit is contained in:
叁玖领域 2026-03-11 21:02:57 +08:00
parent eac118e9a4
commit 5a6729aa31
46 changed files with 2656 additions and 118 deletions

1
.gitignore vendored
View File

@ -21,6 +21,7 @@ build
# other
eclipse
run
generated
runs
run-data

View File

@ -16,7 +16,8 @@ public class Lib39 {
*/
public static final String ENABLE_EXAMPLES_PROPERTY_KEY = "lib39.enable_examples";
public static void initialize() {
Lib39.LOGGER.info("[Lib39-Common] Lib39-Common start initialization.");
Lib39.LOGGER.info("[Lib39-Common] Finished Lib39-Common!.");
}
/**
* Rl resource location.

View File

@ -0,0 +1,769 @@
package top.r3944realms.lib39.client.gui.component;
import com.mojang.blaze3d.platform.Window;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.*;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.narration.NarrationElementOutput;
import net.minecraft.client.renderer.ShaderInstance;
import net.minecraft.network.chat.Component;
import org.joml.Matrix4f;
import org.joml.Vector2f;
import top.r3944realms.lib39.client.shader.Lib39Shaders;
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.
*/
public static final int IGNORE_CURSOR_MOVE_LENGTH = 15;
private static final Vector2f ROTATION_START = new Vector2f(0, 1);
private static final int SELECTION_EFFECT_COLOR = 0xddFFFF00;
private static final int SELECTION_EFFECT_RADIUS = 20;
private final Minecraft minecraft = Minecraft.getInstance();
private final Vector2f centerPos;
private final float ringInnerRadius;
private final float ringOuterRadius;
private final int delay;
private final int animationMs;
private final int closingAnimationMs; //ms
private final int ringColor;
private final int selectionEffectColor;
private final int selectionEffectRadius;
private final float selectionAnimationSpeedFactor;
private final int textColor;
private final float textScale;
private final List<WheelSection> sections = new ArrayList<>();
private long displayTime = System.currentTimeMillis();
private float currentAngle = 0;
/**
* Gets current section index.
*
* @return the current section index
*/
public int getCurrentSectionIndex() {
return currentSectionIndex;
}
/**
* Is closing animation started boolean.
*
* @return the boolean
*/
public boolean isClosingAnimationStarted() {
return closingAnimationStarted;
}
private int currentSectionIndex = -1;
private Vector2f selectionEffectPos;
private boolean animationStarted = false;
/**
* Sets closing animation started.
*
* @param closingAnimationStarted the closing animation started
*/
public void setClosingAnimationStarted(boolean closingAnimationStarted) {
this.closingAnimationStarted = closingAnimationStarted;
}
private boolean closingAnimationStarted = false;
/**
* Instantiates a new Wheel widget.
*
* @param x the x
* @param y the y
* @param width the width
* @param height the height
* @param ringInnerRadius the ring inner radius
* @param ringOuterRadius the ring outer radius
* @param textScale the text scale
* @param sections the sections
*/
public WheelWidget(
int x, int y, int width, int height,
float ringInnerRadius, float ringOuterRadius, float textScale,
List<Pair<Component, FourConsumer<GuiGraphics, PoseStack, Integer, Integer>>> sections
) {
this(x, y, width, height, Component.empty(), ringInnerRadius, ringOuterRadius, textScale, sections);
}
/**
* Instantiates a new Wheel widget.
*
* @param x the x
* @param y the y
* @param width the width
* @param height the height
* @param ringInnerRadius the ring inner radius
* @param ringOuterRadius the ring outer radius
* @param textScale the text scale
* @param degreeOffsetAngle the degree offset angle
* @param sections the sections
*/
public WheelWidget(
int x, int y, int width, int height,
float ringInnerRadius, float ringOuterRadius, float textScale, float degreeOffsetAngle,
List<Pair<Component, FourConsumer<GuiGraphics, PoseStack, Integer, Integer>>> sections
) {
this(x, y, width, height, Component.empty(), ringInnerRadius, ringOuterRadius, textScale, degreeOffsetAngle, sections);
}
/**
* Instantiates a new Wheel widget.
*
* @param x the x
* @param y the y
* @param width the width
* @param height the height
* @param ringInnerRadius the ring inner radius
* @param ringOuterRadius the ring outer radius
* @param sections the sections
*/
public WheelWidget(
int x, int y, int width, int height,
float ringInnerRadius, float ringOuterRadius,
List<Pair<Component, FourConsumer<GuiGraphics, PoseStack, Integer, Integer>>> sections
) {
this(x, y, width, height, Component.empty(), ringInnerRadius, ringOuterRadius, sections);
}
/**
* Instantiates a new Wheel widget.
*
* @param x the x
* @param y the y
* @param width the width
* @param height the height
* @param message the message
* @param ringInnerRadius the ring inner radius
* @param ringOuterRadius the ring outer radius
* @param textScale the text scale
* @param degreeOffsetAngle the degree offset angle
* @param sections the sections
*/
public WheelWidget(
int x, int y, int width, int height, Component message,
float ringInnerRadius, float ringOuterRadius, float textScale, float degreeOffsetAngle,
List<Pair<Component, FourConsumer<GuiGraphics, PoseStack, Integer, Integer>>> sections
) {
this(
x, y, width, height, message,
ringInnerRadius, ringOuterRadius,
150, 300, 150,
0x00000000,
0xddffff00, 20, 5f,
0xfdfdfd, textScale, degreeOffsetAngle,
sections
);
}
/**
* Instantiates a new Wheel widget.
*
* @param x the x
* @param y the y
* @param width the width
* @param height the height
* @param message the message
* @param ringInnerRadius the ring inner radius
* @param ringOuterRadius the ring outer radius
* @param sections the sections
*/
public WheelWidget(
int x, int y, int width, int height, Component message,
float ringInnerRadius, float ringOuterRadius,
List<Pair<Component, FourConsumer<GuiGraphics, PoseStack, Integer, Integer>>> sections
) {
this(
x, y, width, height, message,
ringInnerRadius, ringOuterRadius,
150, 300, 150,
0x00000000,
0xddffff00, 20, 5f,
0xfdfdfd, 1f, 0f,
sections
);
}
/**
* Instantiates a new Wheel widget.
*
* @param x the x
* @param y the y
* @param width the width
* @param height the height
* @param message the message
* @param ringInnerRadius the ring inner radius
* @param ringOuterRadius the ring outer radius
* @param degreeOffsetAngle the degree offset angle
* @param sections the sections
*/
public WheelWidget(
int x, int y, int width, int height, Component message,
float ringInnerRadius, float ringOuterRadius, float degreeOffsetAngle,
List<Pair<Component, FourConsumer<GuiGraphics, PoseStack, Integer, Integer>>> sections
) {
this(
x, y, width, height, message,
ringInnerRadius, ringOuterRadius,
150, 300, 150,
0x00000000,
0xddffff00, 20, 5f,
0xfdfdfd, 1f, degreeOffsetAngle,
sections
);
}
/**
* Instantiates a new Wheel widget.
*
* @param x the x
* @param y the y
* @param width the width
* @param height the height
* @param ringInnerRadius the ring inner radius
* @param ringOuterRadius the ring outer radius
* @param delay the delay
* @param animationMs the animation ms
* @param closingAnimationMs the closing animation ms
* @param ringColor the ring color
* @param selectionEffectColor the selection effect color
* @param selectionEffectRadius the selection effect radius
* @param selectionAnimationSpeedFactor the selection animation speed factor
* @param textColor the text color
* @param textScale the text scale
* @param sections the sections
*/
public WheelWidget(
int x, int y, int width, int height,
float ringInnerRadius, float ringOuterRadius,
int delay, int animationMs, int closingAnimationMs,
int ringColor,
int selectionEffectColor, int selectionEffectRadius, float selectionAnimationSpeedFactor,
int textColor, float textScale,
List<Pair<Component, FourConsumer<GuiGraphics, PoseStack, Integer, Integer>>> sections
) {
this(
x, y, width, height, Component.empty(),
ringInnerRadius, ringOuterRadius,
delay, animationMs, closingAnimationMs,
ringColor,
selectionEffectColor, selectionEffectRadius, selectionAnimationSpeedFactor,
textColor, textScale, 0f,
sections
);
}
/**
* Instantiates a new Wheel widget.
*
* @param x the x
* @param y the y
* @param width the width
* @param height the height
* @param message the message
* @param ringInnerRadius the ring inner radius
* @param ringOuterRadius the ring outer radius
* @param delay the delay
* @param animationMs the animation ms
* @param closingAnimationMs the closing animation ms
* @param ringColor the ring color
* @param selectionEffectColor the selection effect color
* @param selectionEffectRadius the selection effect radius
* @param selectionAnimationSpeedFactor the selection animation speed factor
* @param textColor the text color
* @param textScale the text scale
* @param degreeOffsetAngle the degree offset angle
* @param sections the sections
*/
public WheelWidget(
int x, int y, int width, int height, Component message,
float ringInnerRadius, float ringOuterRadius,
int delay, int animationMs, int closingAnimationMs,
int ringColor,
int selectionEffectColor, int selectionEffectRadius, float selectionAnimationSpeedFactor,
int textColor, float textScale, float degreeOffsetAngle,
List<Pair<Component, FourConsumer<GuiGraphics, PoseStack, Integer, Integer>>> sections
) {
super(x, y, width, height, message);
this.centerPos = new Vector2f(this.getX() + this.getWidth() / 2f, this.getY() + this.getHeight() / 2f);
this.ringInnerRadius = Math.max(ringInnerRadius, IGNORE_CURSOR_MOVE_LENGTH);
this.ringOuterRadius = ringOuterRadius;
this.delay = delay;
this.animationMs = animationMs;
this.closingAnimationMs = closingAnimationMs;
this.ringColor = ringColor;
this.selectionEffectColor = selectionEffectColor;
this.selectionEffectRadius = selectionEffectRadius;
this.selectionAnimationSpeedFactor = selectionAnimationSpeedFactor;
this.textColor = textColor;
this.textScale = textScale;
float degreeEachRotation = 360f / sections.size();
for (int i = 0; i < sections.size(); i++) {
Pair<Component, FourConsumer<GuiGraphics, PoseStack, Integer, Integer>> section = sections.get(i);
float rotation = MathUtil.clampWithProportion((degreeEachRotation * i + degreeOffsetAngle) % 360, 0, 360);
Vector2f rotated = MathUtil.rotationDegrees(ROTATION_START, rotation)
.mul(1, -1)
.mul(this.getSectionCircleDiameter())
.add(this.centerPos);
float detectionStart = (float) (Math.toRadians(rotation - degreeEachRotation / 2f) + Math.PI * 2);
float detectionEnd = (float) (Math.toRadians(rotation + degreeEachRotation / 2f) + Math.PI * 2);
detectionStart = detectionStart % (float) (Math.PI * 2);
detectionEnd = detectionEnd % (float) (Math.PI * 2);
this.sections.add(new WheelSection(
rotated,
(float) (Math.toRadians(rotation) % (Math.PI * 2)),
detectionStart,
detectionEnd,
section.first,
section.second
));
}
this.selectionEffectPos = MathUtil.rotate(
MathUtil.copy(ROTATION_START)
.mul(this.getSectionCircleDiameter()),
this.currentAngle
);
}
/**
* Gets section circle diameter.
*
* @return the section circle diameter
*/
// 滚轮选择器中每个扇形的圆形直径
public float getSectionCircleDiameter() {
return this.ringOuterRadius + this.ringInnerRadius;
}
/**
* Sets current index.
*
* @param index the index
* @return the current index
*/
public WheelWidget setCurrentIndex(int index) {
this.currentSectionIndex = index;
this.currentAngle = this.sections.get(index).angle;
this.selectionEffectPos = MathUtil.rotate(
MathUtil.copy(ROTATION_START)
.mul(this.getSectionCircleDiameter()),
this.currentAngle
);
return this;
}
/**
* Gets section size.
*
* @return the section size
*/
public int getSectionSize() {
return this.sections.size();
}
@Override
public boolean mouseScrolled(double mouseX, double mouseY, double delta) {
if (delta > 0) {
if (this.currentSectionIndex == this.getSectionSize() - 1) {
this.currentSectionIndex = 0;
} else {
this.currentSectionIndex++;
}
} else if (delta < 0) {
if (this.currentSectionIndex == 0) {
this.currentSectionIndex = this.getSectionSize() - 1;
} else {
this.currentSectionIndex--;
}
}
for (WheelSection section : this.sections) {
if (this.sections.indexOf(section) == this.currentSectionIndex) {
this.currentAngle = section.angle;
return true;
}
}
return true;
}
/**
* Check mouse pos.
*
* @param mouseX the mouse x
* @param mouseY the mouse y
*/
public void checkMousePos(double mouseX, double mouseY) {
if (this.closingAnimationStarted) return;
float centerX = this.centerPos.x;
float centerY = this.centerPos.y;
// 鼠标距离屏幕中心的位置向量
Vector2f cursorPos = new Vector2f((float) mouseX - centerX, (float) mouseY - centerY);
if (cursorPos.length() < IGNORE_CURSOR_MOVE_LENGTH) return;
Vector2f rotationStart = new Vector2f(0, 1);
cursorPos.normalize();
// 计算夹角弧度
double rot = Math.acos(rotationStart.dot(cursorPos) / (rotationStart.length() * cursorPos.length()));
double rotation = cursorPos.x < 0 ? Math.PI - rot : Math.PI + rot;
for (WheelSection section : this.sections) {
if (section.angleStart > section.angleEnd && rotation >= section.angleStart
|| rotation >= section.angleStart && rotation <= section.angleEnd
) {
this.currentAngle = section.angle;
this.currentSectionIndex = this.sections.indexOf(section);
break;
}
}
}
/**
* Should render boolean.
*
* @return the boolean
*/
public boolean shouldRender() {
if (this.animationStarted) return true;
return (this.displayTime + this.delay) <= System.currentTimeMillis();
}
@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) {
RenderSystem.enableDepthTest();
RenderSystem.enableBlend();
this.renderClosingAnimation(guiGraphics);
if (!this.shouldRender()) {
return;
}
if (this.closingAnimationStarted) return;
if (!this.animationStarted) {
this.animationStarted = true;
this.displayTime = System.currentTimeMillis();
}
PoseStack poseStack = guiGraphics.pose();
float delta = this.displayTime + this.animationMs - System.currentTimeMillis();
if (delta > 0) {
float progress = 1 - (delta / this.animationMs);
progress = (float) (-Math.pow(progress, 2) + 2 * progress);
if (progress == 0) return;
this.renderProgressAnimation(guiGraphics, progress);
return;
}
renderRing(
guiGraphics,
this.centerPos.x,
this.centerPos.y,
this.ringColor,
this.ringInnerRadius * 2,
this.ringOuterRadius * 2
);
this.renderSelection(guiGraphics);
for (WheelSection value : this.sections) {
float x = value.center.x;
float y = value.center.y;
poseStack.pushPose();
poseStack.translate(x - 10, y - 10, 100);
value.renderer.accept(guiGraphics, poseStack, 20, 20);
poseStack.popPose();
poseStack.pushPose();
float coordinateScale = 0.7f;
float offsetX = 0.1f * this.width;
float offsetY = 0.1f * this.height;
float adjustedX = (x - offsetX) / coordinateScale;
float adjustedY = (y - offsetY - 20 * this.textScale) / coordinateScale;
poseStack.translate(offsetX, offsetY, 0);
poseStack.scale(coordinateScale, coordinateScale, coordinateScale);
poseStack.translate(adjustedX, adjustedY, 0);
poseStack.scale(this.textScale / coordinateScale, this.textScale / coordinateScale, this.textScale / coordinateScale);
guiGraphics.drawCenteredString(
minecraft.font,
value.subTitle,
0,
0,
(0xff << 24) | this.textColor
);
poseStack.popPose();
}
RenderSystem.disableDepthTest();
RenderSystem.disableBlend();
}
/**
* Render closing animation.
*
* @param guiGraphics the gui graphics
*/
public void renderClosingAnimation(GuiGraphics guiGraphics) {
if (!this.closingAnimationStarted) return;
float delta = this.displayTime + this.closingAnimationMs - System.currentTimeMillis();
float progress = delta / this.closingAnimationMs;
if(progress >= 1 || progress <= 0) {
this.minecraft.setScreen(null);
}
this.renderProgressAnimation(guiGraphics, progress);
}
private void renderProgressAnimation(GuiGraphics guiGraphics, float progress) {
progress = (float) (-Math.pow(progress, 2) + 2 * progress);
if (progress == 0) return;
PoseStack poseStack = guiGraphics.pose();
poseStack.pushPose();
renderRing(
guiGraphics,
this.centerPos.x,
this.centerPos.y,
this.ringColor,
this.ringInnerRadius * 2 * progress,
this.ringOuterRadius * 2 * progress
);
poseStack.popPose();
if(this.currentSectionIndex != -1) {
WheelSection section = this.sections.get(this.currentSectionIndex);
Vector2f center = new Vector2f(
(section.center.x - this.centerPos.x) / this.getSectionCircleDiameter(),
(section.center.y - this.centerPos.y) / this.getSectionCircleDiameter()
).mul(this.getSectionCircleDiameter() * progress).add(this.centerPos.x, this.centerPos.y);
renderSelectionEffect(
guiGraphics,
center.x,
center.y,
this.selectionEffectColor,
this.selectionEffectRadius
);
}
for (WheelSection value : this.sections) {
if (sections.get(0) != value) continue;
Vector2f center = new Vector2f(
(value.center.x - this.centerPos.x) / this.getSectionCircleDiameter(),
(value.center.y - this.centerPos.y) / this.getSectionCircleDiameter()
).mul(this.getSectionCircleDiameter() * progress).add(this.centerPos.x, this.centerPos.y);
float x = center.x;
float y = center.y;
poseStack.pushPose();
poseStack.translate(x - 10, y - 10, 100);
value.renderer.accept(guiGraphics, poseStack, 20, 20);
poseStack.pushPose();
}
}
/**
* Render ring.
*
* @param guiGraphics the gui graphics
* @param centerX the center x
* @param centerY the center y
* @param color the color
* @param innerRadius the inner radius
* @param outerRadius the outer radius
*/
public static void renderRing(
GuiGraphics guiGraphics,
float centerX,
float centerY,
int color,
float innerRadius, // 改为半径
float outerRadius // 改为半径
) {
PoseStack poseStack = guiGraphics.pose();
poseStack.pushPose();
Tesselator tesselator = Tesselator.getInstance();
BufferBuilder buffer = tesselator.getBuilder();
// 计算足够大的绘制区域来覆盖整个环形基于外半径
float margin = outerRadius + 100f; // 使用半径计算边距
float x1 = centerX - margin;
float y1 = centerY - margin;
float x2 = centerX + margin;
float y2 = centerY + margin;
buffer.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();
setupRingShader(centerX, centerY, innerRadius, outerRadius);
BufferUploader.drawWithShader(buffer.end());
poseStack.popPose();
}
private static void setupRingShader(float centerX, float centerY, float innerRadius, float outerRadius) {
Window window = Minecraft.getInstance().getWindow();
float guiScale = (float) window.getGuiScale();
RenderSystem.setShader(Lib39Shaders::getRingShader);
// 转换到像素坐标考虑GUI缩放
float pixelCenterX = centerX * guiScale;
float pixelCenterY = window.getHeight() - (centerY * guiScale); // 翻转Y坐标
// 半径考虑GUI缩放
float pixelInnerRadius = innerRadius * guiScale;
float pixelOuterRadius = outerRadius * guiScale;
float pixelAntiAliasing = 2.0f * guiScale; // 抗锯齿范围
System.out.println("Shader Params - Center: (" + pixelCenterX + ", " + pixelCenterY +
"), InnerRadius: " + pixelInnerRadius + ", OuterRadius: " + pixelOuterRadius);
ShaderInstance shader = Lib39Shaders.getRingShader();
shader.safeGetUniform("Center").set(pixelCenterX, pixelCenterY);
shader.safeGetUniform("InnerRadius").set(pixelInnerRadius);
shader.safeGetUniform("OuterRadius").set(pixelOuterRadius);
shader.safeGetUniform("AntiAliasing").set(pixelAntiAliasing);
shader.safeGetUniform("ColorModulator").set(1.0f, 1.0f, 1.0f, .5f);
}
private void renderSelection(GuiGraphics guiGraphics) {
float selectionEffectAngle = MathUtil.angle(
MathUtil.copy(ROTATION_START),
this.selectionEffectPos
);
float diffAngle = this.currentAngle - selectionEffectAngle;
if (diffAngle > Math.PI) {
diffAngle -= (float) (Math.PI * 2);
} else if (diffAngle < -Math.PI) {
diffAngle += (float) (Math.PI * 2);
}
this.selectionEffectPos = MathUtil.rotate(
this.selectionEffectPos,
diffAngle / this.selectionAnimationSpeedFactor
);
Vector2f pos = MathUtil.copy(this.selectionEffectPos)
.mul(1, -1)
.add(this.centerPos);
// 调用时使用半径
renderSelectionEffect(
guiGraphics,
pos.x,
pos.y,
SELECTION_EFFECT_COLOR,
SELECTION_EFFECT_RADIUS // 确保这是半径值
);
}
/**
* Render selection effect.
*
* @param guiGraphics the gui graphics
* @param centerX the center x
* @param centerY the center y
* @param color the color
* @param radius the radius
*/
public static void renderSelectionEffect(
GuiGraphics guiGraphics,
float centerX,
float centerY,
int color,
float radius
) {
RenderSystem.enableBlend();
RenderSystem.defaultBlendFunc();
RenderSystem.disableDepthTest();
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);
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();
Window window = Minecraft.getInstance().getWindow();
float guiScale = (float) window.getGuiScale();
RenderSystem.setShader(Lib39Shaders::getSelectionShader);
System.out.println("Selection Effect Params:");
System.out.println(" Center: " + centerX + ", " + centerY);
System.out.println(" Radius: " + radius);
System.out.println(" GUI Scale: " + guiScale);
System.out.println(" Framebuffer: " + window.getWidth() + "x" + window.getHeight());
Lib39Shaders.getSelectionShader()
.safeGetUniform("Center")
.set(centerX * guiScale, centerY * guiScale);
Lib39Shaders.getSelectionShader()
.safeGetUniform("FramebufferSize")
.set((float) window.getWidth(), (float) window.getHeight());
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()));
RenderSystem.enableDepthTest();
}
/**
* On closing.
*/
public void onClosing() {
if (this.shouldRender() && !this.closingAnimationStarted) {
this.displayTime = System.currentTimeMillis();
this.closingAnimationStarted = true;
} else {
this.minecraft.setScreen(null);
}
}
@Override
protected void updateWidgetNarration(NarrationElementOutput narrationElementOutput) {
}
/**
* The type Wheel section.
*/
public record WheelSection(
Vector2f center,
float angle,
float angleStart,
float angleEnd,
Component subTitle,
FourConsumer<GuiGraphics, PoseStack, Integer, Integer> renderer
) {
}
}

View File

@ -0,0 +1,91 @@
package top.r3944realms.lib39.client.model;
import com.mojang.blaze3d.vertex.PoseStack;
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 top.r3944realms.lib39.Lib39;
/**
* The type Doll model.
*/
public class DollModel extends Model {
/**
* The constant LAYER_LOCATION.
*/
public static final ModelLayerLocation LAYER_LOCATION = new ModelLayerLocation(Lib39.rl("doll_model"), "main");
/**
* The Slim.
*/
public boolean slim = false;
private final ModelPart head;
private final ModelPart body;
private final ModelPart rightArm;
private final ModelPart leftArm;
private final ModelPart rightLeg;
private final ModelPart rightArmSlim;
private final ModelPart leftArmSlim;
private final ModelPart leftLeg;
/**
* Instantiates a new Doll model.
*
* @param root the root
*/
public DollModel(ModelPart root) {
super(RenderType::entityTranslucent);
this.head = root.getChild("head");
this.body = root.getChild("body");
this.rightArm = root.getChild("right_arm");
this.leftArm = root.getChild("left_arm");
this.rightArmSlim = root.getChild("right_arm_slim");
this.leftArmSlim = root.getChild("left_arm_slim");
this.rightLeg = root.getChild("right_leg");
this.leftLeg = root.getChild("left_leg");
}
/**
* Create body layer layer definition.
*
* @return the layer definition
*/
public static LayerDefinition createBodyLayer() {
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));
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) {
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);
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);
} else {
this.rightArm.render(poseStack, vertexConsumer, packedLight, packedOverlay, red, green, blue, alpha);
this.leftArm.render(poseStack, vertexConsumer, packedLight, packedOverlay, red, green, blue, alpha);
}
this.rightLeg.render(poseStack, vertexConsumer, packedLight, packedOverlay, red, green, blue, alpha);
this.leftLeg.render(poseStack, vertexConsumer, packedLight, packedOverlay, red, green, blue, alpha);
poseStack.popPose();
}
}

View File

@ -0,0 +1,381 @@
package top.r3944realms.lib39.client.renderer;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.*;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.network.chat.Component;
import net.minecraft.util.Mth;
import net.minecraft.world.item.ItemStack;
import org.joml.Matrix4f;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
/**
* 圆形径向菜单渲染器
* 用于创建美观的圆形选择菜单
*
* @param <T> the type parameter
*/
public class RadialMenuRenderer<T> {
/**
* The constant DEFAULT_INNER_RADIUS.
*/
// 默认配置常量
public static final float DEFAULT_INNER_RADIUS = 30f;
/**
* The constant DEFAULT_OUTER_RADIUS.
*/
public static final float DEFAULT_OUTER_RADIUS = 80f;
/**
* The constant DEFAULT_MIDDLE_RADIUS.
*/
public static final float DEFAULT_MIDDLE_RADIUS = 55f;
/**
* The constant DEFAULT_SEGMENTS.
*/
public static final int DEFAULT_SEGMENTS = 64;
// 配置选项
private final float innerRadius;
private final float outerRadius;
private final float middleRadius;
private final int segments;
private final boolean enableHoverAnimation;
private final ColorScheme colorScheme;
// 状态
private int hoveredIndex = -1;
private final float[] hoverAnimations;
private long lastAnimationTime = 0;
/**
* The type Color scheme.
*/
public static class ColorScheme {
/**
* The Normal color.
*/
public final float[] normalColor;
/**
* The Hovered color.
*/
public final float[] hoveredColor;
/**
* The Selected color.
*/
public final float[] selectedColor;
/**
* The Background color.
*/
public final float[] backgroundColor;
/**
* Instantiates a new Color scheme.
*
* @param normalColor the normal color
* @param hoveredColor the hovered color
* @param selectedColor the selected color
* @param backgroundColor the background color
*/
public ColorScheme(float[] normalColor, float[] hoveredColor, float[] selectedColor, float[] backgroundColor) {
this.normalColor = normalColor;
this.hoveredColor = hoveredColor;
this.selectedColor = selectedColor;
this.backgroundColor = backgroundColor;
}
/**
* The constant DEFAULT.
*/
// 预定义颜色方案
public static final ColorScheme DEFAULT = new ColorScheme(
new float[]{0.3f, 0.3f, 0.8f, 0.6f}, // 正常 - 蓝色
new float[]{0.9f, 0.7f, 0.1f, 0.8f}, // 悬停 - 金色
new float[]{0.2f, 0.8f, 0.2f, 0.9f}, // 选中 - 绿色
new float[]{0.1f, 0.1f, 0.1f, 0.7f} // 背景
);
/**
* The constant FIRE.
*/
public static final ColorScheme FIRE = new ColorScheme(
new float[]{0.8f, 0.3f, 0.1f, 0.6f}, // 正常 - 红色
new float[]{1.0f, 0.5f, 0.0f, 0.8f}, // 悬停 - 橙色
new float[]{1.0f, 0.9f, 0.0f, 0.9f}, // 选中 - 黄色
new float[]{0.2f, 0.1f, 0.0f, 0.7f} // 背景
);
/**
* The constant NATURE.
*/
public static final ColorScheme NATURE = new ColorScheme(
new float[]{0.2f, 0.6f, 0.3f, 0.6f}, // 正常 - 绿色
new float[]{0.4f, 0.8f, 0.4f, 0.8f}, // 悬停 - 亮绿
new float[]{0.1f, 0.9f, 0.7f, 0.9f}, // 选中 - 青绿
new float[]{0.1f, 0.2f, 0.1f, 0.7f} // 背景
);
}
/**
* Instantiates a new Radial menu renderer.
*/
public RadialMenuRenderer() {
this(DEFAULT_INNER_RADIUS, DEFAULT_OUTER_RADIUS, ColorScheme.DEFAULT);
}
/**
* Instantiates a new Radial menu renderer.
*
* @param innerRadius the inner radius
* @param outerRadius the outer radius
*/
public RadialMenuRenderer(float innerRadius, float outerRadius) {
this(innerRadius, outerRadius, ColorScheme.DEFAULT);
}
/**
* Instantiates a new Radial menu renderer.
*
* @param innerRadius the inner radius
* @param outerRadius the outer radius
* @param colorScheme the color scheme
*/
public RadialMenuRenderer(float innerRadius, float outerRadius, ColorScheme colorScheme) {
this(innerRadius, outerRadius, (innerRadius + outerRadius) / 2f, DEFAULT_SEGMENTS, true, colorScheme);
}
/**
* Instantiates a new Radial menu renderer.
*
* @param innerRadius the inner radius
* @param outerRadius the outer radius
* @param middleRadius the middle radius
* @param segments the segments
* @param enableHoverAnimation the enable hover animation
* @param colorScheme the color scheme
*/
public RadialMenuRenderer(float innerRadius, float outerRadius, float middleRadius,
int segments, boolean enableHoverAnimation, ColorScheme colorScheme) {
this.innerRadius = innerRadius;
this.outerRadius = outerRadius;
this.middleRadius = middleRadius;
this.segments = segments;
this.enableHoverAnimation = enableHoverAnimation;
this.colorScheme = colorScheme;
this.hoverAnimations = new float[0];
}
/**
* 渲染圆形菜单
*
* @param guiGraphics the gui graphics
* @param entries the entries
* @param titleProvider the title provider
* @param iconProvider the icon provider
* @param selectedIndex the selected index
* @param trackMouse the track mouse
*/
public void render(GuiGraphics guiGraphics, List<T> entries,
Function<T, Component> titleProvider,
Function<T, ItemStack> iconProvider,
int selectedIndex, boolean trackMouse) {
if (entries.isEmpty()) return;
// 更新动画状态
updateHoverAnimations(entries.size());
// 设置渲染状态
RenderSystem.enableBlend();
RenderSystem.defaultBlendFunc();
RenderSystem.setShader(GameRenderer::getPositionColorShader);
float centerX = guiGraphics.guiWidth() / 2f;
float centerY = guiGraphics.guiHeight() / 2f;
guiGraphics.pose().pushPose();
guiGraphics.pose().translate(centerX, centerY, 0f);
// 渲染所有扇形区域
renderSectors(guiGraphics, entries, selectedIndex);
// 渲染图标和文本
renderIconsAndText(guiGraphics, entries, titleProvider, iconProvider);
guiGraphics.pose().popPose();
RenderSystem.disableBlend();
}
/**
* 渲染扇形区域
*/
private void renderSectors(GuiGraphics guiGraphics, List<T> entries, int selectedIndex) {
int count = entries.size();
float angleSize = 360f / count;
for (int i = 0; i < count; i++) {
float startAngle = -90f + i * angleSize;
float currentOuterRadius = outerRadius;
// 悬停动画效果
if (enableHoverAnimation && i < hoverAnimations.length) {
currentOuterRadius += hoverAnimations[i] * 5f;
}
// 颜色设置
float[] color = getSectorColor(i, selectedIndex, entries.get(i));
// 绘制扇形
drawSector(guiGraphics, startAngle, angleSize, innerRadius, currentOuterRadius, color);
}
}
/**
* 获取扇形颜色
*/
private float[] getSectorColor(int index, int selectedIndex, T entry) {
if (index == selectedIndex) {
return colorScheme.selectedColor; // 选中状态
} else if (index == hoveredIndex) {
return colorScheme.hoveredColor; // 悬停状态
} else {
return colorScheme.normalColor; // 普通状态
}
}
/**
* 绘制单个扇形
*/
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);
Matrix4f matrix = guiGraphics.pose().last().pose();
float segments = Math.max(8, this.segments * (angleSize / 360f));
for (int i = 0; i <= segments; i++) {
float progress = i / segments;
float angle = startAngle + progress * angleSize;
float rad = angle * Mth.DEG_TO_RAD;
float cos = Mth.cos(rad);
float sin = Mth.sin(rad);
// 外圈顶点
buffer.vertex(matrix, outerRadius * cos, outerRadius * sin, 0)
.color(color[0], color[1], color[2], color[3]).endVertex();
// 内圈顶点
buffer.vertex(matrix, innerRadius * cos, innerRadius * sin, 0)
.color(color[0], color[1], color[2], color[3] * 0.6f).endVertex();
}
BufferUploader.drawWithShader(buffer.end());
}
/**
* 渲染图标和文本
*/
private void renderIconsAndText(GuiGraphics guiGraphics, List<T> entries,
Function<T, Component> titleProvider,
Function<T, ItemStack> iconProvider) {
int count = entries.size();
var font = Minecraft.getInstance().font;
for (int i = 0; i < count; i++) {
T entry = entries.get(i);
float angle = (-90f + 360f * (i + 0.5f) / count) * Mth.DEG_TO_RAD;
// 计算位置
float x = Mth.cos(angle) * middleRadius;
float y = Mth.sin(angle) * middleRadius;
// 渲染图标
ItemStack icon = iconProvider.apply(entry);
if (!icon.isEmpty()) {
guiGraphics.renderItem(icon, (int)(x - 8), (int)(y - 8));
}
// 渲染文本
Component title = titleProvider.apply(entry);
guiGraphics.pose().pushPose();
guiGraphics.pose().translate(x, y + 12, 0);
guiGraphics.pose().scale(0.7f, 0.7f, 0.7f);
guiGraphics.drawString(font, title, -font.width(title) / 2, 0, 0xFFFFFF, true);
guiGraphics.pose().popPose();
}
}
/**
* 更新悬停动画
*/
private void updateHoverAnimations(int entryCount) {
if (!enableHoverAnimation) return;
long currentTime = System.currentTimeMillis();
float deltaTime = Math.min((currentTime - lastAnimationTime) / 1000f, 0.1f);
lastAnimationTime = currentTime;
// 确保数组大小正确
if (hoverAnimations.length != entryCount) {
// 这里需要重新初始化数组实际使用时应该处理数组大小变化
}
// 更新动画值
for (int i = 0; i < hoverAnimations.length && i < entryCount; i++) {
if (i == hoveredIndex) {
hoverAnimations[i] = Mth.clamp(hoverAnimations[i] + deltaTime * 2f, 0f, 1f);
} else {
hoverAnimations[i] = Mth.clamp(hoverAnimations[i] - deltaTime * 3f, 0f, 1f);
}
}
}
/**
* 获取鼠标下的条目索引
*
* @param entries the entries
* @param mouseX the mouse x
* @param mouseY the mouse y
* @return the hovered entry
*/
public int getHoveredEntry(List<T> entries, double mouseX, double mouseY) {
float centerX = Minecraft.getInstance().getWindow().getGuiScaledWidth() / 2f;
float centerY = Minecraft.getInstance().getWindow().getGuiScaledHeight() / 2f;
double relX = mouseX - centerX;
double relY = mouseY - centerY;
double distance = Math.sqrt(relX * relX + relY * relY);
// 检查是否在有效范围内
if (distance < innerRadius || distance > outerRadius) {
hoveredIndex = -1;
return -1;
}
// 计算角度
double angle = Math.atan2(relY, relX) * Mth.RAD_TO_DEG;
angle = (angle + 450) % 360; // 标准化到 0-360
int count = entries.size();
int index = (int) (angle / (360f / count)) % count;
hoveredIndex = index;
return index;
}
/**
* 清除状态
*/
public void clearState() {
hoveredIndex = -1;
// 重置动画数组
Arrays.fill(hoverAnimations, 0f);
}
}

View File

@ -0,0 +1,55 @@
package top.r3944realms.lib39.client.renderer.block;
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.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.core.Direction;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.state.BlockState;
import org.jetbrains.annotations.NotNull;
import top.r3944realms.lib39.client.model.DollModel;
import top.r3944realms.lib39.client.renderer.item.DollItemRenderer;
import top.r3944realms.lib39.content.block.DollBlock;
import top.r3944realms.lib39.content.block.blockentity.DollBlockEntity;
import top.r3944realms.lib39.util.lang.Pair;
/**
* The type Doll block entity renderer.
*/
public class DollBlockEntityRenderer implements BlockEntityRenderer<DollBlockEntity> {
private final DollModel dollModel;
/**
* Instantiates a new Doll block entity renderer.
*
* @param context the context
*/
public DollBlockEntityRenderer(BlockEntityRendererProvider.@NotNull Context context) {
this.dollModel = new DollModel(context.bakeLayer(DollModel.LAYER_LOCATION));
}
@Override
public void render(@NotNull DollBlockEntity dollBlockEntity, float partialTick, @NotNull PoseStack poseStack, @NotNull MultiBufferSource buffer, int packedLight, int packedOverlay) {
BlockState blockState = dollBlockEntity.getBlockState();
if (blockState.getBlock() instanceof DollBlock) {
Direction facing = blockState.getValue(DollBlock.FACING);
GameProfile profile = dollBlockEntity.getOwnerProfile();
Pair<ResourceLocation, Boolean> resourceLocationBooleanPair = DollItemRenderer.loadSkin(profile);
poseStack.pushPose();
poseStack.translate(0.5, 1.5, 0.5);
poseStack.scale(1.0F, -1.0F, -1.0F);
float rotation = facing.toYRot();
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);
poseStack.popPose();
}
}
}

View File

@ -0,0 +1,98 @@
package top.r3944realms.lib39.client.renderer.item;
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.BlockEntityWithoutLevelRenderer;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.resources.DefaultPlayerSkin;
import net.minecraft.client.resources.SkinManager;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.item.ItemStack;
import org.jetbrains.annotations.NotNull;
import top.r3944realms.lib39.client.model.DollModel;
import top.r3944realms.lib39.content.item.DollItem;
import top.r3944realms.lib39.util.GameProfileHelper;
import top.r3944realms.lib39.util.lang.Pair;
/**
* The type Doll item renderer.
*/
public class DollItemRenderer extends BlockEntityWithoutLevelRenderer {
private static DollItemRenderer instance;
private final DollModel dollModel;
private DollItemRenderer() {
super(
Minecraft.getInstance().getBlockEntityRenderDispatcher(),
Minecraft.getInstance().getEntityModels()
);
this.dollModel = new DollModel(
Minecraft.getInstance().getEntityModels().bakeLayer(DollModel.LAYER_LOCATION)
);
}
/**
* Gets instance.
*
* @return the instance
*/
public static DollItemRenderer getInstance() {
if (instance == null) {
instance = new DollItemRenderer();
}
return instance;
}
@Override
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;
}
GameProfile profile = GameProfileHelper.getProfileFromItemStack(stack);
Pair<ResourceLocation, Boolean> resourceLocationBooleanPair = loadSkin(profile);
ResourceLocation playerSkin = resourceLocationBooleanPair.first;
boolean isSlim = resourceLocationBooleanPair.second;
poseStack.pushPose();
VertexConsumer vertexConsumer = buffer.getBuffer(
RenderType.entityTranslucent(playerSkin)
);
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
);
poseStack.popPose();
}
/**
* Load skin pair.
*
* @param profile the profile
* @return the pair
*/
public static @NotNull Pair<ResourceLocation,Boolean> loadSkin(GameProfile 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;
}
return Pair.of(playerSkin, isSlim);
}
}

View File

@ -0,0 +1,68 @@
package top.r3944realms.lib39.client.shader;
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import net.minecraft.client.renderer.ShaderInstance;
import net.minecraft.server.packs.resources.ResourceProvider;
import top.r3944realms.lib39.Lib39;
import java.io.IOException;
import java.util.function.Consumer;
import java.util.function.Supplier;
/**
* The type Lib 39 shaders.
*/
public class Lib39Shaders {
/**
* Gets ring shader.
*
* @return the ring shader
*/
public static ShaderInstance getRingShader() {
return ringShader;
}
/**
* The Ring shader.
*/
static ShaderInstance ringShader;
/**
* Gets selection shader.
*
* @return the selection shader
*/
public static ShaderInstance getSelectionShader() {
return selectionShader;
}
/**
* The Selection shader.
*/
static ShaderInstance selectionShader;
/**
* 在资源重载时注册/重新加载着色器
*/
public static void registerShaders(ResourceProvider resourceProvider) {
try {
// 注册ring着色器
ringShader = new ShaderInstance(
resourceProvider,
"ring",
DefaultVertexFormat.POSITION_COLOR
);
// 注册selection着色器
selectionShader = new ShaderInstance(
resourceProvider,
"selection",
DefaultVertexFormat.POSITION_COLOR
);
} catch (IOException e) {
// 着色器加载失败时的处理
Lib39.LOGGER.error("Failed to load lib39 shaders", e);
}
}
}

View File

@ -2,14 +2,14 @@ package top.r3944realms.lib39.content.item;
import com.mojang.authlib.GameProfile;
import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.Equipable;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TooltipFlag;
import net.minecraft.world.level.Level;
import net.minecraftforge.client.extensions.common.IClientItemExtensions;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import top.r3944realms.lib39.client.renderer.item.DollItemRenderer;
import top.r3944realms.lib39.core.register.Lib39Blocks;
import top.r3944realms.lib39.util.GameProfileHelper;
@ -18,7 +18,7 @@ import java.util.List;
/**
* The type Doll item.
*/
public class DollItem extends BlockItem {
public class DollItem extends BlockItem implements Equipable {
/**
* Instantiates a new Doll item.
*
@ -37,4 +37,9 @@ public class DollItem extends BlockItem {
}
tooltip.add(Component.translatable("tooltip.lib39.content.doll.hover.2"));
}
@Override
public @NotNull EquipmentSlot getEquipmentSlot() {
return EquipmentSlot.HEAD;
}
}

View File

@ -0,0 +1,92 @@
package top.r3944realms.lib39.mixin.minecraft;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.CreativeModeTabs;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import java.util.Comparator;
@Mixin(CreativeModeTabs.class)
public interface CreativeModeTabsAccessor {
@Accessor("BUILDING_BLOCKS")
static ResourceKey<CreativeModeTab> getBuildingBlocks() {
throw new AssertionError();
}
@Accessor("COLORED_BLOCKS")
static ResourceKey<CreativeModeTab> getColoredBlocks() {
throw new AssertionError();
}
@Accessor("NATURAL_BLOCKS")
static ResourceKey<CreativeModeTab> getNaturalBlocks() {
throw new AssertionError();
}
@Accessor("FUNCTIONAL_BLOCKS")
static ResourceKey<CreativeModeTab> getFunctionalBlocks() {
throw new AssertionError();
}
@Accessor("REDSTONE_BLOCKS")
static ResourceKey<CreativeModeTab> getRedstoneBlocks() {
throw new AssertionError();
}
@Accessor("HOTBAR")
static ResourceKey<CreativeModeTab> getHotbar() {
throw new AssertionError();
}
@Accessor("SEARCH")
static ResourceKey<CreativeModeTab> getSearch() {
throw new AssertionError();
}
@Accessor("TOOLS_AND_UTILITIES")
static ResourceKey<CreativeModeTab> getToolsAndUtilities() {
throw new AssertionError();
}
@Accessor("COMBAT")
static ResourceKey<CreativeModeTab> getCombat() {
throw new AssertionError();
}
@Accessor("FOOD_AND_DRINKS")
static ResourceKey<CreativeModeTab> getFoodAndDrinks() {
throw new AssertionError();
}
@Accessor("INGREDIENTS")
static ResourceKey<CreativeModeTab> getIngredients() {
throw new AssertionError();
}
@Accessor("SPAWN_EGGS")
static ResourceKey<CreativeModeTab> getSpawnEggs() {
throw new AssertionError();
}
@Accessor("OP_BLOCKS")
static ResourceKey<CreativeModeTab> getOpBlocks() {
throw new AssertionError();
}
@Accessor("INVENTORY")
static ResourceKey<CreativeModeTab> getInventory() {
throw new AssertionError();
}
@Accessor("CACHED_PARAMETERS")
static CreativeModeTab.ItemDisplayParameters getCachedParameters() {
throw new AssertionError();
}
@Accessor("PAINTING_COMPARATOR")
static Comparator<net.minecraft.world.item.CreativeModeTab> getPaintingComparator() {
throw new AssertionError();
}
}

View File

@ -45,4 +45,6 @@ public interface IPlatformHelper {
* @return the mod version
*/
String getModVersion();
IUtilHelper getUtilHelper();
}

View File

@ -0,0 +1,7 @@
package top.r3944realms.lib39.platform.services;
import top.r3944realms.lib39.util.block.BlockRegistryBuilder;
public interface IUtilHelper {
BlockRegistryBuilder getBlockRegistryBuilder();
}

View File

@ -3,11 +3,11 @@ package top.r3944realms.lib39.util.block;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.CreativeModeTabs;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import top.r3944realms.lib39.mixin.minecraft.CreativeModeTabsAccessor;
import top.r3944realms.lib39.platform.Services;
import java.util.function.BiFunction;
import java.util.function.Supplier;
@ -23,16 +23,9 @@ public abstract class BlockRegistryBuilder {
private boolean needBuildItem;
private Item.Properties properties;
/**
* 创建新的构建器实例
*
* @return the block registry builder
*/
@Contract(value = " -> new", pure = true)
public static @NotNull BlockRegistryBuilder create() {
return new BlockRegistryBuilder();
public static BlockRegistryBuilder create() {
return Services.PLATFORM.getUtilHelper().getBlockRegistryBuilder();
}
/**
* 设置注册名称
*
@ -96,10 +89,7 @@ public abstract class BlockRegistryBuilder {
/**
* 内部方法注册对应的方块物品
*/
@SafeVarargs
private void registerBlockItem(Supplier<Block> blockObject, ResourceKey<CreativeModeTab>... creativeTabs) {
}
protected abstract void registerBlockItem(Supplier<Block> blockObject, ResourceKey<CreativeModeTab>... creativeTabs);
/**
* 注册方块和物品到建筑标签页
@ -110,7 +100,7 @@ public abstract class BlockRegistryBuilder {
*/
public BlockRegistryBuilder registerWithBuildingTab(BiFunction<String, Supplier<Block>,Supplier<Block>> blockRegister, Supplier<Block> blockSupplier) {
registerBlock(blockRegister, blockSupplier);
registerBlockItem(this.blockObject, CreativeModeTabs.BUILDING_BLOCKS);
registerBlockItem(this.blockObject, CreativeModeTabsAccessor.getBuildingBlocks());
return this;
}
@ -123,7 +113,7 @@ public abstract class BlockRegistryBuilder {
*/
public BlockRegistryBuilder registerWithFunctionalTab(BiFunction<String, Supplier<Block>,Supplier<Block>> blockRegister, Supplier<Block> blockSupplier) {
registerBlock(blockRegister, blockSupplier);
registerBlockItem(this.blockObject, CreativeModeTabs.FUNCTIONAL_BLOCKS);
registerBlockItem(this.blockObject, CreativeModeTabsAccessor.getFunctionalBlocks());
return this;
}

View File

@ -0,0 +1,16 @@
public net.minecraft.world.item.CreativeModeTabs f_268496_ # CACHED_PARAMETERS
public net.minecraft.world.item.CreativeModeTabs f_268478_ # PAINTING_COMPARATOR
public net.minecraft.world.item.CreativeModeTabs f_257039_ # INVENTORY
public net.minecraft.world.item.CreativeModeTabs f_257028_ # REDSTONE_BLOCKS
public net.minecraft.world.item.CreativeModeTabs f_256968_ # INGREDIENTS
public net.minecraft.world.item.CreativeModeTabs f_256917_ # HOTBAR
public net.minecraft.world.item.CreativeModeTabs f_256869_ # TOOLS_AND_UTILITIES
public net.minecraft.world.item.CreativeModeTabs f_256839_ # FOOD_AND_DRINKS
public net.minecraft.world.item.CreativeModeTabs f_256837_ # OP_BLOCKS
public net.minecraft.world.item.CreativeModeTabs f_256797_ # COMBAT
public net.minecraft.world.item.CreativeModeTabs f_256791_ # FUNCTIONAL_BLOCKS
public net.minecraft.world.item.CreativeModeTabs f_256788_ # BUILDING_BLOCKS
public net.minecraft.world.item.CreativeModeTabs f_256776_ # NATURAL_BLOCKS
public net.minecraft.world.item.CreativeModeTabs f_256750_ # SEARCH
public net.minecraft.world.item.CreativeModeTabs f_256731_ # SPAWN_EGGS
public net.minecraft.world.item.CreativeModeTabs f_256725_ # COLORED_BLOCKS

View File

@ -0,0 +1,2 @@
accessWidener v2 named
# 不要用这个太垃圾了不支持parchment名

View File

@ -1,18 +1,19 @@
{
"required": true,
"minVersion": "0.8",
"package": "top.r3944realms.lib39.mixin",
"refmap": "${mod_id}.refmap.json",
"compatibilityLevel": "JAVA_17",
"mixins": [
"carryon.MixinCarriedObjectRender"
],
"client": [
],
"server": [
],
"injectors": {
"defaultRequire": 1
}
"required": true,
"minVersion": "0.8",
"package": "top.r3944realms.lib39.mixin",
"refmap": "${mod_id}.refmap.json",
"compatibilityLevel": "JAVA_17",
"mixins": [
"carryon.MixinCarriedObjectRender",
"minecraft.CreativeModeTabsAccessor"
],
"client": [
],
"server": [
],
"injectors": {
"defaultRequire": 1
}
}

View File

@ -1,18 +1,21 @@
package top.r3944realms.lib39;
import net.fabricmc.api.ModInitializer;
import top.r3944realms.lib39.core.CreativeTabAdder;
import top.r3944realms.lib39.core.register.*;
public class Lib39Fabric implements ModInitializer {
@Override
public void onInitialize() {
Lib39.initialize();
// This method is invoked by the Fabric mod loader when it is ready
// to load your mod. You can access Fabric and Common code in this
// project.
// Use Fabric to bootstrap the Common mod.
Lib39.LOGGER.info("Hello Fabric world!");
Lib39.LOGGER.info("[Lib39-Fabric] Hello Fabric!");
FabricLib39Blocks.init();
FabricLib39Items.init();
FabricLib39BlockEntities.init();
FabricLib39SoundEvents.init();
CreativeTabAdder.init();
Lib39.LOGGER.info("[Lib39-Fabric] Finished Initializing.");
}
}

View File

@ -0,0 +1,36 @@
package top.r3944realms.lib39;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.rendering.v1.BuiltinItemRendererRegistry;
import net.fabricmc.fabric.api.resource.ResourceManagerHelper;
import net.fabricmc.fabric.api.resource.SimpleSynchronousResourceReloadListener;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.PackType;
import net.minecraft.server.packs.resources.ResourceManager;
import org.jetbrains.annotations.NotNull;
import top.r3944realms.lib39.client.renderer.item.DollItemRenderer;
import top.r3944realms.lib39.client.shader.Lib39Shaders;
import top.r3944realms.lib39.core.register.Lib39Items;
public class Lib39FabricClient implements ClientModInitializer {
@Override
public void onInitializeClient() {
ResourceManagerHelper.get(PackType.CLIENT_RESOURCES).registerReloadListener(new SimpleSynchronousResourceReloadListener() {
@Override
public void onResourceManagerReload(@NotNull ResourceManager resourceManager) {
Lib39Shaders.registerShaders(resourceManager);
}
@Override
public ResourceLocation getFabricId() {
return Lib39.rl("shaders");
}
});
BuiltinItemRendererRegistry.INSTANCE.register(
Lib39Items.DOLL.get(),
DollItemRenderer.getInstance()::renderByItem
);
}
}

View File

@ -0,0 +1,38 @@
package top.r3944realms.lib39.api.callback;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.server.Services;
import java.util.concurrent.Executor;
/**
* The interface Minecraft set up service callback.
*/
@FunctionalInterface
public interface MinecraftSetUpServiceCallback {
/**
* The constant EVENT.
*/
Event<MinecraftSetUpServiceCallback> EVENT =
EventFactory.createArrayBacked(
MinecraftSetUpServiceCallback.class,
(listeners) -> ((services, mainThreadExecutor) -> {
for (MinecraftSetUpServiceCallback listener : listeners) {
if (listener.load(services, mainThreadExecutor)) {
return true;
}
}
return true;
})
);
/**
* Load boolean.
*
* @param services the services
* @param mainThreadExecutor the main thread executor
* @return 是否取消事件 boolean
*/
boolean load(Services services, Executor mainThreadExecutor);
}

View File

@ -0,0 +1,48 @@
package top.r3944realms.lib39.core;
import net.fabricmc.fabric.api.itemgroup.v1.ItemGroupEvents;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.level.block.Block;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
public class CreativeTabAdder {
private static final Map<Supplier<Block>, ResourceKey<CreativeModeTab>[]> itemAddMap = new ConcurrentHashMap<>();
private static final Map<ResourceKey<CreativeModeTab>, List<Supplier<Block>>> tabToItemsMap = new ConcurrentHashMap<>();
/**
* Add item to tabs.
*
* @param item the item
* @param tabs the tabs
*/
@SafeVarargs
public static void addItemToTabs(Supplier<Block> item, ResourceKey<CreativeModeTab>... tabs) {
itemAddMap.put(item, tabs);
// 更新反向映射
for (ResourceKey<CreativeModeTab> tab : tabs) {
tabToItemsMap.computeIfAbsent(tab, k -> new ArrayList<>()).add(item);
}
}
public static void init() {
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())));
}
}
/**
* Gets item add map.
*
* @return the item add map
*/
public static Map<Supplier<Block>, ResourceKey<CreativeModeTab>[]> getItemAddMap() {
return itemAddMap;
}
}

View File

@ -1,6 +1,12 @@
package top.r3944realms.lib39.core.register;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries;
import net.minecraft.world.level.block.entity.BlockEntityType;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import top.r3944realms.lib39.Lib39;
import top.r3944realms.lib39.content.block.blockentity.DollBlockEntity;
import java.util.function.Supplier;
@ -9,9 +15,15 @@ import java.util.function.Supplier;
* The type Lib 39 block entities.
*/
public class FabricLib39BlockEntities {
/**
* The constant DOLL_BLOCK_ENTITY.
*/
public static Supplier<BlockEntityType<DollBlockEntity>> DOLL_BLOCK_ENTITY;
@SuppressWarnings("DataFlowIssue")
public static void init() {
Lib39BlockEntities.DOLL_BLOCK_ENTITY = register("doll", BlockEntityType.Builder
.of(DollBlockEntity::new, Lib39Blocks.DOLL.get())
.build(null)
);
}
@Contract(pure = true)
public static <T extends BlockEntityType<?>> @NotNull Supplier<T> register(String path, T blockEntityType) {
return () -> Registry.register(BuiltInRegistries.BLOCK_ENTITY_TYPE, Lib39.rl(path), blockEntityType);
}
}

View File

@ -1,6 +1,14 @@
package top.r3944realms.lib39.core.register;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntityType;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import top.r3944realms.lib39.Lib39;
import top.r3944realms.lib39.content.block.DollBlock;
import top.r3944realms.lib39.util.block.BlockRegistryBuilder;
import java.util.function.Supplier;
@ -8,10 +16,16 @@ import java.util.function.Supplier;
* The type Lib 39 blocks.
*/
public class FabricLib39Blocks {
/**
* The constant DOLL.
*/
public static Supplier<Block> DOLL;
public static void init() {
Lib39Blocks.DOLL = BlockRegistryBuilder
.create()
.withName("doll")
.registerBlock((name , block) -> register(name, block.get()), DollBlock::new)
.build();
}
@Contract(pure = true)
public static <T extends Block> @NotNull Supplier<T> register(String path, T block) {
return () -> Registry.register(BuiltInRegistries.BLOCK, Lib39.rl(path), block);
}
}

View File

@ -1,6 +1,13 @@
package top.r3944realms.lib39.core.register;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.entity.BlockEntityType;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import top.r3944realms.lib39.Lib39;
import top.r3944realms.lib39.content.item.DollItem;
import java.util.function.Supplier;
@ -8,8 +15,11 @@ import java.util.function.Supplier;
* The type Ex lib 39 items.
*/
public class FabricLib39Items {
/**
* The constant DOLL.
*/
public static Supplier<Item> DOLL;
public static void init() {
Lib39Items.DOLL = register("doll", new DollItem(new Item.Properties()));
}
@Contract(pure = true)
public static <T extends Item> @NotNull Supplier<T> register(String path, T item) {
return () -> Registry.register(BuiltInRegistries.ITEM, Lib39.rl(path), item);
}
}

View File

@ -1,7 +1,12 @@
package top.r3944realms.lib39.core.register;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundEvents;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import top.r3944realms.lib39.Lib39;
import java.util.function.Supplier;
@ -10,22 +15,11 @@ import java.util.function.Supplier;
* The type Lib 39 sound events.
*/
public class FabricLib39SoundEvents {
/**
* The constant RL_DUCK_TOY.
*/
public static final ResourceLocation RL_DUCK_TOY = Lib39.rl("duck_toy");
/**
* The constant DUCK_TOY.
*/
public static Supplier<SoundEvent> DUCK_TOY;
/**
* Gets sub title translate key.
*
* @param name the name
* @return the sub title translate key
*/
public static String getSubTitleTranslateKey(String name) {
return "sound." + Lib39.MOD_ID + ".subtitle." + name;
public static void init() {
Lib39SoundEvents.DUCK_TOY = register("duck_toy", SoundEvent.createFixedRangeEvent(Lib39SoundEvents.RL_DUCK_TOY, 32.0f));
}
@Contract(pure = true)
public static <T extends SoundEvent> @NotNull Supplier<T> register(String path, T soundEvent) {
return () -> Registry.register(BuiltInRegistries.SOUND_EVENT, Lib39.rl(path), soundEvent);
}
}

View File

@ -0,0 +1,52 @@
package top.r3944realms.lib39.mixin.init;
import com.mojang.datafixers.DataFixer;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.ServerInterface;
import net.minecraft.server.Services;
import net.minecraft.server.WorldStem;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.server.level.progress.ChunkProgressListenerFactory;
import net.minecraft.server.packs.repository.PackRepository;
import net.minecraft.world.level.storage.LevelStorageSource;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import top.r3944realms.lib39.api.callback.MinecraftSetUpServiceCallback;
import java.net.Proxy;
/**
* The type Mixin dedicate server.
*/
@Mixin(DedicatedServer.class)
public abstract class MixinDedicateServer extends MinecraftServer implements ServerInterface {
/**
* Instantiates a new Mixin dedicate server.
*
* @param serverThread the server thread
* @param storageSource the storage source
* @param packRepository the pack repository
* @param worldStem the world stem
* @param proxy the proxy
* @param fixerUpper the fixer upper
* @param services the services
* @param progressListenerFactory the progress listener factory
*/
public MixinDedicateServer(Thread serverThread, LevelStorageSource.LevelStorageAccess storageSource, PackRepository packRepository, WorldStem worldStem, Proxy proxy, DataFixer fixerUpper, Services services, ChunkProgressListenerFactory progressListenerFactory) {
super(serverThread, storageSource, packRepository, worldStem, proxy, fixerUpper, services, progressListenerFactory);
}
@Inject(
method = "initServer",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/server/players/GameProfileCache;setUsesAuthentication(Z)V",
shift = At.Shift.AFTER
)
)
private void initServer$setup(CallbackInfoReturnable<Boolean> cir) {
MinecraftSetUpServiceCallback.EVENT.invoker().load(this.services,this);
}
}

View File

@ -0,0 +1,76 @@
package top.r3944realms.lib39.mixin.init;
import com.llamalad7.mixinextras.sugar.Local;
import com.mojang.blaze3d.platform.WindowEventHandler;
import net.minecraft.client.Minecraft;
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.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import top.r3944realms.lib39.api.callback.MinecraftSetUpServiceCallback;
/**
* The type Mixin minecraft.
*/
@Mixin(Minecraft.class)
public abstract class MixinMinecraft extends ReentrantBlockableEventLoop<Runnable> implements WindowEventHandler {
/**
* Instantiates a new Mixin minecraft.
*
* @param name the name
*/
public MixinMinecraft(String name) {
super(name);
}
/**
* Set level setup.
*
* @param levelClient the level client
* @param ci the ci
* @param services the services
*/
@Inject(
method = "setLevel",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/server/players/GameProfileCache;setUsesAuthentication(Z)V",
shift = At.Shift.AFTER
)
)
public void setLevel$setup(ClientLevel levelClient, 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 packRepository the pack repository
* @param worldStem the world stem
* @param newWorld the new world
* @param ci the ci
* @param services the services
*/
@Inject(
method = "doWorldLoad",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/server/players/GameProfileCache;setUsesAuthentication(Z)V",
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) {
MinecraftSetUpServiceCallback.EVENT.invoker().load(services,this);
}
}

View File

@ -6,6 +6,7 @@ import net.fabricmc.loader.api.metadata.ModMetadata;
import top.r3944realms.lib39.Lib39;
import top.r3944realms.lib39.platform.services.IPlatformHelper;
import net.fabricmc.loader.api.FabricLoader;
import top.r3944realms.lib39.platform.services.IUtilHelper;
import java.util.Objects;
@ -40,4 +41,9 @@ public class FabricPlatformHelper implements IPlatformHelper {
.map(Objects::toString)
.orElse("NONE");
}
@Override
public IUtilHelper getUtilHelper() {
return FabricUtilHelper.INSTANCE;
}
}

View File

@ -0,0 +1,13 @@
package top.r3944realms.lib39.platform;
import top.r3944realms.lib39.platform.services.IUtilHelper;
import top.r3944realms.lib39.util.FabricBlockRegistryBuilder;
import top.r3944realms.lib39.util.block.BlockRegistryBuilder;
public enum FabricUtilHelper implements IUtilHelper {
INSTANCE;
@Override
public BlockRegistryBuilder getBlockRegistryBuilder() {
return new FabricBlockRegistryBuilder();
}
}

View File

@ -0,0 +1,17 @@
package top.r3944realms.lib39.util;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.level.block.Block;
import top.r3944realms.lib39.core.CreativeTabAdder;
import top.r3944realms.lib39.util.block.BlockRegistryBuilder;
import java.util.function.Supplier;
public class FabricBlockRegistryBuilder extends BlockRegistryBuilder {
@SafeVarargs
@Override
protected final void registerBlockItem(Supplier<Block> blockObject, ResourceKey<CreativeModeTab>... creativeTabs) {
CreativeTabAdder.addItemToTabs(blockObject, creativeTabs);
}
}

View File

@ -17,6 +17,9 @@
"entrypoints": {
"main": [
"top.r3944realms.lib39.Lib39Fabric"
],
"client": [
"top.r3944realms.lib39.Lib39FabricClient"
]
},
"mixins": [

View File

@ -1,17 +1,19 @@
{
"required": true,
"minVersion": "0.8",
"package": "top.r3944realms.lib39.mixin",
"refmap": "${mod_id}.refmap.json",
"compatibilityLevel": "JAVA_17",
"mixins": [
],
"client": [
],
"server": [
],
"injectors": {
"defaultRequire": 1
}
"required": true,
"minVersion": "0.8",
"package": "top.r3944realms.lib39.mixin",
"refmap": "${mod_id}.refmap.json",
"compatibilityLevel": "JAVA_17",
"mixins": [
"init.MixinDedicateServer"
],
"client": [
"init.MixinMinecraft"
],
"server": [
],
"injectors": {
"defaultRequire": 1
}
}

View File

@ -49,6 +49,7 @@ sourceSets.main.resources.srcDir project(':common').file('src/generated/resource
dependencies {
compileOnly project(":common")
annotationProcessor("org.spongepowered:mixin:0.8.5-SNAPSHOT:processor")
implementation(annotationProcessor("io.github.llamalad7:mixinextras-common:0.2.0"))
implementation(jarJar("io.github.llamalad7:mixinextras-forge:0.2.0"))
}

View File

@ -3,6 +3,10 @@ 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.register.ForgeLib39BlockEntities;
import top.r3944realms.lib39.core.register.ForgeLib39Blocks;
import top.r3944realms.lib39.core.register.ForgeLib39Items;
import top.r3944realms.lib39.core.register.ForgeLib39SoundEvents;
/**
* The type Lib 39.
@ -17,16 +21,17 @@ public class Lib39Forge {
initialize();
}
/**
* Initialize.
*/
public static void initialize() {
Lib39.LOGGER.info("[Lib39] Initializing Lib39");
Lib39.LOGGER.info("[Lib39-Forge] Hello Forge");
IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus();
Lib39.LOGGER.info("[Lib39] Initialized Lib39");
ForgeLib39Blocks.register(modEventBus);
ForgeLib39Items.register(modEventBus);
ForgeLib39BlockEntities.register(modEventBus);
ForgeLib39SoundEvents.register(modEventBus);
Lib39.LOGGER.info("[Lib39-Forge] Finished Initializing.");
}
}

View File

@ -0,0 +1,31 @@
package top.r3944realms.lib39.api.event;
import net.minecraft.server.Services;
import net.minecraftforge.eventbus.api.Event;
import java.util.concurrent.Executor;
/**
* The type Minecraft set up service event.
*/
public class MinecraftSetUpServiceEvent extends Event {
/**
* The Services.
*/
public final Services services;
/**
* The Main thread executor.
*/
public final Executor mainThreadExecutor;
/**
* Instantiates a new Minecraft set up service event.
*
* @param services the services
* @param mainThreadExecutor the main thread executor
*/
public MinecraftSetUpServiceEvent(Services services, Executor mainThreadExecutor) {
this.services = services;
this.mainThreadExecutor = mainThreadExecutor;
}
}

View File

@ -0,0 +1,87 @@
package top.r3944realms.lib39.core.event;
import net.minecraft.client.multiplayer.ClientLevel;
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 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.core.register.Lib39BlockEntities;
import top.r3944realms.lib39.util.ILevelHelper;
/**
* The type Client handler.
*/
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)
public static class Mod extends ClientEventHandler {
/**
* On register shaders.
*
* @param event the event
*/
@SubscribeEvent
public static void onRegisterShaders(RegisterShadersEvent event) {
Lib39Shaders.registerShaders(event.getResourceProvider());
}
/**
* On register renderer.
*
* @param event the event
*/
@SubscribeEvent
public static void onRegisterRenderer (EntityRenderersEvent.RegisterRenderers event) {
event.registerBlockEntityRenderer(Lib39BlockEntities.DOLL_BLOCK_ENTITY.get(),DollBlockEntityRenderer::new);
}
/**
* Register layer definitions.
*
* @param event the event
*/
@SubscribeEvent
public static void registerLayerDefinitions(EntityRenderersEvent.RegisterLayerDefinitions event) {
event.registerLayerDefinition(DollModel.LAYER_LOCATION, DollModel::createBodyLayer);
}
}
/**
* 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)
public static class Game extends ClientEventHandler {
/**
* Register layer definitions.
*
* @param event the event
*/
@SubscribeEvent
public static void registerLayerDefinitions(LevelEvent.Load event) {
if (event.getLevel() != null && event.getLevel() instanceof ClientLevel level) {
ILevelHelper.LevelHelper.CLIENT.setLevel(level);
}
}
/**
* Register layer definitions.
*
* @param event the event
*/
@SubscribeEvent
public static void registerLayerDefinitions(LevelEvent.Unload event) {
if (event.getLevel() != null && event.getLevel() instanceof ClientLevel level) {
ILevelHelper.LevelHelper.CLIENT.setLevel(null);
}
}
}
}

View File

@ -0,0 +1,294 @@
package top.r3944realms.lib39.core.event;
import com.mojang.authlib.GameProfile;
import net.minecraft.Util;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
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.IEventBus;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.registries.RegistryObject;
import top.r3944realms.lib39.Lib39;
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.item.DollItem;
import top.r3944realms.lib39.content.register.Lib39Items;
import top.r3944realms.lib39.core.compat.CompatManager;
import top.r3944realms.lib39.core.register.Lib39Items;
import top.r3944realms.lib39.core.sync.ISyncData;
import top.r3944realms.lib39.core.sync.SyncData2Manager;
import top.r3944realms.lib39.example.compat.Lib39CompatManager;
import top.r3944realms.lib39.util.GameProfileHelper;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
/**
* The type Common handler.
*/
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)
public static class Game extends CommonEventHandler {
private static ServerLevel sl;
/**
* Gets server level.
*
* @return the server level
*/
public static ServerLevel getServerLevel() {
return sl;
}
/**
* The Sync data 2 manager.
*/
static volatile SyncData2Manager syncData2Manager;
private static boolean isSync2MInitialized = false;
/**
* Gets sync data 2 manager.
*
* @return the sync data 2 manager
*/
public static SyncData2Manager getSyncData2Manager() {
return syncData2Manager;
}
/**
* On world load.
*
* @param event the event
*/
@SubscribeEvent
public static void onWorldLoad(LevelEvent.Load event) {
LevelAccessor level = event.getLevel();
if(level instanceof ServerLevel serverLevel) {
// 只处理主世界避免多次初始化
if (!serverLevel.dimension().equals(Level.OVERWORLD)) return;
synchronized (Game.class) {
if (!isSync2MInitialized) {
syncData2Manager = new SyncData2Manager();
MinecraftForge.EVENT_BUS.post(new SyncManagerRegisterEvent(syncData2Manager));
isSync2MInitialized = true;
sl = serverLevel;
Lib39.LOGGER.info("SyncData2Manager initialized on Sever load");
}
}
} else if (level instanceof ClientLevel clientLevel) {
synchronized (Game.class) {
if (!clientLevel.dimension().equals(Level.OVERWORLD)) return;
if (!isSync2MInitialized) {
syncData2Manager = new SyncData2Manager();
MinecraftForge.EVENT_BUS.post(new SyncManagerRegisterEvent(syncData2Manager));
Lib39.LOGGER.info("SyncData2Manager initialized on Client load");
}
}
}
}
/**
* On world unload.
*
* @param event the event
*/
@SubscribeEvent
public static void onWorldUnload(LevelEvent.Unload event) {
if (event.getLevel().isClientSide() || !(event.getLevel() instanceof ServerLevel serverLevel)) return;
if (!serverLevel.dimension().equals(Level.OVERWORLD)) return;
sl = null;
isSync2MInitialized = false;
}
/**
* On server tick.
*
* @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)));
}
}
/**
* On anvil rename.
*
* @param event the event
*/
@SubscribeEvent
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);
} else {
ItemStack defaultInstance = Items.BARRIER.getDefaultInstance();
defaultInstance.setHoverName(Component.translatable("invalid.player_name.too_long"));
event.setOutput(defaultInstance);
}
}
}
/**
* On entity join world.
*
* @param event the event
*/
@SubscribeEvent
public static void onEntityJoinWorld(EntityJoinLevelEvent event) {
Entity entity = event.getEntity();
if (entity.level().isClientSide) return;
for (ResourceLocation id : syncData2Manager.getRegisteredKeys()) {
if (syncData2Manager.isEntityClassAllowed(id, entity.getClass())) {
syncData2Manager.trackEntityForManager(entity, id);
}
}
}
/**
* On entity leave world.
*
* @param event the event
*/
@SubscribeEvent
public static void onEntityLeaveWorld(EntityLeaveLevelEvent event) {
Entity entity = event.getEntity();
if (entity.level().isClientSide) return;
for (ResourceLocation id : syncData2Manager.getRegisteredKeys()) {
if (syncData2Manager.isEntityClassAllowed(id, entity.getClass())) {
syncData2Manager.untrackEntityForManager(entity, id);
}
}
}
/**
* On register command.
*
* @param event the event
*/
@SubscribeEvent
public static void onRegisterCommand (RegisterCommandsEvent event) {
Lib39HelpCommand lib39HelpCommand = new Lib39HelpCommand(event);
}
}
/**
* The type Mod.
*/
@SuppressWarnings("unused")
@net.minecraftforge.fml.common.Mod.EventBusSubscriber(modid = Lib39.MOD_ID, bus = net.minecraftforge.fml.common.Mod.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<>();
/**
* On fml common setup.
*
* @param event the event
*/
@SubscribeEvent
public static void onFMLCommonSetup(FMLCommonSetupEvent event) {
event.enqueueWork(() -> {
try {
Class.forName("top.r3944realms.lib39.base.command.Lib39CommandHelpManager");
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
});
}
/**
* Add item to tabs.
*
* @param item the item
* @param tabs the tabs
*/
@SafeVarargs
public static void addItemToTabs(Supplier<Block> item, ResourceKey<CreativeModeTab>... tabs) {
itemAddMap.put(item, tabs);
// 更新反向映射
for (ResourceKey<CreativeModeTab> tab : tabs) {
tabToItemsMap.computeIfAbsent(tab, k -> new ArrayList<>()).add(item);
}
}
/**
* On build creative tab contents.
*
* @param event the event
*/
@SubscribeEvent
public static void onBuildCreativeTabContents(BuildCreativeModeTabContentsEvent event) {
List<Supplier<Block>> itemsForTab = tabToItemsMap.get(event.getTabKey());
if (itemsForTab != null) {
itemsForTab.forEach(event::accept);
}
}
/**
* Gather data.
*
* @param event the event
*/
@SubscribeEvent
public static void gatherData(GatherDataEvent event) {
Lib39BaseDataGenEvent.gatherData(event);
}
/**
* Gets item add map.
*
* @return the item add map
*/
public static Map<Supplier<Block>, ResourceKey<CreativeModeTab>[]> getItemAddMap() {
return itemAddMap;
}
}
}

View File

@ -0,0 +1,50 @@
package top.r3944realms.lib39.core.event;
import net.minecraft.client.multiplayer.ClientLevel;
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.minecraftforge.fml.common.Mod;
import top.r3944realms.lib39.Lib39;
import top.r3944realms.lib39.util.ILevelHelper;
/**
* The type Server handler.
*/
public class ServerEventHandler {
/**
* The type Mod.
*/
public static class Mod extends 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)
public static class Game extends ServerEventHandler {
/**
* Register layer definitions.
*
* @param event the event
*/
@SubscribeEvent
public static void registerLayerDefinitions(LevelEvent.Load event) {
if (event.getLevel() != null && event.getLevel() instanceof ServerLevel level) {
ILevelHelper.LevelHelper.SERVER.setLevel(level);
}
}
/**
* Register layer definitions.
*
* @param event the event
*/
@SubscribeEvent
public static void registerLayerDefinitions(LevelEvent.Unload event) {
if (event.getLevel() != null && event.getLevel() instanceof ServerLevel) {
ILevelHelper.LevelHelper.SERVER.setLevel(null);
}
}
}
}

View File

@ -16,15 +16,15 @@ public class ForgeLib39BlockEntities {
* The constant BLOCK_ENTITY_TYPES.
*/
public static final DeferredRegister<BlockEntityType<?>> BLOCK_ENTITY_TYPES = DeferredRegister.create(ForgeRegistries.BLOCK_ENTITY_TYPES, Lib39.MOD_ID);
/**
* The constant DOLL_BLOCK_ENTITY.
*/
@SuppressWarnings("DataFlowIssue")
public static final RegistryObject<BlockEntityType<DollBlockEntity>> DOLL_BLOCK_ENTITY = BLOCK_ENTITY_TYPES.register("doll",
() -> BlockEntityType.Builder
.of(DollBlockEntity::new, ForgeLib39Blocks.DOLL.get())
.build(null)
);
static {
//noinspection DataFlowIssue
Lib39BlockEntities.DOLL_BLOCK_ENTITY = BLOCK_ENTITY_TYPES.register("doll",
() -> BlockEntityType.Builder
.of(DollBlockEntity::new, Lib39Blocks.DOLL.get())
.build(null)
);
}
/**
* Register.

View File

@ -22,7 +22,7 @@ public class ForgeLib39Blocks {
Lib39Blocks.DOLL = BlockRegistryBuilder
.create()
.withName("doll")
.registerBlock(BLOCKS, DollBlock::new)
.registerBlock(BLOCKS::register, DollBlock::new)
.build();
}

View File

@ -0,0 +1,53 @@
package top.r3944realms.lib39.mixin.init;
import com.mojang.datafixers.DataFixer;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.ServerInterface;
import net.minecraft.server.Services;
import net.minecraft.server.WorldStem;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.server.level.progress.ChunkProgressListenerFactory;
import net.minecraft.server.packs.repository.PackRepository;
import net.minecraft.world.level.storage.LevelStorageSource;
import net.minecraftforge.common.MinecraftForge;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import top.r3944realms.lib39.api.event.MinecraftSetUpServiceEvent;
import java.net.Proxy;
/**
* The type Mixin dedicate server.
*/
@Mixin(DedicatedServer.class)
public abstract class MixinDedicateServer extends MinecraftServer implements ServerInterface {
/**
* Instantiates a new Mixin dedicate server.
*
* @param serverThread the server thread
* @param storageSource the storage source
* @param packRepository the pack repository
* @param worldStem the world stem
* @param proxy the proxy
* @param fixerUpper the fixer upper
* @param services the services
* @param progressListenerFactory the progress listener factory
*/
public MixinDedicateServer(Thread serverThread, LevelStorageSource.LevelStorageAccess storageSource, PackRepository packRepository, WorldStem worldStem, Proxy proxy, DataFixer fixerUpper, Services services, ChunkProgressListenerFactory progressListenerFactory) {
super(serverThread, storageSource, packRepository, worldStem, proxy, fixerUpper, services, progressListenerFactory);
}
@Inject(
method = "initServer",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/server/players/GameProfileCache;setUsesAuthentication(Z)V",
shift = At.Shift.AFTER
)
)
private void initServer$setup(CallbackInfoReturnable<Boolean> cir) {
MinecraftForge.EVENT_BUS.post(new MinecraftSetUpServiceEvent(this.services,this));
}
}

View File

@ -0,0 +1,77 @@
package top.r3944realms.lib39.mixin.init;
import com.llamalad7.mixinextras.sugar.Local;
import com.mojang.blaze3d.platform.WindowEventHandler;
import net.minecraft.client.Minecraft;
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 net.minecraftforge.common.MinecraftForge;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import top.r3944realms.lib39.api.event.MinecraftSetUpServiceEvent;
/**
* The type Mixin minecraft.
*/
@Mixin(Minecraft.class)
public abstract class MixinMinecraft extends ReentrantBlockableEventLoop<Runnable> implements WindowEventHandler, net.minecraftforge.client.extensions.IForgeMinecraft {
/**
* Instantiates a new Mixin minecraft.
*
* @param name the name
*/
public MixinMinecraft(String name) {
super(name);
}
/**
* Set level setup.
*
* @param levelClient the level client
* @param ci the ci
* @param services the services
*/
@Inject(
method = "setLevel",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/server/players/GameProfileCache;setUsesAuthentication(Z)V",
shift = At.Shift.AFTER
)
)
public void setLevel$setup(ClientLevel levelClient, CallbackInfo ci,
@Local(ordinal = 0) Services services) {
MinecraftForge.EVENT_BUS.post(new MinecraftSetUpServiceEvent(services,this));
}
/**
* Do world load setup.
*
* @param levelId the level id
* @param level the level
* @param packRepository the pack repository
* @param worldStem the world stem
* @param newWorld the new world
* @param ci the ci
* @param services the services
*/
@Inject(
method = "doWorldLoad",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/server/players/GameProfileCache;setUsesAuthentication(Z)V",
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) {
MinecraftForge.EVENT_BUS.post(new MinecraftSetUpServiceEvent(services,this));
}
}

View File

@ -5,6 +5,7 @@ import net.minecraftforge.fml.loading.FMLEnvironment;
import net.minecraftforge.fml.loading.FMLLoader;
import top.r3944realms.lib39.Lib39;
import top.r3944realms.lib39.platform.services.IPlatformHelper;
import top.r3944realms.lib39.platform.services.IUtilHelper;
public class ForgePlatformHelper implements IPlatformHelper {
@ -35,4 +36,9 @@ public class ForgePlatformHelper implements IPlatformHelper {
.map(c -> c.getModInfo().getVersion().toString())
.orElse("UNKNOWN");
}
@Override
public IUtilHelper getUtilHelper() {
return ForgeUtilHelper.INSTANCE;
}
}

View File

@ -0,0 +1,13 @@
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;
public enum ForgeUtilHelper implements IUtilHelper {
INSTANCE;
@Override
public BlockRegistryBuilder getBlockRegistryBuilder() {
return new ForgeBlockRegistryBuilder();
}
}

View File

@ -0,0 +1,17 @@
package top.r3944realms.lib39.util;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.level.block.Block;
import top.r3944realms.lib39.core.event.CommonEventHandler;
import top.r3944realms.lib39.util.block.BlockRegistryBuilder;
import java.util.function.Supplier;
public class ForgeBlockRegistryBuilder extends BlockRegistryBuilder {
@SafeVarargs
@Override
protected final void registerBlockItem(Supplier<Block> blockObject, ResourceKey<CreativeModeTab>... creativeTabs) {
CommonEventHandler.Mod.addItemToTabs(blockObject, creativeTabs);
}
}

View File

@ -1,17 +1,18 @@
{
"required": true,
"minVersion": "0.8",
"package": "top.r3944realms.lib39.mixin",
"refmap": "${mod_id}.refmap.json",
"compatibilityLevel": "JAVA_17",
"mixins": [
],
"client": [
],
"server": [
],
"injectors": {
"defaultRequire": 1
}
"required": true,
"minVersion": "0.8",
"package": "top.r3944realms.lib39.mixin",
"refmap": "${mod_id}.refmap.json",
"compatibilityLevel": "JAVA_17",
"mixins": [
"init.MixinDedicateServer"
],
"client": [
"init.MixinMinecraft"
],
"server": [
],
"injectors": {
"defaultRequire": 1
}
}

View File

@ -24,7 +24,7 @@ plugins {
}
// This should match the folder name of the project, or else IDEA may complain (see https://youtrack.jetbrains.com/issue/IDEA-317606)
rootProject.name = 'MultiLoader-Template'
rootProject.name = 'Lib39'
include("common")
include("fabric")
include("forge")