diff --git a/src/allomancy/java/leaf/cosmere/allomancy/client/gui/AllomancySpiritwebMenu.java b/src/allomancy/java/leaf/cosmere/allomancy/client/gui/AllomancySpiritwebMenu.java new file mode 100644 index 000000000..075633f39 --- /dev/null +++ b/src/allomancy/java/leaf/cosmere/allomancy/client/gui/AllomancySpiritwebMenu.java @@ -0,0 +1,106 @@ +package leaf.cosmere.allomancy.client.gui; + +import com.mojang.blaze3d.systems.RenderSystem; +import leaf.cosmere.allomancy.common.Allomancy; +import leaf.cosmere.api.Metals; +import leaf.cosmere.client.gui.CosmereScreen; +import leaf.cosmere.client.gui.SpiritwebMenu; +import leaf.cosmere.common.cap.entity.SpiritwebCapability; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import org.lwjgl.opengl.GL11; + +public class AllomancySpiritwebMenu extends CosmereScreen +{ + private static final ResourceLocation BORDER_LOCATION = new ResourceLocation(Allomancy.MODID, "textures/gui/allo_border.png"); + LocalPlayer player; + public AllomancySpiritwebMenu() + { + super(Component.literal("Allomancy"), SpiritwebMenu::selectManiCallback); + player = Minecraft.getInstance().player; + } + + @Override + protected void init() + { + super.init(); + + SpiritwebCapability.get(player).ifPresent( (iSpiritweb -> { + int circleCenterX = width/2; + int circleCenterY = height/2 + height/16; // heh, 16, nice + + // Steel + addRenderableWidget(new OuterRadialButton(circleCenterX, circleCenterY, 4, Metals.MetalType.STEEL, iSpiritweb, manifestationConsumer)); + // Iron + addRenderableWidget(new OuterRadialButton(circleCenterX, circleCenterY, 5, Metals.MetalType.IRON, iSpiritweb, manifestationConsumer)); + // Zinc + addRenderableWidget(new OuterRadialButton(circleCenterX, circleCenterY, 6, Metals.MetalType.ZINC, iSpiritweb, manifestationConsumer)); + // Brass + addRenderableWidget(new OuterRadialButton(circleCenterX, circleCenterY, 7, Metals.MetalType.BRASS, iSpiritweb, manifestationConsumer)); + // Bendalloy + addRenderableWidget(new OuterRadialButton(circleCenterX, circleCenterY, 0, Metals.MetalType.BENDALLOY, iSpiritweb, manifestationConsumer)); + // Cadmium + addRenderableWidget(new OuterRadialButton(circleCenterX, circleCenterY, 1, Metals.MetalType.CADMIUM, iSpiritweb, manifestationConsumer)); + // Chromium + addRenderableWidget(new OuterRadialButton(circleCenterX, circleCenterY, 2, Metals.MetalType.CHROMIUM, iSpiritweb, manifestationConsumer)); + // Nicrosil + addRenderableWidget(new OuterRadialButton(circleCenterX, circleCenterY, 3, Metals.MetalType.NICROSIL, iSpiritweb, manifestationConsumer)); + + // Pewter + addRenderableWidget(new InnerRadialButton(circleCenterX, circleCenterY, 4, Metals.MetalType.PEWTER, iSpiritweb, manifestationConsumer)); + // Tin + addRenderableWidget(new InnerRadialButton(circleCenterX, circleCenterY, 5, Metals.MetalType.TIN, iSpiritweb, manifestationConsumer)); + // Copper + addRenderableWidget(new InnerRadialButton(circleCenterX, circleCenterY, 6, Metals.MetalType.COPPER, iSpiritweb, manifestationConsumer)); + // Bronze + addRenderableWidget(new InnerRadialButton(circleCenterX, circleCenterY, 7, Metals.MetalType.BRONZE, iSpiritweb, manifestationConsumer)); + // Electrum + addRenderableWidget(new InnerRadialButton(circleCenterX, circleCenterY, 0, Metals.MetalType.ELECTRUM, iSpiritweb, manifestationConsumer)); + // Gold + addRenderableWidget(new InnerRadialButton(circleCenterX, circleCenterY, 1, Metals.MetalType.GOLD, iSpiritweb, manifestationConsumer)); + // Aluminum + addRenderableWidget(new InnerRadialButton(circleCenterX, circleCenterY, 2, Metals.MetalType.ALUMINUM, iSpiritweb, manifestationConsumer)); + // Duralumin + addRenderableWidget(new InnerRadialButton(circleCenterX, circleCenterY, 3, Metals.MetalType.DURALUMIN, iSpiritweb, manifestationConsumer)); + + // Atium + addRenderableWidget(new SquareButton(circleCenterX + height/4, circleCenterY + height/3 - height/16, height/8, Metals.MetalType.ATIUM, iSpiritweb, manifestationConsumer)); + })); + } + + @Override + public void render(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) + { + super.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick); + renderBorder(pGuiGraphics); + } + + private void renderBorder(GuiGraphics pGuiGraphics) + { + RenderSystem.setShaderTexture(0, BORDER_LOCATION); + RenderSystem.enableBlend(); + RenderSystem.blendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0); + RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f); + + final int diameter = Minecraft.getInstance().getWindow().getGuiScaledHeight() / 3 * 2 + 2; + final int x = width/2 - diameter/2, y = height/2 - diameter/2 + height/16; + final int iconSize = 256; + + pGuiGraphics.blit(BORDER_LOCATION, + x, + y, + diameter, + diameter, + 0, + 0, + iconSize, + iconSize, + iconSize, + iconSize); + + RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f); + } +} diff --git a/src/allomancy/java/leaf/cosmere/allomancy/client/gui/InnerRadialButton.java b/src/allomancy/java/leaf/cosmere/allomancy/client/gui/InnerRadialButton.java new file mode 100644 index 000000000..70f8a28a9 --- /dev/null +++ b/src/allomancy/java/leaf/cosmere/allomancy/client/gui/InnerRadialButton.java @@ -0,0 +1,393 @@ +package leaf.cosmere.allomancy.client.gui; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.Tesselator; +import com.mojang.blaze3d.vertex.VertexFormat; +import leaf.cosmere.allomancy.common.config.AllomancyConfigs; +import leaf.cosmere.allomancy.common.manifestation.AllomancyManifestation; +import leaf.cosmere.api.IHasMetalType; +import leaf.cosmere.api.Manifestations; +import leaf.cosmere.api.Metals; +import leaf.cosmere.api.manifestation.Manifestation; +import leaf.cosmere.api.spiritweb.ISpiritweb; +import leaf.cosmere.client.gui.GuiUtils; +import leaf.cosmere.client.gui.SpiritwebMenu; +import leaf.cosmere.common.Cosmere; +import leaf.cosmere.common.network.packets.ChangeManifestationModeMessage; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.resources.language.I18n; +import net.minecraft.network.chat.CommonComponents; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; +import org.joml.Matrix4f; +import org.lwjgl.opengl.GL11; + +import java.awt.*; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +public class InnerRadialButton extends Button +{ + private final ResourceLocation iconLocation; + private final List cachedQuads = new ArrayList<>(); + private final Consumer manifestationConsumer; + private final float outerRadius; + private final float innerRadius; + private final double startAngle; + private final double endAngle; + private final int segmentNr; + private final int centerX; + private final int centerY; + private final boolean hasManifestation; + private final Manifestation manifestation; + private final ISpiritweb spiritweb; + private final Metals.MetalType metalType; + + protected InnerRadialButton(int centerX, int centerY, int segmentNr, Metals.MetalType metal, ISpiritweb spiritweb, Consumer maniConsumer) + { + super(centerX, centerY, 16, 16, CommonComponents.EMPTY, (button) -> {}, DEFAULT_NARRATION); + this.spiritweb = spiritweb; + metalType = metal; + manifestation = Manifestations.ManifestationTypes.ALLOMANCY.getManifestation(metalType.getID()); + hasManifestation = spiritweb.hasManifestation(manifestation); + double eighthCircle = Math.toRadians(45.d); // a circle is 360 degrees, / by 8 for 45 degrees, converted to radians + this.segmentNr = segmentNr; + startAngle = segmentNr * eighthCircle; // todo: decided by power ID + endAngle = startAngle + eighthCircle; + this.centerX = centerX; + this.centerY = centerY; + + outerRadius = (float) Minecraft.getInstance().getWindow().getGuiScaledHeight() / 3f * 0.7f; + innerRadius = 0; + + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.setLength(0); + stringBuilder.append("textures/icon/") + .append(manifestation.getManifestationType().getName()) + .append("/"); + + // no need for a switch case, always allomancy + if (manifestation instanceof IHasMetalType metalType) + { + stringBuilder.append(metalType.getMetalType().getName()); + } + + stringBuilder.append(".png"); + iconLocation = new ResourceLocation(manifestation.getRegistryName().getNamespace(), stringBuilder.toString()); + + manifestationConsumer = maniConsumer; + + calculateVertexes(this.centerX, this.centerY, outerRadius, segmentNr); + } + + @Override + protected void renderWidget(@NotNull GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) + { + boolean isHover = isMouseOver(pMouseX, pMouseY); + renderSegment(pGuiGraphics, isHover); + renderIcon(pGuiGraphics); + if (isHover && hasManifestation) + { + renderInfoBlock(pGuiGraphics); + } + } + + @Override + public boolean isMouseOver(double mouseX, double mouseY) + { + boolean retVal; + double distanceX = mouseX - centerX; + double distanceY = mouseY - centerY; + double dSqr = distanceX * distanceX + distanceY * distanceY; + + if (dSqr < innerRadius * innerRadius || + dSqr > outerRadius * outerRadius) + { + return false; + } + + double angle = Math.atan2(distanceY, distanceX); + + if (angle < 0) { + angle += 2 * Math.PI; + } + + double start = normalizeAngle(startAngle); + double end = normalizeAngle(endAngle); + angle = normalizeAngle(angle); + + if (start <= end) + { + retVal = angle >= start && angle <= end; + } + else + { + retVal = angle >= start || angle <= end; + } + + if (hasManifestation) + { + if (retVal) + { + manifestationConsumer.accept(manifestation); + } + } + + return retVal; + } + + @Override + public boolean mouseClicked(double pMouseX, double pMouseY, int pButton) + { + boolean isMouseOver = isMouseOver(pMouseX, pMouseY); + if (isMouseOver && hasManifestation) + { + if (pButton == 0) + Cosmere.packetHandler().sendToServer(new ChangeManifestationModeMessage(manifestation, 1)); + else + Cosmere.packetHandler().sendToServer(new ChangeManifestationModeMessage(manifestation, -1)); + + playDownSound(Minecraft.getInstance().getSoundManager()); + } + return isMouseOver; + } + + private double normalizeAngle(double angle) + { + if (angle != 0) + { + angle = angle % (2 * Math.PI); + if (angle < 0) + { + angle += 2 * Math.PI; + } + } + return angle; + } + + private void renderSegment(GuiGraphics pGuiGraphics, boolean isHovered) + { + float r = GuiUtils.BACKGROUND_COLOR.getRed()/255.f, g = GuiUtils.BACKGROUND_COLOR.getGreen()/255.f, b = GuiUtils.BACKGROUND_COLOR.getBlue()/255.f; + float a = 1f; + + if (!hasManifestation) + { + r *= 0.6f; + g *= 0.6f; + b *= 0.6f; + } + + if (isHovered && hasManifestation) + { + r *= 1.1f; + g *= 1.1f; + b *= 1.1f; + } + + if (manifestation instanceof AllomancyManifestation allomancyManifestation) { + int mode = allomancyManifestation.getMode(spiritweb); + float intensity = Math.min(Math.abs(mode) * 0.2f, 1.0f); // Cap intensity + + if (mode > 0) { + // Blend toward pure red + r = lerp(r, 1.0f, intensity); + g = lerp(g, 0.0f, intensity); + b = lerp(b, 0.0f, intensity); + } else if (mode < 0) { + // Blend toward pure blue + r = lerp(r, 0.0f, intensity); + g = lerp(g, 0.0f, intensity); + b = lerp(b, 1.0f, intensity); + } + } + + RenderSystem.disableCull(); + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + RenderSystem.setShader(GameRenderer::getPositionColorShader); + Matrix4f pose = pGuiGraphics.pose().last().pose(); + + Tesselator tess = Tesselator.getInstance(); + BufferBuilder buf = tess.getBuilder(); + + buf.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); + + for (GuiUtils.CachedQuad quad : cachedQuads) + { + float px = quad.px(); + float py = quad.py(); + float size = quad.size(); + + buf.vertex(pose, px, py, 0).color(r, g, b, a).endVertex(); + buf.vertex(pose, px, py + size, 0).color(r, g, b, a).endVertex(); + buf.vertex(pose, px + size, py + size, 0).color(r, g, b, a).endVertex(); + buf.vertex(pose, px + size, py, 0).color(r, g, b, a).endVertex(); + } + + tess.end(); + RenderSystem.disableBlend(); + } + + private void renderIcon(@NotNull GuiGraphics pGuiGraphics) + { + Color metalColor = metalType.getColor(); + float r = metalColor.getRed()/255.f, g = metalColor.getGreen()/255.f, b = metalColor.getBlue()/255.f; + + if (!hasManifestation) + { + r *= 0.1f; + g *= 0.1f; + b *= 0.1f; + } + + float alpha = hasManifestation ? 1.0f : 0.25f; + RenderSystem.setShaderTexture(0, iconLocation); + RenderSystem.enableBlend(); + RenderSystem.blendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0); + + double midAngle = (startAngle + endAngle) / 2; + double midRadius = (innerRadius + outerRadius) / 1.5; + int iconSize = width-2; + int posX = centerX + (int)(Math.cos(midAngle) * midRadius) - iconSize/2; + int posY = centerY + (int)(Math.sin(midAngle) * midRadius) - iconSize/2; + + RenderSystem.setShaderColor(0f, 0f, 0f, alpha); + pGuiGraphics.blit(iconLocation, + posX+1, + posY+1, + iconSize, + iconSize, + 0, + 0, + width, + height, + width, + height); + + RenderSystem.setShaderColor(r, g, b, alpha); + pGuiGraphics.blit(iconLocation, + posX, + posY, + iconSize, + iconSize, + 0, + 0, + width, + height, + width, + height); + + RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f); + } + + private void renderInfoBlock(GuiGraphics pGuiGraphics) + { + Font font = Minecraft.getInstance().font; + int screenWidth = Minecraft.getInstance().getWindow().getGuiScaledWidth(); + int screenHeight = Minecraft.getInstance().getWindow().getGuiScaledHeight(); + int x = 0; + int y = 0; + int width = GuiUtils.getInfoBoxWidth(Minecraft.getInstance()); + int height = GuiUtils.getInfoBoxHeight(Minecraft.getInstance()); + int color = 0x99333333; + + if (segmentNr <= 1) + { + // bottom right display + x = screenWidth - width - 10; + y = screenHeight - height - 10; + } + else if (segmentNr <= 3) + { + // bottom left display + x = 10; + y = screenHeight - height - 10; + } + else if (segmentNr <= 5) + { + // top left display + x = 10; + y = 10; + } + else if (segmentNr <= 7) + { + // top right display + x = screenWidth - width - 10; + y = 10; + } + + RenderSystem.disableCull(); + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + + pGuiGraphics.fill(x, y, x + width, y + height, color); + + String text = I18n.get(manifestation.getTranslationKey()); + float scale = 0.8f; + GuiUtils.drawScaledString(font, pGuiGraphics, text, x+5, y+10, scale, 0xFFFFFFFF); + + int seconds = manifestation.getInvestitureRemaining(spiritweb); + int hours = seconds / 3600; + int minutes = (seconds % 3600) / 60; + seconds = seconds % 60; + + if (hours > 0) + text = String.format("%d:%02d:%02d", hours, minutes, seconds); + else if (minutes > 0) + text = String.format("%d:%02d", minutes, seconds); + else if (seconds > 0) + text = String.format("%02d", seconds); + else + text = "Empty"; + + GuiUtils.drawScaledString(font, pGuiGraphics, text, x+5, y+12+font.lineHeight*scale, scale, 0xFFFFFFFF); + } + + private void calculateVertexes(float centerX, float centerY, float outerRadius, int segmentNr) + { + cachedQuads.clear(); + + float radsPerSegment = (float) Math.PI * 2 / 8; + float startAngle = segmentNr * radsPerSegment; + float radiusSq = outerRadius * outerRadius; + + int pixelSize = AllomancyConfigs.CLIENT.pixelationAmount.get(); + int rInt = (int) Math.ceil(outerRadius); + + for (int x = -rInt; x <= rInt; x += pixelSize) + { + for (int y = -rInt; y <= rInt; y += pixelSize) + { + float pixelCenterX = x + (pixelSize / 2f); + float pixelCenterY = y + (pixelSize / 2f); + + float distSq = pixelCenterX * pixelCenterX + pixelCenterY * pixelCenterY; + + if (distSq <= radiusSq) + { + float angle = (float) Math.atan2(pixelCenterY, pixelCenterX); + if (angle < 0) angle += (float) (Math.PI * 2); + + float diff = angle - startAngle; + if (diff < 0) diff += (float) (Math.PI * 2); + + if (diff < radsPerSegment) + { + cachedQuads.add(new GuiUtils.CachedQuad(centerX + x, centerY + y, pixelSize)); + } + } + } + } + } + + public float lerp(float start, float end, float pct) { + return start + pct * (end - start); + } +} diff --git a/src/allomancy/java/leaf/cosmere/allomancy/client/gui/OuterRadialButton.java b/src/allomancy/java/leaf/cosmere/allomancy/client/gui/OuterRadialButton.java new file mode 100644 index 000000000..4cc6531f4 --- /dev/null +++ b/src/allomancy/java/leaf/cosmere/allomancy/client/gui/OuterRadialButton.java @@ -0,0 +1,406 @@ +package leaf.cosmere.allomancy.client.gui; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.Tesselator; +import com.mojang.blaze3d.vertex.VertexFormat; +import leaf.cosmere.allomancy.common.config.AllomancyConfigs; +import leaf.cosmere.allomancy.common.manifestation.AllomancyManifestation; +import leaf.cosmere.api.IHasMetalType; +import leaf.cosmere.api.Manifestations; +import leaf.cosmere.api.Metals; +import leaf.cosmere.api.manifestation.Manifestation; +import leaf.cosmere.api.spiritweb.ISpiritweb; +import leaf.cosmere.client.gui.GuiUtils; +import leaf.cosmere.client.gui.SpiritwebMenu; +import leaf.cosmere.common.Cosmere; +import leaf.cosmere.common.network.packets.ChangeManifestationModeMessage; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.resources.language.I18n; +import net.minecraft.client.sounds.SoundManager; +import net.minecraft.network.chat.CommonComponents; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; +import org.joml.Matrix4f; +import org.lwjgl.opengl.GL11; + +import java.awt.Color; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +public class OuterRadialButton extends Button +{ + private final ResourceLocation iconLocation; + private final List cachedQuads = new ArrayList<>(); + private final Consumer manifestationConsumer; + private final float outerRadius; + private final float innerRadius; + private final double startAngle; + private final double endAngle; + private final int segmentNr; + private final int centerX; + private final int centerY; + private final boolean hasManifestation; + private final Manifestation manifestation; + private final ISpiritweb spiritweb; + private final Metals.MetalType metalType; + + protected OuterRadialButton(int centerX, int centerY, int segmentNr, Metals.MetalType metal, ISpiritweb spiritweb, Consumer maniConsumer) + { + super(centerX, centerY, 16, 16, CommonComponents.EMPTY, (button) -> {}, DEFAULT_NARRATION); + this.spiritweb = spiritweb; + metalType = metal; + manifestation = Manifestations.ManifestationTypes.ALLOMANCY.getManifestation(metalType.getID()); + hasManifestation = this.spiritweb.hasManifestation(manifestation); + double eighthCircle = Math.toRadians(45.d); // a circle is 360 degrees, / by 8 for 45 degrees, converted to radians + this.segmentNr = segmentNr; // MetalType doesn't align with the chart in a pattern that can be programmatically written out; we do this manually + startAngle = segmentNr * eighthCircle; + endAngle = startAngle + eighthCircle; + this.centerX = centerX; + this.centerY = centerY; + + outerRadius = (float) Minecraft.getInstance().getWindow().getGuiScaledHeight() / 3; + innerRadius = outerRadius * 0.7f; + + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.setLength(0); + stringBuilder.append("textures/icon/") + .append(manifestation.getManifestationType().getName()) + .append("/"); + + // no need for a switch case, always allomancy + if (manifestation instanceof IHasMetalType metalType) + { + stringBuilder.append(metalType.getMetalType().getName()); + } + + stringBuilder.append(".png"); + iconLocation = new ResourceLocation(manifestation.getRegistryName().getNamespace(), stringBuilder.toString()); + + manifestationConsumer = maniConsumer; + + calculateVertexes(this.centerX, this.centerY, innerRadius, outerRadius, segmentNr); + } + + @Override + protected void renderWidget(@NotNull GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) + { + boolean isHover =isMouseOver(pMouseX, pMouseY); + renderSegment(pGuiGraphics, isHover); + renderIcon(pGuiGraphics); + if (isHover && hasManifestation) + { + renderInfoBlock(pGuiGraphics); + } + } + + @Override + public boolean isMouseOver(double mouseX, double mouseY) + { + boolean retVal; + double distanceX = mouseX - centerX; + double distanceY = mouseY - centerY; + double dSqr = distanceX * distanceX + distanceY * distanceY; + + if (dSqr < innerRadius * innerRadius || + dSqr > outerRadius * outerRadius) + { + return false; + } + + double angle = Math.atan2(distanceY, distanceX); + + if (angle < 0) { + angle += 2 * Math.PI; + } + + double start = normalizeAngle(startAngle); + double end = normalizeAngle(endAngle); + angle = normalizeAngle(angle); + + if (start <= end) { + retVal = angle >= start && angle <= end; + } else { + retVal = angle >= start || angle <= end; + } + + if (hasManifestation) + { + if (retVal) + { + manifestationConsumer.accept(manifestation); + } + } + + return retVal; + } + + @Override + public boolean mouseClicked(double pMouseX, double pMouseY, int pButton) + { + boolean isMouseOver = isMouseOver(pMouseX, pMouseY); + if (isMouseOver && hasManifestation) + { + if (pButton == 0) + Cosmere.packetHandler().sendToServer(new ChangeManifestationModeMessage(manifestation, 1)); + else + Cosmere.packetHandler().sendToServer(new ChangeManifestationModeMessage(manifestation, -1)); + + playDownSound(Minecraft.getInstance().getSoundManager()); + } + return isMouseOver; + } + + @Override + public void playDownSound(SoundManager pHandler) + { + super.playDownSound(pHandler); + } + + private double normalizeAngle(double angle) + { + if (angle != 0) + { + angle = angle % (2 * Math.PI); + if (angle < 0) + { + angle += 2 * Math.PI; + } + } + return angle; + } + + private void renderSegment(@NotNull GuiGraphics pGuiGraphics, boolean isHovered) + { + float r = GuiUtils.BACKGROUND_COLOR.getRed()/255.f, g = GuiUtils.BACKGROUND_COLOR.getGreen()/255.f, b = GuiUtils.BACKGROUND_COLOR.getBlue()/255.f; + float a = 1f; + + if (!hasManifestation) + { + r *= 0.6f; + g *= 0.6f; + b *= 0.6f; + } + + if (isHovered && hasManifestation) + { + r *= 1.1f; + g *= 1.1f; + b *= 1.1f; + } + + if (manifestation instanceof AllomancyManifestation allomancyManifestation) { + int mode = allomancyManifestation.getMode(spiritweb); + float intensity = Math.min(Math.abs(mode) * 0.2f, 1.0f); // Cap intensity + + if (mode > 0) { + // Blend toward pure red + r = lerp(r, 1.0f, intensity); + g = lerp(g, 0.0f, intensity); + b = lerp(b, 0.0f, intensity); + } else if (mode < 0) { + // Blend toward pure blue + r = lerp(r, 0.0f, intensity); + g = lerp(g, 0.0f, intensity); + b = lerp(b, 1.0f, intensity); + } + } + + RenderSystem.disableCull(); + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + RenderSystem.setShader(GameRenderer::getPositionColorShader); + Matrix4f pose = pGuiGraphics.pose().last().pose(); + + Tesselator tess = Tesselator.getInstance(); + BufferBuilder buf = tess.getBuilder(); + + buf.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); + + for (GuiUtils.CachedQuad quad : cachedQuads) + { + float px = quad.px(); + float py = quad.py(); + float size = quad.size(); + + buf.vertex(pose, px, py, 0).color(r, g, b, a).endVertex(); + buf.vertex(pose, px, py + size, 0).color(r, g, b, a).endVertex(); + buf.vertex(pose, px + size, py + size, 0).color(r, g, b, a).endVertex(); + buf.vertex(pose, px + size, py, 0).color(r, g, b, a).endVertex(); + } + + tess.end(); + RenderSystem.disableBlend(); + } + + private void renderIcon(@NotNull GuiGraphics pGuiGraphics) + { + Color metalColor = metalType.getColor(); + float r = metalColor.getRed()/255.f, g = metalColor.getGreen()/255.f, b = metalColor.getBlue()/255.f; + + if (!hasManifestation) + { + r *= 0.1f; + g *= 0.1f; + b *= 0.1f; + } + + float alpha = hasManifestation ? 1.0f : 0.25f; + RenderSystem.setShaderTexture(0, iconLocation); + + RenderSystem.enableBlend(); + RenderSystem.blendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0); + + double midAngle = (startAngle + endAngle) / 2; + double midRadius = (innerRadius + outerRadius) / 2.0; + int iconSize = width - 2; + int posX = centerX + (int)(Math.cos(midAngle) * midRadius) - iconSize/2; + int posY = centerY + (int)(Math.sin(midAngle) * midRadius) - iconSize/2; + + RenderSystem.setShaderColor(0f, 0f, 0f, alpha); + pGuiGraphics.blit(iconLocation, + posX+1, + posY+1, + iconSize, + iconSize, + 0, + 0, + width, + height, + width, + height); + + RenderSystem.setShaderColor(r, g, b, alpha); + pGuiGraphics.blit(iconLocation, + posX, + posY, + iconSize, + iconSize, + 0, + 0, + width, + height, + width, + height); + + RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f); + } + + private void renderInfoBlock(GuiGraphics pGuiGraphics) + { + Font font = Minecraft.getInstance().font; + int screenWidth = Minecraft.getInstance().getWindow().getGuiScaledWidth(); + int screenHeight = Minecraft.getInstance().getWindow().getGuiScaledHeight(); + int x = 0; + int y = 0; + int width = GuiUtils.getInfoBoxWidth(Minecraft.getInstance()); + int height = GuiUtils.getInfoBoxHeight(Minecraft.getInstance()); + int color = 0x99333333; + + if (segmentNr <= 1) + { + // bottom right display + x = screenWidth - width - 10; + y = screenHeight - height - 10; + } + else if (segmentNr <= 3) + { + // bottom left display + x = 10; + y = screenHeight - height - 10; + } + else if (segmentNr <= 5) + { + // top left display + x = 10; + y = 10; + } + else if (segmentNr <= 7) + { + // top right display + x = screenWidth - width - 10; + y = 10; + } + + RenderSystem.disableCull(); + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + + pGuiGraphics.fill(x, y, x + width, y + height, color); + + String text = I18n.get(manifestation.getTranslationKey()); + float scale = 0.8f; + GuiUtils.drawScaledString(font, pGuiGraphics, text, x+5, y+10, scale, 0xFFFFFFFF); + + int seconds = manifestation.getInvestitureRemaining(spiritweb); + int hours = seconds / 3600; + int minutes = (seconds % 3600) / 60; + seconds = seconds % 60; + + if (hours > 0) + text = String.format("%d:%02d:%02d", hours, minutes, seconds); + else if (minutes > 0) + text = String.format("%d:%02d", minutes, seconds); + else if (seconds > 0) + text = String.format("%02d", seconds); + else + text = "Empty"; + + GuiUtils.drawScaledString(font, pGuiGraphics, text, x+5, y+12+font.lineHeight*scale, scale, 0xFFFFFFFF); + } + + private void calculateVertexes(float centerX, float centerY, float innerRadius, float outerRadius, int segmentNr) + { + cachedQuads.clear(); + + float radsPerSegment = (float) Math.PI * 2 / 8; + float startAngle = segmentNr * radsPerSegment; + + float outerRadiusSq = outerRadius * outerRadius; + float innerRadiusSq = innerRadius * innerRadius; + + // Fetched once during construction + int pixelSize = AllomancyConfigs.CLIENT.pixelationAmount.get(); + int rInt = (int) Math.ceil(outerRadius); + + for (int x = -rInt; x <= rInt; x += pixelSize) + { + for (int y = -rInt; y <= rInt; y += pixelSize) + { + float pixelCenterX = x + (pixelSize / 2f); + float pixelCenterY = y + (pixelSize / 2f); + + float distSq = pixelCenterX * pixelCenterX + pixelCenterY * pixelCenterY; + + if (distSq <= outerRadiusSq && distSq >= innerRadiusSq) + { + float angle = (float) Math.atan2(pixelCenterY, pixelCenterX); + if (angle < 0) angle += (float) (Math.PI * 2); + + float diff = angle - startAngle; + if (diff < 0) diff += (float) (Math.PI * 2); + + if (diff < radsPerSegment) + { + float px = centerX + x; + float py = centerY + y; + + // Cache only what the render loop strictly needs + cachedQuads.add(new GuiUtils.CachedQuad(px, py, pixelSize)); + } + } + } + } + } + + public float lerp(float start, float end, float pct) + { + return start + pct * (end - start); + } +} diff --git a/src/allomancy/java/leaf/cosmere/allomancy/client/gui/SquareButton.java b/src/allomancy/java/leaf/cosmere/allomancy/client/gui/SquareButton.java new file mode 100644 index 000000000..9afd0c3d0 --- /dev/null +++ b/src/allomancy/java/leaf/cosmere/allomancy/client/gui/SquareButton.java @@ -0,0 +1,280 @@ +package leaf.cosmere.allomancy.client.gui; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.Tesselator; +import com.mojang.blaze3d.vertex.VertexFormat; +import leaf.cosmere.allomancy.common.manifestation.AllomancyManifestation; +import leaf.cosmere.api.IHasMetalType; +import leaf.cosmere.api.ISpiritwebSubmodule; +import leaf.cosmere.api.Manifestations; +import leaf.cosmere.api.Metals; +import leaf.cosmere.api.manifestation.Manifestation; +import leaf.cosmere.api.spiritweb.ISpiritweb; +import leaf.cosmere.client.gui.GuiUtils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.resources.language.I18n; +import net.minecraft.network.chat.CommonComponents; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import org.joml.Matrix4f; +import org.lwjgl.opengl.GL11; + +import java.awt.*; +import java.util.function.Consumer; + +public class SquareButton extends Button +{ + private final ResourceLocation iconLocation; + private final Consumer manifestationConsumer; + private final ISpiritweb spiritweb; + private final Metals.MetalType metalType; + private final Manifestation manifestation; + private final boolean hasManifestation; + + protected SquareButton(int pX, int pY, int pSize, Metals.MetalType metal, ISpiritweb spiritweb, Consumer maniConsumer) + { + super(pX, pY, pSize, pSize, CommonComponents.EMPTY, (button -> { }), DEFAULT_NARRATION); + + metalType = metal; + manifestation = Manifestations.ManifestationTypes.ALLOMANCY.getManifestation(metalType.getID()); + hasManifestation = spiritweb.hasManifestation(manifestation); + this.spiritweb = spiritweb; + manifestationConsumer = maniConsumer; + + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.setLength(0); + stringBuilder.append("textures/icon/") + .append(manifestation.getManifestationType().getName()) + .append("/"); + + // no need for a switch case, always allomancy + if (manifestation instanceof IHasMetalType metalType) + { + stringBuilder.append(metalType.getMetalType().getName()); + } + + stringBuilder.append(".png"); + iconLocation = new ResourceLocation(manifestation.getRegistryName().getNamespace(), stringBuilder.toString()); + } + + @Override + public void render(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) + { + boolean isHovered = isMouseOver(pMouseX, pMouseY); + + renderBackground(pGuiGraphics, isHovered); + renderIcon(pGuiGraphics); + renderBorder(pGuiGraphics); + if (isHovered) + { + if (hasManifestation) + renderInfoBlock(pGuiGraphics); + manifestationConsumer.accept(manifestation); + } + } + + private void renderBackground(GuiGraphics pGuiGraphics, boolean isHovered) + { + float r = GuiUtils.BACKGROUND_COLOR.getRed()/255.f, g = GuiUtils.BACKGROUND_COLOR.getGreen()/255.f, b = GuiUtils.BACKGROUND_COLOR.getBlue()/255.f; + float a = 1f; + + if (!hasManifestation) + { + r *= 0.6f; + g *= 0.6f; + b *= 0.6f; + } + + if (isHovered && hasManifestation) + { + r *= 1.1f; + g *= 1.1f; + b *= 1.1f; + } + + if (manifestation instanceof AllomancyManifestation allomancyManifestation) { + int mode = allomancyManifestation.getMode(spiritweb); + float intensity = Math.min(Math.abs(mode) * 0.2f, 1.0f); // Cap intensity + + if (mode > 0) { + // Blend toward pure red + r = lerp(r, 1.0f, intensity); + g = lerp(g, 0.0f, intensity); + b = lerp(b, 0.0f, intensity); + } else if (mode < 0) { + // Blend toward pure blue + r = lerp(r, 0.0f, intensity); + g = lerp(g, 0.0f, intensity); + b = lerp(b, 1.0f, intensity); + } + } + + RenderSystem.disableCull(); + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + RenderSystem.setShader(GameRenderer::getPositionColorShader); + Matrix4f pose = pGuiGraphics.pose().last().pose(); + + Tesselator tess = Tesselator.getInstance(); + BufferBuilder buf = tess.getBuilder(); + + buf.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); + + buf.vertex(pose, getX(), getY(), 0).color(r, g, b, a).endVertex(); + buf.vertex(pose, getX()+getWidth(), getY(), 0).color(r, g, b, a).endVertex(); + buf.vertex(pose, getX()+getWidth(), getY()+getHeight(), 0).color(r, g, b, a).endVertex(); + buf.vertex(pose, getX(), getY()+getHeight(), 0).color(r, g, b, a).endVertex(); + + tess.end(); + RenderSystem.disableBlend(); + } + + private void renderBorder(GuiGraphics pGuiGraphics) + { + int color = 0xff9badb7; + int thickness = 1; + RenderSystem.disableCull(); + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + RenderSystem.setShader(GameRenderer::getPositionColorShader); + Matrix4f pose = pGuiGraphics.pose().last().pose(); + + Tesselator tess = Tesselator.getInstance(); + BufferBuilder buf = tess.getBuilder(); + + buf.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); + + int x = getX(); + int y = getY(); + int w = getWidth(); + int h = getHeight(); + + // Top edge + buf.vertex(pose, x, y, 0).color(color).endVertex(); + buf.vertex(pose, x + w, y, 0).color(color).endVertex(); + buf.vertex(pose, x + w, y + thickness, 0).color(color).endVertex(); + buf.vertex(pose, x, y + thickness, 0).color(color).endVertex(); + + // Bottom edge + buf.vertex(pose, x, y + h - thickness, 0).color(color).endVertex(); + buf.vertex(pose, x + w, y + h - thickness, 0).color(color).endVertex(); + buf.vertex(pose, x + w, y + h, 0).color(color).endVertex(); + buf.vertex(pose, x, y + h, 0).color(color).endVertex(); + + // Left edge + buf.vertex(pose, x, y + thickness, 0).color(color).endVertex(); + buf.vertex(pose, x + thickness, y + thickness, 0).color(color).endVertex(); + buf.vertex(pose, x + thickness, y + h - thickness, 0).color(color).endVertex(); + buf.vertex(pose, x, y + h - thickness, 0).color(color).endVertex(); + + // Right edge + buf.vertex(pose, x + w - thickness, y + thickness, 0).color(color).endVertex(); + buf.vertex(pose, x + w, y + thickness, 0).color(color).endVertex(); + buf.vertex(pose, x + w, y + h - thickness, 0).color(color).endVertex(); + buf.vertex(pose, x + w - thickness, y + h - thickness, 0).color(color).endVertex(); + + tess.end(); + RenderSystem.disableBlend(); + } + + private void renderIcon(GuiGraphics pGuiGraphics) + { + Color metalColor = metalType.getColor(); + float r = metalColor.getRed()/255.f, g = metalColor.getGreen()/255.f, b = metalColor.getBlue()/255.f; + + if (!hasManifestation) + { + r *= 0.1f; + g *= 0.1f; + b *= 0.1f; + } + + float alpha = hasManifestation ? 1.0f : 0.25f; + RenderSystem.setShaderTexture(0, iconLocation); + RenderSystem.enableBlend(); + RenderSystem.blendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0); + + int iconSize = width-10; + int posX = getX() + 5; + int posY = getY() + 5; + + RenderSystem.setShaderColor(0f, 0f, 0f, alpha); + pGuiGraphics.blit(iconLocation, + posX+1, + posY+1, + iconSize, + iconSize, + 0, + 0, + width, + height, + width, + height); + + RenderSystem.setShaderColor(r, g, b, alpha); + pGuiGraphics.blit(iconLocation, + posX, + posY, + iconSize, + iconSize, + 0, + 0, + width, + height, + width, + height); + + RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f); + } + + private void renderInfoBlock(GuiGraphics pGuiGraphics) + { + Font font = Minecraft.getInstance().font; + int screenWidth = Minecraft.getInstance().getWindow().getGuiScaledWidth(); + int screenHeight = Minecraft.getInstance().getWindow().getGuiScaledHeight(); + int x = 0; + int y = 0; + int width = GuiUtils.getInfoBoxWidth(Minecraft.getInstance()); + int height = GuiUtils.getInfoBoxHeight(Minecraft.getInstance()); + int color = 0x99333333; + + x = screenWidth - width - 10; + y = screenHeight - height - 10; + + RenderSystem.disableCull(); + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + + pGuiGraphics.fill(x, y, x + width, y + height, color); + + String text = I18n.get(manifestation.getTranslationKey()); + float scale = 0.8f; + GuiUtils.drawScaledString(font, pGuiGraphics, text, x+5, y+10, scale, 0xFFFFFFFF); + + int seconds = manifestation.getInvestitureRemaining(spiritweb); + int hours = seconds / 3600; + int minutes = (seconds % 3600) / 60; + seconds = seconds % 60; + + if (hours > 0) + text = String.format("%d:%02d:%02d", hours, minutes, seconds); + else if (minutes > 0) + text = String.format("%d:%02d", minutes, seconds); + else if (seconds > 0) + text = String.format("%02d", seconds); + else + text = "Empty"; + + GuiUtils.drawScaledString(font, pGuiGraphics, text, x+5, y+12+font.lineHeight*scale, scale, 0xFFFFFFFF); + } + + public float lerp(float start, float end, float pct) { + return start + pct * (end - start); + } +} diff --git a/src/allomancy/java/leaf/cosmere/allomancy/common/capabilities/AllomancySpiritwebSubmodule.java b/src/allomancy/java/leaf/cosmere/allomancy/common/capabilities/AllomancySpiritwebSubmodule.java index 665bfedae..ecba0aad6 100644 --- a/src/allomancy/java/leaf/cosmere/allomancy/common/capabilities/AllomancySpiritwebSubmodule.java +++ b/src/allomancy/java/leaf/cosmere/allomancy/common/capabilities/AllomancySpiritwebSubmodule.java @@ -5,6 +5,7 @@ package leaf.cosmere.allomancy.common.capabilities; import com.mojang.blaze3d.vertex.PoseStack; +import leaf.cosmere.allomancy.client.gui.AllomancySpiritwebMenu; import leaf.cosmere.allomancy.client.metalScanning.IronSteelLinesThread; import leaf.cosmere.allomancy.client.metalScanning.ScanResult; import leaf.cosmere.allomancy.common.Allomancy; @@ -23,7 +24,9 @@ import leaf.cosmere.api.helpers.PlayerHelper; import leaf.cosmere.api.manifestation.Manifestation; import leaf.cosmere.api.spiritweb.ISpiritweb; +import leaf.cosmere.common.cap.entity.SpiritwebCapability; import leaf.cosmere.common.registration.impl.AttributeRegistryObject; +import leaf.cosmere.client.gui.SpiritwebRegistry; import net.minecraft.client.Minecraft; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.entity.ai.attributes.Attribute; @@ -308,23 +311,6 @@ public void renderWorldEffects(ISpiritweb spiritweb, RenderLevelStageEvent event } } - @Override - @OnlyIn(Dist.CLIENT) - public void collectMenuInfo(List m_infoText) - { - for (Metals.MetalType metalType : EnumUtils.METAL_TYPES) - { - int value = METALS_INGESTED.get(metalType); - - if (value > 0) - { - //todo localisation check - final String text = "A. " + metalType.getName() + ": " + value; - m_infoText.add(text); - } - } - } - @Override public void GiveStartingItem(Player player) { @@ -354,6 +340,16 @@ public List getPowers() .map((AttributeRegistryObject::getAttribute)).collect(Collectors.toList()); } + @Override + @OnlyIn(Dist.CLIENT) + public void registerMenu() + { + SpiritwebCapability.get(Minecraft.getInstance().player).ifPresent( (spiritweb) -> { + if (spiritweb.hasManifestationOfType(Manifestations.ManifestationTypes.ALLOMANCY)) + SpiritwebRegistry.getInstance().register(Manifestations.ManifestationTypes.ALLOMANCY, AllomancySpiritwebMenu::new); + }); + } + public int getIngestedMetal(Metals.MetalType metalType) { return METALS_INGESTED.get(metalType); @@ -363,7 +359,7 @@ public boolean adjustIngestedMetal(Metals.MetalType metalType, int amountToAdjus { int ingestedMetal = getIngestedMetal(metalType); - final int newValue = ingestedMetal + amountToAdjust; + final int newValue = Math.min(ingestedMetal + amountToAdjust, AllomancyConfigs.SERVER.MAX_INGESTIBLE_METAL.get()); if (newValue >= 0) { if (doAdjust) diff --git a/src/allomancy/java/leaf/cosmere/allomancy/common/commands/subcommands/FillMetalReservesCommand.java b/src/allomancy/java/leaf/cosmere/allomancy/common/commands/subcommands/FillMetalReservesCommand.java index 65dac247c..26b4a54dc 100644 --- a/src/allomancy/java/leaf/cosmere/allomancy/common/commands/subcommands/FillMetalReservesCommand.java +++ b/src/allomancy/java/leaf/cosmere/allomancy/common/commands/subcommands/FillMetalReservesCommand.java @@ -9,6 +9,7 @@ import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import leaf.cosmere.allomancy.common.capabilities.AllomancySpiritwebSubmodule; +import leaf.cosmere.allomancy.common.config.AllomancyConfigs; import leaf.cosmere.api.EnumUtils; import leaf.cosmere.api.Manifestations; import leaf.cosmere.api.Metals; @@ -53,7 +54,7 @@ private static int fillReserves(CommandContext context) thro final Manifestation manifestation = Manifestations.ManifestationTypes.ALLOMANCY.getManifestation(metalTypeID); if (spiritweb.hasManifestation(manifestation)) { - asm.adjustIngestedMetal(metalType, 999999, true); + asm.adjustIngestedMetal(metalType, AllomancyConfigs.SERVER.MAX_INGESTIBLE_METAL.get(), true); } } } diff --git a/src/allomancy/java/leaf/cosmere/allomancy/common/config/AllomancyClientConfig.java b/src/allomancy/java/leaf/cosmere/allomancy/common/config/AllomancyClientConfig.java index cffb21306..969764109 100644 --- a/src/allomancy/java/leaf/cosmere/allomancy/common/config/AllomancyClientConfig.java +++ b/src/allomancy/java/leaf/cosmere/allomancy/common/config/AllomancyClientConfig.java @@ -14,6 +14,7 @@ public class AllomancyClientConfig implements ICosmereConfig public final ForgeConfigSpec.BooleanValue drawMetalLines; public final ForgeConfigSpec.BooleanValue drawMetalBoxes; public final ForgeConfigSpec.BooleanValue canHearRain; + public final ForgeConfigSpec.IntValue pixelationAmount; AllomancyClientConfig() { @@ -23,6 +24,7 @@ public class AllomancyClientConfig implements ICosmereConfig drawMetalLines = builder.comment("Iron/Steel vision draws metal lines between the user and the source of metal").define("drawMetalLines", true); drawMetalBoxes = builder.comment("Iron/Steel vision draws a blue box overlay over blocks that contain metal").define("drawMetalBoxes", true); canHearRain = builder.comment("Allomantic Tin picks up rain sounds, generating a sculk particle to player and showing an image at position of sound").define("canHearRain", true); + pixelationAmount = builder.comment("Amount of pixelation on the Allomancy power wheel").defineInRange("pixelationAmount", 1, 1, 10); builder.pop(); configSpec = builder.build(); diff --git a/src/allomancy/java/leaf/cosmere/allomancy/common/config/AllomancyServerConfig.java b/src/allomancy/java/leaf/cosmere/allomancy/common/config/AllomancyServerConfig.java index 01d4dff52..a928bf03b 100644 --- a/src/allomancy/java/leaf/cosmere/allomancy/common/config/AllomancyServerConfig.java +++ b/src/allomancy/java/leaf/cosmere/allomancy/common/config/AllomancyServerConfig.java @@ -16,6 +16,7 @@ public class AllomancyServerConfig implements ICosmereConfig public final ForgeConfigSpec.DoubleValue IRON_STEEL_RANGE; public final ForgeConfigSpec.DoubleValue PUSH_PULL_WEIGHT; public final ForgeConfigSpec.DoubleValue MAX_PUSH_PULL_WEIGHT; + public final ForgeConfigSpec.IntValue MAX_INGESTIBLE_METAL; // Boost amount for Duralumin and Nicrosil //public final ForgeConfigSpec.DoubleValue boostAmount; @@ -35,6 +36,8 @@ public class AllomancyServerConfig implements ICosmereConfig PUSH_PULL_WEIGHT = builder.comment("Push/pull weight adjustment per block.").defineInRange("pushPullWeight", 0.05D, 0.01D, 100.0D); MAX_PUSH_PULL_WEIGHT = builder.comment("Maximum pull/push weight adjustment. At 1.0 (default), push/pull power maxes out at 2 times (20 blocks)").defineInRange("maxPushPullWeight", 1.0D, 0D, 999999.0D); + MAX_INGESTIBLE_METAL = builder.comment("Maximum amount of metal possible to ingest in seconds").defineInRange("maxIngestibleMetal", 7200, 1, 999999); + builder.pop(); configSpec = builder.build(); } diff --git a/src/allomancy/java/leaf/cosmere/allomancy/common/manifestation/AllomancyManifestation.java b/src/allomancy/java/leaf/cosmere/allomancy/common/manifestation/AllomancyManifestation.java index 118f3fc0a..87f77d0c4 100644 --- a/src/allomancy/java/leaf/cosmere/allomancy/common/manifestation/AllomancyManifestation.java +++ b/src/allomancy/java/leaf/cosmere/allomancy/common/manifestation/AllomancyManifestation.java @@ -6,6 +6,7 @@ import leaf.cosmere.allomancy.client.AllomancyKeybindings; import leaf.cosmere.allomancy.common.capabilities.AllomancySpiritwebSubmodule; +import leaf.cosmere.allomancy.common.config.AllomancyConfigs; import leaf.cosmere.allomancy.common.registries.AllomancyStats; import leaf.cosmere.api.CosmereAPI; import leaf.cosmere.api.IHasMetalType; @@ -260,4 +261,19 @@ public int getRange(ISpiritweb data) final int mode = Math.max(getMode(data), 0); return Mth.floor(allomanticStrength * mode); } + + @Override + public float getInvestitureHud(ISpiritweb spiritweb) + { + AllomancySpiritwebSubmodule allo = (AllomancySpiritwebSubmodule) spiritweb.getSubmodule(Manifestations.ManifestationTypes.ALLOMANCY); + final float retVal = (float)allo.getIngestedMetal(metalType)/AllomancyConfigs.SERVER.MAX_INGESTIBLE_METAL.get(); + return retVal; + } + + @Override + public int getInvestitureRemaining(ISpiritweb spiritweb) + { + AllomancySpiritwebSubmodule allo = (AllomancySpiritwebSubmodule) spiritweb.getSubmodule(Manifestations.ManifestationTypes.ALLOMANCY); + return allo.getIngestedMetal(metalType); + } } diff --git a/src/allomancy/resources/assets/allomancy/textures/gui/allo_border.png b/src/allomancy/resources/assets/allomancy/textures/gui/allo_border.png new file mode 100644 index 000000000..90c5d4544 Binary files /dev/null and b/src/allomancy/resources/assets/allomancy/textures/gui/allo_border.png differ diff --git a/src/aondor/java/leaf/cosmere/aondor/common/capabilities/AonDorSpiritwebSubmodule.java b/src/aondor/java/leaf/cosmere/aondor/common/capabilities/AonDorSpiritwebSubmodule.java index a0fa4caf0..d655bee35 100644 --- a/src/aondor/java/leaf/cosmere/aondor/common/capabilities/AonDorSpiritwebSubmodule.java +++ b/src/aondor/java/leaf/cosmere/aondor/common/capabilities/AonDorSpiritwebSubmodule.java @@ -10,8 +10,6 @@ import net.minecraft.world.entity.player.Player; import net.minecraftforge.client.event.RenderLevelStageEvent; -import java.util.List; - public class AonDorSpiritwebSubmodule implements ISpiritwebSubmodule { @Override @@ -38,12 +36,6 @@ public void tickServer(ISpiritweb spiritweb) } - @Override - public void collectMenuInfo(List m_infoText) - { - - } - @Override public void renderWorldEffects(ISpiritweb spiritweb, RenderLevelStageEvent event) { diff --git a/src/api/java/leaf/cosmere/api/ISpiritwebSubmodule.java b/src/api/java/leaf/cosmere/api/ISpiritwebSubmodule.java index f7dc690af..6baf79060 100644 --- a/src/api/java/leaf/cosmere/api/ISpiritwebSubmodule.java +++ b/src/api/java/leaf/cosmere/api/ISpiritwebSubmodule.java @@ -40,10 +40,6 @@ default void renderWorldEffects(ISpiritweb spiritweb, RenderLevelStageEvent even { } - default void collectMenuInfo(List m_infoText) - { - } - //give a random starting item from this power set default void GiveStartingItem(Player player) { @@ -56,7 +52,11 @@ default void GiveStartingItem(Player player, Manifestation manifestation) default void resetOnDeath(ISpiritweb spiritweb) { + } + @OnlyIn(Dist.CLIENT) + default void registerMenu() + { } void drainInvestiture(ISpiritweb data, double strength); diff --git a/src/api/java/leaf/cosmere/api/Manifestations.java b/src/api/java/leaf/cosmere/api/Manifestations.java index 4a22d931f..bd3db163d 100644 --- a/src/api/java/leaf/cosmere/api/Manifestations.java +++ b/src/api/java/leaf/cosmere/api/Manifestations.java @@ -109,6 +109,24 @@ public Manifestation getManifestation(int powerID) } return CosmereAPI.manifestationRegistry().getValue(new ResourceLocation("cosmere", "none")); } + + public int getNumberOfManifestations() + { + switch (this) + { + case ALLOMANCY: + case FERUCHEMY: + return 17; + case SURGEBINDING: + return 10; + case AON_DOR: + case AWAKENING: + break; + case SANDMASTERY: + return 5; + } + return 0; + } } } diff --git a/src/api/java/leaf/cosmere/api/manifestation/Manifestation.java b/src/api/java/leaf/cosmere/api/manifestation/Manifestation.java index 754c66afa..53d19e330 100644 --- a/src/api/java/leaf/cosmere/api/manifestation/Manifestation.java +++ b/src/api/java/leaf/cosmere/api/manifestation/Manifestation.java @@ -145,4 +145,14 @@ public Attribute getAttribute() return ForgeRegistries.ATTRIBUTES.getValue(getRegistryName()); } + public int getInvestitureRemaining(ISpiritweb spiritweb) + { + return 0; + } + + public float getInvestitureHud(ISpiritweb spiritweb) + { + return 0.f; + } + } \ No newline at end of file diff --git a/src/api/java/leaf/cosmere/api/spiritweb/ISpiritweb.java b/src/api/java/leaf/cosmere/api/spiritweb/ISpiritweb.java index 2b14bf557..16037231c 100644 --- a/src/api/java/leaf/cosmere/api/spiritweb/ISpiritweb.java +++ b/src/api/java/leaf/cosmere/api/spiritweb/ISpiritweb.java @@ -10,10 +10,13 @@ import leaf.cosmere.api.cosmereEffect.CosmereEffect; import leaf.cosmere.api.cosmereEffect.CosmereEffectInstance; import leaf.cosmere.api.manifestation.Manifestation; +import net.minecraft.client.gui.components.AbstractWidget; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.client.event.RenderLevelStageEvent; import net.minecraftforge.common.util.INBTSerializable; import net.minecraftforge.event.entity.player.PlayerEvent; @@ -31,6 +34,8 @@ public interface ISpiritweb extends INBTSerializable boolean hasManifestation(Manifestation manifestation, boolean ignoreTemporaryPower); + boolean hasManifestationOfType(Manifestations.ManifestationTypes type); + void giveManifestation(Manifestation manifestation, int i); void removeManifestation(Manifestation manifestation); @@ -104,4 +109,7 @@ public interface ISpiritweb extends INBTSerializable void activatePowerState(int num); + @OnlyIn(Dist.CLIENT) + AbstractWidget getSpiritwebHud(); + } diff --git a/src/awakening/java/leaf/cosmere/awakening/common/capabilities/AwakeningSpiritwebSubmodule.java b/src/awakening/java/leaf/cosmere/awakening/common/capabilities/AwakeningSpiritwebSubmodule.java index 999c6efd5..2203a4f83 100644 --- a/src/awakening/java/leaf/cosmere/awakening/common/capabilities/AwakeningSpiritwebSubmodule.java +++ b/src/awakening/java/leaf/cosmere/awakening/common/capabilities/AwakeningSpiritwebSubmodule.java @@ -10,8 +10,6 @@ import net.minecraft.world.entity.player.Player; import net.minecraftforge.client.event.RenderLevelStageEvent; -import java.util.List; - public class AwakeningSpiritwebSubmodule implements ISpiritwebSubmodule { @Override @@ -38,12 +36,6 @@ public void tickServer(ISpiritweb spiritweb) } - @Override - public void collectMenuInfo(List m_infoText) - { - - } - @Override public void renderWorldEffects(ISpiritweb spiritweb, RenderLevelStageEvent event) { diff --git a/src/cosmeretools/java/leaf/cosmere/tools/common/capabilities/ToolsSpiritwebSubmodule.java b/src/cosmeretools/java/leaf/cosmere/tools/common/capabilities/ToolsSpiritwebSubmodule.java index 3c026acb2..0bb2c5bb7 100644 --- a/src/cosmeretools/java/leaf/cosmere/tools/common/capabilities/ToolsSpiritwebSubmodule.java +++ b/src/cosmeretools/java/leaf/cosmere/tools/common/capabilities/ToolsSpiritwebSubmodule.java @@ -10,8 +10,6 @@ import net.minecraft.world.entity.player.Player; import net.minecraftforge.client.event.RenderLevelStageEvent; -import java.util.List; - public class ToolsSpiritwebSubmodule implements ISpiritwebSubmodule { @Override @@ -38,12 +36,6 @@ public void tickServer(ISpiritweb spiritweb) } - @Override - public void collectMenuInfo(List m_infoText) - { - - } - @Override public void renderWorldEffects(ISpiritweb spiritweb, RenderLevelStageEvent event) { diff --git a/src/datagen/generated/allomancy/.cache/430a276c0dd49f98e5202a1b15a1e8bf39ea6301 b/src/datagen/generated/allomancy/.cache/430a276c0dd49f98e5202a1b15a1e8bf39ea6301 index 172ac10fa..1242b8a33 100644 --- a/src/datagen/generated/allomancy/.cache/430a276c0dd49f98e5202a1b15a1e8bf39ea6301 +++ b/src/datagen/generated/allomancy/.cache/430a276c0dd49f98e5202a1b15a1e8bf39ea6301 @@ -1,3 +1,3 @@ -// 1.20.1 2025-11-13T18:09:20.66803 Curios for allomancy -c0ef1b619d27f65ec86ee5bc46971b41748a156a data/allomancy/curios/entities/mistborn.json +// 1.20.1 2026-05-02T16:53:45.089036032 Curios for allomancy +1220185785fce5b2d78679e009b71dd157a8e419 data/allomancy/curios/entities/mistborn.json 1b40b27e696da61cb9fc699a027918ced88c562e data/allomancy/curios/slots/head.json diff --git a/src/datagen/generated/allomancy/.cache/9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e b/src/datagen/generated/allomancy/.cache/9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e index d624b1f54..76af48f07 100644 --- a/src/datagen/generated/allomancy/.cache/9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e +++ b/src/datagen/generated/allomancy/.cache/9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e @@ -1,6 +1,8 @@ -// 1.20.1 2024-10-09T13:22:13.338555 Recipes +// 1.20.1 2026-05-02T23:37:02.49612847 Recipes +445aa9f7a583225384441480a5bbeb7fe0b2e4da data/allomancy/advancements/recipes/combat/mistcloak.json 2ab76b8b72d83f1207051efc1cb9174ae9ae4a61 data/allomancy/advancements/recipes/tools/coin_pouch.json ff01905c7528be493d7b447b09e20762cd818089 data/allomancy/advancements/recipes/tools/metal_vial.json 97699dc7b7a7cd857564421ad0cafff04b654089 data/allomancy/recipes/coin_pouch.json 8ad78df11acb7d92cf1169192b00ab592dc78b93 data/allomancy/recipes/metal_vial.json +08f1f6f97e7fca3553d79b739ffb4ec0038a3230 data/allomancy/recipes/mistcloak.json 08792c13f9fd6638a1e2f0b0a267e81ca8c42849 data/allomancy/recipes/vial_mixing.json diff --git a/src/datagen/generated/allomancy/data/allomancy/curios/entities/mistborn.json b/src/datagen/generated/allomancy/data/allomancy/curios/entities/mistborn.json index 81e90256e..fe00c9f0c 100644 --- a/src/datagen/generated/allomancy/data/allomancy/curios/entities/mistborn.json +++ b/src/datagen/generated/allomancy/data/allomancy/curios/entities/mistborn.json @@ -1,7 +1,7 @@ { "entities": [ - "minecraft:player", - "minecraft:armor_stand" + "minecraft:armor_stand", + "minecraft:player" ], "slots": [ "head" diff --git a/src/datagen/generated/cosmeretools/.cache/dd0552f4815307fa79918bc7fddf7e3ebb5df25c b/src/datagen/generated/cosmeretools/.cache/dd0552f4815307fa79918bc7fddf7e3ebb5df25c index cfddd2bf5..d99e6d6f2 100644 --- a/src/datagen/generated/cosmeretools/.cache/dd0552f4815307fa79918bc7fddf7e3ebb5df25c +++ b/src/datagen/generated/cosmeretools/.cache/dd0552f4815307fa79918bc7fddf7e3ebb5df25c @@ -1,6 +1,6 @@ -// 1.20.1 2026-04-27T10:20:37.528514 Tags: cosmeretools -ea66c36d742d7273f998be596425ce9b7509329e data/minecraft/tags/items/axes.json -d1a8d52c7e8ce77dab7b1ff233349270720c383a data/minecraft/tags/items/hoes.json -97965722f69c61a77ba9ff364164b23ba6cb3219 data/minecraft/tags/items/pickaxes.json -730c6af6ee4b094a3d3d9c0178ac5affaba44785 data/minecraft/tags/items/shovels.json -1cdfe1b204448c10e3d7680a1240401fe4f7c1d7 data/minecraft/tags/items/swords.json +// 1.20.1 2026-05-02T23:37:02.462411953 Tags: cosmeretools +62b7cbba3bce74a1a13f88031f5d78481ed0ec6e data/minecraft/tags/items/axes.json +0f014713bf475e02c04a42a0b3ee79ffc3b6dbd7 data/minecraft/tags/items/hoes.json +d5422673aa1da7a7c75522b526e60a1793e5a602 data/minecraft/tags/items/pickaxes.json +d41f83a87ddcca32f29085a2cbb4ebf9686036eb data/minecraft/tags/items/shovels.json +a5f97d20b5dac76def51bd5e99510da2af42bd52 data/minecraft/tags/items/swords.json diff --git a/src/datagen/generated/cosmeretools/data/minecraft/tags/items/axes.json b/src/datagen/generated/cosmeretools/data/minecraft/tags/items/axes.json index 260fced28..440142691 100644 --- a/src/datagen/generated/cosmeretools/data/minecraft/tags/items/axes.json +++ b/src/datagen/generated/cosmeretools/data/minecraft/tags/items/axes.json @@ -1,26 +1,26 @@ { "values": [ - "cosmeretools:aluminum_axe", + "cosmeretools:chromium_axe", "cosmeretools:electrum_axe", + "cosmeretools:steel_axe", "cosmeretools:lerasatium_axe", - "cosmeretools:nickel_axe", - "cosmeretools:nicrosil_axe", + "cosmeretools:aluminum_axe", + "cosmeretools:copper_axe", "cosmeretools:tin_axe", - "cosmeretools:silver_axe", + "cosmeretools:zinc_axe", + "cosmeretools:bendalloy_axe", "cosmeretools:atium_axe", - "cosmeretools:malatium_axe", - "cosmeretools:copper_axe", - "cosmeretools:cadmium_axe", - "cosmeretools:pewter_axe", "cosmeretools:brass_axe", - "cosmeretools:harmonium_axe", + "cosmeretools:cadmium_axe", + "cosmeretools:duralumin_axe", + "cosmeretools:nicrosil_axe", "cosmeretools:lead_axe", + "cosmeretools:malatium_axe", + "cosmeretools:nickel_axe", "cosmeretools:bronze_axe", - "cosmeretools:chromium_axe", - "cosmeretools:bendalloy_axe", - "cosmeretools:duralumin_axe", - "cosmeretools:lerasium_axe", - "cosmeretools:zinc_axe", - "cosmeretools:steel_axe" + "cosmeretools:harmonium_axe", + "cosmeretools:silver_axe", + "cosmeretools:pewter_axe", + "cosmeretools:lerasium_axe" ] } \ No newline at end of file diff --git a/src/datagen/generated/cosmeretools/data/minecraft/tags/items/hoes.json b/src/datagen/generated/cosmeretools/data/minecraft/tags/items/hoes.json index 40869b552..7fdced381 100644 --- a/src/datagen/generated/cosmeretools/data/minecraft/tags/items/hoes.json +++ b/src/datagen/generated/cosmeretools/data/minecraft/tags/items/hoes.json @@ -1,26 +1,26 @@ { "values": [ - "cosmeretools:aluminum_hoe", + "cosmeretools:chromium_hoe", "cosmeretools:electrum_hoe", + "cosmeretools:steel_hoe", "cosmeretools:lerasatium_hoe", - "cosmeretools:nickel_hoe", - "cosmeretools:nicrosil_hoe", + "cosmeretools:aluminum_hoe", + "cosmeretools:copper_hoe", "cosmeretools:tin_hoe", - "cosmeretools:silver_hoe", + "cosmeretools:zinc_hoe", + "cosmeretools:bendalloy_hoe", "cosmeretools:atium_hoe", - "cosmeretools:malatium_hoe", - "cosmeretools:copper_hoe", - "cosmeretools:cadmium_hoe", - "cosmeretools:pewter_hoe", "cosmeretools:brass_hoe", - "cosmeretools:harmonium_hoe", + "cosmeretools:cadmium_hoe", + "cosmeretools:duralumin_hoe", + "cosmeretools:nicrosil_hoe", "cosmeretools:lead_hoe", + "cosmeretools:malatium_hoe", + "cosmeretools:nickel_hoe", "cosmeretools:bronze_hoe", - "cosmeretools:chromium_hoe", - "cosmeretools:bendalloy_hoe", - "cosmeretools:duralumin_hoe", - "cosmeretools:lerasium_hoe", - "cosmeretools:zinc_hoe", - "cosmeretools:steel_hoe" + "cosmeretools:harmonium_hoe", + "cosmeretools:silver_hoe", + "cosmeretools:pewter_hoe", + "cosmeretools:lerasium_hoe" ] } \ No newline at end of file diff --git a/src/datagen/generated/cosmeretools/data/minecraft/tags/items/pickaxes.json b/src/datagen/generated/cosmeretools/data/minecraft/tags/items/pickaxes.json index 9c8ecac38..b82398041 100644 --- a/src/datagen/generated/cosmeretools/data/minecraft/tags/items/pickaxes.json +++ b/src/datagen/generated/cosmeretools/data/minecraft/tags/items/pickaxes.json @@ -1,26 +1,26 @@ { "values": [ - "cosmeretools:aluminum_pickaxe", + "cosmeretools:chromium_pickaxe", "cosmeretools:electrum_pickaxe", + "cosmeretools:steel_pickaxe", "cosmeretools:lerasatium_pickaxe", - "cosmeretools:nickel_pickaxe", - "cosmeretools:nicrosil_pickaxe", + "cosmeretools:aluminum_pickaxe", + "cosmeretools:copper_pickaxe", "cosmeretools:tin_pickaxe", - "cosmeretools:silver_pickaxe", + "cosmeretools:zinc_pickaxe", + "cosmeretools:bendalloy_pickaxe", "cosmeretools:atium_pickaxe", - "cosmeretools:malatium_pickaxe", - "cosmeretools:copper_pickaxe", - "cosmeretools:cadmium_pickaxe", - "cosmeretools:pewter_pickaxe", "cosmeretools:brass_pickaxe", - "cosmeretools:harmonium_pickaxe", + "cosmeretools:cadmium_pickaxe", + "cosmeretools:duralumin_pickaxe", + "cosmeretools:nicrosil_pickaxe", "cosmeretools:lead_pickaxe", + "cosmeretools:malatium_pickaxe", + "cosmeretools:nickel_pickaxe", "cosmeretools:bronze_pickaxe", - "cosmeretools:chromium_pickaxe", - "cosmeretools:bendalloy_pickaxe", - "cosmeretools:duralumin_pickaxe", - "cosmeretools:lerasium_pickaxe", - "cosmeretools:zinc_pickaxe", - "cosmeretools:steel_pickaxe" + "cosmeretools:harmonium_pickaxe", + "cosmeretools:silver_pickaxe", + "cosmeretools:pewter_pickaxe", + "cosmeretools:lerasium_pickaxe" ] } \ No newline at end of file diff --git a/src/datagen/generated/cosmeretools/data/minecraft/tags/items/shovels.json b/src/datagen/generated/cosmeretools/data/minecraft/tags/items/shovels.json index eab4849e6..22dfc5827 100644 --- a/src/datagen/generated/cosmeretools/data/minecraft/tags/items/shovels.json +++ b/src/datagen/generated/cosmeretools/data/minecraft/tags/items/shovels.json @@ -1,26 +1,26 @@ { "values": [ - "cosmeretools:aluminum_shovel", + "cosmeretools:chromium_shovel", "cosmeretools:electrum_shovel", + "cosmeretools:steel_shovel", "cosmeretools:lerasatium_shovel", - "cosmeretools:nickel_shovel", - "cosmeretools:nicrosil_shovel", + "cosmeretools:aluminum_shovel", + "cosmeretools:copper_shovel", "cosmeretools:tin_shovel", - "cosmeretools:silver_shovel", + "cosmeretools:zinc_shovel", + "cosmeretools:bendalloy_shovel", "cosmeretools:atium_shovel", - "cosmeretools:malatium_shovel", - "cosmeretools:copper_shovel", - "cosmeretools:cadmium_shovel", - "cosmeretools:pewter_shovel", "cosmeretools:brass_shovel", - "cosmeretools:harmonium_shovel", + "cosmeretools:cadmium_shovel", + "cosmeretools:duralumin_shovel", + "cosmeretools:nicrosil_shovel", "cosmeretools:lead_shovel", + "cosmeretools:malatium_shovel", + "cosmeretools:nickel_shovel", "cosmeretools:bronze_shovel", - "cosmeretools:chromium_shovel", - "cosmeretools:bendalloy_shovel", - "cosmeretools:duralumin_shovel", - "cosmeretools:lerasium_shovel", - "cosmeretools:zinc_shovel", - "cosmeretools:steel_shovel" + "cosmeretools:harmonium_shovel", + "cosmeretools:silver_shovel", + "cosmeretools:pewter_shovel", + "cosmeretools:lerasium_shovel" ] } \ No newline at end of file diff --git a/src/datagen/generated/cosmeretools/data/minecraft/tags/items/swords.json b/src/datagen/generated/cosmeretools/data/minecraft/tags/items/swords.json index 698a1fdb6..035174ba6 100644 --- a/src/datagen/generated/cosmeretools/data/minecraft/tags/items/swords.json +++ b/src/datagen/generated/cosmeretools/data/minecraft/tags/items/swords.json @@ -1,26 +1,26 @@ { "values": [ - "cosmeretools:aluminum_sword", + "cosmeretools:chromium_sword", "cosmeretools:electrum_sword", + "cosmeretools:steel_sword", "cosmeretools:lerasatium_sword", - "cosmeretools:nickel_sword", - "cosmeretools:nicrosil_sword", + "cosmeretools:aluminum_sword", + "cosmeretools:copper_sword", "cosmeretools:tin_sword", - "cosmeretools:silver_sword", + "cosmeretools:zinc_sword", + "cosmeretools:bendalloy_sword", "cosmeretools:atium_sword", - "cosmeretools:malatium_sword", - "cosmeretools:copper_sword", - "cosmeretools:cadmium_sword", - "cosmeretools:pewter_sword", "cosmeretools:brass_sword", - "cosmeretools:harmonium_sword", + "cosmeretools:cadmium_sword", + "cosmeretools:duralumin_sword", + "cosmeretools:nicrosil_sword", "cosmeretools:lead_sword", + "cosmeretools:malatium_sword", + "cosmeretools:nickel_sword", "cosmeretools:bronze_sword", - "cosmeretools:chromium_sword", - "cosmeretools:bendalloy_sword", - "cosmeretools:duralumin_sword", - "cosmeretools:lerasium_sword", - "cosmeretools:zinc_sword", - "cosmeretools:steel_sword" + "cosmeretools:harmonium_sword", + "cosmeretools:silver_sword", + "cosmeretools:pewter_sword", + "cosmeretools:lerasium_sword" ] } \ No newline at end of file diff --git a/src/datagen/generated/feruchemy/.cache/60c035799f578be828205f75035ce4e4976d0466 b/src/datagen/generated/feruchemy/.cache/60c035799f578be828205f75035ce4e4976d0466 index 2c0c87863..fcf5d02d5 100644 --- a/src/datagen/generated/feruchemy/.cache/60c035799f578be828205f75035ce4e4976d0466 +++ b/src/datagen/generated/feruchemy/.cache/60c035799f578be828205f75035ce4e4976d0466 @@ -1,5 +1,5 @@ -// 1.20.1 2026-04-27T10:20:37.638454 Curios for feruchemy -6d8604575982ef60b9658bf84e9f93720d8c1978 data/feruchemy/curios/entities/feruchemists.json +// 1.20.1 2026-05-02T16:53:45.09697956 Curios for feruchemy +73df16b7f3493192632a8179ec9b2557e25d965f data/feruchemy/curios/entities/feruchemists.json bbe073ce668da1ecdaf43df2f875912048670cff data/feruchemy/curios/slots/bracelet.json 50651f4d8ef6e4eaf677f5f40e0013e4b16d7e47 data/feruchemy/curios/slots/necklace.json 15229e2ac0d30b7253b5d5b6f82d0433d5cb414c data/feruchemy/curios/slots/ring.json diff --git a/src/datagen/generated/feruchemy/data/feruchemy/curios/entities/feruchemists.json b/src/datagen/generated/feruchemy/data/feruchemy/curios/entities/feruchemists.json index da81b44bb..61b319ff8 100644 --- a/src/datagen/generated/feruchemy/data/feruchemy/curios/entities/feruchemists.json +++ b/src/datagen/generated/feruchemy/data/feruchemy/curios/entities/feruchemists.json @@ -1,7 +1,7 @@ { "entities": [ - "minecraft:player", - "minecraft:armor_stand" + "minecraft:armor_stand", + "minecraft:player" ], "slots": [ "ring", diff --git a/src/datagen/generated/hemalurgy/.cache/5040fc90492c7cdcc7a00ae9539bd053297496a9 b/src/datagen/generated/hemalurgy/.cache/5040fc90492c7cdcc7a00ae9539bd053297496a9 index 248dc6e16..a61b31be5 100644 --- a/src/datagen/generated/hemalurgy/.cache/5040fc90492c7cdcc7a00ae9539bd053297496a9 +++ b/src/datagen/generated/hemalurgy/.cache/5040fc90492c7cdcc7a00ae9539bd053297496a9 @@ -1,5 +1,5 @@ -// 1.20.1 2026-04-27T10:20:37.696925 Curios for hemalurgy -2c626dfa8d54881552e9e9c55aa2784089584b1f data/hemalurgy/curios/entities/hemalurgists.json +// 1.20.1 2026-05-02T16:53:45.109780127 Curios for hemalurgy +626814372fa7619e348a3a7768b51867ea23cf4b data/hemalurgy/curios/entities/hemalurgists.json 3fb00e951b4f3f7f01981550080dacbe27e14423 data/hemalurgy/curios/slots/eyes.json 169721ff151c350c1c8e90f73d41f17f3737007a data/hemalurgy/curios/slots/linchpin.json becad4c0600bfd0706dc0ceb17eaf853bd029cd9 data/hemalurgy/curios/slots/mental.json diff --git a/src/datagen/generated/surgebinding/.cache/109f316ce3b77a5a02bbf6e9c200027075e14620 b/src/datagen/generated/surgebinding/.cache/109f316ce3b77a5a02bbf6e9c200027075e14620 index 30632cb91..02ba11f4f 100644 --- a/src/datagen/generated/surgebinding/.cache/109f316ce3b77a5a02bbf6e9c200027075e14620 +++ b/src/datagen/generated/surgebinding/.cache/109f316ce3b77a5a02bbf6e9c200027075e14620 @@ -1,5 +1,6 @@ -// 1.20.1 2025-11-16T15:05:53.857381 Tags: surgebinding +// 1.20.1 2026-05-02T23:37:02.487174879 Tags: surgebinding 1f4a893d33327a86f361b3e38f9dcf2af46287fc data/cosmere/tags/worldgen/biome/spawn_ores.json +bb5e183a805f753908b6c65efaff0f102df47d81 data/curios/tags/items/shardplate.json b4bf1a40695628bad3692a7d5d6044ffdbf07e9b data/forge/tags/blocks/ores/diamond.json 535ffd326e438b4244fa9119ac3fc325a55e6769 data/forge/tags/blocks/ores/garnet.json 1f7903a2e11f5238538de7da1ab2946070c410a9 data/forge/tags/blocks/ores/heliodor.json @@ -17,6 +18,7 @@ aeaede227bae14370d9c20b5fa1fde9a29521ebb data/forge/tags/blocks/storage_blocks/h 5cd7c38bcb41dd20d7f68f84f3a282e6f3fcbf38 data/forge/tags/blocks/storage_blocks/smokestone.json 538b3e977ed89fbf5346bda5d9c2a31519709789 data/forge/tags/blocks/storage_blocks/topaz.json 5ce6a2023aa95ada658bb30be3a2bf1a1ab729a3 data/forge/tags/blocks/storage_blocks/zircon.json +bb5e183a805f753908b6c65efaff0f102df47d81 data/forge/tags/items/armors.json 9535dc5cb151b00d02ad4970b0b9b6ad387de67e data/forge/tags/items/gems.json 1740e87a5918faaa0662e6a6f82cdaceccc0f7ab data/forge/tags/items/gems/diamond.json 13fe09136216305b7e8326229706b6a29aeea74f data/forge/tags/items/gems/garnet.json diff --git a/src/datagen/generated/surgebinding/.cache/892be08db83774b45ce3700a46f41c5cc1a66597 b/src/datagen/generated/surgebinding/.cache/892be08db83774b45ce3700a46f41c5cc1a66597 index 2f5c543b2..c74644454 100644 --- a/src/datagen/generated/surgebinding/.cache/892be08db83774b45ce3700a46f41c5cc1a66597 +++ b/src/datagen/generated/surgebinding/.cache/892be08db83774b45ce3700a46f41c5cc1a66597 @@ -1,3 +1,3 @@ -// 1.20.1 2025-11-16T14:11:17.138575 Curios for surgebinding -ea0facc7e6a7280ae63171bec810b2d2fbeb682c data/surgebinding/curios/entities/shardbearers.json +// 1.20.1 2026-05-02T23:37:02.487017933 Curios for surgebinding +16d26545def8944005bbc9401156e83d07ab4e28 data/surgebinding/curios/entities/shardbearers.json aa7a9b208fbf01ed1b10da26876fa24c8af277a4 data/surgebinding/curios/slots/shardplate.json diff --git a/src/datagen/generated/surgebinding/.cache/9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e b/src/datagen/generated/surgebinding/.cache/9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e index 7acbc212f..349dc59eb 100644 --- a/src/datagen/generated/surgebinding/.cache/9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e +++ b/src/datagen/generated/surgebinding/.cache/9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e @@ -1,4 +1,4 @@ -// 1.20.1 2026-03-02T03:22:01.8457524 Recipes +// 1.20.1 2026-05-02T23:37:02.487450468 Recipes 4a484301203532f8e76dbd4dc854a2869ce2cbdc data/minecraft/advancements/recipes/misc/cut_amethyst_large_from_amethyst_shard_stonecutting.json b6af109fe2db6d0b5b0fc46dfc3e1fcb1bd36f82 data/minecraft/advancements/recipes/misc/cut_amethyst_medium_from_amethyst_shard_stonecutting.json 9cc4ea7f31a0e883bdd6185a51ea8eff5d2adbb0 data/minecraft/advancements/recipes/misc/cut_amethyst_small_from_amethyst_shard_stonecutting.json @@ -93,6 +93,7 @@ b8166393ff084e93d43d2867715f5cd4113521b0 data/surgebinding/recipes/conversions/z d0b8c41bf8cbc79ecb34acbaab234e7562602964 data/surgebinding/recipes/cooked_chull_meat.json 22c5810cae232dd766e9cf13db3134fc02c81ccb data/surgebinding/recipes/garnet_block.json f576d70fd168df476d29b0341b67edd6f6952d53 data/surgebinding/recipes/heliodor_block.json +191264d7369d8dd7d03596b160b0a28b37a58544 data/surgebinding/recipes/plate_charging.json e2c4e98de7566305d536524fb4334b61dbe18f0f data/surgebinding/recipes/rosharan_diamond_block.json 850b0804e90c35bd588551599916c9b01d5a8792 data/surgebinding/recipes/ruby_block.json 70b3a858f88b4b31446282f8c8f96e0d376473fd data/surgebinding/recipes/sapphire_block.json diff --git a/src/datagen/generated/surgebinding/.cache/a42c2d14910c607d1cdeea761ec88e5ad05f96c6 b/src/datagen/generated/surgebinding/.cache/a42c2d14910c607d1cdeea761ec88e5ad05f96c6 index 62d967290..5f770034a 100644 --- a/src/datagen/generated/surgebinding/.cache/a42c2d14910c607d1cdeea761ec88e5ad05f96c6 +++ b/src/datagen/generated/surgebinding/.cache/a42c2d14910c607d1cdeea761ec88e5ad05f96c6 @@ -1,4 +1,4 @@ -// 1.20.1 2026-04-27T10:20:37.587036 Item Models: surgebinding +// 1.20.1 2026-05-02T23:37:02.487998506 Item Models: surgebinding f11fb5b2de87bddd0918dffcc40c267bcc6b4da7 assets/surgebinding/models/item/amethyst_mark.json 63ec6c618a3a23eab4cab9c52d7d3250de9b516e assets/surgebinding/models/item/chull_spawn_egg.json e48028cab31d580fbb89862d7fd4717bd06fd66a assets/surgebinding/models/item/cooked_chull_leg.json @@ -48,10 +48,7 @@ a2fab60aae34e89444507b186249f22ba45612a0 assets/surgebinding/models/item/heliodo a91ca4972b8d3422763281c9cb8be570a54a5339 assets/surgebinding/models/item/ruby_mark.json 258e0d8e4ad57decd1a39dae134b836ce98f7f14 assets/surgebinding/models/item/sapphire.json e1a1241601f1e134a276a6beac7c6491344a004d assets/surgebinding/models/item/sapphire_mark.json -7817652b27f6e14fee558b9f7ed79a803bcc9651 assets/surgebinding/models/item/shardplate_boots.json -fbee7654e8cdfae717bccf39f76848666cc51bb5 assets/surgebinding/models/item/shardplate_chest.json -095355a2bd3bcf962839dd947514af66d6dd9639 assets/surgebinding/models/item/shardplate_helmet.json -0fc29fc960fce820dfb1b37d580efb2bdbd7d052 assets/surgebinding/models/item/shardplate_leggings.json +8b5900e5e58805cdeb319817cdd965b796e36c2d assets/surgebinding/models/item/shardplate.json f92f7e1e4564703f4c2e0007c9f8c521b080c721 assets/surgebinding/models/item/smokestone.json 273b3611916007e08e308048afb1d444167a0acd assets/surgebinding/models/item/smokestone_mark.json b50c314162637445327770e943368dd644413878 assets/surgebinding/models/item/surge_banner_pattern.json diff --git a/src/datagen/generated/surgebinding/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 b/src/datagen/generated/surgebinding/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 index 81f49902b..e196c4f82 100644 --- a/src/datagen/generated/surgebinding/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 +++ b/src/datagen/generated/surgebinding/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 @@ -1,2 +1,2 @@ -// 1.20.1 2026-03-04T19:26:42.166289 Languages: en_us -02db61e73dc098aa4c1d5fdf74888060397f5370 assets/surgebinding/lang/en_us.json +// 1.20.1 2026-05-02T23:37:02.487918438 Languages: en_us +1cc07e7eab32ed0e54a3d2e8d0a0598fdc3d126f assets/surgebinding/lang/en_us.json diff --git a/src/datagen/generated/surgebinding/assets/surgebinding/lang/en_us.json b/src/datagen/generated/surgebinding/assets/surgebinding/lang/en_us.json index 83bb56b8b..0c3cd1f74 100644 --- a/src/datagen/generated/surgebinding/assets/surgebinding/lang/en_us.json +++ b/src/datagen/generated/surgebinding/assets/surgebinding/lang/en_us.json @@ -140,7 +140,10 @@ "item.surgebinding.windrunner_honorblade": "Windrunner Honorblade", "item.surgebinding.zircon": "Zircon", "item.surgebinding.zircon_mark": "Zircon Mark", + "key.cosmere.stormlight.dispatch_stormlight": "Dispatch Stormlight", + "key.cosmere.stormlight.request_stormlight": "Request Stormlight", "key.cosmere.stormlight.shardblade": "Summon/Dismiss Shardblade", + "keys.surgebinding.main": "Surgebinding", "manifestation.surgebinding.abrasion": "Abrasion", "manifestation.surgebinding.abrasion.description": "Needs description", "manifestation.surgebinding.adhesion": "Adhesion", diff --git a/src/datagen/generated/surgebinding/data/surgebinding/curios/entities/shardbearers.json b/src/datagen/generated/surgebinding/data/surgebinding/curios/entities/shardbearers.json index 40a4037c3..324c045eb 100644 --- a/src/datagen/generated/surgebinding/data/surgebinding/curios/entities/shardbearers.json +++ b/src/datagen/generated/surgebinding/data/surgebinding/curios/entities/shardbearers.json @@ -1,10 +1,10 @@ { "entities": [ - "minecraft:vindicator", - "minecraft:pillager", "minecraft:armor_stand", - "minecraft:villager", - "minecraft:player" + "minecraft:pillager", + "minecraft:player", + "minecraft:vindicator", + "minecraft:villager" ], "slots": [ "shardplate" diff --git a/src/datagen/surgebinding/java/leaf/cosmere/surgebinding/SurgebindingEngLangGen.java b/src/datagen/surgebinding/java/leaf/cosmere/surgebinding/SurgebindingEngLangGen.java index 3141b6905..eb785eb89 100644 --- a/src/datagen/surgebinding/java/leaf/cosmere/surgebinding/SurgebindingEngLangGen.java +++ b/src/datagen/surgebinding/java/leaf/cosmere/surgebinding/SurgebindingEngLangGen.java @@ -22,7 +22,7 @@ import java.util.List; -import static leaf.cosmere.api.Constants.Strings.KEY_SHARDBLADE; +import static leaf.cosmere.api.Constants.Strings.*; import static leaf.cosmere.surgebinding.common.registries.SurgebindingAttributes.SURGEBINDING_ATTRIBUTES; public class SurgebindingEngLangGen extends LanguageProvider @@ -181,10 +181,13 @@ private void addCommands() private void addKeybindings() { add(KEY_SHARDBLADE, "Summon/Dismiss Shardblade"); + add(KEY_REQUEST_STORMLIGHT, "Request Stormlight"); + add(KEY_DISPATCH_STORMLIGHT, "Dispatch Stormlight"); + add("keys.surgebinding.main", "Surgebinding"); } private void addStats() { } -} \ No newline at end of file +} diff --git a/src/example/java/leaf/cosmere/example/common/capabilities/ExampleSpiritwebSubmodule.java b/src/example/java/leaf/cosmere/example/common/capabilities/ExampleSpiritwebSubmodule.java index 8652f1cc1..219e75fd9 100644 --- a/src/example/java/leaf/cosmere/example/common/capabilities/ExampleSpiritwebSubmodule.java +++ b/src/example/java/leaf/cosmere/example/common/capabilities/ExampleSpiritwebSubmodule.java @@ -10,8 +10,6 @@ import net.minecraft.world.entity.player.Player; import net.minecraftforge.client.event.RenderLevelStageEvent; -import java.util.List; - public class ExampleSpiritwebSubmodule implements ISpiritwebSubmodule { @Override @@ -38,12 +36,6 @@ public void tickServer(ISpiritweb spiritweb) } - @Override - public void collectMenuInfo(List m_infoText) - { - - } - @Override public void renderWorldEffects(ISpiritweb spiritweb, RenderLevelStageEvent event) { diff --git a/src/feruchemy/java/leaf/cosmere/feruchemy/client/FeruchemyClientSetup.java b/src/feruchemy/java/leaf/cosmere/feruchemy/client/FeruchemyClientSetup.java index 382c3cc44..6e845fff3 100644 --- a/src/feruchemy/java/leaf/cosmere/feruchemy/client/FeruchemyClientSetup.java +++ b/src/feruchemy/java/leaf/cosmere/feruchemy/client/FeruchemyClientSetup.java @@ -5,6 +5,9 @@ package leaf.cosmere.feruchemy.client; import leaf.cosmere.api.CosmereAPI; +import leaf.cosmere.api.Manifestations; +import leaf.cosmere.client.gui.SpiritwebRegistry; +import leaf.cosmere.feruchemy.client.gui.FeruchemySpiritwebMenu; import leaf.cosmere.common.cap.entity.SpiritwebCapability; import leaf.cosmere.feruchemy.client.gui.NicrosilMenu; import leaf.cosmere.feruchemy.client.render.FeruchemyLayerDefinitions; diff --git a/src/feruchemy/java/leaf/cosmere/feruchemy/client/gui/FeruchemySpiritwebMenu.java b/src/feruchemy/java/leaf/cosmere/feruchemy/client/gui/FeruchemySpiritwebMenu.java new file mode 100644 index 000000000..746e8c288 --- /dev/null +++ b/src/feruchemy/java/leaf/cosmere/feruchemy/client/gui/FeruchemySpiritwebMenu.java @@ -0,0 +1,153 @@ +package leaf.cosmere.feruchemy.client.gui; + +import com.mojang.blaze3d.systems.RenderSystem; +import leaf.cosmere.api.Metals; +import leaf.cosmere.client.gui.CosmereScreen; +import leaf.cosmere.client.gui.SpiritwebMenu; +import leaf.cosmere.common.cap.entity.SpiritwebCapability; +import leaf.cosmere.feruchemy.common.Feruchemy; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import org.lwjgl.opengl.GL11; + +public class FeruchemySpiritwebMenu extends CosmereScreen +{ + private static final ResourceLocation BORDER_LOCATION = new ResourceLocation(Feruchemy.MODID, "textures/gui/feru_border.png"); + private static final ResourceLocation SINGLE_BORDER_LOCATION = new ResourceLocation(Feruchemy.MODID, "textures/gui/feru_single_border.png"); + private static final float QUARTER_PI_F = (float) (Math.PI/2.f); + private int distance; + final LocalPlayer player; + public FeruchemySpiritwebMenu() + { + super(Component.literal("Feruchemy"), SpiritwebMenu::selectManiCallback); + player = Minecraft.getInstance().player; + } + + @Override + protected void init() + { + distance = this.height / 6; + final float topLeftRot = 0.f; + final float topRightRot = QUARTER_PI_F; + final float bottomRightRot = topRightRot + QUARTER_PI_F; + final float bottomLeftRot = bottomRightRot + QUARTER_PI_F; + + SpiritwebCapability.get(player).ifPresent( (spiritweb -> { + int x = this.width/2 - distance; + int y = this.height/2 - distance*2; + + addRenderableWidget(new TriangleButton(x, y, + distance, topLeftRot, Metals.MetalType.IRON, spiritweb, manifestationConsumer)); + addRenderableWidget(new TriangleButton(x + distance, y, + distance, topRightRot, Metals.MetalType.STEEL, spiritweb, manifestationConsumer)); + addRenderableWidget(new TriangleButton(x + distance, y + distance, + distance, bottomRightRot, Metals.MetalType.TIN, spiritweb, manifestationConsumer)); + addRenderableWidget(new TriangleButton(x, y + distance, + distance, bottomLeftRot, Metals.MetalType.PEWTER, spiritweb, manifestationConsumer)); + + x = this.width / 2; + y = this.height / 2 - distance; + + addRenderableWidget(new TriangleButton(x, y, + distance, topLeftRot, Metals.MetalType.ZINC, spiritweb, manifestationConsumer)); + addRenderableWidget(new TriangleButton(x + distance, y, + distance, topRightRot, Metals.MetalType.COPPER, spiritweb, manifestationConsumer)); + addRenderableWidget(new TriangleButton(x + distance, y + distance, + distance, bottomRightRot, Metals.MetalType.BRASS, spiritweb, manifestationConsumer)); + addRenderableWidget(new TriangleButton(x, y + distance, + distance, bottomLeftRot, Metals.MetalType.BRONZE, spiritweb, manifestationConsumer)); + + x = this.width / 2 - distance; + y = this.height / 2; + + addRenderableWidget(new TriangleButton(x, y, + distance, topLeftRot, Metals.MetalType.GOLD, spiritweb, manifestationConsumer)); + addRenderableWidget(new TriangleButton(x + distance, y, + distance, topRightRot, Metals.MetalType.ELECTRUM, spiritweb, manifestationConsumer)); + addRenderableWidget(new TriangleButton(x + distance, y + distance, + distance, bottomRightRot, Metals.MetalType.CADMIUM, spiritweb, manifestationConsumer)); + addRenderableWidget(new TriangleButton(x, y + distance, + distance, bottomLeftRot, Metals.MetalType.BENDALLOY, spiritweb, manifestationConsumer)); + + x = this.width / 2 - distance*2; + y = this.height / 2 - distance; + + addRenderableWidget(new TriangleButton(x, y, + distance, topLeftRot, Metals.MetalType.CHROMIUM, spiritweb, manifestationConsumer)); + addRenderableWidget(new TriangleButton(x + distance, y, + distance, topRightRot, Metals.MetalType.DURALUMIN, spiritweb, manifestationConsumer)); + addRenderableWidget(new TriangleButton(x + distance, y + distance, + distance, bottomRightRot, Metals.MetalType.NICROSIL, spiritweb, manifestationConsumer)); + addRenderableWidget(new TriangleButton(x, y + distance, + distance, bottomLeftRot, Metals.MetalType.ALUMINUM, spiritweb, manifestationConsumer)); + + y = this.height/2 + distance; + + addRenderableWidget(new TriangleButton(x, y, + distance, topRightRot, Metals.MetalType.ATIUM, spiritweb, manifestationConsumer)); + })); + } + + @Override + public void render(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) + { + super.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick); + renderBorder(pGuiGraphics); + renderAtiumBorder(pGuiGraphics); + } + + private void renderBorder(GuiGraphics pGuiGraphics) + { + RenderSystem.setShaderTexture(0, BORDER_LOCATION); + RenderSystem.enableBlend(); + RenderSystem.blendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0); + RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f); + + final int x = width/2 - distance*2, y = height/2 - distance*2; + final int screenSize = distance*4; + final int iconSize = 256; + + pGuiGraphics.blit(BORDER_LOCATION, + x, + y, + screenSize, + screenSize, + 0, + 0, + iconSize, + iconSize, + iconSize, + iconSize); + + RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f); + } + + private void renderAtiumBorder(GuiGraphics pGuiGraphics) + { + RenderSystem.setShaderTexture(0, SINGLE_BORDER_LOCATION); + RenderSystem.enableBlend(); + RenderSystem.blendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0); + RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f); + + final int x = this.width / 2 - distance*2-1, y = this.height/2 + distance+1; + final int screenSize = distance; + final int iconSize = 64; + + pGuiGraphics.blit(SINGLE_BORDER_LOCATION, + x, + y, + screenSize, + screenSize, + 0, + 0, + iconSize, + iconSize, + iconSize, + iconSize); + + RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f); + } +} diff --git a/src/feruchemy/java/leaf/cosmere/feruchemy/client/gui/TriangleButton.java b/src/feruchemy/java/leaf/cosmere/feruchemy/client/gui/TriangleButton.java new file mode 100644 index 000000000..16ff8b3f2 --- /dev/null +++ b/src/feruchemy/java/leaf/cosmere/feruchemy/client/gui/TriangleButton.java @@ -0,0 +1,384 @@ +package leaf.cosmere.feruchemy.client.gui; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.Tesselator; +import com.mojang.blaze3d.vertex.VertexFormat; +import leaf.cosmere.api.IHasMetalType; +import leaf.cosmere.api.Manifestations; +import leaf.cosmere.api.Metals; +import leaf.cosmere.api.manifestation.Manifestation; +import leaf.cosmere.api.spiritweb.ISpiritweb; +import leaf.cosmere.client.gui.GuiUtils; +import leaf.cosmere.client.gui.SpiritwebMenu; +import leaf.cosmere.common.Cosmere; +import leaf.cosmere.common.network.packets.ChangeManifestationModeMessage; +import leaf.cosmere.feruchemy.common.manifestation.FeruchemyManifestation; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.resources.language.I18n; +import net.minecraft.network.chat.CommonComponents; +import net.minecraft.resources.ResourceLocation; +import org.joml.Matrix4f; +import org.lwjgl.opengl.GL11; + +import java.awt.*; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +public class TriangleButton extends Button +{ + private final ResourceLocation iconLocation; + private final List cachedQuads = new ArrayList<>(); + private final Consumer manifestationConsumer; + private final ISpiritweb spiritweb; + private final Manifestation manifestation; + private final Metals.MetalType metal; + private final boolean hasManifestation; + private final float rotation; + + public TriangleButton(int pX, int pY, int distance, float rotation, Metals.MetalType metal, ISpiritweb spiritweb, Consumer maniConsumer) + { + super(pX, pY, distance, distance, CommonComponents.EMPTY, (button) -> { }, DEFAULT_NARRATION); + this.rotation = rotation; + this.spiritweb = spiritweb; + this.metal = metal; + manifestation = Manifestations.ManifestationTypes.FERUCHEMY.getManifestation(metal.getID()); + hasManifestation = spiritweb.hasManifestation(manifestation); + + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.setLength(0); + stringBuilder.append("textures/icon/") + .append(manifestation.getManifestationType().getName()) + .append("/"); + + // no need for a switch case, always allomancy + if (manifestation instanceof IHasMetalType metalType) + { + stringBuilder.append(metalType.getMetalType().getName()); + } + + stringBuilder.append(".png"); + iconLocation = new ResourceLocation(manifestation.getRegistryName().getNamespace(), stringBuilder.toString()); + + manifestationConsumer = maniConsumer; + + calculateVertexes(pX, pY, getWidth(), rotation); + } + + @Override + protected void renderWidget(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) + { + boolean isHover = isMouseOver(pMouseX, pMouseY); + renderTriangle(pGuiGraphics, isHover); + renderIcon(pGuiGraphics); + if (isHover && hasManifestation) + { + renderInfoBlock(pGuiGraphics); + } + } + + @Override + public boolean isMouseOver(double mouseX, double mouseY) + { + boolean retVal; + + float radius = getWidth() / 2.0f; + float centerX = getX() + radius; + float centerY = getY() + radius; + + float dx = (float) mouseX - centerX; + float dy = (float) mouseY - centerY; + + float cos = (float) Math.cos(-rotation); + float sin = (float) Math.sin(-rotation); + + float px = dx * cos - dy * sin; + float py = dx * sin + dy * cos; + + retVal = (px <= radius && py <= radius && (px + py) >= 0); + + if (hasManifestation) + { + if (retVal) + { + manifestationConsumer.accept(manifestation); + } + } + + return retVal; + } + + @Override + public boolean mouseClicked(double pMouseX, double pMouseY, int pButton) + { + boolean isMouseOver = isMouseOver(pMouseX, pMouseY); + if (isMouseOver && hasManifestation) + { + if (manifestation.hasMenu()) + { + manifestation.openMenu(); + } + else + { + if (pButton == 0) + Cosmere.packetHandler().sendToServer(new ChangeManifestationModeMessage(manifestation, 1)); + else + Cosmere.packetHandler().sendToServer(new ChangeManifestationModeMessage(manifestation, -1)); + } + + playDownSound(Minecraft.getInstance().getSoundManager()); + } + return isMouseOver; + } + + private void renderTriangle(GuiGraphics pGuiGraphics, boolean isHovered) + { + float r = GuiUtils.BACKGROUND_COLOR.getRed()/255.f, g = GuiUtils.BACKGROUND_COLOR.getGreen()/255.f, b = GuiUtils.BACKGROUND_COLOR.getBlue()/255.f; + float a = 1f; + + if (!hasManifestation) + { + r *= 0.6f; + g *= 0.6f; + b *= 0.6f; + } + + if (isHovered && hasManifestation) + { + r *= 1.1f; + g *= 1.1f; + b *= 1.1f; + } + + if (manifestation instanceof FeruchemyManifestation feruchemyManifestation) + { + int mode = feruchemyManifestation.getMode(spiritweb); + float intensity = 0; + if (mode < 0) + intensity = Math.min(Math.abs(mode) * (1f/16f), 1.0f); + if (mode > 0) + intensity = Math.min(Math.abs(mode) * (1f/5f), 1.0f); + + if (mode > 0) + { + // Blend toward pure red + r = lerp(r, 1.0f, intensity); + g = lerp(g, 0.0f, intensity); + b = lerp(b, 0.0f, intensity); + } + else if (mode < 0) + { + // Blend toward pure blue + r = lerp(r, 0.0f, intensity); + g = lerp(g, 0.0f, intensity); + b = lerp(b, 1.0f, intensity); + } + } + + RenderSystem.disableCull(); + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + RenderSystem.setShader(GameRenderer::getPositionColorShader); + + Matrix4f pose = pGuiGraphics.pose().last().pose(); + + Tesselator tess = Tesselator.getInstance(); + BufferBuilder buf = tess.getBuilder(); + + buf.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); + + for (GuiUtils.CachedQuad quad : cachedQuads) + { + float px = quad.px(); + float py = quad.py(); + float size = quad.size(); + + buf.vertex(pose, px, py, 0).color(r,g,b,a).endVertex(); + buf.vertex(pose, px, py + size, 0).color(r,g,b,a).endVertex(); + buf.vertex(pose, px + size, py + size, 0).color(r,g,b,a).endVertex(); + buf.vertex(pose, px + size, py, 0).color(r,g,b,a).endVertex(); + } + + tess.end(); + RenderSystem.disableBlend(); + } + + private void renderIcon(GuiGraphics pGuiGraphics) + { + Color metalColor = metal.getColor(); + float r = metalColor.getRed()/255.f, g = metalColor.getGreen()/255.f, b = metalColor.getBlue()/255.f; + + if (!hasManifestation) + { + r *= 0.1f; + g *= 0.1f; + b *= 0.1f; + } + + float alpha = hasManifestation ? 1.0f : 0.25f; + RenderSystem.setShaderTexture(0, iconLocation); + RenderSystem.enableBlend(); + RenderSystem.blendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0); + + int iconSize = width / 4; + + float radius = width / 2.0f; + float centerX = getX() + radius; + float centerY = getY() + radius; + + float localCx = radius / 3.0f; + float localCy = radius / 3.0f; + + float cos = (float) Math.cos(rotation); + float sin = (float) Math.sin(rotation); + + int posX = (int) (centerX + localCx * cos - localCy * sin) - iconSize / 2; + int posY = (int) (centerY + localCx * sin + localCy * cos) - iconSize / 2; + + RenderSystem.setShaderColor(0f, 0f, 0f, alpha); + pGuiGraphics.blit(iconLocation, + posX + 1, + posY + 1, + iconSize, + iconSize, + 0, + 0, + width, + height, + width, + height); + + RenderSystem.setShaderColor(r, g, b, alpha); + pGuiGraphics.blit(iconLocation, + posX, + posY, + iconSize, + iconSize, + 0, + 0, + width, + height, + width, + height); + + RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f); + } + + private void renderInfoBlock(GuiGraphics pGuiGraphics) + { + Font font = Minecraft.getInstance().font; + int screenWidth = Minecraft.getInstance().getWindow().getGuiScaledWidth(); + int screenHeight = Minecraft.getInstance().getWindow().getGuiScaledHeight(); + int x = 0; + int y = 0; + int width = GuiUtils.getInfoBoxWidth(Minecraft.getInstance()); + int height = GuiUtils.getInfoBoxHeight(Minecraft.getInstance()); + int color = 0x99333333; + + boolean isLeft = getX() < screenWidth/2; + boolean isTop = getY() < screenHeight/2; + + if (!isLeft && !isTop) + { + // bottom right display + x = screenWidth - width - 10; + y = screenHeight - height - 10; + } + if (isLeft && !isTop) + { + // bottom left display + x = 10; + y = screenHeight - height - 10; + } + if (isLeft && isTop) + { + // top left display + x = 10; + y = 10; + } + if (!isLeft && isTop) + { + // top right display + x = screenWidth - width - 10; + y = 10; + } + + RenderSystem.disableCull(); + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + + pGuiGraphics.fill(x, y, x + width, y + height, color); + + String text = I18n.get(manifestation.getTranslationKey()); + float scale = 0.8f; + GuiUtils.drawScaledString(font, pGuiGraphics, text, x+5, y+10, scale, 0xFFFFFFFF); + + if (metal != Metals.MetalType.NICROSIL) + { + int seconds = manifestation.getInvestitureRemaining(spiritweb); + int hours = seconds / 3600; + int minutes = (seconds % 3600) / 60; + seconds = seconds % 60; + + if (hours > 0) + { + text = String.format("%d:%02d:%02d", hours, minutes, seconds); + } + else if (minutes > 0) + { + text = String.format("%d:%02d", minutes, seconds); + } + else if (seconds > 0) + { + text = String.format("%02d", seconds); + } + else + { + text = "Empty"; + } + + GuiUtils.drawScaledString(font, pGuiGraphics, text, x+5, y+12+font.lineHeight*scale, scale, 0xFFFFFFFF); + } + } + + private void calculateVertexes(float posX, float posY, float size, float rotation) + { + cachedQuads.clear(); + + float radius = size / 2.0f; + int pixelSize = 1; + float centerX = posX + radius; + float centerY = posY + radius; + int maxR = (int) Math.ceil(Math.sqrt(radius * radius + radius * radius)); + + float cos = (float) Math.cos(-rotation); + float sin = (float) Math.sin(-rotation); + + for (int x = -maxR; x <= maxR; x += pixelSize) + { + for (int y = -maxR; y <= maxR; y += pixelSize) + { + float pixelCenterX = x + (pixelSize / 2f); + float pixelCenterY = y + (pixelSize / 2f); + + float px = pixelCenterX * cos - pixelCenterY * sin; + float py = pixelCenterX * sin + pixelCenterY * cos; + + if (px <= radius && py <= radius && px + py >= 0) + { + cachedQuads.add(new GuiUtils.CachedQuad(centerX + x, centerY + y, pixelSize)); + } + } + } + } + + public float lerp(float start, float end, float pct) { + return start + pct * (end - start); + } +} diff --git a/src/feruchemy/java/leaf/cosmere/feruchemy/client/utils/FeruchemyChargeThread.java b/src/feruchemy/java/leaf/cosmere/feruchemy/client/utils/FeruchemyChargeThread.java index 47df8f6b3..58e9e6a13 100644 --- a/src/feruchemy/java/leaf/cosmere/feruchemy/client/utils/FeruchemyChargeThread.java +++ b/src/feruchemy/java/leaf/cosmere/feruchemy/client/utils/FeruchemyChargeThread.java @@ -24,6 +24,7 @@ public class FeruchemyChargeThread implements Runnable private static final Lock lock = new ReentrantLock(); private static FeruchemyChargeThread INSTANCE; private static final HashMap feruchemyChargeMap = new HashMap<>(); + private static final HashMap feruchemyMaxChargeMap = new HashMap<>(); static Thread t; static boolean isStopping = false; @@ -39,22 +40,37 @@ public static FeruchemyChargeThread getInstance() public HashMap getCharges() { - try + HashMap retVal = new HashMap<>(); + if (lock.tryLock()) { - HashMap retVal = new HashMap<>(); - if (lock.tryLock()) + try { retVal.putAll(feruchemyChargeMap); + } + finally + { lock.unlock(); } - return retVal; } - catch (Exception e) + return retVal; + } + + public HashMap getMaximumCharges() + { + HashMap retVal = new HashMap<>(); + if (lock.tryLock()) { - e.printStackTrace(); - lock.unlock(); + try + { + retVal.putAll(feruchemyMaxChargeMap); + } + finally + { + lock.unlock(); + } } - return new HashMap<>(); + + return retVal; } public void start() @@ -83,6 +99,7 @@ public void run() // hashmap to keep track of each metal's f-charge in the inventory final HashMap metalmindCharges = new HashMap<>(); + final HashMap metalmindMaxCharges = new HashMap<>(); while (!isStopping) { @@ -108,6 +125,7 @@ public void run() } metalmindCharges.clear(); + metalmindMaxCharges.clear(); // all inventory metalminds are counted for (ItemStack stack : mc.player.getInventory().items) @@ -126,6 +144,16 @@ public void run() { metalmindCharges.put(item.getMetalType(), chargeToAdd); } + + Double maxToAdd = (double) item.getMaxCharge(stack); + if (metalmindMaxCharges.containsKey(item.getMetalType())) + { + metalmindMaxCharges.put(item.getMetalType(), metalmindMaxCharges.get(item.getMetalType()) + maxToAdd); + } + else + { + metalmindMaxCharges.put(item.getMetalType(), maxToAdd); + } } } } @@ -152,6 +180,16 @@ public void run() { metalmindCharges.put(item.getMetalType(), chargeToAdd); } + + Double maxToAdd = (double) item.getMaxCharge(stackInSlot); + if (metalmindMaxCharges.containsKey(item.getMetalType())) + { + metalmindMaxCharges.put(item.getMetalType(), metalmindMaxCharges.get(item.getMetalType()) + maxToAdd); + } + else + { + metalmindMaxCharges.put(item.getMetalType(), maxToAdd); + } } } } @@ -164,18 +202,17 @@ public void run() return true; }); + if (lock.tryLock()) try { - if (lock.tryLock()) - { - feruchemyChargeMap.clear(); - feruchemyChargeMap.putAll(metalmindCharges); - lock.unlock(); - } + feruchemyChargeMap.clear(); + feruchemyChargeMap.putAll(metalmindCharges); + + feruchemyMaxChargeMap.clear(); + feruchemyMaxChargeMap.putAll(metalmindMaxCharges); } - catch (Exception e) + finally { - e.printStackTrace(); lock.unlock(); } } diff --git a/src/feruchemy/java/leaf/cosmere/feruchemy/common/capabilities/FeruchemySpiritwebSubmodule.java b/src/feruchemy/java/leaf/cosmere/feruchemy/common/capabilities/FeruchemySpiritwebSubmodule.java index f09b5ad87..225593b72 100644 --- a/src/feruchemy/java/leaf/cosmere/feruchemy/common/capabilities/FeruchemySpiritwebSubmodule.java +++ b/src/feruchemy/java/leaf/cosmere/feruchemy/common/capabilities/FeruchemySpiritwebSubmodule.java @@ -5,13 +5,16 @@ package leaf.cosmere.feruchemy.common.capabilities; import leaf.cosmere.api.ISpiritwebSubmodule; +import leaf.cosmere.api.Manifestations; import leaf.cosmere.api.Metals; import leaf.cosmere.api.helpers.PlayerHelper; import leaf.cosmere.api.manifestation.Manifestation; import leaf.cosmere.api.math.MathHelper; import leaf.cosmere.api.spiritweb.ISpiritweb; +import leaf.cosmere.client.gui.SpiritwebRegistry; +import leaf.cosmere.common.cap.entity.SpiritwebCapability; +import leaf.cosmere.feruchemy.client.gui.FeruchemySpiritwebMenu; import leaf.cosmere.common.registration.impl.AttributeRegistryObject; -import leaf.cosmere.feruchemy.client.utils.FeruchemyChargeThread; import leaf.cosmere.feruchemy.common.config.FeruchemyConfigs; import leaf.cosmere.feruchemy.common.items.NicrosilRingMetalmindItem; import leaf.cosmere.feruchemy.common.items.RingMetalmindItem; @@ -26,14 +29,11 @@ import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; -import java.util.HashMap; import java.util.List; import java.util.stream.Collectors; public class FeruchemySpiritwebSubmodule implements ISpiritwebSubmodule { - private static final HashMap metalmindChargesMap = new HashMap<>(); - @Override public void GiveStartingItem(Player player) { @@ -76,25 +76,12 @@ public void drainInvestiture(ISpiritweb data, double strength) @Override @OnlyIn(Dist.CLIENT) - public void collectMenuInfo(List m_infoText) + public void registerMenu() { - if (Minecraft.getInstance().player != null && Minecraft.getInstance().player.tickCount % 2 == 1) // only do on odd tick - { - metalmindChargesMap.clear(); - metalmindChargesMap.putAll(FeruchemyChargeThread.getInstance().getCharges()); - } - - if (!metalmindChargesMap.isEmpty()) - { - for (Metals.MetalType metalType : metalmindChargesMap.keySet()) - { - // todo localisation check - final String text = "F. " + metalType.getName() + ": " + metalmindChargesMap.getOrDefault(metalType, 0D).intValue(); - m_infoText.add(text); - } - } - - ISpiritwebSubmodule.super.collectMenuInfo(m_infoText); + SpiritwebCapability.get(Minecraft.getInstance().player).ifPresent( (spiritweb) -> { + if (spiritweb.hasManifestationOfType(Manifestations.ManifestationTypes.FERUCHEMY)) + SpiritwebRegistry.getInstance().register(Manifestations.ManifestationTypes.FERUCHEMY, FeruchemySpiritwebMenu::new); + }); } private static void GiveStartingItem(Player player, Metals.MetalType metalType, float fillAmount) diff --git a/src/feruchemy/java/leaf/cosmere/feruchemy/common/manifestation/FeruchemyManifestation.java b/src/feruchemy/java/leaf/cosmere/feruchemy/common/manifestation/FeruchemyManifestation.java index b2f6a1f31..68c32ffb3 100644 --- a/src/feruchemy/java/leaf/cosmere/feruchemy/common/manifestation/FeruchemyManifestation.java +++ b/src/feruchemy/java/leaf/cosmere/feruchemy/common/manifestation/FeruchemyManifestation.java @@ -13,13 +13,21 @@ import leaf.cosmere.api.manifestation.Manifestation; import leaf.cosmere.api.spiritweb.ISpiritweb; import leaf.cosmere.common.charge.MetalmindChargeHelper; +import leaf.cosmere.feruchemy.client.utils.FeruchemyChargeThread; import leaf.cosmere.feruchemy.common.registries.FeruchemyEffects; +import net.minecraft.client.Minecraft; import net.minecraft.util.Mth; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.item.ItemStack; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +import java.util.HashMap; public class FeruchemyManifestation extends Manifestation implements IHasMetalType { + private static final HashMap metalmindChargesMap = new HashMap<>(); + private static final HashMap metalmindMaxChargesMap = new HashMap<>(); protected final Metals.MetalType metalType; public FeruchemyManifestation(Metals.MetalType metalType) @@ -76,6 +84,36 @@ public void onModeChange(ISpiritweb data, int lastMode) } } + @OnlyIn(Dist.CLIENT) + private void collectMenuInfo() + { + if (Minecraft.getInstance().player != null && Minecraft.getInstance().player.tickCount % 2 == 1) // only do on odd tick + { + metalmindChargesMap.clear(); + metalmindChargesMap.putAll(FeruchemyChargeThread.getInstance().getCharges()); + + metalmindMaxChargesMap.clear(); + metalmindMaxChargesMap.putAll(FeruchemyChargeThread.getInstance().getMaximumCharges()); + } + } + + @Override + public int getInvestitureRemaining(ISpiritweb spiritweb) + { + collectMenuInfo(); + return (int) Math.floor(metalmindChargesMap.getOrDefault(metalType, 0d)); + } + + @Override + public float getInvestitureHud(ISpiritweb spiritweb) + { + collectMenuInfo(); + double maximum = metalmindMaxChargesMap.getOrDefault(metalType, 0d); + double charge = metalmindChargesMap.getOrDefault(metalType, 0d); + if (maximum <= 0) return 0.f; + return (float) (charge/maximum); + } + protected CosmereEffect getTappingEffect() { return FeruchemyEffects.TAPPING_EFFECTS.get(this.metalType).get(); diff --git a/src/feruchemy/java/leaf/cosmere/feruchemy/common/manifestation/FeruchemyNicrosil.java b/src/feruchemy/java/leaf/cosmere/feruchemy/common/manifestation/FeruchemyNicrosil.java index c36d32d5c..ed6689ad6 100644 --- a/src/feruchemy/java/leaf/cosmere/feruchemy/common/manifestation/FeruchemyNicrosil.java +++ b/src/feruchemy/java/leaf/cosmere/feruchemy/common/manifestation/FeruchemyNicrosil.java @@ -30,6 +30,7 @@ public void openMenu() { Minecraft minecraft = Minecraft.getInstance(); NicrosilMenu.instance.closeScreen(); + // todo: replace with SpiritwebMenu call. might also be good to send a supplier instead of a singleton minecraft.setScreen(NicrosilMenu.instance); } diff --git a/src/feruchemy/resources/assets/feruchemy/textures/gui/feru_border.png b/src/feruchemy/resources/assets/feruchemy/textures/gui/feru_border.png new file mode 100644 index 000000000..a3ff498f1 Binary files /dev/null and b/src/feruchemy/resources/assets/feruchemy/textures/gui/feru_border.png differ diff --git a/src/feruchemy/resources/assets/feruchemy/textures/gui/feru_single_border.png b/src/feruchemy/resources/assets/feruchemy/textures/gui/feru_single_border.png new file mode 100644 index 000000000..5822c24f9 Binary files /dev/null and b/src/feruchemy/resources/assets/feruchemy/textures/gui/feru_single_border.png differ diff --git a/src/main/java/leaf/cosmere/client/ClientForgeEvents.java b/src/main/java/leaf/cosmere/client/ClientForgeEvents.java index fbeee02e1..d5a183a00 100644 --- a/src/main/java/leaf/cosmere/client/ClientForgeEvents.java +++ b/src/main/java/leaf/cosmere/client/ClientForgeEvents.java @@ -7,7 +7,11 @@ import com.mojang.blaze3d.platform.InputConstants; import leaf.cosmere.api.Activator; +import leaf.cosmere.api.CosmereAPI; import leaf.cosmere.api.manifestation.Manifestation; +import leaf.cosmere.client.gui.SpiritwebHud; +import leaf.cosmere.client.gui.SpiritwebMenu; +import leaf.cosmere.client.gui.SpiritwebRegistry; import leaf.cosmere.common.Cosmere; import leaf.cosmere.common.cap.entity.SpiritwebCapability; import leaf.cosmere.common.fog.FogManager; @@ -25,7 +29,9 @@ import net.minecraftforge.client.event.ClientPlayerNetworkEvent; import net.minecraftforge.client.event.InputEvent; import net.minecraftforge.client.event.InputEvent.MouseScrollingEvent; +import net.minecraftforge.client.event.RenderGuiOverlayEvent; import net.minecraftforge.client.event.RenderLevelStageEvent; +import net.minecraftforge.client.gui.overlay.VanillaGuiOverlay; import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; @@ -67,6 +73,18 @@ public static void onKey(InputEvent.Key event) SpiritwebCapability.get(player).ifPresent(spiritweb -> { + if (Keybindings.MANIFESTATION_MENU.consumeClick()) + { + SpiritwebRegistry.getInstance().clear(); + SpiritwebCapability.get(player).ifPresent( (iSpiritweb -> + { + iSpiritweb.getSubmodules().forEach( ((manifestationTypes, iSpiritwebSubmodule) -> { + iSpiritwebSubmodule.registerMenu(); + })); + })); + Minecraft.getInstance().setScreen(new SpiritwebMenu(Component.literal("Spiritweb Menu"), spiritweb)); + } + Manifestation selected = spiritweb.getSelectedManifestation(); if (isKeyPressed(event, Keybindings.MANIFESTATIONS_DEACTIVATE)) { @@ -203,6 +221,28 @@ public static void onRenderLevelLastEvent(final RenderLevelStageEvent event) } + @SubscribeEvent + public static void onRenderGuiOverlayPost(RenderGuiOverlayEvent.Post event) + { + // make sure it only renders once per frame + if (event.getOverlay().id().equals(VanillaGuiOverlay.HOTBAR.id())) + { + Minecraft mc = Minecraft.getInstance(); + ProfilerFiller profiler = mc.getProfiler(); + LocalPlayer playerEntity = mc.player; + profiler.push("cosmere-spiritweb-hud"); + { + SpiritwebCapability.get(playerEntity).ifPresent(spiritweb -> + { + // Shouldn't need mouse location, will only render as a HUD element + spiritweb.getSpiritwebHud().render(event.getGuiGraphics(), 0, 0, event.getPartialTick()); + }); + } + profiler.pop(); + } + } + + @SubscribeEvent public static void onClientPlayerClone(ClientPlayerNetworkEvent.Clone event) { diff --git a/src/main/java/leaf/cosmere/client/ClientModEvents.java b/src/main/java/leaf/cosmere/client/ClientModEvents.java index 700798726..3256c3846 100644 --- a/src/main/java/leaf/cosmere/client/ClientModEvents.java +++ b/src/main/java/leaf/cosmere/client/ClientModEvents.java @@ -4,17 +4,20 @@ package leaf.cosmere.client; +import com.mojang.blaze3d.vertex.PoseStack; import leaf.cosmere.api.CosmereAPI; -import leaf.cosmere.client.gui.ISyncSpiritweb; import leaf.cosmere.client.gui.SpiritwebMenu; import leaf.cosmere.client.render.CosmereRenderers; import leaf.cosmere.common.Cosmere; import leaf.cosmere.common.cap.entity.SpiritwebCapability; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.renderer.texture.TextureAtlas; +import net.minecraft.world.inventory.InventoryMenu; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.event.EntityRenderersEvent; import net.minecraftforge.client.event.RegisterGuiOverlaysEvent; +import net.minecraftforge.client.event.TextureStitchEvent; import net.minecraftforge.client.gui.overlay.VanillaGuiOverlay; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; @@ -72,16 +75,14 @@ public static void renderSpiritwebHUD(final GuiGraphics guiGraphics) final Minecraft mc = Minecraft.getInstance(); SpiritwebCapability.get(mc.player).ifPresent(cap -> { - SpiritwebCapability spiritweb = (SpiritwebCapability) cap; - //normal hud stuff - if (!(mc.screen instanceof ISyncSpiritweb)) + if (!(mc.screen instanceof SpiritwebMenu)) { - spiritweb.renderSelectedHUD(guiGraphics); + //cap.renderSelectedHUD(guiGraphics); } //actual menu stuff - SpiritwebMenu.instance.postRender(spiritweb); + //SpiritwebMenu.instance.postRender(spiritweb); }); } diff --git a/src/main/java/leaf/cosmere/client/gui/CosmereScreen.java b/src/main/java/leaf/cosmere/client/gui/CosmereScreen.java new file mode 100644 index 000000000..c364b8d82 --- /dev/null +++ b/src/main/java/leaf/cosmere/client/gui/CosmereScreen.java @@ -0,0 +1,19 @@ +package leaf.cosmere.client.gui; + +import leaf.cosmere.api.manifestation.Manifestation; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; + +import java.util.function.Consumer; + +// would be an interface if Screen wasn't a class +// might be unnecessary, but could be nice to have in future, I guess +public class CosmereScreen extends Screen +{ + protected final Consumer manifestationConsumer; + protected CosmereScreen(Component pTitle, Consumer manifestationConsumer) + { + super(pTitle); + this.manifestationConsumer = manifestationConsumer; + } +} diff --git a/src/main/java/leaf/cosmere/client/gui/GuiUtils.java b/src/main/java/leaf/cosmere/client/gui/GuiUtils.java new file mode 100644 index 000000000..f7a794d38 --- /dev/null +++ b/src/main/java/leaf/cosmere/client/gui/GuiUtils.java @@ -0,0 +1,33 @@ +package leaf.cosmere.client.gui; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphics; + +import java.awt.*; + +public class GuiUtils +{ + public static final Color BACKGROUND_COLOR = new Color(61, 61, 71); + + public static final int getInfoBoxWidth(Minecraft minecraft) + { + return (int) (minecraft.getWindow().getGuiScaledWidth() * 0.2); + } + + public static final int getInfoBoxHeight(Minecraft minecraft) + { + return minecraft.getWindow().getGuiScaledHeight() / 8; + } + + public static void drawScaledString(Font font, GuiGraphics pGuiGraphics, String text, float x, float y, float scale, int color) + { + pGuiGraphics.pose().pushPose(); + pGuiGraphics.pose().translate(x, y, 0); + pGuiGraphics.pose().scale(scale, scale, 1.0f); + pGuiGraphics.drawString(font, text, 0, 0, color, false); + pGuiGraphics.pose().popPose(); + } + + public record CachedQuad(float px, float py, float size) {} +} diff --git a/src/main/java/leaf/cosmere/client/gui/SpiritwebHud.java b/src/main/java/leaf/cosmere/client/gui/SpiritwebHud.java new file mode 100644 index 000000000..9f4caeae0 --- /dev/null +++ b/src/main/java/leaf/cosmere/client/gui/SpiritwebHud.java @@ -0,0 +1,199 @@ +package leaf.cosmere.client.gui; + +import com.mojang.blaze3d.systems.RenderSystem; +import leaf.cosmere.api.IHasMetalType; +import leaf.cosmere.api.Manifestations; +import leaf.cosmere.api.manifestation.Manifestation; +import leaf.cosmere.common.cap.entity.SpiritwebCapability; +import leaf.cosmere.common.config.CosmereConfigs; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +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.GameRenderer; +import net.minecraft.client.resources.language.I18n; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.player.Player; + +import java.awt.*; + +public class SpiritwebHud extends AbstractWidget +{ + private Player player; + + public SpiritwebHud(Player player) + { + super(CosmereConfigs.CLIENT_CONFIG.hudXCoordinate.get(), + CosmereConfigs.CLIENT_CONFIG.hudYCoordinate.get(), + CosmereConfigs.CLIENT_CONFIG.hudSizeX.get(), + CosmereConfigs.CLIENT_CONFIG.hudSizeY.get(), + Component.literal("Spiritweb HUD")); + this.player = player; + } + + @Override + protected void renderWidget(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) + { + SpiritwebCapability.get(player).ifPresent( (spiritweb -> { + if (!CosmereConfigs.CLIENT_CONFIG.disableSelectedManifestationHud.get() + && spiritweb.getSelectedManifestation().getManifestationType() != Manifestations.ManifestationTypes.NONE) + { + renderBackground(pGuiGraphics); + renderUsage(pGuiGraphics); + renderIcon(pGuiGraphics); + renderText(pGuiGraphics); + } + })); + } + + @Override + protected void updateWidgetNarration(NarrationElementOutput pNarrationElementOutput) + { + // no + } + + protected void renderBackground(GuiGraphics pGuiGraphics) + { + pGuiGraphics.fill(getX(), getY(), getX() + getWidth(), getY() + getHeight(), 0xCC333333); + } + + protected void renderUsage(GuiGraphics pGuiGraphics) + { + SpiritwebCapability.get(player).ifPresent(spiritweb -> + { + Manifestation manifestation = spiritweb.getSelectedManifestation(); + float r, g, b; + float a = 0.2f; + r = g = b = 1.0f; + + int mode = manifestation.getMode(spiritweb); + + if (manifestation.getManifestationType() == Manifestations.ManifestationTypes.FERUCHEMY) + { + float intensity = 0; + if (mode < 0) + intensity = Math.min(Math.abs(mode) * (1f/16f), 1.0f); + if (mode > 0) + intensity = Math.min(Math.abs(mode) * (1f/5f), 1.0f); + + if (mode > 0) + { + r = lerp(r, 1.0f, intensity); + g = lerp(g, 0.0f, intensity); + b = lerp(b, 0.0f, intensity); + } + else if (mode < 0) { + r = lerp(r, 0.0f, intensity); + g = lerp(g, 0.0f, intensity); + b = lerp(b, 1.0f, intensity); + } + } + else if (manifestation.getManifestationType() == Manifestations.ManifestationTypes.ALLOMANCY) + { + float intensity = Math.min(Math.abs(mode) * 0.2f, 1.0f); + + if (mode > 0) + { + r = lerp(r, 1.0f, intensity); + g = lerp(g, 0.0f, intensity); + b = lerp(b, 0.0f, intensity); + } + else if (mode < 0) + { + r = lerp(r, 0.0f, intensity); + g = lerp(g, 0.0f, intensity); + b = lerp(b, 1.0f, intensity); + } + } + + int color = toHex(new Color(r, g, b, a)); + + float width = getWidth(); + float usagePercentage = spiritweb.getSelectedManifestation().getInvestitureHud(spiritweb); + + width = width * usagePercentage; + pGuiGraphics.fill(getX(), getY(), (int) (getX() + width), getY() + getHeight(), color); + }); + } + + protected void renderIcon(GuiGraphics pGuiGraphics) + { + SpiritwebCapability.get(player).ifPresent(spiritweb -> + { + Manifestation selectedManifestation = spiritweb.getSelectedManifestation(); + if (selectedManifestation != null) + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.setLength(0); + stringBuilder.append("textures/icon/") + .append(selectedManifestation.getManifestationType().getName()) + .append("/"); + + switch (selectedManifestation.getManifestationType()) + { + case ALLOMANCY: + case FERUCHEMY: + if (selectedManifestation instanceof IHasMetalType metalType) + { + stringBuilder.append(metalType.getMetalType().getName()); + } + break; + case SURGEBINDING: + stringBuilder.append(selectedManifestation.getName()); + break; + case AON_DOR: + break; + case AWAKENING: + break; + } + + stringBuilder.append(".png"); + final ResourceLocation resourceLocation = new ResourceLocation(selectedManifestation.getRegistryName().getNamespace(), stringBuilder.toString()); + RenderSystem.setShader(GameRenderer::getPositionTexShader); + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + + pGuiGraphics.blit(resourceLocation, + getX(), + getY() + 2, + getHeight()-4, + getHeight()-4, + 0, + 0, + 18, + 18, + 18, + 18); + } + }); + } + + protected void renderText(GuiGraphics pGuiGraphics) + { + SpiritwebCapability.get(player).ifPresent(spiritweb -> + { + Font font = Minecraft.getInstance().font; + String text = I18n.get(spiritweb.getSelectedManifestation().getTranslationKey()); + float scale = 0.8f; + + float targetX = getX() + getHeight() + 2; + float targetY = getY() + (getHeight() / 2f) - ((font.lineHeight * scale) / 2f); + + GuiUtils.drawScaledString(font, pGuiGraphics, text, targetX, targetY, scale, 0xFFDDDDDD); + }); + } + + protected int toHex(Color color) + { + return (color.getAlpha() << 24) | + (color.getRed() << 16) | + (color.getGreen() << 8) | + color.getBlue(); + } + + public float lerp(float start, float end, float pct) { + return start + pct * (end - start); + } +} diff --git a/src/main/java/leaf/cosmere/client/gui/SpiritwebMenu.java b/src/main/java/leaf/cosmere/client/gui/SpiritwebMenu.java index d6157b707..29c4cecb9 100644 --- a/src/main/java/leaf/cosmere/client/gui/SpiritwebMenu.java +++ b/src/main/java/leaf/cosmere/client/gui/SpiritwebMenu.java @@ -5,68 +5,38 @@ package leaf.cosmere.client.gui; import com.google.common.base.Stopwatch; -import com.mojang.blaze3d.platform.GlStateManager; -import com.mojang.blaze3d.platform.Window; -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.*; -import leaf.cosmere.api.IHasMetalType; -import leaf.cosmere.api.ISpiritwebSubmodule; +import leaf.cosmere.api.CosmereAPI; import leaf.cosmere.api.Manifestations; -import leaf.cosmere.api.Metals; import leaf.cosmere.api.manifestation.Manifestation; import leaf.cosmere.api.math.MathHelper; -import leaf.cosmere.api.math.Vector2; +import leaf.cosmere.api.spiritweb.ISpiritweb; import leaf.cosmere.client.Keybindings; import leaf.cosmere.common.Cosmere; -import leaf.cosmere.common.cap.entity.SpiritwebCapability; -import leaf.cosmere.common.network.packets.ChangeManifestationModeMessage; import leaf.cosmere.common.network.packets.SetSelectedManifestationMessage; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.screens.Screen; -import net.minecraft.client.renderer.GameRenderer; -import net.minecraft.client.resources.language.I18n; -import net.minecraft.core.Direction; import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.NotNull; -import org.lwjgl.opengl.GL11; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; -public class SpiritwebMenu extends Screen implements ISyncSpiritweb +public class SpiritwebMenu extends Screen { - final double TEXT_DISTANCE = 30; - - public static final SpiritwebMenu instance = new SpiritwebMenu(); - private SpiritwebCapability spiritweb = null; - private float visibility = 0.0f; private Stopwatch lastChange = Stopwatch.createStarted(); - public Manifestation selectedManifestation = null; - public SidedMenuButton doAction = null; - private Manifestations.ManifestationTypes selectedPowerType = Manifestations.ManifestationTypes.ALLOMANCY; - - protected ArrayList radialMenuButtons = new ArrayList<>(); - protected ArrayList sidedMenuButtons = new ArrayList<>(); - protected ArrayList metalQuadrants = new ArrayList<>(); - - private final List m_infoText = new ArrayList<>(); - - protected SpiritwebMenu() - { - super(Component.literal("Menu")); - this.minecraft = getMinecraft(); - } + private final ISpiritweb spiritweb; + private final SpiritwebRegistry registry; + private CosmereScreen selectedManifestationScreen = null; + public static Manifestations.ManifestationTypes selectedManifestationType = Manifestations.ManifestationTypes.NONE; + private static Manifestation selectedManifestation = null; - @Override - public boolean isPauseScreen() + public SpiritwebMenu(Component pTitle, ISpiritweb spiritweb) { - return false; + super(pTitle); + this.spiritweb = spiritweb; + this.registry = SpiritwebRegistry.getInstance(); } public void raiseVisibility() @@ -76,960 +46,117 @@ public void raiseVisibility() lastChange = Stopwatch.createStarted(); } - public void setScaledResolution(final int scaledWidth, final int scaledHeight) - { - width = scaledWidth; - height = scaledHeight; - } - - @Override - public Minecraft getMinecraft() - { - return Minecraft.getInstance(); - } - - - public void postRender(SpiritwebCapability spiritweb) - { - if (this.minecraft.screen != SpiritwebMenu.instance && this.minecraft.screen != null) - { - return; - } - if (Keybindings.MANIFESTATION_MENU.consumeClick()) - { - final Window window = this.minecraft.getWindow(); - init(this.minecraft, window.getGuiScaledWidth(), window.getGuiScaledHeight()); - setScaledResolution(window.getGuiScaledWidth(), window.getGuiScaledHeight()); - this.spiritweb = spiritweb; - this.minecraft.setScreen(SpiritwebMenu.instance); - visibility = 0; - lastChange = Stopwatch.createStarted(); - - selectedManifestation = spiritweb.getSelectedManifestation(); - - SetupButtons(); - } - if (this.minecraft.screen == SpiritwebMenu.instance) - { - raiseVisibility(); - } - } - - @Override - public boolean keyReleased(int pKeyCode, int pScanCode, int pModifiers) - { - if (Keybindings.MANIFESTATION_MENU.matches(pKeyCode, pScanCode)) - { - for (RadialMenuButton radialMenuButton : radialMenuButtons) - { - if (radialMenuButton.highlighted) - { - Cosmere.packetHandler().sendToServer(new SetSelectedManifestationMessage(radialMenuButton.manifestation)); - break; - } - } - - CloseScreen(); - } - return super.keyReleased(pKeyCode, pScanCode, pModifiers); - } - - @Override - public boolean mouseClicked(final double mouseX, final double mouseY, final int button) - { - for (RadialMenuButton radialMenuButton : radialMenuButtons) - { - if (radialMenuButton.highlighted) - { - //final ResourceLocation selectedPower = radialMenuButton.manifestation.getRegistryName(); - //if (selectedPower.getNamespace().equals("feruchemy") && selectedPower.getPath().equals("nicrosil")) - if (radialMenuButton.manifestation.hasMenu()) - { - radialMenuButton.manifestation.openMenu(); - - } - else - { - if (button == 0) - { - Cosmere.packetHandler().sendToServer(new ChangeManifestationModeMessage(radialMenuButton.manifestation, 1)); - } - else - { - Cosmere.packetHandler().sendToServer(new ChangeManifestationModeMessage(radialMenuButton.manifestation, -1)); - } - return true; - } - } - } - for (SidedMenuButton sidedMenuButton : sidedMenuButtons) - { - if (sidedMenuButton.highlighted) - { - if (sidedMenuButton.powerType != -1) - { - selectedPowerType = Manifestations.ManifestationTypes.valueOf(sidedMenuButton.powerType).get(); - SetupButtons(); - } - else if (sidedMenuButton.action != null) - { - //do other action - } - - return true; - } - } - return true; - } - private void CloseScreen() { + prepareClose(); this.minecraft.setScreen(null); } - private static class SidedMenuButton - { - public double x1, x2; - public double y1, y2; - public boolean highlighted; - - public final ButtonAction action; - public final int powerType; - public int color; - public String name; - public Direction textSide; - - // NEW: logical layout info - public final int index; - public final int size; - - // For "action" buttons (if you ever use them) - public SidedMenuButton( - final String name, - final ButtonAction action, - final int index, - final int size, - final Direction textSide) - { - this.name = name; - this.action = action; - this.powerType = -1; - this.color = 0xffffff; - this.textSide = textSide; - this.index = index; - this.size = size; - } - - // For "power type" buttons (current use) - public SidedMenuButton( - final String name, - final int powerType, - final int index, - final int size, - final Direction textSide) - { - this.name = name; - this.action = null; - this.powerType = powerType; - this.color = 0xffffff; - this.textSide = textSide; - this.index = index; - this.size = size; - } - } - - - static class RadialMenuButton - { - - public final Manifestation manifestation; - public double centerX; - public double centerY; - public boolean highlighted; - - public RadialMenuButton(final Manifestation manifestation) - { - this.manifestation = manifestation; - } - - } - - static class MetalQuadrant + public void prepareClose() { - public final Metals.MetalType metalType; - public double centerX; - public double centerY; - public static double width = 50; - public static double height = 40; - - public MetalQuadrant(final Metals.MetalType metalType, double centerX, double centerY) + if (selectedManifestationScreen != null && selectedManifestation != null) { - this.metalType = metalType; - this.centerX = centerX; - this.centerY = centerY; - } - - } - - public void onSpiritwebUpdated(SpiritwebCapability cap) - { - this.spiritweb = cap; - // if you want the radial menu to reflect changes immediately: - SetupButtons(); - } - - protected void SetupButtons() - { - radialMenuButtons.clear(); - sidedMenuButtons.clear(); - metalQuadrants.clear(); - - if (selectedPowerType == Manifestations.ManifestationTypes.ALLOMANCY || selectedPowerType == Manifestations.ManifestationTypes.FERUCHEMY) - { - // adding manually one-by-one was better than a for loop, as there would have to be a switch case anyway - - // add physical metals - double quadCenterX = width / 2F - MetalQuadrant.width * 3; // these multiplications are kinda random, but if it works, it works - double quadCenterY = height / 2F - MetalQuadrant.height * 0.75; - metalQuadrants.add(new MetalQuadrant(Metals.MetalType.IRON, - quadCenterX - MetalQuadrant.width / 2, - quadCenterY - MetalQuadrant.height / 2)); - - metalQuadrants.add(new MetalQuadrant(Metals.MetalType.STEEL, - quadCenterX + 2 + MetalQuadrant.width / 2, - quadCenterY - MetalQuadrant.height / 2)); - - metalQuadrants.add(new MetalQuadrant(Metals.MetalType.TIN, - quadCenterX - MetalQuadrant.width / 2, - quadCenterY + 2 + MetalQuadrant.height / 2)); - - metalQuadrants.add(new MetalQuadrant(Metals.MetalType.PEWTER, - quadCenterX + 2 + MetalQuadrant.width / 2, - quadCenterY + 2 + MetalQuadrant.height / 2)); - - // add mental metals - quadCenterX = width / 2 + MetalQuadrant.width * 3; - metalQuadrants.add(new MetalQuadrant(Metals.MetalType.ZINC, - quadCenterX - MetalQuadrant.width / 2, - quadCenterY - MetalQuadrant.height / 2)); - - metalQuadrants.add(new MetalQuadrant(Metals.MetalType.BRASS, - quadCenterX + 2 + MetalQuadrant.width / 2, - quadCenterY - MetalQuadrant.height / 2)); - - metalQuadrants.add(new MetalQuadrant(Metals.MetalType.COPPER, - quadCenterX - MetalQuadrant.width / 2, - quadCenterY + 2 + MetalQuadrant.height / 2)); - - metalQuadrants.add(new MetalQuadrant(Metals.MetalType.BRONZE, - quadCenterX + 2 + MetalQuadrant.width / 2, - quadCenterY + 2 + MetalQuadrant.height / 2)); - - // add enhancement metals - quadCenterX = width / 2F - MetalQuadrant.width * 3; - quadCenterY = height / 2F + MetalQuadrant.height * 1.75; - metalQuadrants.add(new MetalQuadrant(Metals.MetalType.ALUMINUM, - quadCenterX - MetalQuadrant.width / 2, - quadCenterY - MetalQuadrant.height / 2)); - - metalQuadrants.add(new MetalQuadrant(Metals.MetalType.DURALUMIN, - quadCenterX + 2 + MetalQuadrant.width / 2, - quadCenterY - MetalQuadrant.height / 2)); - - metalQuadrants.add(new MetalQuadrant(Metals.MetalType.CHROMIUM, - quadCenterX - MetalQuadrant.width / 2, - quadCenterY + 2 + MetalQuadrant.height / 2)); - - metalQuadrants.add(new MetalQuadrant(Metals.MetalType.NICROSIL, - quadCenterX + 2 + MetalQuadrant.width / 2, - quadCenterY + 2 + MetalQuadrant.height / 2)); - - // add temporal metals - quadCenterX = width / 2 + MetalQuadrant.width * 3; - metalQuadrants.add(new MetalQuadrant(Metals.MetalType.GOLD, - quadCenterX - MetalQuadrant.width / 2, - quadCenterY - MetalQuadrant.height / 2)); - - metalQuadrants.add(new MetalQuadrant(Metals.MetalType.ELECTRUM, - quadCenterX + 2 + MetalQuadrant.width / 2, - quadCenterY - MetalQuadrant.height / 2)); - - metalQuadrants.add(new MetalQuadrant(Metals.MetalType.CADMIUM, - quadCenterX - MetalQuadrant.width / 2, - quadCenterY + 2 + MetalQuadrant.height / 2)); - - metalQuadrants.add(new MetalQuadrant(Metals.MetalType.BENDALLOY, - quadCenterX + 2 + MetalQuadrant.width / 2, - quadCenterY + 2 + MetalQuadrant.height / 2)); - - // add atium - metalQuadrants.add(new MetalQuadrant(Metals.MetalType.ATIUM, - width / 2D, - quadCenterY + MetalQuadrant.height / 2)); - } - - final List availableManifestations = spiritweb.getAvailableManifestations(); - - if (availableManifestations.size() <= 16) - { - for (Manifestation manifestation : availableManifestations) - { - radialMenuButtons.add(new RadialMenuButton(manifestation)); - } - } - else - { - Set foundPowerTypes = new HashSet<>(); - - for (Manifestation manifestation : availableManifestations) - { - if (manifestation.getManifestationType() == selectedPowerType) - { - radialMenuButtons.add(new RadialMenuButton(manifestation)); - } - foundPowerTypes.add(manifestation.getManifestationType()); - } - - int index = 0; - int size = foundPowerTypes.size(); - - for (Manifestations.ManifestationTypes foundPowerType : foundPowerTypes) - { - sidedMenuButtons.add( - new SidedMenuButton( - foundPowerType.getName(), - foundPowerType.getID(), - index++, - size, - Direction.UP) - ); - } + Cosmere.packetHandler().sendToServer(new SetSelectedManifestationMessage(selectedManifestation)); + selectedManifestation = null; } } @Override - public void render(final GuiGraphics guiGraphics, final int mouseX, final int mouseY, final float partialTicks) + protected void init() { - PoseStack matrixStack = guiGraphics.pose(); - if (spiritweb == null) + if (spiritweb.getSelectedManifestation() != null) { - return; + selectedManifestationType = spiritweb.getSelectedManifestation().getManifestationType(); } - - matrixStack.pushPose(); - - final int start = (int) (visibility * 98) << 24; - final int end = (int) (visibility * 128) << 24; - - guiGraphics.fillGradient(0, 0, width, height, start, end); - - //RenderSystem.disableTexture(); - RenderSystem.enableBlend(); - RenderSystem.blendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0); - final Tesselator tessellator = Tesselator.getInstance(); - final BufferBuilder buffer = tessellator.getBuilder(); - - buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); - - final double mouseVecX = mouseX - width / 2f; - final double mouseVecY = (mouseY - height / 2f); - - final double middle_x = width / 2f; - final double middle_y = height / 2f; - - selectedManifestation = null; - doAction = null; - - //render the button backgrounds - renderRadialButtons(buffer, mouseVecX, mouseVecY, middle_x, middle_y); - renderSidedButtons(buffer, mouseVecX, mouseVecY, middle_x, middle_y); - - //render the metal quadrant backgrounds - renderMetalQuadrants(buffer); - - //draw out what we've asked for - tessellator.end(); - - drawIcons(guiGraphics, buffer, middle_x, middle_y); - - - // draw radial button strings - // Removing radial button strings since its so cluttered with the metal submenu - //renderRadialButtonStrings(guiGraphics, (int) middle_x, (int) middle_y); - //draw sided button strings - renderSidedButtonStrings(guiGraphics, middle_x, middle_y); - //draw quadrant strings - renderMetalQuadrantsStrings(guiGraphics); - //do extra text info stuff - renderAnyExtraInfoTexts(guiGraphics, (int) middle_x, (int) middle_y); - - matrixStack.popPose(); - } - - private void drawIcons(@NotNull GuiGraphics guiGraphics, BufferBuilder buffer, double middle_x, double middle_y) - { - PoseStack matrixStack = guiGraphics.pose(); - matrixStack.pushPose(); - //RenderSystem.enableTexture(); - RenderSystem.enableBlend(); - - //then we switch to icons - RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA); - RenderSystem.setShader(GameRenderer::getPositionTexShader); - //RenderSystem.bindTexture(Minecraft.getInstance().getTextureManager().getTexture(InventoryMenu.BLOCK_ATLAS).getId()); - //buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX_COLOR); - - //put the icons on the region buttons - renderRadialButtonIcons(guiGraphics, middle_x, middle_y); - //put the icons on the sided buttons - renderSidedButtonIcons(guiGraphics, middle_x, middle_y); - - matrixStack.popPose(); - } - - private void renderAnyExtraInfoTexts(GuiGraphics guiGraphics, int middle_x, int middle_y) - { - int leftSideX = 10; - final int[] y = {(int) middle_y / 2}; - - if (selectedPowerType == Manifestations.ManifestationTypes.SANDMASTERY) + AtomicInteger added = new AtomicInteger(0); + int count = registry.getManifestationScreenMap().size(); + int buttonWidth = 32; + int offset = 5; + int totalBlockWidth = (count-1) * (buttonWidth+offset) + buttonWidth; + int startX = (this.width/2) - (totalBlockWidth/2); + for (int i = 0; i < Manifestations.ManifestationTypes.AVIAR.getID(); i++) { - m_infoText.clear(); - - for (ISpiritwebSubmodule spiritwebSubmodule : spiritweb.getSubmodules().values()) + Manifestations.ManifestationTypes.valueOf(i).ifPresent( (maniType) -> { - spiritwebSubmodule.collectMenuInfo(m_infoText); - } - - for (String s : m_infoText) - { - if (s.toLowerCase().contains("hydration")) - { - guiGraphics.drawString(font, s, leftSideX, y[0], 0xffffffff); - y[0] += 10; - } - } - } - - if (selectedManifestation == null) - { - return; - } - - int sidedMenuX = !sidedMenuButtons.isEmpty() ? (int) sidedMenuButtons.get(sidedMenuButtons.size() - 1).x2 + 35 : 0; - int sidedMenuY = !sidedMenuButtons.isEmpty() ? (int) sidedMenuButtons.get(sidedMenuButtons.size() - 1).y1 : -85; - - sidedMenuX += middle_x; - sidedMenuY += middle_y; - - String displayString = "+" + (int) selectedManifestation.getStrength(spiritweb, false) + " " + I18n.get(selectedManifestation.getTranslationKey()); - guiGraphics.drawString(font, displayString, sidedMenuX, sidedMenuY, 0xffffffff); - //todo mode translation - guiGraphics.drawString(font, "Mode: " + spiritweb.getMode(selectedManifestation), sidedMenuX, sidedMenuY + 10, 0xffffffff); - - } - - private void renderMetalQuadrantsStrings(GuiGraphics guiGraphics) - { - PoseStack matrixStack = guiGraphics.pose(); - m_infoText.clear(); - - List maniList = spiritweb.getAvailableManifestations(); - int maniListSize = maniList.size(); - boolean manifestationNotNull = selectedManifestation != null; - boolean inMetalSubmenu = (selectedPowerType == Manifestations.ManifestationTypes.ALLOMANCY || selectedPowerType == Manifestations.ManifestationTypes.FERUCHEMY) && maniListSize > 16; - boolean shouldShowAllomancy = maniListSize <= 16 && manifestationNotNull && selectedManifestation.getManifestationType() == Manifestations.ManifestationTypes.ALLOMANCY; - boolean shouldShowFeruchemy = maniListSize <= 16 && manifestationNotNull && selectedManifestation.getManifestationType() == Manifestations.ManifestationTypes.FERUCHEMY; - boolean manifestationIsSelected = shouldShowAllomancy || shouldShowFeruchemy; - - for (ISpiritwebSubmodule submodule : spiritweb.getSubmodules().values()) - { - submodule.collectMenuInfo(m_infoText); - } - - for (MetalQuadrant quad : metalQuadrants) - { - boolean foundNumber = false; - boolean selectedAllomancyType = selectedPowerType == Manifestations.ManifestationTypes.ALLOMANCY || shouldShowAllomancy; - boolean selectedFeruchemyType = selectedPowerType == Manifestations.ManifestationTypes.FERUCHEMY || shouldShowFeruchemy; - - // if there are submenus, or if a manifestation is selected in the menu, proceed - if (inMetalSubmenu || manifestationIsSelected) - { - for (String s : m_infoText) + if (registry.getManifestationScreenMap().get(maniType) != null) { - if (((inMetalSubmenu && selectedAllomancyType) || shouldShowAllomancy) && s.toLowerCase().contains("a. " + quad.metalType.getName()) && maniList.contains(Manifestations.ManifestationTypes.ALLOMANCY.getManifestation(quad.metalType.getID()))) + int x = startX + (added.get() * (buttonWidth+offset)); + addRenderableWidget(new TabButton(x, (pButton -> { - String displayString = s.split(":")[1].stripLeading(); - guiGraphics.drawString(font, displayString, (int) (quad.centerX - font.width(displayString) / 2F), (int) quad.centerY + font.lineHeight, 0xffffffff); + if (maniType != selectedManifestationType) + { + selectedManifestationType = maniType; + selectedManifestationScreen = registry.getManifestationScreenMap().get(maniType).get(); + selectedManifestationScreen.init(Minecraft.getInstance(), this.width, this.height); + } + }), maniType)); - displayString = quad.metalType.getName().substring(0, 1).toUpperCase() + quad.metalType.getName().substring(1); - guiGraphics.drawString(font, displayString, (int) (quad.centerX - font.width(displayString) / 2F), (int) (quad.centerY - font.lineHeight * 1.5F), 0xffffffff); + added.set(added.get()+1); - foundNumber = true; - break; + if (selectedManifestationType == maniType) + { + selectedManifestationScreen = registry.getManifestationScreenMap().get(maniType).get(); } - else if (((inMetalSubmenu && selectedFeruchemyType) || shouldShowFeruchemy) && s.toLowerCase().contains("f. " + quad.metalType.getName()) && maniList.contains(Manifestations.ManifestationTypes.FERUCHEMY.getManifestation(quad.metalType.getID()))) + else if (added.get() == 1 && selectedManifestationScreen != null) { - String displayString = s.split(":")[1].stripLeading(); - guiGraphics.drawString(font, displayString, (int) (quad.centerX - font.width(displayString) / 2F), (int) quad.centerY + font.lineHeight, 0xffffffff); - - displayString = quad.metalType.getName().substring(0, 1).toUpperCase() + quad.metalType.getName().substring(1); - guiGraphics.drawString(font, displayString, (int) (quad.centerX - font.width(displayString) / 2F), (int) (quad.centerY - font.lineHeight * 1.5F), 0xffffffff); - - foundNumber = true; - break; + selectedManifestationType = maniType; + selectedManifestationScreen = registry.getManifestationScreenMap().get(maniType).get(); } } - } - - boolean alloManiListContains = maniList.contains(Manifestations.ManifestationTypes.ALLOMANCY.getManifestation(quad.metalType.getID())); - boolean feruManiListContains = maniList.contains(Manifestations.ManifestationTypes.FERUCHEMY.getManifestation(quad.metalType.getID())); - - boolean shouldDrawMetalNames = !foundNumber && ((inMetalSubmenu && ((selectedAllomancyType && alloManiListContains) || (selectedFeruchemyType && feruManiListContains))) - || (!inMetalSubmenu && ((shouldShowAllomancy && alloManiListContains) || (shouldShowFeruchemy && feruManiListContains)))); - if (shouldDrawMetalNames) - { - String displayString; - displayString = "0"; - guiGraphics.drawString(font, displayString, (int) (quad.centerX - font.width(displayString) / 2F), (int) (quad.centerY + font.lineHeight), 0xffffffff); - - displayString = quad.metalType.getName().substring(0, 1).toUpperCase() + quad.metalType.getName().substring(1); - guiGraphics.drawString(font, displayString, (int) (quad.centerX - font.width(displayString) / 2F), (int) (quad.centerY - font.lineHeight * 1.5F), 0xffffffff); - } - } - } - - private void renderSidedButtonStrings(GuiGraphics guiGraphics, double middle_x, double middle_y) - { - for (final SidedMenuButton sideButton : sidedMenuButtons) - { - //but only if that sided button is highlighted - if (sideButton.highlighted) - { - final String text = I18n.get(sideButton.name); - - switch (sideButton.textSide) - { - case WEST: - guiGraphics.drawString(font, text, (int) (middle_x + sideButton.x1 - 8) - font.width(text), (int) (middle_y + sideButton.y1 + 6), 0xffffffff); - break; - case EAST: - guiGraphics.drawString(font, text, (int) (middle_x + sideButton.x2 + 8), (int) (middle_y + sideButton.y1 + 6), 0xffffffff); - break; - case UP: - guiGraphics.drawString(font, text, (int) (middle_x + (sideButton.x1 + sideButton.x2) * 0.5 - font.width(text) * 0.5), (int) (middle_y + sideButton.y1 - 14), 0xffffffff); - break; - case DOWN: - guiGraphics.drawString(font, text, (int) (middle_x + (sideButton.x1 + sideButton.x2) * 0.5 - font.width(text) * 0.5), (int) (middle_y + sideButton.y1 + 24), 0xffffffff); - break; - } - - } + }); } + if (selectedManifestationScreen != null) + selectedManifestationScreen.init(Minecraft.getInstance(), this.width, this.height); } - private void renderRadialButtonStrings(GuiGraphics guiGraphics, int middle_x, int middle_y) + @Override + public void render(@NotNull GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) { - for (final RadialMenuButton button : radialMenuButtons) - { - //but only if that button is highlighted - if (button.highlighted) - { - final double x = button.centerX; - final double y = button.centerY; - - int fixed_x = (int) x;//(x + TEXT_DISTANCE); - final int fixed_y = (int) y;//(y + TEXT_DISTANCE); - - //todo localisation check - final String text = I18n.get(button.manifestation.getTranslationKey()); - - fixed_x = (int) (x < 0 - ? fixed_x - (font.width(text) + TEXT_DISTANCE) - : fixed_x + TEXT_DISTANCE); - - guiGraphics.drawString(font, text, middle_x + fixed_x, middle_y + fixed_y, 0xffffffff); + super.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick); + selectedManifestation = null; + raiseVisibility(); + final int start = (int) (visibility * 98) << 24; + final int end = (int) (visibility * 128) << 24; - //no need to keep searching, we only keep one highlighted at a time. - break; - } - } - } + pGuiGraphics.fillGradient(0, 0, width, height, start, end); - private void renderSidedButtonIcons(GuiGraphics guiGraphics, double middleX, double middleY) - { - final StringBuilder stringBuilder = new StringBuilder(); - for (final SidedMenuButton button : sidedMenuButtons) + if (selectedManifestationScreen != null) { - stringBuilder.setLength(0); - final double x = (button.x1 + button.x2) / 2 + 0.01; - final double y = (button.y1 + button.y2) / 2 + 0.01; - - stringBuilder - .append("textures/icon/") - .append(button.name) - .append(".png"); - - //RenderSystem.setShaderTexture(0, new ResourceLocation(button.name, stringBuilder.toString())); - guiGraphics.blit(new ResourceLocation(button.name, stringBuilder.toString()), (int) (middleX + x - 8), (int) (middleY + y - 8), 16, 16, 0, 0, 18, 18, 18, 18); - + selectedManifestationScreen.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick); } } - private void renderRadialButtonIcons(GuiGraphics guiGraphics, double middleX, double middleY) + @Override + public boolean mouseClicked(double pMouseX, double pMouseY, int pButton) { - final StringBuilder stringBuilder = new StringBuilder(); - for (final RadialMenuButton menuRegion : radialMenuButtons) + if (selectedManifestationScreen != null) { - stringBuilder.setLength(0); - final double x = menuRegion.centerX; - final double y = menuRegion.centerY; - - final double scalex = 15 * 0.5; - final double scaley = 15 * 0.5; - final double x1 = x - scalex; - final double y1 = y - scaley; - - Manifestation mani = menuRegion.manifestation; - final Manifestations.ManifestationTypes manifestationType = mani.getManifestationType(); - String manifestationTypeName = manifestationType.getName(); - stringBuilder - .append("textures/icon/") - .append(manifestationTypeName) - .append("/"); - - switch (manifestationType) - { - case ALLOMANCY: - case FERUCHEMY: - if (mani instanceof IHasMetalType metalType) - { - stringBuilder.append(metalType.getMetalType().getName()); - } - break; - case SURGEBINDING: - stringBuilder.append(mani.getName()); - break; - case AON_DOR: - break; - case AWAKENING: - break; - } - - stringBuilder.append(".png"); - final ResourceLocation textureLocation = new ResourceLocation(mani.getRegistryName().getNamespace(), stringBuilder.toString()); - RenderSystem.setShaderTexture(0, textureLocation); - guiGraphics.blit(textureLocation, - (int) (middleX + x1), - (int) (middleY + y1), - 16, - 16, - 0, - 0, - 18, - 18, - 18, - 18); - + selectedManifestationScreen.mouseClicked(pMouseX, pMouseY, pButton); } + return super.mouseClicked(pMouseX, pMouseY, pButton); } - private void renderSidedButtons(BufferBuilder buffer, double mouseVecX, double mouseVecY, double middle_x, double middle_y) + @Override + public boolean keyReleased(int pKeyCode, int pScanCode, int pModifiers) { - if (sidedMenuButtons.isEmpty()) - { - return; - } - - // How many buttons in this row - final int size = sidedMenuButtons.size(); - - // Match Nicrosil-style spacing: distance between button centers - final double spacing = 25.0; - final double half = (size - 1) / 2.0; - - // Vertical offset relative to center (was hardcoded -90 in SetupButtons before) - final double rowYOffset = -90.0; - - for (int i = 0; i < size; i++) + if (Keybindings.MANIFESTATION_MENU.matches(pKeyCode, pScanCode)) { - final SidedMenuButton button = sidedMenuButtons.get(i); - - // Center offsets relative to screen center - double centerX = spacing * (i - half); - double centerY = rowYOffset; - - // Button is 18x18 → half-size = 9 - double halfSize = 9.0; - button.x1 = centerX - halfSize; - button.x2 = centerX + halfSize; - button.y1 = centerY - halfSize; - button.y2 = centerY + halfSize; - - final float a = 0.5f; - float f; - - // Mouse is also relative to center here (mouseVecX/mouseVecY) - boolean inside = (button.x1 <= mouseVecX && button.x2 >= mouseVecX - && button.y1 <= mouseVecY && button.y2 >= mouseVecY); - - if (inside) - { - f = 1; - button.highlighted = true; - doAction = button; - } - else - { - button.highlighted = false; - - // Highlight selected power type, even if not hovered - f = selectedPowerType.getID() == button.powerType - ? 1 - : 0; - } - - // Draw the quad at center-relative position - buffer.vertex(middle_x + button.x1, middle_y + button.y1, 0).color(f, f, f, a).endVertex(); - buffer.vertex(middle_x + button.x1, middle_y + button.y2, 0).color(f, f, f, a).endVertex(); - buffer.vertex(middle_x + button.x2, middle_y + button.y2, 0).color(f, f, f, a).endVertex(); - buffer.vertex(middle_x + button.x2, middle_y + button.y1, 0).color(f, f, f, a).endVertex(); + CloseScreen(); } - } - - - private void renderMetalQuadrants(BufferBuilder buffer) - { - List maniList = spiritweb.getAvailableManifestations(); - boolean manifestationIsSelected = selectedManifestation != null && maniList.size() <= 16 && (selectedManifestation.getManifestationType() == Manifestations.ManifestationTypes.ALLOMANCY || selectedManifestation.getManifestationType() == Manifestations.ManifestationTypes.FERUCHEMY); - boolean allomancySubmenuOpen = selectedPowerType == Manifestations.ManifestationTypes.ALLOMANCY && maniList.size() > 16; - boolean feruchemySubmenuOpen = selectedPowerType == Manifestations.ManifestationTypes.FERUCHEMY && maniList.size() > 16; - boolean hasSubmenu = allomancySubmenuOpen || feruchemySubmenuOpen; - boolean allomancySelected = !hasSubmenu && manifestationIsSelected && selectedManifestation.getManifestationType() == Manifestations.ManifestationTypes.ALLOMANCY; - boolean feruchemySelected = !hasSubmenu && manifestationIsSelected && selectedManifestation.getManifestationType() == Manifestations.ManifestationTypes.FERUCHEMY; - int r = 0, g = 0, b = 0, a = 127; // 127 is halfway between 0 and 255, so 0.5 transparency - - for (MetalQuadrant quadrant : metalQuadrants) - { - Manifestation alloMani = Manifestations.ManifestationTypes.ALLOMANCY.getManifestation(quadrant.metalType.getID()); - Manifestation feruMani = Manifestations.ManifestationTypes.FERUCHEMY.getManifestation(quadrant.metalType.getID()); - // if player doesn't have the manifestation, skip it - if ((hasSubmenu && ((allomancySubmenuOpen && maniList.contains(alloMani)) || (feruchemySubmenuOpen && maniList.contains(feruMani)))) - || (!hasSubmenu && ((allomancySelected && maniList.contains(alloMani)) || (feruchemySelected && maniList.contains(feruMani))))) - { - buffer.vertex(quadrant.centerX - MetalQuadrant.width / 2, quadrant.centerY - MetalQuadrant.height / 2, 0).color(r, g, b, a).endVertex(); - buffer.vertex(quadrant.centerX - MetalQuadrant.width / 2, quadrant.centerY + MetalQuadrant.height / 2, 0).color(r, g, b, a).endVertex(); - buffer.vertex(quadrant.centerX + MetalQuadrant.width / 2, quadrant.centerY + MetalQuadrant.height / 2, 0).color(r, g, b, a).endVertex(); - buffer.vertex(quadrant.centerX + MetalQuadrant.width / 2, quadrant.centerY - MetalQuadrant.height / 2, 0).color(r, g, b, a).endVertex(); - } - } + return super.keyReleased(pKeyCode, pScanCode, pModifiers); } - private void renderRadialButtons(BufferBuilder buffer, double mouseVecX, double mouseVecY, double middle_x, double middle_y) + @Override + public boolean isPauseScreen() { - if (!radialMenuButtons.isEmpty()) - { - final float ring_inner_edge = -20; - final float ring_outer_edge = -60; - - // todo test if I can get down to one button only - final int totalButtons = radialMenuButtons.size(); - - Vector2 innerEdge; - Vector2 outerEdge; - - int drawMode = radialMenuButtons.size(); - - innerEdge = new Vector2(0, ring_inner_edge); - outerEdge = new Vector2(0, ring_outer_edge); - - int i = radialMenuButtons.size() - 1; - while (i >= 0) - { - RadialMenuButton region = radialMenuButtons.get(i); - //left side inner point - double x1m1; - double y1m1; - - //left side outer point - double x2m1; - double y2m1; - - //right side inner point - double x1m2; - double y1m2; - //right side outer point - double x2m2; - double y2m2; - - if (drawMode == 1) - { - //1 - x1m1 = outerEdge.x; - y1m1 = outerEdge.y; - outerEdge.Rotate(90); - - //2 - x2m1 = outerEdge.x; - y2m1 = outerEdge.y; - outerEdge.Rotate(90); - - //3 - x1m2 = outerEdge.x; - y1m2 = outerEdge.y; - outerEdge.Rotate(90); - - } - else if (drawMode == 2) - { - //1 - x1m1 = outerEdge.x; - y1m1 = outerEdge.y; - outerEdge.Rotate(60); - - //2 - x2m1 = outerEdge.x; - y2m1 = outerEdge.y; - outerEdge.Rotate(60); - - //3 - x1m2 = outerEdge.x; - y1m2 = outerEdge.y; - outerEdge.Rotate(60); - - } - else - { - - //left side inner point - x1m1 = innerEdge.x; - y1m1 = innerEdge.y; - - //left side outer point - x2m1 = outerEdge.x; - y2m1 = outerEdge.y; - - //rotate vectors around the point - innerEdge.Rotate(-(360f / totalButtons)); - outerEdge.Rotate(-(360f / totalButtons)); - - //right side inner point - x1m2 = innerEdge.x; - y1m2 = innerEdge.y; - - } - //4 or right side outer point - x2m2 = outerEdge.x; - y2m2 = outerEdge.y; - - //the center of a regular polygon can be found by adding up - // all corner positions and divide by the total count - region.centerX = (x1m1 + x2m1 + x1m2 + x2m2) / 4; - region.centerY = (y1m1 + y2m1 + y1m2 + y2m2) / 4; - - - float a = 0.5f; - float f = 0f; - - final boolean showHighlight; - if (drawMode <= 2) - { - showHighlight = - MathHelper.inTriangle( - x1m1, y1m1, - x2m1, y2m1, - x1m2, y1m2, - mouseVecX, mouseVecY) - || MathHelper.inTriangle( - x1m2, y1m2, - x2m2, y2m2, - x1m1, y1m1, - mouseVecX, mouseVecY); - } - else - { - showHighlight = - MathHelper.inTriangle( - x1m1, y1m1, - x2m2, y2m2, - x2m1, y2m1, - mouseVecX, mouseVecY) - || MathHelper.inTriangle( - x1m1, y1m1, - x1m2, y1m2, - x2m2, y2m2, - mouseVecX, mouseVecY); - } - - //if mouse is within the region, as defined by the two triangles - //if (begin_rad <= mouseAngle && mouseAngle <= end_rad && showHighlight) - if (showHighlight) - { - f = 0.1f; - region.highlighted = true; - selectedManifestation = region.manifestation; - } - else - { - region.highlighted = false; - } - - float lerpPositive = 0; - float lerpNegative = 0; - float green = 0; - - if (region.manifestation != null) - { - int mode = region.manifestation.getMode(spiritweb); - int modeMin = region.manifestation.modeMin(spiritweb); - int modeMax = region.manifestation.modeMax(spiritweb); - - if (region.manifestation.hasMenu()) - { - lerpPositive = 0.25f; - green = 0.25f; - lerpNegative = 0.25f; - a = 0.75f; - } - else if (mode > 0) - { - lerpPositive = MathHelper.InverseLerp(0, modeMax, mode) - 0.1f; - } - else if (mode < 0) - { - lerpNegative = MathHelper.InverseLerp(0, Math.abs(modeMin), Math.abs(mode)) - 0.1f; - } - } - - float r = lerpPositive + f; - float g = f + green; - float b = lerpNegative + f; - - if (drawMode <= 2) - { - buffer.vertex(middle_x + x2m1, middle_y + y2m1, 0).color(r, g, b, a).endVertex(); - buffer.vertex(middle_x + x1m1, middle_y + y1m1, 0).color(r, g, b, a).endVertex(); - } - else - { - //set the square pos - buffer.vertex(middle_x + x1m1, middle_y + y1m1, 0).color(r, g, b, a).endVertex(); - buffer.vertex(middle_x + x2m1, middle_y + y2m1, 0).color(r, g, b, a).endVertex(); - } - - buffer.vertex(middle_x + x2m2, middle_y + y2m2, 0).color(r, g, b, a).endVertex(); - buffer.vertex(middle_x + x1m2, middle_y + y1m2, 0).color(r, g, b, a).endVertex(); - - i--; - } - } + // no pause >:( + return false; } - public SpiritwebCapability getSpiritweb() + public static void selectManiCallback(Manifestation manifestation) { - return spiritweb; + selectedManifestation = manifestation; + selectedManifestationType = manifestation.getManifestationType(); } - -} \ No newline at end of file +} diff --git a/src/main/java/leaf/cosmere/client/gui/SpiritwebRegistry.java b/src/main/java/leaf/cosmere/client/gui/SpiritwebRegistry.java new file mode 100644 index 000000000..56baff54d --- /dev/null +++ b/src/main/java/leaf/cosmere/client/gui/SpiritwebRegistry.java @@ -0,0 +1,33 @@ +package leaf.cosmere.client.gui; + +import leaf.cosmere.api.Manifestations; +import net.minecraft.client.gui.screens.Screen; + +import java.util.HashMap; +import java.util.function.Supplier; + +public class SpiritwebRegistry +{ + private static volatile SpiritwebRegistry INSTANCE = new SpiritwebRegistry(); + private final HashMap> manifestationScreenMap = new HashMap<>(); + + public static SpiritwebRegistry getInstance() + { + return INSTANCE; + } + + public void register(Manifestations.ManifestationTypes maniType, Supplier subScreen) + { + manifestationScreenMap.put(maniType, subScreen); + } + + public HashMap> getManifestationScreenMap() + { + return manifestationScreenMap; + } + + public void clear() + { + manifestationScreenMap.clear(); + } +} diff --git a/src/main/java/leaf/cosmere/client/gui/TabButton.java b/src/main/java/leaf/cosmere/client/gui/TabButton.java new file mode 100644 index 000000000..8410eda2d --- /dev/null +++ b/src/main/java/leaf/cosmere/client/gui/TabButton.java @@ -0,0 +1,90 @@ +package leaf.cosmere.client.gui; + +import com.mojang.blaze3d.systems.RenderSystem; +import leaf.cosmere.api.Manifestations; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.Button; +import net.minecraft.network.chat.CommonComponents; +import net.minecraft.resources.ResourceLocation; +import org.lwjgl.opengl.GL11; + +public class TabButton extends Button +{ + private static final int WIDTH = 32; + private static final int HEIGHT = 32; + private static final int START_Y = 10; + public Manifestations.ManifestationTypes manifestation; + + public TabButton(int x, Button.OnPress onPress, Manifestations.ManifestationTypes manifestation) + { + super(x, START_Y, WIDTH, HEIGHT, CommonComponents.EMPTY, onPress, DEFAULT_NARRATION); + this.manifestation = manifestation; + } + + @Override + protected void renderWidget(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) + { + renderBackground(pGuiGraphics, pMouseX, pMouseY); + renderIcon(pGuiGraphics, pMouseX, pMouseY); + } + + private void renderBackground(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY) + { + float alpha = isMouseOver(pMouseX, pMouseY) ? 1.0f : 0.3f; + alpha = (SpiritwebMenu.selectedManifestationType == this.manifestation) ? 1.0f : alpha; + final ResourceLocation resourceLocation = new ResourceLocation(manifestation.getName(), "textures/gui/hud_background.png"); + + if (Minecraft.getInstance().getResourceManager().getResource(resourceLocation).isPresent()) + { + RenderSystem.setShaderTexture(0, resourceLocation); + float[] shaderColor = RenderSystem.getShaderColor(); + RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, alpha); + + RenderSystem.enableBlend(); + RenderSystem.blendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0); + pGuiGraphics.blit( + resourceLocation, + getX(), + getY(), + 0, + 0, + width, + height, + width, + height + ); + } + else + { + pGuiGraphics.fill(getX(), getY(), getX()+width, getY()+height, 0x99333333); + } + + RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f); + } + + private void renderIcon(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY) + { + float alpha = isMouseOver(pMouseX, pMouseY) ? 1.0f : 0.3f; + alpha = (SpiritwebMenu.selectedManifestationType == this.manifestation) ? 1.0f : alpha; + final ResourceLocation resourceLocation = new ResourceLocation(manifestation.getName(), "textures/icon/" + manifestation.getName() + ".png"); + RenderSystem.setShaderTexture(0, resourceLocation); + RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, alpha); + + RenderSystem.enableBlend(); + RenderSystem.blendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0); + pGuiGraphics.blit( + resourceLocation, + getX()+1, + getY()+1, + 0, + 0, + width-2, + height-2, + width-2, + height-2 + ); + + RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f); + } +} diff --git a/src/main/java/leaf/cosmere/common/cap/entity/SpiritwebCapability.java b/src/main/java/leaf/cosmere/common/cap/entity/SpiritwebCapability.java index be75795db..e8c5494c9 100644 --- a/src/main/java/leaf/cosmere/common/cap/entity/SpiritwebCapability.java +++ b/src/main/java/leaf/cosmere/common/cap/entity/SpiritwebCapability.java @@ -6,16 +6,14 @@ package leaf.cosmere.common.cap.entity; import com.google.common.collect.Maps; -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.*; import leaf.cosmere.api.CosmereAPI; -import leaf.cosmere.api.IHasMetalType; import leaf.cosmere.api.ISpiritwebSubmodule; import leaf.cosmere.api.Manifestations; import leaf.cosmere.api.cosmereEffect.CosmereEffect; import leaf.cosmere.api.cosmereEffect.CosmereEffectInstance; import leaf.cosmere.api.manifestation.Manifestation; import leaf.cosmere.api.spiritweb.ISpiritweb; +import leaf.cosmere.client.gui.SpiritwebHud; import leaf.cosmere.common.Cosmere; import leaf.cosmere.common.config.CosmereConfigs; import leaf.cosmere.common.network.packets.ChangeManifestationModeMessage; @@ -24,14 +22,11 @@ import leaf.cosmere.common.registry.GameEventRegistry; import leaf.cosmere.common.registry.ManifestationRegistry; import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.renderer.GameRenderer; -import net.minecraft.client.resources.language.I18n; +import net.minecraft.client.gui.components.AbstractWidget; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.Mth; @@ -41,6 +36,7 @@ import net.minecraft.world.entity.ai.attributes.Attribute; import net.minecraft.world.entity.ai.attributes.AttributeInstance; import net.minecraft.world.entity.ai.attributes.AttributeMap; +import net.minecraft.world.entity.player.Player; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.client.event.RenderLevelStageEvent; @@ -52,9 +48,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; -import java.io.FileNotFoundException; import java.util.*; -import java.util.List; /* "The actual outlet of the power is not chosen by the practitioner, but instead is hardwritten into their Spiritweb" @@ -75,6 +69,8 @@ public class SpiritwebCapability implements ISpiritweb public final Map MANIFESTATIONS_MODE = new HashMap<>(); private Manifestation selectedManifestation = ManifestationRegistry.NONE.get(); + @OnlyIn(Dist.CLIENT) + private SpiritwebHud spiritwebHud; public List pushBlocks = new ArrayList<>(4); public List pushEntities = new ArrayList<>(4); @@ -545,205 +541,6 @@ public void renderWorldEffects(RenderLevelStageEvent event) } } - public void renderSelectedHUD(GuiGraphics gg) - { - if (CosmereConfigs.CLIENT_CONFIG.disableSelectedManifestationHud.get() || selectedManifestation.getManifestationType() == Manifestations.ManifestationTypes.NONE) - { - return; - } - - Minecraft mc = Minecraft.getInstance(); - int startX = CosmereConfigs.CLIENT_CONFIG.hudXCoordinate.get(); - int startY = CosmereConfigs.CLIENT_CONFIG.hudYCoordinate.get(); - int size = CosmereConfigs.CLIENT_CONFIG.hudSize.get(); - - String stringToDraw = I18n.get(selectedManifestation.getTextComponent().getString()); - int xOffset = -5; - float textScale = size / (float) (mc.font.width(stringToDraw) - 20); - gg.pose().pushPose(); - gg.pose().scale(textScale, textScale, 1f); - gg.drawString(mc.font, stringToDraw, (int) ((startX + xOffset) / textScale), (int) ((startY + size + 5) / textScale), 0xFFFFFF); - gg.pose().popPose(); - - int mode = getMode(selectedManifestation); - - String stringToDraw2 = ""; - - gg.pose().pushPose(); - RenderSystem.setShader(GameRenderer::getPositionTexShader); - RenderSystem.enableBlend(); - RenderSystem.defaultBlendFunc(); - Tesselator tesselator = Tesselator.getInstance(); - BufferBuilder buffer = tesselator.getBuilder(); - - // draw square - try { - final ResourceLocation textureLocation = new ResourceLocation(selectedManifestation.getRegistryName().getNamespace(), "textures/gui/hud_background.png"); - mc.getResourceManager().getResourceOrThrow(textureLocation); - - RenderSystem.setShaderTexture(0, textureLocation); - gg.blit(textureLocation, - startX, - startY, - size, - size, - 0, - 0, - 18, - 18, - 18, - 18); - } - catch (FileNotFoundException ex) // backup in case no texture - { - RenderSystem.setShader(GameRenderer::getPositionColorShader); - buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); - int color = 0xCC000000; - //set first triangle - buffer.vertex(startX, startY, 0).color(color).endVertex(); - buffer.vertex(startX, startY + size, 0).color(color).endVertex(); - //set second triangle - buffer.vertex(startX + size, startY + size, 0).color(color).endVertex(); - buffer.vertex(startX + size, startY, 0).color(color).endVertex(); - tesselator.end(); - } - - // draw manifestation icon - { - final StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.setLength(0); - String manifestationTypeName = selectedManifestation.getManifestationType().getName(); - stringBuilder - .append("textures/icon/") - .append(manifestationTypeName) - .append("/"); - switch (selectedManifestation.getManifestationType()) - { - case ALLOMANCY: - case FERUCHEMY: - if (selectedManifestation instanceof IHasMetalType metalType) - { - stringBuilder.append(metalType.getMetalType().getName()); - } - break; - case SURGEBINDING: - stringBuilder.append(selectedManifestation.getName()); - break; - case AON_DOR: - break; - case AWAKENING: - break; - } - stringBuilder.append(".png"); - - final ResourceLocation textureLocation = new ResourceLocation(selectedManifestation.getRegistryName().getNamespace(), stringBuilder.toString()); - RenderSystem.setShaderTexture(0, textureLocation); - int posX = startX + 4; - int posY = startY + 2; - if (selectedManifestation.getManifestationType() != Manifestations.ManifestationTypes.ALLOMANCY && selectedManifestation.getManifestationType() != Manifestations.ManifestationTypes.FERUCHEMY) - { - posX = startX + 2; - } - gg.blit(textureLocation, - posX, - posY, - size - 4, - size - 4, - 0, - 0, - 18, - 18, - 18, - 18); - } - - // todo draw pentagon -// { -// int color = 0xCC000000; -// float centerX = (float) mc.getWindow().getGuiScaledWidth() /2;//startX + (float) size / 2; -// float centerY = (float) mc.getWindow().getGuiScaledHeight() /2;//startY + size + 10; -// float[][] pentagonVertices = calculatePentagonVertices(centerX, centerY, 40, 0.5f); -// -// RenderSystem.setShader(GameRenderer::getPositionColorShader); -// buffer.begin(VertexFormat.Mode.TRIANGLE_FAN, DefaultVertexFormat.POSITION_COLOR); -// -// buffer.vertex(centerX, centerY, 0).color(color).endVertex(); // Center point for triangle fan -// for (float[] vertex : pentagonVertices) -// { -// buffer.vertex(vertex[0], vertex[1], 0).color(color).endVertex(); -// } -// buffer.vertex(pentagonVertices[0][0], pentagonVertices[0][1], 0).color(color).endVertex(); -// tesselator.end(); -// } - - gg.pose().popPose(); - RenderSystem.disableBlend(); - - //todo migrate drawing text to manifestation, this shouldn't be in main module. - if (selectedManifestation.getManifestationType() == Manifestations.ManifestationTypes.FERUCHEMY) - { - //todo translations - if (mode < 0) - { - stringToDraw2 = "T" + mode; - } - else if (mode > 0) - { - stringToDraw2 = "S" + mode; - } - else - { - //don't draw - //stringToDraw2 = ""; - } - } - else if (selectedManifestation.getManifestationType() == Manifestations.ManifestationTypes.ALLOMANCY) - { - String rate; - - switch (mode) - { - case -2 -> rate = "CF"; - case -1 -> rate = "C"; - default -> rate = ""; - case 1 -> rate = "B"; - case 2, 3 -> rate = "F";//copper has a 3rd mode for only smoking self - } - stringToDraw2 = rate; - } - - //todo translations - if (!stringToDraw2.isEmpty()) - { - int yOffset = (size / 2) - (stringToDraw2.length() * mc.font.lineHeight) / 2; // center the text vertically - for (char c : stringToDraw2.toCharArray()) - { - if (c == '-') - c = '|'; - xOffset = mc.font.width(String.valueOf(c)) / 2 - 4; - gg.drawString(mc.font, String.valueOf(c), startX - xOffset, startY + yOffset, 0xFFFFFF); - yOffset += mc.font.lineHeight; - } - } - } - - static float[][] calculatePentagonVertices(float centerX, float centerY, float radius, float scaleY) - { -// for i in range(5): -// angle = 2 * math.pi * i / 5 # Divide 360° into 5 angles (in radians) -// x = cx + radius * math.cos(angle) -// y = cy + radius * math.sin(angle) -// vertices.append((x, y)) -// return vertices - float[][] vertices = new float[5][2]; - for (int i = 0; i < 5; i++) { - double angle = 2 * Math.PI * ((double) i / 5); - vertices[i][0] = centerX + (float) (radius * Math.cos(angle)); - vertices[i][1] = centerY + (float) (radius * Math.sin(angle)); // Scale Y - } - return vertices; - } - @Override public void setSelectedManifestation(Manifestation manifestation) { @@ -825,6 +622,17 @@ public boolean hasManifestation(Manifestation manifestation, boolean ignoreTempo return false; } + @Override + public boolean hasManifestationOfType(Manifestations.ManifestationTypes type) + { + for (int i = 0; i < type.getNumberOfManifestations(); i++) + { + if (hasManifestation(type.getManifestation(i))) + return true; + } + return false; + } + @Override public void giveManifestation(Manifestation manifestation, int baseValue) { @@ -1071,6 +879,15 @@ public void syncToClients(@Nullable ServerPlayer serverPlayerEntity) } } + @Override + @OnlyIn(Dist.CLIENT) + public AbstractWidget getSpiritwebHud() + { + if (spiritwebHud == null && livingEntity instanceof Player player) + spiritwebHud = new SpiritwebHud(player); + return spiritwebHud; + } + public void saveNewState(int num) { if(num < 0 || num > 8) diff --git a/src/main/java/leaf/cosmere/common/config/CosmereClientConfig.java b/src/main/java/leaf/cosmere/common/config/CosmereClientConfig.java index b0a267352..1d27094ae 100644 --- a/src/main/java/leaf/cosmere/common/config/CosmereClientConfig.java +++ b/src/main/java/leaf/cosmere/common/config/CosmereClientConfig.java @@ -14,7 +14,8 @@ public class CosmereClientConfig implements ICosmereConfig public final ForgeConfigSpec.BooleanValue disableSelectedManifestationHud; public final ForgeConfigSpec.IntValue hudXCoordinate; public final ForgeConfigSpec.IntValue hudYCoordinate; - public final ForgeConfigSpec.IntValue hudSize; + public final ForgeConfigSpec.IntValue hudSizeX; + public final ForgeConfigSpec.IntValue hudSizeY; public final ForgeConfigSpec.BooleanValue disableActivatorChatMessage; @@ -28,8 +29,9 @@ public class CosmereClientConfig implements ICosmereConfig disableSelectedManifestationHud = builder.comment("Disables the HUD for selected power").define("disableSelectedManifestationHud", false); hudXCoordinate = builder.comment("X coordinate for the HUD").defineInRange("hudXCoordinate", 10, 0, Integer.MAX_VALUE); - hudYCoordinate = builder.comment("Y coordinate for the HUD").defineInRange("hudYCoordinate", 20, 0, Integer.MAX_VALUE); - hudSize = builder.comment("Size of the icon in the HUD; both width and height").defineInRange("hudSize", 40, 0, Integer.MAX_VALUE); + hudYCoordinate = builder.comment("Y coordinate for the HUD").defineInRange("hudYCoordinate", 40, 0, Integer.MAX_VALUE); + hudSizeX = builder.comment("Width of the HUD").defineInRange("hudSizeX", 140, 0, Integer.MAX_VALUE); + hudSizeY = builder.comment("Height of the HUD").defineInRange("hudSizeY", 30, 0, Integer.MAX_VALUE); disableActivatorChatMessage = builder.comment("Disables the chat message alerting you when you active or save a power state").define("disableActivatorChatMessage", false); builder.pop(); diff --git a/src/sandmastery/java/leaf/cosmere/sandmastery/client/gui/RadialButton.java b/src/sandmastery/java/leaf/cosmere/sandmastery/client/gui/RadialButton.java new file mode 100644 index 000000000..d653cda2e --- /dev/null +++ b/src/sandmastery/java/leaf/cosmere/sandmastery/client/gui/RadialButton.java @@ -0,0 +1,268 @@ +package leaf.cosmere.sandmastery.client.gui; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.Tesselator; +import com.mojang.blaze3d.vertex.VertexFormat; +import leaf.cosmere.api.Manifestations; +import leaf.cosmere.api.manifestation.Manifestation; +import leaf.cosmere.client.gui.GuiUtils; +import leaf.cosmere.client.gui.SpiritwebMenu; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.resources.language.I18n; +import net.minecraft.network.chat.CommonComponents; +import net.minecraft.resources.ResourceLocation; +import org.joml.Matrix4f; +import org.lwjgl.opengl.GL11; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +public class RadialButton extends Button +{ + private final ResourceLocation iconLocation; + private final List cachedQuads = new ArrayList<>(); + private final Consumer manifestationConsumer; + private final int radius, centerX, centerY, segmentNr; + private final float startAngle; + private final float endAngle; + private final Manifestation manifestation; + protected RadialButton(int pX, int pY, int radius, int segmentNr, Manifestation manifestation, Consumer maniConsumer) + { + super(pX, pY, 16, 16, CommonComponents.EMPTY, (button) -> { }, DEFAULT_NARRATION); + this.manifestation = manifestation; + this.radius = radius; + this.segmentNr = segmentNr; + centerX = pX; + centerY = pY; + + float fifthCircle = (float) Math.toRadians(360d/5d); + startAngle = (float) (fifthCircle*segmentNr); + endAngle = startAngle + fifthCircle; + + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.setLength(0); + stringBuilder.append("textures/icon/") + .append(manifestation.getManifestationType().getName()) + .append("/.png"); + + iconLocation = new ResourceLocation(manifestation.getRegistryName().getNamespace(), stringBuilder.toString()); + + manifestationConsumer = maniConsumer; + + calculateVertexes(centerX, centerY, radius, segmentNr); + } + + @Override + public boolean isMouseOver(double mouseX, double mouseY) + { + boolean retVal; + double distanceX = mouseX - centerX; + double distanceY = mouseY - centerY; + double dSqr = distanceX * distanceX + distanceY * distanceY; + + if (dSqr > radius * radius) + { + return false; + } + + double angle = Math.atan2(distanceY, distanceX); + + if (angle < 0) { + angle += 2 * Math.PI; + } + + double start = normalizeAngle(startAngle); + double end = normalizeAngle(endAngle); + angle = normalizeAngle(angle); + + if (start <= end) + { + retVal = angle >= start && angle <= end; + } + else + { + retVal = angle >= start || angle <= end; + } + + if (retVal) + { + manifestationConsumer.accept(manifestation); + } + + + return retVal; + } + + @Override + public boolean mouseClicked(double pMouseX, double pMouseY, int pButton) + { + return false; + } + + @Override + public void render(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) + { + boolean isHovered = isMouseOver(pMouseX, pMouseY); + renderRadial(pGuiGraphics, isHovered); + renderIcon(pGuiGraphics); + if (isHovered) + renderInfoBlock(pGuiGraphics); + } + + private void renderRadial(GuiGraphics pGuiGraphics, boolean isHovered) + { + float r = GuiUtils.BACKGROUND_COLOR.getRed()/255.f, g = GuiUtils.BACKGROUND_COLOR.getGreen()/255.f, b = GuiUtils.BACKGROUND_COLOR.getBlue()/255.f; + float a = 1f; + + if (isHovered) + { + r *= 1.1f; + g *= 1.1f; + b *= 1.1f; + } + + RenderSystem.disableCull(); + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + RenderSystem.setShader(GameRenderer::getPositionColorShader); + Matrix4f pose = pGuiGraphics.pose().last().pose(); + + Tesselator tess = Tesselator.getInstance(); + BufferBuilder buf = tess.getBuilder(); + + buf.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); + + for (GuiUtils.CachedQuad quad : cachedQuads) + { + float px = quad.px(); + float py = quad.py(); + float size = quad.size(); + + buf.vertex(pose, px, py, 0).color(r, g, b, a).endVertex(); + buf.vertex(pose, px, py + size, 0).color(r, g, b, a).endVertex(); + buf.vertex(pose, px + size, py + size, 0).color(r, g, b, a).endVertex(); + buf.vertex(pose, px + size, py, 0).color(r, g, b, a).endVertex(); + } + + tess.end(); + RenderSystem.disableBlend(); + } + + private void renderIcon(GuiGraphics pGuiGraphics) + { + float alpha = 1.0f; + RenderSystem.setShaderTexture(0, iconLocation); + RenderSystem.enableBlend(); + RenderSystem.blendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0); + + double midAngle = (startAngle + endAngle) / 2; + double midRadius = (radius) / 1.5; + int iconSize = width-2; + int posX = centerX + (int)(Math.cos(midAngle) * midRadius) - iconSize/2; + int posY = centerY + (int)(Math.sin(midAngle) * midRadius) - iconSize/2; + + RenderSystem.setShaderColor(0f, 0f, 0f, alpha); + pGuiGraphics.blit(iconLocation, + posX+1, + posY+1, + iconSize, + iconSize, + 0, + 0, + width, + height, + width, + height); + + RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, alpha); + pGuiGraphics.blit(iconLocation, + posX, + posY, + iconSize, + iconSize, + 0, + 0, + width, + height, + width, + height); + + RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f); + } + + private void renderInfoBlock(GuiGraphics pGuiGraphics) + { + Font font = Minecraft.getInstance().font; + float radsPerSegment = (float) (Math.PI * 2 / 5); + float midAngle = (segmentNr * radsPerSegment) + (radsPerSegment / 2f); + + int padding = 15; + float textOffsetDist = radius + padding; + + int textCenterX = (int) (centerX + Math.cos(midAngle) * textOffsetDist); + int textCenterY = (int) (centerY + Math.sin(midAngle) * textOffsetDist); + + int drawY = textCenterY - (font.lineHeight / 2); + + String text = I18n.get(manifestation.getTranslationKey()).replace("Sand Mastery ", ""); + + pGuiGraphics.drawCenteredString(font, text, textCenterX, drawY, 0xFFFFFF); + } + + private void calculateVertexes(float centerX, float centerY, float radius, int segmentNr) + { + cachedQuads.clear(); + + float radsPerSegment = (float) Math.PI * 2 / 5; + float startAngle = segmentNr * radsPerSegment; + float radiusSq = radius * radius; + + int pixelSize = 1; + int rInt = (int) Math.ceil(radius); + + for (int x = -rInt; x <= rInt; x += pixelSize) + { + for (int y = -rInt; y <= rInt; y += pixelSize) + { + float pixelCenterX = x + (pixelSize / 2f); + float pixelCenterY = y + (pixelSize / 2f); + + float distSq = pixelCenterX * pixelCenterX + pixelCenterY * pixelCenterY; + + if (distSq <= radiusSq) + { + float angle = (float) Math.atan2(pixelCenterY, pixelCenterX); + if (angle < 0) angle += (float) (Math.PI * 2); + + float diff = angle - startAngle; + if (diff < 0) diff += (float) (Math.PI * 2); + + if (diff < radsPerSegment) + { + cachedQuads.add(new GuiUtils.CachedQuad(centerX + x, centerY + y, pixelSize)); + } + } + } + } + } + + private double normalizeAngle(double angle) + { + if (angle != 0) + { + angle = angle % (2 * Math.PI); + if (angle < 0) + { + angle += 2 * Math.PI; + } + } + return angle; + } +} diff --git a/src/sandmastery/java/leaf/cosmere/sandmastery/client/gui/SandmasterySpiritwebMenu.java b/src/sandmastery/java/leaf/cosmere/sandmastery/client/gui/SandmasterySpiritwebMenu.java new file mode 100644 index 000000000..df03d20c7 --- /dev/null +++ b/src/sandmastery/java/leaf/cosmere/sandmastery/client/gui/SandmasterySpiritwebMenu.java @@ -0,0 +1,45 @@ +package leaf.cosmere.sandmastery.client.gui; + +import leaf.cosmere.api.Manifestations; +import leaf.cosmere.api.manifestation.Manifestation; +import leaf.cosmere.client.gui.CosmereScreen; +import leaf.cosmere.client.gui.SpiritwebMenu; +import leaf.cosmere.common.cap.entity.SpiritwebCapability; +import net.minecraft.client.Minecraft; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.network.chat.Component; + +import java.util.List; + +public class SandmasterySpiritwebMenu extends CosmereScreen +{ + final LocalPlayer player; + public SandmasterySpiritwebMenu() + { + super(Component.literal("Sandmastery"), SpiritwebMenu::selectManiCallback); + player = Minecraft.getInstance().player; + } + + @Override + protected void init() + { + super.init(); + + int centerX = width/2; + int centerY = height/2 + height/16; + + SpiritwebCapability.get(player).ifPresent( (spiritweb -> { + final List availableManifestations = spiritweb.getAvailableManifestations(); + + int i = 0; + for (Manifestation mani : availableManifestations) + { + if (mani.getManifestationType() == Manifestations.ManifestationTypes.SANDMASTERY) + { + addRenderableWidget(new RadialButton(centerX, centerY, height/3, i, mani, manifestationConsumer)); + i++; + } + } + })); + } +} diff --git a/src/sandmastery/java/leaf/cosmere/sandmastery/common/capabilities/SandmasterySpiritwebSubmodule.java b/src/sandmastery/java/leaf/cosmere/sandmastery/common/capabilities/SandmasterySpiritwebSubmodule.java index f3c95a5d7..610f28dd5 100644 --- a/src/sandmastery/java/leaf/cosmere/sandmastery/common/capabilities/SandmasterySpiritwebSubmodule.java +++ b/src/sandmastery/java/leaf/cosmere/sandmastery/common/capabilities/SandmasterySpiritwebSubmodule.java @@ -13,7 +13,10 @@ import leaf.cosmere.api.manifestation.Manifestation; import leaf.cosmere.api.spiritweb.ISpiritweb; import leaf.cosmere.client.Keybindings; +import leaf.cosmere.client.gui.SpiritwebRegistry; +import leaf.cosmere.common.cap.entity.SpiritwebCapability; import leaf.cosmere.sandmastery.client.SandmasteryKeybindings; +import leaf.cosmere.sandmastery.client.gui.SandmasterySpiritwebMenu; import leaf.cosmere.sandmastery.common.Sandmastery; import leaf.cosmere.sandmastery.common.config.SandmasteryConfigs; import leaf.cosmere.sandmastery.common.manifestation.SandmasteryManifestation; @@ -22,6 +25,7 @@ import leaf.cosmere.sandmastery.common.registries.SandmasteryEffects; import leaf.cosmere.sandmastery.common.registries.SandmasteryItems; import leaf.cosmere.sandmastery.common.utils.SandmasteryConstants; +import net.minecraft.client.Minecraft; import net.minecraft.nbt.CompoundTag; import net.minecraft.util.Mth; import net.minecraft.world.entity.LivingEntity; @@ -181,14 +185,14 @@ public void drainInvestiture(ISpiritweb data, double strength) // we could force it to turn off ribbons? } - @Override - @OnlyIn(Dist.CLIENT) - public void collectMenuInfo(List m_infoText) - { - //todo Localization - final String text = "Hydration: " + getHydrationLevel(); - m_infoText.add(text); - } +// @Override +// @OnlyIn(Dist.CLIENT) +// public void collectMenuInfo(List m_infoText) +// { +// //todo Localization +// final String text = "Hydration: " + getHydrationLevel(); +// m_infoText.add(text); +// } @Override public void GiveStartingItem(Player player) @@ -206,6 +210,16 @@ public void GiveStartingItem(Player player, Manifestation manifestation) { } + @Override + @OnlyIn(Dist.CLIENT) + public void registerMenu() + { + SpiritwebCapability.get(Minecraft.getInstance().player).ifPresent(spiritweb -> { + if (spiritweb.hasManifestationOfType(Manifestations.ManifestationTypes.SANDMASTERY)) + SpiritwebRegistry.getInstance().register(Manifestations.ManifestationTypes.SANDMASTERY, SandmasterySpiritwebMenu::new); + }); + } + @Override public List getPowers() { diff --git a/src/soulforgery/java/leaf/cosmere/soulforgery/common/capabilities/SoulforgerySpiritwebSubmodule.java b/src/soulforgery/java/leaf/cosmere/soulforgery/common/capabilities/SoulforgerySpiritwebSubmodule.java index e0ac9895f..9065988c1 100644 --- a/src/soulforgery/java/leaf/cosmere/soulforgery/common/capabilities/SoulforgerySpiritwebSubmodule.java +++ b/src/soulforgery/java/leaf/cosmere/soulforgery/common/capabilities/SoulforgerySpiritwebSubmodule.java @@ -10,8 +10,6 @@ import net.minecraft.world.entity.player.Player; import net.minecraftforge.client.event.RenderLevelStageEvent; -import java.util.List; - public class SoulforgerySpiritwebSubmodule implements ISpiritwebSubmodule { @Override @@ -38,12 +36,6 @@ public void tickServer(ISpiritweb spiritweb) } - @Override - public void collectMenuInfo(List m_infoText) - { - - } - @Override public void renderWorldEffects(ISpiritweb spiritweb, RenderLevelStageEvent event) { diff --git a/src/surgebinding/java/leaf/cosmere/surgebinding/client/SurgebindingKeybindings.java b/src/surgebinding/java/leaf/cosmere/surgebinding/client/SurgebindingKeybindings.java index 2f547b13b..4af3a3592 100644 --- a/src/surgebinding/java/leaf/cosmere/surgebinding/client/SurgebindingKeybindings.java +++ b/src/surgebinding/java/leaf/cosmere/surgebinding/client/SurgebindingKeybindings.java @@ -46,16 +46,13 @@ public class SurgebindingKeybindings @SubscribeEvent public static void register(RegisterKeyMappingsEvent event) { - - event.register(SHARDBLADE = new KeyMapping(KEY_SHARDBLADE, GLFW.GLFW_KEY_X, KEYS_CATEGORY)); - for (Roshar.Surges surge : SURGEBINDING_POWER.keySet()) { KeyMapping key = SURGEBINDING_POWER.get(surge); SurgebindingManifestation manifest = (SurgebindingManifestation) SURGEBINDING_POWERS.get(surge).getManifestation(); event.register(key); Activator entry = new Activator(key, manifest); - entry.setCategory("stormlight"); + entry.setCategory("keys.surgebinding.main"); Keybindings.activators.add(entry); } diff --git a/src/surgebinding/java/leaf/cosmere/surgebinding/client/gui/CircleButton.java b/src/surgebinding/java/leaf/cosmere/surgebinding/client/gui/CircleButton.java new file mode 100644 index 000000000..c947a5b2e --- /dev/null +++ b/src/surgebinding/java/leaf/cosmere/surgebinding/client/gui/CircleButton.java @@ -0,0 +1,212 @@ +package leaf.cosmere.surgebinding.client.gui; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.Tesselator; +import com.mojang.blaze3d.vertex.VertexFormat; +import leaf.cosmere.api.manifestation.Manifestation; +import leaf.cosmere.api.spiritweb.ISpiritweb; +import leaf.cosmere.client.gui.GuiUtils; +import leaf.cosmere.client.gui.SpiritwebMenu; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.resources.language.I18n; +import net.minecraft.network.chat.CommonComponents; +import net.minecraft.resources.ResourceLocation; +import org.joml.Matrix4f; +import org.lwjgl.opengl.GL11; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +public class CircleButton extends Button +{ + private final ResourceLocation iconLocation; + private final List cachedQuads = new ArrayList<>(); + private final Consumer manifestationConsumer; + final ISpiritweb spiritweb; + final Manifestation manifestation; + final int centerX, centerY; + final int radius; + + public CircleButton(int pX, int pY, int radius, ISpiritweb spiritweb, Manifestation manifestation, Consumer maniConsumer) + { + super(pX, pY, radius, radius, CommonComponents.EMPTY, (button) -> { }, DEFAULT_NARRATION); + + this.spiritweb = spiritweb; + this.centerX = pX; + this.centerY = pY; + this.radius = radius; + this.manifestation = manifestation; + + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.setLength(0); + stringBuilder.append("textures/icon/") + .append(manifestation.getManifestationType().getName()) + .append("/"); + + stringBuilder.append(manifestation.getName()); + stringBuilder.append(".png"); + + iconLocation = new ResourceLocation(manifestation.getRegistryName().getNamespace(), stringBuilder.toString()); + + manifestationConsumer = maniConsumer; + + calculateVertexes(centerX, centerY, radius); + } + + @Override + public boolean isMouseOver(double mouseX, double mouseY) { + double distanceX = mouseX - centerX; + double distanceY = mouseY - centerY; + + if ((distanceX * distanceX + distanceY * distanceY) <= (radius * radius)) { + manifestationConsumer.accept(manifestation); + return true; + } + + return false; + } + + @Override + public boolean mouseClicked(double pMouseX, double pMouseY, int pButton) + { + return false; + } + + @Override + public void render(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) + { + boolean isHovered = isMouseOver(pMouseX, pMouseY); + renderCircle(pGuiGraphics, isHovered); + renderIcon(pGuiGraphics); + if (isHovered) + renderText(pGuiGraphics); + } + + private void renderCircle(GuiGraphics pGuiGraphics, boolean isHovered) + { + float r = GuiUtils.BACKGROUND_COLOR.getRed()/255.f, g = GuiUtils.BACKGROUND_COLOR.getGreen()/255.f, b = GuiUtils.BACKGROUND_COLOR.getBlue()/255.f; + float a = 1f; + + if (isHovered) + { + r *= 1.1f; + g *= 1.1f; + b *= 1.1f; + } + + RenderSystem.disableCull(); + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + RenderSystem.setShader(GameRenderer::getPositionColorShader); + Matrix4f pose = pGuiGraphics.pose().last().pose(); + + Tesselator tess = Tesselator.getInstance(); + BufferBuilder buf = tess.getBuilder(); + + buf.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); + + for (GuiUtils.CachedQuad quad : cachedQuads) + { + float px = quad.px(); + float py = quad.py(); + float size = quad.size(); + + buf.vertex(pose, px, py, 0).color(r, g, b, a).endVertex(); + buf.vertex(pose, px, py + size, 0).color(r, g, b, a).endVertex(); + buf.vertex(pose, px + size, py + size, 0).color(r, g, b, a).endVertex(); + buf.vertex(pose, px + size, py, 0).color(r, g, b, a).endVertex(); + } + + tess.end(); + RenderSystem.disableBlend(); + } + + public void renderIcon(GuiGraphics pGuiGraphics) + { + float alpha = 1.0f; + RenderSystem.setShaderTexture(0, iconLocation); + RenderSystem.enableBlend(); + RenderSystem.blendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0); + + int iconSize = width-2; + int posX = centerX - iconSize/2; + int posY = centerY - iconSize/2; + + RenderSystem.setShaderColor(0f, 0f, 0f, alpha); + pGuiGraphics.blit(iconLocation, + posX+1, + posY+1, + iconSize, + iconSize, + 0, + 0, + width, + height, + width, + height); + + RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, alpha); + pGuiGraphics.blit(iconLocation, + posX, + posY, + iconSize, + iconSize, + 0, + 0, + width, + height, + width, + height); + + RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f); + } + + private void renderText(GuiGraphics pGuiGraphics) + { + Font font = Minecraft.getInstance().font; + String text = I18n.get(manifestation.getTranslationKey()); + int x; + int y = getY(); + int windowWidth = Minecraft.getInstance().getWindow().getGuiScaledWidth(); + + if (getX() < windowWidth/2) + { + x = getX() - radius - 5 - font.width(text); + } + else + { + x = getX() + radius + 5; + } + + pGuiGraphics.drawString(font, text, x, y-font.lineHeight/2, 0xFFFFFFFF); + } + + private void calculateVertexes(float centerX, float centerY, int radius) + { + cachedQuads.clear(); + + float radiusSq = radius * radius; + int pixelSize = 1; + + for (int x = -radius; x <= radius; x += pixelSize) + { + for (int y = -radius; y <= radius; y += pixelSize) + { + float pixelCenterX = x + (pixelSize / 2f); + float pixelCenterY = y + (pixelSize / 2f); + + if ((pixelCenterX * pixelCenterX + pixelCenterY * pixelCenterY) <= radiusSq) + { + cachedQuads.add(new GuiUtils.CachedQuad(centerX + x, centerY + y, pixelSize)); + } + } + } + } +} diff --git a/src/surgebinding/java/leaf/cosmere/surgebinding/client/gui/SurgebindingSpiritwebMenu.java b/src/surgebinding/java/leaf/cosmere/surgebinding/client/gui/SurgebindingSpiritwebMenu.java new file mode 100644 index 000000000..296792f7c --- /dev/null +++ b/src/surgebinding/java/leaf/cosmere/surgebinding/client/gui/SurgebindingSpiritwebMenu.java @@ -0,0 +1,51 @@ +package leaf.cosmere.surgebinding.client.gui; + +import leaf.cosmere.api.Manifestations; +import leaf.cosmere.api.manifestation.Manifestation; +import leaf.cosmere.client.gui.CosmereScreen; +import leaf.cosmere.client.gui.SpiritwebMenu; +import leaf.cosmere.common.cap.entity.SpiritwebCapability; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.network.chat.Component; + +import java.util.List; + +public class SurgebindingSpiritwebMenu extends CosmereScreen +{ + final LocalPlayer player; + public SurgebindingSpiritwebMenu() + { + super(Component.literal("Surgebinding"), SpiritwebMenu::selectManiCallback); + player = Minecraft.getInstance().player; + } + + @Override + protected void init() + { + super.init(); + + int radius = height/16; + + SpiritwebCapability.get(player).ifPresent( (spiritweb -> { + final List availableManifestations = spiritweb.getAvailableManifestations(); + + int i = 0; + for (Manifestation mani : availableManifestations) + { + if (mani.getManifestationType() == Manifestations.ManifestationTypes.SURGEBINDING) + { + addRenderableWidget(new CircleButton((int) (width/2f - radius*1.5 + (radius*3) * i), height/2, radius, spiritweb, mani, manifestationConsumer)); + i++; + } + } + })); + } + + @Override + public void render(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) + { + super.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick); + } +} diff --git a/src/surgebinding/java/leaf/cosmere/surgebinding/common/capabilities/SurgebindingSpiritwebSubmodule.java b/src/surgebinding/java/leaf/cosmere/surgebinding/common/capabilities/SurgebindingSpiritwebSubmodule.java index f5e9973be..e9d59f1c5 100644 --- a/src/surgebinding/java/leaf/cosmere/surgebinding/common/capabilities/SurgebindingSpiritwebSubmodule.java +++ b/src/surgebinding/java/leaf/cosmere/surgebinding/common/capabilities/SurgebindingSpiritwebSubmodule.java @@ -9,6 +9,10 @@ import leaf.cosmere.api.Manifestations; import leaf.cosmere.api.helpers.EffectsHelper; import leaf.cosmere.api.spiritweb.ISpiritweb; +import leaf.cosmere.client.gui.SpiritwebRegistry; +import leaf.cosmere.common.cap.entity.SpiritwebCapability; +import leaf.cosmere.common.items.CapWrapper; +import leaf.cosmere.surgebinding.client.gui.SurgebindingSpiritwebMenu; import leaf.cosmere.api.helpers.CuriosHelper; import leaf.cosmere.common.items.CapWrapper; import leaf.cosmere.common.registration.impl.ItemRegistryObject; @@ -19,6 +23,7 @@ import leaf.cosmere.surgebinding.common.manifestation.SurgeProgression; import leaf.cosmere.surgebinding.common.registries.SurgebindingDimensions; import leaf.cosmere.surgebinding.common.registries.SurgebindingItems; +import net.minecraft.client.Minecraft; import net.minecraft.nbt.CompoundTag; import net.minecraft.util.Mth; import net.minecraft.world.Container; @@ -28,6 +33,8 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.event.ServerChatEvent; import net.minecraftforge.items.wrapper.PlayerInvWrapper; import top.theillusivec4.curios.api.CuriosApi; @@ -179,6 +186,15 @@ public void drainInvestiture(ISpiritweb data, double strength) stormlightStored = (int) (stormlightStored * 0.1f); } + @Override + @OnlyIn(Dist.CLIENT) + public void registerMenu() + { + SpiritwebCapability.get(Minecraft.getInstance().player).ifPresent((spiritweb -> { + if (spiritweb.hasManifestationOfType(Manifestations.ManifestationTypes.SURGEBINDING)) + SpiritwebRegistry.getInstance().register(Manifestations.ManifestationTypes.SURGEBINDING, SurgebindingSpiritwebMenu::new); + })); + } private void requestGemStormlight(ItemStack item, int amountDrawn) {