Fix some more text wrapping issues and catch exceptions whilst loading chapters

This commit is contained in:
Sollace 2022-09-02 12:53:14 +02:00
parent 5256f1f273
commit 37148fad51
5 changed files with 76 additions and 39 deletions

View file

@ -2,8 +2,7 @@ package com.minelittlepony.unicopia.container;
import java.util.*; import java.util.*;
import com.google.gson.JsonArray; import com.google.gson.*;
import com.google.gson.JsonObject;
import com.minelittlepony.common.client.gui.IViewRoot; import com.minelittlepony.common.client.gui.IViewRoot;
import com.minelittlepony.common.client.gui.dimension.Bounds; import com.minelittlepony.common.client.gui.dimension.Bounds;
import com.minelittlepony.unicopia.client.gui.DrawableUtil; import com.minelittlepony.unicopia.client.gui.DrawableUtil;
@ -25,8 +24,8 @@ public class DynamicContent implements Content {
private Bounds bounds = Bounds.empty(); private Bounds bounds = Bounds.empty();
public DynamicContent(JsonArray pages) { public DynamicContent(JsonArray json) {
pages.forEach(page -> this.pages.add(new Page(page.getAsJsonObject()))); json.forEach(element -> pages.add(new Page(element.getAsJsonObject())));
} }
@Override @Override
@ -36,8 +35,10 @@ public class DynamicContent implements Content {
getPage(pageIndex).ifPresent(page -> page.draw(matrices, mouseX, mouseY, container)); getPage(pageIndex).ifPresent(page -> page.draw(matrices, mouseX, mouseY, container));
matrices.push(); matrices.push();
matrices.translate(bounds.width / 2 + 20, 0, 0); getPage(pageIndex + 1).ifPresent(page -> {
getPage(pageIndex + 1).ifPresent(page -> page.draw(matrices, mouseX, mouseY, container)); page.bounds.left = bounds.left + bounds.width / 2 + 20;
page.draw(matrices, mouseX, mouseY, container);
});
matrices.pop(); matrices.pop();
} }
@ -45,7 +46,7 @@ public class DynamicContent implements Content {
public void copyStateFrom(Content old) { public void copyStateFrom(Content old) {
if (old instanceof DynamicContent o) { if (old instanceof DynamicContent o) {
offset = o.offset; offset = o.offset;
bounds = o.bounds; setBounds(o.bounds);
} }
} }
@ -56,10 +57,18 @@ public class DynamicContent implements Content {
return Optional.of(pages.get(index)); return Optional.of(pages.get(index));
} }
private void setBounds(Bounds bounds) {
this.bounds = bounds;
pages.forEach(page -> {
page.reset();
page.bounds.copy(bounds);
page.bounds.width /= 2;
});
}
@Override @Override
public void init(SpellbookScreen screen) { public void init(SpellbookScreen screen) {
bounds = screen.getFrameBounds(); setBounds(screen.getFrameBounds());
pages.forEach(Page::reset);
screen.addPageButtons(187, 30, 350, incr -> { screen.addPageButtons(187, 30, 350, incr -> {
offset = MathHelper.clamp(offset + incr, 0, (int)Math.ceil(pages.size() / 2F) - 1); offset = MathHelper.clamp(offset + incr, 0, (int)Math.ceil(pages.size() / 2F) - 1);
}); });
@ -73,6 +82,8 @@ public class DynamicContent implements Content {
private boolean compiled; private boolean compiled;
private Bounds bounds = Bounds.empty();
public Page(JsonObject json) { public Page(JsonObject json) {
title = Text.Serializer.fromJson(json.get("title")); title = Text.Serializer.fromJson(json.get("title"));
level = JsonHelper.getInt(json, "level", 0); level = JsonHelper.getInt(json, "level", 0);
@ -82,7 +93,7 @@ public class DynamicContent implements Content {
} }
protected int getLineLimitAt(int yPosition) { protected int getLineLimitAt(int yPosition) {
return (bounds.width / 2 - 10) - elements.stream() return (bounds.width - 10) - elements.stream()
.filter(PageElement::isFloating) .filter(PageElement::isFloating)
.map(PageElement::bounds) .map(PageElement::bounds)
.filter(b -> b.contains(b.left + b.width / 2, yPosition)) .filter(b -> b.contains(b.left + b.width / 2, yPosition))
@ -113,6 +124,11 @@ public class DynamicContent implements Content {
@Override @Override
public void draw(MatrixStack matrices, int mouseX, int mouseY, IViewRoot container) { public void draw(MatrixStack matrices, int mouseX, int mouseY, IViewRoot container) {
if (elements.isEmpty()) {
return;
}
if (!compiled) { if (!compiled) {
compiled = true; compiled = true;
int relativeY = 0; int relativeY = 0;

View file

@ -54,7 +54,7 @@ interface PageElement extends Drawable {
); );
} }
if (el.has("recipe")) { if (el.has("recipe")) {
return new Recipe(page, new Identifier(JsonHelper.getString(el, "texture")), new Bounds(0, 0, 0, 30)); return new Recipe(page, new Identifier(JsonHelper.getString(el, "recipe")), new Bounds(0, 0, 0, 0));
} }
return new TextBlock(page, Text.Serializer.fromJson(element)); return new TextBlock(page, Text.Serializer.fromJson(element));
} }
@ -86,11 +86,10 @@ interface PageElement extends Drawable {
@Override @Override
public void compile(int y, IViewRoot container) { public void compile(int y, IViewRoot container) {
wrappedText.clear(); wrappedText.clear();
ParagraphWrappingVisitor visitor = new ParagraphWrappingVisitor(yPosition -> { ParagraphWrappingVisitor visitor = new ParagraphWrappingVisitor(
return page.getLineLimitAt(y + yPosition); yPosition -> page.getLineLimitAt(y + yPosition),
}, (line, yPosition) -> { (line, yPosition) -> wrappedText.add(new Line(line, page.getLeftMarginAt(y + yPosition)))
wrappedText.add(new Line(line, page.getLeftMarginAt(y + yPosition))); );
});
unwrappedText.visit(visitor, Style.EMPTY); unwrappedText.visit(visitor, Style.EMPTY);
visitor.forceAdvance(); visitor.forceAdvance();
bounds.height = MinecraftClient.getInstance().textRenderer.fontHeight * (wrappedText.size()); bounds.height = MinecraftClient.getInstance().textRenderer.fontHeight * (wrappedText.size());
@ -128,12 +127,18 @@ interface PageElement extends Drawable {
} }
@Override @Override
public void compile(int y, IViewRoot Container) { public void compile(int y, IViewRoot container) {
if (container instanceof SpellbookScreen book) {
bounds().left = book.getX();
bounds().top = book.getY();
}
MinecraftClient.getInstance().world.getRecipeManager().get(id).ifPresent(recipe -> { MinecraftClient.getInstance().world.getRecipeManager().get(id).ifPresent(recipe -> {
if (recipe instanceof SpellbookRecipe spellRecipe) { if (recipe instanceof SpellbookRecipe spellRecipe) {
IngredientTree tree = new IngredientTree(page.getBounds().left, y, page().getBounds().width / 2 - 20, 20); IngredientTree tree = new IngredientTree(
bounds().left + page().getBounds().left,
bounds().top + page().getBounds().top + y + 10, page().getBounds().width - 20, 20);
spellRecipe.buildCraftingTree(tree); spellRecipe.buildCraftingTree(tree);
bounds.height = tree.build(Container); bounds.height = tree.build(container) - 10;
} }
}); });
} }

View file

@ -40,7 +40,7 @@ class ParagraphWrappingVisitor implements StyledVisitor<Object> {
int newline = s.indexOf('\n'); int newline = s.indexOf('\n');
if (newline >= 0 && newline < trimmedLength) { if (newline >= 0 && newline < trimmedLength) {
trimmedLength = newline; trimmedLength = newline + 1;
} else { } else {
newline = -1; newline = -1;
} }
@ -49,17 +49,23 @@ class ParagraphWrappingVisitor implements StyledVisitor<Object> {
trimmedLength = s.length(); trimmedLength = s.length();
} }
String wrappedFragment = s.substring(0, trimmedLength); // avoid breaking in the middle of a word
int lastSpace = wrappedFragment.lastIndexOf(' '); if (trimmedLength < s.length() - 1 && trimmedLength > 0
trimmedLength = lastSpace > 0 ? Math.min(lastSpace, trimmedLength) : trimmedLength; && (!Character.isWhitespace(s.charAt(trimmedLength + 1)) || !Character.isWhitespace(s.charAt(trimmedLength - 1)))) {
String wrappedFragment = s.substring(0, trimmedLength);
int lastSpace = wrappedFragment.lastIndexOf(' ');
trimmedLength = lastSpace > 0 ? Math.min(lastSpace, trimmedLength) : trimmedLength;
}
Text fragment = Text.literal(s.substring(0, trimmedLength).trim()).setStyle(style); Text fragment = Text.literal(s.substring(0, trimmedLength).trim()).setStyle(style);
float grabbedWidth = handler.getWidth(fragment); float grabbedWidth = handler.getWidth(fragment);
// advance if appending the next segment would cause an overflow
if (currentLineCollectedLength + grabbedWidth > pageWidth) { if (currentLineCollectedLength + grabbedWidth > pageWidth) {
advance(); advance();
} }
// append the segment to the line that's being built
if (currentLineCollectedLength > 0) { if (currentLineCollectedLength > 0) {
currentLine.append(" "); currentLine.append(" ");
currentLineCollectedLength += handler.getWidth(" "); currentLineCollectedLength += handler.getWidth(" ");
@ -67,6 +73,10 @@ class ParagraphWrappingVisitor implements StyledVisitor<Object> {
currentLine.append(fragment); currentLine.append(fragment);
currentLineCollectedLength += grabbedWidth; currentLineCollectedLength += grabbedWidth;
if (newline >= 0) {
advance();
}
if (trimmedLength <= s.length()) { if (trimmedLength <= s.length()) {
s = s.substring(trimmedLength, s.length()); s = s.substring(trimmedLength, s.length());
} }

View file

@ -4,10 +4,13 @@ import java.util.*;
import java.util.concurrent.*; import java.util.concurrent.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.slf4j.Logger;
import com.google.gson.*; import com.google.gson.*;
import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.container.SpellbookChapterList.*; import com.minelittlepony.unicopia.container.SpellbookChapterList.*;
import com.minelittlepony.unicopia.util.Resources; import com.minelittlepony.unicopia.util.Resources;
import com.mojang.logging.LogUtils;
import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener; import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
@ -17,10 +20,10 @@ import net.minecraft.util.*;
import net.minecraft.util.profiler.Profiler; import net.minecraft.util.profiler.Profiler;
public class SpellbookChapterLoader extends JsonDataLoader implements IdentifiableResourceReloadListener { public class SpellbookChapterLoader extends JsonDataLoader implements IdentifiableResourceReloadListener {
private static final Logger LOGGER = LogUtils.getLogger();
public static boolean DEBUG = true;
private static final Identifier ID = Unicopia.id("spellbook/chapters"); private static final Identifier ID = Unicopia.id("spellbook/chapters");
private static final Executor EXECUTOR = CompletableFuture.delayedExecutor(5, TimeUnit.SECONDS);
public static boolean DEBUG = true;
public static final SpellbookChapterLoader INSTANCE = new SpellbookChapterLoader(); public static final SpellbookChapterLoader INSTANCE = new SpellbookChapterLoader();
@ -39,20 +42,22 @@ public class SpellbookChapterLoader extends JsonDataLoader implements Identifiab
return new HashSet<>(chapters.values()); return new HashSet<>(chapters.values());
} }
private static final Executor EXECUTOR = CompletableFuture.delayedExecutor(5, TimeUnit.SECONDS);
@Override @Override
protected void apply(Map<Identifier, JsonElement> data, ResourceManager manager, Profiler profiler) { protected void apply(Map<Identifier, JsonElement> data, ResourceManager manager, Profiler profiler) {
chapters = data.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> { try {
JsonObject json = JsonHelper.asObject(entry.getValue(), "root"); chapters = data.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> {
JsonObject json = JsonHelper.asObject(entry.getValue(), "root");
return new Chapter(entry.getKey(), return new Chapter(entry.getKey(),
TabSide.valueOf(JsonHelper.getString(json, "side")), TabSide.valueOf(JsonHelper.getString(json, "side")),
JsonHelper.getInt(json, "y_position"), JsonHelper.getInt(json, "y_position"),
JsonHelper.getInt(json, "color", 0), JsonHelper.getInt(json, "color", 0),
loadContent(JsonHelper.getObject(json, "content", new JsonObject())) loadContent(JsonHelper.getObject(json, "content", new JsonObject()))
); );
})); }));
} catch (IllegalStateException | JsonParseException e) {
LOGGER.error("Could not load spellbook chapters due to exception", e);
}
if (DEBUG) { if (DEBUG) {
CompletableFuture.runAsync(() -> { CompletableFuture.runAsync(() -> {

View file

@ -64,13 +64,14 @@ public class SpellbookProfilePageContent extends DrawableHelper implements Spell
float alphaF = (MathHelper.sin(delta / 9F) + 1) / 2F; float alphaF = (MathHelper.sin(delta / 9F) + 1) / 2F;
int alpha = (int)(alphaF * 0x10) & 0xFF; int alpha = (int)(alphaF * 0x10) & 0xFF;
int color = 0x10404000 | alpha; int color = 0x10404000 | alpha;
int xpColor = 0xAA0040FF | ((int)(xpPercentage * 0xFF) & 0xFF) << 16; int xpColor = 0xAA0040FF | ((int)((0.3F + 0.7F * xpPercentage) * 0xFF) & 0xFF) << 16;
int manaColor = 0xFF00F040 | (int)((0.3F + 0.7F * alphaF) * 0x40) << 16;
DrawableUtil.drawArc(matrices, 0, radius + 24, 0, DrawableUtil.TAU, color, false); DrawableUtil.drawArc(matrices, 0, radius + 24, 0, DrawableUtil.TAU, color, false);
DrawableUtil.drawArc(matrices, radius / 3, radius + 6, 0, DrawableUtil.TAU, color, false); DrawableUtil.drawArc(matrices, radius / 3, radius + 6, 0, DrawableUtil.TAU, color, false);
DrawableUtil.drawArc(matrices, radius / 3, radius + 6, 0, xpPercentage * DrawableUtil.TAU, xpColor, false); DrawableUtil.drawArc(matrices, radius / 3, radius + 6, 0, xpPercentage * DrawableUtil.TAU, xpColor, false);
radius += 8; radius += 8;
DrawableUtil.drawArc(matrices, radius, radius + 6 + growth, 0, manaPercentage * DrawableUtil.TAU, 0xFF40F040, false); DrawableUtil.drawArc(matrices, radius, radius + 6 + growth, 0, manaPercentage * DrawableUtil.TAU, manaColor, false);
String manaString = (int)reserves.getMana().get() + "/" + (int)reserves.getMana().getMax(); String manaString = (int)reserves.getMana().get() + "/" + (int)reserves.getMana().getMax();