From 5a6729aa313defe4c21b97094177b6f8ac364595 Mon Sep 17 00:00:00 2001 From: 3944Realms Date: Wed, 11 Mar 2026 21:02:57 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=B7=A8=E7=89=88=E6=9C=AC=E5=8C=96?= =?UTF-8?q?=EF=BC=8C=E7=AC=AC=E4=BA=8C=E9=83=A8=E5=88=86=EF=BC=8C=E6=9C=AA?= =?UTF-8?q?=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + .../java/top/r3944realms/lib39/Lib39.java | 3 +- .../client/gui/component/WheelWidget.java | 769 ++++++++++++++++++ .../lib39/client/model/DollModel.java | 91 +++ .../client/renderer/RadialMenuRenderer.java | 381 +++++++++ .../block/DollBlockEntityRenderer.java | 55 ++ .../renderer/item/DollItemRenderer.java | 98 +++ .../lib39/client/shader/Lib39Shaders.java | 68 ++ .../lib39/content/item/DollItem.java | 11 +- .../minecraft/CreativeModeTabsAccessor.java | 92 +++ .../platform/services/IPlatformHelper.java | 2 + .../lib39/platform/services/IUtilHelper.java | 7 + .../util/block/BlockRegistryBuilder.java | 24 +- .../src/main/resources/accesstransformer.cfg | 16 + common/src/main/resources/lib39.accesswidener | 2 + common/src/main/resources/lib39.mixins.json | 31 +- .../top/r3944realms/lib39/Lib39Fabric.java | 15 +- .../r3944realms/lib39/Lib39FabricClient.java | 36 + .../MinecraftSetUpServiceCallback.java | 38 + .../lib39/core/CreativeTabAdder.java | 48 ++ .../register/FabricLib39BlockEntities.java | 22 +- .../core/register/FabricLib39Blocks.java | 24 +- .../lib39/core/register/FabricLib39Items.java | 18 +- .../core/register/FabricLib39SoundEvents.java | 28 +- .../lib39/mixin/init/MixinDedicateServer.java | 52 ++ .../lib39/mixin/init/MixinMinecraft.java | 76 ++ .../lib39/platform/FabricPlatformHelper.java | 6 + .../lib39/platform/FabricUtilHelper.java | 13 + .../util/FabricBlockRegistryBuilder.java | 17 + fabric/src/main/resources/fabric.mod.json | 3 + .../main/resources/lib39.fabric.mixins.json | 30 +- forge/build.gradle | 1 + .../top/r3944realms/lib39/Lib39Forge.java | 15 +- .../api/event/MinecraftSetUpServiceEvent.java | 31 + .../lib39/core/event/ClientEventHandler.java | 87 ++ .../lib39/core/event/CommonEventHandler.java | 294 +++++++ .../lib39/core/event/ServerEventHandler.java | 50 ++ .../register/ForgeLib39BlockEntities.java | 18 +- .../lib39/core/register/ForgeLib39Blocks.java | 2 +- .../lib39/mixin/init/MixinDedicateServer.java | 53 ++ .../lib39/mixin/init/MixinMinecraft.java | 77 ++ .../lib39/platform/ForgePlatformHelper.java | 6 + .../lib39/platform/ForgeUtilHelper.java | 13 + .../lib39/util/ForgeBlockRegistryBuilder.java | 17 + .../main/resources/lib39.forge.mixins.json | 31 +- settings.gradle | 2 +- 46 files changed, 2656 insertions(+), 118 deletions(-) create mode 100644 common/src/main/java/top/r3944realms/lib39/client/gui/component/WheelWidget.java create mode 100644 common/src/main/java/top/r3944realms/lib39/client/model/DollModel.java create mode 100644 common/src/main/java/top/r3944realms/lib39/client/renderer/RadialMenuRenderer.java create mode 100644 common/src/main/java/top/r3944realms/lib39/client/renderer/block/DollBlockEntityRenderer.java create mode 100644 common/src/main/java/top/r3944realms/lib39/client/renderer/item/DollItemRenderer.java create mode 100644 common/src/main/java/top/r3944realms/lib39/client/shader/Lib39Shaders.java create mode 100644 common/src/main/java/top/r3944realms/lib39/mixin/minecraft/CreativeModeTabsAccessor.java create mode 100644 common/src/main/java/top/r3944realms/lib39/platform/services/IUtilHelper.java create mode 100644 common/src/main/resources/accesstransformer.cfg create mode 100644 common/src/main/resources/lib39.accesswidener create mode 100644 fabric/src/main/java/top/r3944realms/lib39/Lib39FabricClient.java create mode 100644 fabric/src/main/java/top/r3944realms/lib39/api/callback/MinecraftSetUpServiceCallback.java create mode 100644 fabric/src/main/java/top/r3944realms/lib39/core/CreativeTabAdder.java create mode 100644 fabric/src/main/java/top/r3944realms/lib39/mixin/init/MixinDedicateServer.java create mode 100644 fabric/src/main/java/top/r3944realms/lib39/mixin/init/MixinMinecraft.java create mode 100644 fabric/src/main/java/top/r3944realms/lib39/platform/FabricUtilHelper.java create mode 100644 fabric/src/main/java/top/r3944realms/lib39/util/FabricBlockRegistryBuilder.java create mode 100644 forge/src/main/java/top/r3944realms/lib39/api/event/MinecraftSetUpServiceEvent.java create mode 100644 forge/src/main/java/top/r3944realms/lib39/core/event/ClientEventHandler.java create mode 100644 forge/src/main/java/top/r3944realms/lib39/core/event/CommonEventHandler.java create mode 100644 forge/src/main/java/top/r3944realms/lib39/core/event/ServerEventHandler.java create mode 100644 forge/src/main/java/top/r3944realms/lib39/mixin/init/MixinDedicateServer.java create mode 100644 forge/src/main/java/top/r3944realms/lib39/mixin/init/MixinMinecraft.java create mode 100644 forge/src/main/java/top/r3944realms/lib39/platform/ForgeUtilHelper.java create mode 100644 forge/src/main/java/top/r3944realms/lib39/util/ForgeBlockRegistryBuilder.java diff --git a/.gitignore b/.gitignore index 5c8ba59..1f055c6 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ build # other eclipse run +generated runs run-data diff --git a/common/src/main/java/top/r3944realms/lib39/Lib39.java b/common/src/main/java/top/r3944realms/lib39/Lib39.java index d224270..88c6d17 100644 --- a/common/src/main/java/top/r3944realms/lib39/Lib39.java +++ b/common/src/main/java/top/r3944realms/lib39/Lib39.java @@ -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. diff --git a/common/src/main/java/top/r3944realms/lib39/client/gui/component/WheelWidget.java b/common/src/main/java/top/r3944realms/lib39/client/gui/component/WheelWidget.java new file mode 100644 index 0000000..a4ecbfe --- /dev/null +++ b/common/src/main/java/top/r3944realms/lib39/client/gui/component/WheelWidget.java @@ -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 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>> 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>> 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>> 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>> 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>> 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>> 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>> 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>> 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> 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 renderer + ) { + } +} diff --git a/common/src/main/java/top/r3944realms/lib39/client/model/DollModel.java b/common/src/main/java/top/r3944realms/lib39/client/model/DollModel.java new file mode 100644 index 0000000..e96d5a6 --- /dev/null +++ b/common/src/main/java/top/r3944realms/lib39/client/model/DollModel.java @@ -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(); + } +} diff --git a/common/src/main/java/top/r3944realms/lib39/client/renderer/RadialMenuRenderer.java b/common/src/main/java/top/r3944realms/lib39/client/renderer/RadialMenuRenderer.java new file mode 100644 index 0000000..a20d515 --- /dev/null +++ b/common/src/main/java/top/r3944realms/lib39/client/renderer/RadialMenuRenderer.java @@ -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 the type parameter + */ +public class RadialMenuRenderer { + /** + * 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 entries, + Function titleProvider, + Function 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 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 entries, + Function titleProvider, + Function 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 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); + } +} diff --git a/common/src/main/java/top/r3944realms/lib39/client/renderer/block/DollBlockEntityRenderer.java b/common/src/main/java/top/r3944realms/lib39/client/renderer/block/DollBlockEntityRenderer.java new file mode 100644 index 0000000..fd1796c --- /dev/null +++ b/common/src/main/java/top/r3944realms/lib39/client/renderer/block/DollBlockEntityRenderer.java @@ -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 { + 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 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(); + } + } +} diff --git a/common/src/main/java/top/r3944realms/lib39/client/renderer/item/DollItemRenderer.java b/common/src/main/java/top/r3944realms/lib39/client/renderer/item/DollItemRenderer.java new file mode 100644 index 0000000..7e29275 --- /dev/null +++ b/common/src/main/java/top/r3944realms/lib39/client/renderer/item/DollItemRenderer.java @@ -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 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 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); + } +} diff --git a/common/src/main/java/top/r3944realms/lib39/client/shader/Lib39Shaders.java b/common/src/main/java/top/r3944realms/lib39/client/shader/Lib39Shaders.java new file mode 100644 index 0000000..6e98b52 --- /dev/null +++ b/common/src/main/java/top/r3944realms/lib39/client/shader/Lib39Shaders.java @@ -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); + } + } +} diff --git a/common/src/main/java/top/r3944realms/lib39/content/item/DollItem.java b/common/src/main/java/top/r3944realms/lib39/content/item/DollItem.java index c518943..8fdc61c 100644 --- a/common/src/main/java/top/r3944realms/lib39/content/item/DollItem.java +++ b/common/src/main/java/top/r3944realms/lib39/content/item/DollItem.java @@ -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; + } } diff --git a/common/src/main/java/top/r3944realms/lib39/mixin/minecraft/CreativeModeTabsAccessor.java b/common/src/main/java/top/r3944realms/lib39/mixin/minecraft/CreativeModeTabsAccessor.java new file mode 100644 index 0000000..e21c66d --- /dev/null +++ b/common/src/main/java/top/r3944realms/lib39/mixin/minecraft/CreativeModeTabsAccessor.java @@ -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 getBuildingBlocks() { + throw new AssertionError(); + } + + @Accessor("COLORED_BLOCKS") + static ResourceKey getColoredBlocks() { + throw new AssertionError(); + } + + @Accessor("NATURAL_BLOCKS") + static ResourceKey getNaturalBlocks() { + throw new AssertionError(); + } + + @Accessor("FUNCTIONAL_BLOCKS") + static ResourceKey getFunctionalBlocks() { + throw new AssertionError(); + } + + @Accessor("REDSTONE_BLOCKS") + static ResourceKey getRedstoneBlocks() { + throw new AssertionError(); + } + + @Accessor("HOTBAR") + static ResourceKey getHotbar() { + throw new AssertionError(); + } + + @Accessor("SEARCH") + static ResourceKey getSearch() { + throw new AssertionError(); + } + + @Accessor("TOOLS_AND_UTILITIES") + static ResourceKey getToolsAndUtilities() { + throw new AssertionError(); + } + + @Accessor("COMBAT") + static ResourceKey getCombat() { + throw new AssertionError(); + } + + @Accessor("FOOD_AND_DRINKS") + static ResourceKey getFoodAndDrinks() { + throw new AssertionError(); + } + + @Accessor("INGREDIENTS") + static ResourceKey getIngredients() { + throw new AssertionError(); + } + + @Accessor("SPAWN_EGGS") + static ResourceKey getSpawnEggs() { + throw new AssertionError(); + } + + @Accessor("OP_BLOCKS") + static ResourceKey getOpBlocks() { + throw new AssertionError(); + } + + @Accessor("INVENTORY") + static ResourceKey getInventory() { + throw new AssertionError(); + } + + @Accessor("CACHED_PARAMETERS") + static CreativeModeTab.ItemDisplayParameters getCachedParameters() { + throw new AssertionError(); + } + + @Accessor("PAINTING_COMPARATOR") + static Comparator getPaintingComparator() { + throw new AssertionError(); + } +} diff --git a/common/src/main/java/top/r3944realms/lib39/platform/services/IPlatformHelper.java b/common/src/main/java/top/r3944realms/lib39/platform/services/IPlatformHelper.java index f7fee96..7a25c86 100644 --- a/common/src/main/java/top/r3944realms/lib39/platform/services/IPlatformHelper.java +++ b/common/src/main/java/top/r3944realms/lib39/platform/services/IPlatformHelper.java @@ -45,4 +45,6 @@ public interface IPlatformHelper { * @return the mod version */ String getModVersion(); + + IUtilHelper getUtilHelper(); } \ No newline at end of file diff --git a/common/src/main/java/top/r3944realms/lib39/platform/services/IUtilHelper.java b/common/src/main/java/top/r3944realms/lib39/platform/services/IUtilHelper.java new file mode 100644 index 0000000..07fe001 --- /dev/null +++ b/common/src/main/java/top/r3944realms/lib39/platform/services/IUtilHelper.java @@ -0,0 +1,7 @@ +package top.r3944realms.lib39.platform.services; + +import top.r3944realms.lib39.util.block.BlockRegistryBuilder; + +public interface IUtilHelper { + BlockRegistryBuilder getBlockRegistryBuilder(); +} diff --git a/common/src/main/java/top/r3944realms/lib39/util/block/BlockRegistryBuilder.java b/common/src/main/java/top/r3944realms/lib39/util/block/BlockRegistryBuilder.java index f6fc4e8..9680f90 100644 --- a/common/src/main/java/top/r3944realms/lib39/util/block/BlockRegistryBuilder.java +++ b/common/src/main/java/top/r3944realms/lib39/util/block/BlockRegistryBuilder.java @@ -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 blockObject, ResourceKey... creativeTabs) { - - } + protected abstract void registerBlockItem(Supplier blockObject, ResourceKey... creativeTabs); /** * 注册方块和物品到建筑标签页 @@ -110,7 +100,7 @@ public abstract class BlockRegistryBuilder { */ public BlockRegistryBuilder registerWithBuildingTab(BiFunction,Supplier> blockRegister, Supplier 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,Supplier> blockRegister, Supplier blockSupplier) { registerBlock(blockRegister, blockSupplier); - registerBlockItem(this.blockObject, CreativeModeTabs.FUNCTIONAL_BLOCKS); + registerBlockItem(this.blockObject, CreativeModeTabsAccessor.getFunctionalBlocks()); return this; } diff --git a/common/src/main/resources/accesstransformer.cfg b/common/src/main/resources/accesstransformer.cfg new file mode 100644 index 0000000..5075e4f --- /dev/null +++ b/common/src/main/resources/accesstransformer.cfg @@ -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 diff --git a/common/src/main/resources/lib39.accesswidener b/common/src/main/resources/lib39.accesswidener new file mode 100644 index 0000000..f4cac66 --- /dev/null +++ b/common/src/main/resources/lib39.accesswidener @@ -0,0 +1,2 @@ +accessWidener v2 named +# 不要用这个,太垃圾了,不支持parchment名 \ No newline at end of file diff --git a/common/src/main/resources/lib39.mixins.json b/common/src/main/resources/lib39.mixins.json index e622f45..6bcbbb4 100644 --- a/common/src/main/resources/lib39.mixins.json +++ b/common/src/main/resources/lib39.mixins.json @@ -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 + } } diff --git a/fabric/src/main/java/top/r3944realms/lib39/Lib39Fabric.java b/fabric/src/main/java/top/r3944realms/lib39/Lib39Fabric.java index 5190a66..3028c80 100644 --- a/fabric/src/main/java/top/r3944realms/lib39/Lib39Fabric.java +++ b/fabric/src/main/java/top/r3944realms/lib39/Lib39Fabric.java @@ -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."); } } diff --git a/fabric/src/main/java/top/r3944realms/lib39/Lib39FabricClient.java b/fabric/src/main/java/top/r3944realms/lib39/Lib39FabricClient.java new file mode 100644 index 0000000..20d001b --- /dev/null +++ b/fabric/src/main/java/top/r3944realms/lib39/Lib39FabricClient.java @@ -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 + ); + } +} diff --git a/fabric/src/main/java/top/r3944realms/lib39/api/callback/MinecraftSetUpServiceCallback.java b/fabric/src/main/java/top/r3944realms/lib39/api/callback/MinecraftSetUpServiceCallback.java new file mode 100644 index 0000000..d1af907 --- /dev/null +++ b/fabric/src/main/java/top/r3944realms/lib39/api/callback/MinecraftSetUpServiceCallback.java @@ -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 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); +} diff --git a/fabric/src/main/java/top/r3944realms/lib39/core/CreativeTabAdder.java b/fabric/src/main/java/top/r3944realms/lib39/core/CreativeTabAdder.java new file mode 100644 index 0000000..d0731c2 --- /dev/null +++ b/fabric/src/main/java/top/r3944realms/lib39/core/CreativeTabAdder.java @@ -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, ResourceKey[]> itemAddMap = new ConcurrentHashMap<>(); + private static final Map, List>> tabToItemsMap = new ConcurrentHashMap<>(); + /** + * Add item to tabs. + * + * @param item the item + * @param tabs the tabs + */ + @SafeVarargs + public static void addItemToTabs(Supplier item, ResourceKey... tabs) { + itemAddMap.put(item, tabs); + + // 更新反向映射 + for (ResourceKey tab : tabs) { + tabToItemsMap.computeIfAbsent(tab, k -> new ArrayList<>()).add(item); + } + } + + public static void init() { + for (Map.Entry, List>> 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, ResourceKey[]> getItemAddMap() { + return itemAddMap; + } + +} diff --git a/fabric/src/main/java/top/r3944realms/lib39/core/register/FabricLib39BlockEntities.java b/fabric/src/main/java/top/r3944realms/lib39/core/register/FabricLib39BlockEntities.java index 5e8c6f6..587dd64 100644 --- a/fabric/src/main/java/top/r3944realms/lib39/core/register/FabricLib39BlockEntities.java +++ b/fabric/src/main/java/top/r3944realms/lib39/core/register/FabricLib39BlockEntities.java @@ -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> 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 > @NotNull Supplier register(String path, T blockEntityType) { + return () -> Registry.register(BuiltInRegistries.BLOCK_ENTITY_TYPE, Lib39.rl(path), blockEntityType); + } } diff --git a/fabric/src/main/java/top/r3944realms/lib39/core/register/FabricLib39Blocks.java b/fabric/src/main/java/top/r3944realms/lib39/core/register/FabricLib39Blocks.java index d4b8f3b..0c7a35c 100644 --- a/fabric/src/main/java/top/r3944realms/lib39/core/register/FabricLib39Blocks.java +++ b/fabric/src/main/java/top/r3944realms/lib39/core/register/FabricLib39Blocks.java @@ -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 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 @NotNull Supplier register(String path, T block) { + return () -> Registry.register(BuiltInRegistries.BLOCK, Lib39.rl(path), block); + } } diff --git a/fabric/src/main/java/top/r3944realms/lib39/core/register/FabricLib39Items.java b/fabric/src/main/java/top/r3944realms/lib39/core/register/FabricLib39Items.java index ee97a62..880f582 100644 --- a/fabric/src/main/java/top/r3944realms/lib39/core/register/FabricLib39Items.java +++ b/fabric/src/main/java/top/r3944realms/lib39/core/register/FabricLib39Items.java @@ -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 DOLL; + public static void init() { + Lib39Items.DOLL = register("doll", new DollItem(new Item.Properties())); + } + @Contract(pure = true) + public static @NotNull Supplier register(String path, T item) { + return () -> Registry.register(BuiltInRegistries.ITEM, Lib39.rl(path), item); + } } diff --git a/fabric/src/main/java/top/r3944realms/lib39/core/register/FabricLib39SoundEvents.java b/fabric/src/main/java/top/r3944realms/lib39/core/register/FabricLib39SoundEvents.java index 7aa2a33..46c1e78 100644 --- a/fabric/src/main/java/top/r3944realms/lib39/core/register/FabricLib39SoundEvents.java +++ b/fabric/src/main/java/top/r3944realms/lib39/core/register/FabricLib39SoundEvents.java @@ -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 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 @NotNull Supplier register(String path, T soundEvent) { + return () -> Registry.register(BuiltInRegistries.SOUND_EVENT, Lib39.rl(path), soundEvent); } } diff --git a/fabric/src/main/java/top/r3944realms/lib39/mixin/init/MixinDedicateServer.java b/fabric/src/main/java/top/r3944realms/lib39/mixin/init/MixinDedicateServer.java new file mode 100644 index 0000000..222b7e8 --- /dev/null +++ b/fabric/src/main/java/top/r3944realms/lib39/mixin/init/MixinDedicateServer.java @@ -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 cir) { + MinecraftSetUpServiceCallback.EVENT.invoker().load(this.services,this); + } +} diff --git a/fabric/src/main/java/top/r3944realms/lib39/mixin/init/MixinMinecraft.java b/fabric/src/main/java/top/r3944realms/lib39/mixin/init/MixinMinecraft.java new file mode 100644 index 0000000..8e3c8bb --- /dev/null +++ b/fabric/src/main/java/top/r3944realms/lib39/mixin/init/MixinMinecraft.java @@ -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 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); + } +} + diff --git a/fabric/src/main/java/top/r3944realms/lib39/platform/FabricPlatformHelper.java b/fabric/src/main/java/top/r3944realms/lib39/platform/FabricPlatformHelper.java index 8d9d2a2..71e9d7a 100644 --- a/fabric/src/main/java/top/r3944realms/lib39/platform/FabricPlatformHelper.java +++ b/fabric/src/main/java/top/r3944realms/lib39/platform/FabricPlatformHelper.java @@ -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; + } } diff --git a/fabric/src/main/java/top/r3944realms/lib39/platform/FabricUtilHelper.java b/fabric/src/main/java/top/r3944realms/lib39/platform/FabricUtilHelper.java new file mode 100644 index 0000000..4a8b5ac --- /dev/null +++ b/fabric/src/main/java/top/r3944realms/lib39/platform/FabricUtilHelper.java @@ -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(); + } +} diff --git a/fabric/src/main/java/top/r3944realms/lib39/util/FabricBlockRegistryBuilder.java b/fabric/src/main/java/top/r3944realms/lib39/util/FabricBlockRegistryBuilder.java new file mode 100644 index 0000000..6e594f0 --- /dev/null +++ b/fabric/src/main/java/top/r3944realms/lib39/util/FabricBlockRegistryBuilder.java @@ -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 blockObject, ResourceKey... creativeTabs) { + CreativeTabAdder.addItemToTabs(blockObject, creativeTabs); + } +} diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json index e40f6ac..00a4878 100644 --- a/fabric/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -17,6 +17,9 @@ "entrypoints": { "main": [ "top.r3944realms.lib39.Lib39Fabric" + ], + "client": [ + "top.r3944realms.lib39.Lib39FabricClient" ] }, "mixins": [ diff --git a/fabric/src/main/resources/lib39.fabric.mixins.json b/fabric/src/main/resources/lib39.fabric.mixins.json index a514a6f..d925eee 100644 --- a/fabric/src/main/resources/lib39.fabric.mixins.json +++ b/fabric/src/main/resources/lib39.fabric.mixins.json @@ -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 + } } diff --git a/forge/build.gradle b/forge/build.gradle index 0c09784..cf2b3e4 100644 --- a/forge/build.gradle +++ b/forge/build.gradle @@ -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")) } diff --git a/forge/src/main/java/top/r3944realms/lib39/Lib39Forge.java b/forge/src/main/java/top/r3944realms/lib39/Lib39Forge.java index 1105278..31ab597 100644 --- a/forge/src/main/java/top/r3944realms/lib39/Lib39Forge.java +++ b/forge/src/main/java/top/r3944realms/lib39/Lib39Forge.java @@ -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."); } } diff --git a/forge/src/main/java/top/r3944realms/lib39/api/event/MinecraftSetUpServiceEvent.java b/forge/src/main/java/top/r3944realms/lib39/api/event/MinecraftSetUpServiceEvent.java new file mode 100644 index 0000000..e15831f --- /dev/null +++ b/forge/src/main/java/top/r3944realms/lib39/api/event/MinecraftSetUpServiceEvent.java @@ -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; + } +} diff --git a/forge/src/main/java/top/r3944realms/lib39/core/event/ClientEventHandler.java b/forge/src/main/java/top/r3944realms/lib39/core/event/ClientEventHandler.java new file mode 100644 index 0000000..5a47fc2 --- /dev/null +++ b/forge/src/main/java/top/r3944realms/lib39/core/event/ClientEventHandler.java @@ -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); + } + } + } + +} diff --git a/forge/src/main/java/top/r3944realms/lib39/core/event/CommonEventHandler.java b/forge/src/main/java/top/r3944realms/lib39/core/event/CommonEventHandler.java new file mode 100644 index 0000000..282c9b8 --- /dev/null +++ b/forge/src/main/java/top/r3944realms/lib39/core/event/CommonEventHandler.java @@ -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, ResourceKey[]> itemAddMap = new ConcurrentHashMap<>(); + private static final Map, List>> 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 item, ResourceKey... tabs) { + itemAddMap.put(item, tabs); + + // 更新反向映射 + for (ResourceKey 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> 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, ResourceKey[]> getItemAddMap() { + return itemAddMap; + } + } +} diff --git a/forge/src/main/java/top/r3944realms/lib39/core/event/ServerEventHandler.java b/forge/src/main/java/top/r3944realms/lib39/core/event/ServerEventHandler.java new file mode 100644 index 0000000..e75ba20 --- /dev/null +++ b/forge/src/main/java/top/r3944realms/lib39/core/event/ServerEventHandler.java @@ -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); + } + } + } +} diff --git a/forge/src/main/java/top/r3944realms/lib39/core/register/ForgeLib39BlockEntities.java b/forge/src/main/java/top/r3944realms/lib39/core/register/ForgeLib39BlockEntities.java index 37c47f3..4ba05f7 100644 --- a/forge/src/main/java/top/r3944realms/lib39/core/register/ForgeLib39BlockEntities.java +++ b/forge/src/main/java/top/r3944realms/lib39/core/register/ForgeLib39BlockEntities.java @@ -16,15 +16,15 @@ public class ForgeLib39BlockEntities { * The constant BLOCK_ENTITY_TYPES. */ public static final DeferredRegister> BLOCK_ENTITY_TYPES = DeferredRegister.create(ForgeRegistries.BLOCK_ENTITY_TYPES, Lib39.MOD_ID); - /** - * The constant DOLL_BLOCK_ENTITY. - */ - @SuppressWarnings("DataFlowIssue") - public static final RegistryObject> 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. diff --git a/forge/src/main/java/top/r3944realms/lib39/core/register/ForgeLib39Blocks.java b/forge/src/main/java/top/r3944realms/lib39/core/register/ForgeLib39Blocks.java index 739cf3a..ddd2da8 100644 --- a/forge/src/main/java/top/r3944realms/lib39/core/register/ForgeLib39Blocks.java +++ b/forge/src/main/java/top/r3944realms/lib39/core/register/ForgeLib39Blocks.java @@ -22,7 +22,7 @@ public class ForgeLib39Blocks { Lib39Blocks.DOLL = BlockRegistryBuilder .create() .withName("doll") - .registerBlock(BLOCKS, DollBlock::new) + .registerBlock(BLOCKS::register, DollBlock::new) .build(); } diff --git a/forge/src/main/java/top/r3944realms/lib39/mixin/init/MixinDedicateServer.java b/forge/src/main/java/top/r3944realms/lib39/mixin/init/MixinDedicateServer.java new file mode 100644 index 0000000..0d9ce29 --- /dev/null +++ b/forge/src/main/java/top/r3944realms/lib39/mixin/init/MixinDedicateServer.java @@ -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 cir) { + MinecraftForge.EVENT_BUS.post(new MinecraftSetUpServiceEvent(this.services,this)); + } +} diff --git a/forge/src/main/java/top/r3944realms/lib39/mixin/init/MixinMinecraft.java b/forge/src/main/java/top/r3944realms/lib39/mixin/init/MixinMinecraft.java new file mode 100644 index 0000000..8fdb48f --- /dev/null +++ b/forge/src/main/java/top/r3944realms/lib39/mixin/init/MixinMinecraft.java @@ -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 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)); + } +} + diff --git a/forge/src/main/java/top/r3944realms/lib39/platform/ForgePlatformHelper.java b/forge/src/main/java/top/r3944realms/lib39/platform/ForgePlatformHelper.java index f3f3609..cc2b57b 100644 --- a/forge/src/main/java/top/r3944realms/lib39/platform/ForgePlatformHelper.java +++ b/forge/src/main/java/top/r3944realms/lib39/platform/ForgePlatformHelper.java @@ -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; + } } diff --git a/forge/src/main/java/top/r3944realms/lib39/platform/ForgeUtilHelper.java b/forge/src/main/java/top/r3944realms/lib39/platform/ForgeUtilHelper.java new file mode 100644 index 0000000..d2239f7 --- /dev/null +++ b/forge/src/main/java/top/r3944realms/lib39/platform/ForgeUtilHelper.java @@ -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(); + } +} diff --git a/forge/src/main/java/top/r3944realms/lib39/util/ForgeBlockRegistryBuilder.java b/forge/src/main/java/top/r3944realms/lib39/util/ForgeBlockRegistryBuilder.java new file mode 100644 index 0000000..bc44d1c --- /dev/null +++ b/forge/src/main/java/top/r3944realms/lib39/util/ForgeBlockRegistryBuilder.java @@ -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 blockObject, ResourceKey... creativeTabs) { + CommonEventHandler.Mod.addItemToTabs(blockObject, creativeTabs); + } +} diff --git a/forge/src/main/resources/lib39.forge.mixins.json b/forge/src/main/resources/lib39.forge.mixins.json index c953842..7f52e81 100644 --- a/forge/src/main/resources/lib39.forge.mixins.json +++ b/forge/src/main/resources/lib39.forge.mixins.json @@ -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 + } } \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 309bbc5..ca66cbf 100644 --- a/settings.gradle +++ b/settings.gradle @@ -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")