More rewrites and allow for adding recipes to book pages

This commit is contained in:
Sollace 2022-09-01 22:28:55 +02:00
parent 0bc9f447f6
commit 50b709fa3c
9 changed files with 253 additions and 179 deletions

View file

@ -11,6 +11,7 @@ import net.minecraft.client.render.VertexFormat;
import net.minecraft.client.render.VertexFormats;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.item.ItemStack;
import net.minecraft.text.Text;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Matrix4f;
@ -20,6 +21,14 @@ public interface DrawableUtil {
double NUM_RINGS = 300;
double INCREMENT = TAU / NUM_RINGS;
static void drawScaledText(MatrixStack matrices, Text text, int x, int y, float size, int color) {
matrices.push();
matrices.translate(x, y, 0);
matrices.scale(size, size, 1);
MinecraftClient.getInstance().textRenderer.draw(matrices, text, 0, 0, color);
matrices.pop();
}
static void renderItemIcon(ItemStack stack, double x, double y, float scale) {
MatrixStack modelStack = RenderSystem.getModelViewStack();
modelStack.push();

View file

@ -4,41 +4,40 @@ import java.util.*;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.minelittlepony.common.client.gui.IViewRoot;
import com.minelittlepony.common.client.gui.dimension.Bounds;
import com.minelittlepony.unicopia.client.gui.DrawableUtil;
import com.minelittlepony.unicopia.container.SpellbookChapterList.Content;
import com.minelittlepony.unicopia.container.SpellbookChapterList.Drawable;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.DrawableHelper;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.Style;
import net.minecraft.text.Text;
import net.minecraft.util.*;
import net.minecraft.util.math.MathHelper;
public class DynamicContent implements Content {
private static final Text UNKNOWN = Text.of("???");
private static final Text UNKNOWN_LEVEL = Text.literal("Level: ???").formatted(Formatting.DARK_GREEN);
private int offset = 0;
private final List<Page> pages = new ArrayList<>();
Bounds bounds = Bounds.empty();
private Bounds bounds = Bounds.empty();
public DynamicContent(JsonArray pages) {
pages.forEach(page -> this.pages.add(new Page(page.getAsJsonObject())));
}
@Override
public void draw(MatrixStack matrices, int mouseX, int mouseY) {
public void draw(MatrixStack matrices, int mouseX, int mouseY, IViewRoot container) {
int pageIndex = offset * 2;
getPage(pageIndex).ifPresent(page -> page.draw(matrices, mouseX, mouseY));
getPage(pageIndex).ifPresent(page -> page.draw(matrices, mouseX, mouseY, container));
matrices.push();
matrices.translate(bounds.width / 2 + 20, 0, 0);
getPage(pageIndex + 1).ifPresent(page -> page.draw(matrices, mouseX, mouseY));
getPage(pageIndex + 1).ifPresent(page -> page.draw(matrices, mouseX, mouseY, container));
matrices.pop();
}
@ -67,9 +66,6 @@ public class DynamicContent implements Content {
}
class Page implements Drawable {
private final List<Page.Paragraph> paragraphs = new ArrayList<>();
private final List<Page.Image> images = new ArrayList<>();
private final List<PageElement> elements = new ArrayList<>();
private final Text title;
@ -80,98 +76,11 @@ public class DynamicContent implements Content {
public Page(JsonObject json) {
title = Text.Serializer.fromJson(json.get("title"));
level = JsonHelper.getInt(json, "level", 0);
int[] lineNumber = new int[1];
JsonHelper.getArray(json, "elements", new JsonArray()).forEach(element -> {
if (element.isJsonPrimitive()) {
paragraphs.add(new Paragraph(lineNumber[0], Text.Serializer.fromJson(element)));
} else {
JsonObject image = JsonHelper.asObject(element, "element");
if (image.has("texture")) {
images.add(new Image(
new Identifier(JsonHelper.getString(image, "texture")),
new Bounds(
JsonHelper.getInt(image, "y", 0),
JsonHelper.getInt(image, "x", 0),
JsonHelper.getInt(image, "width", 0),
JsonHelper.getInt(image, "height", 0)
),
Flow.valueOf(JsonHelper.getString(image, "flow", "RIGHT"))
));
} else {
paragraphs.add(new Paragraph(lineNumber[0], Text.Serializer.fromJson(element)));
}
}
lineNumber[0]++;
elements.add(PageElement.fromJson(this, element));
});
}
public void reset() {
compiled = false;
}
@Override
public void draw(MatrixStack matrices, int mouseX, int mouseY) {
if (!compiled) {
compiled = true;
int relativeY = 0;
for (PageElement element : elements.stream().filter(PageElement::isInline).toList()) {
element.compile(relativeY);
relativeY += element.bounds().height;
}
}
TextRenderer font = MinecraftClient.getInstance().textRenderer;
boolean needsMoreXp = level < 0 || Pony.of(MinecraftClient.getInstance().player).getLevel().get() < level;
matrices.push();
matrices.translate(bounds.left, bounds.top - 10, mouseY);
matrices.scale(1.3F, 1.3F, 1);
font.draw(matrices, needsMoreXp ? Text.of("???") : title, 0, 0, mouseY);
matrices.pop();
matrices.push();
matrices.translate(bounds.left, bounds.top - 10, mouseY);
matrices.translate(0, 12, 0);
matrices.scale(0.8F, 0.8F, 1);
font.draw(matrices, Text.literal(level < 0 ? "Level: ???" : "Level: " + (level + 1)).formatted(Formatting.DARK_GREEN), 0, 0, mouseY);
matrices.pop();
matrices.push();
matrices.translate(bounds.left, bounds.top + 16, 0);
elements.stream().filter(PageElement::isFloating).forEach(element -> {
Bounds bounds = element.bounds();
matrices.push();
matrices.translate(bounds.left, bounds.top, 0);
element.draw(matrices, mouseX, mouseY);
matrices.pop();
});
matrices.push();
elements.stream().filter(PageElement::isInline).forEach(element -> {
element.draw(matrices, mouseX, mouseY);
matrices.translate(0, element.bounds().height, 0);
});
matrices.pop();
images.forEach(image -> image.draw(matrices, mouseX, mouseY));
matrices.pop();
}
public record Paragraph(int y, Text text) {}
public record Image(
Identifier texture,
Bounds bounds,
Flow flow) implements PageElement {
@Override
public void draw(MatrixStack matrices, int mouseX, int mouseY) {
RenderSystem.setShaderTexture(0, texture);
DrawableHelper.drawTexture(matrices, bounds().left, bounds().top, 0, 0, 0, bounds().width, bounds().height, bounds().width, bounds().height);
RenderSystem.setShaderTexture(0, SpellbookScreen.TEXTURE);
}
}
protected int getLineLimitAt(int yPosition) {
return (bounds.width / 2 - 10) - elements.stream()
.filter(PageElement::isFloating)
@ -183,78 +92,59 @@ public class DynamicContent implements Content {
protected int getLeftMarginAt(int yPosition) {
return elements.stream()
.filter(p -> p.flow() == Flow.LEFT)
.filter(p -> p.flow() == PageElement.Flow.LEFT)
.map(PageElement::bounds)
.filter(b -> b.contains(b.left + b.width / 2, yPosition))
.mapToInt(b -> b.width)
.sum();
}
public class TextBlock implements PageElement {
private final Text unwrappedText;
private final List<Line> wrappedText = new ArrayList<>();
private final Bounds bounds = Bounds.empty();
protected int getLevel() {
return level;
}
public TextBlock(Text text) {
unwrappedText = text;
protected Bounds getBounds() {
return bounds;
}
public void reset() {
compiled = false;
}
@Override
public void draw(MatrixStack matrices, int mouseX, int mouseY, IViewRoot container) {
if (!compiled) {
compiled = true;
int relativeY = 0;
for (PageElement element : elements.stream().filter(PageElement::isInline).toList()) {
element.compile(relativeY, container);
relativeY += element.bounds().height;
}
}
@Override
public void compile(int y) {
wrappedText.clear();
ParagraphWrappingVisitor visitor = new ParagraphWrappingVisitor(yPosition -> {
return getLineLimitAt(y + yPosition);
}, (line, yPosition) -> {
wrappedText.add(new Line(line, getLeftMarginAt(y + yPosition)));
});
unwrappedText.visit(visitor, Style.EMPTY);
visitor.forceAdvance();
bounds.height = MinecraftClient.getInstance().textRenderer.fontHeight * (wrappedText.size() + 1);
}
boolean needsMoreXp = level < 0 || Pony.of(MinecraftClient.getInstance().player).getLevel().get() < level;
@Override
public void draw(MatrixStack matrices, int mouseX, int mouseY) {
TextRenderer font = MinecraftClient.getInstance().textRenderer;
boolean needsMoreXp = level < 0 || Pony.of(MinecraftClient.getInstance().player).getLevel().get() < level;
DrawableUtil.drawScaledText(matrices, needsMoreXp ? UNKNOWN : title, bounds.left, bounds.top - 10, 1.3F, mouseY);
DrawableUtil.drawScaledText(matrices, level < 0 ? UNKNOWN_LEVEL : Text.literal("Level: " + (level + 1)).formatted(Formatting.DARK_GREEN), bounds.left, bounds.top - 10 + 12, 0.8F, mouseY);
matrices.push();
matrices.translate(bounds.left, bounds.top + 16, 0);
elements.stream().filter(PageElement::isFloating).forEach(element -> {
Bounds bounds = element.bounds();
matrices.push();
wrappedText.forEach(line -> {
font.draw(matrices, needsMoreXp ? line.text().copy().formatted(Formatting.OBFUSCATED) : line.text(), line.x(), 0, 0);
matrices.translate(0, font.fontHeight, 0);
});
matrices.translate(bounds.left, bounds.top, 0);
element.draw(matrices, mouseX, mouseY, container);
matrices.pop();
}
});
@Override
public Bounds bounds() {
return bounds;
}
matrices.push();
elements.stream().filter(PageElement::isInline).forEach(element -> {
element.draw(matrices, mouseX, mouseY, container);
matrices.translate(0, element.bounds().height, 0);
});
matrices.pop();
@Override
public Flow flow() {
return Flow.NONE;
}
private record Line(Text text, int x) { }
}
private interface PageElement extends Drawable {
Bounds bounds();
Flow flow();
default boolean isInline() {
return flow() == Flow.NONE;
}
default boolean isFloating() {
return !isInline();
}
default void compile(int y) {}
}
private enum Flow {
NONE, LEFT, RIGHT
matrices.pop();
}
}
}

View file

@ -4,8 +4,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import com.minelittlepony.common.client.gui.ScrollContainer;
import com.minelittlepony.common.client.gui.Tooltip;
import com.minelittlepony.common.client.gui.*;
import com.minelittlepony.common.client.gui.element.Button;
import com.minelittlepony.unicopia.ability.magic.spell.crafting.SpellbookRecipe;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
@ -54,7 +53,7 @@ class IngredientTree implements SpellbookRecipe.CraftingTreeBuilder {
}
}
public int build(ScrollContainer container) {
public int build(IViewRoot container) {
if (entries.isEmpty()) {
return 0;

View file

@ -0,0 +1,150 @@
package com.minelittlepony.unicopia.container;
import java.util.ArrayList;
import java.util.List;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.minelittlepony.common.client.gui.IViewRoot;
import com.minelittlepony.common.client.gui.dimension.Bounds;
import com.minelittlepony.unicopia.ability.magic.spell.crafting.SpellbookRecipe;
import com.minelittlepony.unicopia.container.SpellbookChapterList.Drawable;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.DrawableHelper;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.Style;
import net.minecraft.text.Text;
import net.minecraft.util.*;
interface PageElement extends Drawable {
Bounds bounds();
Flow flow();
default boolean isInline() {
return flow() == Flow.NONE;
}
default boolean isFloating() {
return !isInline();
}
default void compile(int y, IViewRoot Container) {}
static PageElement fromJson(DynamicContent.Page page, JsonElement element) {
if (element.isJsonPrimitive()) {
return new TextBlock(page, Text.Serializer.fromJson(element));
}
JsonObject el = JsonHelper.asObject(element, "element");
if (el.has("texture")) {
return new Image(
new Identifier(JsonHelper.getString(el, "texture")),
new Bounds(
JsonHelper.getInt(el, "y", 0),
JsonHelper.getInt(el, "x", 0),
JsonHelper.getInt(el, "width", 0),
JsonHelper.getInt(el, "height", 0)
),
Flow.valueOf(JsonHelper.getString(el, "flow", "RIGHT"))
);
}
if (el.has("recipe")) {
return new Recipe(page, new Identifier(JsonHelper.getString(el, "texture")), new Bounds(0, 0, 0, 30));
}
return new TextBlock(page, Text.Serializer.fromJson(element));
}
record Image(
Identifier texture,
Bounds bounds,
Flow flow) implements PageElement {
@Override
public void draw(MatrixStack matrices, int mouseX, int mouseY, IViewRoot container) {
RenderSystem.setShaderTexture(0, texture);
DrawableHelper.drawTexture(matrices, 0, 0, 0, 0, 0, bounds().width, bounds().height, bounds().width, bounds().height);
RenderSystem.setShaderTexture(0, SpellbookScreen.TEXTURE);
}
}
class TextBlock implements PageElement {
private final DynamicContent.Page page;
private final Text unwrappedText;
private final List<Line> wrappedText = new ArrayList<>();
private final Bounds bounds = Bounds.empty();
public TextBlock(DynamicContent.Page page,Text text) {
this.page = page;
unwrappedText = text;
}
@Override
public void compile(int y, IViewRoot container) {
wrappedText.clear();
ParagraphWrappingVisitor visitor = new ParagraphWrappingVisitor(yPosition -> {
return page.getLineLimitAt(y + yPosition);
}, (line, yPosition) -> {
wrappedText.add(new Line(line, page.getLeftMarginAt(y + yPosition)));
});
unwrappedText.visit(visitor, Style.EMPTY);
visitor.forceAdvance();
bounds.height = MinecraftClient.getInstance().textRenderer.fontHeight * (wrappedText.size() + 1);
}
@Override
public void draw(MatrixStack matrices, int mouseX, int mouseY, IViewRoot container) {
TextRenderer font = MinecraftClient.getInstance().textRenderer;
boolean needsMoreXp = page.getLevel() < 0 || Pony.of(MinecraftClient.getInstance().player).getLevel().get() < page.getLevel();
matrices.push();
wrappedText.forEach(line -> {
font.draw(matrices, needsMoreXp ? line.text().copy().formatted(Formatting.OBFUSCATED) : line.text(), line.x(), 0, 0);
matrices.translate(0, font.fontHeight, 0);
});
matrices.pop();
}
@Override
public Bounds bounds() {
return bounds;
}
@Override
public Flow flow() {
return Flow.NONE;
}
private record Line(Text text, int x) { }
}
record Recipe (DynamicContent.Page page, Identifier id, Bounds bounds) implements PageElement {
@Override
public void draw(MatrixStack matrices, int mouseX, int mouseY, IViewRoot container) {
}
@Override
public void compile(int y, IViewRoot Container) {
MinecraftClient.getInstance().world.getRecipeManager().get(id).ifPresent(recipe -> {
if (recipe instanceof SpellbookRecipe spellRecipe) {
IngredientTree tree = new IngredientTree(page.getBounds().left, y, page().getBounds().width / 2 - 20, 20);
spellRecipe.buildCraftingTree(tree);
bounds.height = tree.build(Container);
}
});
}
@Override
public Flow flow() {
return Flow.NONE;
}
}
enum Flow {
NONE, LEFT, RIGHT
}
}

View file

@ -4,6 +4,7 @@ import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Stream;
import com.minelittlepony.common.client.gui.IViewRoot;
import com.minelittlepony.unicopia.Unicopia;
import net.minecraft.client.util.math.MatrixStack;
@ -78,14 +79,14 @@ public class SpellbookChapterList {
}
@Override
public void draw(MatrixStack matrices, int mouseX, int mouseY) {
obj.draw(matrices, mouseX, mouseY);
public void draw(MatrixStack matrices, int mouseX, int mouseY, IViewRoot container) {
obj.draw(matrices, mouseX, mouseY, container);
}
});
}
}
public interface Drawable {
void draw(MatrixStack matrices, int mouseX, int mouseY);
void draw(MatrixStack matrices, int mouseX, int mouseY, IViewRoot container);
}
}

View file

@ -36,7 +36,7 @@ public class SpellbookCraftingPageContent extends ScrollContainer implements Spe
}
@Override
public void draw(MatrixStack matrices, int mouseX, int mouseY) {
public void draw(MatrixStack matrices, int mouseX, int mouseY, IViewRoot container) {
textRenderer.draw(matrices, screen.getTitle(), SpellbookScreen.TITLE_X, SpellbookScreen.TITLE_Y, SpellbookScreen.TITLE_COLOR);
textRenderer.draw(matrices, SpellbookPage.getCurrent().getLabel(), screen.getBackgroundWidth() / 2 + SpellbookScreen.TITLE_X, SpellbookScreen.TITLE_Y, SpellbookScreen.TITLE_COLOR);

View file

@ -1,10 +1,10 @@
package com.minelittlepony.unicopia.container;
import com.minelittlepony.common.client.gui.IViewRoot;
import com.minelittlepony.common.client.gui.dimension.Bounds;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.client.gui.DrawableUtil;
import com.minelittlepony.unicopia.entity.player.MagicReserves;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.entity.player.*;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.MinecraftClient;
@ -32,23 +32,15 @@ public class SpellbookProfilePageContent extends DrawableHelper implements Spell
}
@Override
public void draw(MatrixStack matrices, int mouseX, int mouseY) {
public void draw(MatrixStack matrices, int mouseX, int mouseY, IViewRoot container) {
int y = SpellbookScreen.TITLE_Y;
float delta = pony.getEntity().age + client.getTickDelta();
int currentLevel = pony.getLevel().get();
matrices.push();
matrices.translate(SpellbookScreen.TITLE_X, y, 0);
matrices.scale(1.3F, 1.3F, 1);
font.draw(matrices, pony.getEntity().getName(), 0, 0, SpellbookScreen.TITLE_COLOR);
matrices.pop();
matrices.push();
matrices.translate(SpellbookScreen.TITLE_X, y + 13, 0);
matrices.scale(0.8F, 0.8F, 1);
font.draw(matrices, "Friendship Student", 0, 0, 0xAA0040FF);
matrices.pop();
DrawableUtil.drawScaledText(matrices, pony.getEntity().getName(), SpellbookScreen.TITLE_X, y, 1.3F, SpellbookScreen.TITLE_COLOR);
DrawableUtil.drawScaledText(matrices, ExperienceGroup.forLevel(currentLevel).getLabel(), SpellbookScreen.TITLE_X, y + 13, 0.8F, 0xAA0040FF);
MagicReserves reserves = pony.getMagicalReserves();

View file

@ -4,6 +4,7 @@ import java.util.Optional;
import java.util.function.IntConsumer;
import com.minelittlepony.common.client.gui.GameGui;
import com.minelittlepony.common.client.gui.IViewRoot;
import com.minelittlepony.common.client.gui.dimension.Bounds;
import com.minelittlepony.common.client.gui.element.Button;
import com.minelittlepony.common.client.gui.sprite.TextureSprite;
@ -179,7 +180,7 @@ public class SpellbookScreen extends HandledScreen<SpellbookScreenHandler> imple
@Override
protected void drawForeground(MatrixStack matrices, int mouseX, int mouseY) {
chapters.getCurrentChapter().content().ifPresent(content -> content.draw(matrices, mouseX, mouseY));
chapters.getCurrentChapter().content().ifPresent(content -> content.draw(matrices, mouseX, mouseY, (IViewRoot)this));
}
@Override

View file

@ -0,0 +1,32 @@
package com.minelittlepony.unicopia.entity.player;
import net.minecraft.text.Text;
public enum ExperienceGroup {
MAGICAL_KINDERGARTENER,
FRIENDSHIP_STUDENT,
SENIOR_FRIENDSHIP_STUDENT,
JUNIOR_MAGE,
MAGE,
ARCHMAGE,
ARCHMAGUS,
SENIOR_ARCHMAGUS,
ASCENDED_SENIOR_ARCHMAGUS,
DEMI_GOD,
ARCH_DEMI_GOD,
ALICORN_PRINCESS,
POLYCORN_PRINCESS,
FAUSTIAN_LEGEND;
private final Text label = Text.literal(name().toLowerCase());
public Text getLabel() {
return label;
}
public static ExperienceGroup forLevel(int level) {
level /= 20;
return FRIENDSHIP_STUDENT;
}
}