Added gui classes and some textures from Create.

This commit is contained in:
Christian Knaapen
2023-01-24 23:46:45 +01:00
parent 4ea34fc854
commit a760565b66
38 changed files with 3798 additions and 0 deletions

View File

@@ -0,0 +1,39 @@
package nl.requios.effortlessbuilding.create;
import com.mojang.blaze3d.platform.InputConstants;
import net.minecraft.client.KeyMapping;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.Screen;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.RegisterKeyMappingsEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import org.lwjgl.glfw.GLFW;
public class AllKeys {
public static boolean isKeyDown(int key) {
return InputConstants.isKeyDown(Minecraft.getInstance()
.getWindow()
.getWindow(), key);
}
public static boolean isMouseButtonDown(int button) {
return GLFW.glfwGetMouseButton(Minecraft.getInstance()
.getWindow()
.getWindow(), button) == 1;
}
public static boolean ctrlDown() {
return Screen.hasControlDown();
}
public static boolean shiftDown() {
return Screen.hasShiftDown();
}
public static boolean altDown() {
return Screen.hasAltDown();
}
}

View File

@@ -0,0 +1,168 @@
package nl.requios.effortlessbuilding.create.foundation.gui;
import com.mojang.blaze3d.platform.InputConstants;
import com.mojang.blaze3d.vertex.PoseStack;
import nl.requios.effortlessbuilding.create.foundation.gui.widget.AbstractSimiWidget;
import nl.requios.effortlessbuilding.create.foundation.utility.Components;
import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.components.Widget;
import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.narration.NarratableEntry;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import java.util.Collection;
import java.util.List;
@OnlyIn(Dist.CLIENT)
public abstract class AbstractSimiScreen extends Screen {
protected int windowWidth, windowHeight;
protected int windowXOffset, windowYOffset;
protected int guiLeft, guiTop;
protected AbstractSimiScreen(Component title) {
super(title);
}
protected AbstractSimiScreen() {
this(Components.immutableEmpty());
}
/**
* This method must be called before {@code super.init()}!
*/
protected void setWindowSize(int width, int height) {
windowWidth = width;
windowHeight = height;
}
/**
* This method must be called before {@code super.init()}!
*/
protected void setWindowOffset(int xOffset, int yOffset) {
windowXOffset = xOffset;
windowYOffset = yOffset;
}
@Override
protected void init() {
guiLeft = (width - windowWidth) / 2;
guiTop = (height - windowHeight) / 2;
guiLeft += windowXOffset;
guiTop += windowYOffset;
}
@Override
public void tick() {
for (GuiEventListener listener : children()) {
if (listener instanceof TickableGuiEventListener tickable) {
tickable.tick();
}
}
}
@Override
public boolean isPauseScreen() {
return false;
}
@SuppressWarnings("unchecked")
protected <W extends GuiEventListener & Widget & NarratableEntry> void addRenderableWidgets(W... widgets) {
for (W widget : widgets) {
addRenderableWidget(widget);
}
}
protected <W extends GuiEventListener & Widget & NarratableEntry> void addRenderableWidgets(Collection<W> widgets) {
for (W widget : widgets) {
addRenderableWidget(widget);
}
}
protected void removeWidgets(GuiEventListener... widgets) {
for (GuiEventListener widget : widgets) {
removeWidget(widget);
}
}
protected void removeWidgets(Collection<? extends GuiEventListener> widgets) {
for (GuiEventListener widget : widgets) {
removeWidget(widget);
}
}
@Override
public void render(PoseStack ms, int mouseX, int mouseY, float partialTicks) {
partialTicks = minecraft.getFrameTime();
ms.pushPose();
prepareFrame();
renderWindowBackground(ms, mouseX, mouseY, partialTicks);
renderWindow(ms, mouseX, mouseY, partialTicks);
super.render(ms, mouseX, mouseY, partialTicks);
renderWindowForeground(ms, mouseX, mouseY, partialTicks);
endFrame();
ms.popPose();
}
@Override
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
boolean keyPressed = super.keyPressed(keyCode, scanCode, modifiers);
if (keyPressed || getFocused() != null)
return keyPressed;
InputConstants.Key mouseKey = InputConstants.getKey(keyCode, scanCode);
if (this.minecraft.options.keyInventory.isActiveAndMatches(mouseKey)) {
this.onClose();
return true;
}
return false;
}
protected void prepareFrame() {}
protected void renderWindowBackground(PoseStack ms, int mouseX, int mouseY, float partialTicks) {
renderBackground(ms);
}
protected abstract void renderWindow(PoseStack ms, int mouseX, int mouseY, float partialTicks);
protected void renderWindowForeground(PoseStack ms, int mouseX, int mouseY, float partialTicks) {
for (Widget widget : renderables) {
if (widget instanceof AbstractSimiWidget simiWidget && simiWidget.isHoveredOrFocused()
&& simiWidget.visible) {
List<Component> tooltip = simiWidget.getToolTip();
if (tooltip.isEmpty())
continue;
int ttx = simiWidget.lockedTooltipX == -1 ? mouseX : simiWidget.lockedTooltipX + simiWidget.x;
int tty = simiWidget.lockedTooltipY == -1 ? mouseY : simiWidget.lockedTooltipY + simiWidget.y;
renderComponentTooltip(ms, tooltip, ttx, tty);
}
}
}
protected void endFrame() {}
@Deprecated
protected void debugWindowArea(PoseStack matrixStack) {
fill(matrixStack, guiLeft + windowWidth, guiTop + windowHeight, guiLeft, guiTop, 0xD3D3D3D3);
}
@Override
public GuiEventListener getFocused() {
GuiEventListener focused = super.getFocused();
if (focused instanceof AbstractWidget && !((AbstractWidget) focused).isFocused())
focused = null;
setFocused(focused);
return focused;
}
}

View File

@@ -0,0 +1,95 @@
package nl.requios.effortlessbuilding.create.foundation.gui;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import nl.requios.effortlessbuilding.create.Create;
import nl.requios.effortlessbuilding.create.foundation.gui.element.ScreenElement;
import nl.requios.effortlessbuilding.create.foundation.utility.Color;
import net.minecraft.client.gui.GuiComponent;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
public enum AllGuiTextures implements ScreenElement {
// Widgets
BUTTON("widgets", 18, 18),
BUTTON_HOVER("widgets", 18, 0, 18, 18),
BUTTON_DOWN("widgets", 36, 0, 18, 18),
INDICATOR("widgets", 0, 18, 18, 6),
INDICATOR_WHITE("widgets", 18, 18, 18, 6),
INDICATOR_GREEN("widgets", 36, 18, 18, 6),
INDICATOR_YELLOW("widgets", 54, 18, 18, 6),
INDICATOR_RED("widgets", 72, 18, 18, 6),
HOTSLOT_ARROW("widgets", 24, 51, 20, 12),
HOTSLOT("widgets", 0, 68, 22, 22),
HOTSLOT_ACTIVE("widgets", 0, 46, 22, 22),
HOTSLOT_SUPER_ACTIVE("widgets", 27, 67, 24, 24),
SPEECH_TOOLTIP_BACKGROUND("widgets", 0, 24, 8, 8),
SPEECH_TOOLTIP_COLOR("widgets", 8, 24, 8, 8),
TRAIN_HUD_SPEED_BG("widgets", 0, 190, 182, 5),
TRAIN_HUD_SPEED("widgets", 0, 185, 182, 5),
TRAIN_HUD_THROTTLE("widgets", 0, 195, 182, 5),
TRAIN_HUD_THROTTLE_POINTER("widgets", 0, 209, 6, 9),
TRAIN_HUD_FRAME("widgets", 0, 200, 186, 7),
TRAIN_HUD_DIRECTION("widgets", 77, 165, 28, 20),
TRAIN_PROMPT_L("widgets", 8, 209, 3, 16),
TRAIN_PROMPT_R("widgets", 11, 209, 3, 16),
TRAIN_PROMPT("widgets", 0, 230, 256, 16),
;
public static final int FONT_COLOR = 0x575F7A;
public final ResourceLocation location;
public int width, height;
public int startX, startY;
private AllGuiTextures(String location, int width, int height) {
this(location, 0, 0, width, height);
}
private AllGuiTextures(int startX, int startY) {
this("icons", startX * 16, startY * 16, 16, 16);
}
private AllGuiTextures(String location, int startX, int startY, int width, int height) {
this(Create.ID, location, startX, startY, width, height);
}
private AllGuiTextures(String namespace, String location, int startX, int startY, int width, int height) {
this.location = new ResourceLocation(namespace, "textures/gui/" + location + ".png");
this.width = width;
this.height = height;
this.startX = startX;
this.startY = startY;
}
@OnlyIn(Dist.CLIENT)
public void bind() {
RenderSystem.setShaderTexture(0, location);
}
@OnlyIn(Dist.CLIENT)
@Override
public void render(PoseStack ms, int x, int y) {
bind();
GuiComponent.blit(ms, x, y, 0, startX, startY, width, height, 256, 256);
}
@OnlyIn(Dist.CLIENT)
public void render(PoseStack ms, int x, int y, GuiComponent component) {
bind();
component.blit(ms, x, y, startX, startY, width, height);
}
@OnlyIn(Dist.CLIENT)
public void render(PoseStack ms, int x, int y, Color c) {
bind();
UIRenderHelper.drawColoredTexture(ms, c, x, y, startX, startY, width, height);
}
}

View File

@@ -0,0 +1,224 @@
package nl.requios.effortlessbuilding.create.foundation.gui;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Matrix4f;
import nl.requios.effortlessbuilding.create.Create;
import nl.requios.effortlessbuilding.create.foundation.gui.element.DelegatedStencilElement;
import nl.requios.effortlessbuilding.create.foundation.gui.element.ScreenElement;
import nl.requios.effortlessbuilding.create.foundation.utility.Color;
import net.minecraft.client.gui.GuiComponent;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
public class AllIcons implements ScreenElement {
public static final ResourceLocation ICON_ATLAS = Create.asResource("textures/gui/icons.png");
public static final int ICON_ATLAS_SIZE = 256;
private static int x = 0, y = -1;
private int iconX;
private int iconY;
public static final AllIcons
I_ADD = newRow(),
I_TRASH = next(),
I_3x3 = next(),
I_TARGET = next(),
I_PRIORITY_VERY_LOW = next(),
I_PRIORITY_LOW = next(),
I_PRIORITY_HIGH = next(),
I_PRIORITY_VERY_HIGH = next(),
I_BLACKLIST = next(),
I_WHITELIST = next(),
I_WHITELIST_OR = next(),
I_WHITELIST_AND = next(),
I_WHITELIST_NOT = next(),
I_RESPECT_NBT = next(),
I_IGNORE_NBT = next();
public static final AllIcons
I_CONFIRM = newRow(),
I_NONE = next(),
I_OPEN_FOLDER = next(),
I_REFRESH = next(),
I_ACTIVE = next(),
I_PASSIVE = next(),
I_ROTATE_PLACE = next(),
I_ROTATE_PLACE_RETURNED = next(),
I_ROTATE_NEVER_PLACE = next(),
I_MOVE_PLACE = next(),
I_MOVE_PLACE_RETURNED = next(),
I_MOVE_NEVER_PLACE = next(),
I_CART_ROTATE = next(),
I_CART_ROTATE_PAUSED = next(),
I_CART_ROTATE_LOCKED = next();
public static final AllIcons
I_DONT_REPLACE = newRow(),
I_REPLACE_SOLID = next(),
I_REPLACE_ANY = next(),
I_REPLACE_EMPTY = next(),
I_CENTERED = next(),
I_ATTACHED = next(),
I_INSERTED = next(),
I_FILL = next(),
I_PLACE = next(),
I_REPLACE = next(),
I_CLEAR = next(),
I_OVERLAY = next(),
I_FLATTEN = next(),
I_LMB = next(),
I_SCROLL = next(),
I_RMB = next();
public static final AllIcons
I_TOOL_DEPLOY = newRow(),
I_SKIP_MISSING = next(),
I_SKIP_TILES = next(),
I_DICE = next(),
I_TUNNEL_SPLIT = next(),
I_TUNNEL_FORCED_SPLIT = next(),
I_TUNNEL_ROUND_ROBIN = next(),
I_TUNNEL_FORCED_ROUND_ROBIN = next(),
I_TUNNEL_PREFER_NEAREST = next(),
I_TUNNEL_RANDOMIZE = next(),
I_TUNNEL_SYNCHRONIZE = next(),
I_TOOLBOX = next(),
I_VIEW_SCHEDULE = next(),
I_TOOL_MOVE_XZ = newRow(),
I_TOOL_MOVE_Y = next(),
I_TOOL_ROTATE = next(),
I_TOOL_MIRROR = next(),
I_ARM_ROUND_ROBIN = next(),
I_ARM_FORCED_ROUND_ROBIN = next(),
I_ARM_PREFER_FIRST = next(),
I_ADD_INVERTED_ATTRIBUTE = next(),
I_FLIP = next(),
I_PLAY = newRow(),
I_PAUSE = next(),
I_STOP = next(),
I_PLACEMENT_SETTINGS = next(),
I_ROTATE_CCW = next(),
I_HOUR_HAND_FIRST = next(),
I_MINUTE_HAND_FIRST = next(),
I_HOUR_HAND_FIRST_24 = next(),
I_PATTERN_SOLID = newRow(),
I_PATTERN_CHECKERED = next(),
I_PATTERN_CHECKERED_INVERSED = next(),
I_PATTERN_CHANCE_25 = next(),
I_PATTERN_CHANCE_50 = newRow(),
I_PATTERN_CHANCE_75 = next(),
I_FOLLOW_DIAGONAL = next(),
I_FOLLOW_MATERIAL = next(),
I_SCHEMATIC = newRow(),
I_SEQ_REPEAT = next(),
I_MTD_LEFT = newRow(),
I_MTD_CLOSE = next(),
I_MTD_RIGHT = next(),
I_MTD_SCAN = next(),
I_MTD_REPLAY = next(),
I_MTD_USER_MODE = next(),
I_MTD_SLOW_MODE = next(),
I_CONFIG_UNLOCKED = newRow(),
I_CONFIG_LOCKED = next(),
I_CONFIG_DISCARD = next(),
I_CONFIG_SAVE = next(),
I_CONFIG_RESET = next(),
I_CONFIG_BACK = next(),
I_CONFIG_PREV = next(),
I_CONFIG_NEXT = next(),
I_DISABLE = next(),
I_CONFIG_OPEN = next(),
I_FX_SURFACE_OFF = newRow(),
I_FX_SURFACE_ON = next(),
I_FX_FIELD_OFF = next(),
I_FX_FIELD_ON = next(),
I_FX_BLEND = next(),
I_FX_BLEND_OFF = next();
;
public AllIcons(int x, int y) {
iconX = x * 16;
iconY = y * 16;
}
private static AllIcons next() {
return new AllIcons(++x, y);
}
private static AllIcons newRow() {
return new AllIcons(x = 0, ++y);
}
@OnlyIn(Dist.CLIENT)
public void bind() {
RenderSystem.setShaderTexture(0, ICON_ATLAS);
}
@OnlyIn(Dist.CLIENT)
@Override
public void render(PoseStack matrixStack, int x, int y) {
bind();
GuiComponent.blit(matrixStack, x, y, 0, iconX, iconY, 16, 16, 256, 256);
}
@OnlyIn(Dist.CLIENT)
public void render(PoseStack matrixStack, int x, int y, GuiComponent component) {
bind();
component.blit(matrixStack, x, y, iconX, iconY, 16, 16);
}
@OnlyIn(Dist.CLIENT)
public void render(PoseStack ms, MultiBufferSource buffer, int color) {
VertexConsumer builder = buffer.getBuffer(RenderType.textSeeThrough(ICON_ATLAS));
Matrix4f matrix = ms.last().pose();
Color rgb = new Color(color);
int light = LightTexture.FULL_BRIGHT;
Vec3 vec1 = new Vec3(0, 0, 0);
Vec3 vec2 = new Vec3(0, 1, 0);
Vec3 vec3 = new Vec3(1, 1, 0);
Vec3 vec4 = new Vec3(1, 0, 0);
float u1 = iconX * 1f / ICON_ATLAS_SIZE;
float u2 = (iconX + 16) * 1f / ICON_ATLAS_SIZE;
float v1 = iconY * 1f / ICON_ATLAS_SIZE;
float v2 = (iconY + 16) * 1f / ICON_ATLAS_SIZE;
vertex(builder, matrix, vec1, rgb, u1, v1, light);
vertex(builder, matrix, vec2, rgb, u1, v2, light);
vertex(builder, matrix, vec3, rgb, u2, v2, light);
vertex(builder, matrix, vec4, rgb, u2, v1, light);
}
@OnlyIn(Dist.CLIENT)
private void vertex(VertexConsumer builder, Matrix4f matrix, Vec3 vec, Color rgb, float u, float v, int light) {
builder.vertex(matrix, (float) vec.x, (float) vec.y, (float) vec.z)
.color(rgb.getRed(), rgb.getGreen(), rgb.getBlue(), 255)
.uv(u, v)
.uv2(light)
.endVertex();
}
@OnlyIn(Dist.CLIENT)
public DelegatedStencilElement asStencil() {
return new DelegatedStencilElement().withStencilRenderer((ms, w, h, alpha) -> this.render(ms, 0, 0)).withBounds(16, 16);
}
}

View File

@@ -0,0 +1,227 @@
package nl.requios.effortlessbuilding.create.foundation.gui;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import nl.requios.effortlessbuilding.create.foundation.gui.element.BoxElement;
import nl.requios.effortlessbuilding.create.foundation.gui.element.TextStencilElement;
import nl.requios.effortlessbuilding.create.foundation.gui.widget.BoxWidget;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.FormattedText;
import net.minecraft.network.chat.Style;
import org.lwjgl.opengl.GL30;
import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public class ConfirmationScreen extends AbstractSimiScreen {
private Screen source;
private Consumer<Response> action = _success -> {
};
private List<FormattedText> text = new ArrayList<>();
private boolean centered = false;
private int x;
private int y;
private int textWidth;
private int textHeight;
private boolean tristate;
private BoxWidget confirm;
private BoxWidget confirmDontSave;
private BoxWidget cancel;
private BoxElement textBackground;
public enum Response {
Confirm, ConfirmDontSave, Cancel
}
/*
* Removes text lines from the back of the list
* */
public ConfirmationScreen removeTextLines(int amount) {
if (amount > text.size())
return clearText();
text.subList(text.size() - amount, text.size()).clear();
return this;
}
public ConfirmationScreen clearText() {
this.text.clear();
return this;
}
public ConfirmationScreen addText(FormattedText text) {
this.text.add(text);
return this;
}
public ConfirmationScreen withText(FormattedText text) {
return clearText().addText(text);
}
public ConfirmationScreen at(int x, int y) {
this.x = Math.max(x, 0);
this.y = Math.max(y, 0);
this.centered = false;
return this;
}
public ConfirmationScreen centered() {
this.centered = true;
return this;
}
public ConfirmationScreen withAction(Consumer<Boolean> action) {
this.action = r -> action.accept(r == Response.Confirm);
return this;
}
public ConfirmationScreen withThreeActions(Consumer<Response> action) {
this.action = action;
this.tristate = true;
return this;
}
public void open(@Nonnull Screen source) {
this.source = source;
Minecraft client = source.getMinecraft();
this.init(client, client.getWindow().getGuiScaledWidth(), client.getWindow().getGuiScaledHeight());
this.minecraft.screen = this;
}
@Override
public void tick() {
super.tick();
source.tick();
}
@Override
protected void init() {
super.init();
ArrayList<FormattedText> copy = new ArrayList<>(text);
text.clear();
copy.forEach(t -> text.addAll(font.getSplitter().splitLines(t, 300, Style.EMPTY)));
textHeight = text.size() * (font.lineHeight + 1) + 4;
textWidth = 300;
if (centered) {
x = width/2 - textWidth/2 - 2;
y = height/2 - textHeight/2 - 16;
} else {
x = Math.max(0, x - textWidth / 2);
y = Math.max(0, y -= textHeight);
}
if (x + textWidth > width) {
x = width - textWidth;
}
if (y + textHeight + 30 > height) {
y = height - textHeight - 30;
}
int buttonX = x + textWidth / 2 - 6 - (int) (70 * (tristate ? 1.5f : 1));
TextStencilElement confirmText =
new TextStencilElement(font, tristate ? "Save" : "Confirm").centered(true, true);
confirm = new BoxWidget(buttonX, y + textHeight + 6, 70, 16).withCallback(() -> accept(Response.Confirm));
confirm.showingElement(confirmText.withElementRenderer(BoxWidget.gradientFactory.apply(confirm)));
addRenderableWidget(confirm);
buttonX += 12 + 70;
if (tristate) {
TextStencilElement confirmDontSaveText =
new TextStencilElement(font, "Don't Save").centered(true, true);
confirmDontSave =
new BoxWidget(buttonX, y + textHeight + 6, 70, 16).withCallback(() -> accept(Response.ConfirmDontSave));
confirmDontSave.showingElement(
confirmDontSaveText.withElementRenderer(BoxWidget.gradientFactory.apply(confirmDontSave)));
addRenderableWidget(confirmDontSave);
buttonX += 12 + 70;
}
TextStencilElement cancelText = new TextStencilElement(font, "Cancel").centered(true, true);
cancel = new BoxWidget(buttonX, y + textHeight + 6, 70, 16)
.withCallback(() -> accept(Response.Cancel));
cancel.showingElement(cancelText.withElementRenderer(BoxWidget.gradientFactory.apply(cancel)));
addRenderableWidget(cancel);
textBackground = new BoxElement()
.gradientBorder(Theme.p(Theme.Key.BUTTON_DISABLE))
.withBounds(width + 10, textHeight + 35)
.at(-5, y - 5);
if (text.size() == 1)
x = (width - font.width(text.get(0))) / 2;
}
@Override
public void onClose() {
accept(Response.Cancel);
}
private void accept(Response success) {
minecraft.screen = source;
action.accept(success);
}
@Override
protected void renderWindow(PoseStack ms, int mouseX, int mouseY, float partialTicks) {
textBackground.render(ms);
int offset = font.lineHeight + 1;
int lineY = y - offset;
ms.pushPose();
ms.translate(0, 0, 200);
for (FormattedText line : text) {
lineY += offset;
if (line == null)
continue;
font.draw(ms, line.getString(), x, lineY, 0xeaeaea);
}
ms.popPose();
}
@Override
protected void renderWindowBackground(PoseStack ms, int mouseX, int mouseY, float partialTicks) {
endFrame();
source.render(ms, 0, 0, 10); // zero mouse coords to prevent further tooltips
prepareFrame();
this.fillGradient(ms, 0, 0, this.width, this.height, 0x70101010, 0x80101010);
}
@Override
protected void prepareFrame() {
UIRenderHelper.swapAndBlitColor(minecraft.getMainRenderTarget(), UIRenderHelper.framebuffer);
RenderSystem.clear(GL30.GL_STENCIL_BUFFER_BIT | GL30.GL_DEPTH_BUFFER_BIT, Minecraft.ON_OSX);
}
@Override
protected void endFrame() {
UIRenderHelper.swapAndBlitColor(UIRenderHelper.framebuffer, minecraft.getMainRenderTarget());
}
@Override
public void resize(@Nonnull Minecraft client, int width, int height) {
super.resize(client, width, height);
source.resize(client, width, height);
}
@Override
public boolean isPauseScreen() {
return true;
}
}

View File

@@ -0,0 +1,81 @@
package nl.requios.effortlessbuilding.create.foundation.gui;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.math.Matrix4f;
import com.mojang.math.Vector3f;
public class CustomLightingSettings implements ILightingSettings {
private Vector3f light1;
private Vector3f light2;
private Matrix4f lightMatrix;
protected CustomLightingSettings(float yRot, float xRot) {
init(yRot, xRot, 0, 0, false);
}
protected CustomLightingSettings(float yRot1, float xRot1, float yRot2, float xRot2) {
init(yRot1, xRot1, yRot2, xRot2, true);
}
protected void init(float yRot1, float xRot1, float yRot2, float xRot2, boolean doubleLight) {
light1 = Vector3f.ZP.copy();
light1.transform(Vector3f.YP.rotationDegrees(yRot1));
light1.transform(Vector3f.XN.rotationDegrees(xRot1));
if (doubleLight) {
light2 = Vector3f.ZP.copy();
light2.transform(Vector3f.YP.rotationDegrees(yRot2));
light2.transform(Vector3f.XN.rotationDegrees(xRot2));
} else {
light2 = Vector3f.ZERO;
}
lightMatrix = new Matrix4f();
lightMatrix.setIdentity();
}
@Override
public void applyLighting() {
RenderSystem.setupLevelDiffuseLighting(light1, light2, lightMatrix);
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
private float yRot1, xRot1;
private float yRot2, xRot2;
private boolean doubleLight;
public Builder firstLightRotation(float yRot, float xRot) {
yRot1 = yRot;
xRot1 = xRot;
return this;
}
public Builder secondLightRotation(float yRot, float xRot) {
yRot2 = yRot;
xRot2 = xRot;
doubleLight = true;
return this;
}
public Builder doubleLight() {
doubleLight = true;
return this;
}
public CustomLightingSettings build() {
if (doubleLight) {
return new CustomLightingSettings(yRot1, xRot1, yRot2, xRot2);
} else {
return new CustomLightingSettings(yRot1, xRot1);
}
}
}
}

View File

@@ -0,0 +1,12 @@
package nl.requios.effortlessbuilding.create.foundation.gui;
import com.mojang.blaze3d.platform.Lighting;
public interface ILightingSettings {
void applyLighting();
static final ILightingSettings DEFAULT_3D = () -> Lighting.setupFor3DItems();
static final ILightingSettings DEFAULT_FLAT = () -> Lighting.setupForFlatItems();
}

View File

@@ -0,0 +1,197 @@
package nl.requios.effortlessbuilding.create.foundation.gui;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.Tesselator;
import com.mojang.math.Matrix4f;
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.network.chat.FormattedText;
import net.minecraft.network.chat.Style;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.client.ForgeHooksClient;
import net.minecraftforge.client.event.RenderTooltipEvent;
import net.minecraftforge.client.gui.ScreenUtils;
import net.minecraftforge.common.MinecraftForge;
import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.List;
public class RemovedGuiUtils {
@Nonnull
private static ItemStack cachedTooltipStack = ItemStack.EMPTY;
public static void preItemToolTip(@Nonnull ItemStack stack) {
cachedTooltipStack = stack;
}
public static void postItemToolTip() {
cachedTooltipStack = ItemStack.EMPTY;
}
public static void drawHoveringText(PoseStack mStack, List<? extends FormattedText> textLines, int mouseX,
int mouseY, int screenWidth, int screenHeight, int maxTextWidth, Font font) {
drawHoveringText(mStack, textLines, mouseX, mouseY, screenWidth, screenHeight, maxTextWidth,
ScreenUtils.DEFAULT_BACKGROUND_COLOR, ScreenUtils.DEFAULT_BORDER_COLOR_START, ScreenUtils.DEFAULT_BORDER_COLOR_END,
font);
}
public static void drawHoveringText(PoseStack mStack, List<? extends FormattedText> textLines, int mouseX,
int mouseY, int screenWidth, int screenHeight, int maxTextWidth, int backgroundColor, int borderColorStart,
int borderColorEnd, Font font) {
drawHoveringText(cachedTooltipStack, mStack, textLines, mouseX, mouseY, screenWidth, screenHeight, maxTextWidth,
backgroundColor, borderColorStart, borderColorEnd, font);
}
public static void drawHoveringText(@Nonnull final ItemStack stack, PoseStack mStack,
List<? extends FormattedText> textLines, int mouseX, int mouseY, int screenWidth, int screenHeight,
int maxTextWidth, Font font) {
drawHoveringText(stack, mStack, textLines, mouseX, mouseY, screenWidth, screenHeight, maxTextWidth,
ScreenUtils.DEFAULT_BACKGROUND_COLOR, ScreenUtils.DEFAULT_BORDER_COLOR_START, ScreenUtils.DEFAULT_BORDER_COLOR_END,
font);
}
public static void drawHoveringText(@Nonnull final ItemStack stack, PoseStack pStack,
List<? extends FormattedText> textLines, int mouseX, int mouseY, int screenWidth, int screenHeight,
int maxTextWidth, int backgroundColor, int borderColorStart, int borderColorEnd, Font font) {
if (textLines.isEmpty())
return;
List<ClientTooltipComponent> list = ForgeHooksClient.gatherTooltipComponents(stack, textLines,
stack.getTooltipImage(), mouseX, screenWidth, screenHeight, font, font);
RenderTooltipEvent.Pre event =
new RenderTooltipEvent.Pre(stack, pStack, mouseX, mouseY, screenWidth, screenHeight, font, list);
if (MinecraftForge.EVENT_BUS.post(event))
return;
mouseX = event.getX();
mouseY = event.getY();
screenWidth = event.getScreenWidth();
screenHeight = event.getScreenHeight();
font = event.getFont();
// RenderSystem.disableRescaleNormal();
RenderSystem.disableDepthTest();
int tooltipTextWidth = 0;
for (FormattedText textLine : textLines) {
int textLineWidth = font.width(textLine);
if (textLineWidth > tooltipTextWidth)
tooltipTextWidth = textLineWidth;
}
boolean needsWrap = false;
int titleLinesCount = 1;
int tooltipX = mouseX + 12;
if (tooltipX + tooltipTextWidth + 4 > screenWidth) {
tooltipX = mouseX - 16 - tooltipTextWidth;
if (tooltipX < 4) // if the tooltip doesn't fit on the screen
{
if (mouseX > screenWidth / 2)
tooltipTextWidth = mouseX - 12 - 8;
else
tooltipTextWidth = screenWidth - 16 - mouseX;
needsWrap = true;
}
}
if (maxTextWidth > 0 && tooltipTextWidth > maxTextWidth) {
tooltipTextWidth = maxTextWidth;
needsWrap = true;
}
if (needsWrap) {
int wrappedTooltipWidth = 0;
List<FormattedText> wrappedTextLines = new ArrayList<>();
for (int i = 0; i < textLines.size(); i++) {
FormattedText textLine = textLines.get(i);
List<FormattedText> wrappedLine = font.getSplitter()
.splitLines(textLine, tooltipTextWidth, Style.EMPTY);
if (i == 0)
titleLinesCount = wrappedLine.size();
for (FormattedText line : wrappedLine) {
int lineWidth = font.width(line);
if (lineWidth > wrappedTooltipWidth)
wrappedTooltipWidth = lineWidth;
wrappedTextLines.add(line);
}
}
tooltipTextWidth = wrappedTooltipWidth;
textLines = wrappedTextLines;
if (mouseX > screenWidth / 2)
tooltipX = mouseX - 16 - tooltipTextWidth;
else
tooltipX = mouseX + 12;
}
int tooltipY = mouseY - 12;
int tooltipHeight = 8;
if (textLines.size() > 1) {
tooltipHeight += (textLines.size() - 1) * 10;
if (textLines.size() > titleLinesCount)
tooltipHeight += 2; // gap between title lines and next lines
}
if (tooltipY < 4)
tooltipY = 4;
else if (tooltipY + tooltipHeight + 4 > screenHeight)
tooltipY = screenHeight - tooltipHeight - 4;
final int zLevel = 400;
RenderTooltipEvent.Color colorEvent = new RenderTooltipEvent.Color(stack, pStack, tooltipX, tooltipY,
font, backgroundColor, borderColorStart, borderColorEnd, list);
MinecraftForge.EVENT_BUS.post(colorEvent);
backgroundColor = colorEvent.getBackgroundStart();
borderColorStart = colorEvent.getBorderStart();
borderColorEnd = colorEvent.getBorderEnd();
pStack.pushPose();
Matrix4f mat = pStack.last()
.pose();
ScreenUtils.drawGradientRect(mat, zLevel, tooltipX - 3, tooltipY - 4, tooltipX + tooltipTextWidth + 3,
tooltipY - 3, backgroundColor, backgroundColor);
ScreenUtils.drawGradientRect(mat, zLevel, tooltipX - 3, tooltipY + tooltipHeight + 3,
tooltipX + tooltipTextWidth + 3, tooltipY + tooltipHeight + 4, backgroundColor, backgroundColor);
ScreenUtils.drawGradientRect(mat, zLevel, tooltipX - 3, tooltipY - 3, tooltipX + tooltipTextWidth + 3,
tooltipY + tooltipHeight + 3, backgroundColor, backgroundColor);
ScreenUtils.drawGradientRect(mat, zLevel, tooltipX - 4, tooltipY - 3, tooltipX - 3, tooltipY + tooltipHeight + 3,
backgroundColor, backgroundColor);
ScreenUtils.drawGradientRect(mat, zLevel, tooltipX + tooltipTextWidth + 3, tooltipY - 3,
tooltipX + tooltipTextWidth + 4, tooltipY + tooltipHeight + 3, backgroundColor, backgroundColor);
ScreenUtils.drawGradientRect(mat, zLevel, tooltipX - 3, tooltipY - 3 + 1, tooltipX - 3 + 1,
tooltipY + tooltipHeight + 3 - 1, borderColorStart, borderColorEnd);
ScreenUtils.drawGradientRect(mat, zLevel, tooltipX + tooltipTextWidth + 2, tooltipY - 3 + 1,
tooltipX + tooltipTextWidth + 3, tooltipY + tooltipHeight + 3 - 1, borderColorStart, borderColorEnd);
ScreenUtils.drawGradientRect(mat, zLevel, tooltipX - 3, tooltipY - 3, tooltipX + tooltipTextWidth + 3,
tooltipY - 3 + 1, borderColorStart, borderColorStart);
ScreenUtils.drawGradientRect(mat, zLevel, tooltipX - 3, tooltipY + tooltipHeight + 2,
tooltipX + tooltipTextWidth + 3, tooltipY + tooltipHeight + 3, borderColorEnd, borderColorEnd);
MultiBufferSource.BufferSource renderType = MultiBufferSource.immediate(Tesselator.getInstance()
.getBuilder());
pStack.translate(0.0D, 0.0D, zLevel);
for (int lineNumber = 0; lineNumber < list.size(); ++lineNumber) {
ClientTooltipComponent line = list.get(lineNumber);
if (line != null)
line.renderText(font, tooltipX, tooltipY, mat, renderType);
if (lineNumber + 1 == titleLinesCount)
tooltipY += 2;
tooltipY += 10;
}
renderType.endBatch();
pStack.popPose();
RenderSystem.enableDepthTest();
}
}

View File

@@ -0,0 +1,229 @@
package nl.requios.effortlessbuilding.create.foundation.gui;
import nl.requios.effortlessbuilding.create.foundation.utility.Color;
import nl.requios.effortlessbuilding.create.foundation.utility.Couple;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
public class Theme {
private static final List<Theme> THEMES = new ArrayList<>();
public static final Theme BASE = addTheme(new Theme());
public static Theme addTheme(@Nonnull Theme theme) {
THEMES.add(theme);
THEMES.sort(Comparator.comparingInt(Theme::getPriority).reversed());
return theme;
}
public static void removeTheme(Theme theme) {
THEMES.remove(theme);
}
public static void reload() {
THEMES.forEach(Theme::init);
}
private static ColorHolder resolve(String key) {
return THEMES
.stream()
.map(theme -> theme.get(key))
.filter(Objects::nonNull)
.findFirst()
.map(holder -> holder.lookupKey == null ? holder : resolve(holder.lookupKey))
.orElse(ColorHolder.MISSING);
}
@Nonnull public static Couple<Color> p(@Nonnull Key key) {return p(key.get());}
@Nonnull public static Couple<Color> p(String key) {return resolve(key).asPair();}
@Nonnull public static Color c(@Nonnull Key key, boolean first) {return c(key.get(), first);}
@Nonnull public static Color c(String key, boolean first) {return p(key).get(first);}
public static int i(@Nonnull Key key, boolean first) {return i(key.get(), first);}
public static int i(String key, boolean first) {return p(key).get(first).getRGB();}
@Nonnull public static Color c(@Nonnull Key key) {return c(key.get());}
@Nonnull public static Color c(String key) {return resolve(key).get();}
public static int i(@Nonnull Key key) {return i(key.get());}
public static int i(String key) {return resolve(key).get().getRGB();}
//-----------//
protected final Map<String, ColorHolder> colors;
private int priority = 0;
protected Theme() {
colors = new HashMap<>();
init();
}
/*
* Small note to addons: if you also want to make use of Theme,
* and add new Keys, please do not use mixins. Instead make a Theme
* subclass, override init and apply it via the static #addTheme
*
**/
protected void init() {
put(Key.BUTTON_IDLE, new Color(0xdd_8ab6d6, true), new Color(0x90_8ab6d6, true));
put(Key.BUTTON_HOVER, new Color(0xff_9ABBD3, true), new Color(0xd0_9ABBD3, true));
put(Key.BUTTON_CLICK, new Color(0xff_ffffff), new Color(0xee_ffffff));
put(Key.BUTTON_DISABLE, new Color(0x80_909090, true), new Color(0x60_909090, true));
put(Key.BUTTON_SUCCESS, new Color(0xcc_88f788, true), new Color(0xcc_20cc20, true));
put(Key.BUTTON_FAIL, new Color(0xcc_f78888, true), new Color(0xcc_cc2020, true));
put(Key.TEXT, new Color(0xff_eeeeee), new Color(0xff_a3a3a3));
put(Key.TEXT_DARKER, new Color(0xff_a3a3a3), new Color(0xff_808080));
put(Key.TEXT_ACCENT_STRONG, new Color(0xff_8ab6d6), new Color(0xff_8ab6d6));
put(Key.TEXT_ACCENT_SLIGHT, new Color(0xff_ddeeff), new Color(0xff_a0b0c0));
put(Key.STREAK, new Color(0x101010, false));
put(Key.VANILLA_TOOLTIP_BORDER, new Color(0x50_5000ff, true), new Color(0x50_28007f, true));
put(Key.VANILLA_TOOLTIP_BACKGROUND, new Color(0xf0_100010, true));
put(Key.PONDER_BUTTON_IDLE, new Color(0x60_c0c0ff, true), new Color(0x30_c0c0ff, true));
put(Key.PONDER_BUTTON_HOVER, new Color(0xf0_c0c0ff, true), new Color(0xa0_c0c0ff, true));
put(Key.PONDER_BUTTON_CLICK, new Color(0xff_ffffff), new Color(0xdd_ffffff));
put(Key.PONDER_BUTTON_DISABLE, new Color(0x80_909090, true), new Color(0x20_909090, true));
put(Key.PONDER_BACKGROUND_TRANSPARENT, new Color(0xdd_000000, true));
put(Key.PONDER_BACKGROUND_FLAT, new Color(0xff_000000, false));
put(Key.PONDER_BACKGROUND_IMPORTANT, new Color(0xdd_0e0e20, true));
put(Key.PONDER_IDLE, new Color(0x40ffeedd, true), new Color(0x20ffeedd, true));
put(Key.PONDER_HOVER, new Color(0x70ffffff, true), new Color(0x30ffffff, true));
put(Key.PONDER_HIGHLIGHT, new Color(0xf0ffeedd, true), new Color(0x60ffeedd, true));
put(Key.TEXT_WINDOW_BORDER, new Color(0x607a6000, true), new Color(0x207a6000, true));
put(Key.PONDER_BACK_ARROW, new Color(0xf0aa9999, true), new Color(0x30aa9999, true));
put(Key.PONDER_PROGRESSBAR, new Color(0x80ffeedd, true), new Color(0x50ffeedd, true));
put(Key.PONDER_MISSING_CREATE, new Color(0x70_984500, true), new Color(0x70_692400, true));
//put(Key.PONDER_MISSING_VANILLA, new Color(0x50_5000ff, true), new Color(0x50_300077, true));
lookup(Key.PONDER_MISSING_VANILLA, Key.VANILLA_TOOLTIP_BORDER);
put(Key.CONFIG_TITLE_A, new Color(0xffc69fbc, true), new Color(0xfff6b8bb, true));
put(Key.CONFIG_TITLE_B, new Color(0xfff6b8bb, true), new Color(0xfffbf994, true));
//put(Key., new Color(0x, true), new Color(0x, true));
}
protected void put(String key, Color c) {
colors.put(key, ColorHolder.single(c));
}
protected void put(Key key, Color c) {
put(key.get(), c);
}
protected void put(String key, Color c1, Color c2) {
colors.put(key, ColorHolder.pair(c1, c2));
}
protected void put(Key key, Color c1, Color c2) {
put(key.get(), c1, c2);
}
protected void lookup(Key key, Key source) {
colors.put(key.get(), ColorHolder.lookup(source.get()));
}
@Nullable protected ColorHolder get(String key) {
return colors.get(key);
}
public int getPriority() {
return priority;
}
public Theme setPriority(int priority) {
this.priority = priority;
return this;
}
public static class Key {
public static final Key BUTTON_IDLE = new Key();
public static final Key BUTTON_HOVER = new Key();
public static final Key BUTTON_CLICK = new Key();
public static final Key BUTTON_DISABLE = new Key();
public static final Key BUTTON_SUCCESS = new Key();
public static final Key BUTTON_FAIL = new Key();
public static final Key TEXT = new Key();
public static final Key TEXT_DARKER = new Key();
public static final Key TEXT_ACCENT_STRONG = new Key();
public static final Key TEXT_ACCENT_SLIGHT = new Key();
public static final Key STREAK = new Key();
public static final Key VANILLA_TOOLTIP_BORDER = new Key();
public static final Key VANILLA_TOOLTIP_BACKGROUND = new Key();
public static final Key PONDER_BACKGROUND_TRANSPARENT = new Key();
public static final Key PONDER_BACKGROUND_FLAT = new Key();
public static final Key PONDER_BACKGROUND_IMPORTANT = new Key();
public static final Key PONDER_IDLE = new Key();
public static final Key PONDER_HOVER = new Key();
public static final Key PONDER_HIGHLIGHT = new Key();
public static final Key TEXT_WINDOW_BORDER = new Key();
public static final Key PONDER_BACK_ARROW = new Key();
public static final Key PONDER_PROGRESSBAR = new Key();
public static final Key PONDER_MISSING_CREATE = new Key();
public static final Key PONDER_MISSING_VANILLA = new Key();
public static final Key PONDER_BUTTON_IDLE = new Key();
public static final Key PONDER_BUTTON_HOVER = new Key();
public static final Key PONDER_BUTTON_CLICK = new Key();
public static final Key PONDER_BUTTON_DISABLE = new Key();
public static final Key CONFIG_TITLE_A = new Key();
public static final Key CONFIG_TITLE_B = new Key();
private static int index = 0;
private final String s;
protected Key() {
this.s = "_" + index++;
}
protected Key(String s) {
this.s = s;
}
public String get() {
return s;
}
}
private static class ColorHolder {
private static final ColorHolder MISSING = ColorHolder.single(Color.BLACK);
private Couple<Color> colors;
private String lookupKey;
private static ColorHolder single(Color c) {
ColorHolder h = new ColorHolder();
h.colors = Couple.create(c.setImmutable(), c.setImmutable());
return h;
}
private static ColorHolder pair(Color first, Color second) {
ColorHolder h = new ColorHolder();
h.colors = Couple.create(first.setImmutable(), second.setImmutable());
return h;
}
private static ColorHolder lookup(String key) {
ColorHolder h = new ColorHolder();
h.lookupKey = key;
return h;
}
private Color get() {
return colors.getFirst();
}
private Couple<Color> asPair() {
return colors;
}
}
}

View File

@@ -0,0 +1,7 @@
package nl.requios.effortlessbuilding.create.foundation.gui;
import net.minecraft.client.gui.components.events.GuiEventListener;
public interface TickableGuiEventListener extends GuiEventListener {
void tick();
}

View File

@@ -0,0 +1,316 @@
package nl.requios.effortlessbuilding.create.foundation.gui;
import com.mojang.blaze3d.pipeline.RenderTarget;
import com.mojang.blaze3d.platform.GlConst;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.platform.Window;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.*;
import com.mojang.math.Matrix4f;
import com.mojang.math.Vector3f;
import nl.requios.effortlessbuilding.create.foundation.utility.Color;
import nl.requios.effortlessbuilding.create.foundation.utility.Couple;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraftforge.client.gui.ScreenUtils;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;
import javax.annotation.Nonnull;
public class UIRenderHelper {
/**
* An FBO that has a stencil buffer for use wherever stencil are necessary. Forcing the main FBO to have a stencil
* buffer will cause GL error spam when using fabulous graphics.
*/
public static CustomRenderTarget framebuffer;
public static void init() {
RenderSystem.recordRenderCall(() -> {
Window mainWindow = Minecraft.getInstance().getWindow();
framebuffer = CustomRenderTarget.create(mainWindow);
});
}
public static void updateWindowSize(Window mainWindow) {
if (framebuffer != null)
framebuffer.resize(mainWindow.getWidth(), mainWindow.getHeight(), Minecraft.ON_OSX);
}
public static void drawFramebuffer(float alpha) {
framebuffer.renderWithAlpha(alpha);
}
/**
* Switch from src to dst, after copying the contents of src to dst.
*/
public static void swapAndBlitColor(RenderTarget src, RenderTarget dst) {
GlStateManager._glBindFramebuffer(GL30.GL_READ_FRAMEBUFFER, src.frameBufferId);
GlStateManager._glBindFramebuffer(GL30.GL_DRAW_FRAMEBUFFER, dst.frameBufferId);
GlStateManager._glBlitFrameBuffer(0, 0, src.viewWidth, src.viewHeight, 0, 0, dst.viewWidth, dst.viewHeight, GL30.GL_COLOR_BUFFER_BIT, GL20.GL_LINEAR);
GlStateManager._glBindFramebuffer(GlConst.GL_FRAMEBUFFER, dst.frameBufferId);
}
public static void streak(PoseStack ms, float angle, int x, int y, int breadth, int length) {
streak(ms, angle, x, y, breadth, length, Theme.i(Theme.Key.STREAK));
}
// angle in degrees; 0° -> fading to the right
// x and y specify the middle point of the starting edge
// breadth is the total width of the streak
public static void streak(PoseStack ms, float angle, int x, int y, int breadth, int length, int color) {
int a1 = 0xa0 << 24;
int a2 = 0x80 << 24;
int a3 = 0x10 << 24;
int a4 = 0x00 << 24;
color &= 0x00FFFFFF;
int c1 = a1 | color;
int c2 = a2 | color;
int c3 = a3 | color;
int c4 = a4 | color;
ms.pushPose();
ms.translate(x, y, 0);
ms.mulPose(Vector3f.ZP.rotationDegrees(angle - 90));
streak(ms, breadth / 2, length, c1, c2, c3, c4);
ms.popPose();
}
public static void streak(PoseStack ms, float angle, int x, int y, int breadth, int length, Color c) {
Color color = c.copy().setImmutable();
int c1 = color.scaleAlpha(0.625f).getRGB();
int c2 = color.scaleAlpha(0.5f).getRGB();
int c3 = color.scaleAlpha(0.0625f).getRGB();
int c4 = color.scaleAlpha(0f).getRGB();
ms.pushPose();
ms.translate(x, y, 0);
ms.mulPose(Vector3f.ZP.rotationDegrees(angle - 90));
streak(ms, breadth / 2, length, c1, c2, c3, c4);
ms.popPose();
}
private static void streak(PoseStack ms, int width, int height, int c1, int c2, int c3, int c4) {
double split1 = .5;
double split2 = .75;
Matrix4f model = ms.last().pose();
ScreenUtils.drawGradientRect(model, 0, -width, 0, width, (int) (split1 * height), c1, c2);
ScreenUtils.drawGradientRect(model, 0, -width, (int) (split1 * height), width, (int) (split2 * height), c2, c3);
ScreenUtils.drawGradientRect(model, 0, -width, (int) (split2 * height), width, height, c3, c4);
}
/**
* @see #angledGradient(MatrixStack, float, int, int, int, int, int, Color, Color)
*/
public static void angledGradient(@Nonnull PoseStack ms, float angle, int x, int y, int breadth, int length, Couple<Color> c) {
angledGradient(ms, angle, x, y, 0, breadth, length, c);
}
/**
* @see #angledGradient(MatrixStack, float, int, int, int, int, int, Color, Color)
*/
public static void angledGradient(@Nonnull PoseStack ms, float angle, int x, int y, int z, int breadth, int length, Couple<Color> c) {
angledGradient(ms, angle, x, y, z, breadth, length, c.getFirst(), c.getSecond());
}
/**
* @see #angledGradient(MatrixStack, float, int, int, int, int, int, Color, Color)
*/
public static void angledGradient(@Nonnull PoseStack ms, float angle, int x, int y, int breadth, int length, Color color1, Color color2) {
angledGradient(ms, angle, x, y, 0, breadth, length, color1, color2);
}
/**
* x and y specify the middle point of the starting edge
*
* @param angle the angle of the gradient in degrees; 0° means from left to right
* @param color1 the color at the starting edge
* @param color2 the color at the ending edge
* @param breadth the total width of the gradient
*/
public static void angledGradient(@Nonnull PoseStack ms, float angle, int x, int y, int z, int breadth, int length, Color color1, Color color2) {
ms.pushPose();
ms.translate(x, y, z);
ms.mulPose(Vector3f.ZP.rotationDegrees(angle - 90));
Matrix4f model = ms.last().pose();
int w = breadth / 2;
ScreenUtils.drawGradientRect(model, 0, -w, 0, w, length, color1.getRGB(), color2.getRGB());
ms.popPose();
}
public static void breadcrumbArrow(PoseStack matrixStack, int x, int y, int z, int width, int height, int indent, Couple<Color> colors) {breadcrumbArrow(matrixStack, x, y, z, width, height, indent, colors.getFirst(), colors.getSecond());}
// draws a wide chevron-style breadcrumb arrow pointing left
public static void breadcrumbArrow(PoseStack matrixStack, int x, int y, int z, int width, int height, int indent, Color startColor, Color endColor) {
matrixStack.pushPose();
matrixStack.translate(x - indent, y, z);
breadcrumbArrow(matrixStack, width, height, indent, startColor, endColor);
matrixStack.popPose();
}
private static void breadcrumbArrow(PoseStack ms, int width, int height, int indent, Color c1, Color c2) {
/*
* 0,0 x1,y1 ********************* x4,y4 ***** x7,y7
* **** ****
* **** ****
* x0,y0 x2,y2 x5,y5
* **** ****
* **** ****
* x3,y3 ********************* x6,y6 ***** x8,y8
*
*/
float x0 = 0, y0 = height / 2f;
float x1 = indent, y1 = 0;
float x2 = indent, y2 = height / 2f;
float x3 = indent, y3 = height;
float x4 = width, y4 = 0;
float x5 = width, y5 = height / 2f;
float x6 = width, y6 = height;
float x7 = indent + width, y7 = 0;
float x8 = indent + width, y8 = height;
indent = Math.abs(indent);
width = Math.abs(width);
Color fc1 = Color.mixColors(c1, c2, 0);
Color fc2 = Color.mixColors(c1, c2, (indent) / (width + 2f * indent));
Color fc3 = Color.mixColors(c1, c2, (indent + width) / (width + 2f * indent));
Color fc4 = Color.mixColors(c1, c2, 1);
RenderSystem.disableTexture();
RenderSystem.enableBlend();
RenderSystem.disableCull();
RenderSystem.defaultBlendFunc();
RenderSystem.setShader(GameRenderer::getPositionColorShader);
Tesselator tessellator = Tesselator.getInstance();
BufferBuilder bufferbuilder = tessellator.getBuilder();
Matrix4f model = ms.last().pose();
bufferbuilder.begin(VertexFormat.Mode.TRIANGLES, DefaultVertexFormat.POSITION_COLOR);
bufferbuilder.vertex(model, x0, y0, 0).color(fc1.getRed(), fc1.getGreen(), fc1.getBlue(), fc1.getAlpha()).endVertex();
bufferbuilder.vertex(model, x1, y1, 0).color(fc2.getRed(), fc2.getGreen(), fc2.getBlue(), fc2.getAlpha()).endVertex();
bufferbuilder.vertex(model, x2, y2, 0).color(fc2.getRed(), fc2.getGreen(), fc2.getBlue(), fc2.getAlpha()).endVertex();
bufferbuilder.vertex(model, x0, y0, 0).color(fc1.getRed(), fc1.getGreen(), fc1.getBlue(), fc1.getAlpha()).endVertex();
bufferbuilder.vertex(model, x2, y2, 0).color(fc2.getRed(), fc2.getGreen(), fc2.getBlue(), fc2.getAlpha()).endVertex();
bufferbuilder.vertex(model, x3, y3, 0).color(fc2.getRed(), fc2.getGreen(), fc2.getBlue(), fc2.getAlpha()).endVertex();
bufferbuilder.vertex(model, x3, y3, 0).color(fc2.getRed(), fc2.getGreen(), fc2.getBlue(), fc2.getAlpha()).endVertex();
bufferbuilder.vertex(model, x1, y1, 0).color(fc2.getRed(), fc2.getGreen(), fc2.getBlue(), fc2.getAlpha()).endVertex();
bufferbuilder.vertex(model, x4, y4, 0).color(fc3.getRed(), fc3.getGreen(), fc3.getBlue(), fc3.getAlpha()).endVertex();
bufferbuilder.vertex(model, x3, y3, 0).color(fc2.getRed(), fc2.getGreen(), fc2.getBlue(), fc2.getAlpha()).endVertex();
bufferbuilder.vertex(model, x4, y4, 0).color(fc3.getRed(), fc3.getGreen(), fc3.getBlue(), fc3.getAlpha()).endVertex();
bufferbuilder.vertex(model, x6, y6, 0).color(fc3.getRed(), fc3.getGreen(), fc3.getBlue(), fc3.getAlpha()).endVertex();
bufferbuilder.vertex(model, x5, y5, 0).color(fc3.getRed(), fc3.getGreen(), fc3.getBlue(), fc3.getAlpha()).endVertex();
bufferbuilder.vertex(model, x4, y4, 0).color(fc3.getRed(), fc3.getGreen(), fc3.getBlue(), fc3.getAlpha()).endVertex();
bufferbuilder.vertex(model, x7, y7, 0).color(fc4.getRed(), fc4.getGreen(), fc4.getBlue(), fc4.getAlpha()).endVertex();
bufferbuilder.vertex(model, x6, y6, 0).color(fc3.getRed(), fc3.getGreen(), fc3.getBlue(), fc3.getAlpha()).endVertex();
bufferbuilder.vertex(model, x5, y5, 0).color(fc3.getRed(), fc3.getGreen(), fc3.getBlue(), fc3.getAlpha()).endVertex();
bufferbuilder.vertex(model, x8, y8, 0).color(fc4.getRed(), fc4.getGreen(), fc4.getBlue(), fc4.getAlpha()).endVertex();
tessellator.end();
RenderSystem.enableCull();
RenderSystem.disableBlend();
RenderSystem.enableTexture();
}
//just like AbstractGui#drawTexture, but with a color at every vertex
public static void drawColoredTexture(PoseStack ms, Color c, int x, int y, int tex_left, int tex_top, int width, int height) {
drawColoredTexture(ms, c, x, y, 0, (float) tex_left, (float) tex_top, width, height, 256, 256);
}
public static void drawColoredTexture(PoseStack ms, Color c, int x, int y, int z, float tex_left, float tex_top, int width, int height, int sheet_width, int sheet_height) {
drawColoredTexture(ms, c, x, x + width, y, y + height, z, width, height, tex_left, tex_top, sheet_width, sheet_height);
}
public static void drawStretched(PoseStack ms, int left, int top, int w, int h, int z, AllGuiTextures tex) {
tex.bind();
drawTexturedQuad(ms.last()
.pose(), Color.WHITE, left, left + w, top, top + h, z, tex.startX / 256f, (tex.startX + tex.width) / 256f,
tex.startY / 256f, (tex.startY + tex.height) / 256f);
}
private static void drawColoredTexture(PoseStack ms, Color c, int left, int right, int top, int bot, int z, int tex_width, int tex_height, float tex_left, float tex_top, int sheet_width, int sheet_height) {
drawTexturedQuad(ms.last().pose(), c, left, right, top, bot, z, (tex_left + 0.0F) / (float) sheet_width, (tex_left + (float) tex_width) / (float) sheet_width, (tex_top + 0.0F) / (float) sheet_height, (tex_top + (float) tex_height) / (float) sheet_height);
}
private static void drawTexturedQuad(Matrix4f m, Color c, int left, int right, int top, int bot, int z, float u1, float u2, float v1, float v2) {
Tesselator tesselator = Tesselator.getInstance();
BufferBuilder bufferbuilder = tesselator.getBuilder();
RenderSystem.enableBlend();
RenderSystem.defaultBlendFunc();
RenderSystem.setShader(GameRenderer::getPositionColorTexShader);
bufferbuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR_TEX);
bufferbuilder.vertex(m, (float) left , (float) bot, (float) z).color(c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()).uv(u1, v2).endVertex();
bufferbuilder.vertex(m, (float) right, (float) bot, (float) z).color(c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()).uv(u2, v2).endVertex();
bufferbuilder.vertex(m, (float) right, (float) top, (float) z).color(c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()).uv(u2, v1).endVertex();
bufferbuilder.vertex(m, (float) left , (float) top, (float) z).color(c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()).uv(u1, v1).endVertex();
tesselator.end();
RenderSystem.disableBlend();
}
public static void flipForGuiRender(PoseStack poseStack) {
poseStack.mulPoseMatrix(Matrix4f.createScaleMatrix(1, -1, 1));
}
public static class CustomRenderTarget extends RenderTarget {
public CustomRenderTarget(boolean useDepth) {
super(useDepth);
}
public static CustomRenderTarget create(Window mainWindow) {
CustomRenderTarget framebuffer = new CustomRenderTarget(true);
framebuffer.resize(mainWindow.getWidth(), mainWindow.getHeight(), Minecraft.ON_OSX);
framebuffer.setClearColor(0, 0, 0, 0);
framebuffer.enableStencil();
return framebuffer;
}
public void renderWithAlpha(float alpha) {
Window window = Minecraft.getInstance().getWindow();
float vx = (float) window.getGuiScaledWidth();
float vy = (float) window.getGuiScaledHeight();
float tx = (float) viewWidth / (float) width;
float ty = (float) viewHeight / (float) height;
RenderSystem.enableTexture();
RenderSystem.enableDepthTest();
RenderSystem.setShader(() -> Minecraft.getInstance().gameRenderer.blitShader);
RenderSystem.getShader().setSampler("DiffuseSampler", colorTextureId);
bindRead();
Tesselator tessellator = Tesselator.getInstance();
BufferBuilder bufferbuilder = tessellator.getBuilder();
bufferbuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR_TEX);
bufferbuilder.vertex(0, vy, 0).color(1, 1, 1, alpha).uv(0, 0).endVertex();
bufferbuilder.vertex(vx, vy, 0).color(1, 1, 1, alpha).uv(tx, 0).endVertex();
bufferbuilder.vertex(vx, 0, 0).color(1, 1, 1, alpha).uv(tx, ty).endVertex();
bufferbuilder.vertex(0, 0, 0).color(1, 1, 1, alpha).uv(0, ty).endVertex();
tessellator.end();
unbindRead();
}
}
}

View File

@@ -0,0 +1,175 @@
package nl.requios.effortlessbuilding.create.foundation.gui.container;
import com.mojang.blaze3d.platform.InputConstants;
import com.mojang.blaze3d.vertex.PoseStack;
import nl.requios.effortlessbuilding.create.foundation.gui.AllGuiTextures;
import nl.requios.effortlessbuilding.create.foundation.gui.TickableGuiEventListener;
import nl.requios.effortlessbuilding.create.foundation.gui.widget.AbstractSimiWidget;
import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.components.Widget;
import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.narration.NarratableEntry;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.client.gui.screens.inventory.ContainerScreen;
import net.minecraft.client.renderer.Rect2i;
import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@OnlyIn(Dist.CLIENT)
@ParametersAreNonnullByDefault
public abstract class AbstractSimiContainerScreen<T extends AbstractContainerMenu> extends AbstractContainerScreen<T> {
protected int windowXOffset, windowYOffset;
public AbstractSimiContainerScreen(T container, Inventory inv, Component title) {
super(container, inv, title);
}
/**
* This method must be called before {@code super.init()}!
*/
protected void setWindowSize(int width, int height) {
imageWidth = width;
imageHeight = height;
}
/**
* This method must be called before {@code super.init()}!
*/
protected void setWindowOffset(int xOffset, int yOffset) {
windowXOffset = xOffset;
windowYOffset = yOffset;
}
@Override
protected void init() {
super.init();
leftPos += windowXOffset;
topPos += windowYOffset;
}
@Override
protected void containerTick() {
for (GuiEventListener listener : children()) {
if (listener instanceof TickableGuiEventListener tickable) {
tickable.tick();
}
}
}
@SuppressWarnings("unchecked")
protected <W extends GuiEventListener & Widget & NarratableEntry> void addRenderableWidgets(W... widgets) {
for (W widget : widgets) {
addRenderableWidget(widget);
}
}
protected <W extends GuiEventListener & Widget & NarratableEntry> void addRenderableWidgets(Collection<W> widgets) {
for (W widget : widgets) {
addRenderableWidget(widget);
}
}
protected void removeWidgets(GuiEventListener... widgets) {
for (GuiEventListener widget : widgets) {
removeWidget(widget);
}
}
protected void removeWidgets(Collection<? extends GuiEventListener> widgets) {
for (GuiEventListener widget : widgets) {
removeWidget(widget);
}
}
@Override
public void render(PoseStack matrixStack, int mouseX, int mouseY, float partialTicks) {
partialTicks = minecraft.getFrameTime();
renderBackground(matrixStack);
super.render(matrixStack, mouseX, mouseY, partialTicks);
renderForeground(matrixStack, mouseX, mouseY, partialTicks);
}
@Override
protected void renderLabels(PoseStack poseStack, int mouseX, int mouseY) {
// no-op to prevent screen- and inventory-title from being rendered at incorrect
// location
// could also set this.titleX/Y and this.playerInventoryTitleX/Y to the proper
// values instead
}
protected void renderForeground(PoseStack ms, int mouseX, int mouseY, float partialTicks) {
renderTooltip(ms, mouseX, mouseY);
for (Widget widget : renderables) {
if (widget instanceof AbstractSimiWidget simiWidget && simiWidget.isHoveredOrFocused()) {
List<Component> tooltip = simiWidget.getToolTip();
if (tooltip.isEmpty())
continue;
int ttx = simiWidget.lockedTooltipX == -1 ? mouseX : simiWidget.lockedTooltipX + simiWidget.x;
int tty = simiWidget.lockedTooltipY == -1 ? mouseY : simiWidget.lockedTooltipY + simiWidget.y;
renderComponentTooltip(ms, tooltip, ttx, tty);
}
}
}
public int getLeftOfCentered(int textureWidth) {
return leftPos - windowXOffset + (imageWidth - textureWidth) / 2;
}
public void renderPlayerInventory(PoseStack ms, int x, int y) {
AllGuiTextures.PLAYER_INVENTORY.render(ms, x, y, this);
font.draw(ms, playerInventoryTitle, x + 8, y + 6, 0x404040);
}
@Override
public boolean keyPressed(int pKeyCode, int pScanCode, int pModifiers) {
InputConstants.Key mouseKey = InputConstants.getKey(pKeyCode, pScanCode);
if (getFocused() != null && this.minecraft.options.keyInventory.isActiveAndMatches(mouseKey))
return false;
return super.keyPressed(pKeyCode, pScanCode, pModifiers);
}
@Override
public GuiEventListener getFocused() {
GuiEventListener focused = super.getFocused();
if (focused instanceof AbstractWidget && !((AbstractWidget) focused).isFocused())
focused = null;
setFocused(focused);
return focused;
}
/**
* Used for moving JEI out of the way of extra things like block renders.
*
* @return the space that the GUI takes up outside the normal rectangle defined
* by {@link ContainerScreen}.
*/
public List<Rect2i> getExtraAreas() {
return Collections.emptyList();
}
@Deprecated
protected void debugWindowArea(PoseStack matrixStack) {
fill(matrixStack, leftPos + imageWidth, topPos + imageHeight, leftPos, topPos, 0xD3D3D3D3);
}
@Deprecated
protected void debugExtraAreas(PoseStack matrixStack) {
for (Rect2i area : getExtraAreas()) {
fill(matrixStack, area.getX() + area.getWidth(), area.getY() + area.getHeight(), area.getX(), area.getY(),
0xD3D3D3D3);
}
}
}

View File

@@ -0,0 +1,35 @@
package nl.requios.effortlessbuilding.create.foundation.gui.container;
import nl.requios.effortlessbuilding.create.foundation.networking.SimplePacketBase;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.network.NetworkEvent.Context;
import java.util.function.Supplier;
public class ClearContainerPacket extends SimplePacketBase {
public ClearContainerPacket() {}
public ClearContainerPacket(FriendlyByteBuf buffer) {}
@Override
public void write(FriendlyByteBuf buffer) {}
@Override
public void handle(Supplier<Context> context) {
context.get()
.enqueueWork(() -> {
ServerPlayer player = context.get()
.getSender();
if (player == null)
return;
if (!(player.containerMenu instanceof IClearableContainer))
return;
((IClearableContainer) player.containerMenu).clearContents();
});
context.get()
.setPacketHandled(true);
}
}

View File

@@ -0,0 +1,70 @@
package nl.requios.effortlessbuilding.create.foundation.gui.container;
import nl.requios.effortlessbuilding.create.foundation.utility.IInteractionChecker;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.MenuType;
import net.minecraft.world.inventory.Slot;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
public abstract class ContainerBase<T> extends AbstractContainerMenu {
public Player player;
public Inventory playerInventory;
public T contentHolder;
protected ContainerBase(MenuType<?> type, int id, Inventory inv, FriendlyByteBuf extraData) {
super(type, id);
init(inv, createOnClient(extraData));
}
protected ContainerBase(MenuType<?> type, int id, Inventory inv, T contentHolder) {
super(type, id);
init(inv, contentHolder);
}
protected void init(Inventory inv, T contentHolderIn) {
player = inv.player;
playerInventory = inv;
contentHolder = contentHolderIn;
initAndReadInventory(contentHolder);
addSlots();
broadcastChanges();
}
@OnlyIn(Dist.CLIENT)
protected abstract T createOnClient(FriendlyByteBuf extraData);
protected abstract void initAndReadInventory(T contentHolder);
protected abstract void addSlots();
protected abstract void saveData(T contentHolder);
protected void addPlayerSlots(int x, int y) {
for (int hotbarSlot = 0; hotbarSlot < 9; ++hotbarSlot)
this.addSlot(new Slot(playerInventory, hotbarSlot, x + hotbarSlot * 18, y + 58));
for (int row = 0; row < 3; ++row)
for (int col = 0; col < 9; ++col)
this.addSlot(new Slot(playerInventory, col + row * 9 + 9, x + col * 18, y + row * 18));
}
@Override
public void removed(Player playerIn) {
super.removed(playerIn);
saveData(contentHolder);
}
@Override
public boolean stillValid(Player player) {
if (contentHolder == null)
return false;
if (contentHolder instanceof IInteractionChecker)
return ((IInteractionChecker) contentHolder).canPlayerUse(player);
return true;
}
}

View File

@@ -0,0 +1,108 @@
package nl.requios.effortlessbuilding.create.foundation.gui.container;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.ClickType;
import net.minecraft.world.inventory.MenuType;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.items.ItemHandlerHelper;
import net.minecraftforge.items.ItemStackHandler;
public abstract class GhostItemContainer<T> extends ContainerBase<T> implements IClearableContainer {
public ItemStackHandler ghostInventory;
protected GhostItemContainer(MenuType<?> type, int id, Inventory inv, FriendlyByteBuf extraData) {
super(type, id, inv, extraData);
}
protected GhostItemContainer(MenuType<?> type, int id, Inventory inv, T contentHolder) {
super(type, id, inv, contentHolder);
}
protected abstract ItemStackHandler createGhostInventory();
protected abstract boolean allowRepeats();
@Override
protected void initAndReadInventory(T contentHolder) {
ghostInventory = createGhostInventory();
}
@Override
public void clearContents() {
for (int i = 0; i < ghostInventory.getSlots(); i++)
ghostInventory.setStackInSlot(i, ItemStack.EMPTY);
}
@Override
public boolean canTakeItemForPickAll(ItemStack stack, Slot slotIn) {
return slotIn.container == playerInventory;
}
@Override
public boolean canDragTo(Slot slotIn) {
if (allowRepeats())
return true;
return slotIn.container == playerInventory;
}
@Override
public void clicked(int slotId, int dragType, ClickType clickTypeIn, Player player) {
if (slotId < 36) {
super.clicked(slotId, dragType, clickTypeIn, player);
return;
}
if (clickTypeIn == ClickType.THROW)
return;
ItemStack held = getCarried();
int slot = slotId - 36;
if (clickTypeIn == ClickType.CLONE) {
if (player.isCreative() && held.isEmpty()) {
ItemStack stackInSlot = ghostInventory.getStackInSlot(slot)
.copy();
stackInSlot.setCount(stackInSlot.getMaxStackSize());
setCarried(stackInSlot);
return;
}
return;
}
ItemStack insert;
if (held.isEmpty()) {
insert = ItemStack.EMPTY;
} else {
insert = held.copy();
insert.setCount(1);
}
ghostInventory.setStackInSlot(slot, insert);
getSlot(slotId).setChanged();
}
@Override
public ItemStack quickMoveStack(Player playerIn, int index) {
if (index < 36) {
ItemStack stackToInsert = playerInventory.getItem(index);
for (int i = 0; i < ghostInventory.getSlots(); i++) {
ItemStack stack = ghostInventory.getStackInSlot(i);
if (!allowRepeats() && ItemHandlerHelper.canItemStacksStack(stack, stackToInsert))
break;
if (stack.isEmpty()) {
ItemStack copy = stackToInsert.copy();
copy.setCount(1);
ghostInventory.insertItem(i, copy, false);
getSlot(i + 36).setChanged();
break;
}
}
} else {
ghostInventory.extractItem(index - 36, 1, false);
getSlot(index).setChanged();
}
return ItemStack.EMPTY;
}
}

View File

@@ -0,0 +1,52 @@
package nl.requios.effortlessbuilding.create.foundation.gui.container;
import nl.requios.effortlessbuilding.create.foundation.networking.SimplePacketBase;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.network.NetworkEvent.Context;
import java.util.function.Supplier;
public class GhostItemSubmitPacket extends SimplePacketBase {
private final ItemStack item;
private final int slot;
public GhostItemSubmitPacket(ItemStack item, int slot) {
this.item = item;
this.slot = slot;
}
public GhostItemSubmitPacket(FriendlyByteBuf buffer) {
item = buffer.readItem();
slot = buffer.readInt();
}
@Override
public void write(FriendlyByteBuf buffer) {
buffer.writeItem(item);
buffer.writeInt(slot);
}
@Override
public void handle(Supplier<Context> context) {
context.get()
.enqueueWork(() -> {
ServerPlayer player = context.get()
.getSender();
if (player == null)
return;
if (player.containerMenu instanceof GhostItemContainer) {
GhostItemContainer<?> c = (GhostItemContainer<?>) player.containerMenu;
c.ghostInventory.setStackInSlot(slot, item);
c.getSlot(36 + slot).setChanged();
}
});
context.get()
.setPacketHandled(true);
}
}

View File

@@ -0,0 +1,14 @@
package nl.requios.effortlessbuilding.create.foundation.gui.container;
//import nl.requios.effortlessbuilding.create.foundation.networking.AllPackets;
public interface IClearableContainer {
default void sendClearPacket() {
// AllPackets.channel.sendToServer(new ClearContainerPacket());
}
@Deprecated //warning: does not work
public void clearContents();
}

View File

@@ -0,0 +1,153 @@
package nl.requios.effortlessbuilding.create.foundation.gui.element;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.*;
import com.mojang.math.Matrix4f;
import nl.requios.effortlessbuilding.create.foundation.utility.Color;
import nl.requios.effortlessbuilding.create.foundation.utility.Couple;
import net.minecraft.client.renderer.GameRenderer;
public class BoxElement extends RenderElement {
protected Color background = new Color(0xff000000, true);
protected Color borderTop = new Color(0x40ffeedd, true);
protected Color borderBot = new Color(0x20ffeedd, true);
protected int borderOffset = 2;
public <T extends BoxElement> T withBackground(Color color) {
this.background = color;
//noinspection unchecked
return (T) this;
}
public <T extends BoxElement> T withBackground(int color) {
return withBackground(new Color(color, true));
}
public <T extends BoxElement> T flatBorder(Color color) {
this.borderTop = color;
this.borderBot = color;
//noinspection unchecked
return (T) this;
}
public <T extends BoxElement> T flatBorder(int color) {
return flatBorder(new Color(color, true));
}
public <T extends BoxElement> T gradientBorder(Couple<Color> colors) {
this.borderTop = colors.getFirst();
this.borderBot = colors.getSecond();
//noinspection unchecked
return (T) this;
}
public <T extends BoxElement> T gradientBorder(Color top, Color bot) {
this.borderTop = top;
this.borderBot = bot;
//noinspection unchecked
return (T) this;
}
public <T extends BoxElement> T gradientBorder(int top, int bot) {
return gradientBorder(new Color(top, true), new Color(bot, true));
}
public <T extends BoxElement> T withBorderOffset(int offset) {
this.borderOffset = offset;
//noinspection unchecked
return (T) this;
}
@Override
public void render(PoseStack ms) {
renderBox(ms);
}
//total box width = 1 * 2 (outer border) + 1 * 2 (inner color border) + 2 * borderOffset + width
//defaults to 2 + 2 + 4 + 16 = 24px
//batch everything together to save a bunch of gl calls over ScreenUtils
protected void renderBox(PoseStack ms) {
/*
* _____________
* _|_____________|_
* | | ___________ | |
* | | | | | | |
* | | | | | | |
* | | |--* | | | |
* | | | h | | |
* | | | --w-+ | | |
* | | | | | |
* | | |_________| | |
* |_|_____________|_|
* |_____________|
*
* */
RenderSystem.disableTexture();
RenderSystem.enableBlend();
RenderSystem.defaultBlendFunc();
RenderSystem.setShader(GameRenderer::getPositionColorShader);
Matrix4f model = ms.last().pose();
int f = borderOffset;
Color c1 = background.copy().scaleAlpha(alpha);
Color c2 = borderTop.copy().scaleAlpha(alpha);
Color c3 = borderBot.copy().scaleAlpha(alpha);
Tesselator tessellator = Tesselator.getInstance();
BufferBuilder b = tessellator.getBuilder();
b.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR);
//outer top
b.vertex(model, x - f - 1 , y - f - 2 , z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex();
b.vertex(model, x - f - 1 , y - f - 1 , z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex();
b.vertex(model, x + f + 1 + width, y - f - 1 , z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex();
b.vertex(model, x + f + 1 + width, y - f - 2 , z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex();
//outer left
b.vertex(model, x - f - 2 , y - f - 1 , z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex();
b.vertex(model, x - f - 2 , y + f + 1 + height, z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex();
b.vertex(model, x - f - 1 , y + f + 1 + height, z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex();
b.vertex(model, x - f - 1 , y - f - 1 , z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex();
//outer bottom
b.vertex(model, x - f - 1 , y + f + 1 + height, z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex();
b.vertex(model, x - f - 1 , y + f + 2 + height, z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex();
b.vertex(model, x + f + 1 + width, y + f + 2 + height, z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex();
b.vertex(model, x + f + 1 + width, y + f + 1 + height, z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex();
//outer right
b.vertex(model, x + f + 1 + width, y - f - 1 , z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex();
b.vertex(model, x + f + 1 + width, y + f + 1 + height, z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex();
b.vertex(model, x + f + 2 + width, y + f + 1 + height, z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex();
b.vertex(model, x + f + 2 + width, y - f - 1 , z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex();
//inner background - also render behind the inner edges
b.vertex(model, x - f - 1 , y - f - 1 , z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex();
b.vertex(model, x - f - 1 , y + f + 1 + height, z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex();
b.vertex(model, x + f + 1 + width, y + f + 1 + height, z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex();
b.vertex(model, x + f + 1 + width, y - f - 1 , z).color(c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha()).endVertex();
tessellator.end();
b.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR);
//inner top - includes corners
b.vertex(model, x - f - 1 , y - f - 1 , z).color(c2.getRed(), c2.getGreen(), c2.getBlue(), c2.getAlpha()).endVertex();
b.vertex(model, x - f - 1 , y - f , z).color(c2.getRed(), c2.getGreen(), c2.getBlue(), c2.getAlpha()).endVertex();
b.vertex(model, x + f + 1 + width, y - f , z).color(c2.getRed(), c2.getGreen(), c2.getBlue(), c2.getAlpha()).endVertex();
b.vertex(model, x + f + 1 + width, y - f - 1 , z).color(c2.getRed(), c2.getGreen(), c2.getBlue(), c2.getAlpha()).endVertex();
//inner left - excludes corners
b.vertex(model, x - f - 1 , y - f , z).color(c2.getRed(), c2.getGreen(), c2.getBlue(), c2.getAlpha()).endVertex();
b.vertex(model, x - f - 1 , y + f + height, z).color(c3.getRed(), c3.getGreen(), c3.getBlue(), c3.getAlpha()).endVertex();
b.vertex(model, x - f , y + f + height, z).color(c3.getRed(), c3.getGreen(), c3.getBlue(), c3.getAlpha()).endVertex();
b.vertex(model, x - f , y - f , z).color(c2.getRed(), c2.getGreen(), c2.getBlue(), c2.getAlpha()).endVertex();
//inner bottom - includes corners
b.vertex(model, x - f - 1 , y + f + height, z).color(c3.getRed(), c3.getGreen(), c3.getBlue(), c3.getAlpha()).endVertex();
b.vertex(model, x - f - 1 , y + f + 1 + height, z).color(c3.getRed(), c3.getGreen(), c3.getBlue(), c3.getAlpha()).endVertex();
b.vertex(model, x + f + 1 + width, y + f + 1 + height, z).color(c3.getRed(), c3.getGreen(), c3.getBlue(), c3.getAlpha()).endVertex();
b.vertex(model, x + f + 1 + width, y + f + height, z).color(c3.getRed(), c3.getGreen(), c3.getBlue(), c3.getAlpha()).endVertex();
//inner right - excludes corners
b.vertex(model, x + f + width, y - f , z).color(c2.getRed(), c2.getGreen(), c2.getBlue(), c2.getAlpha()).endVertex();
b.vertex(model, x + f + width, y + f + height, z).color(c3.getRed(), c3.getGreen(), c3.getBlue(), c3.getAlpha()).endVertex();
b.vertex(model, x + f + 1 + width, y + f + height, z).color(c3.getRed(), c3.getGreen(), c3.getBlue(), c3.getAlpha()).endVertex();
b.vertex(model, x + f + 1 + width, y - f , z).color(c2.getRed(), c2.getGreen(), c2.getBlue(), c2.getAlpha()).endVertex();
tessellator.end();
RenderSystem.disableBlend();
RenderSystem.enableTexture();
}
}

View File

@@ -0,0 +1,79 @@
package nl.requios.effortlessbuilding.create.foundation.gui.element;
import com.mojang.blaze3d.vertex.PoseStack;
import javax.annotation.Nonnull;
public class CombinedStencilElement extends StencilElement {
private StencilElement element1;
private StencilElement element2;
private ElementMode mode;
private CombinedStencilElement() {}
public static CombinedStencilElement of(@Nonnull StencilElement element1, @Nonnull StencilElement element2) {
return of(element1, element2, ElementMode.FIRST);
}
public static CombinedStencilElement of(@Nonnull StencilElement element1, @Nonnull StencilElement element2, ElementMode mode) {
CombinedStencilElement e = new CombinedStencilElement();
e.element1 = element1;
e.element2 = element2;
e.mode = mode;
return e;
}
public <T extends CombinedStencilElement> T withFirst(StencilElement element) {
this.element1 = element;
//noinspection unchecked
return (T) this;
}
public <T extends CombinedStencilElement> T withSecond(StencilElement element) {
this.element2 = element;
//noinspection unchecked
return (T) this;
}
public <T extends CombinedStencilElement> T withMode(ElementMode mode) {
this.mode = mode;
//noinspection unchecked
return (T) this;
}
@Override
protected void renderStencil(PoseStack ms) {
ms.pushPose();
element1.transform(ms);
element1.withBounds(width, height);
element1.renderStencil(ms);
ms.popPose();
ms.pushPose();
element2.transform(ms);
element2.withBounds(width, height);
element2.renderStencil(ms);
ms.popPose();
}
@Override
protected void renderElement(PoseStack ms) {
if (mode.rendersFirst())
element1.<StencilElement>withBounds(width, height).renderElement(ms);
if (mode.rendersSecond())
element2.<StencilElement>withBounds(width, height).renderElement(ms);
}
public enum ElementMode {
FIRST, SECOND, BOTH;
boolean rendersFirst() {
return this == FIRST || this == BOTH;
}
boolean rendersSecond() {
return this == SECOND || this == BOTH;
}
}
}

View File

@@ -0,0 +1,52 @@
package nl.requios.effortlessbuilding.create.foundation.gui.element;
import com.mojang.blaze3d.vertex.PoseStack;
import nl.requios.effortlessbuilding.create.foundation.gui.UIRenderHelper;
import nl.requios.effortlessbuilding.create.foundation.utility.Color;
public class DelegatedStencilElement extends StencilElement {
protected static final ElementRenderer EMPTY_RENDERER = (ms, width, height, alpha) -> {};
protected static final ElementRenderer DEFAULT_ELEMENT = (ms, width, height, alpha) -> UIRenderHelper.angledGradient(ms, 0, -3, 5, height+4, width+6, new Color(0xff_10dd10).scaleAlpha(alpha), new Color(0xff_1010dd).scaleAlpha(alpha));
protected ElementRenderer stencil;
protected ElementRenderer element;
public DelegatedStencilElement() {
stencil = EMPTY_RENDERER;
element = DEFAULT_ELEMENT;
}
public DelegatedStencilElement(ElementRenderer stencil, ElementRenderer element) {
this.stencil = stencil;
this.element = element;
}
public <T extends DelegatedStencilElement> T withStencilRenderer(ElementRenderer renderer) {
stencil = renderer;
//noinspection unchecked
return (T) this;
}
public <T extends DelegatedStencilElement> T withElementRenderer(ElementRenderer renderer) {
element = renderer;
//noinspection unchecked
return (T) this;
}
@Override
protected void renderStencil(PoseStack ms) {
stencil.render(ms, width, height, 1);
}
@Override
protected void renderElement(PoseStack ms) {
element.render(ms, width, height, alpha);
}
@FunctionalInterface
public interface ElementRenderer {
void render(PoseStack ms, int width, int height, float alpha);
}
}

View File

@@ -0,0 +1,297 @@
package nl.requios.effortlessbuilding.create.foundation.gui.element;
import com.jozufozu.flywheel.core.PartialModel;
import com.jozufozu.flywheel.core.model.ModelUtil;
import com.mojang.blaze3d.platform.GlStateManager.DestFactor;
import com.mojang.blaze3d.platform.GlStateManager.SourceFactor;
import com.mojang.blaze3d.platform.Lighting;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Vector3f;
//import nl.requios.effortlessbuilding.create.foundation.fluid.FluidRenderer;
import nl.requios.effortlessbuilding.create.foundation.gui.ILightingSettings;
import nl.requios.effortlessbuilding.create.foundation.gui.UIRenderHelper;
import nl.requios.effortlessbuilding.create.foundation.utility.Color;
import nl.requios.effortlessbuilding.create.foundation.utility.VecHelper;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.Sheets;
import net.minecraft.client.renderer.block.BlockRenderDispatcher;
import net.minecraft.client.renderer.block.model.ItemTransforms;
import net.minecraft.client.renderer.entity.ItemRenderer;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.core.BlockPos;
import net.minecraft.util.RandomSource;
import net.minecraft.world.inventory.InventoryMenu;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.level.block.BaseFireBlock;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.LiquidBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.client.RenderTypeHelper;
import net.minecraftforge.fluids.FluidStack;
import javax.annotation.Nullable;
public class GuiGameElement {
public static GuiRenderBuilder of(ItemStack stack) {
return new GuiItemRenderBuilder(stack);
}
public static GuiRenderBuilder of(ItemLike itemProvider) {
return new GuiItemRenderBuilder(itemProvider);
}
public static GuiRenderBuilder of(BlockState state) {
return new GuiBlockStateRenderBuilder(state);
}
public static GuiRenderBuilder of(PartialModel partial) {
return new GuiBlockPartialRenderBuilder(partial);
}
public static GuiRenderBuilder of(Fluid fluid) {
return new GuiBlockStateRenderBuilder(fluid.defaultFluidState()
.createLegacyBlock()
.setValue(LiquidBlock.LEVEL, 0));
}
public static abstract class GuiRenderBuilder extends RenderElement {
protected double xLocal, yLocal, zLocal;
protected double xRot, yRot, zRot;
protected double scale = 1;
protected int color = 0xFFFFFF;
protected Vec3 rotationOffset = Vec3.ZERO;
protected ILightingSettings customLighting = null;
public GuiRenderBuilder atLocal(double x, double y, double z) {
this.xLocal = x;
this.yLocal = y;
this.zLocal = z;
return this;
}
public GuiRenderBuilder rotate(double xRot, double yRot, double zRot) {
this.xRot = xRot;
this.yRot = yRot;
this.zRot = zRot;
return this;
}
public GuiRenderBuilder rotateBlock(double xRot, double yRot, double zRot) {
return this.rotate(xRot, yRot, zRot)
.withRotationOffset(VecHelper.getCenterOf(BlockPos.ZERO));
}
public GuiRenderBuilder scale(double scale) {
this.scale = scale;
return this;
}
public GuiRenderBuilder color(int color) {
this.color = color;
return this;
}
public GuiRenderBuilder withRotationOffset(Vec3 offset) {
this.rotationOffset = offset;
return this;
}
public GuiRenderBuilder lighting(ILightingSettings lighting) {
customLighting = lighting;
return this;
}
protected void prepareMatrix(PoseStack matrixStack) {
matrixStack.pushPose();
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
RenderSystem.enableDepthTest();
RenderSystem.enableBlend();
RenderSystem.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA);
prepareLighting(matrixStack);
}
protected void transformMatrix(PoseStack matrixStack) {
matrixStack.translate(x, y, z);
matrixStack.scale((float) scale, (float) scale, (float) scale);
matrixStack.translate(xLocal, yLocal, zLocal);
UIRenderHelper.flipForGuiRender(matrixStack);
matrixStack.translate(rotationOffset.x, rotationOffset.y, rotationOffset.z);
matrixStack.mulPose(Vector3f.ZP.rotationDegrees((float) zRot));
matrixStack.mulPose(Vector3f.XP.rotationDegrees((float) xRot));
matrixStack.mulPose(Vector3f.YP.rotationDegrees((float) yRot));
matrixStack.translate(-rotationOffset.x, -rotationOffset.y, -rotationOffset.z);
}
protected void cleanUpMatrix(PoseStack matrixStack) {
matrixStack.popPose();
cleanUpLighting(matrixStack);
}
protected void prepareLighting(PoseStack matrixStack) {
if (customLighting != null) {
customLighting.applyLighting();
} else {
Lighting.setupFor3DItems();
}
}
protected void cleanUpLighting(PoseStack matrixStack) {
if (customLighting != null) {
Lighting.setupFor3DItems();
}
}
}
private static class GuiBlockModelRenderBuilder extends GuiRenderBuilder {
protected BakedModel blockModel;
protected BlockState blockState;
public GuiBlockModelRenderBuilder(BakedModel blockmodel, @Nullable BlockState blockState) {
this.blockState = blockState == null ? Blocks.AIR.defaultBlockState() : blockState;
this.blockModel = blockmodel;
}
@Override
public void render(PoseStack matrixStack) {
prepareMatrix(matrixStack);
Minecraft mc = Minecraft.getInstance();
BlockRenderDispatcher blockRenderer = mc.getBlockRenderer();
MultiBufferSource.BufferSource buffer = mc.renderBuffers()
.bufferSource();
transformMatrix(matrixStack);
RenderSystem.setShaderTexture(0, InventoryMenu.BLOCK_ATLAS);
renderModel(blockRenderer, buffer, matrixStack);
cleanUpMatrix(matrixStack);
}
protected void renderModel(BlockRenderDispatcher blockRenderer, MultiBufferSource.BufferSource buffer,
PoseStack ms) {
if (blockState.getBlock() == Blocks.AIR) {
RenderType renderType = Sheets.translucentCullBlockSheet();
blockRenderer.getModelRenderer()
.renderModel(ms.last(), buffer.getBuffer(renderType), blockState, blockModel, 1, 1, 1,
LightTexture.FULL_BRIGHT, OverlayTexture.NO_OVERLAY, ModelUtil.VIRTUAL_DATA, null);
} else {
int color = Minecraft.getInstance()
.getBlockColors()
.getColor(blockState, null, null, 0);
Color rgb = new Color(color == -1 ? this.color : color);
for (RenderType chunkType : blockModel.getRenderTypes(blockState, RandomSource.create(42L), ModelUtil.VIRTUAL_DATA)) {
RenderType renderType = RenderTypeHelper.getEntityRenderType(chunkType, true);
blockRenderer.getModelRenderer()
.renderModel(ms.last(), buffer.getBuffer(renderType), blockState, blockModel,
rgb.getRedAsFloat(), rgb.getGreenAsFloat(), rgb.getBlueAsFloat(),
LightTexture.FULL_BRIGHT, OverlayTexture.NO_OVERLAY, ModelUtil.VIRTUAL_DATA, chunkType);
}
}
buffer.endBatch();
}
}
public static class GuiBlockStateRenderBuilder extends GuiBlockModelRenderBuilder {
public GuiBlockStateRenderBuilder(BlockState blockstate) {
super(Minecraft.getInstance()
.getBlockRenderer()
.getBlockModel(blockstate), blockstate);
}
@Override
protected void renderModel(BlockRenderDispatcher blockRenderer, MultiBufferSource.BufferSource buffer,
PoseStack ms) {
if (blockState.getBlock() instanceof BaseFireBlock) {
Lighting.setupForFlatItems();
super.renderModel(blockRenderer, buffer, ms);
Lighting.setupFor3DItems();
return;
}
super.renderModel(blockRenderer, buffer, ms);
if (blockState.getFluidState()
.isEmpty())
return;
// FluidRenderer.renderFluidBox(new FluidStack(blockState.getFluidState()
// .getType(), 1000), 0, 0, 0, 1, 1, 1, buffer, ms, LightTexture.FULL_BRIGHT, false);
// buffer.endBatch();
}
}
public static class GuiBlockPartialRenderBuilder extends GuiBlockModelRenderBuilder {
public GuiBlockPartialRenderBuilder(PartialModel partial) {
super(partial.get(), null);
}
}
public static class GuiItemRenderBuilder extends GuiRenderBuilder {
private final ItemStack stack;
public GuiItemRenderBuilder(ItemStack stack) {
this.stack = stack;
}
public GuiItemRenderBuilder(ItemLike provider) {
this(new ItemStack(provider));
}
@Override
public void render(PoseStack matrixStack) {
prepareMatrix(matrixStack);
transformMatrix(matrixStack);
renderItemIntoGUI(matrixStack, stack, customLighting == null);
cleanUpMatrix(matrixStack);
}
public static void renderItemIntoGUI(PoseStack matrixStack, ItemStack stack, boolean useDefaultLighting) {
ItemRenderer renderer = Minecraft.getInstance().getItemRenderer();
BakedModel bakedModel = renderer.getModel(stack, null, null, 0);
renderer.textureManager.getTexture(InventoryMenu.BLOCK_ATLAS).setFilter(false, false);
RenderSystem.setShaderTexture(0, InventoryMenu.BLOCK_ATLAS);
RenderSystem.enableBlend();
RenderSystem.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA);
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
matrixStack.pushPose();
matrixStack.translate(0, 0, 100.0F + renderer.blitOffset);
matrixStack.translate(8.0F, -8.0F, 0.0F);
matrixStack.scale(16.0F, 16.0F, 16.0F);
MultiBufferSource.BufferSource buffer = Minecraft.getInstance().renderBuffers().bufferSource();
boolean flatLighting = !bakedModel.usesBlockLight();
if (useDefaultLighting && flatLighting) {
Lighting.setupForFlatItems();
}
renderer.render(stack, ItemTransforms.TransformType.GUI, false, matrixStack, buffer, LightTexture.FULL_BRIGHT, OverlayTexture.NO_OVERLAY, bakedModel);
buffer.endBatch();
RenderSystem.enableDepthTest();
if (useDefaultLighting && flatLighting) {
Lighting.setupFor3DItems();
}
matrixStack.popPose();
}
}
}

View File

@@ -0,0 +1,89 @@
package nl.requios.effortlessbuilding.create.foundation.gui.element;
import com.mojang.blaze3d.vertex.PoseStack;
public abstract class RenderElement implements ScreenElement {
public static final RenderElement EMPTY = new RenderElement() {
@Override
public void render(PoseStack ms) {
}
};
public static RenderElement of(ScreenElement renderable) {
return new SimpleRenderElement(renderable);
}
protected int width = 16, height = 16;
protected float x = 0, y = 0, z = 0;
protected float alpha = 1f;
public <T extends RenderElement> T at(float x, float y) {
this.x = x;
this.y = y;
//noinspection unchecked
return (T) this;
}
public <T extends RenderElement> T at(float x, float y, float z) {
this.x = x;
this.y = y;
this.z = z;
//noinspection unchecked
return (T) this;
}
public <T extends RenderElement> T withBounds(int width, int height) {
this.width = width;
this.height = height;
//noinspection unchecked
return (T) this;
}
public <T extends RenderElement> T withAlpha(float alpha) {
this.alpha = alpha;
//noinspection unchecked
return (T) this;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public float getX() {
return x;
}
public float getY() {
return y;
}
public float getZ() {
return z;
}
public abstract void render(PoseStack ms);
@Override
public void render(PoseStack ms, int x, int y) {
this.at(x, y).render(ms);
}
public static class SimpleRenderElement extends RenderElement {
private ScreenElement renderable;
public SimpleRenderElement(ScreenElement renderable) {
this.renderable = renderable;
}
@Override
public void render(PoseStack ms) {
renderable.render(ms, (int) x, (int) y);
}
}
}

View File

@@ -0,0 +1,12 @@
package nl.requios.effortlessbuilding.create.foundation.gui.element;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
public interface ScreenElement {
@OnlyIn(Dist.CLIENT)
void render(PoseStack ms, int x, int y);
}

View File

@@ -0,0 +1,50 @@
package nl.requios.effortlessbuilding.create.foundation.gui.element;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Minecraft;
import org.lwjgl.opengl.GL11;
public abstract class StencilElement extends RenderElement {
@Override
public void render(PoseStack ms) {
ms.pushPose();
transform(ms);
prepareStencil(ms);
renderStencil(ms);
prepareElement(ms);
renderElement(ms);
cleanUp(ms);
ms.popPose();
}
protected abstract void renderStencil(PoseStack ms);
protected abstract void renderElement(PoseStack ms);
protected void transform(PoseStack ms) {
ms.translate(x, y, z);
}
protected void prepareStencil(PoseStack ms) {
GL11.glDisable(GL11.GL_STENCIL_TEST);
RenderSystem.stencilMask(~0);
RenderSystem.clear(GL11.GL_STENCIL_BUFFER_BIT, Minecraft.ON_OSX);
GL11.glEnable(GL11.GL_STENCIL_TEST);
RenderSystem.stencilOp(GL11.GL_REPLACE, GL11.GL_KEEP, GL11.GL_KEEP);
RenderSystem.stencilMask(0xFF);
RenderSystem.stencilFunc(GL11.GL_NEVER, 1, 0xFF);
}
protected void prepareElement(PoseStack ms) {
GL11.glEnable(GL11.GL_STENCIL_TEST);
RenderSystem.stencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_KEEP);
RenderSystem.stencilFunc(GL11.GL_EQUAL, 1, 0xFF);
}
protected void cleanUp(PoseStack ms) {
GL11.glDisable(GL11.GL_STENCIL_TEST);
}
}

View File

@@ -0,0 +1,78 @@
package nl.requios.effortlessbuilding.create.foundation.gui.element;
import com.mojang.blaze3d.vertex.PoseStack;
import nl.requios.effortlessbuilding.create.foundation.utility.Components;
import net.minecraft.client.gui.Font;
import net.minecraft.network.chat.MutableComponent;
public class TextStencilElement extends DelegatedStencilElement {
protected Font font;
protected MutableComponent component;
protected boolean centerVertically = false;
protected boolean centerHorizontally = false;
public TextStencilElement(Font font) {
super();
this.font = font;
height = 10;
}
public TextStencilElement(Font font, String text) {
this(font);
component = Components.literal(text);
}
public TextStencilElement(Font font, MutableComponent component) {
this(font);
this.component = component;
}
public TextStencilElement withText(String text) {
component = Components.literal(text);
return this;
}
public TextStencilElement withText(MutableComponent component) {
this.component = component;
return this;
}
public TextStencilElement centered(boolean vertical, boolean horizontal) {
this.centerVertically = vertical;
this.centerHorizontally = horizontal;
return this;
}
@Override
protected void renderStencil(PoseStack ms) {
float x = 0, y = 0;
if (centerHorizontally)
x = width / 2f - font.width(component) / 2f;
if (centerVertically)
y = height / 2f - (font.lineHeight - 1) / 2f;
font.draw(ms, component, x, y, 0xff_000000);
}
@Override
protected void renderElement(PoseStack ms) {
float x = 0, y = 0;
if (centerHorizontally)
x = width / 2f - font.width(component) / 2f;
if (centerVertically)
y = height / 2f - (font.lineHeight - 1) / 2f;
ms.pushPose();
ms.translate(x, y, 0);
element.render(ms, font.width(component), font.lineHeight + 2, alpha);
ms.popPose();
}
public MutableComponent getComponent() {
return component;
}
}

View File

@@ -0,0 +1,98 @@
package nl.requios.effortlessbuilding.create.foundation.gui.widget;
import com.mojang.blaze3d.vertex.PoseStack;
import nl.requios.effortlessbuilding.create.foundation.gui.TickableGuiEventListener;
import nl.requios.effortlessbuilding.create.foundation.utility.Components;
import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.narration.NarrationElementOutput;
import net.minecraft.network.chat.Component;
import javax.annotation.Nonnull;
import java.util.LinkedList;
import java.util.List;
import java.util.function.BiConsumer;
public abstract class AbstractSimiWidget extends AbstractWidget implements TickableGuiEventListener {
public static final int HEADER_RGB = 0x5391E1;
protected float z;
protected boolean wasHovered = false;
protected List<Component> toolTip = new LinkedList<>();
protected BiConsumer<Integer, Integer> onClick = (_$, _$$) -> {};
public int lockedTooltipX = -1;
public int lockedTooltipY = -1;
protected AbstractSimiWidget(int x, int y) {
this(x, y, 16, 16);
}
protected AbstractSimiWidget(int x, int y, int width, int height) {
this(x, y, width, height, Components.immutableEmpty());
}
protected AbstractSimiWidget(int x, int y, int width, int height, Component message) {
super(x, y, width, height, message);
}
public <T extends AbstractSimiWidget> T withCallback(BiConsumer<Integer, Integer> cb) {
this.onClick = cb;
//noinspection unchecked
return (T) this;
}
public <T extends AbstractSimiWidget> T withCallback(Runnable cb) {
return withCallback((_$, _$$) -> cb.run());
}
public <T extends AbstractSimiWidget> T atZLevel(float z) {
this.z = z;
//noinspection unchecked
return (T) this;
}
public List<Component> getToolTip() {
return toolTip;
}
@Override
public void tick() {}
@Override
public void render(@Nonnull PoseStack ms, int mouseX, int mouseY, float partialTicks) {
if (visible) {
isHovered = mouseX >= x && mouseY >= y && mouseX < x + width && mouseY < y + height;
beforeRender(ms, mouseX, mouseY, partialTicks);
renderButton(ms, mouseX, mouseY, partialTicks);
afterRender(ms, mouseX, mouseY, partialTicks);
wasHovered = isHoveredOrFocused();
}
}
protected void beforeRender(@Nonnull PoseStack ms, int mouseX, int mouseY, float partialTicks) {
ms.pushPose();
}
@Override
public void renderButton(@Nonnull PoseStack ms, int mouseX, int mouseY, float partialTicks) {
}
protected void afterRender(@Nonnull PoseStack ms, int mouseX, int mouseY, float partialTicks) {
ms.popPose();
}
public void runCallback(double mouseX, double mouseY) {
onClick.accept((int) mouseX, (int) mouseY);
}
@Override
public void onClick(double mouseX, double mouseY) {
runCallback(mouseX, mouseY);
}
@Override
public void updateNarration(NarrationElementOutput pNarrationElementOutput) {
defaultButtonNarrationText(pNarrationElementOutput);
}
}

View File

@@ -0,0 +1,228 @@
package nl.requios.effortlessbuilding.create.foundation.gui.widget;
import com.mojang.blaze3d.vertex.PoseStack;
import nl.requios.effortlessbuilding.create.foundation.gui.Theme;
import nl.requios.effortlessbuilding.create.foundation.gui.Theme.Key;
import nl.requios.effortlessbuilding.create.foundation.gui.UIRenderHelper;
import nl.requios.effortlessbuilding.create.foundation.gui.element.BoxElement;
import nl.requios.effortlessbuilding.create.foundation.gui.element.DelegatedStencilElement;
import nl.requios.effortlessbuilding.create.foundation.utility.Color;
import nl.requios.effortlessbuilding.create.foundation.utility.Couple;
import nl.requios.effortlessbuilding.create.foundation.utility.animation.LerpedFloat;
import javax.annotation.Nonnull;
import java.util.function.Function;
public class BoxWidget extends ElementWidget {
public static final Function<BoxWidget, DelegatedStencilElement.ElementRenderer> gradientFactory = (box) -> (ms, w, h, alpha) -> UIRenderHelper.angledGradient(ms, 90, w/2, -2, w + 4, h + 4, box.gradientColor1, box.gradientColor2);
protected BoxElement box;
protected Color customBorderTop;
protected Color customBorderBot;
protected Color customBackground;
protected boolean animateColors = true;
protected LerpedFloat colorAnimation = LerpedFloat.linear();
protected Color gradientColor1, gradientColor2;
private Color previousColor1, previousColor2;
private Color colorTarget1 = Theme.c(getIdleTheme(), true).copy();
private Color colorTarget2 = Theme.c(getIdleTheme(), false).copy();
public BoxWidget() {
this(0, 0);
}
public BoxWidget(int x, int y) {
this(x, y, 16, 16);
}
public BoxWidget(int x, int y, int width, int height) {
super(x, y, width, height);
box = new BoxElement()
.at(x, y)
.withBounds(width, height);
gradientColor1 = colorTarget1;
gradientColor2 = colorTarget2;
}
public <T extends BoxWidget> T withBounds(int width, int height) {
this.width = width;
this.height = height;
//noinspection unchecked
return (T) this;
}
public <T extends BoxWidget> T withBorderColors(Couple<Color> colors) {
this.customBorderTop = colors.getFirst();
this.customBorderBot = colors.getSecond();
updateColorsFromState();
//noinspection unchecked
return (T) this;
}
public <T extends BoxWidget> T withBorderColors(Color top, Color bot) {
this.customBorderTop = top;
this.customBorderBot = bot;
updateColorsFromState();
//noinspection unchecked
return (T) this;
}
public <T extends BoxWidget> T withCustomBackground(Color color) {
this.customBackground = color;
//noinspection unchecked
return (T) this;
}
public <T extends BoxWidget> T animateColors(boolean b) {
this.animateColors = b;
//noinspection unchecked
return (T) this;
}
@Override
public void tick() {
super.tick();
colorAnimation.tickChaser();
}
@Override
public void onClick(double x, double y) {
super.onClick(x, y);
gradientColor1 = Theme.c(getClickTheme(), true);
gradientColor2 = Theme.c(getClickTheme(), false);
startGradientAnimation(getColorForState(true), getColorForState(false), true, 0.15);
}
@Override
protected void beforeRender(@Nonnull PoseStack ms, int mouseX, int mouseY, float partialTicks) {
super.beforeRender(ms, mouseX, mouseY, partialTicks);
if (isHovered != wasHovered) {
startGradientAnimation(
getColorForState(true),
getColorForState(false),
isHovered
);
}
if (colorAnimation.settled()) {
gradientColor1 = colorTarget1;
gradientColor2 = colorTarget2;
} else {
float animationValue = 1 - Math.abs(colorAnimation.getValue(partialTicks));
gradientColor1 = Color.mixColors(previousColor1, colorTarget1, animationValue);
gradientColor2 = Color.mixColors(previousColor2, colorTarget2, animationValue);
}
}
@Override
public void renderButton(@Nonnull PoseStack ms, int mouseX, int mouseY, float partialTicks) {
float fadeValue = fade.getValue(partialTicks);
if (fadeValue < .1f)
return;
box.withAlpha(fadeValue);
box.withBackground(customBackground != null ? customBackground : Theme.c(Theme.Key.PONDER_BACKGROUND_TRANSPARENT))
.gradientBorder(gradientColor1, gradientColor2)
.at(x, y, z)
.withBounds(width, height)
.render(ms);
super.renderButton(ms, mouseX, mouseY, partialTicks);
wasHovered = isHovered;
}
@Override
public boolean isMouseOver(double mX, double mY) {
if (!active || !visible)
return false;
float padX = 2 + paddingX;
float padY = 2 + paddingY;
return x - padX <= mX && y - padY <= mY && mX < x + padX + width && mY < y + padY + height;
}
@Override
protected boolean clicked(double pMouseX, double pMouseY) {
if (!active || !visible)
return false;
return isMouseOver(pMouseX, pMouseY);
}
public BoxElement getBox() {
return box;
}
public void updateColorsFromState() {
colorTarget1 = getColorForState(true);
colorTarget2 = getColorForState(false);
}
public void animateGradientFromState() {
startGradientAnimation(
getColorForState(true),
getColorForState(false),
true
);
}
private void startGradientAnimation(Color c1, Color c2, boolean positive, double expSpeed) {
if (!animateColors)
return;
colorAnimation.startWithValue(positive ? 1 : -1);
colorAnimation.chase(0, expSpeed, LerpedFloat.Chaser.EXP);
colorAnimation.tickChaser();
previousColor1 = gradientColor1;
previousColor2 = gradientColor2;
colorTarget1 = c1;
colorTarget2 = c2;
}
private void startGradientAnimation(Color c1, Color c2, boolean positive) {
startGradientAnimation(c1, c2, positive, 0.6);
}
private Color getColorForState(boolean first) {
if (!active)
return Theme.p(getDisabledTheme()).get(first);
if (isHovered) {
if (first)
return customBorderTop != null ? customBorderTop.darker() : Theme.c(getHoverTheme(), true);
else
return customBorderBot != null ? customBorderBot.darker() : Theme.c(getHoverTheme(), false);
}
if (first)
return customBorderTop != null ? customBorderTop : Theme.c(getIdleTheme(), true);
else
return customBorderBot != null ? customBorderBot : Theme.c(getIdleTheme(), false);
}
public Key getDisabledTheme() {
return Theme.Key.BUTTON_DISABLE;
}
public Key getIdleTheme() {
return Theme.Key.BUTTON_IDLE;
}
public Key getHoverTheme() {
return Theme.Key.BUTTON_HOVER;
}
public Key getClickTheme() {
return Theme.Key.BUTTON_CLICK;
}
}

View File

@@ -0,0 +1,156 @@
package nl.requios.effortlessbuilding.create.foundation.gui.widget;
import com.mojang.blaze3d.vertex.PoseStack;
import nl.requios.effortlessbuilding.create.foundation.gui.element.RenderElement;
import nl.requios.effortlessbuilding.create.foundation.gui.element.ScreenElement;
import nl.requios.effortlessbuilding.create.foundation.utility.animation.LerpedFloat;
import javax.annotation.Nonnull;
import java.util.function.Consumer;
import java.util.function.UnaryOperator;
public class ElementWidget extends AbstractSimiWidget {
protected RenderElement element = RenderElement.EMPTY;
protected boolean usesFade = false;
protected int fadeModX;
protected int fadeModY;
protected LerpedFloat fade = LerpedFloat.linear().startWithValue(1);
protected boolean rescaleElement = false;
protected float rescaleSizeX;
protected float rescaleSizeY;
protected float paddingX = 0;
protected float paddingY = 0;
public ElementWidget(int x, int y) {
super(x, y);
}
public ElementWidget(int x, int y, int width, int height) {
super(x, y, width, height);
}
public <T extends ElementWidget> T showingElement(RenderElement element) {
this.element = element;
//noinspection unchecked
return (T) this;
}
public <T extends ElementWidget> T showing(ScreenElement renderable) {
return this.showingElement(RenderElement.of(renderable));
}
public <T extends ElementWidget> T modifyElement(Consumer<RenderElement> consumer) {
if (element != null)
consumer.accept(element);
//noinspection unchecked
return (T) this;
}
public <T extends ElementWidget> T mapElement(UnaryOperator<RenderElement> function) {
if (element != null)
element = function.apply(element);
//noinspection unchecked
return (T) this;
}
public <T extends ElementWidget> T withPadding(float paddingX, float paddingY) {
this.paddingX = paddingX;
this.paddingY = paddingY;
//noinspection unchecked
return (T) this;
}
public <T extends ElementWidget> T enableFade(int fadeModifierX, int fadeModifierY) {
this.fade.startWithValue(0);
this.usesFade = true;
this.fadeModX = fadeModifierX;
this.fadeModY = fadeModifierY;
//noinspection unchecked
return (T) this;
}
public <T extends ElementWidget> T disableFade() {
this.fade.startWithValue(1);
this.usesFade = false;
//noinspection unchecked
return (T) this;
}
public LerpedFloat fade() {
return fade;
}
public <T extends ElementWidget> T fade(float target) {
fade.chase(target, 0.1, LerpedFloat.Chaser.EXP);
//noinspection unchecked
return (T) this;
}
/**
* Rescaling and its effects aren't properly tested with most elements.
* Thought it should work fine when using a TextStencilElement.
* Check BaseConfigScreen's title for such an example.
*/
@Deprecated
public <T extends ElementWidget> T rescaleElement(float rescaleSizeX, float rescaleSizeY) {
this.rescaleElement = true;
this.rescaleSizeX = rescaleSizeX;
this.rescaleSizeY = rescaleSizeY;
//noinspection unchecked
return (T) this;
}
public <T extends ElementWidget> T disableRescale() {
this.rescaleElement = false;
//noinspection unchecked
return (T) this;
}
@Override
public void tick() {
super.tick();
fade.tickChaser();
}
@Override
protected void beforeRender(@Nonnull PoseStack ms, int mouseX, int mouseY, float partialTicks) {
super.beforeRender(ms, mouseX, mouseY, partialTicks);
isHovered = isMouseOver(mouseX, mouseY);
float fadeValue = fade.getValue(partialTicks);
element.withAlpha(fadeValue);
if (fadeValue < 1) {
ms.translate((1 - fadeValue) * fadeModX, (1 - fadeValue) * fadeModY, 0);
}
}
@Override
public void renderButton(@Nonnull PoseStack ms, int mouseX, int mouseY, float partialTicks) {
ms.pushPose();
ms.translate(x + paddingX, y + paddingY, z);
float innerWidth = width - 2 * paddingX;
float innerHeight = height - 2 * paddingY;
float eX = element.getX(), eY = element.getY();
if (rescaleElement) {
float xScale = innerWidth / rescaleSizeX;
float yScale = innerHeight / rescaleSizeY;
ms.scale(xScale, yScale, 1);
element.at(eX / xScale, eY / yScale);
innerWidth /= xScale;
innerHeight /= yScale;
}
element.withBounds((int) innerWidth, (int) innerHeight).render(ms);
ms.popPose();
if (rescaleElement) {
element.at(eX, eY);
}
}
public RenderElement getRenderElement() {
return element;
}
}

View File

@@ -0,0 +1,51 @@
package nl.requios.effortlessbuilding.create.foundation.gui.widget;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import nl.requios.effortlessbuilding.create.foundation.gui.AllGuiTextures;
import nl.requios.effortlessbuilding.create.foundation.gui.element.ScreenElement;
import net.minecraft.network.chat.Component;
import javax.annotation.Nonnull;
public class IconButton extends AbstractSimiWidget {
protected ScreenElement icon;
public IconButton(int x, int y, ScreenElement icon) {
this(x, y, 18, 18, icon);
}
public IconButton(int x, int y, int w, int h, ScreenElement icon) {
super(x, y, w, h);
this.icon = icon;
}
@Override
public void renderButton(@Nonnull PoseStack matrixStack, int mouseX, int mouseY, float partialTicks) {
if (visible) {
isHovered = mouseX >= x && mouseY >= y && mouseX < x + width && mouseY < y + height;
AllGuiTextures button = !active ? AllGuiTextures.BUTTON_DOWN
: isHoveredOrFocused() ? AllGuiTextures.BUTTON_HOVER : AllGuiTextures.BUTTON;
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
drawBg(matrixStack, button);
icon.render(matrixStack, x + 1, y + 1);
}
}
protected void drawBg(PoseStack matrixStack, AllGuiTextures button) {
AllGuiTextures.BUTTON.bind();
blit(matrixStack, x, y, button.startX, button.startY, button.width, button.height);
}
public void setToolTip(Component text) {
toolTip.clear();
toolTip.add(text);
}
public void setIcon(ScreenElement icon) {
this.icon = icon;
}
}

View File

@@ -0,0 +1,41 @@
package nl.requios.effortlessbuilding.create.foundation.gui.widget;
import com.google.common.collect.ImmutableList;
import com.mojang.blaze3d.vertex.PoseStack;
import nl.requios.effortlessbuilding.create.foundation.gui.AllGuiTextures;
import net.minecraft.network.chat.Component;
import javax.annotation.Nonnull;
public class Indicator extends AbstractSimiWidget {
public State state;
public Indicator(int x, int y, Component tooltip) {
super(x, y, AllGuiTextures.INDICATOR.width, AllGuiTextures.INDICATOR.height);
this.toolTip = ImmutableList.of(tooltip);
this.state = State.OFF;
}
@Override
public void render(@Nonnull PoseStack matrixStack, int mouseX, int mouseY, float partialTicks ) {
if (!visible)
return;
AllGuiTextures toDraw;
switch (state) {
case ON: toDraw = AllGuiTextures.INDICATOR_WHITE; break;
case OFF: toDraw = AllGuiTextures.INDICATOR; break;
case RED: toDraw = AllGuiTextures.INDICATOR_RED; break;
case YELLOW: toDraw = AllGuiTextures.INDICATOR_YELLOW; break;
case GREEN: toDraw = AllGuiTextures.INDICATOR_GREEN; break;
default: toDraw = AllGuiTextures.INDICATOR; break;
}
toDraw.render(matrixStack, x, y, this);
}
public enum State {
OFF, ON,
RED, YELLOW, GREEN;
}
}

View File

@@ -0,0 +1,88 @@
package nl.requios.effortlessbuilding.create.foundation.gui.widget;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import nl.requios.effortlessbuilding.create.foundation.utility.Components;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import javax.annotation.Nonnull;
public class Label extends AbstractSimiWidget {
public Component text;
public String suffix;
protected boolean hasShadow;
protected int color;
protected Font font;
public Label(int x, int y, Component text) {
super(x, y, Minecraft.getInstance().font.width(text), 10);
font = Minecraft.getInstance().font;
this.text = Components.literal("Label");
color = 0xFFFFFF;
hasShadow = false;
suffix = "";
}
public Label colored(int color) {
this.color = color;
return this;
}
public Label withShadow() {
this.hasShadow = true;
return this;
}
public Label withSuffix(String s) {
suffix = s;
return this;
}
public void setTextAndTrim(Component newText, boolean trimFront, int maxWidthPx) {
Font fontRenderer = Minecraft.getInstance().font;
if (fontRenderer.width(newText) <= maxWidthPx) {
text = newText;
return;
}
String trim = "...";
int trimWidth = fontRenderer.width(trim);
String raw = newText.getString();
StringBuilder builder = new StringBuilder(raw);
int startIndex = trimFront ? 0 : raw.length() - 1;
int endIndex = !trimFront ? 0 : raw.length() - 1;
int step = (int) Math.signum(endIndex - startIndex);
for (int i = startIndex; i != endIndex; i += step) {
String sub = builder.substring(trimFront ? i : startIndex, trimFront ? endIndex + 1 : i + 1);
if (fontRenderer.width(Components.literal(sub).setStyle(newText.getStyle())) + trimWidth <= maxWidthPx) {
text = Components.literal(trimFront ? trim + sub : sub + trim).setStyle(newText.getStyle());
return;
}
}
}
@Override
public void renderButton(@Nonnull PoseStack matrixStack, int mouseX, int mouseY, float partialTicks) {
if (text == null || text.getString().isEmpty())
return;
RenderSystem.setShaderColor(1, 1, 1, 1);
MutableComponent copy = text.plainCopy();
if (suffix != null && !suffix.isEmpty())
copy.append(suffix);
if (hasShadow)
font.drawShadow(matrixStack, copy, x, y, color);
else
font.draw(matrixStack, copy, x, y, color);
}
}

View File

@@ -0,0 +1,173 @@
package nl.requios.effortlessbuilding.create.foundation.gui.widget;
import nl.requios.effortlessbuilding.create.AllKeys;
//import nl.requios.effortlessbuilding.create.AllSoundEvents;
import nl.requios.effortlessbuilding.create.foundation.utility.Components;
import nl.requios.effortlessbuilding.create.foundation.utility.Lang;
import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
//import net.minecraft.client.resources.sounds.SimpleSoundInstance;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import java.util.function.Consumer;
import java.util.function.Function;
public class ScrollInput extends AbstractSimiWidget {
protected Consumer<Integer> onScroll;
protected int state;
protected Component title = Lang.translateDirect("gui.scrollInput.defaultTitle");
protected final Component scrollToModify = Lang.translateDirect("gui.scrollInput.scrollToModify");
protected final Component shiftScrollsFaster = Lang.translateDirect("gui.scrollInput.shiftScrollsFaster");
protected Label displayLabel;
protected boolean inverted;
protected Function<Integer, Component> formatter;
protected int min, max;
protected int shiftStep;
Function<StepContext, Integer> step;
public ScrollInput(int xIn, int yIn, int widthIn, int heightIn) {
super(xIn, yIn, widthIn, heightIn);
state = 0;
min = 0;
max = 1;
shiftStep = 5;
step = standardStep();
formatter = i -> Components.literal(String.valueOf(i));
}
public Function<StepContext, Integer> standardStep() {
return c -> c.shift ? shiftStep : 1;
}
public ScrollInput inverted() {
inverted = true;
return this;
}
public ScrollInput withRange(int min, int max) {
this.min = min;
this.max = max;
return this;
}
public ScrollInput calling(Consumer<Integer> onScroll) {
this.onScroll = onScroll;
return this;
}
public ScrollInput format(Function<Integer, Component> formatter) {
this.formatter = formatter;
return this;
}
public ScrollInput removeCallback() {
this.onScroll = null;
return this;
}
public ScrollInput titled(MutableComponent title) {
this.title = title;
updateTooltip();
return this;
}
public ScrollInput withStepFunction(Function<StepContext, Integer> step) {
this.step = step;
return this;
}
public ScrollInput writingTo(Label label) {
this.displayLabel = label;
if (label != null)
writeToLabel();
return this;
}
public int getState() {
return state;
}
public ScrollInput setState(int state) {
this.state = state;
clampState();
updateTooltip();
if (displayLabel != null)
writeToLabel();
return this;
}
public ScrollInput withShiftStep(int step) {
shiftStep = step;
return this;
}
@Override
public boolean mouseScrolled(double mouseX, double mouseY, double delta) {
if (inverted)
delta *= -1;
StepContext context = new StepContext();
context.control = AllKeys.ctrlDown();
context.shift = AllKeys.shiftDown();
context.currentValue = state;
context.forward = delta > 0;
int priorState = state;
boolean shifted = AllKeys.shiftDown();
int step = (int) Math.signum(delta) * this.step.apply(context);
state += step;
if (shifted)
state -= state % shiftStep;
clampState();
if (priorState != state) {
// Minecraft.getInstance().getSoundManager().play(SimpleSoundInstance.forUI(AllSoundEvents.SCROLL_VALUE.getMainEvent(), 1.5f + 0.1f * (state-min)/(max-min)));
onChanged();
}
return priorState != state;
}
protected void clampState() {
if (state >= max)
state = max - 1;
if (state < min)
state = min;
}
public void onChanged() {
if (displayLabel != null)
writeToLabel();
if (onScroll != null)
onScroll.accept(state);
updateTooltip();
}
protected void writeToLabel() {
displayLabel.text = formatter.apply(state);
}
protected void updateTooltip() {
toolTip.clear();
if (title == null)
return;
toolTip.add(title.plainCopy()
.withStyle(s -> s.withColor(HEADER_RGB)));
toolTip.add(scrollToModify.plainCopy()
.withStyle(ChatFormatting.ITALIC, ChatFormatting.DARK_GRAY));
toolTip.add(shiftScrollsFaster.plainCopy()
.withStyle(ChatFormatting.ITALIC, ChatFormatting.DARK_GRAY));
}
public static class StepContext {
public int currentValue;
public boolean forward;
public boolean shift;
public boolean control;
}
}

View File

@@ -0,0 +1,67 @@
package nl.requios.effortlessbuilding.create.foundation.gui.widget;
import nl.requios.effortlessbuilding.create.foundation.utility.Components;
import nl.requios.effortlessbuilding.create.foundation.utility.Lang;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import java.util.ArrayList;
import java.util.List;
public class SelectionScrollInput extends ScrollInput {
private final MutableComponent scrollToSelect = Lang.translateDirect("gui.scrollInput.scrollToSelect");
protected List<? extends Component> options;
public SelectionScrollInput(int xIn, int yIn, int widthIn, int heightIn) {
super(xIn, yIn, widthIn, heightIn);
options = new ArrayList<>();
inverted();
}
public ScrollInput forOptions(List<? extends Component> options) {
this.options = options;
this.max = options.size();
format(options::get);
updateTooltip();
return this;
}
@Override
protected void updateTooltip() {
toolTip.clear();
if (title == null)
return;
toolTip.add(title.plainCopy()
.withStyle(s -> s.withColor(HEADER_RGB)));
int min = Math.min(this.max - 16, state - 7);
int max = Math.max(this.min + 16, state + 8);
min = Math.max(min, this.min);
max = Math.min(max, this.max);
if (this.min + 1 == min)
min--;
if (min > this.min)
toolTip.add(Components.literal("> ...").withStyle(ChatFormatting.GRAY));
if (this.max - 1 == max)
max++;
for (int i = min; i < max; i++) {
if (i == state)
toolTip.add(Components.empty()
.append("-> ")
.append(options.get(i))
.withStyle(ChatFormatting.WHITE));
else
toolTip.add(Components.empty()
.append("> ")
.append(options.get(i))
.withStyle(ChatFormatting.GRAY));
}
if (max < this.max)
toolTip.add(Components.literal("> ...").withStyle(ChatFormatting.GRAY));
toolTip.add(scrollToSelect.plainCopy()
.withStyle(ChatFormatting.DARK_GRAY, ChatFormatting.ITALIC));
}
}

View File

@@ -0,0 +1,25 @@
package nl.requios.effortlessbuilding.create.foundation.gui.widget;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.network.chat.Component;
import java.util.List;
public class TooltipArea extends AbstractSimiWidget {
public TooltipArea(int x, int y, int width, int height) {
super(x, y, width, height);
}
@Override
public void renderButton(PoseStack ms, int mouseX, int mouseY, float partialTicks) {
if (visible)
isHovered = mouseX >= x && mouseY >= y && mouseX < x + width && mouseY < y + height;
}
public TooltipArea withTooltip(List<Component> tooltip) {
this.toolTip = tooltip;
return this;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -0,0 +1,12 @@
display_link.png, icons.png and widgets.png within this folder fall under the MIT license.
The MIT License Copyright (c) <year> <copyright holders> Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
following conditions: The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB