feat: 跨版本化,第二部分,未完成
This commit is contained in:
parent
eac118e9a4
commit
5a6729aa31
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -21,6 +21,7 @@ build
|
|||
# other
|
||||
eclipse
|
||||
run
|
||||
generated
|
||||
runs
|
||||
run-data
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -45,4 +45,6 @@ public interface IPlatformHelper {
|
|||
* @return the mod version
|
||||
*/
|
||||
String getModVersion();
|
||||
|
||||
IUtilHelper getUtilHelper();
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package top.r3944realms.lib39.platform.services;
|
||||
|
||||
import top.r3944realms.lib39.util.block.BlockRegistryBuilder;
|
||||
|
||||
public interface IUtilHelper {
|
||||
BlockRegistryBuilder getBlockRegistryBuilder();
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
16
common/src/main/resources/accesstransformer.cfg
Normal file
16
common/src/main/resources/accesstransformer.cfg
Normal 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
|
||||
2
common/src/main/resources/lib39.accesswidener
Normal file
2
common/src/main/resources/lib39.accesswidener
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
accessWidener v2 named
|
||||
# 不要用这个,太垃圾了,不支持parchment名
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.");
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -17,6 +17,9 @@
|
|||
"entrypoints": {
|
||||
"main": [
|
||||
"top.r3944realms.lib39.Lib39Fabric"
|
||||
],
|
||||
"client": [
|
||||
"top.r3944realms.lib39.Lib39FabricClient"
|
||||
]
|
||||
},
|
||||
"mixins": [
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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"))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.");
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ public class ForgeLib39Blocks {
|
|||
Lib39Blocks.DOLL = BlockRegistryBuilder
|
||||
.create()
|
||||
.withName("doll")
|
||||
.registerBlock(BLOCKS, DollBlock::new)
|
||||
.registerBlock(BLOCKS::register, DollBlock::new)
|
||||
.build();
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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")
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user