Skip to content

Commit

Permalink
Embeds in Better Questing Unofficial Descriptions
Browse files Browse the repository at this point in the history
Colors, pulsing speed and general aesthetics may change. Syntax is less likely to change, but it may change if more embeds/custom formatting elements are added.
  • Loading branch information
IntegerLimit committed Mar 2, 2025
1 parent a4e3d14 commit 1afd0cb
Show file tree
Hide file tree
Showing 14 changed files with 776 additions and 55 deletions.
4 changes: 2 additions & 2 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -284,8 +284,8 @@ enable_effortless_building = false
# If this is set to false, Effortless + FTB Utils Compat will not be applied, and the mixin will not apply.
enable_ftb_utils = false

# Whether to enable BQu in runtime. Enables Labs Tier Helper.
enable_bqu = false
# Whether to enable BQu in runtime. Enables Labs Tier Helper and custom Description Handling.
enable_bqu = true

# Whether to enable Controlling in runtime. Enables Controlling compat.
enable_controlling = false
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.nomiceu.nomilabs.integration.betterquesting;

/**
* Part of the implementation for custom Description Embeds in BQu.
* <br>
* See the <a href="https://github.com/Nomi-CEu/Nomi-Labs/wiki/Custom-Better-Questing-Unofficial-Embeds">Nomi Labs
* Wiki</a> for more information.
*/
public interface AccessibleGuiRectText {

void labs$setHeight(int h);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
package com.nomiceu.nomilabs.integration.betterquesting;

import static com.nomiceu.nomilabs.integration.betterquesting.PanelDescription.fontRenderer;
import static com.nomiceu.nomilabs.integration.betterquesting.RenderDescriptionPart.*;

import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import net.minecraft.client.gui.FontRenderer;

import com.google.common.collect.ImmutableList;

import it.unimi.dsi.fastutil.objects.ObjectArrayList;

/**
* Part of the implementation for custom Description Embeds in BQu.
* <br>
* See the <a href="https://github.com/Nomi-CEu/Nomi-Labs/wiki/Custom-Better-Questing-Unofficial-Embeds">Nomi Labs
* Wiki</a> for more information.
*/
public abstract class DescriptionPart {

public static final Pattern SPECIAL_MATCH = Pattern
.compile("<\\{(link|copy)}>(.+?)(?:<\\|>(.+?))?(?:<\\|>(disabled))?<\\{\\1}>");

public abstract DescriptionPart allAfter(int startIndex);

public abstract RenderDescriptionPart toRender(int x, int y);

public abstract RenderDescriptionPart toRender(int x, int y, int end);

public abstract String toRenderText();

public static boolean textContainsCustom(String text) {
return SPECIAL_MATCH.matcher(text).find();
}

public static List<DescriptionPart> splitString(String text) {
List<DescriptionPart> parts = new ObjectArrayList<>();
Matcher matcher = SPECIAL_MATCH.matcher(text);

int lastHandled = 0;
String currFormat = "";

while (matcher.find()) {
String normalText = currFormat + text.substring(lastHandled, matcher.start());
parts.add(new DescriptionText(normalText));

// The Pattern matches only link or copy, so we can directly assume the other is true if one is not.
parts.add(new DescriptionInteractive(matcher.group(1), matcher.group(2), matcher.group(3),
matcher.group(4) != null));

// Save New Values
lastHandled = matcher.end();
currFormat = FontRenderer.getFormatFromString(normalText);
}

String remainingText = text.substring(lastHandled);
if (!remainingText.isEmpty())
parts.add(new DescriptionText(currFormat + remainingText));

return ImmutableList.copyOf(parts);
}

public static class DescriptionText extends DescriptionPart {

protected final String text;

public DescriptionText(String text) {
this.text = text;
}

@Override
public DescriptionPart allAfter(int startIndex) {
String sub = text.substring(startIndex);
sub = FontRenderer.getFormatFromString(text.substring(0, startIndex)) + sub;
return new DescriptionText(sub);
}

@Override
public RenderDescriptionPart toRender(int x, int y) {
return toRender(x, y, text.length());
}

@Override
public RenderDescriptionPart toRender(int x, int y, int end) {
String sub = text.substring(0, end);
return new RenderDescriptionText(sub, fontRenderer().getStringWidth(sub), x, y);
}

@Override
public String toRenderText() {
return text;
}
}

public static class DescriptionInteractive extends DescriptionPart {

protected final String type;
protected final String display;
protected final String content;
protected final InteractiveState state;

public DescriptionInteractive(String type, String content, String display, boolean disabled) {
this.type = type;
this.content = content;

this.state = CustomType.valueOf(type.toUpperCase()).toState.toState(content, disabled);

if (display == null)
this.display = state.format() + content;
else
this.display = state.format() + display;
}

private DescriptionInteractive(String type, String content, String display, InteractiveState state) {
this.type = type;
this.content = content;
this.display = state.format() + display;
this.state = state;
}

public InteractiveState getState() {
return state;
}

@Override
public DescriptionPart allAfter(int startIndex) {
return new DescriptionInteractive(type, content, display.substring(startIndex), state);
}

@Override
public RenderDescriptionPart toRender(int x, int y) {
return toRender(x, y, display.length());
}

@Override
public RenderDescriptionPart toRender(int x, int y, int end) {
String sub = display.substring(0, end);
return new RenderDescriptionInteractive(sub, fontRenderer().getStringWidth(sub), x, y, state);
}

@Override
public String toRenderText() {
return display;
}
}

public enum CustomType {

LINK(InteractiveState.InteractiveLink::new),
COPY(InteractiveState.InteractiveCopy::new);

public final TypeToState toState;

CustomType(TypeToState toState) {
this.toState = toState;
}
}

@FunctionalInterface
public interface TypeToState {

InteractiveState toState(String toCopy, boolean disabled);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
package com.nomiceu.nomilabs.integration.betterquesting;

import java.util.List;

import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.util.text.TextFormatting;

import com.google.common.collect.ImmutableList;
import com.nomiceu.nomilabs.mixinhelper.GuiCustomConfirmOpenLink;
import com.nomiceu.nomilabs.util.LabsTranslate;

import betterquesting.api2.client.gui.controls.io.ValueFuncIO;
import betterquesting.api2.client.gui.resources.colors.GuiColorPulse;
import betterquesting.api2.client.gui.resources.colors.GuiColorStatic;
import betterquesting.api2.client.gui.resources.colors.GuiColorTransition;
import betterquesting.api2.client.gui.resources.colors.IGuiColor;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;

/**
* Part of the implementation for custom Description Embeds in BQu.
* <br>
* See the <a href="https://github.com/Nomi-CEu/Nomi-Labs/wiki/Custom-Better-Questing-Unofficial-Embeds">Nomi Labs
* Wiki</a> for more information.
*/
public abstract class InteractiveState {

protected final List<RenderDescriptionPart.RenderDescriptionInteractive> parts;

public InteractiveState() {
parts = new ObjectArrayList<>();
}

public void addPart(RenderDescriptionPart.RenderDescriptionInteractive part) {
parts.add(part);
}

public void clearParts() {
parts.clear();
}

public abstract String format();

public abstract GuiColorTransition color();

public abstract List<String> tooltip(boolean mouseOver);

public abstract void handleMouseOver(boolean mouseOver);

public abstract void handleMouseClick(GuiScreen parent);

public static class InteractiveCopy extends InteractiveState {

public static final GuiColorPulse DEFAULT_COLOR = new GuiColorPulse(0x3CB371, 0x98FB98, 2.0F, 1.0F);
public static final GuiColorStatic OVER_COLOR = new GuiColorStatic(0xff55ff);
public static final float TRANSITION_TIME = 250.0F;
public static final int DISPLAY_COPIED_TIME = 1000;

protected final GuiColorTransition color;

protected final boolean disabled;
protected final String toCopy;

protected long lastMouseTransitionUpdate;
protected float mouseTransition = 0.0F;
protected boolean mouseOver = false;

protected long lastCopy = 0;

public InteractiveCopy(String toCopy, boolean disabled) {
this(toCopy, disabled, DEFAULT_COLOR, OVER_COLOR);
}

protected InteractiveCopy(String toCopy, boolean disabled, IGuiColor defaultColor, IGuiColor overColor) {
super();
this.disabled = disabled;
this.toCopy = toCopy;

this.lastMouseTransitionUpdate = System.currentTimeMillis();

this.color = new GuiColorTransition(overColor, defaultColor);
this.color.setupBlending(true, 1.0F).setBlendDriver(new ValueFuncIO<>(() -> mouseTransition));
}

@Override
public void handleMouseOver(boolean mouseOver) {
if (disabled) return;

this.mouseOver = mouseOver;

long mills = System.currentTimeMillis();
if (mouseOver && mouseTransition < 1.0F) {
mouseTransition += (mills - lastMouseTransitionUpdate) / TRANSITION_TIME;
mouseTransition = Math.min(mouseTransition, 1.0F);
} else if (mouseTransition > 0.0F) {
mouseTransition -= (mills - lastMouseTransitionUpdate) / TRANSITION_TIME;
mouseTransition = Math.max(mouseTransition, 0.0F);
}
lastMouseTransitionUpdate = mills;
}

@Override
public void handleMouseClick(GuiScreen parent) {
if (disabled) return;

GuiScreen.setClipboardString(toCopy);
lastCopy = System.currentTimeMillis();
}

@Override
public String format() {
return TextFormatting.ITALIC.toString();
}

@Override
public GuiColorTransition color() {
return color;
}

@Override
public List<String> tooltip(boolean mouseOver) {
if (disabled) return null;

if (System.currentTimeMillis() - lastCopy < DISPLAY_COPIED_TIME)
return ImmutableList.of(LabsTranslate.translate("nomilabs.gui.bqu.custom.copied.tooltip"));

if (mouseOver)
return ImmutableList.of(LabsTranslate.translate("nomilabs.gui.bqu.custom.copy.tooltip"));

return null;
}
}

public static class InteractiveLink extends InteractiveCopy {

public static final GuiColorPulse DEFAULT_COLOR = new GuiColorPulse(0x87ceeb, 0x6495ed, 2.0F, 1.0F);

public InteractiveLink(String toCopy, boolean disabled) {
super(toCopy, disabled, DEFAULT_COLOR, OVER_COLOR);
}

@Override
public String format() {
return TextFormatting.UNDERLINE.toString();
}

@Override
public void handleMouseClick(GuiScreen parent) {
if (disabled) return;

Minecraft.getMinecraft().displayGuiScreen(new GuiCustomConfirmOpenLink(parent, toCopy, null));
}

@Override
public List<String> tooltip(boolean mouseOver) {
if (disabled) return null;

if (mouseOver)
return ImmutableList.of(LabsTranslate.translate("nomilabs.gui.bqu.custom.link.tooltip"));

return null;
}
}
}
Loading

0 comments on commit 1afd0cb

Please sign in to comment.