From af7cb167bad2d18bb5a2bfd37e729e9645a5c857 Mon Sep 17 00:00:00 2001 From: Minecraftschurli Date: Wed, 15 Jun 2022 22:27:18 +0200 Subject: [PATCH 1/8] re add jei integration --- build.gradle | 27 +++++++++++++++---- .../dev/gigaherz/guidebook/jei/JEIPlugin.java | 13 ++++----- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/build.gradle b/build.gradle index d1e2649..ad5c14f 100644 --- a/build.gradle +++ b/build.gradle @@ -63,8 +63,9 @@ minecraft { property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg" mods { - thismod { + gbook { source sourceSets.main + source sourceSets.test } } } @@ -80,11 +81,27 @@ minecraft { property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg" mods { - thismod { + gbook { source sourceSets.main } } } + data { + property 'forge.logging.markers', '' + property 'forge.logging.console.level', 'debug' + + property 'mixin.env.remapRefMap', 'true' + property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg" + + args '--mod', 'gbook', '--all', '--output', file('src/test/resources/'), '--existing', file('src/main/resources/') + + mods { + gbook { + source sourceSets.main + source sourceSets.test + } + } + } } } @@ -92,8 +109,8 @@ dependencies { minecraft 'net.minecraftforge:forge:1.19-41.0.17' - //compileOnly fg.deobf("mezz.jei:jei-1.18.2:9.5.5.174:api") - //runtimeOnly fg.deobf("mezz.jei:jei-1.18.2:9.5.5.174") + compileOnly fg.deobf("mezz.jei:jei-1.18.2-common-api:10.0.0.191") + //runtimeOnly fg.deobf("mezz.jei:jei-1.19-forge:10.0.0.191") implementation fg.deobf( "net.darkhax.gamestages:GameStages-Forge-1.19:9.0.1") implementation fg.deobf( "net.darkhax.bookshelf:Bookshelf-Forge-1.19:14.0.2") @@ -162,4 +179,4 @@ project.afterEvaluate { } } } -} \ No newline at end of file +} diff --git a/src/main/java/dev/gigaherz/guidebook/jei/JEIPlugin.java b/src/main/java/dev/gigaherz/guidebook/jei/JEIPlugin.java index 0a59f89..396cffd 100644 --- a/src/main/java/dev/gigaherz/guidebook/jei/JEIPlugin.java +++ b/src/main/java/dev/gigaherz/guidebook/jei/JEIPlugin.java @@ -1,12 +1,12 @@ package dev.gigaherz.guidebook.jei; -/* + import dev.gigaherz.guidebook.GuidebookMod; import dev.gigaherz.guidebook.guidebook.GuidebookItem; import mezz.jei.api.IModPlugin; import mezz.jei.api.JeiPlugin; +import mezz.jei.api.constants.VanillaTypes; import mezz.jei.api.registration.ISubtypeRegistration; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.item.ItemStack; @JeiPlugin public class JEIPlugin implements IModPlugin @@ -22,18 +22,15 @@ public ResourceLocation getPluginUid() @Override public void registerItemSubtypes(ISubtypeRegistration subtypeRegistry) { - subtypeRegistry.registerSubtypeInterpreter(GuidebookMod.guidebook, (ingredient, context) -> { + subtypeRegistry.registerSubtypeInterpreter(VanillaTypes.ITEM_STACK, GuidebookMod.guidebook, (ingredient, context) -> { if (ingredient.getItem() instanceof GuidebookItem item) { - ItemStack stack = new ItemStack(item); - stack.setTag(ingredient.getTag()); - var key = item.getBookLocation(stack); + var key = item.getBookLocation(ingredient); return key == null ? "" : "book_" + key; } return ""; }); } - -}*/ \ No newline at end of file +} From a63bc5245abb03fdcfa4637e93c238f421a48de1 Mon Sep 17 00:00:00 2001 From: Minecraftschurli Date: Wed, 15 Jun 2022 22:29:03 +0200 Subject: [PATCH 2/8] cleanups --- .../guidebook/guidebook/BookDocument.java | 456 ++++++++---------- .../guidebook/elements/ElementLink.java | 3 +- .../guidebook/elements/ElementParagraph.java | 40 +- .../guidebook/elements/ElementStack.java | 88 ++-- 4 files changed, 242 insertions(+), 345 deletions(-) diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/BookDocument.java b/src/main/java/dev/gigaherz/guidebook/guidebook/BookDocument.java index 8ba1644..7f5e2ac 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/BookDocument.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/BookDocument.java @@ -19,13 +19,13 @@ import dev.gigaherz.guidebook.guidebook.util.Rect; import dev.gigaherz.guidebook.guidebook.util.Size; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.texture.TextureAtlas; import net.minecraft.client.resources.model.Material; import net.minecraft.client.resources.model.ModelResourceLocation; import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.packs.resources.Resource; +import net.minecraft.world.inventory.InventoryMenu; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; +import net.minecraftforge.fml.ModList; import net.minecraftforge.registries.ForgeRegistries; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; @@ -39,6 +39,7 @@ import javax.xml.parsers.ParserConfigurationException; import java.io.*; import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.BiConsumer; import java.util.function.Predicate; @@ -56,7 +57,7 @@ public class BookDocument private ResourceLocation bookModel; final List chapters = Lists.newArrayList(); - private Map stackLinks = Maps.newHashMap(); + private final Map stackLinks = Maps.newHashMap(); final Map chaptersByName = Maps.newHashMap(); final Map sectionsByName = Maps.newHashMap(); @@ -80,6 +81,11 @@ public static void registerCustomElement(ResourceLocation location, ElementFacto static { registerCustomElement(new ResourceLocation("minecraft:recipe"), ElementRecipe::new); + registerCustomElement(new ResourceLocation("grid"), ElementGrid::new); + registerCustomElement(new ResourceLocation("space"), ElementPanel::new); + registerCustomElement(new ResourceLocation("group"), ElementPanel::new); + registerCustomElement(new ResourceLocation("panel"), ElementPanel::new); + registerCustomElement(new ResourceLocation("div"), ElementPanel::new); } public BookDocument(ResourceLocation bookLocation) @@ -152,7 +158,7 @@ public int chapterCount() public void findTextures(Set textures) { if (bookCover != null) - textures.add(new Material(TextureAtlas.LOCATION_BLOCKS, bookCover)); + textures.add(new Material(InventoryMenu.BLOCK_ATLAS, bookCover)); for (ChapterData chapter : chapters) { @@ -178,6 +184,7 @@ public void initializeWithLoadError(String error) pg.elements.add(ElementParagraph.of(error, TextStyle.ERROR)); } + @SuppressWarnings({"BooleanMethodIsAlwaysInverted", "UnstableApiUsage"}) public boolean parseBook(InputStream stream, boolean loadedFromConfigFolder) { try @@ -198,7 +205,7 @@ public boolean parseBook(InputStream stream, boolean loadedFromConfigFolder) @Override public Predicate getCondition(String name) { - return this.getCondition(name); + return BookDocument.this.getCondition(name); } @Override @@ -262,12 +269,11 @@ public DocumentBuilder xmlDocumentBuilder() { for (String s : n.getTextContent().split(",")) { - // TODO - /*if (!Loader.isModLoaded(s)) + if (!ModList.get().isLoaded(s)) { initializeWithLoadError("Dependency not loaded: " + s); return false; - }*/ + } } } } @@ -285,26 +291,22 @@ public DocumentBuilder xmlDocumentBuilder() private void parseDocumentLevelElements(ParsingContext context, NodeList firstLevel) { - int chapterNumber = 0; + AtomicInteger chapterNumber = new AtomicInteger(0); for (int i = 0; i < firstLevel.getLength(); i++) { Node firstLevelNode = firstLevel.item(i); - chapterNumber = parseDocumentLevelElement(context, chapterNumber, firstLevelNode); + parseDocumentLevelElement(context, chapterNumber, firstLevelNode); } } - private int parseDocumentLevelElement(ParsingContext context, int chapterNumber, Node firstLevelNode) + private void parseDocumentLevelElement(ParsingContext context, AtomicInteger chapterNumber, Node firstLevelNode) { String nodeName = firstLevelNode.getNodeName(); - if (nodeName.equals("template")) - { - parseTemplateDefinition(context,firstLevelNode, templates); - } - else if (nodeName.equals("include")) + switch (nodeName) { - int[] cn = new int[]{chapterNumber}; - parseInclude(context, firstLevelNode, (resLoc, document) -> { + case "template" -> parseTemplateDefinition(context, firstLevelNode, templates); + case "include" -> parseInclude(context, firstLevelNode, (resLoc, document) -> { var includeRoot = document.getDocumentElement(); if (includeRoot.getTagName().equals("library")) { @@ -313,24 +315,13 @@ else if (nodeName.equals("include")) } else { - cn[0] = parseDocumentLevelElement(context, cn[0], includeRoot); + parseDocumentLevelElement(context, chapterNumber, includeRoot); } }); - chapterNumber = cn[0]; - } - else if (nodeName.equals("chapter")) - { - parseChapter(context, chapterNumber++, firstLevelNode); - } - else if (nodeName.equals("stack-links")) - { - parseStackLinks(firstLevelNode); - } - else if (nodeName.equals("conditions")) - { - parseConditions(firstLevelNode); + case "chapter" -> parseChapter(context, chapterNumber.getAndIncrement(), firstLevelNode); + case "stack-links" -> parseStackLinks(firstLevelNode); + case "conditions" -> parseConditions(firstLevelNode); } - return chapterNumber; } private static void parseInclude(ParsingContext context, Node firstLevelNode, BiConsumer includeAction) @@ -402,8 +393,6 @@ private void parseConditions(Node node) continue; NamedNodeMap attributes = condition.getAttributes(); - if (attributes == null) - continue; Node conditionName = attributes.getNamedItem("name"); String name = conditionName != null ? conditionName.getTextContent() : null; @@ -496,37 +485,24 @@ private void parseChapter(ParsingContext context, int chapterNumber, Node chapte } } - int sectionNumber = 0; + AtomicInteger sectionNumber = new AtomicInteger(0); NodeList pagesList = chapterItem.getChildNodes(); for (int j = 0; j < pagesList.getLength(); j++) { Node pageItem = pagesList.item(j); - sectionNumber = parseChapterElement(context, chapterNumber, chapter, sectionNumber, pageItem); + parseChapterElement(context, chapterNumber, chapter, sectionNumber, pageItem); } } - private int parseChapterElement(ParsingContext context, int chapterNumber, ChapterData chapter, int sectionNumber, Node pageItem) + private void parseChapterElement(ParsingContext context, int chapterNumber, ChapterData chapter, AtomicInteger sectionNumber, Node pageItem) { - String nodeName = pageItem.getNodeName(); - - if (nodeName.equals("page")) + switch (pageItem.getNodeName()) { - parsePage(context, chapter, new SectionRef(chapterNumber, sectionNumber++), pageItem); + case "page" -> parsePage(context, chapter, new SectionRef(chapterNumber, sectionNumber.getAndIncrement()), pageItem); + case "section" -> parseSection(context, chapter, new SectionRef(chapterNumber, sectionNumber.getAndIncrement()), pageItem); + case "include" -> parseInclude(context, pageItem, (name, document) -> parseChapterElement(context, chapterNumber, chapter, sectionNumber, document.getDocumentElement())); } - else if (nodeName.equals("section")) - { - parseSection(context, chapter, new SectionRef(chapterNumber, sectionNumber++), pageItem); - } - else if (nodeName.equals("include")) - { - int[] sn = new int[]{sectionNumber}; - parseInclude(context, pageItem, (name,document) -> { - sn[0] = parseChapterElement(context, chapterNumber, chapter, sn[0], document.getDocumentElement()); - }); - sectionNumber = sn[0]; - } - return sectionNumber; } private void parsePage(ParsingContext context, ChapterData chapter, SectionRef ref, Node pageItem) @@ -591,262 +567,226 @@ private static void parsePageElement(ParsingContext context, List eleme elementItem.getNodeType() == Node.ELEMENT_NODE ? new ResourceLocation(nodeName) : new ResourceLocation("_"); - if (nodeName.equals("section-break")) - { - parsedElement = new ElementBreak(); - } - else if (nodeName.equals("include")) + switch (nodeName) { - parseInclude(context, elementItem, (name,document) -> { - parsePageElement(context, elements, templates, generateParagraphs, defaultStyle, isFirstElement, isLastElement, document.getDocumentElement()); - }); - } - else if (nodeName.equals("p") || nodeName.equals("title")) - { - ElementParagraph p = new ElementParagraph(); - - TextStyle tagDefaults = defaultStyle; - if (nodeName.equals("title")) - { - p.alignment = ElementParagraph.ALIGN_CENTER; - p.space = 4; - tagDefaults = new TextStyle(defaultStyle.color, true, false, true, false, false, null, 1.0f); - } + case "section-break" -> parsedElement = new ElementBreak(); + case "include" -> parseInclude(context, elementItem, (name,document) -> + parsePageElement(context, elements, templates, generateParagraphs, defaultStyle, isFirstElement, isLastElement, document.getDocumentElement()) + ); + case "p", "title" -> { + ElementParagraph p = new ElementParagraph(); - TextStyle paragraphDefautls = TextStyle.parse(elementItem.getAttributes(), tagDefaults); + TextStyle tagDefaults = defaultStyle; + if (nodeName.equals("title")) + { + p.alignment = ElementParagraph.ALIGN_CENTER; + p.space = 4; + tagDefaults = new TextStyle(defaultStyle.color, true, false, true, false, false, null, 1.0f); + } - NodeList childList = elementItem.getChildNodes(); - int l = childList.getLength(); - for (int q = 0; q < l; q++) - { - Node childNode = childList.item(q); - ElementInline parsedChild = parseParagraphElement(context, childNode, childNode.getNodeName(), isFirstElement, isLastElement, paragraphDefautls); + TextStyle paragraphDefautls = TextStyle.parse(elementItem.getAttributes(), tagDefaults); - if (parsedChild == null) + NodeList childList = elementItem.getChildNodes(); + for (int q = 0; q < childList.getLength(); q++) { - GuidebookMod.logger.warn("Unrecognized tag: {}", childNode.getNodeName()); + Node childNode = childList.item(q); + ElementInline parsedChild = parseParagraphElement(context, childNode, childNode.getNodeName(), isFirstElement, isLastElement, paragraphDefautls); + + if (parsedChild == null) + { + GuidebookMod.logger.warn("Unrecognized tag: {}", childNode.getNodeName()); + } + else + { + p.inlines.add(parsedChild); + } } - else + + if (elementItem.hasAttributes()) { - p.inlines.add(parsedChild); + p.parse(context, elementItem.getAttributes()); } - } - if (elementItem.hasAttributes()) - { - p.parse(context, elementItem.getAttributes()); + parsedElement = p; } + default -> { + if (customElements.containsKey(nodeLoc)) + { + ElementFactory factory = customElements.get(nodeLoc); - parsedElement = p; - } - else if (nodeName.equals("space") - || nodeName.equals("group") - || nodeName.equals("panel") - || nodeName.equals("div")) - { - ElementPanel p = new ElementPanel(); + Element t = factory.newInstance(); - if (elementItem.hasAttributes()) - { - p.parse(context, elementItem.getAttributes()); - } + if (elementItem.hasAttributes()) + { + t.parse(context, elementItem.getAttributes()); + } - if (elementItem.hasChildNodes()) - { - p.parseChildNodes(context, elementItem.getChildNodes(), templates, defaultStyle); - } + if (elementItem.hasChildNodes()) + { + t.parseChildNodes(context, elementItem.getChildNodes(), templates, defaultStyle); + } - parsedElement = p; - } - else if (nodeName.equals("grid")) - { - ElementGrid g = new ElementGrid(); + parsedElement = t; + } + else if (templates.containsKey(nodeName)) + { + TemplateDefinition tDef = templates.get(nodeName); - if (elementItem.hasAttributes()) - { - g.parse(context, elementItem.getAttributes()); - } + ElementPanel t = new ElementPanel(); + t.parse(context, tDef.attributes); - if (elementItem.hasChildNodes()) - { - g.parseChildNodes(context, elementItem.getChildNodes(), templates, defaultStyle); - } + if (elementItem.hasAttributes()) + { + t.parse(context, elementItem.getAttributes()); + } - parsedElement = g; - } - else if (customElements.containsKey(nodeLoc)) - { - ElementFactory factory = customElements.get(nodeLoc); + List elementList = Lists.newArrayList(); - Element t = factory.newInstance(); + parseChildElements(context, elementItem.getChildNodes(), elementList, templates, false, defaultStyle); - if (elementItem.hasAttributes()) - { - t.parse(context, elementItem.getAttributes()); - } + List effectiveList = tDef.applyTemplate(context, elementList); - if (elementItem.hasChildNodes()) - { - t.parseChildNodes(context, elementItem.getChildNodes(), templates, defaultStyle); - } + t.innerElements.addAll(effectiveList); - parsedElement = t; + parsedElement = t; + } + else if (elementItem.getNodeType() == Node.TEXT_NODE) + { + if (generateParagraphs) + { + String textContent = ElementText.compactString(elementItem.getTextContent(), isFirstElement, isLastElement); + if (!Strings.isNullOrEmpty(textContent) && !textContent.matches("^[ \t\r\n]+$")) + parsedElement = ElementSpan.of(textContent, defaultStyle); + } + } + else if (elementItem.getNodeType() != Node.COMMENT_NODE) + { + parsedElement = parseParagraphElement(context, elementItem, nodeName, isFirstElement, isLastElement, defaultStyle); + + if (parsedElement == null) + { + GuidebookMod.logger.warn("Unrecognized tag: {}", nodeName); + } + } + } } - else if (templates.containsKey(nodeName)) - { - TemplateDefinition tDef = templates.get(nodeName); - ElementPanel t = new ElementPanel(); - t.parse(context, tDef.attributes); + if (parsedElement == null) return; + + if (!parsedElement.supportsPageLevel() && generateParagraphs && parsedElement instanceof ElementInline) + { + ElementParagraph p = new ElementParagraph(); if (elementItem.hasAttributes()) { - t.parse(context, elementItem.getAttributes()); + p.parse(context, elementItem.getAttributes()); + parsedElement.parse(context, elementItem.getAttributes()); } - List elementList = Lists.newArrayList(); - - parseChildElements(context, elementItem.getChildNodes(), elementList, templates, false, defaultStyle); - - List effectiveList = tDef.applyTemplate(context, elementList); + p.inlines.add((ElementInline) parsedElement); - t.innerElements.addAll(effectiveList); - - parsedElement = t; - } - else if (elementItem.getNodeType() == Node.TEXT_NODE) - { - if (generateParagraphs) - { - String textContent = ElementText.compactString(elementItem.getTextContent(), isFirstElement, isLastElement); - if (!Strings.isNullOrEmpty(textContent) && !textContent.matches("^[ \t\r\n]+$")) - parsedElement = ElementSpan.of(textContent, defaultStyle); - } - } - else if (elementItem.getNodeType() == Node.COMMENT_NODE) - { - // Ignore. + parsedElement = p; } - else - { - parsedElement = parseParagraphElement(context, elementItem, nodeName, isFirstElement, isLastElement, defaultStyle); - if (parsedElement == null) - { - GuidebookMod.logger.warn("Unrecognized tag: {}", nodeName); - } - } + if (parsedElement.supportsPageLevel()) + elements.add(parsedElement); + } - if (parsedElement != null) + @Nullable + public static ElementInline parseParagraphElement(ParsingContext context, Node elementItem, String nodeName, boolean isFirstElement, boolean isLastElement, TextStyle defaultStyle) + { + return switch (nodeName) { - if (!parsedElement.supportsPageLevel() && generateParagraphs && parsedElement instanceof ElementInline) + case "span" -> { - ElementParagraph p = new ElementParagraph(); + ElementSpan span = new ElementSpan(isFirstElement, isLastElement); if (elementItem.hasAttributes()) { - p.parse(context, elementItem.getAttributes()); - parsedElement.parse(context, elementItem.getAttributes()); + span.parse(context, elementItem.getAttributes()); } - p.inlines.add((ElementInline) parsedElement); + if (elementItem.hasChildNodes()) + { + TextStyle spanDefaults = TextStyle.parse(elementItem.getAttributes(), defaultStyle); - parsedElement = p; - } + List elementList = Lists.newArrayList(); - if (parsedElement.supportsPageLevel()) - elements.add(parsedElement); - } - } + parseRunElements(context, elementItem, elementList, spanDefaults); - @Nullable - public static ElementInline parseParagraphElement(ParsingContext context, Node elementItem, String nodeName, boolean isFirstElement, boolean isLastElement, TextStyle defaultStyle) - { - ElementInline parsedElement = null; - if (nodeName.equals("span")) - { - ElementSpan span = new ElementSpan(isFirstElement, isLastElement); + span.inlines.addAll(elementList); + } - if (elementItem.hasAttributes()) - { - span.parse(context, elementItem.getAttributes()); + yield span; } - - if (elementItem.hasChildNodes()) + case "link", "a" -> { - TextStyle spanDefaults = TextStyle.parse(elementItem.getAttributes(), defaultStyle); + ElementLink link = new ElementLink(isFirstElement, isLastElement); - List elementList = Lists.newArrayList(); + if (elementItem.hasAttributes()) + { + link.parse(context, elementItem.getAttributes()); + } - parseRunElements(context, elementItem, elementList, spanDefaults); + if (elementItem.hasChildNodes()) + { + TextStyle spanDefaults = TextStyle.parse(elementItem.getAttributes(), TextStyle.LINK); - span.inlines.addAll(elementList); - } + List elementList = Lists.newArrayList(); - parsedElement = span; - } - else if (nodeName.equals("link") || nodeName.equals("a")) - { - ElementLink link = new ElementLink(isFirstElement, isLastElement); + parseRunElements(context, elementItem, elementList, spanDefaults); - if (elementItem.hasAttributes()) - { - link.parse(context, elementItem.getAttributes()); - } + link.inlines.addAll(elementList); + } - if (elementItem.hasChildNodes()) + yield link; + } + case "stack" -> { - TextStyle spanDefaults = TextStyle.parse(elementItem.getAttributes(), TextStyle.LINK); - - List elementList = Lists.newArrayList(); + ElementStack s = new ElementStack(isFirstElement, isLastElement); - parseRunElements(context, elementItem, elementList, spanDefaults); + if (elementItem.hasAttributes()) + { + s.parse(context, elementItem.getAttributes()); + } - link.inlines.addAll(elementList); + yield s; } - - parsedElement = link; - } - else if (nodeName.equals("stack")) - { - ElementStack s = new ElementStack(isFirstElement, isLastElement); - - if (elementItem.hasAttributes()) + case "image" -> { - s.parse(context, elementItem.getAttributes()); - } + ElementImage i = new ElementImage(isFirstElement, isLastElement); - parsedElement = s; - } - else if (nodeName.equals("image")) - { - ElementImage i = new ElementImage(isFirstElement, isLastElement); + if (elementItem.hasAttributes()) + { + i.parse(context, elementItem.getAttributes()); + } - if (elementItem.hasAttributes()) - { - i.parse(context, elementItem.getAttributes()); + yield i; } + case "element" -> + { + TemplateElement i = new TemplateElement(isFirstElement, isLastElement); - parsedElement = i; - } - else if (nodeName.equals("element")) - { - TemplateElement i = new TemplateElement(isFirstElement, isLastElement); + if (elementItem.hasAttributes()) + { + i.parse(context, elementItem.getAttributes()); + } - if (elementItem.hasAttributes()) + yield i; + } + default -> { - i.parse(context, elementItem.getAttributes()); + if (elementItem.getNodeType() == Node.TEXT_NODE) + { + String textContent = ElementText.compactString(elementItem.getTextContent(), isFirstElement, isLastElement); + if (!Strings.isNullOrEmpty(textContent)) + { + yield ElementSpan.of(textContent, isFirstElement, isLastElement, defaultStyle); + } + } + yield null; } - - parsedElement = i; - } - else if (elementItem.getNodeType() == Node.TEXT_NODE) - { - String textContent = ElementText.compactString(elementItem.getTextContent(), isFirstElement, isLastElement); - if (!Strings.isNullOrEmpty(textContent)) - parsedElement = ElementSpan.of(textContent, isFirstElement, isLastElement, defaultStyle); - } - return parsedElement; + }; } public static void parseRunElements(ParsingContext context, Node pageItem, List elements, TextStyle defaultStyle) @@ -872,19 +812,19 @@ public static void parseRunElements(ParsingContext context, Node pageItem, List< Element t = factory.newInstance(); - if (t instanceof ElementInline) + if (t instanceof ElementInline inline) { if (elementItem.hasAttributes()) { - t.parse(context, elementItem.getAttributes()); + inline.parse(context, elementItem.getAttributes()); } if (elementItem.hasChildNodes()) { - t.parseChildNodes(context, elementItem.getChildNodes(), Collections.emptyMap(), defaultStyle); + inline.parseChildNodes(context, elementItem.getChildNodes(), Collections.emptyMap(), defaultStyle); } - parsedElement = (ElementInline) t; + parsedElement = inline; } } else if (elementItem.getNodeType() == Node.TEXT_NODE) @@ -893,11 +833,7 @@ else if (elementItem.getNodeType() == Node.TEXT_NODE) if (!Strings.isNullOrEmpty(textContent)) parsedElement = ElementSpan.of(textContent, isFirstElement, isLastElement, defaultStyle); } - else if (elementItem.getNodeType() == Node.COMMENT_NODE) - { - // Ignore. - } - else + else if (elementItem.getNodeType() != Node.COMMENT_NODE) { parsedElement = parseParagraphElement(context, elementItem, nodeName, isFirstElement, isLastElement, defaultStyle); @@ -957,7 +893,7 @@ public boolean reevaluateConditions(ConditionContext ctx) return anyChanged; } - public class ChapterData + public static class ChapterData { public final int num; public String id; @@ -1006,7 +942,7 @@ public boolean isEmpty() } } - public class PageData + public static class PageData { public final SectionRef ref; public String id; @@ -1074,7 +1010,7 @@ public boolean isEmpty() * * */ - public class PageGroup extends PageData + public static class PageGroup extends PageData { public PageGroup(SectionRef ref) { diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementLink.java b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementLink.java index 9dc6e08..0202961 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementLink.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementLink.java @@ -25,9 +25,8 @@ public List measure(IBookGraphics nav, int width, int firstLineWi { List texts = super.measure(nav, width, firstLineWidth); texts.forEach(e -> { - if (e instanceof LinkHelper.ILinkable) + if (e instanceof LinkHelper.ILinkable linkable) { - LinkHelper.ILinkable linkable = (LinkHelper.ILinkable) e; linkable.setLinkContext(ctx); } }); diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementParagraph.java b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementParagraph.java index aff8659..620c361 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementParagraph.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementParagraph.java @@ -64,12 +64,11 @@ public int reflow(List paragraph, IBookGraphics nav, Rect bounds, if (pieces.size() < 1) continue; - for (int i = 0; i < pieces.size(); i++) + for (VisualElement current : pieces) { - VisualElement current = pieces.get(i); Size size = current.size; - boolean isLineBreak = "\n".equals(current.getText()); + boolean isLineBreak = "\n".equals(current.getText().getString()); if (isLineBreak || (currentLineLeft + size.width > bounds.size.width && currentLineLeft > 0)) { @@ -119,17 +118,12 @@ private void processAlignment(List paragraph, int width, int curr if (paragraph.size() <= firstInLine) return; - int realWidth = currentLineLeft; - int leftOffset = 0; - switch (alignment) + int leftOffset = switch (alignment) { - case ALIGN_CENTER: - leftOffset = (width - realWidth) / 2; - break; - case ALIGN_RIGHT: - leftOffset = width - realWidth; - break; - } + case ALIGN_CENTER -> (width - currentLineLeft) / 2; + case ALIGN_RIGHT -> width - currentLineLeft; + default -> 0; + }; int yMin = Integer.MAX_VALUE; int yMax = Integer.MIN_VALUE; @@ -142,7 +136,7 @@ private void processAlignment(List paragraph, int width, int curr e.position = new Point(e.position.x + leftOffset, e.position.y); yMin = Math.min(yMin, e.position.y); - yMax = Math.min(yMax, e.position.y + e.size.height); + yMax = Math.min(yMax, e.position.y + e.size.height); // TODO check if this is correct yBaseline = Math.min(yBaseline, e.position.y + (int) (e.size.height * e.baseline)); } } @@ -193,19 +187,13 @@ public void parse(ParsingContext context, NamedNodeMap attributes) Node attr = attributes.getNamedItem("align"); if (attr != null) { - String a = attr.getTextContent(); - switch (a) + alignment = switch (attr.getTextContent()) { - case "left": - alignment = ElementParagraph.ALIGN_LEFT; - break; - case "center": - alignment = ElementParagraph.ALIGN_CENTER; - break; - case "right": - alignment = ElementParagraph.ALIGN_RIGHT; - break; - } + case "left" -> ElementParagraph.ALIGN_LEFT; + case "center" -> ElementParagraph.ALIGN_CENTER; + case "right" -> ElementParagraph.ALIGN_RIGHT; + default -> alignment; + }; } indent = getAttribute(attributes, "indent", indent); diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementStack.java b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementStack.java index ec8cd07..e8efd38 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementStack.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementStack.java @@ -10,12 +10,15 @@ import dev.gigaherz.guidebook.guidebook.util.Rect; import dev.gigaherz.guidebook.guidebook.util.Size; import net.minecraft.core.NonNullList; +import net.minecraft.core.Registry; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.TagParser; import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.TagKey; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraftforge.registries.ForgeRegistries; +import net.minecraftforge.registries.tags.ITag; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; @@ -24,8 +27,6 @@ public class ElementStack extends ElementInline { - public static final String WILDCARD = "*"; - public final NonNullList stacks = NonNullList.create(); public float scale = 1.0f; @@ -71,43 +72,29 @@ public int reflow(List paragraph, IBookGraphics nav, Rect bounds, public void parse(ParsingContext context, NamedNodeMap attributes) { int stackSize = 1; - CompoundTag tag = new CompoundTag(); + CompoundTag nbt = new CompoundTag(); super.parse(context, attributes); scale = getAttribute(attributes, "scale", scale); - Node attr = attributes.getNamedItem("item"); - if (attr != null) - { - String itemName = attr.getTextContent(); - - Item item = ForgeRegistries.ITEMS.getValue(new ResourceLocation(itemName)); - - if (item != null) - { - ItemStack stack = new ItemStack(item, stackSize); - stack.setTag(tag); - stacks.add(stack); - } - } - + Node attr; attr = attributes.getNamedItem("count"); if (attr != null) { stackSize = Ints.tryParse(attr.getTextContent()); } - attr = attributes.getNamedItem("tag"); + attr = attributes.getNamedItem("nbt"); if (attr != null) { try { - tag = TagParser.parseTag(attr.getTextContent()); + nbt = TagParser.parseTag(attr.getTextContent()); } catch (CommandSyntaxException e) { - GuidebookMod.logger.warn("Invalid tag format: " + e.getMessage()); + GuidebookMod.logger.warn("Invalid nbt format: " + e.getMessage()); } } @@ -116,7 +103,7 @@ public void parse(ParsingContext context, NamedNodeMap attributes) { try { - tag = TagParser.parseTag(attr.getTextContent()); + nbt = TagParser.parseTag(attr.getTextContent());// TODO this does not make sense } catch (CommandSyntaxException e) { @@ -124,49 +111,36 @@ public void parse(ParsingContext context, NamedNodeMap attributes) } } - // TODO: Tags - /* - //get stacks from ore dictionary - attr = attributes.getNamedItem("ore"); + attr = attributes.getNamedItem("item"); + if (attr != null) + { + String itemName = attr.getTextContent(); + + Item item = ForgeRegistries.ITEMS.getValue(new ResourceLocation(itemName)); + + if (item != null) + { + ItemStack stack = new ItemStack(item, stackSize); + stack.setTag(nbt); + stacks.add(stack); + } + } + + attr = attributes.getNamedItem("tag"); if (attr != null) { - String oreName = attr.getTextContent(); - //list of matching item stack; may contain wildcard meta data - NonNullList items = OreDictionary.getOres(oreName); + TagKey tagKey = TagKey.create(Registry.ITEM_REGISTRY, new ResourceLocation(attr.getTextContent())); + ITag tag = ForgeRegistries.ITEMS.tags().getTag(tagKey); - if (items.size() != 0) + if (!tag.isEmpty()) { - //foreach item: try to resolve wildcard meta data - for (ItemStack item : items) + for (Item item : tag) { - //make sure not to mess up ore dictionary item stacks - item = item.copy(); - meta = item.getMetadata(); - - if (meta == OreDictionary.WILDCARD_VALUE && item.getHasSubtypes()) - { - //replace wildcard metas with subitems - NonNullList subitems = NonNullList.create(); - item.getItem().getSubItems(CreativeTabs.SEARCH, subitems); - for (ItemStack subitem : subitems) - { - //just in case the ItemStack instance is not just a copy or a new instance - subitem = subitem.copy(); - - subitem.setCount(stackSize); - subitem.setTagCompound(tag); - stacks.add(subitem); - } - } - else - { - item.setCount(stackSize); - stacks.add(item); - } + ItemStack stack = new ItemStack(item, stackSize); + stacks.add(stack); } } } - */ } @Override From bfef0921f518834159f0f779e3956e0af74bb563 Mon Sep 17 00:00:00 2001 From: Minecraftschurli Date: Mon, 20 Jun 2022 19:25:14 +0200 Subject: [PATCH 3/8] huge refactor --- .../gigaherz/guidebook/client/ClientAPI.java | 2 +- .../guidebook/guidebook/BookDocument.java | 1087 ----------------- .../guidebook/guidebook/BookRegistry.java | 17 +- .../guidebook/guidebook/IBookGraphics.java | 2 + .../guidebook/guidebook/ParsingContext.java | 13 - .../guidebook/book/BookDocument.java | 166 +++ .../guidebook/book/BookDocumentParser.java | 795 ++++++++++++ .../guidebook/guidebook/book/ChapterData.java | 94 ++ .../book/DocumentLevelElementParser.java | 10 + .../guidebook/book/ElementFactory.java | 9 + .../guidebook/book/ElementModifier.java | 16 + .../guidebook/guidebook/book/IParseable.java | 20 + .../guidebook/book/InlineElementFactory.java | 9 + .../guidebook/guidebook/book/PageData.java | 95 ++ .../guidebook/guidebook/book/PageFactory.java | 7 + .../guidebook/guidebook/book/PageGroup.java | 111 ++ .../guidebook/book/ParsingContext.java | 85 ++ .../guidebook/{ => book}/SectionRef.java | 2 +- .../guidebook/client/BookBakedModel.java | 3 +- .../guidebook/client/BookRendering.java | 15 +- .../guidebook/client/GuidebookScreen.java | 7 +- .../conditions/AdvancementCondition.java | 4 +- .../guidebook/conditions/BasicConditions.java | 10 +- .../conditions/CompositeCondition.java | 8 +- .../conditions/ConditionContext.java | 2 +- .../conditions/ConditionManager.java | 6 +- .../conditions/GameStageCondition.java | 4 +- .../conditions/IDisplayConditionFactory.java | 3 +- .../guidebook/drawing/VisualPage.java | 2 +- .../guidebook/drawing/VisualStack.java | 2 +- .../guidebook/guidebook/elements/Element.java | 64 +- .../guidebook/elements/ElementBreak.java | 7 + .../guidebook/elements/ElementFactory.java | 7 - .../guidebook/elements/ElementGrid.java | 8 +- .../guidebook/elements/ElementImage.java | 2 +- .../guidebook/elements/ElementInline.java | 2 +- .../guidebook/elements/ElementLink.java | 23 +- .../guidebook/elements/ElementPanel.java | 7 +- .../guidebook/elements/ElementParagraph.java | 32 +- .../guidebook/elements/ElementRecipe.java | 11 +- .../guidebook/elements/ElementSpan.java | 12 +- .../guidebook/elements/ElementStack.java | 2 +- .../guidebook/elements/ElementText.java | 2 +- .../guidebook/elements/ElementTitle.java | 19 + .../guidebook/elements/LinkContext.java | 2 +- .../templates/TemplateDefinition.java | 2 +- .../guidebook/templates/TemplateElement.java | 2 +- .../guidebook/templates/TemplateLibrary.java | 39 +- 48 files changed, 1600 insertions(+), 1249 deletions(-) delete mode 100644 src/main/java/dev/gigaherz/guidebook/guidebook/BookDocument.java delete mode 100644 src/main/java/dev/gigaherz/guidebook/guidebook/ParsingContext.java create mode 100644 src/main/java/dev/gigaherz/guidebook/guidebook/book/BookDocument.java create mode 100644 src/main/java/dev/gigaherz/guidebook/guidebook/book/BookDocumentParser.java create mode 100644 src/main/java/dev/gigaherz/guidebook/guidebook/book/ChapterData.java create mode 100644 src/main/java/dev/gigaherz/guidebook/guidebook/book/DocumentLevelElementParser.java create mode 100644 src/main/java/dev/gigaherz/guidebook/guidebook/book/ElementFactory.java create mode 100644 src/main/java/dev/gigaherz/guidebook/guidebook/book/ElementModifier.java create mode 100644 src/main/java/dev/gigaherz/guidebook/guidebook/book/IParseable.java create mode 100644 src/main/java/dev/gigaherz/guidebook/guidebook/book/InlineElementFactory.java create mode 100644 src/main/java/dev/gigaherz/guidebook/guidebook/book/PageData.java create mode 100644 src/main/java/dev/gigaherz/guidebook/guidebook/book/PageFactory.java create mode 100644 src/main/java/dev/gigaherz/guidebook/guidebook/book/PageGroup.java create mode 100644 src/main/java/dev/gigaherz/guidebook/guidebook/book/ParsingContext.java rename src/main/java/dev/gigaherz/guidebook/guidebook/{ => book}/SectionRef.java (99%) delete mode 100644 src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementFactory.java create mode 100644 src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementTitle.java diff --git a/src/main/java/dev/gigaherz/guidebook/client/ClientAPI.java b/src/main/java/dev/gigaherz/guidebook/client/ClientAPI.java index 7aed26c..1a560af 100644 --- a/src/main/java/dev/gigaherz/guidebook/client/ClientAPI.java +++ b/src/main/java/dev/gigaherz/guidebook/client/ClientAPI.java @@ -1,6 +1,6 @@ package dev.gigaherz.guidebook.client; -import dev.gigaherz.guidebook.guidebook.BookDocument; +import dev.gigaherz.guidebook.guidebook.book.BookDocument; import dev.gigaherz.guidebook.guidebook.BookRegistry; import dev.gigaherz.guidebook.guidebook.client.GuidebookScreen; import net.minecraft.client.Minecraft; diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/BookDocument.java b/src/main/java/dev/gigaherz/guidebook/guidebook/BookDocument.java deleted file mode 100644 index 7f5e2ac..0000000 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/BookDocument.java +++ /dev/null @@ -1,1087 +0,0 @@ -package dev.gigaherz.guidebook.guidebook; - -import com.google.common.base.Strings; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.primitives.Floats; -import dev.gigaherz.guidebook.GuidebookMod; -import dev.gigaherz.guidebook.guidebook.conditions.ConditionContext; -import dev.gigaherz.guidebook.guidebook.conditions.ConditionManager; -import dev.gigaherz.guidebook.guidebook.drawing.VisualChapter; -import dev.gigaherz.guidebook.guidebook.drawing.VisualElement; -import dev.gigaherz.guidebook.guidebook.drawing.VisualPage; -import dev.gigaherz.guidebook.guidebook.drawing.VisualPageBreak; -import dev.gigaherz.guidebook.guidebook.elements.*; -import dev.gigaherz.guidebook.guidebook.templates.TemplateDefinition; -import dev.gigaherz.guidebook.guidebook.templates.TemplateElement; -import dev.gigaherz.guidebook.guidebook.templates.TemplateLibrary; -import dev.gigaherz.guidebook.guidebook.util.Point; -import dev.gigaherz.guidebook.guidebook.util.Rect; -import dev.gigaherz.guidebook.guidebook.util.Size; -import net.minecraft.client.Minecraft; -import net.minecraft.client.resources.model.Material; -import net.minecraft.client.resources.model.ModelResourceLocation; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.inventory.InventoryMenu; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; -import net.minecraftforge.fml.ModList; -import net.minecraftforge.registries.ForgeRegistries; -import org.w3c.dom.Document; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.SAXException; - -import javax.annotation.Nullable; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import java.io.*; -import java.util.*; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.BiConsumer; -import java.util.function.Predicate; - -public class BookDocument -{ - private static final float DEFAULT_FONT_SIZE = 1.0f; - - private float fontSize = 1.0f; - - public SectionRef home = new SectionRef(0, 0); - - private final ResourceLocation bookLocation; - private String bookName; - private ResourceLocation bookCover; - private ResourceLocation bookModel; - - final List chapters = Lists.newArrayList(); - private final Map stackLinks = Maps.newHashMap(); - - final Map chaptersByName = Maps.newHashMap(); - final Map sectionsByName = Maps.newHashMap(); - - private final Map templates = Maps.newHashMap(); - private final Map> conditions = Maps.newHashMap(); - - private IBookGraphics renderingManager; - - private static final Map customElements = Maps.newHashMap(); - private ResourceLocation background; - - public static void registerCustomElement(ResourceLocation location, ElementFactory factory) - { - if (customElements.containsKey(location)) - throw new RuntimeException("Can not register two custom element factories with the same id."); - - customElements.put(location, factory); - } - - static - { - registerCustomElement(new ResourceLocation("minecraft:recipe"), ElementRecipe::new); - registerCustomElement(new ResourceLocation("grid"), ElementGrid::new); - registerCustomElement(new ResourceLocation("space"), ElementPanel::new); - registerCustomElement(new ResourceLocation("group"), ElementPanel::new); - registerCustomElement(new ResourceLocation("panel"), ElementPanel::new); - registerCustomElement(new ResourceLocation("div"), ElementPanel::new); - } - - public BookDocument(ResourceLocation bookLocation) - { - this.bookLocation = bookLocation; - } - - public ResourceLocation getLocation() - { - return bookLocation; - } - - @Nullable - public String getName() - { - return bookName; - } - - @Nullable - public ResourceLocation getCover() - { - return bookCover; - } - - @Nullable - public ResourceLocation getModel() - { - return bookModel; - } - - @Nullable - public ResourceLocation getBackground() - { - return background; - } - - @Nullable - public IBookGraphics getRendering() - { - return renderingManager; - } - - public void setRendering(IBookGraphics rendering) - { - this.renderingManager = rendering; - } - - public ChapterData getChapter(int i) - { - return chapters.get(i); - } - - @Nullable - public SectionRef getStackLink(ItemStack stack) - { - Item item = stack.getItem(); - return stackLinks.get(item); - } - - public float getFontSize() - { - return fontSize; - } - - public int chapterCount() - { - return chapters.size(); - } - - public void findTextures(Set textures) - { - if (bookCover != null) - textures.add(new Material(InventoryMenu.BLOCK_ATLAS, bookCover)); - - for (ChapterData chapter : chapters) - { - for (PageData page : chapter.sections) - { - for (Element element : page.elements) - { - element.findTextures(textures); - } - } - } - } - - public void initializeWithLoadError(String error) - { - ChapterData ch = new ChapterData(0); - chapters.add(ch); - - PageData pg = new PageData(new SectionRef(0, 0)); - ch.sections.add(pg); - - pg.elements.add(ElementParagraph.of("Error loading book:", TextStyle.ERROR)); - pg.elements.add(ElementParagraph.of(error, TextStyle.ERROR)); - } - - @SuppressWarnings({"BooleanMethodIsAlwaysInverted", "UnstableApiUsage"}) - public boolean parseBook(InputStream stream, boolean loadedFromConfigFolder) - { - try - { - chapters.clear(); - bookName = ""; - bookCover = null; - fontSize = DEFAULT_FONT_SIZE; - chaptersByName.clear(); - - DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); - DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); - Document doc = dBuilder.parse(stream); - - var parsingContext = new ParsingContext() - { - - @Override - public Predicate getCondition(String name) - { - return BookDocument.this.getCondition(name); - } - - @Override - public boolean loadedFromConfigFolder() - { - return loadedFromConfigFolder; - } - - @Override - public DocumentBuilder xmlDocumentBuilder() - { - return dBuilder; - } - }; - - doc.getDocumentElement().normalize(); - - Node root = doc.getChildNodes().item(0); - - if (root.hasAttributes()) - { - NamedNodeMap attributes = root.getAttributes(); - Node n = attributes.getNamedItem("title"); - if (n != null) - { - bookName = n.getTextContent(); - } - n = attributes.getNamedItem("cover"); - if (n != null) - { - bookCover = new ResourceLocation(n.getTextContent()); - } - n = attributes.getNamedItem("model"); - if (n != null) - { - var text = n.getTextContent(); - if (text.contains("#")) - bookModel = new ModelResourceLocation(text); - else - bookModel = new ResourceLocation(text); - } - n = attributes.getNamedItem("background"); - if (n != null) - { - background = new ResourceLocation(n.getTextContent()); - } - n = attributes.getNamedItem("fontSize"); - if (n != null) - { - Float f = Floats.tryParse(n.getTextContent()); - fontSize = f != null ? f : DEFAULT_FONT_SIZE; - } - n = attributes.getNamedItem("home"); - if (n != null) - { - String ref = n.getTextContent(); - home = SectionRef.fromString(ref); - } - n = attributes.getNamedItem("dependencies"); - if (n != null) - { - for (String s : n.getTextContent().split(",")) - { - if (!ModList.get().isLoaded(s)) - { - initializeWithLoadError("Dependency not loaded: " + s); - return false; - } - } - } - } - - parseDocumentLevelElements(parsingContext, root.getChildNodes()); - } - catch (IOException | ParserConfigurationException | SAXException e) - { - initializeWithLoadError(e.toString()); - } - return true; - } - - private static final Map includeCache = new HashMap<>(); - - private void parseDocumentLevelElements(ParsingContext context, NodeList firstLevel) - { - AtomicInteger chapterNumber = new AtomicInteger(0); - for (int i = 0; i < firstLevel.getLength(); i++) - { - Node firstLevelNode = firstLevel.item(i); - - parseDocumentLevelElement(context, chapterNumber, firstLevelNode); - } - } - - private void parseDocumentLevelElement(ParsingContext context, AtomicInteger chapterNumber, Node firstLevelNode) - { - String nodeName = firstLevelNode.getNodeName(); - switch (nodeName) - { - case "template" -> parseTemplateDefinition(context, firstLevelNode, templates); - case "include" -> parseInclude(context, firstLevelNode, (resLoc, document) -> { - var includeRoot = document.getDocumentElement(); - if (includeRoot.getTagName().equals("library")) - { - TemplateLibrary tpl = TemplateLibrary.get(context, resLoc, document); - templates.putAll(tpl.templates); - } - else - { - parseDocumentLevelElement(context, chapterNumber, includeRoot); - } - }); - case "chapter" -> parseChapter(context, chapterNumber.getAndIncrement(), firstLevelNode); - case "stack-links" -> parseStackLinks(firstLevelNode); - case "conditions" -> parseConditions(firstLevelNode); - } - } - - private static void parseInclude(ParsingContext context, Node firstLevelNode, BiConsumer includeAction) - { - NamedNodeMap attributes = firstLevelNode.getAttributes(); - Node n = attributes.getNamedItem("ref"); - - ResourceLocation id = new ResourceLocation(n.getTextContent()); - Document include = includeCache.computeIfAbsent(id, resLoc -> { - - // Prevents loading includes from config folder if the book was found in resource packs. - if (context.loadedFromConfigFolder() && resLoc.getNamespace().equals("gbook")) - { - File booksFolder = BookRegistry.getBooksFolder(); - File file = new File(booksFolder, resLoc.getPath()); - if (file.exists() && file.isFile()) - { - try (InputStream stream = new FileInputStream(file)) - { - return context.xmlDocumentBuilder().parse(stream); - } - catch (FileNotFoundException e) - { - // WUT? continue and try to load from resource pack - } - catch (IOException e) - { - throw new UncheckedIOException(e); - } - catch (SAXException e) - { - throw new RuntimeException(e); - } - } - } - - try - { - var res = Minecraft.getInstance().getResourceManager().getResourceOrThrow(resLoc); - try (InputStream stream = res.open()) - { - return context.xmlDocumentBuilder().parse(stream); - } - catch (IOException e) - { - throw new UncheckedIOException(e); - } - catch (SAXException e) - { - throw new RuntimeException(e); - } - } - catch (FileNotFoundException e) - { - throw new UncheckedIOException(e); - } - }); - - includeAction.accept(id, include); - } - - private void parseConditions(Node node) - { - NodeList children = node.getChildNodes(); - for (int i = 0; i < children.getLength(); i++) - { - Node condition = children.item(i); - if (condition.getNodeType() != Node.ELEMENT_NODE) - continue; - - NamedNodeMap attributes = condition.getAttributes(); - - Node conditionName = attributes.getNamedItem("name"); - String name = conditionName != null ? conditionName.getTextContent() : null; - - if (Strings.isNullOrEmpty(name)) - { - throw new BookParsingException("Condition node found without a name attribute"); - } - - Predicate displayCondition = parseSingleCondition(this, condition); - - conditions.put(name, displayCondition); - } - } - - public static List> parseChildConditions(BookDocument context, Node node) - { - List> conditions = Lists.newArrayList(); - NodeList children = node.getChildNodes(); - for (int i = 0; i < children.getLength(); i++) - { - Node condition = children.item(i); - if (condition.getNodeType() != Node.ELEMENT_NODE) - continue; - - Predicate displayCondition = parseSingleCondition(context, condition); - - conditions.add(displayCondition); - } - return conditions; - } - - private static Predicate parseSingleCondition(BookDocument context, Node condition) - { - Predicate displayCondition; - try - { - displayCondition = ConditionManager.parseCondition(context, condition); - if (displayCondition == null) - { - throw new BookParsingException("Condition not found"); - } - } - catch (Exception e) - { - throw new BookParsingException("Exception parsing condition", e); - } - return displayCondition; - } - - private void parseTemplateDefinition(ParsingContext context, Node templateItem, Map templates) - { - if (!templateItem.hasAttributes()) - return; // TODO: Throw error - - TemplateDefinition page = new TemplateDefinition(); - - NamedNodeMap attributes = templateItem.getAttributes(); - Node n = attributes.getNamedItem("id"); - if (n == null) - return; - - templates.put(n.getTextContent(), page); - - parseChildElements(context, templateItem.getChildNodes(), page.elements, templates, true, TextStyle.DEFAULT); - - attributes.removeNamedItem("id"); - page.attributes = attributes; - } - - private void parseChapter(ParsingContext context, int chapterNumber, Node chapterItem) - { - ChapterData chapter = new ChapterData(chapters.size()); - chapters.add(chapter); - - if (chapterItem.hasAttributes()) - { - NamedNodeMap attributes = chapterItem.getAttributes(); - Node n = attributes.getNamedItem("id"); - if (n != null) - { - chapter.id = n.getTextContent(); - chaptersByName.put(chapter.id, chapter.num); - } - - n = attributes.getNamedItem("condition"); - if (n != null) - { - chapter.condition = conditions.get(n.getTextContent()); - } - } - - AtomicInteger sectionNumber = new AtomicInteger(0); - NodeList pagesList = chapterItem.getChildNodes(); - for (int j = 0; j < pagesList.getLength(); j++) - { - Node pageItem = pagesList.item(j); - - parseChapterElement(context, chapterNumber, chapter, sectionNumber, pageItem); - } - } - - private void parseChapterElement(ParsingContext context, int chapterNumber, ChapterData chapter, AtomicInteger sectionNumber, Node pageItem) - { - switch (pageItem.getNodeName()) - { - case "page" -> parsePage(context, chapter, new SectionRef(chapterNumber, sectionNumber.getAndIncrement()), pageItem); - case "section" -> parseSection(context, chapter, new SectionRef(chapterNumber, sectionNumber.getAndIncrement()), pageItem); - case "include" -> parseInclude(context, pageItem, (name, document) -> parseChapterElement(context, chapterNumber, chapter, sectionNumber, document.getDocumentElement())); - } - } - - private void parsePage(ParsingContext context, ChapterData chapter, SectionRef ref, Node pageItem) - { - PageData page = new PageData(ref); - parseSection(context, chapter, pageItem, page); - } - - private void parseSection(ParsingContext context, ChapterData chapter, SectionRef ref, Node pageItem) - { - PageData page = new PageGroup(ref); - parseSection(context, chapter, pageItem, page); - } - - private void parseSection(ParsingContext context, ChapterData chapter, Node pageItem, PageData page) - { - int num = chapter.sections.size(); - chapter.sections.add(page); - - if (pageItem.hasAttributes()) - { - NamedNodeMap attributes = pageItem.getAttributes(); - Node n = attributes.getNamedItem("id"); - if (n != null) - { - page.id = n.getTextContent(); - sectionsByName.put(page.id, new SectionRef(chapter.num, num)); - chapter.sectionsByName.put(page.id, num); - } - - n = attributes.getNamedItem("condition"); - if (n != null) - { - page.condition = conditions.get(n.getTextContent()); - } - } - - parseChildElements(context, pageItem.getChildNodes(), page.elements, templates, true, TextStyle.DEFAULT); - } - - public static void parseChildElements(ParsingContext context, NodeList elementsList, List elements, Map templates, - boolean generateParagraphs, TextStyle defaultStyle) - { - for (int k = 0; k < elementsList.getLength(); k++) - { - boolean isFirstElement = k == 0; - boolean isLastElement = (k + 1) == elementsList.getLength(); - - Node elementItem = elementsList.item(k); - - parsePageElement(context, elements, templates, generateParagraphs, defaultStyle, isFirstElement, isLastElement, elementItem); - } - } - - private static void parsePageElement(ParsingContext context, List elements, Map templates, boolean generateParagraphs, - TextStyle defaultStyle, boolean isFirstElement, boolean isLastElement, Node elementItem) - { - Element parsedElement = null; - - String nodeName = elementItem.getNodeName(); - ResourceLocation nodeLoc = - elementItem.getNodeType() == Node.ELEMENT_NODE ? - new ResourceLocation(nodeName) : new ResourceLocation("_"); - - switch (nodeName) - { - case "section-break" -> parsedElement = new ElementBreak(); - case "include" -> parseInclude(context, elementItem, (name,document) -> - parsePageElement(context, elements, templates, generateParagraphs, defaultStyle, isFirstElement, isLastElement, document.getDocumentElement()) - ); - case "p", "title" -> { - ElementParagraph p = new ElementParagraph(); - - TextStyle tagDefaults = defaultStyle; - if (nodeName.equals("title")) - { - p.alignment = ElementParagraph.ALIGN_CENTER; - p.space = 4; - tagDefaults = new TextStyle(defaultStyle.color, true, false, true, false, false, null, 1.0f); - } - - TextStyle paragraphDefautls = TextStyle.parse(elementItem.getAttributes(), tagDefaults); - - NodeList childList = elementItem.getChildNodes(); - for (int q = 0; q < childList.getLength(); q++) - { - Node childNode = childList.item(q); - ElementInline parsedChild = parseParagraphElement(context, childNode, childNode.getNodeName(), isFirstElement, isLastElement, paragraphDefautls); - - if (parsedChild == null) - { - GuidebookMod.logger.warn("Unrecognized tag: {}", childNode.getNodeName()); - } - else - { - p.inlines.add(parsedChild); - } - } - - if (elementItem.hasAttributes()) - { - p.parse(context, elementItem.getAttributes()); - } - - parsedElement = p; - } - default -> { - if (customElements.containsKey(nodeLoc)) - { - ElementFactory factory = customElements.get(nodeLoc); - - Element t = factory.newInstance(); - - if (elementItem.hasAttributes()) - { - t.parse(context, elementItem.getAttributes()); - } - - if (elementItem.hasChildNodes()) - { - t.parseChildNodes(context, elementItem.getChildNodes(), templates, defaultStyle); - } - - parsedElement = t; - } - else if (templates.containsKey(nodeName)) - { - TemplateDefinition tDef = templates.get(nodeName); - - ElementPanel t = new ElementPanel(); - t.parse(context, tDef.attributes); - - if (elementItem.hasAttributes()) - { - t.parse(context, elementItem.getAttributes()); - } - - List elementList = Lists.newArrayList(); - - parseChildElements(context, elementItem.getChildNodes(), elementList, templates, false, defaultStyle); - - List effectiveList = tDef.applyTemplate(context, elementList); - - t.innerElements.addAll(effectiveList); - - parsedElement = t; - } - else if (elementItem.getNodeType() == Node.TEXT_NODE) - { - if (generateParagraphs) - { - String textContent = ElementText.compactString(elementItem.getTextContent(), isFirstElement, isLastElement); - if (!Strings.isNullOrEmpty(textContent) && !textContent.matches("^[ \t\r\n]+$")) - parsedElement = ElementSpan.of(textContent, defaultStyle); - } - } - else if (elementItem.getNodeType() != Node.COMMENT_NODE) - { - parsedElement = parseParagraphElement(context, elementItem, nodeName, isFirstElement, isLastElement, defaultStyle); - - if (parsedElement == null) - { - GuidebookMod.logger.warn("Unrecognized tag: {}", nodeName); - } - } - } - } - - if (parsedElement == null) return; - - if (!parsedElement.supportsPageLevel() && generateParagraphs && parsedElement instanceof ElementInline) - { - ElementParagraph p = new ElementParagraph(); - - if (elementItem.hasAttributes()) - { - p.parse(context, elementItem.getAttributes()); - parsedElement.parse(context, elementItem.getAttributes()); - } - - p.inlines.add((ElementInline) parsedElement); - - parsedElement = p; - } - - if (parsedElement.supportsPageLevel()) - elements.add(parsedElement); - } - - @Nullable - public static ElementInline parseParagraphElement(ParsingContext context, Node elementItem, String nodeName, boolean isFirstElement, boolean isLastElement, TextStyle defaultStyle) - { - return switch (nodeName) - { - case "span" -> - { - ElementSpan span = new ElementSpan(isFirstElement, isLastElement); - - if (elementItem.hasAttributes()) - { - span.parse(context, elementItem.getAttributes()); - } - - if (elementItem.hasChildNodes()) - { - TextStyle spanDefaults = TextStyle.parse(elementItem.getAttributes(), defaultStyle); - - List elementList = Lists.newArrayList(); - - parseRunElements(context, elementItem, elementList, spanDefaults); - - span.inlines.addAll(elementList); - } - - yield span; - } - case "link", "a" -> - { - ElementLink link = new ElementLink(isFirstElement, isLastElement); - - if (elementItem.hasAttributes()) - { - link.parse(context, elementItem.getAttributes()); - } - - if (elementItem.hasChildNodes()) - { - TextStyle spanDefaults = TextStyle.parse(elementItem.getAttributes(), TextStyle.LINK); - - List elementList = Lists.newArrayList(); - - parseRunElements(context, elementItem, elementList, spanDefaults); - - link.inlines.addAll(elementList); - } - - yield link; - } - case "stack" -> - { - ElementStack s = new ElementStack(isFirstElement, isLastElement); - - if (elementItem.hasAttributes()) - { - s.parse(context, elementItem.getAttributes()); - } - - yield s; - } - case "image" -> - { - ElementImage i = new ElementImage(isFirstElement, isLastElement); - - if (elementItem.hasAttributes()) - { - i.parse(context, elementItem.getAttributes()); - } - - yield i; - } - case "element" -> - { - TemplateElement i = new TemplateElement(isFirstElement, isLastElement); - - if (elementItem.hasAttributes()) - { - i.parse(context, elementItem.getAttributes()); - } - - yield i; - } - default -> - { - if (elementItem.getNodeType() == Node.TEXT_NODE) - { - String textContent = ElementText.compactString(elementItem.getTextContent(), isFirstElement, isLastElement); - if (!Strings.isNullOrEmpty(textContent)) - { - yield ElementSpan.of(textContent, isFirstElement, isLastElement, defaultStyle); - } - } - yield null; - } - }; - } - - public static void parseRunElements(ParsingContext context, Node pageItem, List elements, TextStyle defaultStyle) - { - NodeList elementsList = pageItem.getChildNodes(); - for (int k = 0; k < elementsList.getLength(); k++) - { - boolean isFirstElement = k == 0; - boolean isLastElement = (k + 1) == elementsList.getLength(); - - Node elementItem = elementsList.item(k); - - ElementInline parsedElement = null; - - String nodeName = elementItem.getNodeName(); - ResourceLocation nodeLoc = - elementItem.getNodeType() == Node.ELEMENT_NODE ? - new ResourceLocation(nodeName) : new ResourceLocation("_"); - - if (customElements.containsKey(nodeLoc)) - { - ElementFactory factory = customElements.get(nodeLoc); - - Element t = factory.newInstance(); - - if (t instanceof ElementInline inline) - { - if (elementItem.hasAttributes()) - { - inline.parse(context, elementItem.getAttributes()); - } - - if (elementItem.hasChildNodes()) - { - inline.parseChildNodes(context, elementItem.getChildNodes(), Collections.emptyMap(), defaultStyle); - } - - parsedElement = inline; - } - } - else if (elementItem.getNodeType() == Node.TEXT_NODE) - { - String textContent = ElementText.compactString(elementItem.getTextContent(), isFirstElement, isLastElement); - if (!Strings.isNullOrEmpty(textContent)) - parsedElement = ElementSpan.of(textContent, isFirstElement, isLastElement, defaultStyle); - } - else if (elementItem.getNodeType() != Node.COMMENT_NODE) - { - parsedElement = parseParagraphElement(context, elementItem, nodeName, isFirstElement, isLastElement, defaultStyle); - - if (parsedElement == null) - { - GuidebookMod.logger.warn("Unrecognized tag: {}", nodeName); - } - } - - if (parsedElement != null) - { - elements.add(parsedElement); - } - } - } - - private void parseStackLinks(Node refsItem) - { - NodeList refsList = refsItem.getChildNodes(); - for (int j = 0; j < refsList.getLength(); j++) - { - Node refItem = refsList.item(j); - String nodeName = refItem.getNodeName(); - - if (nodeName.equals("stack")) - { - if (refItem.hasAttributes()) - { - Node item_node = refItem.getAttributes().getNamedItem("item"); //get item - if (item_node != null) - { - Item item = ForgeRegistries.ITEMS.getValue(new ResourceLocation(item_node.getTextContent())); - if (item != null) - { - String ref = refItem.getTextContent(); - stackLinks.put(item, SectionRef.fromString(ref)); - } - } - } - } - } - } - - public Predicate getCondition(String name) - { - return conditions.get(name); - } - - public boolean reevaluateConditions(ConditionContext ctx) - { - boolean anyChanged = false; - for (ChapterData chapter : chapters) - { - anyChanged |= chapter.reevaluateConditions(ctx); - } - - return anyChanged; - } - - public static class ChapterData - { - public final int num; - public String id; - public Predicate condition; - public boolean conditionResult; - - public final List sections = Lists.newArrayList(); - public final Map sectionsByName = Maps.newHashMap(); - - private ChapterData(int num) - { - this.num = num; - } - - public boolean reevaluateConditions(ConditionContext ctx) - { - boolean oldValue = conditionResult; - conditionResult = condition == null || condition.test(ctx); - - boolean anyChanged = conditionResult != oldValue; - for (PageData section : sections) - { - anyChanged |= section.reevaluateConditions(ctx); - } - - return anyChanged; - } - - public void reflow(IBookGraphics rendering, VisualChapter ch, Size pageSize) - { - for (PageData section : sections) - { - if (!section.conditionResult || section.isEmpty()) - continue; - - if (!Strings.isNullOrEmpty(section.id)) - ch.pagesByName.put(section.id, ch.pages.size()); - - ch.pages.addAll(section.reflow(rendering, pageSize)); - } - } - - public boolean isEmpty() - { - return sections.stream().noneMatch(s -> s.conditionResult && !s.isEmpty()); - } - } - - public static class PageData - { - public final SectionRef ref; - public String id; - public Predicate condition; - public boolean conditionResult; - - public final List elements = Lists.newArrayList(); - - public PageData(SectionRef ref) - { - this.ref = ref; - } - - public List reflow(IBookGraphics rendering, Size pageSize) - { - VisualPage page = new VisualPage(ref); - Rect pageBounds = new Rect(new Point(), pageSize); - - int top = 0; - for (Element element : elements) - { - if (element.conditionResult) - top = element.reflow(page.children, rendering, new Rect(new Point(0, top), pageSize), pageBounds); - } - - return Collections.singletonList(page); - } - - public boolean reevaluateConditions(ConditionContext ctx) - { - boolean oldValue = conditionResult; - conditionResult = condition == null || condition.test(ctx); - - boolean anyChanged = conditionResult != oldValue; - for (Element element : elements) - { - anyChanged |= element.reevaluateConditions(ctx); - } - - return anyChanged; - } - - public boolean isEmpty() - { - return elements.stream().noneMatch(e -> e.conditionResult); - } - } - - /** - * This class represents a group of pages clearly delimited by start/end of chapters, sections, or explicit section braks. - * Example: - * - * - *
- * Group 1 - *
- *
- * Group 2 - *
- *
- * - * Group 3 - * - * Group 4 - * - *
- */ - public static class PageGroup extends PageData - { - public PageGroup(SectionRef ref) - { - super(ref); - } - - @Override - public List reflow(IBookGraphics rendering, Size pageSize) - { - List pages = Lists.newArrayList(); - - VisualPage page = new VisualPage(ref); - Rect pageBounds = new Rect(new Point(0, 0), pageSize); - - int top = pageBounds.position.y; - for (Element element : elements) - { - if (element.conditionResult) - top = element.reflow(page.children, rendering, new Rect(new Point(pageBounds.position.x, top), pageBounds.size), pageBounds); - } - - boolean needsRepagination = false; - for (VisualElement child : page.children) - { - if (child instanceof VisualPageBreak || (child.position.y + child.size.height > (pageBounds.position.y + pageBounds.size.height))) - { - needsRepagination = true; - break; - } - } - - if (needsRepagination) - { - VisualPage page2 = new VisualPage(ref); - - int offsetY = 0; - boolean pageBreakRequired = false; - for (VisualElement child : page.children) - { - int cpy = child.position.y + offsetY; - if (pageBreakRequired || (cpy + child.size.height > (pageBounds.position.y + pageBounds.size.height) - && child.position.y > pageBounds.position.y)) - { - pages.add(page2); - page2 = new VisualPage(ref); - - offsetY = pageBounds.position.y - child.position.y; - pageBreakRequired = false; - } - - if (child instanceof VisualPageBreak) - { - pageBreakRequired = true; - } - else - { - child.position = new Point( - child.position.x, - child.position.y + offsetY); - page2.children.add(child); - } - } - - pages.add(page2); - } - else - { - pages.add(page); - } - - return pages; - } - } -} diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/BookRegistry.java b/src/main/java/dev/gigaherz/guidebook/guidebook/BookRegistry.java index 8e16268..78f4fc9 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/BookRegistry.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/BookRegistry.java @@ -5,10 +5,10 @@ import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import dev.gigaherz.guidebook.GuidebookMod; +import dev.gigaherz.guidebook.guidebook.book.BookDocument; +import dev.gigaherz.guidebook.guidebook.book.BookDocumentParser; import dev.gigaherz.guidebook.guidebook.templates.TemplateLibrary; import net.minecraft.client.Minecraft; -import net.minecraft.client.resources.language.LanguageManager; -import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.FolderPackResources; @@ -82,6 +82,8 @@ public static void parseAllBooks(ResourceManager manager) LOADED_BOOKS.clear(); + BookDocumentParser.invalidateIncludeCache(); + Set toLoad = Sets.newHashSet(REGISTRY); for (String domain : manager.getNamespaces()) @@ -170,8 +172,7 @@ private static BookDocument parseBook(ResourceManager manager, ResourceLocation } try (InputStream stream = bookResource.open()) { - if (!bookDocument.parseBook(stream, false)) - return null; + return BookDocumentParser.parseBook(bookDocument, stream, false); } } catch (IOException e) @@ -185,13 +186,11 @@ private static BookDocument parseBook(ResourceManager manager, ResourceLocation private static BookDocument parseBook(ResourceLocation location, File file) { BookDocument bookDocument = new BookDocument(location); - try + try(InputStream stream = new FileInputStream(file)) { - InputStream stream = new FileInputStream(file); - if (!bookDocument.parseBook(stream, true)) - return null; + return BookDocumentParser.parseBook(bookDocument, stream, true); } - catch (Exception e) + catch (IOException e) { bookDocument.initializeWithLoadError(e.toString()); } diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/IBookGraphics.java b/src/main/java/dev/gigaherz/guidebook/guidebook/IBookGraphics.java index c2069af..67b7e54 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/IBookGraphics.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/IBookGraphics.java @@ -1,6 +1,8 @@ package dev.gigaherz.guidebook.guidebook; import com.mojang.blaze3d.vertex.PoseStack; +import dev.gigaherz.guidebook.guidebook.book.BookDocument; +import dev.gigaherz.guidebook.guidebook.book.SectionRef; import dev.gigaherz.guidebook.guidebook.drawing.VisualElement; import dev.gigaherz.guidebook.guidebook.util.Size; import net.minecraft.network.chat.Component; diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/ParsingContext.java b/src/main/java/dev/gigaherz/guidebook/guidebook/ParsingContext.java deleted file mode 100644 index 544efc9..0000000 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/ParsingContext.java +++ /dev/null @@ -1,13 +0,0 @@ -package dev.gigaherz.guidebook.guidebook; - -import dev.gigaherz.guidebook.guidebook.conditions.ConditionContext; - -import javax.xml.parsers.DocumentBuilder; -import java.util.function.Predicate; - -public interface ParsingContext -{ - Predicate getCondition(String name); - boolean loadedFromConfigFolder(); - DocumentBuilder xmlDocumentBuilder(); -} diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/book/BookDocument.java b/src/main/java/dev/gigaherz/guidebook/guidebook/book/BookDocument.java new file mode 100644 index 0000000..e80e834 --- /dev/null +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/book/BookDocument.java @@ -0,0 +1,166 @@ +package dev.gigaherz.guidebook.guidebook.book; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import dev.gigaherz.guidebook.guidebook.IBookGraphics; +import dev.gigaherz.guidebook.guidebook.conditions.ConditionContext; +import dev.gigaherz.guidebook.guidebook.elements.Element; +import dev.gigaherz.guidebook.guidebook.elements.ElementParagraph; +import dev.gigaherz.guidebook.guidebook.elements.TextStyle; +import dev.gigaherz.guidebook.guidebook.templates.TemplateDefinition; +import net.minecraft.client.resources.model.Material; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.inventory.InventoryMenu; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; + +import javax.annotation.Nullable; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Predicate; + +public class BookDocument +{ + + float fontSize = 1.0f; + + public SectionRef home = new SectionRef(0, 0); + + private final ResourceLocation bookLocation; + String bookName; + ResourceLocation bookCover; + ResourceLocation bookModel; + + final List chapters = Lists.newArrayList(); + final Map stackLinks = Maps.newHashMap(); + + final Map chaptersByName = Maps.newHashMap(); + final Map sectionsByName = Maps.newHashMap(); + + final Map templates = Maps.newHashMap(); + final Map> conditions = Maps.newHashMap(); + + private IBookGraphics renderingManager; + + ResourceLocation background; + ResourceLocation widgets; + + public BookDocument(ResourceLocation bookLocation) + { + this.bookLocation = bookLocation; + } + + public ResourceLocation getLocation() + { + return bookLocation; + } + + @Nullable + public String getName() + { + return bookName; + } + + @Nullable + public ResourceLocation getCover() + { + return bookCover; + } + + @Nullable + public ResourceLocation getModel() + { + return bookModel; + } + + @Nullable + public ResourceLocation getBackground() + { + return background; + } + + @Nullable + public ResourceLocation getWidgets() + { + return widgets; + } + + @Nullable + public IBookGraphics getRendering() + { + return renderingManager; + } + + public void setRendering(IBookGraphics rendering) + { + this.renderingManager = rendering; + } + + public ChapterData getChapter(int i) + { + return chapters.get(i); + } + + @Nullable + public SectionRef getStackLink(ItemStack stack) + { + Item item = stack.getItem(); + return stackLinks.get(item); + } + + public float getFontSize() + { + return fontSize; + } + + public int chapterCount() + { + return chapters.size(); + } + + public void findTextures(Set textures) + { + if (bookCover != null) + textures.add(new Material(InventoryMenu.BLOCK_ATLAS, bookCover)); + + for (ChapterData chapter : chapters) + { + for (PageData page : chapter.sections) + { + for (Element element : page.elements) + { + element.findTextures(textures); + } + } + } + } + + public void initializeWithLoadError(String error) + { + ChapterData ch = new ChapterData(0); + chapters.add(ch); + + PageData pg = new PageData(new SectionRef(0, 0)); + ch.sections.add(pg); + + pg.elements.add(ElementParagraph.of("Error loading book:", TextStyle.ERROR)); + pg.elements.add(ElementParagraph.of(error, TextStyle.ERROR)); + } + + public Predicate getCondition(String name) + { + return conditions.get(name); + } + + public boolean reevaluateConditions(ConditionContext ctx) + { + boolean anyChanged = false; + for (ChapterData chapter : chapters) + { + anyChanged |= chapter.reevaluateConditions(ctx); + } + + return anyChanged; + } +} diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/book/BookDocumentParser.java b/src/main/java/dev/gigaherz/guidebook/guidebook/book/BookDocumentParser.java new file mode 100644 index 0000000..5327a92 --- /dev/null +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/book/BookDocumentParser.java @@ -0,0 +1,795 @@ +package dev.gigaherz.guidebook.guidebook.book; + +import com.google.common.base.Strings; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.primitives.Floats; +import dev.gigaherz.guidebook.GuidebookMod; +import dev.gigaherz.guidebook.guidebook.BookParsingException; +import dev.gigaherz.guidebook.guidebook.BookRegistry; +import dev.gigaherz.guidebook.guidebook.conditions.ConditionContext; +import dev.gigaherz.guidebook.guidebook.conditions.ConditionManager; +import dev.gigaherz.guidebook.guidebook.elements.*; +import dev.gigaherz.guidebook.guidebook.templates.TemplateDefinition; +import dev.gigaherz.guidebook.guidebook.templates.TemplateElement; +import dev.gigaherz.guidebook.guidebook.templates.TemplateLibrary; +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.model.ModelResourceLocation; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; +import net.minecraftforge.fml.ModList; +import net.minecraftforge.registries.ForgeRegistries; +import org.w3c.dom.Document; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +import javax.annotation.Nullable; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BiConsumer; +import java.util.function.Predicate; + +public class BookDocumentParser +{ + private static final float DEFAULT_FONT_SIZE = 1.0f; + + private static final Map documentLevelElements = Maps.newHashMap(); + private static final Map inlineElements = Maps.newHashMap(); + private static final Map elements = Maps.newHashMap(); + private static final Map pages = Maps.newHashMap(); + private static final Map modifiers = Maps.newHashMap(); + private static final Map includeCache = Maps.newHashMap(); + + static { + registerDefaultPage("page", PageData::new); + registerDefaultPage("section", PageGroup::new); + registerDefaultElement("recipe", ElementRecipe::new); + registerDefaultElement("grid", ElementGrid::new); + registerDefaultElement("space", ElementPanel::new); + registerDefaultElement("group", ElementPanel::new); + registerDefaultElement("panel", ElementPanel::new); + registerDefaultElement("div", ElementPanel::new); + registerDefaultElement("section-break", ElementBreak::new); + registerDefaultElement("p", ElementParagraph::new); + registerDefaultElement("title", ElementTitle::new); + registerDefaultInlineElement("span", ElementSpan::new); + registerDefaultInlineElement("link", ElementLink::new); + registerDefaultInlineElement("a", ElementLink::new); + registerDefaultInlineElement("stack", ElementStack::new); + registerDefaultInlineElement("image", ElementImage::new); + registerDefaultInlineElement("element", TemplateElement::new); + registerDefaultDocumentLevelElement("template", (context, chapterNumber, node) -> parseTemplateDefinition(context, node, context.document().templates)); + registerDefaultDocumentLevelElement("stack-links", (context, chapterNumber, node) -> parseStackLinks(context, node)); + registerDefaultDocumentLevelElement("conditions", (context, chapterNumber, node) -> parseConditions(context, node)); + registerDefaultDocumentLevelElement("chapter", (context, chapterNumber, node) -> parseChapter(context, chapterNumber.getAndIncrement(), node)); + } + + public static void registerCustomElement(ResourceLocation location, ElementFactory factory) + { + if (elements.containsKey(location)) + { + throw new IllegalArgumentException("Can not register two custom element factories with the same id."); + } + + elements.put(location, factory); + } + + public static void registerCustomInlineElement(ResourceLocation location, InlineElementFactory factory) + { + if (inlineElements.containsKey(location)) + { + throw new IllegalArgumentException("Can not register two custom inline element factories with the same id."); + } + + inlineElements.put(location, factory); + } + + public static void registerCustomPage(ResourceLocation location, PageFactory factory) + { + if (pages.containsKey(location)) + { + throw new IllegalArgumentException("Can not register two page factories with the same id."); + } + + pages.put(location, factory); + } + + public static void registerCustomDocumentLevelElement(ResourceLocation location, DocumentLevelElementParser parser) + { + if (documentLevelElements.containsKey(location)) + { + throw new IllegalArgumentException("Can not register two document level element parser with the same id."); + } + + documentLevelElements.put(location, parser); + } + + public static void registerCustomDocumentLevelElement(ResourceLocation location, ElementModifier modifier) + { + if (modifiers.containsKey(location)) + { + throw new IllegalArgumentException("Can not register two element modifier with the same id."); + } + + modifiers.put(location, modifier); + } + + public static void invalidateIncludeCache() + { + includeCache.clear(); + } + + @SuppressWarnings({"BooleanMethodIsAlwaysInverted", "UnstableApiUsage"}) + @Nullable + public static BookDocument parseBook(BookDocument document, InputStream stream, boolean loadedFromConfigFolder) + { + try + { + document.chapters.clear(); + document.bookName = ""; + document.bookCover = null; + document.fontSize = DEFAULT_FONT_SIZE; + document.chaptersByName.clear(); + + DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); + Document doc = dBuilder.parse(stream); + + var parsingContext = new ParsingContext() + { + @Override + public boolean loadedFromConfigFolder() + { + return loadedFromConfigFolder; + } + + @Override + public DocumentBuilder xmlDocumentBuilder() + { + return dBuilder; + } + + @Override + public BookDocument document() + { + return document; + } + }; + + doc.getDocumentElement().normalize(); + + Node root = doc.getChildNodes().item(0); + + if (root.hasAttributes()) + { + NamedNodeMap attributes = root.getAttributes(); + Node n = attributes.getNamedItem("title"); + if (n != null) + { + document.bookName = n.getTextContent(); + } + n = attributes.getNamedItem("cover"); + if (n != null) + { + document.bookCover = new ResourceLocation(n.getTextContent()); + } + n = attributes.getNamedItem("model"); + if (n != null) + { + var text = n.getTextContent(); + if (text.contains("#")) + { + document.bookModel = new ModelResourceLocation(text); + } + else + { + document.bookModel = new ResourceLocation(text); + } + } + n = attributes.getNamedItem("background"); + if (n != null) + { + document.background = new ResourceLocation(n.getTextContent()); + } + n = attributes.getNamedItem("widgets"); + if (n != null) + { + document.widgets = new ResourceLocation(n.getTextContent()); + } + n = attributes.getNamedItem("fontSize"); + if (n != null) + { + Float f = Floats.tryParse(n.getTextContent()); + document.fontSize = f != null ? f : DEFAULT_FONT_SIZE; + } + n = attributes.getNamedItem("home"); + if (n != null) + { + String ref = n.getTextContent(); + document.home = SectionRef.fromString(ref); + } + n = attributes.getNamedItem("dependencies"); + if (n != null) + { + for (String s : n.getTextContent().split(",")) + { + if (!ModList.get().isLoaded(s)) + { + document.initializeWithLoadError("Dependency not loaded: " + s); + return null; + } + } + } + } + + parseDocumentLevelElements(parsingContext, root.getChildNodes()); + } + catch (IOException | ParserConfigurationException | SAXException e) + { + document.initializeWithLoadError(e.toString()); + } + return document; + } + + public static void parseTemplateDefinition(ParsingContext context, Node templateItem, Map templates) + { + if (!templateItem.hasAttributes()) return; // TODO: Throw error + + TemplateDefinition page = new TemplateDefinition(); + + NamedNodeMap attributes = templateItem.getAttributes(); + Node n = attributes.getNamedItem("id"); + if (n == null) return; + + templates.put(n.getTextContent(), page); + + parseChildElements(context, templateItem.getChildNodes(), page.elements, templates, true, TextStyle.DEFAULT); + + attributes.removeNamedItem("id"); + page.attributes = attributes; + } + + public static List> parseChildConditions(Node node) + { + List> conditions = Lists.newArrayList(); + NodeList children = node.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) + { + Node condition = children.item(i); + if (condition.getNodeType() != Node.ELEMENT_NODE) continue; + + Predicate displayCondition = parseSingleCondition(condition); + + conditions.add(displayCondition); + } + return conditions; + } + + public static void parseChildElements(ParsingContext context, NodeList elementsList, List elements, Map templates, + boolean generateParagraphs, TextStyle defaultStyle) + { + for (int k = 0; k < elementsList.getLength(); k++) + { + boolean isFirstElement = k == 0; + boolean isLastElement = (k + 1) == elementsList.getLength(); + + var ctx = new ParsingContext.Wrapper(context) + { + @Override + public boolean isFirstElement() + { + return isFirstElement; + } + + @Override + public boolean isLastElement() + { + return isLastElement; + } + }; + + Node elementItem = elementsList.item(k); + + parsePageElement(ctx, elements, templates, generateParagraphs, defaultStyle, elementItem); + } + } + + @Nullable + public static ElementInline parseParagraphElement(ParsingContext context, Node elementItem, String nodeName, TextStyle defaultStyle) + { + if (elementItem.getNodeType() != Node.TEXT_NODE) + { + return createInlineElement(context, defaultStyle, elementItem, new ResourceLocation(nodeName)); + } + else + { + String textContent = ElementText.compactString(elementItem.getTextContent(), context.isFirstElement(), context.isLastElement()); + if (!Strings.isNullOrEmpty(textContent)) + { + return ElementSpan.of(textContent, context.isFirstElement(), context.isLastElement(), defaultStyle); + } + } + return null; + } + + public static void parseRunElements(ParsingContext parent, NodeList elementsList, List elements, TextStyle defaultStyle) + { + for (int k = 0; k < elementsList.getLength(); k++) + { + boolean isFirstElement = k == 0; + boolean isLastElement = (k + 1) == elementsList.getLength(); + + var context = new ParsingContext.Wrapper(parent) + { + @Override + public boolean isFirstElement() + { + return isFirstElement; + } + + @Override + public boolean isLastElement() + { + return isLastElement; + } + }; + + Node elementItem = elementsList.item(k); + + ElementInline parsedElement = null; + + String nodeName = elementItem.getNodeName(); + ResourceLocation nodeLoc = + elementItem.getNodeType() == Node.ELEMENT_NODE ? + new ResourceLocation(nodeName) : new ResourceLocation("_"); + + if (BookDocumentParser.elements.containsKey(nodeLoc)) + { + if (createElement(context, Collections.emptyMap(), defaultStyle, elementItem, nodeLoc) instanceof ElementInline inline) + { + if (elementItem.hasAttributes()) + { + inline.parse(context, elementItem.getAttributes()); + } + + if (elementItem.hasChildNodes()) + { + inline.parseChildNodes(context, elementItem.getChildNodes(), Collections.emptyMap(), defaultStyle); + } + + parsedElement = inline; + } + } + else if (inlineElements.containsKey(nodeLoc)) + { + parsedElement = createInlineElement(context, defaultStyle, elementItem, nodeLoc); + } + else if (elementItem.getNodeType() == Node.TEXT_NODE) + { + String textContent = ElementText.compactString(elementItem.getTextContent(), context.isFirstElement(), context.isLastElement()); + if (!Strings.isNullOrEmpty(textContent)) + { + parsedElement = ElementSpan.of(textContent, context.isFirstElement(), context.isLastElement(), defaultStyle); + } + } + else if (elementItem.getNodeType() != Node.COMMENT_NODE) + { + parsedElement = parseParagraphElement(context, elementItem, nodeName, defaultStyle); + + if (parsedElement == null) + { + GuidebookMod.logger.warn("Unrecognized tag: {}", nodeName); + } + } + + if (parsedElement != null) + { + elements.add(parsedElement); + } + } + } + + private static void registerDefaultElement(String location, ElementFactory factory) + { + elements.put(new ResourceLocation(location), factory); + } + + private static void registerDefaultInlineElement(String location, InlineElementFactory factory) + { + inlineElements.put(new ResourceLocation(location), factory); + } + + private static void registerDefaultDocumentLevelElement(String location, DocumentLevelElementParser parser) + { + documentLevelElements.put(new ResourceLocation(location), parser); + } + + private static void registerDefaultPage(String location, PageFactory parser) + { + pages.put(new ResourceLocation(location), parser); + } + + private static void parseDocumentLevelElements(ParsingContext context, NodeList firstLevel) + { + AtomicInteger chapterNumber = new AtomicInteger(0); + for (int i = 0; i < firstLevel.getLength(); i++) + { + Node firstLevelNode = firstLevel.item(i); + + parseDocumentLevelElement(context, chapterNumber, firstLevelNode); + } + } + + private static void parseDocumentLevelElement(ParsingContext context, AtomicInteger chapterNumber, Node firstLevelNode) + { + String nodeName = firstLevelNode.getNodeName(); + if ("include".equals(nodeName)) + { + parseInclude(context, firstLevelNode, (resLoc, document) -> { + var includeRoot = document.getDocumentElement(); + if (includeRoot.getTagName().equals("library")) + { + TemplateLibrary tpl = TemplateLibrary.get(context, resLoc, document); + context.document().templates.putAll(tpl.templates); + } + else + { + parseDocumentLevelElement(context, chapterNumber, includeRoot); + } + }); + return; + } + if (firstLevelNode.getNodeType() != Node.ELEMENT_NODE) + return; + DocumentLevelElementParser parser = documentLevelElements.get(new ResourceLocation(nodeName)); + if (parser != null) + { + parser.parse(context, chapterNumber, firstLevelNode); + } + } + + private static void parseStackLinks(ParsingContext context, Node refsItem) + { + NodeList refsList = refsItem.getChildNodes(); + for (int j = 0; j < refsList.getLength(); j++) + { + Node refItem = refsList.item(j); + String nodeName = refItem.getNodeName(); + + if (nodeName.equals("stack")) + { + if (refItem.hasAttributes()) + { + Node item_node = refItem.getAttributes().getNamedItem("item"); //get item + if (item_node != null) + { + Item item = ForgeRegistries.ITEMS.getValue(new ResourceLocation(item_node.getTextContent())); + if (item != null) + { + String ref = refItem.getTextContent(); + context.document().stackLinks.put(item, SectionRef.fromString(ref)); + } + } + } + } + } + } + + private static void parseConditions(ParsingContext context, Node node) + { + NodeList children = node.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) + { + Node condition = children.item(i); + if (condition.getNodeType() != Node.ELEMENT_NODE) + { + continue; + } + + NamedNodeMap attributes = condition.getAttributes(); + + Node conditionName = attributes.getNamedItem("name"); + String name = conditionName != null ? conditionName.getTextContent() : null; + + if (Strings.isNullOrEmpty(name)) + { + throw new BookParsingException("Condition node found without a name attribute"); + } + + Predicate displayCondition = parseSingleCondition(condition); + + context.document().conditions.put(name, displayCondition); + } + } + + private static void parseChapter(ParsingContext context, int chapterNumber, Node chapterItem) + { + ChapterData chapter = new ChapterData(context.document().chapters.size()); + context.document().chapters.add(chapter); + + if (chapterItem.hasAttributes()) + { + chapter.parse(context, chapterItem.getAttributes()); + } + + AtomicInteger sectionNumber = new AtomicInteger(0); + NodeList pagesList = chapterItem.getChildNodes(); + for (int j = 0; j < pagesList.getLength(); j++) + { + Node pageItem = pagesList.item(j); + + parseChapterElement(context, chapterNumber, chapter, sectionNumber, pageItem); + } + } + + private static void parseChapterElement(ParsingContext context, int chapterNumber, ChapterData chapter, AtomicInteger sectionNumber, Node pageItem) + { + if ("include".equals(pageItem.getNodeName())) + { + parseInclude(context, pageItem, (name, doc) -> parseChapterElement(context, chapterNumber, chapter, sectionNumber, doc.getDocumentElement())); + } + else if (pageItem.getNodeType() == Node.ELEMENT_NODE && pages.containsKey(new ResourceLocation(pageItem.getNodeName()))) + { + PageFactory factory = pages.get(new ResourceLocation(pageItem.getNodeName())); + PageData page = factory.newInstance(new SectionRef(chapterNumber, sectionNumber.getAndIncrement())); + parseSection(context, chapter, pageItem, page); + } + } + + private static void parseSection(ParsingContext parentContext, ChapterData chapter, Node pageItem, PageData page) + { + chapter.sections.add(page); + + var context = new ParsingContext.Wrapper(parentContext) + { + @Override + public ChapterData chapter() + { + return chapter; + } + }; + + if (pageItem.hasAttributes()) + { + page.parse(context, pageItem.getAttributes()); + } + + if (pageItem.hasChildNodes()) + { + page.parseChildNodes(context, pageItem.getChildNodes(), context.document().templates, TextStyle.DEFAULT); + } + } + + private static void parseInclude(ParsingContext context, Node firstLevelNode, BiConsumer includeAction) + { + NamedNodeMap attributes = firstLevelNode.getAttributes(); + Node n = attributes.getNamedItem("ref"); + + ResourceLocation id = new ResourceLocation(n.getTextContent()); + Document include = includeCache.computeIfAbsent(id, resLoc -> { + + // Prevents loading includes from config folder if the book was found in resource packs. + if (context.loadedFromConfigFolder() && resLoc.getNamespace().equals("gbook")) + { + File booksFolder = BookRegistry.getBooksFolder(); + File file = new File(booksFolder, resLoc.getPath()); + if (file.exists() && file.isFile()) + { + try (InputStream stream = new FileInputStream(file)) + { + return context.xmlDocumentBuilder().parse(stream); + } + catch (FileNotFoundException e) + { + // WUT? continue and try to load from resource pack + } + catch (IOException e) + { + throw new UncheckedIOException(e); + } + catch (SAXException e) + { + throw new RuntimeException(e); + } + } + } + + try + { + var res = Minecraft.getInstance().getResourceManager().getResourceOrThrow(resLoc); + try (InputStream stream = res.open()) + { + return context.xmlDocumentBuilder().parse(stream); + } + catch (IOException e) + { + throw new UncheckedIOException(e); + } + catch (SAXException e) + { + throw new RuntimeException(e); + } + } + catch (FileNotFoundException e) + { + throw new UncheckedIOException(e); + } + }); + + includeAction.accept(id, include); + } + + private static Predicate parseSingleCondition(Node condition) + { + Predicate displayCondition; + try + { + displayCondition = ConditionManager.parseCondition(condition); + if (displayCondition == null) + { + throw new BookParsingException("Condition not found"); + } + } + catch (Exception e) + { + throw new BookParsingException("Exception parsing condition", e); + } + return displayCondition; + } + + private static void parsePageElement(ParsingContext context, List elements, Map templates, boolean generateParagraphs, + TextStyle defaultStyle, Node elementItem) + { + Element parsedElement = null; + + String nodeName = elementItem.getNodeName(); + ResourceLocation nodeLoc = + elementItem.getNodeType() == Node.ELEMENT_NODE ? + new ResourceLocation(nodeName) : new ResourceLocation("_"); + + if ("include".equals(nodeName)) + { + parseInclude(context, elementItem, (name, document) -> + parsePageElement(context, elements, templates, generateParagraphs, defaultStyle, document.getDocumentElement()) + ); + } + else if (BookDocumentParser.elements.containsKey(nodeLoc)) + { + parsedElement = createElement(context, templates, defaultStyle, elementItem, nodeLoc); + } + else if (templates.containsKey(nodeName)) + { + TemplateDefinition tDef = templates.get(nodeName); + + ElementPanel t = new ElementPanel(); + t.parse(context, tDef.attributes); + + if (elementItem.hasAttributes()) + { + t.parse(context, elementItem.getAttributes()); + } + + List elementList = Lists.newArrayList(); + + parseChildElements(context, elementItem.getChildNodes(), elementList, templates, false, defaultStyle); + + List effectiveList = tDef.applyTemplate(context, elementList); + + t.innerElements.addAll(effectiveList); + + parsedElement = t; + } + else if (elementItem.getNodeType() == Node.TEXT_NODE) + { + if (generateParagraphs) + { + String textContent = ElementText.compactString(elementItem.getTextContent(), context.isFirstElement(), context.isLastElement()); + if (!Strings.isNullOrEmpty(textContent) && !textContent.matches("^[ \t\r\n]+$")) + { + parsedElement = ElementSpan.of(textContent, defaultStyle); + } + } + } + else if (elementItem.getNodeType() != Node.COMMENT_NODE) + { + parsedElement = parseParagraphElement(context, elementItem, nodeName, defaultStyle); + + if (parsedElement == null) + { + GuidebookMod.logger.warn("Unrecognized tag: {}", nodeName); + } + } + + if (parsedElement == null) return; + + if (!parsedElement.supportsPageLevel() && generateParagraphs && parsedElement instanceof ElementInline) + { + ElementParagraph p = new ElementParagraph(); + + if (elementItem.hasAttributes()) + { + p.parse(context, elementItem.getAttributes()); + parsedElement.parse(context, elementItem.getAttributes()); + } + + p.inlines.add((ElementInline) parsedElement); + + parsedElement = p; + } + + if (parsedElement.supportsPageLevel()) + { + elements.add(parsedElement); + } + } + + @Nullable + private static Element createElement(ParsingContext context, Map templates, TextStyle defaultStyle, Node elementItem, ResourceLocation nodeLoc) + { + ElementFactory factory = elements.get(nodeLoc); + if (factory == null) + { + return null; + } + Element t = factory.newInstance(); + TextStyle childStyle = t.childStyle(context, elementItem.getAttributes(), defaultStyle); + if (elementItem.hasAttributes()) + { + NamedNodeMap attributes = elementItem.getAttributes(); + t.parse(context, attributes); + applyModifiers(context, defaultStyle, t, attributes); + } + if (elementItem.hasChildNodes()) + { + t.parseChildNodes(context, elementItem.getChildNodes(), templates, childStyle); + } + return t; + } + + @Nullable + private static ElementInline createInlineElement(ParsingContext context, TextStyle defaultStyle, Node elementItem, ResourceLocation nodeLoc) + { + InlineElementFactory factory = inlineElements.get(nodeLoc); + if (factory == null) return null; + ElementInline element = factory.newInstance(context.isFirstElement(), context.isLastElement()); + TextStyle childStyle = element.childStyle(context, elementItem.getAttributes(), defaultStyle); + if (elementItem.hasAttributes()) + { + NamedNodeMap attributes = elementItem.getAttributes(); + element.parse(context, attributes); + applyModifiers(context, defaultStyle, element, attributes); + } + if (elementItem.hasChildNodes()) + { + element.parseChildNodes(context, elementItem.getChildNodes(), Collections.emptyMap(), childStyle); + } + return element; + } + + private static void applyModifiers(ParsingContext context, TextStyle defaultStyle, Element element, NamedNodeMap attributes) + { + for (int i = 0; i < attributes.getLength(); i++) + { + Node attr = attributes.item(i); + ResourceLocation key = ResourceLocation.tryParse(attr.getNodeName()); + if (key == null) continue; + if (!modifiers.containsKey(key)) continue; + ElementModifier elementModifier = modifiers.get(key); + if (!elementModifier.canModify(context, element)) continue; + elementModifier.modify(context, element, attr.getNodeValue(), attributes, defaultStyle); + } + } +} diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/book/ChapterData.java b/src/main/java/dev/gigaherz/guidebook/guidebook/book/ChapterData.java new file mode 100644 index 0000000..a7fd22a --- /dev/null +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/book/ChapterData.java @@ -0,0 +1,94 @@ +package dev.gigaherz.guidebook.guidebook.book; + +import com.google.common.base.Strings; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import dev.gigaherz.guidebook.guidebook.IBookGraphics; +import dev.gigaherz.guidebook.guidebook.conditions.ConditionContext; +import dev.gigaherz.guidebook.guidebook.drawing.VisualChapter; +import dev.gigaherz.guidebook.guidebook.elements.TextStyle; +import dev.gigaherz.guidebook.guidebook.templates.TemplateDefinition; +import dev.gigaherz.guidebook.guidebook.util.Size; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; + +public class ChapterData implements IParseable +{ + public final int num; + public String id; + public Predicate condition; + public boolean conditionResult; + + public final List sections = Lists.newArrayList(); + public final Map sectionsByName = Maps.newHashMap(); + + ChapterData(int num) + { + this.num = num; + } + + public boolean reevaluateConditions(ConditionContext ctx) + { + boolean oldValue = conditionResult; + conditionResult = condition == null || condition.test(ctx); + + boolean anyChanged = conditionResult != oldValue; + for (PageData section : sections) + { + anyChanged |= section.reevaluateConditions(ctx); + } + + return anyChanged; + } + + public void reflow(IBookGraphics rendering, VisualChapter ch, Size pageSize) + { + for (PageData section : sections) + { + if (!section.conditionResult || section.isEmpty()) + { + continue; + } + + if (!Strings.isNullOrEmpty(section.id)) + { + ch.pagesByName.put(section.id, ch.pages.size()); + } + + ch.pages.addAll(section.reflow(rendering, pageSize)); + } + } + + public boolean isEmpty() + { + return sections.stream().noneMatch(s -> s.conditionResult && !s.isEmpty()); + } + + @Override + public void parse(ParsingContext context, NamedNodeMap attributes) + { + Node n = attributes.getNamedItem("id"); + if (n != null) + { + id = n.getTextContent(); + context.document().chaptersByName.put(id, num); + } + + n = attributes.getNamedItem("condition"); + if (n != null) + { + condition = context.getCondition(n.getTextContent()); + } + } + + @Override + public void parseChildNodes(ParsingContext context, NodeList childNodes, Map templates, TextStyle defaultStyle) + { + + } +} diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/book/DocumentLevelElementParser.java b/src/main/java/dev/gigaherz/guidebook/guidebook/book/DocumentLevelElementParser.java new file mode 100644 index 0000000..f27c15a --- /dev/null +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/book/DocumentLevelElementParser.java @@ -0,0 +1,10 @@ +package dev.gigaherz.guidebook.guidebook.book; + +import org.w3c.dom.Node; + +import java.util.concurrent.atomic.AtomicInteger; + +public interface DocumentLevelElementParser +{ + void parse(ParsingContext context, AtomicInteger chapterNumber, Node node); +} diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/book/ElementFactory.java b/src/main/java/dev/gigaherz/guidebook/guidebook/book/ElementFactory.java new file mode 100644 index 0000000..51cc5c3 --- /dev/null +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/book/ElementFactory.java @@ -0,0 +1,9 @@ +package dev.gigaherz.guidebook.guidebook.book; + +import dev.gigaherz.guidebook.guidebook.elements.Element; + +@FunctionalInterface +public interface ElementFactory +{ + Element newInstance(); +} diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/book/ElementModifier.java b/src/main/java/dev/gigaherz/guidebook/guidebook/book/ElementModifier.java new file mode 100644 index 0000000..92f8dd9 --- /dev/null +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/book/ElementModifier.java @@ -0,0 +1,16 @@ +package dev.gigaherz.guidebook.guidebook.book; + +import dev.gigaherz.guidebook.guidebook.elements.Element; +import dev.gigaherz.guidebook.guidebook.elements.TextStyle; +import org.w3c.dom.NamedNodeMap; + +@FunctionalInterface +public interface ElementModifier +{ + void modify(ParsingContext context, Element element, String value, NamedNodeMap attributes, TextStyle defaultStyle); + + default boolean canModify(ParsingContext context, Element element) + { + return true; + } +} diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/book/IParseable.java b/src/main/java/dev/gigaherz/guidebook/guidebook/book/IParseable.java new file mode 100644 index 0000000..eac8e72 --- /dev/null +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/book/IParseable.java @@ -0,0 +1,20 @@ +package dev.gigaherz.guidebook.guidebook.book; + +import dev.gigaherz.guidebook.guidebook.elements.TextStyle; +import dev.gigaherz.guidebook.guidebook.templates.TemplateDefinition; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.NodeList; + +import java.util.Map; + +public interface IParseable +{ + void parse(ParsingContext context, NamedNodeMap attributes); + + void parseChildNodes(ParsingContext context, NodeList childNodes, Map templates, TextStyle defaultStyle); + + default TextStyle childStyle(ParsingContext context, NamedNodeMap attributes, TextStyle defaultStyle) + { + return defaultStyle; + } +} diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/book/InlineElementFactory.java b/src/main/java/dev/gigaherz/guidebook/guidebook/book/InlineElementFactory.java new file mode 100644 index 0000000..16b3b2a --- /dev/null +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/book/InlineElementFactory.java @@ -0,0 +1,9 @@ +package dev.gigaherz.guidebook.guidebook.book; + +import dev.gigaherz.guidebook.guidebook.elements.ElementInline; + +@FunctionalInterface +public interface InlineElementFactory +{ + ElementInline newInstance(boolean isFirstElement, boolean isLastElement); +} diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/book/PageData.java b/src/main/java/dev/gigaherz/guidebook/guidebook/book/PageData.java new file mode 100644 index 0000000..615e87b --- /dev/null +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/book/PageData.java @@ -0,0 +1,95 @@ +package dev.gigaherz.guidebook.guidebook.book; + +import com.google.common.collect.Lists; +import dev.gigaherz.guidebook.guidebook.IBookGraphics; +import dev.gigaherz.guidebook.guidebook.conditions.ConditionContext; +import dev.gigaherz.guidebook.guidebook.drawing.VisualPage; +import dev.gigaherz.guidebook.guidebook.elements.Element; +import dev.gigaherz.guidebook.guidebook.elements.TextStyle; +import dev.gigaherz.guidebook.guidebook.templates.TemplateDefinition; +import dev.gigaherz.guidebook.guidebook.util.Point; +import dev.gigaherz.guidebook.guidebook.util.Rect; +import dev.gigaherz.guidebook.guidebook.util.Size; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; + +public class PageData implements IParseable +{ + public final SectionRef ref; + public String id; + public Predicate condition; + public boolean conditionResult; + + public final List elements = Lists.newArrayList(); + + public PageData(SectionRef ref) + { + this.ref = ref; + } + + public List reflow(IBookGraphics rendering, Size pageSize) + { + VisualPage page = new VisualPage(ref); + Rect pageBounds = new Rect(new Point(), pageSize); + + int top = 0; + for (Element element : elements) + { + if (element.conditionResult) + { + top = element.reflow(page.children, rendering, new Rect(new Point(0, top), pageSize), pageBounds); + } + } + + return Collections.singletonList(page); + } + + public boolean reevaluateConditions(ConditionContext ctx) + { + boolean oldValue = conditionResult; + conditionResult = condition == null || condition.test(ctx); + + boolean anyChanged = conditionResult != oldValue; + for (Element element : elements) + { + anyChanged |= element.reevaluateConditions(ctx); + } + + return anyChanged; + } + + public boolean isEmpty() + { + return elements.stream().noneMatch(e -> e.conditionResult); + } + + @Override + public void parse(ParsingContext context, NamedNodeMap attributes) + { + Node n = attributes.getNamedItem("id"); + if (n != null) + { + id = n.getTextContent(); + context.document().sectionsByName.put(id, ref); + context.chapter().sectionsByName.put(id, ref.section); + } + + n = attributes.getNamedItem("condition"); + if (n != null) + { + condition = context.getCondition(n.getTextContent()); + } + } + + @Override + public void parseChildNodes(ParsingContext context, NodeList childNodes, Map templates, TextStyle defaultStyle) + { + BookDocumentParser.parseChildElements(context, childNodes, elements, templates, true, defaultStyle); + } +} diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/book/PageFactory.java b/src/main/java/dev/gigaherz/guidebook/guidebook/book/PageFactory.java new file mode 100644 index 0000000..61ef970 --- /dev/null +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/book/PageFactory.java @@ -0,0 +1,7 @@ +package dev.gigaherz.guidebook.guidebook.book; + +@FunctionalInterface +public interface PageFactory +{ + PageData newInstance(SectionRef ref); +} diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/book/PageGroup.java b/src/main/java/dev/gigaherz/guidebook/guidebook/book/PageGroup.java new file mode 100644 index 0000000..68d3a24 --- /dev/null +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/book/PageGroup.java @@ -0,0 +1,111 @@ +package dev.gigaherz.guidebook.guidebook.book; + +import com.google.common.collect.Lists; +import dev.gigaherz.guidebook.guidebook.IBookGraphics; +import dev.gigaherz.guidebook.guidebook.drawing.VisualElement; +import dev.gigaherz.guidebook.guidebook.drawing.VisualPage; +import dev.gigaherz.guidebook.guidebook.drawing.VisualPageBreak; +import dev.gigaherz.guidebook.guidebook.elements.Element; +import dev.gigaherz.guidebook.guidebook.util.Point; +import dev.gigaherz.guidebook.guidebook.util.Rect; +import dev.gigaherz.guidebook.guidebook.util.Size; + +import java.util.List; + +/** + * This class represents a group of pages clearly delimited by start/end of chapters, sections, or explicit section braks. + * Example: + *
{@code
+ * 
+ *   
+ *     
+ * Group 1 + *
+ *
+ * Group 2 + *
+ *
+ * + * Group 3 + * + * Group 4 + * + *
+ * }
+ */ +public class PageGroup extends PageData +{ + public PageGroup(SectionRef ref) + { + super(ref); + } + + @Override + public List reflow(IBookGraphics rendering, Size pageSize) + { + List pages = Lists.newArrayList(); + + VisualPage page = new VisualPage(ref); + Rect pageBounds = new Rect(new Point(0, 0), pageSize); + + int top = pageBounds.position.y; + for (Element element : elements) + { + if (element.conditionResult) + { + top = element.reflow(page.children, rendering, new Rect(new Point(pageBounds.position.x, top), pageBounds.size), pageBounds); + } + } + + boolean needsRepagination = false; + for (VisualElement child : page.children) + { + if (child instanceof VisualPageBreak || (child.position.y + child.size.height > (pageBounds.position.y + pageBounds.size.height))) + { + needsRepagination = true; + break; + } + } + + if (needsRepagination) + { + VisualPage page2 = new VisualPage(ref); + + int offsetY = 0; + boolean pageBreakRequired = false; + for (VisualElement child : page.children) + { + int cpy = child.position.y + offsetY; + if (pageBreakRequired || (cpy + child.size.height > (pageBounds.position.y + pageBounds.size.height) + && child.position.y > pageBounds.position.y)) + { + pages.add(page2); + page2 = new VisualPage(ref); + + offsetY = pageBounds.position.y - child.position.y; + pageBreakRequired = false; + } + + if (child instanceof VisualPageBreak) + { + pageBreakRequired = true; + } + else + { + child.position = new Point( + child.position.x, + child.position.y + offsetY); + page2.children.add(child); + } + } + + pages.add(page2); + } + else + { + pages.add(page); + } + + return pages; + } +} diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/book/ParsingContext.java b/src/main/java/dev/gigaherz/guidebook/guidebook/book/ParsingContext.java new file mode 100644 index 0000000..d808886 --- /dev/null +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/book/ParsingContext.java @@ -0,0 +1,85 @@ +package dev.gigaherz.guidebook.guidebook.book; + +import dev.gigaherz.guidebook.guidebook.conditions.ConditionContext; + +import javax.annotation.Nullable; +import javax.xml.parsers.DocumentBuilder; +import java.util.function.Predicate; + +public interface ParsingContext +{ + boolean loadedFromConfigFolder(); + DocumentBuilder xmlDocumentBuilder(); + BookDocument document(); + default Predicate getCondition(String name) + { + var doc = document(); + if (doc == null) + return null; + return doc.getCondition(name); + } + default ChapterData chapter() + { + return null; + } + default boolean isFirstElement() + { + return false; + } + default boolean isLastElement() + { + return false; + } + + abstract class Wrapper implements ParsingContext + { + private final ParsingContext delegate; + + public Wrapper(ParsingContext delegate) + { + this.delegate = delegate; + } + + @Override + public boolean loadedFromConfigFolder() + { + return delegate.loadedFromConfigFolder(); + } + + @Override + public DocumentBuilder xmlDocumentBuilder() + { + return delegate.xmlDocumentBuilder(); + } + + @Override + public BookDocument document() + { + return delegate.document(); + } + + @Override + public Predicate getCondition(String name) + { + return delegate.getCondition(name); + } + + @Override + public ChapterData chapter() + { + return delegate.chapter(); + } + + @Override + public boolean isFirstElement() + { + return delegate.isFirstElement(); + } + + @Override + public boolean isLastElement() + { + return delegate.isLastElement(); + } + } +} diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/SectionRef.java b/src/main/java/dev/gigaherz/guidebook/guidebook/book/SectionRef.java similarity index 99% rename from src/main/java/dev/gigaherz/guidebook/guidebook/SectionRef.java rename to src/main/java/dev/gigaherz/guidebook/guidebook/book/SectionRef.java index 92aaacd..ea34aa4 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/SectionRef.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/book/SectionRef.java @@ -1,4 +1,4 @@ -package dev.gigaherz.guidebook.guidebook; +package dev.gigaherz.guidebook.guidebook.book; import com.google.common.base.Strings; import com.google.common.primitives.Ints; diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/client/BookBakedModel.java b/src/main/java/dev/gigaherz/guidebook/guidebook/client/BookBakedModel.java index 0461f54..6582544 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/client/BookBakedModel.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/client/BookBakedModel.java @@ -7,7 +7,7 @@ import com.google.gson.JsonObject; import com.mojang.datafixers.util.Either; import com.mojang.datafixers.util.Pair; -import dev.gigaherz.guidebook.guidebook.BookDocument; +import dev.gigaherz.guidebook.guidebook.book.BookDocument; import dev.gigaherz.guidebook.guidebook.BookRegistry; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.renderer.block.model.BakedQuad; @@ -26,7 +26,6 @@ import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.client.model.ForgeModelBakery; import net.minecraftforge.client.model.IModelConfiguration; import net.minecraftforge.client.model.IModelLoader; import net.minecraftforge.client.model.geometry.IModelGeometry; diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/client/BookRendering.java b/src/main/java/dev/gigaherz/guidebook/guidebook/client/BookRendering.java index 9692265..c3d8d64 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/client/BookRendering.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/client/BookRendering.java @@ -6,10 +6,12 @@ import com.mojang.blaze3d.vertex.*; import com.mojang.math.Matrix4f; import dev.gigaherz.guidebook.ConfigValues; -import dev.gigaherz.guidebook.guidebook.BookDocument; +import dev.gigaherz.guidebook.guidebook.book.BookDocument; import dev.gigaherz.guidebook.guidebook.HoverContext; import dev.gigaherz.guidebook.guidebook.IBookGraphics; -import dev.gigaherz.guidebook.guidebook.SectionRef; +import dev.gigaherz.guidebook.guidebook.book.SectionRef; +import dev.gigaherz.guidebook.guidebook.book.ChapterData; +import dev.gigaherz.guidebook.guidebook.book.PageData; import dev.gigaherz.guidebook.guidebook.drawing.VisualChapter; import dev.gigaherz.guidebook.guidebook.drawing.VisualElement; import dev.gigaherz.guidebook.guidebook.drawing.VisualPage; @@ -24,7 +26,6 @@ import net.minecraft.network.chat.Component; import net.minecraft.network.chat.FormattedText; import net.minecraft.network.chat.Style; -import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.Mth; import net.minecraft.world.item.ItemStack; @@ -393,16 +394,16 @@ private boolean needChapter(int chapterNumber) { if (chapterNumber < 0 || chapterNumber >= book.chapterCount()) return false; - BookDocument.ChapterData ch = book.getChapter(chapterNumber); + ChapterData ch = book.getChapter(chapterNumber); return ch.conditionResult && !ch.isEmpty(); } private boolean needSection(int chapterNumber, int sectionNumber) { - BookDocument.ChapterData ch = book.getChapter(chapterNumber); + ChapterData ch = book.getChapter(chapterNumber); if (sectionNumber < 0 || sectionNumber >= ch.sections.size()) return false; - BookDocument.PageData section = ch.sections.get(sectionNumber); + PageData section = ch.sections.get(sectionNumber); return section.conditionResult && !section.isEmpty(); } @@ -443,7 +444,7 @@ private VisualChapter getVisualChapter(int chapter) { while (chapters.size() <= chapter && lastProcessedChapter < book.chapterCount()) { - BookDocument.ChapterData bc = book.getChapter(lastProcessedChapter++); + ChapterData bc = book.getChapter(lastProcessedChapter++); if (!bc.conditionResult) continue; diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/client/GuidebookScreen.java b/src/main/java/dev/gigaherz/guidebook/guidebook/client/GuidebookScreen.java index 8a25544..b515ba2 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/client/GuidebookScreen.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/client/GuidebookScreen.java @@ -4,7 +4,7 @@ import com.mojang.blaze3d.vertex.PoseStack; import dev.gigaherz.guidebook.ConfigValues; import dev.gigaherz.guidebook.GuidebookMod; -import dev.gigaherz.guidebook.guidebook.BookDocument; +import dev.gigaherz.guidebook.guidebook.book.BookDocument; import dev.gigaherz.guidebook.guidebook.BookRegistry; import dev.gigaherz.guidebook.guidebook.conditions.ConditionContext; import net.minecraft.client.Minecraft; @@ -16,11 +16,12 @@ import net.minecraft.client.renderer.ItemModelShaper; import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; import org.lwjgl.glfw.GLFW; +import java.util.Objects; + public class GuidebookScreen extends Screen { private static final ResourceLocation BOOK_GUI_TEXTURES = GuidebookMod.location("textures/gui/book.png"); @@ -340,7 +341,7 @@ public void renderButton(PoseStack matrixStack, int mouseX, int mouseY, float pa RenderSystem.setShader(GameRenderer::getPositionTexShader); RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - RenderSystem.setShaderTexture(0, BOOK_GUI_TEXTURES); + RenderSystem.setShaderTexture(0, Objects.requireNonNullElse(book.getBook().getWidgets(), BOOK_GUI_TEXTURES)); int x = xPixel[whichIcon]; int y = yPixel[whichIcon]; diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/conditions/AdvancementCondition.java b/src/main/java/dev/gigaherz/guidebook/guidebook/conditions/AdvancementCondition.java index 4ade266..df29a96 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/conditions/AdvancementCondition.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/conditions/AdvancementCondition.java @@ -34,8 +34,8 @@ protected AdvancementCondition(ResourceLocation advancement) public static void register() { - ConditionManager.register("advancement-locked", (doc, node) -> new Locked(parseAdvancementLocation(node))); - ConditionManager.register("advancement-unlocked", (doc, node) -> new Unlocked(parseAdvancementLocation(node))); + ConditionManager.register("advancement-locked", (node) -> new Locked(parseAdvancementLocation(node))); + ConditionManager.register("advancement-unlocked", (node) -> new Unlocked(parseAdvancementLocation(node))); } public static class Locked extends AdvancementCondition diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/conditions/BasicConditions.java b/src/main/java/dev/gigaherz/guidebook/guidebook/conditions/BasicConditions.java index d47c9a7..d3e35d2 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/conditions/BasicConditions.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/conditions/BasicConditions.java @@ -13,11 +13,11 @@ public abstract class BasicConditions implements Predicate { public static void register() { - ConditionManager.register("true", (doc, node) -> new True()); - ConditionManager.register("false", (doc, node) -> new False()); - ConditionManager.register("mod-loaded", (doc, node) -> new ModLoaded(parseModId(node))); - ConditionManager.register("item-exists", (doc, node) -> new ItemExists(parseItemName(node))); - ConditionManager.register("condition", (doc, node) -> new Ref(parseConditionId(node))); + ConditionManager.register("true", (node) -> new True()); + ConditionManager.register("false", (node) -> new False()); + ConditionManager.register("mod-loaded", (node) -> new ModLoaded(parseModId(node))); + ConditionManager.register("item-exists", (node) -> new ItemExists(parseItemName(node))); + ConditionManager.register("condition", (node) -> new Ref(parseConditionId(node))); } public static class True extends BasicConditions diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/conditions/CompositeCondition.java b/src/main/java/dev/gigaherz/guidebook/guidebook/conditions/CompositeCondition.java index 78e752f..0c8f8a3 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/conditions/CompositeCondition.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/conditions/CompositeCondition.java @@ -1,6 +1,6 @@ package dev.gigaherz.guidebook.guidebook.conditions; -import dev.gigaherz.guidebook.guidebook.BookDocument; +import dev.gigaherz.guidebook.guidebook.book.BookDocumentParser; import java.util.List; import java.util.function.Predicate; @@ -16,9 +16,9 @@ protected CompositeCondition(List> children) public static void register() { - IDisplayConditionFactory any = (doc, node) -> new Any(BookDocument.parseChildConditions(doc, node)); - IDisplayConditionFactory all = (doc, node) -> new All(BookDocument.parseChildConditions(doc, node)); - IDisplayConditionFactory not = (doc, node) -> new Not(BookDocument.parseChildConditions(doc, node)); + IDisplayConditionFactory any = (node) -> new Any(BookDocumentParser.parseChildConditions(node)); + IDisplayConditionFactory all = (node) -> new All(BookDocumentParser.parseChildConditions(node)); + IDisplayConditionFactory not = (node) -> new Not(BookDocumentParser.parseChildConditions(node)); ConditionManager.register("any", any); ConditionManager.register("or", any); ConditionManager.register("all", all); diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/conditions/ConditionContext.java b/src/main/java/dev/gigaherz/guidebook/guidebook/conditions/ConditionContext.java index cbf0b8e..fe9a886 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/conditions/ConditionContext.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/conditions/ConditionContext.java @@ -1,6 +1,6 @@ package dev.gigaherz.guidebook.guidebook.conditions; -import dev.gigaherz.guidebook.guidebook.BookDocument; +import dev.gigaherz.guidebook.guidebook.book.BookDocument; import net.minecraft.client.player.LocalPlayer; public class ConditionContext diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/conditions/ConditionManager.java b/src/main/java/dev/gigaherz/guidebook/guidebook/conditions/ConditionManager.java index 0ad82cb..1a76230 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/conditions/ConditionManager.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/conditions/ConditionManager.java @@ -1,7 +1,7 @@ package dev.gigaherz.guidebook.guidebook.conditions; import com.google.common.collect.Maps; -import dev.gigaherz.guidebook.guidebook.BookDocument; +import dev.gigaherz.guidebook.guidebook.book.BookDocument; import org.w3c.dom.Node; import java.util.Map; @@ -16,11 +16,11 @@ public static synchronized void register(String id, IDisplayConditionFactory fac REGISTRY.put(id, factory); } - public static Predicate parseCondition(BookDocument document, Node node) + public static Predicate parseCondition(Node node) { IDisplayConditionFactory factory = REGISTRY.get(node.getNodeName()); if (factory == null) return null; - return factory.parse(document, node); + return factory.parse(node); } } diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/conditions/GameStageCondition.java b/src/main/java/dev/gigaherz/guidebook/guidebook/conditions/GameStageCondition.java index 0f1aece..868657a 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/conditions/GameStageCondition.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/conditions/GameStageCondition.java @@ -18,8 +18,8 @@ protected GameStageCondition(String stageName) public static void register() { - ConditionManager.register("stage-locked", (doc, node) -> new Locked(parseStageName(node))); - ConditionManager.register("stage-unlocked", (doc, node) -> new Unlocked(parseStageName(node))); + ConditionManager.register("stage-locked", (node) -> new Locked(parseStageName(node))); + ConditionManager.register("stage-unlocked", (node) -> new Unlocked(parseStageName(node))); } public static class Locked extends GameStageCondition diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/conditions/IDisplayConditionFactory.java b/src/main/java/dev/gigaherz/guidebook/guidebook/conditions/IDisplayConditionFactory.java index df479ea..b985b43 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/conditions/IDisplayConditionFactory.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/conditions/IDisplayConditionFactory.java @@ -1,6 +1,5 @@ package dev.gigaherz.guidebook.guidebook.conditions; -import dev.gigaherz.guidebook.guidebook.BookDocument; import org.w3c.dom.Node; import java.util.function.Predicate; @@ -8,5 +7,5 @@ @FunctionalInterface public interface IDisplayConditionFactory { - Predicate parse(BookDocument document, Node xmlNode); + Predicate parse(Node xmlNode); } diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualPage.java b/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualPage.java index 57012bf..666f042 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualPage.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualPage.java @@ -1,7 +1,7 @@ package dev.gigaherz.guidebook.guidebook.drawing; import com.google.common.collect.Lists; -import dev.gigaherz.guidebook.guidebook.SectionRef; +import dev.gigaherz.guidebook.guidebook.book.SectionRef; import java.util.List; diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualStack.java b/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualStack.java index 3739ff8..b113cf4 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualStack.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualStack.java @@ -3,7 +3,7 @@ import com.mojang.blaze3d.vertex.PoseStack; import dev.gigaherz.guidebook.guidebook.HoverContext; import dev.gigaherz.guidebook.guidebook.IBookGraphics; -import dev.gigaherz.guidebook.guidebook.SectionRef; +import dev.gigaherz.guidebook.guidebook.book.SectionRef; import dev.gigaherz.guidebook.guidebook.util.Size; import net.minecraft.core.NonNullList; import net.minecraft.world.item.ItemStack; diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/Element.java b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/Element.java index 51e7a43..191d04f 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/Element.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/Element.java @@ -2,7 +2,8 @@ import dev.gigaherz.guidebook.GuidebookMod; import dev.gigaherz.guidebook.guidebook.IBookGraphics; -import dev.gigaherz.guidebook.guidebook.ParsingContext; +import dev.gigaherz.guidebook.guidebook.book.IParseable; +import dev.gigaherz.guidebook.guidebook.book.ParsingContext; import dev.gigaherz.guidebook.guidebook.conditions.ConditionContext; import dev.gigaherz.guidebook.guidebook.drawing.VisualElement; import dev.gigaherz.guidebook.guidebook.templates.TemplateDefinition; @@ -15,7 +16,6 @@ import org.w3c.dom.NodeList; import javax.annotation.Nullable; -import javax.xml.parsers.DocumentBuilder; import java.util.Collections; import java.util.List; import java.util.Map; @@ -24,7 +24,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -public abstract class Element +public abstract class Element implements IParseable { public static final int VA_TOP = 0; public static final int VA_MIDDLE = 1; @@ -118,17 +118,13 @@ public boolean supportsSpanLevel() public Point applyPosition(Point point, Point parent) { - switch (position) + return switch (position) { - case POS_RELATIVE: - return new Point(point.x + x, point.y + y); - case POS_ABSOLUTE: - return new Point(parent.x + x, parent.y + y); - case POS_FIXED: - return new Point(x, y); - } - - return new Point(point.x, point.y); + case POS_RELATIVE -> new Point(point.x + x, point.y + y); + case POS_ABSOLUTE -> new Point(parent.x + x, parent.y + y); + case POS_FIXED -> new Point(x, y); + default -> new Point(point.x, point.y); + }; } protected T copy(T other) @@ -142,6 +138,7 @@ protected T copy(T other) return other; } + @Override public void parse(ParsingContext context, NamedNodeMap attributes) { x = getAttribute(attributes, "x", x); @@ -155,40 +152,26 @@ public void parse(ParsingContext context, NamedNodeMap attributes) Node attr = attributes.getNamedItem("align"); if (attr != null) { - String a = attr.getTextContent(); - switch (a) + position = switch (attr.getTextContent()) { - case "relative": - position = 0; - break; - case "absolute": - position = 1; - break; - case "fixed": - position = 2; - break; - } + case "relative" -> 0; + case "absolute" -> 1; + case "fixed" -> 2; + default -> position; + }; } attr = attributes.getNamedItem("vertical-align"); if (attr != null) { - String a = attr.getTextContent(); - switch (a) + verticalAlignment = switch (attr.getTextContent()) { - case "top": - verticalAlignment = VA_TOP; - break; - case "middle": - verticalAlignment = VA_MIDDLE; - break; - case "baseline": - verticalAlignment = VA_BASELINE; - break; - case "bottom": - verticalAlignment = VA_BOTTOM; - break; - } + case "top" -> VA_TOP; + case "middle" -> VA_MIDDLE; + case "baseline" -> VA_BASELINE; + case "bottom" -> VA_BOTTOM; + default -> verticalAlignment; + }; } attr = attributes.getNamedItem("condition"); @@ -198,6 +181,7 @@ public void parse(ParsingContext context, NamedNodeMap attributes) } } + @Override public void parseChildNodes(ParsingContext context, NodeList childNodes, Map templates, TextStyle defaultStyle) { } diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementBreak.java b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementBreak.java index 033b9c9..82f16e0 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementBreak.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementBreak.java @@ -1,10 +1,12 @@ package dev.gigaherz.guidebook.guidebook.elements; import dev.gigaherz.guidebook.guidebook.IBookGraphics; +import dev.gigaherz.guidebook.guidebook.book.ParsingContext; import dev.gigaherz.guidebook.guidebook.drawing.VisualElement; import dev.gigaherz.guidebook.guidebook.drawing.VisualPageBreak; import dev.gigaherz.guidebook.guidebook.util.Rect; import dev.gigaherz.guidebook.guidebook.util.Size; +import org.w3c.dom.NamedNodeMap; import java.util.List; @@ -17,6 +19,11 @@ public int reflow(List list, IBookGraphics nav, Rect bounds, Rect return bounds.position.y; } + @Override + public void parse(ParsingContext context, NamedNodeMap attributes) + { + } + @Override public Element copy() { diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementFactory.java b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementFactory.java deleted file mode 100644 index 00e4f55..0000000 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementFactory.java +++ /dev/null @@ -1,7 +0,0 @@ -package dev.gigaherz.guidebook.guidebook.elements; - -@FunctionalInterface -public interface ElementFactory -{ - Element newInstance(); -} diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementGrid.java b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementGrid.java index 36fbce9..2d3e12b 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementGrid.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementGrid.java @@ -2,10 +2,11 @@ import com.google.common.collect.Lists; import com.google.common.primitives.Ints; -import dev.gigaherz.guidebook.guidebook.BookDocument; +import dev.gigaherz.guidebook.guidebook.book.BookDocument; import dev.gigaherz.guidebook.guidebook.BookParsingException; import dev.gigaherz.guidebook.guidebook.IBookGraphics; -import dev.gigaherz.guidebook.guidebook.ParsingContext; +import dev.gigaherz.guidebook.guidebook.book.BookDocumentParser; +import dev.gigaherz.guidebook.guidebook.book.ParsingContext; import dev.gigaherz.guidebook.guidebook.conditions.ConditionContext; import dev.gigaherz.guidebook.guidebook.drawing.VisualElement; import dev.gigaherz.guidebook.guidebook.drawing.VisualPanel; @@ -19,7 +20,6 @@ import org.w3c.dom.NodeList; import javax.annotation.Nullable; -import javax.xml.parsers.DocumentBuilder; import java.util.*; public class ElementGrid extends Element @@ -105,7 +105,7 @@ public void parseChildNodes(ParsingContext context, NodeList rowNodes, Map(); - BookDocument.parseChildElements(context, colNode.getChildNodes(), list, templates, true, defaultStyle); + BookDocumentParser.parseChildElements(context, colNode.getChildNodes(), list, templates, true, defaultStyle); if (list.size() == 1) cell.content = list.get(0); diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementImage.java b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementImage.java index 9ea7415..bea5398 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementImage.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementImage.java @@ -1,7 +1,7 @@ package dev.gigaherz.guidebook.guidebook.elements; import dev.gigaherz.guidebook.guidebook.IBookGraphics; -import dev.gigaherz.guidebook.guidebook.ParsingContext; +import dev.gigaherz.guidebook.guidebook.book.ParsingContext; import dev.gigaherz.guidebook.guidebook.drawing.VisualElement; import dev.gigaherz.guidebook.guidebook.drawing.VisualImage; import dev.gigaherz.guidebook.guidebook.util.Rect; diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementInline.java b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementInline.java index 752c32e..efbb0fa 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementInline.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementInline.java @@ -1,7 +1,7 @@ package dev.gigaherz.guidebook.guidebook.elements; import dev.gigaherz.guidebook.guidebook.IBookGraphics; -import dev.gigaherz.guidebook.guidebook.ParsingContext; +import dev.gigaherz.guidebook.guidebook.book.ParsingContext; import dev.gigaherz.guidebook.guidebook.drawing.VisualElement; import dev.gigaherz.guidebook.guidebook.util.Rect; import org.w3c.dom.NamedNodeMap; diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementLink.java b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementLink.java index 0202961..de358b5 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementLink.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementLink.java @@ -1,14 +1,19 @@ package dev.gigaherz.guidebook.guidebook.elements; +import com.google.common.collect.Lists; import dev.gigaherz.guidebook.guidebook.IBookGraphics; -import dev.gigaherz.guidebook.guidebook.ParsingContext; -import dev.gigaherz.guidebook.guidebook.SectionRef; +import dev.gigaherz.guidebook.guidebook.book.BookDocumentParser; +import dev.gigaherz.guidebook.guidebook.book.ParsingContext; +import dev.gigaherz.guidebook.guidebook.book.SectionRef; import dev.gigaherz.guidebook.guidebook.drawing.VisualElement; +import dev.gigaherz.guidebook.guidebook.templates.TemplateDefinition; import dev.gigaherz.guidebook.guidebook.util.LinkHelper; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; +import org.w3c.dom.NodeList; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; public class ElementLink extends ElementSpan @@ -65,6 +70,20 @@ public void parse(ParsingContext context, NamedNodeMap attributes) } } + @Override + public TextStyle childStyle(ParsingContext context, NamedNodeMap attributes, TextStyle defaultStyle) + { + return TextStyle.parse(attributes, TextStyle.LINK); + } + + @Override + public void parseChildNodes(ParsingContext context, NodeList childNodes, Map templates, TextStyle defaultStyle) + { + List elementList = Lists.newArrayList(); + BookDocumentParser.parseRunElements(context, childNodes, elementList, defaultStyle); + inlines.addAll(elementList); + } + @Override public ElementInline copy() { diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementPanel.java b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementPanel.java index ff77d67..6914ed9 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementPanel.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementPanel.java @@ -2,9 +2,10 @@ import com.google.common.collect.Lists; import com.google.common.primitives.Ints; -import dev.gigaherz.guidebook.guidebook.BookDocument; +import dev.gigaherz.guidebook.guidebook.book.BookDocument; import dev.gigaherz.guidebook.guidebook.IBookGraphics; -import dev.gigaherz.guidebook.guidebook.ParsingContext; +import dev.gigaherz.guidebook.guidebook.book.BookDocumentParser; +import dev.gigaherz.guidebook.guidebook.book.ParsingContext; import dev.gigaherz.guidebook.guidebook.conditions.ConditionContext; import dev.gigaherz.guidebook.guidebook.drawing.VisualElement; import dev.gigaherz.guidebook.guidebook.drawing.VisualPanel; @@ -82,7 +83,7 @@ public void parse(ParsingContext context, NamedNodeMap attributes) @Override public void parseChildNodes(ParsingContext context, NodeList childNodes, Map templates, TextStyle defaultStyle) { - BookDocument.parseChildElements(context, childNodes, innerElements, templates, true, defaultStyle); + BookDocumentParser.parseChildElements(context, childNodes, innerElements, templates, true, defaultStyle); } @Override diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementParagraph.java b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementParagraph.java index 620c361..fe7b8f6 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementParagraph.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementParagraph.java @@ -1,18 +1,23 @@ package dev.gigaherz.guidebook.guidebook.elements; import com.google.common.collect.Lists; +import dev.gigaherz.guidebook.GuidebookMod; import dev.gigaherz.guidebook.guidebook.IBookGraphics; -import dev.gigaherz.guidebook.guidebook.ParsingContext; +import dev.gigaherz.guidebook.guidebook.book.BookDocumentParser; +import dev.gigaherz.guidebook.guidebook.book.ParsingContext; import dev.gigaherz.guidebook.guidebook.conditions.ConditionContext; import dev.gigaherz.guidebook.guidebook.drawing.VisualElement; +import dev.gigaherz.guidebook.guidebook.templates.TemplateDefinition; import dev.gigaherz.guidebook.guidebook.util.Point; import dev.gigaherz.guidebook.guidebook.util.Rect; import dev.gigaherz.guidebook.guidebook.util.Size; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; +import org.w3c.dom.NodeList; import javax.annotation.Nullable; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; public class ElementParagraph extends Element @@ -200,6 +205,31 @@ public void parse(ParsingContext context, NamedNodeMap attributes) space = getAttribute(attributes, "space", space); } + @Override + public TextStyle childStyle(ParsingContext context, NamedNodeMap attributes, TextStyle defaultStyle) + { + return TextStyle.parse(attributes, defaultStyle); + } + + @Override + public void parseChildNodes(ParsingContext context, NodeList childNodes, Map templates, TextStyle defaultStyle) + { + for (int q = 0; q < childNodes.getLength(); q++) + { + Node childNode = childNodes.item(q); + ElementInline parsedChild = BookDocumentParser.parseParagraphElement(context, childNode, childNode.getNodeName(), defaultStyle); + + if (parsedChild == null) + { + GuidebookMod.logger.warn("Unrecognized tag: {}", childNode.getNodeName()); + } + else + { + inlines.add(parsedChild); + } + } + } + @Override public String toString(boolean complete) { diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementRecipe.java b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementRecipe.java index 002d343..45e30d9 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementRecipe.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementRecipe.java @@ -2,9 +2,9 @@ import com.google.common.primitives.Ints; import dev.gigaherz.guidebook.GuidebookMod; -import dev.gigaherz.guidebook.guidebook.BookDocument; import dev.gigaherz.guidebook.guidebook.IBookGraphics; -import dev.gigaherz.guidebook.guidebook.ParsingContext; +import dev.gigaherz.guidebook.guidebook.book.BookDocumentParser; +import dev.gigaherz.guidebook.guidebook.book.ParsingContext; import dev.gigaherz.guidebook.guidebook.drawing.VisualElement; import dev.gigaherz.guidebook.guidebook.recipe.IRecipeLayoutProvider; import dev.gigaherz.guidebook.guidebook.recipe.RecipeLayout; @@ -25,9 +25,9 @@ import java.util.Map; /** - * @author joazlazer * A section element that will display a recipe provided by the specified recipe type's RecipeProvider and will render hoverable stacks, * a background image, and additional components to display said recipe + * @author joazlazer */ public class ElementRecipe extends Element { @@ -40,7 +40,7 @@ public class ElementRecipe extends Element @Nonnull private RecipeLayout getRecipeLayout(@Nonnull Level world, IRecipeLayoutProvider recipeProvider, ElementStack output) { - if (output == null || output.stacks == null || output.stacks.size() == 0) + if (output == null || output.stacks.size() == 0) throw new IllegalArgumentException("Provided output stack is null or empty."); ItemStack targetOutput = output.stacks.get(0); @@ -106,6 +106,7 @@ else if (recipeOutput instanceof ElementStack) } } + @SuppressWarnings("UnstableApiUsage") @Override public void parse(ParsingContext context, NamedNodeMap attributes) { @@ -159,7 +160,7 @@ public void parseChildNodes(ParsingContext context, NodeList childNodes, Map measure(IBookGraphics nav, int width, int firstLineWi } @Override - public void parse(ParsingContext context, NamedNodeMap attributes) + public void parseChildNodes(ParsingContext context, NodeList childNodes, Map templates, TextStyle defaultStyle) { - super.parse(context, attributes); + List elementList = Lists.newArrayList(); + BookDocumentParser.parseRunElements(context, childNodes, elementList, defaultStyle); + inlines.addAll(elementList); } @Override diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementStack.java b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementStack.java index e8efd38..c70631b 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementStack.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementStack.java @@ -4,7 +4,7 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException; import dev.gigaherz.guidebook.GuidebookMod; import dev.gigaherz.guidebook.guidebook.IBookGraphics; -import dev.gigaherz.guidebook.guidebook.ParsingContext; +import dev.gigaherz.guidebook.guidebook.book.ParsingContext; import dev.gigaherz.guidebook.guidebook.drawing.VisualElement; import dev.gigaherz.guidebook.guidebook.drawing.VisualStack; import dev.gigaherz.guidebook.guidebook.util.Rect; diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementText.java b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementText.java index b706891..73df810 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementText.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementText.java @@ -1,7 +1,7 @@ package dev.gigaherz.guidebook.guidebook.elements; import dev.gigaherz.guidebook.guidebook.IBookGraphics; -import dev.gigaherz.guidebook.guidebook.ParsingContext; +import dev.gigaherz.guidebook.guidebook.book.ParsingContext; import dev.gigaherz.guidebook.guidebook.drawing.VisualElement; import dev.gigaherz.guidebook.guidebook.drawing.VisualText; import dev.gigaherz.guidebook.guidebook.util.Rect; diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementTitle.java b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementTitle.java new file mode 100644 index 0000000..631ac3c --- /dev/null +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementTitle.java @@ -0,0 +1,19 @@ +package dev.gigaherz.guidebook.guidebook.elements; + +import dev.gigaherz.guidebook.guidebook.book.ParsingContext; +import org.w3c.dom.NamedNodeMap; + +public class ElementTitle extends ElementParagraph +{ + public ElementTitle() + { + alignment = ElementParagraph.ALIGN_CENTER; + space = 4; + } + + @Override + public TextStyle childStyle(ParsingContext context, NamedNodeMap attributes, TextStyle defaultStyle) + { + return TextStyle.parse(attributes, new TextStyle(defaultStyle.color, true, false, true, false, false, null, 1.0f)); + } +} diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/LinkContext.java b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/LinkContext.java index c254cc9..a61c3e0 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/LinkContext.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/LinkContext.java @@ -1,6 +1,6 @@ package dev.gigaherz.guidebook.guidebook.elements; -import dev.gigaherz.guidebook.guidebook.SectionRef; +import dev.gigaherz.guidebook.guidebook.book.SectionRef; public class LinkContext { diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/templates/TemplateDefinition.java b/src/main/java/dev/gigaherz/guidebook/guidebook/templates/TemplateDefinition.java index daa9f8f..8ddf248 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/templates/TemplateDefinition.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/templates/TemplateDefinition.java @@ -1,7 +1,7 @@ package dev.gigaherz.guidebook.guidebook.templates; import com.google.common.collect.Lists; -import dev.gigaherz.guidebook.guidebook.ParsingContext; +import dev.gigaherz.guidebook.guidebook.book.ParsingContext; import dev.gigaherz.guidebook.guidebook.elements.Element; import org.w3c.dom.NamedNodeMap; diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/templates/TemplateElement.java b/src/main/java/dev/gigaherz/guidebook/guidebook/templates/TemplateElement.java index 16d6f1c..fe28a20 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/templates/TemplateElement.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/templates/TemplateElement.java @@ -2,7 +2,7 @@ import com.google.common.primitives.Ints; import dev.gigaherz.guidebook.guidebook.IBookGraphics; -import dev.gigaherz.guidebook.guidebook.ParsingContext; +import dev.gigaherz.guidebook.guidebook.book.ParsingContext; import dev.gigaherz.guidebook.guidebook.drawing.VisualElement; import dev.gigaherz.guidebook.guidebook.elements.Element; import dev.gigaherz.guidebook.guidebook.elements.ElementInline; diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/templates/TemplateLibrary.java b/src/main/java/dev/gigaherz/guidebook/guidebook/templates/TemplateLibrary.java index c65aff9..13ca49b 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/templates/TemplateLibrary.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/templates/TemplateLibrary.java @@ -1,9 +1,10 @@ package dev.gigaherz.guidebook.guidebook.templates; import com.google.common.collect.Maps; -import dev.gigaherz.guidebook.guidebook.BookDocument; +import dev.gigaherz.guidebook.guidebook.book.BookDocument; import dev.gigaherz.guidebook.guidebook.BookRegistry; -import dev.gigaherz.guidebook.guidebook.ParsingContext; +import dev.gigaherz.guidebook.guidebook.book.BookDocumentParser; +import dev.gigaherz.guidebook.guidebook.book.ParsingContext; import dev.gigaherz.guidebook.guidebook.conditions.ConditionContext; import dev.gigaherz.guidebook.guidebook.elements.TextStyle; import net.minecraft.client.Minecraft; @@ -70,43 +71,15 @@ public void parseLibrary(ParsingContext context, Document doc) throws ParserConf private void parseTemplateDefinition(ParsingContext parentContext, Node templateItem) { - if (!templateItem.hasAttributes()) - return; // TODO: Throw error - - TemplateDefinition page = new TemplateDefinition(); - - NamedNodeMap attributes = templateItem.getAttributes(); - Node n = attributes.getNamedItem("id"); - if (n == null) - return; - - templates.put(n.getTextContent(), page); - - var context = new ParsingContext() + ParsingContext.Wrapper context = new ParsingContext.Wrapper(parentContext) { @Override - public Predicate getCondition(String name) + public BookDocument document() { return null; } - - @Override - public boolean loadedFromConfigFolder() - { - return parentContext.loadedFromConfigFolder(); - } - - @Override - public DocumentBuilder xmlDocumentBuilder() - { - return parentContext.xmlDocumentBuilder(); - } }; - - BookDocument.parseChildElements(context, templateItem.getChildNodes(), page.elements, templates, true, TextStyle.DEFAULT); - - attributes.removeNamedItem("id"); - page.attributes = attributes; + BookDocumentParser.parseTemplateDefinition(context, templateItem, templates); } public static Map LIBRARIES = Maps.newHashMap(); From f10308449ae3fc6bdac7859e47432cae9ef2fe16 Mon Sep 17 00:00:00 2001 From: Minecraftschurli Date: Mon, 20 Jun 2022 19:48:13 +0200 Subject: [PATCH 4/8] add datagen and test --- .../gigaherz/guidebook/data/BookProvider.java | 484 ++++++++++++++++++ .../gigaherz/guidebook/data/package-info.java | 7 + .../guidebook/example/GuidebookExample.java | 31 ++ 3 files changed, 522 insertions(+) create mode 100644 src/main/java/dev/gigaherz/guidebook/data/BookProvider.java create mode 100644 src/main/java/dev/gigaherz/guidebook/data/package-info.java diff --git a/src/main/java/dev/gigaherz/guidebook/data/BookProvider.java b/src/main/java/dev/gigaherz/guidebook/data/BookProvider.java new file mode 100644 index 0000000..93fee91 --- /dev/null +++ b/src/main/java/dev/gigaherz/guidebook/data/BookProvider.java @@ -0,0 +1,484 @@ +package dev.gigaherz.guidebook.data; + +import com.google.common.hash.Hashing; +import com.google.common.hash.HashingOutputStream; +import com.google.gson.JsonArray; +import com.mojang.logging.LogUtils; +import net.minecraft.data.CachedOutput; +import net.minecraft.data.DataGenerator; +import net.minecraft.data.DataProvider; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.PackType; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.common.data.ExistingFileHelper; +import net.minecraftforge.common.data.ExistingFileHelper.IResourceType; +import net.minecraftforge.common.data.ExistingFileHelper.ResourceType; +import net.minecraftforge.registries.ForgeRegistries; +import org.slf4j.Logger; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Consumer; + +@SuppressWarnings("unused") +public abstract class BookProvider implements DataProvider +{ + public static final IResourceType RESOURCE_TYPE = new ResourceType(PackType.CLIENT_RESOURCES, ".xml", ""); + + private final Map documents = new HashMap<>(); + private final Logger logger = LogUtils.getLogger(); + + private final DataGenerator generator; + private final ExistingFileHelper existingFileHelper; + private final String modid; + private final DocumentBuilder documentBuilder; + + public BookProvider(DataGenerator generator, ExistingFileHelper existingFileHelper, String modid) + { + this.generator = generator; + this.existingFileHelper = existingFileHelper; + this.modid = modid; + try + { + this.documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + } + catch (ParserConfigurationException e) + { + throw new RuntimeException(e); + } + } + + @Override + public void run(CachedOutput cachedOutput) throws IOException + { + documents.clear(); + createBooks(); + JsonArray books = new JsonArray(); + documents.entrySet() + .stream() + .filter(entry -> "book".equals(entry.getValue().getDocumentElement().getNodeName())) + .map(Map.Entry::getKey) + .map(Objects::toString) + .forEach(books::add); + DataProvider.saveStable(cachedOutput, books, generator.getOutputFolder().resolve("assets/" + modid + "/books.json")); + for (Map.Entry builder : documents.entrySet()) + { + ResourceLocation key = builder.getKey(); + Document value = builder.getValue(); + try + { + save(cachedOutput, makePath(key), value); + } + catch (TransformerException e) + { + logger.error("Couldn't save book {}", key, e); + } + } + } + + private Path makePath(ResourceLocation location) + { + return generator.getOutputFolder() + .resolve(RESOURCE_TYPE.getPackType().getDirectory()) + .resolve(location.getNamespace()) + .resolve(RESOURCE_TYPE.getPrefix()) + .resolve(location.getPath()); + } + + protected abstract void createBooks(); + + @SuppressWarnings({"deprecation", "UnstableApiUsage"}) + private static void save(CachedOutput cachedOutput, Path path, Node doc) throws TransformerException, IOException + { + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + Transformer transformer = transformerFactory.newTransformer(); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + ByteArrayOutputStream bytearrayoutputstream = new ByteArrayOutputStream(); + HashingOutputStream hashingoutputstream = new HashingOutputStream(Hashing.sha1(), bytearrayoutputstream); + transformer.transform(new DOMSource(doc), new StreamResult(hashingoutputstream)); + cachedOutput.writeIfNeeded(path, bytearrayoutputstream.toByteArray(), hashingoutputstream.hash()); + } + + public BookBuilder book(String name) + { + return book(name, false, false, false); + } + + public BookBuilder book(String name, boolean extractChapters, boolean extractSections, boolean extractPages) + { + BookBuilder bookBuilder = new BookBuilder(new ResourceLocation(modid, name + ".xml"), documentBuilder.newDocument(), extractChapters, extractSections, extractPages); + trackDocument(bookBuilder.location, bookBuilder.document()); + return bookBuilder; + } + + protected final void trackDocument(ResourceLocation location, Document doc) + { + existingFileHelper.trackGenerated(location, RESOURCE_TYPE); + documents.put(location, doc); + } + + public abstract static class ElementBuilder + { + private final Document document; + private final Element element; + + protected ElementBuilder(Document document, Element element) + { + this.document = document; + this.element = element; + } + + protected Element createChildElement(String name) + { + Element child = createElement(name); + this.element.appendChild(child); + return child; + } + + protected Element createElement(String name) + { + return document.createElement(name); + } + + protected void setAttribute(String name, String value) + { + this.element.setAttribute(name, value); + } + + public Document document() + { + return document; + } + + public Element element() + { + return element; + } + } + + public class BookBuilder extends ElementBuilder + { + private final Set conditions = new HashSet<>(); + private final ResourceLocation location; + private final boolean extractChapters; + private final boolean extractSections; + private final boolean extractPages; + private Element conditionsElement; + + private static Element root(Document document) + { + document.appendChild(document.createElement("book")); + return document.getDocumentElement(); + } + + private BookBuilder(ResourceLocation location, Document document, boolean extractChapters, boolean extractSections, boolean extractPages) + { + super(document, root(document)); + this.location = location; + this.extractChapters = extractChapters; + this.extractSections = extractSections; + this.extractPages = extractPages; + } + + public BookBuilder title(String title) + { + setAttribute("title", title); + return this; + } + + public BookBuilder cover(ResourceLocation cover) + { + setAttribute("cover", cover.toString()); + return this; + } + + public BookBuilder model(ResourceLocation model) + { + setAttribute("model", model.toString()); + return this; + } + + public BookBuilder background(ResourceLocation background) + { + setAttribute("background", background.toString()); + return this; + } + + public BookBuilder fontSize(float size) + { + setAttribute("fontSize", String.valueOf(size)); + return this; + } + + public BookBuilder home(String chapter, String section) + { + setAttribute("home", chapter + ":" + section); + return this; + } + + public BookBuilder home(String ref) + { + setAttribute("home", ref); + return this; + } + + public BookBuilder dependencies(String... dependencies) + { + setAttribute("dependencies", String.join(",", dependencies)); + return this; + } + + public BookBuilder include(ResourceLocation location) + { + existingFileHelper.exists(location, PackType.CLIENT_RESOURCES); + Element include = createChildElement("include"); + include.setAttribute("ref", location.toString()); + return this; + } + + public BookBuilder chapter(String name, Consumer consumer) + { + return chapter(name, extractChapters, consumer); + } + + public BookBuilder chapter(String name, boolean extract, Consumer consumer) + { + if (extract) + { + Document chapterDoc = documentBuilder.newDocument(); + chapterDoc.appendChild(chapterDoc.createElement("chapter")); + ResourceLocation chapterLocation = new ResourceLocation(location.getNamespace(), String.join("/", location.getPath().split("\\.")[0], "chapters", name + ".xml")); + consumer.accept(new ChapterBuilder(chapterDoc, chapterDoc.getDocumentElement())); + trackDocument(chapterLocation, chapterDoc); + return include(chapterLocation); + } + consumer.accept(new ChapterBuilder(document(), createChildElement("chapter"))); + return this; + } + + public BookBuilder condition(String type, String name, Map attributes) + { + if (this.conditionsElement == null) + this.conditionsElement = createChildElement("conditions"); + Element element = createElement(type); + attributes.forEach(element::setAttribute); + element.setAttribute("name", name); + this.conditionsElement.appendChild(element); + this.conditions.add(name); + return this; + } + + public BookBuilder template(String id, Consumer consumer) + { + Element template = createChildElement("template"); + consumer.accept(template); + template.setAttribute("id", id); + return this; + } + + protected boolean conditionExists(String name) + { + return this.conditions.contains(name); + } + + public class ChapterBuilder extends ElementBuilder + { + public ChapterBuilder(Document document, Element chapterElement) + { + super(document, chapterElement); + } + + public ChapterBuilder id(String id) + { + setAttribute("id", id); + return this; + } + + public ChapterBuilder condition(String condition) + { + if (!conditionExists(condition)) + throw new IllegalArgumentException("Condition " + condition + " does not exist"); + setAttribute("condition", condition); + return this; + } + + public ChapterBuilder include(ResourceLocation location) + { + existingFileHelper.exists(location, PackType.CLIENT_RESOURCES); + Element include = createChildElement("include"); + include.setAttribute("ref", location.toString()); + return this; + } + + public ChapterBuilder page(String name, Consumer consumer) + { + return page(name, extractPages, consumer); + } + + public ChapterBuilder page(String name, boolean extract, Consumer consumer) + { + if (extract) + { + Document pageDoc = documentBuilder.newDocument(); + pageDoc.appendChild(pageDoc.createElement("page")); + ResourceLocation pageLoc = new ResourceLocation(location.getNamespace(), String.join("/", location.getPath().split("\\.")[0], "pages", name + ".xml")); + consumer.accept(new PageBuilder(pageDoc, pageDoc.getDocumentElement())); + trackDocument(pageLoc, pageDoc); + return include(pageLoc); + } + consumer.accept(new PageBuilder(document(), createChildElement("page"))); + return this; + } + + public ChapterBuilder section(String name, Consumer consumer) + { + return section(name, extractSections, consumer); + } + + public ChapterBuilder section(String name, boolean extract, Consumer consumer) + { + if (extract) + { + Document pageDoc = documentBuilder.newDocument(); + pageDoc.appendChild(pageDoc.createElement("section")); + ResourceLocation pageLoc = new ResourceLocation(location.getNamespace(), String.join("/", location.getPath().split("\\.")[0], "sections", name + ".xml")); + consumer.accept(new PageBuilder(pageDoc, pageDoc.getDocumentElement())); + trackDocument(pageLoc, pageDoc); + return include(pageLoc); + } + consumer.accept(new PageBuilder(document(), createChildElement("section"))); + return this; + } + + public class PageBuilder extends ElementBuilder + { + public PageBuilder(Document document, Element pageElement) + { + super(document, pageElement); + } + + public PageBuilder id(String id) + { + setAttribute("id", id); + return this; + } + + public PageBuilder condition(String condition) + { + if (!conditionExists(condition)) + throw new IllegalArgumentException("Condition " + condition + " does not exist"); + setAttribute("condition", condition); + return this; + } + + public PageBuilder sectionBreak() + { + createChildElement("section-break"); + return this; + } + + public PageBuilder include(ResourceLocation location) + { + existingFileHelper.exists(location, PackType.CLIENT_RESOURCES); + Element include = createChildElement("include"); + include.setAttribute("ref", location.toString()); + return this; + } + + public PageBuilder paragraph(Consumer consumer) + { + Element p = createChildElement("p"); + consumer.accept(new ParagraphBuilder(document(), p)); + return this; + } + + public PageBuilder title(String text, Consumer consumer) + { + Element p = createChildElement("title"); + consumer.accept(p); + p.setTextContent(text); + return this; + } + + public PageBuilder text(String text) + { + element().appendChild(document().createTextNode(text)); + return this; + } + + private class ParagraphBuilder extends ElementBuilder + { + public ParagraphBuilder(Document document, Element paragraphElement) + { + super(document, paragraphElement); + } + + public ParagraphBuilder text(String text) + { + element().appendChild(document().createTextNode(text)); + return this; + } + + public ParagraphBuilder node(String type, Consumer consumer) + { + Element p = createChildElement(type); + consumer.accept(p); + return this; + } + + public ParagraphBuilder span(Consumer consumer) + { + return node("span", consumer); + } + + public ParagraphBuilder link(Consumer consumer) + { + return node("a", consumer); + } + + public ParagraphBuilder stack(ItemStack stack) + { + return node("stack", e -> { + if (stack.hasTag()) + e.setAttribute("nbt", stack.getTag().toString()); + if (stack.getCount() > 1) + e.setAttribute("count", String.valueOf(stack.getCount())); + e.setAttribute("item", ForgeRegistries.ITEMS.getKey(stack.getItem()).toString()); + }); + } + + public ParagraphBuilder image(ResourceLocation img, Consumer consumer) + { + return node("image", e -> { + consumer.accept(e); + e.setAttribute("src", img.toString()); + }); + } + + public ParagraphBuilder element(Consumer consumer) + { + return node("element", consumer); + } + } + } + } + } +} diff --git a/src/main/java/dev/gigaherz/guidebook/data/package-info.java b/src/main/java/dev/gigaherz/guidebook/data/package-info.java new file mode 100644 index 0000000..ceca890 --- /dev/null +++ b/src/main/java/dev/gigaherz/guidebook/data/package-info.java @@ -0,0 +1,7 @@ +@MethodsReturnNonnullByDefault +@ParametersAreNonnullByDefault +package dev.gigaherz.guidebook.data; + +import net.minecraft.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/test/java/dev/gigaherz/guidebook/example/GuidebookExample.java b/src/test/java/dev/gigaherz/guidebook/example/GuidebookExample.java index 058f03f..63ccf0e 100644 --- a/src/test/java/dev/gigaherz/guidebook/example/GuidebookExample.java +++ b/src/test/java/dev/gigaherz/guidebook/example/GuidebookExample.java @@ -1,6 +1,8 @@ package dev.gigaherz.guidebook.example; +import dev.gigaherz.guidebook.data.BookProvider; import dev.gigaherz.guidebook.guidebook.GuidebookItem; +import net.minecraft.data.DataGenerator; import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.Entity; @@ -8,10 +10,14 @@ import net.minecraft.world.item.ItemStack; import net.minecraftforge.common.util.Lazy; import net.minecraftforge.event.entity.EntityJoinWorldEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.forge.event.lifecycle.GatherDataEvent; import net.minecraftforge.registries.RegistryObject; import net.minecraftforge.items.ItemHandlerHelper; import net.minecraftforge.registries.ForgeRegistries; +@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD, modid = "gbook") public class GuidebookExample { public static final RegistryObject GUIDEBOOK_ITEM = RegistryObject.create(new ResourceLocation("gbook","guidebook"), ForgeRegistries.ITEMS); @@ -26,6 +32,31 @@ public void test() { } + @SubscribeEvent + public static void testDatagen(GatherDataEvent event) + { + DataGenerator generator = event.getGenerator(); + generator.addProvider(event.includeClient(), new BookProvider(generator, event.getExistingFileHelper(), "gbooktest") { + + @Override + public String getName() + { + return "Guidebook Test"; + } + + @Override + protected void createBooks() + { + book("testbook") + .chapter("testchapter1", chapterBuilder -> chapterBuilder.page("testpage1", pageBuilder -> pageBuilder.text("testtext1"))) + .chapter("testchapter2", chapterBuilder -> {}); + book("extracted-testbook", true, true, true) + .chapter("testchapter1", chapterBuilder -> chapterBuilder.page("testpage1", pageBuilder -> pageBuilder.text("testtext1"))) + .chapter("testchapter2", chapterBuilder -> {}); + } + }); + } + public static void checkGbookGiven(EntityJoinWorldEvent event) { if (MY_BOOK.get().getCount() > 0) From 528a0965d5e0e65882fed4398fd251a7916e1dc4 Mon Sep 17 00:00:00 2001 From: Minecraftschurli Date: Tue, 21 Jun 2022 11:35:36 +0200 Subject: [PATCH 5/8] more cleanup --- .../guidebook/book/BookDocumentParser.java | 125 +++++++++--------- .../guidebook/elements/ElementParagraph.java | 2 +- .../guidebook/elements/ElementRecipe.java | 2 +- .../guidebook/elements/ElementText.java | 15 ++- .../recipe/RecipeLayoutProviders.java | 12 +- .../recipe/VanillaRecipeLayoutProvider.java | 25 ++-- .../guidebook/templates/TemplateLibrary.java | 8 +- .../resources/assets/gbook/xml/guidebook.xml | 23 ++-- .../resources/assets/gbook/xml/standard.xml | 2 +- 9 files changed, 109 insertions(+), 105 deletions(-) diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/book/BookDocumentParser.java b/src/main/java/dev/gigaherz/guidebook/guidebook/book/BookDocumentParser.java index 5327a92..a3eeb32 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/book/BookDocumentParser.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/book/BookDocumentParser.java @@ -19,6 +19,7 @@ import net.minecraft.world.item.Item; import net.minecraftforge.fml.ModList; import net.minecraftforge.registries.ForgeRegistries; +import org.jetbrains.annotations.NotNull; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; @@ -308,19 +309,16 @@ public boolean isLastElement() } @Nullable - public static ElementInline parseParagraphElement(ParsingContext context, Node elementItem, String nodeName, TextStyle defaultStyle) + public static ElementInline parseParagraphElement(ParsingContext context, Node elementItem, TextStyle defaultStyle) { if (elementItem.getNodeType() != Node.TEXT_NODE) { - return createInlineElement(context, defaultStyle, elementItem, new ResourceLocation(nodeName)); + return createInlineElement(context, defaultStyle, elementItem, getNodeLoc(elementItem)); } - else + String textContent = ElementText.compactString(elementItem.getTextContent(), context.isFirstElement(), context.isLastElement()); + if (!Strings.isNullOrEmpty(textContent)) { - String textContent = ElementText.compactString(elementItem.getTextContent(), context.isFirstElement(), context.isLastElement()); - if (!Strings.isNullOrEmpty(textContent)) - { - return ElementSpan.of(textContent, context.isFirstElement(), context.isLastElement(), defaultStyle); - } + return ElementSpan.of(textContent, context.isFirstElement(), context.isLastElement(), defaultStyle); } return null; } @@ -347,59 +345,66 @@ public boolean isLastElement() } }; - Node elementItem = elementsList.item(k); - - ElementInline parsedElement = null; + parseRunElement(context, elements, elementsList.item(k), defaultStyle); + } + } - String nodeName = elementItem.getNodeName(); - ResourceLocation nodeLoc = - elementItem.getNodeType() == Node.ELEMENT_NODE ? - new ResourceLocation(nodeName) : new ResourceLocation("_"); + private static void parseRunElement(ParsingContext context, List elements, Node elementItem, TextStyle defaultStyle) + { + String nodeName = elementItem.getNodeName(); + ResourceLocation nodeLoc = getNodeLoc(elementItem); - if (BookDocumentParser.elements.containsKey(nodeLoc)) + if (BookDocumentParser.elements.containsKey(nodeLoc)) + { + if (createElement(context, Collections.emptyMap(), defaultStyle, elementItem, nodeLoc) instanceof ElementInline inline) { - if (createElement(context, Collections.emptyMap(), defaultStyle, elementItem, nodeLoc) instanceof ElementInline inline) - { - if (elementItem.hasAttributes()) - { - inline.parse(context, elementItem.getAttributes()); - } - - if (elementItem.hasChildNodes()) - { - inline.parseChildNodes(context, elementItem.getChildNodes(), Collections.emptyMap(), defaultStyle); - } - - parsedElement = inline; - } + elements.add(inline); } - else if (inlineElements.containsKey(nodeLoc)) + } + else if (inlineElements.containsKey(nodeLoc)) + { + var e = createInlineElement(context, defaultStyle, elementItem, nodeLoc); + if (e != null) { - parsedElement = createInlineElement(context, defaultStyle, elementItem, nodeLoc); + elements.add(e); } - else if (elementItem.getNodeType() == Node.TEXT_NODE) + } + else + { + var e = switch (elementItem.getNodeType()) { - String textContent = ElementText.compactString(elementItem.getTextContent(), context.isFirstElement(), context.isLastElement()); - if (!Strings.isNullOrEmpty(textContent)) + case Node.TEXT_NODE -> { - parsedElement = ElementSpan.of(textContent, context.isFirstElement(), context.isLastElement(), defaultStyle); + String textContent = ElementText.compactString(elementItem.getTextContent(), context.isFirstElement(), context.isLastElement()); + if (!Strings.isNullOrEmpty(textContent)) + { + yield ElementSpan.of(textContent, context.isFirstElement(), context.isLastElement(), defaultStyle); + } + yield null; } - } - else if (elementItem.getNodeType() != Node.COMMENT_NODE) - { - parsedElement = parseParagraphElement(context, elementItem, nodeName, defaultStyle); - - if (parsedElement == null) + case Node.COMMENT_NODE -> null; + default -> { - GuidebookMod.logger.warn("Unrecognized tag: {}", nodeName); + var el = parseParagraphElement(context, elementItem, defaultStyle); + if (el == null) + { + GuidebookMod.logger.warn("Unrecognized tag: {}", nodeName); + } + yield el; } - } - - if (parsedElement != null) + }; + if (e != null) { - elements.add(parsedElement); + elements.add(e); } } + + } + + @NotNull + private static ResourceLocation getNodeLoc(Node elementItem) + { + return elementItem.getNodeType() == Node.ELEMENT_NODE ? new ResourceLocation(elementItem.getNodeName()) : new ResourceLocation("_"); } private static void registerDefaultElement(String location, ElementFactory factory) @@ -438,11 +443,10 @@ private static void parseDocumentLevelElement(ParsingContext context, AtomicInte String nodeName = firstLevelNode.getNodeName(); if ("include".equals(nodeName)) { - parseInclude(context, firstLevelNode, (resLoc, document) -> { - var includeRoot = document.getDocumentElement(); - if (includeRoot.getTagName().equals("library")) + parseInclude(context, firstLevelNode, (resLoc, includeRoot) -> { + if ("library".equals(includeRoot.getNodeName())) { - TemplateLibrary tpl = TemplateLibrary.get(context, resLoc, document); + TemplateLibrary tpl = TemplateLibrary.get(context, resLoc, includeRoot); context.document().templates.putAll(tpl.templates); } else @@ -454,7 +458,7 @@ private static void parseDocumentLevelElement(ParsingContext context, AtomicInte } if (firstLevelNode.getNodeType() != Node.ELEMENT_NODE) return; - DocumentLevelElementParser parser = documentLevelElements.get(new ResourceLocation(nodeName)); + DocumentLevelElementParser parser = documentLevelElements.get(getNodeLoc(firstLevelNode)); if (parser != null) { parser.parse(context, chapterNumber, firstLevelNode); @@ -539,11 +543,11 @@ private static void parseChapterElement(ParsingContext context, int chapterNumbe { if ("include".equals(pageItem.getNodeName())) { - parseInclude(context, pageItem, (name, doc) -> parseChapterElement(context, chapterNumber, chapter, sectionNumber, doc.getDocumentElement())); + parseInclude(context, pageItem, (name, doc) -> parseChapterElement(context, chapterNumber, chapter, sectionNumber, doc)); } - else if (pageItem.getNodeType() == Node.ELEMENT_NODE && pages.containsKey(new ResourceLocation(pageItem.getNodeName()))) + else if (pageItem.getNodeType() == Node.ELEMENT_NODE && pages.containsKey(getNodeLoc(pageItem))) { - PageFactory factory = pages.get(new ResourceLocation(pageItem.getNodeName())); + PageFactory factory = pages.get(getNodeLoc(pageItem)); PageData page = factory.newInstance(new SectionRef(chapterNumber, sectionNumber.getAndIncrement())); parseSection(context, chapter, pageItem, page); } @@ -573,7 +577,7 @@ public ChapterData chapter() } } - private static void parseInclude(ParsingContext context, Node firstLevelNode, BiConsumer includeAction) + private static void parseInclude(ParsingContext context, Node firstLevelNode, BiConsumer includeAction) { NamedNodeMap attributes = firstLevelNode.getAttributes(); Node n = attributes.getNamedItem("ref"); @@ -629,7 +633,7 @@ private static void parseInclude(ParsingContext context, Node firstLevelNode, Bi } }); - includeAction.accept(id, include); + includeAction.accept(id, include.getDocumentElement()); } private static Predicate parseSingleCondition(Node condition) @@ -657,13 +661,12 @@ private static void parsePageElement(ParsingContext context, List eleme String nodeName = elementItem.getNodeName(); ResourceLocation nodeLoc = - elementItem.getNodeType() == Node.ELEMENT_NODE ? - new ResourceLocation(nodeName) : new ResourceLocation("_"); + getNodeLoc(elementItem); if ("include".equals(nodeName)) { parseInclude(context, elementItem, (name, document) -> - parsePageElement(context, elements, templates, generateParagraphs, defaultStyle, document.getDocumentElement()) + parsePageElement(context, elements, templates, generateParagraphs, defaultStyle, document) ); } else if (BookDocumentParser.elements.containsKey(nodeLoc)) @@ -705,7 +708,7 @@ else if (elementItem.getNodeType() == Node.TEXT_NODE) } else if (elementItem.getNodeType() != Node.COMMENT_NODE) { - parsedElement = parseParagraphElement(context, elementItem, nodeName, defaultStyle); + parsedElement = parseParagraphElement(context, elementItem, defaultStyle); if (parsedElement == null) { diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementParagraph.java b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementParagraph.java index fe7b8f6..d32b65c 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementParagraph.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementParagraph.java @@ -217,7 +217,7 @@ public void parseChildNodes(ParsingContext context, NodeList childNodes, Map style + MutableComponent mutable; + if (text instanceof Component) + { + mutable = ((Component) text).copy(); + } + else + { + mutable = Component.literal(text.getString()); + } + return mutable.withStyle(style -> style .withBold(bold) .withItalic(italics) .withUnderlined(underline) @@ -61,9 +71,8 @@ public List measure(IBookGraphics nav, int width, int firstLineWi List elements = nav.measure(getStringWithFormat(getActualString()), width, firstLineWidth, scale, position, baseline, verticalAlignment); for (VisualElement text : elements) { - if (text instanceof VisualText) + if (text instanceof VisualText visualText) { - VisualText visualText = (VisualText) text; visualText.color = color; } } diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/recipe/RecipeLayoutProviders.java b/src/main/java/dev/gigaherz/guidebook/guidebook/recipe/RecipeLayoutProviders.java index 0ab0c1f..f7369a9 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/recipe/RecipeLayoutProviders.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/recipe/RecipeLayoutProviders.java @@ -1,9 +1,9 @@ package dev.gigaherz.guidebook.guidebook.recipe; import com.google.common.collect.Maps; -import net.minecraft.core.Registry; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.crafting.RecipeType; +import net.minecraftforge.registries.ForgeRegistries; import javax.annotation.Nonnull; import java.util.Map; @@ -14,14 +14,16 @@ public class RecipeLayoutProviders private static final Map registry = Maps.newHashMap(); - public static void register(RecipeType type, VanillaRecipeLayoutProvider provider) + public static void register(RecipeType type, IRecipeLayoutProvider provider) { - ResourceLocation id = Registry.RECIPE_TYPE.getKey(type); - registry.put(id, provider); + ResourceLocation id = ForgeRegistries.RECIPE_TYPES.getKey(type); + registerAlias(id, provider); } - public static void registerAlias(ResourceLocation id, VanillaRecipeLayoutProvider provider) + public static void registerAlias(ResourceLocation id, IRecipeLayoutProvider provider) { + if (registry.containsKey(id)) + throw new IllegalArgumentException("Duplicate recipe layout provider for " + id); registry.put(id, provider); } diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/recipe/VanillaRecipeLayoutProvider.java b/src/main/java/dev/gigaherz/guidebook/guidebook/recipe/VanillaRecipeLayoutProvider.java index 3487d8f..2a566fb 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/recipe/VanillaRecipeLayoutProvider.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/recipe/VanillaRecipeLayoutProvider.java @@ -18,8 +18,8 @@ import java.util.ArrayList; /** - * @author joazlazer * A class designed to provide both shaped and shapeless crafting recipes for display in Guidebooks + * @author joazlazer */ public class VanillaRecipeLayoutProvider implements IRecipeLayoutProvider { @@ -71,9 +71,8 @@ private RecipeLayout getRecipeLayout(@Nonnull Recipe recipe) else { int gridHeight; - if (recipe instanceof IShapedRecipe) + if (recipe instanceof IShapedRecipe shapedRecipe) { - IShapedRecipe shapedRecipe = (IShapedRecipe) recipe; gridWidth = shapedRecipe.getRecipeWidth(); gridHeight = shapedRecipe.getRecipeHeight(); } @@ -84,18 +83,12 @@ private RecipeLayout getRecipeLayout(@Nonnull Recipe recipe) gridHeight = Mth.ceil(ingredients / (double) gridWidth); } - switch (Math.max(gridWidth, gridHeight)) + recipeGraphic = switch (Math.max(gridWidth, gridHeight)) { - case 1: - recipeGraphic = 3; - break; - case 2: - recipeGraphic = 1; - break; - default: - recipeGraphic = 0; - break; - } + case 1 -> 3; + case 2 -> 1; + default -> 0; + }; } ArrayList stackComponents = new ArrayList<>(); @@ -110,9 +103,9 @@ private RecipeLayout getRecipeLayout(@Nonnull Recipe recipe) if (matching.length == 0) continue; // If the recipe area is blank, continue and ignore // Copy each stack - for (int j = 0; j < matching.length; ++j) + for (ItemStack itemStack : matching) { - inputSlot.stacks.add(matching[j].copy()); + inputSlot.stacks.add(itemStack.copy()); } int posX = i % gridWidth; diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/templates/TemplateLibrary.java b/src/main/java/dev/gigaherz/guidebook/guidebook/templates/TemplateLibrary.java index 13ca49b..abb1c2d 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/templates/TemplateLibrary.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/templates/TemplateLibrary.java @@ -50,11 +50,9 @@ public void parseLibrary(ParsingContext context, InputStream stream) throws Pars } } - public void parseLibrary(ParsingContext context, Document doc) throws ParserConfigurationException, IOException, SAXException + public void parseLibrary(ParsingContext context, Node root) throws ParserConfigurationException, IOException, SAXException { - doc.getDocumentElement().normalize(); - - Node root = doc.getChildNodes().item(0); + root.normalize(); NodeList chaptersList = root.getChildNodes(); for (int i = 0; i < chaptersList.getLength(); i++) @@ -136,7 +134,7 @@ public static TemplateLibrary get(ParsingContext context, String path, boolean u return lib; } - public static TemplateLibrary get(ParsingContext context, ResourceLocation path, Document doc) + public static TemplateLibrary get(ParsingContext context, ResourceLocation path, Node doc) { TemplateLibrary lib = LIBRARIES.get(path.toString()); if (lib == null) diff --git a/src/main/resources/assets/gbook/xml/guidebook.xml b/src/main/resources/assets/gbook/xml/guidebook.xml index ad66951..58d3e25 100644 --- a/src/main/resources/assets/gbook/xml/guidebook.xml +++ b/src/main/resources/assets/gbook/xml/guidebook.xml @@ -235,7 +235,7 @@

Recipe Keys

Another way to declare a recipe is to use its registry name. Simply use the key attribute and specify the domain ("minecraft" by default) as well as the path for the json file that the recipe was contained in. For example, the following XML:

-

<recipe type="crafting" key="minecraft:fire_charge"/>

+

<recipe type="crafting" key="minecraft:fire_charge"/>

@@ -287,18 +287,17 @@
Template Libraries

Templates can be defined inside template library files, and thosefiles can be included from books.

-

Browse this mod's source code on github for an example of use and declaration.

+

Browse this mod's source code on GitHub for an example of use and declaration.

Although the recipe panel system exists, another way to display recipes is to declare them using the template system. The result looks as follows:

-

For Items with multiple Id's (for example orange dye - 351:14) use the meta tag as below for bonemeal

- + - + @@ -309,13 +308,13 @@ - - - - - - - + + + + + + +
diff --git a/src/main/resources/assets/gbook/xml/standard.xml b/src/main/resources/assets/gbook/xml/standard.xml index 2bdc5f2..f38951a 100644 --- a/src/main/resources/assets/gbook/xml/standard.xml +++ b/src/main/resources/assets/gbook/xml/standard.xml @@ -33,4 +33,4 @@

- \ No newline at end of file + From 53b7337aee363719066bab8facf7c2959da73a4b Mon Sep 17 00:00:00 2001 From: Minecraftschurli Date: Tue, 21 Jun 2022 18:11:47 +0200 Subject: [PATCH 6/8] more cleanup and refactoring --- .../dev/gigaherz/guidebook/GuidebookMod.java | 7 +- .../guidebook/guidebook/book/IParseable.java | 112 ++++++++ .../guidebook/guidebook/book/PageData.java | 6 +- .../guidebook/guidebook/book/PageGroup.java | 24 +- .../guidebook/client/BookRendering.java | 43 ++- .../guidebook/drawing/VisualElement.java | 2 +- .../guidebook/drawing/VisualImage.java | 2 +- .../guidebook/drawing/VisualPanel.java | 8 +- .../guidebook/drawing/VisualStack.java | 2 +- .../guidebook/drawing/VisualText.java | 7 +- .../guidebook/guidebook/elements/Element.java | 166 +---------- .../guidebook/elements/ElementBreak.java | 2 +- .../guidebook/elements/ElementGrid.java | 33 ++- .../guidebook/elements/ElementImage.java | 17 +- .../guidebook/elements/ElementPanel.java | 19 +- .../guidebook/elements/ElementParagraph.java | 83 +++--- .../guidebook/elements/ElementRecipe.java | 8 +- .../guidebook/elements/ElementStack.java | 7 +- .../guidebook/elements/ElementText.java | 22 +- .../guidebook/elements/ElementTitle.java | 4 +- .../guidebook/elements/LinkContext.java | 2 +- .../guidebook/elements/TextStyle.java | 58 ++-- .../guidebook/guidebook/util/Color.java | 266 ++++++++++++++++++ .../guidebook/guidebook/util/LinkHelper.java | 34 ++- .../guidebook/guidebook/util/Point.java | 18 -- .../guidebook/guidebook/util/Point2D.java | 22 ++ .../guidebook/guidebook/util/Point2F.java | 22 ++ .../guidebook/guidebook/util/Point2I.java | 22 ++ .../guidebook/guidebook/util/PointD.java | 18 -- .../guidebook/guidebook/util/PointF.java | 18 -- .../guidebook/guidebook/util/Rect.java | 37 ++- .../guidebook/guidebook/util/Size.java | 18 +- .../resources/assets/gbook/lang/en_us.json | 3 +- 33 files changed, 688 insertions(+), 424 deletions(-) create mode 100644 src/main/java/dev/gigaherz/guidebook/guidebook/util/Color.java delete mode 100644 src/main/java/dev/gigaherz/guidebook/guidebook/util/Point.java create mode 100644 src/main/java/dev/gigaherz/guidebook/guidebook/util/Point2D.java create mode 100644 src/main/java/dev/gigaherz/guidebook/guidebook/util/Point2F.java create mode 100644 src/main/java/dev/gigaherz/guidebook/guidebook/util/Point2I.java delete mode 100644 src/main/java/dev/gigaherz/guidebook/guidebook/util/PointD.java delete mode 100644 src/main/java/dev/gigaherz/guidebook/guidebook/util/PointF.java diff --git a/src/main/java/dev/gigaherz/guidebook/GuidebookMod.java b/src/main/java/dev/gigaherz/guidebook/GuidebookMod.java index a2c5a65..b564c27 100644 --- a/src/main/java/dev/gigaherz/guidebook/GuidebookMod.java +++ b/src/main/java/dev/gigaherz/guidebook/GuidebookMod.java @@ -18,11 +18,10 @@ import net.minecraftforge.fml.event.config.ModConfigEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import net.minecraftforge.items.ItemHandlerHelper; -import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.ObjectHolder; import net.minecraftforge.registries.RegisterEvent; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; @Mod(GuidebookMod.MODID) public class GuidebookMod @@ -35,7 +34,7 @@ public class GuidebookMod @ObjectHolder(value = "gbook:guidebook", registryName = "item") public static GuidebookItem guidebook; - public static final Logger logger = LogManager.getLogger(MODID); + public static final Logger logger = LoggerFactory.getLogger(MODID); public static final CreativeModeTab tabGuidebooks = new CreativeModeTab(MODID) { diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/book/IParseable.java b/src/main/java/dev/gigaherz/guidebook/guidebook/book/IParseable.java index eac8e72..efa0b23 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/book/IParseable.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/book/IParseable.java @@ -1,8 +1,12 @@ package dev.gigaherz.guidebook.guidebook.book; +import dev.gigaherz.guidebook.GuidebookMod; import dev.gigaherz.guidebook.guidebook.elements.TextStyle; import dev.gigaherz.guidebook.guidebook.templates.TemplateDefinition; +import dev.gigaherz.guidebook.guidebook.util.Color; +import net.minecraft.resources.ResourceLocation; import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; import org.w3c.dom.NodeList; import java.util.Map; @@ -17,4 +21,112 @@ default TextStyle childStyle(ParsingContext context, NamedNodeMap attributes, Te { return defaultStyle; } + + static String getAttribute(NamedNodeMap attributes, String name, String def) + { + Node attr = attributes.getNamedItem(name); + if (attr != null) + { + String text = attr.getTextContent(); + if (text != null) + return text; + } + return def; + } + + static ResourceLocation getAttribute(NamedNodeMap attributes, String name, ResourceLocation def) + { + Node attr = attributes.getNamedItem(name); + if (attr != null) + { + String text = attr.getTextContent(); + if (text != null) + return new ResourceLocation(text); + } + return def; + } + + static boolean getAttribute(NamedNodeMap attributes, String name, boolean def) + { + Node attr = attributes.getNamedItem(name); + if (attr != null) + { + String text = attr.getTextContent(); + return text.isEmpty() || Boolean.parseBoolean(text); + } + return def; + } + + static int getAttribute(NamedNodeMap attributes, String name, int def) + { + Node attr = attributes.getNamedItem(name); + if (attr != null) + { + String text = attr.getTextContent(); + try + { + return Integer.parseInt(text); + } + catch (NumberFormatException e) + { + // ignored + } + } + return def; + } + + static float getAttribute(NamedNodeMap attributes, String name, float def) + { + Node attr = attributes.getNamedItem(name); + if (attr != null) + { + String text = attr.getTextContent(); + try + { + return Float.parseFloat(text); + } + catch (NumberFormatException e) + { + // ignored + } + } + return def; + } + + static > T getAttribute(NamedNodeMap attributes, String name, T def, Class enumClass) + { + Node attr = attributes.getNamedItem(name); + if (attr != null) + { + String text = attr.getTextContent(); + if (text != null) + { + try + { + return T.valueOf(enumClass, text.toUpperCase()); + } + catch (IllegalArgumentException ignored) + { + } + } + } + return def; + } + + static Color getAttribute(NamedNodeMap attributes, String name, Color def) + { + Node attr = attributes.getNamedItem(name); + + if (attr == null) return def; + + try + { + return Color.parse(attr.getTextContent()); + } + catch (Color.ColorParseException e) + { + GuidebookMod.logger.warn("Color value not valid {}", e.getColorString(), e); + return def; + } + } } diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/book/PageData.java b/src/main/java/dev/gigaherz/guidebook/guidebook/book/PageData.java index 615e87b..5f124e0 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/book/PageData.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/book/PageData.java @@ -7,7 +7,7 @@ import dev.gigaherz.guidebook.guidebook.elements.Element; import dev.gigaherz.guidebook.guidebook.elements.TextStyle; import dev.gigaherz.guidebook.guidebook.templates.TemplateDefinition; -import dev.gigaherz.guidebook.guidebook.util.Point; +import dev.gigaherz.guidebook.guidebook.util.Point2I; import dev.gigaherz.guidebook.guidebook.util.Rect; import dev.gigaherz.guidebook.guidebook.util.Size; import org.w3c.dom.NamedNodeMap; @@ -36,14 +36,14 @@ public PageData(SectionRef ref) public List reflow(IBookGraphics rendering, Size pageSize) { VisualPage page = new VisualPage(ref); - Rect pageBounds = new Rect(new Point(), pageSize); + Rect pageBounds = new Rect(new Point2I(), pageSize); int top = 0; for (Element element : elements) { if (element.conditionResult) { - top = element.reflow(page.children, rendering, new Rect(new Point(0, top), pageSize), pageBounds); + top = element.reflow(page.children, rendering, new Rect(new Point2I(0, top), pageSize), pageBounds); } } diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/book/PageGroup.java b/src/main/java/dev/gigaherz/guidebook/guidebook/book/PageGroup.java index 68d3a24..44f1e37 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/book/PageGroup.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/book/PageGroup.java @@ -6,7 +6,7 @@ import dev.gigaherz.guidebook.guidebook.drawing.VisualPage; import dev.gigaherz.guidebook.guidebook.drawing.VisualPageBreak; import dev.gigaherz.guidebook.guidebook.elements.Element; -import dev.gigaherz.guidebook.guidebook.util.Point; +import dev.gigaherz.guidebook.guidebook.util.Point2I; import dev.gigaherz.guidebook.guidebook.util.Rect; import dev.gigaherz.guidebook.guidebook.util.Size; @@ -46,21 +46,21 @@ public List reflow(IBookGraphics rendering, Size pageSize) List pages = Lists.newArrayList(); VisualPage page = new VisualPage(ref); - Rect pageBounds = new Rect(new Point(0, 0), pageSize); + Rect pageBounds = new Rect(new Point2I(0, 0), pageSize); - int top = pageBounds.position.y; + int top = pageBounds.position.y(); for (Element element : elements) { if (element.conditionResult) { - top = element.reflow(page.children, rendering, new Rect(new Point(pageBounds.position.x, top), pageBounds.size), pageBounds); + top = element.reflow(page.children, rendering, new Rect(new Point2I(pageBounds.position.x(), top), pageBounds.size), pageBounds); } } boolean needsRepagination = false; for (VisualElement child : page.children) { - if (child instanceof VisualPageBreak || (child.position.y + child.size.height > (pageBounds.position.y + pageBounds.size.height))) + if (child instanceof VisualPageBreak || (child.position.y() + child.size.height() > (pageBounds.position.y() + pageBounds.size.height()))) { needsRepagination = true; break; @@ -75,14 +75,14 @@ public List reflow(IBookGraphics rendering, Size pageSize) boolean pageBreakRequired = false; for (VisualElement child : page.children) { - int cpy = child.position.y + offsetY; - if (pageBreakRequired || (cpy + child.size.height > (pageBounds.position.y + pageBounds.size.height) - && child.position.y > pageBounds.position.y)) + int cpy = child.position.y() + offsetY; + if (pageBreakRequired || (cpy + child.size.height() > (pageBounds.position.y() + pageBounds.size.height()) + && child.position.y() > pageBounds.position.y())) { pages.add(page2); page2 = new VisualPage(ref); - offsetY = pageBounds.position.y - child.position.y; + offsetY = pageBounds.position.y() - child.position.y(); pageBreakRequired = false; } @@ -92,9 +92,9 @@ public List reflow(IBookGraphics rendering, Size pageSize) } else { - child.position = new Point( - child.position.x, - child.position.y + offsetY); + child.position = new Point2I( + child.position.x(), + child.position.y() + offsetY); page2.children.add(child); } } diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/client/BookRendering.java b/src/main/java/dev/gigaherz/guidebook/guidebook/client/BookRendering.java index c3d8d64..3a06dde 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/client/BookRendering.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/client/BookRendering.java @@ -16,7 +16,7 @@ import dev.gigaherz.guidebook.guidebook.drawing.VisualElement; import dev.gigaherz.guidebook.guidebook.drawing.VisualPage; import dev.gigaherz.guidebook.guidebook.drawing.VisualText; -import dev.gigaherz.guidebook.guidebook.util.PointD; +import dev.gigaherz.guidebook.guidebook.util.Point2D; import dev.gigaherz.guidebook.guidebook.util.Size; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; @@ -481,9 +481,9 @@ public int addString(PoseStack matrixStack, int left, int top, Component text, i double top0 = top; if (hasScale && ConfigValues.flexibleScale) { - PointD pt = getPageOffset(currentDrawingPage); - left0 = Math.floor((pt.x + left) * scalingFactor) / scalingFactor - pt.x; - top0 = Math.floor((pt.y + top) * scalingFactor) / scalingFactor - pt.y; + Point2D pt = getPageOffset(currentDrawingPage); + left0 = Math.floor((pt.x() + left) * scalingFactor) / scalingFactor - pt.x(); + top0 = Math.floor((pt.y() + top) * scalingFactor) / scalingFactor - pt.y(); } // Does scaling need to be performed? @@ -544,13 +544,13 @@ public boolean mouseClicked(int mx, int my, int mouseButton) private boolean mouseClickPage(double mX, double mY, VisualPage pg, boolean isLeftPage) { - PointD offset = getPageOffset(isLeftPage); - mX -= offset.x; - mY -= offset.y; + Point2D offset = getPageOffset(isLeftPage); + mX -= offset.x(); + mY -= offset.y(); for (VisualElement e : pg.children) { - if (mX >= e.position.x && mX <= (e.position.x + e.size.width) && - mY >= e.position.y && mY <= (e.position.y + e.size.height)) + if (mX >= e.position.x() && mX <= (e.position.x() + e.size.width()) && + mY >= e.position.y() && mY <= (e.position.y() + e.size.height())) { e.click(this); return true; @@ -609,22 +609,17 @@ private VisualElement mouseHoverPage(VisualPage pg, boolean isLeftPage, HoverCon GLFW.glfwGetCursorPos(mc.getWindow().getWindow(), xPos, yPos); double mX = xPos[0] * dw / width; double mY = yPos[0] * dh / height; - PointD offset = getPageOffset(isLeftPage); + Point2D offset = getPageOffset(isLeftPage); - mX -= offset.x; - mY -= offset.y; + mX -= offset.x(); + mY -= offset.y(); mouseCoords.mouseScaledX = mX; mouseCoords.mouseScaledY = mY; for (VisualElement e : pg.children) { - if (mX >= e.position.x && mX <= (e.position.x + e.size.width) && - mY >= e.position.y && mY <= (e.position.y + e.size.height)) - { - if (e.wantsHover()) - return e; - } + if (e.contains(mX, mY) && e.wantsHover()) return e; } return null; @@ -655,13 +650,13 @@ public void drawCurrentPages(PoseStack matrixStack) } } - private PointD getPageOffset(boolean leftPage) + private Point2D getPageOffset(boolean leftPage) { double left = (scaledWidth - bookWidth) / 2 + outerMargin; double right = left + pageWidth + innerMargin * 2; double top = (scaledHeight - bookHeight) / 2 + topMargin; - return new PointD(leftPage ? left : right, top); + return new Point2D(leftPage ? left : right, top); } private void drawPage(PoseStack matrixStack, int page) @@ -674,12 +669,12 @@ private void drawPage(PoseStack matrixStack, int page) VisualPage pg = ch.pages.get(page); - PointD offset = getPageOffset(currentDrawingPage); + Point2D offset = getPageOffset(currentDrawingPage); matrixStack.pushPose(); if (ConfigValues.flexibleScale) - matrixStack.translate(offset.x, offset.y, 0); + matrixStack.translate(offset.x(), offset.y(), 0); else - matrixStack.translate((int) offset.x, (int) offset.y, 0); + matrixStack.translate((int) offset.x(), (int) offset.y(), 0); if (DEBUG_DRAW_BOUNDS) { @@ -694,7 +689,7 @@ private void drawPage(PoseStack matrixStack, int page) Component cnt = Component.literal(String.valueOf(ch.startPair * 2 + page + 1)); Size sz = measure(cnt); - addString(matrixStack, (pageWidth - sz.width) / 2, pageHeight + 8, cnt, 0xFF000000, 1.0f); + addString(matrixStack, (pageWidth - sz.width()) / 2, pageHeight + 8, cnt, 0xFF000000, 1.0f); matrixStack.popPose(); } diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualElement.java b/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualElement.java index a198b6f..695426d 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualElement.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualElement.java @@ -36,7 +36,7 @@ public void draw(IBookGraphics nav, PoseStack matrixStack) { if (BookRendering.DEBUG_DRAW_BOUNDS) { - GuiComponent.fill(matrixStack, this.position.x, this.position.y, this.position.x + this.size.width, this.position.y + this.size.height, 0x3f000000); + GuiComponent.fill(matrixStack, this.position.x(), this.position.y(), this.position.x() + this.size.width(), this.position.y() + this.size.height(), 0x3f000000); } } diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualImage.java b/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualImage.java index a1e799b..e773cfc 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualImage.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualImage.java @@ -39,7 +39,7 @@ public VisualImage(Size size, int positionMode, float baseline, int verticalAlig public void draw(IBookGraphics nav, PoseStack matrixStack) { super.draw(nav, matrixStack); - nav.drawImage(matrixStack, textureLocation, position.x, position.y, tx, ty, w, h, tw, th, scale); + nav.drawImage(matrixStack, textureLocation, position.x(), position.y(), tx, ty, w, h, tw, th, scale); } //public int colorHover = 0xFF77cc66; diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualPanel.java b/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualPanel.java index c6dc5fe..635f3e4 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualPanel.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualPanel.java @@ -34,11 +34,7 @@ public void mouseOver(IBookGraphics nav, HoverContext hoverContext, PoseStack ma VisualElement newOver = null; for (VisualElement child : children) { - if (child.wantsHover() - && x >= child.position.x - && y >= child.position.y - && (x - child.position.x) < child.size.width - && (y - child.position.y) < child.size.height) + if (child.wantsHover() && child.contains(x, y)) { newOver = child; break; @@ -78,6 +74,6 @@ public void click(IBookGraphics nav) @Override public boolean wantsHover() { - return children.stream().anyMatch(e -> e.wantsHover()); + return children.stream().anyMatch(VisualElement::wantsHover); } } diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualStack.java b/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualStack.java index b113cf4..e2215d5 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualStack.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualStack.java @@ -39,7 +39,7 @@ public void draw(IBookGraphics nav, PoseStack matrixStack) ItemStack stack = getCurrentStack(); if (stack.getCount() > 0) { - nav.drawItemStack(matrixStack, position.x, position.y, z, stack, 0xFFFFFFFF, scale); + nav.drawItemStack(matrixStack, position.x(), position.y(), z, stack, 0xFFFFFFFF, scale); } } diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualText.java b/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualText.java index 88bcfca..0ae4645 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualText.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualText.java @@ -4,6 +4,7 @@ import dev.gigaherz.guidebook.guidebook.HoverContext; import dev.gigaherz.guidebook.guidebook.IBookGraphics; import dev.gigaherz.guidebook.guidebook.elements.LinkContext; +import dev.gigaherz.guidebook.guidebook.util.Color; import dev.gigaherz.guidebook.guidebook.util.LinkHelper; import dev.gigaherz.guidebook.guidebook.util.Size; import net.minecraft.network.chat.Component; @@ -12,7 +13,7 @@ public class VisualText extends VisualElement implements LinkHelper.ILinkable { public Component text; - public int color; + public Color color; public float scale; public LinkContext linkContext = null; @@ -29,9 +30,9 @@ public void draw(IBookGraphics nav, PoseStack matrixStack) { super.draw(nav, matrixStack); if (linkContext != null) - nav.addString(matrixStack, position.x, position.y, text, linkContext.isHovering ? linkContext.colorHover : color, scale); + nav.addString(matrixStack, position.x(), position.y(), text, linkContext.isHovering ? linkContext.colorHover : color.argb(), scale); else - nav.addString(matrixStack, position.x, position.y, text, color, scale); + nav.addString(matrixStack, position.x(), position.y(), text, color.argb(), scale); } @Override diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/Element.java b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/Element.java index 191d04f..7842cee 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/Element.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/Element.java @@ -1,16 +1,14 @@ package dev.gigaherz.guidebook.guidebook.elements; -import dev.gigaherz.guidebook.GuidebookMod; import dev.gigaherz.guidebook.guidebook.IBookGraphics; import dev.gigaherz.guidebook.guidebook.book.IParseable; import dev.gigaherz.guidebook.guidebook.book.ParsingContext; import dev.gigaherz.guidebook.guidebook.conditions.ConditionContext; import dev.gigaherz.guidebook.guidebook.drawing.VisualElement; import dev.gigaherz.guidebook.guidebook.templates.TemplateDefinition; -import dev.gigaherz.guidebook.guidebook.util.Point; +import dev.gigaherz.guidebook.guidebook.util.Point2I; import dev.gigaherz.guidebook.guidebook.util.Rect; import net.minecraft.client.resources.model.Material; -import net.minecraft.resources.ResourceLocation; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; @@ -21,7 +19,6 @@ import java.util.Map; import java.util.Set; import java.util.function.Predicate; -import java.util.regex.Matcher; import java.util.regex.Pattern; public abstract class Element implements IParseable @@ -116,14 +113,14 @@ public boolean supportsSpanLevel() return true; } - public Point applyPosition(Point point, Point parent) + public Point2I applyPosition(Point2I point, Point2I parent) { return switch (position) { - case POS_RELATIVE -> new Point(point.x + x, point.y + y); - case POS_ABSOLUTE -> new Point(parent.x + x, parent.y + y); - case POS_FIXED -> new Point(x, y); - default -> new Point(point.x, point.y); + case POS_RELATIVE -> new Point2I(point.x() + x, point.y() + y); + case POS_ABSOLUTE -> new Point2I(parent.x() + x, parent.y() + y); + case POS_FIXED -> new Point2I(x, y); + default -> new Point2I(point); }; } @@ -141,13 +138,13 @@ protected T copy(T other) @Override public void parse(ParsingContext context, NamedNodeMap attributes) { - x = getAttribute(attributes, "x", x); - y = getAttribute(attributes, "y", y); - z = getAttribute(attributes, "z", z); - w = getAttribute(attributes, "w", w); - h = getAttribute(attributes, "h", h); + x = IParseable.getAttribute(attributes, "x", x); + y = IParseable.getAttribute(attributes, "y", y); + z = IParseable.getAttribute(attributes, "z", z); + w = IParseable.getAttribute(attributes, "w", w); + h = IParseable.getAttribute(attributes, "h", h); - baseline = getAttribute(attributes, "baseline", baseline); + baseline = IParseable.getAttribute(attributes, "baseline", baseline); Node attr = attributes.getNamedItem("align"); if (attr != null) @@ -186,145 +183,6 @@ public void parseChildNodes(ParsingContext context, NodeList childNodes, Map[0-9a-f]{3})|(?[0-9a-f]{6})|(?[0-9a-f]{8})|(?rgb\\((?[0-9]{1,3}),(?[0-9]{1,3}),(?[0-9]{1,3})\\))|(?rgba\\((?[0-9]{1,3}),(?[0-9]{1,3}),(?[0-9]{1,3}),(?[0-9]{1,3})\\)))$"); - - protected static int getColorAttribute(NamedNodeMap attributes, int def) - { - Node attr = attributes.getNamedItem("color"); - if (attr != null) - { - String c = attr.getTextContent(); - - Matcher m = COLOR_PARSE.matcher(c); - if (m.matches()) - { - try - { - String value; - if ((value = m.group("c3")) != null) - { - String s = new String(new char[]{value.charAt(0), value.charAt(0), value.charAt(1), value.charAt(1), value.charAt(2), value.charAt(2)}); - return 0xFF000000 | Integer.parseInt(s, 16); - } - else if ((value = m.group("c6")) != null) - { - return 0xFF000000 | Integer.parseInt(value, 16); - } - else if ((value = m.group("c8")) != null) - { - return Integer.parseUnsignedInt(value, 16); - } - else if (m.group("rgb") != null) - { - int r = Integer.parseUnsignedInt(m.group("r")); - int g = Integer.parseUnsignedInt(m.group("g")); - int b = Integer.parseUnsignedInt(m.group("b")); - if (r > 255) throw new NumberFormatException("Number too big. Expected range: 0 to 255"); - if (g > 255) throw new NumberFormatException("Number too big. Expected range: 0 to 255"); - if (b > 255) throw new NumberFormatException("Number too big. Expected range: 0 to 255"); - return 0xFF000000 | (r << 16) | (g << 8) | b; - } - else if (m.group("rgba") != null) - { - int r = Integer.parseUnsignedInt(m.group("r2")); - int g = Integer.parseUnsignedInt(m.group("g2")); - int b = Integer.parseUnsignedInt(m.group("b2")); - int a = Integer.parseUnsignedInt(m.group("a2")); - if (r > 255) throw new NumberFormatException("Number too big. Expected range: 0 to 255"); - if (g > 255) throw new NumberFormatException("Number too big. Expected range: 0 to 255"); - if (b > 255) throw new NumberFormatException("Number too big. Expected range: 0 to 255"); - if (a > 255) throw new NumberFormatException("Number too big. Expected range: 0 to 255"); - return (a << 24) | (r << 16) | (g << 8) | b; - } - - GuidebookMod.logger.warn("Unrecognized color value {}, ignored.", c); - } - catch (NumberFormatException e) - { - GuidebookMod.logger.warn("Color value not valid {}", c, e); - // ignored - } - } - } - - return def; - } - @Override public String toString() { diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementBreak.java b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementBreak.java index 82f16e0..a206315 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementBreak.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementBreak.java @@ -16,7 +16,7 @@ public class ElementBreak extends Element public int reflow(List list, IBookGraphics nav, Rect bounds, Rect page) { list.add(new VisualPageBreak(new Size())); - return bounds.position.y; + return bounds.position.y(); } @Override diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementGrid.java b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementGrid.java index 2d3e12b..a854f7f 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementGrid.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementGrid.java @@ -2,7 +2,6 @@ import com.google.common.collect.Lists; import com.google.common.primitives.Ints; -import dev.gigaherz.guidebook.guidebook.book.BookDocument; import dev.gigaherz.guidebook.guidebook.BookParsingException; import dev.gigaherz.guidebook.guidebook.IBookGraphics; import dev.gigaherz.guidebook.guidebook.book.BookDocumentParser; @@ -11,7 +10,7 @@ import dev.gigaherz.guidebook.guidebook.drawing.VisualElement; import dev.gigaherz.guidebook.guidebook.drawing.VisualPanel; import dev.gigaherz.guidebook.guidebook.templates.TemplateDefinition; -import dev.gigaherz.guidebook.guidebook.util.Point; +import dev.gigaherz.guidebook.guidebook.util.Point2I; import dev.gigaherz.guidebook.guidebook.util.Rect; import dev.gigaherz.guidebook.guidebook.util.Size; import net.minecraft.client.resources.model.Material; @@ -171,10 +170,10 @@ public int reflow(List list, IBookGraphics nav, Rect bounds, Rect { List visuals = Lists.newArrayList(); - Point adjustedPosition = applyPosition(bounds.position, bounds.position); + Point2I adjustedPosition = applyPosition(bounds.position, bounds.position); Rect adjustedBounds = new Rect(adjustedPosition, bounds.size); - int top = adjustedPosition.y; + int top = adjustedPosition.y(); var explicitHeight = 0; for (var row : rows) @@ -185,22 +184,22 @@ public int reflow(List list, IBookGraphics nav, Rect bounds, Rect explicitHeight += row.computedHeight; } } - var flexHeight = adjustedBounds.size.height - explicitHeight; + var flexHeight = adjustedBounds.size.height() - explicitHeight; var accHeight = 0; for (var row : rows) { - row.computedHeight = adjustedBounds.size.height / rows.size(); + row.computedHeight = adjustedBounds.size.height() / rows.size(); if (row.height != null) - row.computedHeight = (row.heightPercent ? (row.height * bounds.size.height / 100) : row.height); + row.computedHeight = (row.heightPercent ? (row.height * bounds.size.height() / 100) : row.height); accHeight += row.computedHeight; } - if (accHeight > adjustedBounds.size.height) + if (accHeight > adjustedBounds.size.height()) { var div = accHeight; accHeight = 0; for (var row : rows) { - row.computedHeight = row.computedHeight * adjustedBounds.size.height / div; + row.computedHeight = row.computedHeight * adjustedBounds.size.height() / div; accHeight += row.computedHeight; } } @@ -208,18 +207,18 @@ public int reflow(List list, IBookGraphics nav, Rect bounds, Rect var accWidth = 0; for (var col : cols) { - col.computedWidth = adjustedBounds.size.width / cols.size(); + col.computedWidth = adjustedBounds.size.width() / cols.size(); if (col.width != null) - col.computedWidth = (col.widthPercent ? (col.width * bounds.size.width / 100) : col.width); + col.computedWidth = (col.widthPercent ? (col.width * bounds.size.width() / 100) : col.width); accWidth += col.computedWidth; } - if (accWidth > adjustedBounds.size.width) + if (accWidth > adjustedBounds.size.width()) { var div = accWidth; accWidth = 0; for (var col : cols) { - col.computedWidth = col.computedWidth * adjustedBounds.size.width / div; + col.computedWidth = col.computedWidth * adjustedBounds.size.width() / div; accWidth += col.computedWidth; } } @@ -229,7 +228,7 @@ public int reflow(List list, IBookGraphics nav, Rect bounds, Rect var rowHeight = row.computedHeight; int col = 0; - int left = adjustedBounds.position.x; + int left = adjustedBounds.position.x(); for(var cell : row.cells) { var cellWidth = 0; @@ -251,16 +250,16 @@ public int reflow(List list, IBookGraphics nav, Rect bounds, Rect if (position != POS_RELATIVE) { - top = bounds.position.y; + top = bounds.position.y(); } else if (height != null) { - top = adjustedPosition.y + (heightPercent ? (height * bounds.size.height / 100) : height); + top = adjustedPosition.y() + (heightPercent ? (height * bounds.size.height() / 100) : height); } if (visuals.size() > 0) { - Size size = new Size(bounds.size.width, top - adjustedPosition.y); + Size size = new Size(bounds.size.width(), top - adjustedPosition.y()); VisualPanel p = new VisualPanel(size, position, baseline, verticalAlignment); diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementImage.java b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementImage.java index bea5398..7587e22 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementImage.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementImage.java @@ -1,6 +1,7 @@ package dev.gigaherz.guidebook.guidebook.elements; import dev.gigaherz.guidebook.guidebook.IBookGraphics; +import dev.gigaherz.guidebook.guidebook.book.IParseable; import dev.gigaherz.guidebook.guidebook.book.ParsingContext; import dev.gigaherz.guidebook.guidebook.drawing.VisualElement; import dev.gigaherz.guidebook.guidebook.drawing.VisualImage; @@ -54,8 +55,8 @@ public int reflow(List paragraph, IBookGraphics nav, Rect bounds, element.position = applyPosition(bounds.position, bounds.position); paragraph.add(element); if (position != POS_RELATIVE) - return bounds.position.y; - return bounds.position.y + element.size.height; + return bounds.position.y(); + return bounds.position.y() + element.size.height(); } @Override @@ -70,12 +71,12 @@ public void parse(ParsingContext context, NamedNodeMap attributes) { super.parse(context, attributes); - tx = getAttribute(attributes, "tx", tx); - ty = getAttribute(attributes, "ty", ty); - tw = getAttribute(attributes, "tw", tw); - th = getAttribute(attributes, "th", th); - textureLocation = getAttribute(attributes, "src", textureLocation); - scale = getAttribute(attributes, "scale", scale); + tx = IParseable.getAttribute(attributes, "tx", tx); + ty = IParseable.getAttribute(attributes, "ty", ty); + tw = IParseable.getAttribute(attributes, "tw", tw); + th = IParseable.getAttribute(attributes, "th", th); + textureLocation = IParseable.getAttribute(attributes, "src", textureLocation); + scale = IParseable.getAttribute(attributes, "scale", scale); } @Override diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementPanel.java b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementPanel.java index 6914ed9..6ceaddb 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementPanel.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementPanel.java @@ -2,7 +2,6 @@ import com.google.common.collect.Lists; import com.google.common.primitives.Ints; -import dev.gigaherz.guidebook.guidebook.book.BookDocument; import dev.gigaherz.guidebook.guidebook.IBookGraphics; import dev.gigaherz.guidebook.guidebook.book.BookDocumentParser; import dev.gigaherz.guidebook.guidebook.book.ParsingContext; @@ -10,7 +9,7 @@ import dev.gigaherz.guidebook.guidebook.drawing.VisualElement; import dev.gigaherz.guidebook.guidebook.drawing.VisualPanel; import dev.gigaherz.guidebook.guidebook.templates.TemplateDefinition; -import dev.gigaherz.guidebook.guidebook.util.Point; +import dev.gigaherz.guidebook.guidebook.util.Point2I; import dev.gigaherz.guidebook.guidebook.util.Rect; import dev.gigaherz.guidebook.guidebook.util.Size; import net.minecraft.client.resources.model.Material; @@ -113,10 +112,10 @@ public int reflow(List list, IBookGraphics nav, Rect bounds, Rect { List visuals = Lists.newArrayList(); - Point adjustedPosition = applyPosition(bounds.position, bounds.position); + Point2I adjustedPosition = applyPosition(bounds.position, bounds.position); Rect adjustedBounds = new Rect(adjustedPosition, bounds.size); - int top = adjustedPosition.y; + int top = adjustedPosition.y(); if (mode == PanelMode.DEFAULT) { for (Element element : innerElements) @@ -126,7 +125,7 @@ public int reflow(List list, IBookGraphics nav, Rect bounds, Rect element.reflow(visuals, nav, adjustedBounds, pageBounds); } } - top += adjustedBounds.size.height; + top += adjustedBounds.size.height(); } else { @@ -134,8 +133,8 @@ public int reflow(List list, IBookGraphics nav, Rect bounds, Rect { if (element.conditionResult) { - Point tempPos = new Point(adjustedPosition.x, top); - Size tempSize = new Size(adjustedBounds.size.width, adjustedBounds.size.height - (top - adjustedPosition.y)); + Point2I tempPos = new Point2I(adjustedPosition.x(), top); + Size tempSize = new Size(adjustedBounds.size.width(), adjustedBounds.size.height() - (top - adjustedPosition.y())); Rect tempBounds = new Rect(tempPos, tempSize); top = element.reflow(visuals, nav, tempBounds, pageBounds); @@ -145,16 +144,16 @@ public int reflow(List list, IBookGraphics nav, Rect bounds, Rect if (position != POS_RELATIVE) { - top = bounds.position.y; + top = bounds.position.y(); } else if (space != null) { - top = adjustedPosition.y + (asPercent ? (space * bounds.size.height / 100) : space); + top = adjustedPosition.y() + (asPercent ? (space * bounds.size.height() / 100) : space); } if (visuals.size() > 0) { - Size size = new Size(bounds.size.width, top - adjustedPosition.y); + Size size = new Size(bounds.size.width(), top - adjustedPosition.y()); VisualPanel p = new VisualPanel(size, position, baseline, verticalAlignment); diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementParagraph.java b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementParagraph.java index d32b65c..78f0ba3 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementParagraph.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementParagraph.java @@ -4,11 +4,12 @@ import dev.gigaherz.guidebook.GuidebookMod; import dev.gigaherz.guidebook.guidebook.IBookGraphics; import dev.gigaherz.guidebook.guidebook.book.BookDocumentParser; +import dev.gigaherz.guidebook.guidebook.book.IParseable; import dev.gigaherz.guidebook.guidebook.book.ParsingContext; import dev.gigaherz.guidebook.guidebook.conditions.ConditionContext; import dev.gigaherz.guidebook.guidebook.drawing.VisualElement; import dev.gigaherz.guidebook.guidebook.templates.TemplateDefinition; -import dev.gigaherz.guidebook.guidebook.util.Point; +import dev.gigaherz.guidebook.guidebook.util.Point2I; import dev.gigaherz.guidebook.guidebook.util.Rect; import dev.gigaherz.guidebook.guidebook.util.Size; import org.w3c.dom.NamedNodeMap; @@ -22,11 +23,7 @@ public class ElementParagraph extends Element { - public static final int ALIGN_LEFT = 0; - public static final int ALIGN_CENTER = 1; - public static final int ALIGN_RIGHT = 2; - - public int alignment = ALIGN_LEFT; + public Alignment alignment = Alignment.LEFT; public int indent = 0; // First line? public int indentFirstLine = 0; // First line? public int space = 2; @@ -51,8 +48,8 @@ public boolean reevaluateConditions(ConditionContext ctx) @Override public int reflow(List paragraph, IBookGraphics nav, Rect bounds, Rect page) { - Point adjustedPosition = applyPosition(bounds.position, bounds.position); - int currentLineTop = adjustedPosition.y; + Point2I adjustedPosition = applyPosition(bounds.position, bounds.position); + int currentLineTop = adjustedPosition.y(); int currentLineLeft = indentFirstLine; int currentLineHeight = 0; int currentIndent = indentFirstLine; @@ -61,9 +58,9 @@ public int reflow(List paragraph, IBookGraphics nav, Rect bounds, for (Element element : inlines) { - int firstLineWidth = bounds.size.width - currentLineLeft - indent - indentFirstLine; + int firstLineWidth = bounds.size.width() - currentLineLeft - indent - indentFirstLine; List pieces = element.measure(nav, - bounds.size.width - indent, + bounds.size.width() - indent, firstLineWidth); if (pieces.size() < 1) @@ -75,9 +72,9 @@ public int reflow(List paragraph, IBookGraphics nav, Rect bounds, boolean isLineBreak = "\n".equals(current.getText().getString()); - if (isLineBreak || (currentLineLeft + size.width > bounds.size.width && currentLineLeft > 0)) + if (isLineBreak || (currentLineLeft + size.width() > bounds.size.width() && currentLineLeft > 0)) { - processAlignment(paragraph, bounds.size.width - currentIndent, currentLineLeft, firstInLine); + processAlignment(paragraph, bounds.size.width() - currentIndent, currentLineLeft, firstInLine); currentLineTop += currentLineHeight; currentLineLeft = 0; @@ -90,15 +87,15 @@ public int reflow(List paragraph, IBookGraphics nav, Rect bounds, if (isLineBreak) continue; - if (size.height > currentLineHeight) - currentLineHeight = size.height; + if (size.height() > currentLineHeight) + currentLineHeight = size.height(); - current.position = element.applyPosition(new Point(adjustedPosition.x + currentLineLeft + indent, currentLineTop), bounds.position); + current.position = element.applyPosition(new Point2I(adjustedPosition.x() + currentLineLeft + indent, currentLineTop), bounds.position); - if (size.width > 0) - currentLineLeft += size.width; + if (size.width() > 0) + currentLineLeft += size.width(); - if (currentLineLeft > bounds.size.width) + if (currentLineLeft > bounds.size.width()) { currentLineTop += currentLineHeight; currentLineLeft = 0; @@ -111,10 +108,10 @@ public int reflow(List paragraph, IBookGraphics nav, Rect bounds, } } - processAlignment(paragraph, bounds.size.width - currentIndent, currentLineLeft, firstInLine); + processAlignment(paragraph, bounds.size.width() - currentIndent, currentLineLeft, firstInLine); if (position != POS_RELATIVE) - return bounds.position.y; + return bounds.position.y(); return currentLineTop + currentLineHeight + space; } @@ -125,8 +122,8 @@ private void processAlignment(List paragraph, int width, int curr int leftOffset = switch (alignment) { - case ALIGN_CENTER -> (width - currentLineLeft) / 2; - case ALIGN_RIGHT -> width - currentLineLeft; + case CENTER -> (width - currentLineLeft) / 2; + case RIGHT -> width - currentLineLeft; default -> 0; }; @@ -138,11 +135,11 @@ private void processAlignment(List paragraph, int width, int curr VisualElement e = paragraph.get(i); if (e.positionMode == 0) { - e.position = new Point(e.position.x + leftOffset, e.position.y); + e.position = new Point2I(e.position.x() + leftOffset, e.position.y()); - yMin = Math.min(yMin, e.position.y); - yMax = Math.min(yMax, e.position.y + e.size.height); // TODO check if this is correct - yBaseline = Math.min(yBaseline, e.position.y + (int) (e.size.height * e.baseline)); + yMin = Math.min(yMin, e.position.y()); + yMax = Math.min(yMax, e.position.y() + e.size.height()); // TODO check if this is correct + yBaseline = Math.min(yBaseline, e.position.y() + (int) (e.size.height() * e.baseline)); } } @@ -155,18 +152,18 @@ private void processAlignment(List paragraph, int width, int curr { if (e.verticalAlign == VA_MIDDLE) { - e.position = new Point(e.position.x, yMin + (yHeight - e.size.height) / 2); + e.position = new Point2I(e.position.x(), yMin + (yHeight - e.size.height()) / 2); } else if (e.verticalAlign == VA_BASELINE) { - e.position = new Point(e.position.x, yBaseline - (int) (e.size.height * e.baseline)); + e.position = new Point2I(e.position.x(), yBaseline - (int) (e.size.height() * e.baseline)); } else if (e.verticalAlign == VA_BOTTOM) { - e.position = new Point(e.position.x, yMax - e.size.height); + e.position = new Point2I(e.position.x(), yMax - e.size.height()); } - yMin2 = Math.min(yMin2, e.position.y); + yMin2 = Math.min(yMin2, e.position.y()); } } @@ -178,7 +175,7 @@ else if (e.verticalAlign == VA_BOTTOM) VisualElement e = paragraph.get(i); if (e.positionMode == 0) { - e.position = new Point(e.position.x, e.position.y + yOffset); + e.position = new Point2I(e.position.x(), e.position.y() + yOffset); } } } @@ -189,20 +186,9 @@ public void parse(ParsingContext context, NamedNodeMap attributes) { super.parse(context, attributes); - Node attr = attributes.getNamedItem("align"); - if (attr != null) - { - alignment = switch (attr.getTextContent()) - { - case "left" -> ElementParagraph.ALIGN_LEFT; - case "center" -> ElementParagraph.ALIGN_CENTER; - case "right" -> ElementParagraph.ALIGN_RIGHT; - default -> alignment; - }; - } - - indent = getAttribute(attributes, "indent", indent); - space = getAttribute(attributes, "space", space); + alignment = IParseable.getAttribute(attributes, "align", alignment, Alignment.class); + indent = IParseable.getAttribute(attributes, "indent", indent); + space = IParseable.getAttribute(attributes, "space", space); } @Override @@ -297,5 +283,12 @@ public static ElementParagraph of(String text, TextStyle style) p.inlines.add(s); return p; } + + public enum Alignment + { + LEFT, + CENTER, + RIGHT + } } diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementRecipe.java b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementRecipe.java index f9d59c1..ffc448b 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementRecipe.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementRecipe.java @@ -10,7 +10,7 @@ import dev.gigaherz.guidebook.guidebook.recipe.RecipeLayout; import dev.gigaherz.guidebook.guidebook.recipe.RecipeLayoutProviders; import dev.gigaherz.guidebook.guidebook.templates.TemplateDefinition; -import dev.gigaherz.guidebook.guidebook.util.Point; +import dev.gigaherz.guidebook.guidebook.util.Point2I; import dev.gigaherz.guidebook.guidebook.util.Rect; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; @@ -84,7 +84,7 @@ else if (recipeOutput instanceof ElementStack) ElementStack[] ingredients = recipeLayout.recipeComponents; int height = h != 0 ? h : recipeLayout.height; - Point adjustedPosition = applyPosition(bounds.position, bounds.position); + Point2I adjustedPosition = applyPosition(bounds.position, bounds.position); Rect adjustedBounds = new Rect(adjustedPosition, bounds.size); for (ElementStack ingredient : ingredients) @@ -96,8 +96,8 @@ else if (recipeOutput instanceof ElementStack) if (additionalRenderer != null) list.add(additionalRenderer); if (position != POS_RELATIVE) - return bounds.position.y; - return adjustedPosition.y + height; + return bounds.position.y(); + return adjustedPosition.y() + height; } catch (Exception e) { diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementStack.java b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementStack.java index c70631b..89353f3 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementStack.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementStack.java @@ -4,6 +4,7 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException; import dev.gigaherz.guidebook.GuidebookMod; import dev.gigaherz.guidebook.guidebook.IBookGraphics; +import dev.gigaherz.guidebook.guidebook.book.IParseable; import dev.gigaherz.guidebook.guidebook.book.ParsingContext; import dev.gigaherz.guidebook.guidebook.drawing.VisualElement; import dev.gigaherz.guidebook.guidebook.drawing.VisualStack; @@ -64,8 +65,8 @@ public int reflow(List paragraph, IBookGraphics nav, Rect bounds, element.position = applyPosition(bounds.position, bounds.position); paragraph.add(element); if (position != POS_RELATIVE) - return bounds.position.y; - return bounds.position.y + element.size.height; + return bounds.position.y(); + return bounds.position.y() + element.size.height(); } @Override @@ -76,7 +77,7 @@ public void parse(ParsingContext context, NamedNodeMap attributes) super.parse(context, attributes); - scale = getAttribute(attributes, "scale", scale); + scale = IParseable.getAttribute(attributes, "scale", scale); Node attr; attr = attributes.getNamedItem("count"); diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementText.java b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementText.java index 2a0b58f..e265c6d 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementText.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementText.java @@ -1,9 +1,11 @@ package dev.gigaherz.guidebook.guidebook.elements; import dev.gigaherz.guidebook.guidebook.IBookGraphics; +import dev.gigaherz.guidebook.guidebook.book.IParseable; import dev.gigaherz.guidebook.guidebook.book.ParsingContext; import dev.gigaherz.guidebook.guidebook.drawing.VisualElement; import dev.gigaherz.guidebook.guidebook.drawing.VisualText; +import dev.gigaherz.guidebook.guidebook.util.Color; import dev.gigaherz.guidebook.guidebook.util.Rect; import net.minecraft.network.chat.FormattedText; import net.minecraft.network.chat.Component; @@ -16,7 +18,7 @@ public class ElementText extends ElementInline { public final String text; - public int color; + public Color color; public boolean bold; public boolean italics; public boolean underline; @@ -30,14 +32,14 @@ public ElementText(String text, boolean isFirstElement, boolean isLastElement, T { super(isFirstElement, isLastElement); this.text = compactString(text, isFirstElement, isLastElement); - color = style.color; - bold = style.bold; - italics = style.italics; - underline = style.underline; - strikethrough = style.strikethrough; - obfuscated = style.obfuscated; - font = style.font; - scale = style.scale; + color = style.color(); + bold = style.bold(); + italics = style.italics(); + underline = style.underline(); + strikethrough = style.strikethrough(); + obfuscated = style.obfuscated(); + font = style.font(); + scale = style.scale(); } private FormattedText getStringWithFormat(FormattedText text) @@ -96,7 +98,7 @@ public int reflow(List paragraph, IBookGraphics nav, Rect bounds, public void parse(ParsingContext context, NamedNodeMap attributes) { super.parse(context, attributes); - scale = getAttribute(attributes, "scale", scale); + scale = IParseable.getAttribute(attributes, "scale", scale); } @Override diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementTitle.java b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementTitle.java index 631ac3c..e81fdcd 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementTitle.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementTitle.java @@ -7,13 +7,13 @@ public class ElementTitle extends ElementParagraph { public ElementTitle() { - alignment = ElementParagraph.ALIGN_CENTER; + alignment = Alignment.CENTER; space = 4; } @Override public TextStyle childStyle(ParsingContext context, NamedNodeMap attributes, TextStyle defaultStyle) { - return TextStyle.parse(attributes, new TextStyle(defaultStyle.color, true, false, true, false, false, null, 1.0f)); + return TextStyle.parse(attributes, new TextStyle(defaultStyle.color(), true, false, true, false, false, null, 1.0f)); } } diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/LinkContext.java b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/LinkContext.java index a61c3e0..2a97204 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/LinkContext.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/LinkContext.java @@ -18,6 +18,6 @@ public LinkContext copy() link.colorHover = colorHover; link.textTarget = textTarget; link.textAction = textAction; - return null; + return link; } } diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/TextStyle.java b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/TextStyle.java index 8e13e65..676fb9c 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/TextStyle.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/TextStyle.java @@ -1,47 +1,39 @@ package dev.gigaherz.guidebook.guidebook.elements; +import dev.gigaherz.guidebook.guidebook.book.IParseable; +import dev.gigaherz.guidebook.guidebook.util.Color; import net.minecraft.network.chat.Style; import net.minecraft.resources.ResourceLocation; import org.w3c.dom.NamedNodeMap; -public class TextStyle +public record TextStyle(Color color, boolean bold, boolean italics, boolean underline, boolean strikethrough, + boolean obfuscated, ResourceLocation font, float scale) implements Cloneable { - public static final TextStyle DEFAULT = new TextStyle(0xFF000000, false, false, false, false, false, Style.DEFAULT_FONT, 1.0f); - public static final TextStyle LINK = new TextStyle(0xFF7766cc, false, false, true, false, false, Style.DEFAULT_FONT, 1.0f); - public static final TextStyle ERROR = new TextStyle(0xFFcc7766, false, false, true, false, false, Style.DEFAULT_FONT, 1.0f); - - public final int color; - public final boolean bold; - public final boolean italics; - public final boolean underline; - public final boolean strikethrough; - public final boolean obfuscated; - public final ResourceLocation font; - public final float scale; - - public TextStyle(int color, boolean bold, boolean italics, boolean underline, boolean strikethrough, boolean obfuscated, ResourceLocation font, float scale) - { - this.color = color; - this.bold = bold; - this.italics = italics; - this.underline = underline; - this.strikethrough = strikethrough; - this.obfuscated = obfuscated; - this.font = font; - this.scale = scale; - } + public static final TextStyle DEFAULT = new TextStyle(Color.fromARGB(0xFF000000), false, false, false, false, false, Style.DEFAULT_FONT, 1.0f); + public static final TextStyle LINK = new TextStyle(Color.fromARGB(0xFF7766cc), false, false, true, false, false, Style.DEFAULT_FONT, 1.0f); + public static final TextStyle ERROR = new TextStyle(Color.fromARGB(0xFFcc7766), false, false, true, false, false, Style.DEFAULT_FONT, 1.0f); public static TextStyle parse(NamedNodeMap attributes, TextStyle defaults) { - int color1 = Element.getColorAttribute(attributes, defaults != null ? defaults.color : DEFAULT.color); - boolean bold1 = Element.getAttribute(attributes, "bold", defaults != null ? defaults.bold : DEFAULT.bold); - boolean italics1 = Element.getAttribute(attributes, "italics", defaults != null ? defaults.italics : DEFAULT.italics); - boolean underline1 = Element.getAttribute(attributes, "underline", defaults != null ? defaults.underline : DEFAULT.underline); - boolean strikethrough1 = Element.getAttribute(attributes, "strikethrough", defaults != null ? defaults.strikethrough : DEFAULT.strikethrough); - boolean obfuscated1 = Element.getAttribute(attributes, "obfuscated", defaults != null ? defaults.obfuscated : DEFAULT.obfuscated); - ResourceLocation font1 = Element.getAttribute(attributes, "font", defaults != null ? defaults.font : DEFAULT.font); - float scale1 = Element.getAttribute(attributes, "scale", defaults != null ? defaults.scale : DEFAULT.scale); + if (defaults == null) + { + defaults = DEFAULT; + } + Color color1 = IParseable.getAttribute(attributes, "color", defaults.color); + boolean bold1 = IParseable.getAttribute(attributes, "bold", defaults.bold); + boolean italics1 = IParseable.getAttribute(attributes, "italics", defaults.italics); + boolean underline1 = IParseable.getAttribute(attributes, "underline", defaults.underline); + boolean strikethrough1 = IParseable.getAttribute(attributes, "strikethrough", defaults.strikethrough); + boolean obfuscated1 = IParseable.getAttribute(attributes, "obfuscated", defaults.obfuscated); + ResourceLocation font1 = IParseable.getAttribute(attributes, "font", defaults.font); + float scale1 = IParseable.getAttribute(attributes, "scale", defaults.scale); return new TextStyle(color1, bold1, italics1, underline1, strikethrough1, obfuscated1, font1, scale1); } + + @Override + public TextStyle clone() throws CloneNotSupportedException + { + return (TextStyle) super.clone(); + } } diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/util/Color.java b/src/main/java/dev/gigaherz/guidebook/guidebook/util/Color.java new file mode 100644 index 0000000..b7474e7 --- /dev/null +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/util/Color.java @@ -0,0 +1,266 @@ +package dev.gigaherz.guidebook.guidebook.util; + +import net.minecraft.world.item.DyeColor; + +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public record Color(int argb) +{ + // For an exploded description of this regex, see: https://regex101.com/r/4wQobv/2/ + private static final Pattern COLOR_PARSE = Pattern.compile("^(?:#?(?:(?[0-9a-f]{3})|(?[0-9a-f]{4})|(?[0-9a-f]{6})|(?[0-9a-f]{8}))|(?rgb\\((?25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}),(?25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}),(?25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})\\))|(?rgba\\((?25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}),(?25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}),(?25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}),(?[0-9]{1,3})\\))|(?hsl\\((?360|3[0-5][0-9]|[1-2]?[0-9]{1,2}),(?[1-9][0-9]?|100)%?,(?[1-9][0-9]?|100)%?\\))|(?hsla\\((?

360|3[0-5][0-9]|[1-2]?[0-9]{1,2}),(?[1-9][0-9]?|100)%?,(?[1-9][0-9]?|100)%?,(?0|1|1\\.0|0\\.[0-9]+)\\)))$", Pattern.CASE_INSENSITIVE); + private static final Map DEFAULT_COLORS = new HashMap<>(); + + static + { + for (DyeColor value : DyeColor.values()) + { + DEFAULT_COLORS.put(value.getName(), fromRGB(value.getTextColor())); + } + } + + public int rgb() + { + return argb() & 0xFFFFFF; + } + + public int alpha() + { + return (argb() >> 24) & 0xFF; + } + + public int red() + { + return (argb() >> 16) & 0xFF; + } + + public int green() + { + return (argb() >> 8) & 0xFF; + } + + public int blue() + { + return argb() & 0xFF; + } + + @Override + public String toString() + { + return '#' + Integer.toHexString(argb()).toUpperCase(); + } + + public static Color fromARGB(int argb) + { + return new Color(argb); + } + + public static Color fromRGB(int rgb) + { + return fromARGB(0xFF000000 | rgb); + } + + public static Color fromRGBA(int r, int g, int b, int a) + { + if (r > 255) throw new IllegalArgumentException("Red value too big. Expected range: 0 to 255"); + if (r < 0) throw new IllegalArgumentException("Red value too small. Expected range: 0 to 255"); + if (g > 255) throw new IllegalArgumentException("Green value too big. Expected range: 0 to 255"); + if (g < 0) throw new IllegalArgumentException("Green value too small. Expected range: 0 to 255"); + if (b > 255) throw new IllegalArgumentException("Blue value too big. Expected range: 0 to 255"); + if (b < 0) throw new IllegalArgumentException("Blue value too small. Expected range: 0 to 255"); + if (a > 255) throw new IllegalArgumentException("Alpha value too big. Expected range: 0 to 255"); + if (a < 0) throw new IllegalArgumentException("Alpha value too small. Expected range: 0 to 255"); + return fromARGB(a << 24 | (r << 16) | (g << 8) | b); + } + + public static Color fromRGB(int r, int g, int b) + { + return fromRGBA(r, g, b, 255); + } + + public static Color fromRGBA(int r, int g, int b, float a) + { + return fromRGBA(r, g, b, (int) (a * 255.0f)); + } + + public static Color fromRGB(float r, float g, float b) + { + return fromRGB((int) (r * 255.0f), (int) (g * 255.0f), (int) (b * 255.0f)); + } + + public static Color fromRGBA(float r, float g, float b, float a) + { + return fromRGBA((int) (r * 255.0f), (int) (g * 255.0f), (int) (b * 255.0f), (int) (a * 255.0f)); + } + + public static Color fromHSLA(int h, int s, int l, float a) + { + if (h > 360) throw new IllegalArgumentException("Hue value too big. Expected range: 0 to 360"); + if (h < 0) throw new IllegalArgumentException("Hue value too small. Expected range: 0 to 360"); + if (s > 100) throw new IllegalArgumentException("Saturation value too big. Expected range: 0 to 100"); + if (s < 0) throw new IllegalArgumentException("Saturation value too small. Expected range: 0 to 100"); + if (l > 100) throw new IllegalArgumentException("Lightness value too big. Expected range: 0 to 100"); + if (l < 0) throw new IllegalArgumentException("Lightness value too small. Expected range: 0 to 100"); + if (a > 1.0f) throw new IllegalArgumentException("Alpha value too big. Expected range: 0 to 1"); + if (a < 0.0f) throw new IllegalArgumentException("Alpha value too small. Expected range: 0 to 1"); + return fromARGB(hslToRgb(h, s, l, a)); + } + + public static Color fromHSL(int h, int s, int l) + { + return fromHSLA(h, s, l, 1.0f); + } + + public static Color parse(String c) throws ColorParseException + { + Matcher m = COLOR_PARSE.matcher(c); + + if (!m.matches()) + { + if (DEFAULT_COLORS.containsKey(c)) + { + return DEFAULT_COLORS.get(c); + } + throw new ColorParseException(c); + } + + try + { + String value; + if ((value = m.group("c3")) != null) + { + String s = new String(new char[]{value.charAt(0), value.charAt(0), value.charAt(1), value.charAt(1), value.charAt(2), value.charAt(2)}); + return fromRGB(Integer.parseInt(s, 16)); + } + else if ((value = m.group("c4")) != null) + { + String s = new String(new char[]{value.charAt(0), value.charAt(0), value.charAt(1), value.charAt(1), value.charAt(2), value.charAt(2), value.charAt(3), value.charAt(3)}); + return fromARGB(Integer.parseUnsignedInt(s, 16)); + } + else if ((value = m.group("c6")) != null) + { + return fromRGB(Integer.parseInt(value, 16)); + } + else if ((value = m.group("c8")) != null) + { + return fromARGB(Integer.parseUnsignedInt(value, 16)); + } + else if (m.group("rgb") != null) + { + int r = Integer.parseUnsignedInt(m.group("r")); + int g = Integer.parseUnsignedInt(m.group("g")); + int b = Integer.parseUnsignedInt(m.group("b")); + return fromRGB(r, g, b); + } + else if (m.group("rgba") != null) + { + int r = Integer.parseUnsignedInt(m.group("r2")); + int g = Integer.parseUnsignedInt(m.group("g2")); + int b = Integer.parseUnsignedInt(m.group("b2")); + int a = Integer.parseUnsignedInt(m.group("a2")); + return fromRGBA(r, g, b, a); + } + else if (m.group("hsl") != null) + { + int h = Integer.parseUnsignedInt(m.group("h")); + int s = Integer.parseUnsignedInt(m.group("s")); + int l = Integer.parseUnsignedInt(m.group("l")); + return fromHSL(h, s, l); + } + else if (m.group("hsla") != null) + { + int h = Integer.parseUnsignedInt(m.group("h2")); + int s = Integer.parseUnsignedInt(m.group("s2")); + int l = Integer.parseUnsignedInt(m.group("l2")); + float a = Float.parseFloat(m.group("a3")); + return fromHSLA(h, s, l, a); + } + else + { + throw new ColorParseException(c); + } + } + catch (IllegalArgumentException e) + { + throw new ColorParseException(c, e); + } + } + + static int hslToRgb(int h, int s, int l, float a) + { + float hf = h / 360.0f; + float sf = s / 100.0f; + float lf = l / 100.0f; + + float q; + + if (lf < 0.5) + q = lf * (1 + sf); + else + q = (lf + sf) - (sf * l); + + float p = 2 * lf - q; + + float r = hueToRgb(p, q, hf + (1.0f / 3.0f)); + float g = hueToRgb(p, q, hf); + float b = hueToRgb(p, q, hf - (1.0f / 3.0f)); + + return ((int) (a * 255.0f) << 24) | ((int) (r * 255.0f) << 16) | ((int) (g * 255.0f) << 8) | ((int) (b * 255.0f)); + } + + static float hueToRgb(float p, float q, float h) + { + if (h < 0) + h += 1; + + if (h > 1) + h -= 1; + + if (6 * h < 1) + { + return p + ((q - p) * 6 * h); + } + + if (2 * h < 1) + { + return q; + } + + if (3 * h < 2) + { + return p + ((q - p) * 6 * ((2.0f / 3.0f) - h)); + } + + return p; + } + + public static class ColorParseException extends Exception + { + private final String colorString; + + public ColorParseException(String colorString) + { + super(); + this.colorString = colorString; + } + + public ColorParseException(String colorString, Throwable cause) + { + super(cause); + this.colorString = colorString; + } + + @Override + public String getMessage() + { + return "Invalid color string: " + getColorString(); + } + + public String getColorString() + { + return colorString; + } + } +} diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/util/LinkHelper.java b/src/main/java/dev/gigaherz/guidebook/guidebook/util/LinkHelper.java index 00a4c59..508367a 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/util/LinkHelper.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/util/LinkHelper.java @@ -11,19 +11,36 @@ import net.minecraft.client.gui.screens.ConfirmLinkScreen; import net.minecraft.client.gui.screens.ConfirmScreen; import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; import org.lwjgl.glfw.GLFW; import java.net.URI; import java.net.URISyntaxException; +import java.util.HashMap; import java.util.Locale; +import java.util.Map; import java.util.Set; +import java.util.function.Consumer; public class LinkHelper { - private static final MutableComponent COPY_TO_CLIPBOARD_1 = Component.translatable("text.gbook.actions.copy_to_clipboard.line1"); - private static final MutableComponent COPY_TO_CLIPBOARD_2 = Component.translatable("text.gbook.actions.copy_to_clipboard.line2"); + private static final Component COPY_TO_CLIPBOARD_1 = Component.translatable("text.gbook.actions.copy_to_clipboard.line1"); + private static final Component COPY_TO_CLIPBOARD_2 = Component.translatable("text.gbook.actions.copy_to_clipboard.line2"); + private static final Component COPY_TO_CLIPBOARD_SUCCESS = Component.translatable("text.gbook.actions.copy_to_clipboard.success"); + private static final Component TEMPORARY_CHAT_WINDOW = Component.translatable("text.gbook.actions.copy_to_chat.window_open"); private static final Set PROTOCOLS = Sets.newHashSet("http", "https"); + private static final Map> ACTIONS = new HashMap<>(); + + static + { + registerLinkAction("openUrl", context -> clickWeb(context.textTarget)); + registerLinkAction("copyText", context -> clickCopyToClipboard(context.textTarget)); + registerLinkAction("copyToChat", context -> clickCopyToChat(context.textTarget)); + } + + public static void registerLinkAction(String name, Consumer action) + { + ACTIONS.put(name, action); + } public interface ILinkable { @@ -34,12 +51,7 @@ public static void click(IBookGraphics nav, LinkContext context) { if (context.textTarget != null && context.textAction != null) { - switch (context.textAction) - { - case "openUrl" -> clickWeb(context.textTarget); - case "copyText" -> clickCopyToClipboard(context.textTarget); - case "copyToChat" -> clickCopyToChat(context.textTarget); - } + ACTIONS.getOrDefault(context.textAction, $ -> {}).accept(context); } if (context.target != null) { @@ -54,7 +66,7 @@ public static void clickCopyToClipboard(String textTarget) if (result) { GLFW.glfwSetClipboardString(mc.getWindow().getWindow(), textTarget); - mc.gui.getChat().addMessage(Component.translatable("text.gbook.actions.copy_to_clipboard.success")); + mc.gui.getChat().addMessage(COPY_TO_CLIPBOARD_SUCCESS); } mc.popGuiLayer(); }, COPY_TO_CLIPBOARD_1, COPY_TO_CLIPBOARD_2)); @@ -68,7 +80,7 @@ public static void clickCopyToChat(String textTarget) @Override public void render(PoseStack matrixStack, int mouseX, int mouseY, float partialTicks) { - String text = "Temporary chat window open, press ESCAPE to cancel."; + Component text = TEMPORARY_CHAT_WINDOW; int textWidth = Math.max(font.width(text) + 40, width / 2); fill(matrixStack, (width - textWidth) / 2, height / 4, (width + textWidth) / 2, height * 3 / 4, 0x7F000000); drawCenteredString(matrixStack, font, text, width / 2, (height - font.lineHeight) / 2, 0xFFFFFFFF); diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/util/Point.java b/src/main/java/dev/gigaherz/guidebook/guidebook/util/Point.java deleted file mode 100644 index f10c156..0000000 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/util/Point.java +++ /dev/null @@ -1,18 +0,0 @@ -package dev.gigaherz.guidebook.guidebook.util; - -public class Point -{ - public final int x; - public final int y; - - public Point() - { - this.x = this.y = 0; - } - - public Point(int x, int y) - { - this.x = x; - this.y = y; - } -} diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/util/Point2D.java b/src/main/java/dev/gigaherz/guidebook/guidebook/util/Point2D.java new file mode 100644 index 0000000..944138d --- /dev/null +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/util/Point2D.java @@ -0,0 +1,22 @@ +package dev.gigaherz.guidebook.guidebook.util; + +public record Point2D(double x, double y) implements Cloneable +{ + public static final Point2D ZERO = new Point2D(); + + public Point2D() + { + this(0, 0); + } + + public Point2D(Point2D other) + { + this(other.x, other.y); + } + + @Override + public Point2D clone() throws CloneNotSupportedException + { + return (Point2D) super.clone(); + } +} diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/util/Point2F.java b/src/main/java/dev/gigaherz/guidebook/guidebook/util/Point2F.java new file mode 100644 index 0000000..0d6f175 --- /dev/null +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/util/Point2F.java @@ -0,0 +1,22 @@ +package dev.gigaherz.guidebook.guidebook.util; + +public record Point2F(float x, float y) +{ + public static final Point2F ZERO = new Point2F(); + + public Point2F() + { + this(0, 0); + } + + public Point2F(Point2F other) + { + this(other.x, other.y); + } + + @Override + public Point2F clone() throws CloneNotSupportedException + { + return (Point2F) super.clone(); + } +} diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/util/Point2I.java b/src/main/java/dev/gigaherz/guidebook/guidebook/util/Point2I.java new file mode 100644 index 0000000..a782d14 --- /dev/null +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/util/Point2I.java @@ -0,0 +1,22 @@ +package dev.gigaherz.guidebook.guidebook.util; + +public record Point2I(int x, int y) implements Cloneable +{ + public static final Point2I ZERO = new Point2I(); + + public Point2I() + { + this(0, 0); + } + + public Point2I(Point2I other) + { + this(other.x, other.y); + } + + @Override + public Point2I clone() throws CloneNotSupportedException + { + return (Point2I) super.clone(); + } +} diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/util/PointD.java b/src/main/java/dev/gigaherz/guidebook/guidebook/util/PointD.java deleted file mode 100644 index e679087..0000000 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/util/PointD.java +++ /dev/null @@ -1,18 +0,0 @@ -package dev.gigaherz.guidebook.guidebook.util; - -public class PointD -{ - public final double x; - public final double y; - - public PointD() - { - this.x = this.y = 0; - } - - public PointD(double x, double y) - { - this.x = x; - this.y = y; - } -} diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/util/PointF.java b/src/main/java/dev/gigaherz/guidebook/guidebook/util/PointF.java deleted file mode 100644 index c8a38a0..0000000 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/util/PointF.java +++ /dev/null @@ -1,18 +0,0 @@ -package dev.gigaherz.guidebook.guidebook.util; - -public class PointF -{ - public final float x; - public final float y; - - public PointF() - { - this.x = this.y = 0; - } - - public PointF(float x, float y) - { - this.x = x; - this.y = y; - } -} diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/util/Rect.java b/src/main/java/dev/gigaherz/guidebook/guidebook/util/Rect.java index 8e8a558..51c3795 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/util/Rect.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/util/Rect.java @@ -1,17 +1,17 @@ package dev.gigaherz.guidebook.guidebook.util; -public class Rect +public class Rect implements Cloneable { - public Point position; + public Point2I position; public Size size; public Rect() { - this.position = new Point(); + this.position = new Point2I(); this.size = new Size(); } - public Rect(Point point, Size size) + public Rect(Point2I point, Size size) { this.position = point; this.size = size; @@ -19,12 +19,33 @@ public Rect(Point point, Size size) public Rect(int x, int y, int width, int height) { - this.position = new Point(x, y); + this.position = new Point2I(x, y); this.size = new Size(width, height); } - public Rect copy() + public boolean contains(double x, double y) { - return new Rect(position.x, position.y, size.width, size.height); + return x >= position.x() && x <= (position.x() + size.width()) && y >= position.y() && y <= (position.y() + size.height()); } -} \ No newline at end of file + + public boolean contains(Point2I point) + { + return contains(point.x(), point.y()); + } + + public boolean contains(Point2D point) + { + return contains(point.x(), point.y()); + } + + public boolean contains(Point2F point) + { + return contains(point.x(), point.y()); + } + + @Override + public Rect clone() throws CloneNotSupportedException + { + return (Rect) super.clone(); + } +} diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/util/Size.java b/src/main/java/dev/gigaherz/guidebook/guidebook/util/Size.java index 7627d62..e0003f0 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/util/Size.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/util/Size.java @@ -1,18 +1,22 @@ package dev.gigaherz.guidebook.guidebook.util; -public class Size +public record Size(int width, int height) implements Cloneable { - public final int width; - public final int height; + public static final Size ZERO = new Size(); public Size() { - this.width = this.height = 0; + this(0, 0); } - public Size(int width, int height) + public Size(Size other) { - this.width = width; - this.height = height; + this(other.width, other.height); + } + + @Override + public Size clone() throws CloneNotSupportedException + { + return (Size) super.clone(); } } diff --git a/src/main/resources/assets/gbook/lang/en_us.json b/src/main/resources/assets/gbook/lang/en_us.json index e5f9e15..f0bb029 100644 --- a/src/main/resources/assets/gbook/lang/en_us.json +++ b/src/main/resources/assets/gbook/lang/en_us.json @@ -6,8 +6,9 @@ "text.gbook.actions.copy_to_clipboard.line1": "The book wants to put text in your clipboard.", "text.gbook.actions.copy_to_clipboard.line2": "Are you sure you want to allow this?", "text.gbook.actions.copy_to_clipboard.success": "Text successfully copied.", + "text.gbook.actions.copy_to_chat.window_open": "Temporary chat window open, press ESCAPE to cancel.", "cmd.gbook.guide.done": "Reloading complete", "text.gbook.tooltip.book": "Book: %s" -} \ No newline at end of file +} From 1518830eecfd91ef3b6acd553c1169d0acef64ef Mon Sep 17 00:00:00 2001 From: Minecraftschurli Date: Wed, 22 Jun 2022 20:13:25 +0200 Subject: [PATCH 7/8] move some values to enums and add Length as a step towards being able to use different length units --- .../guidebook/guidebook/IBookGraphics.java | 3 +- .../guidebook/guidebook/book/IParseable.java | 21 +++++ .../guidebook/client/BookRendering.java | 3 +- .../guidebook/drawing/VisualElement.java | 11 +-- .../guidebook/drawing/VisualImage.java | 5 +- .../guidebook/drawing/VisualPageBreak.java | 3 +- .../guidebook/drawing/VisualPanel.java | 3 +- .../guidebook/drawing/VisualStack.java | 3 +- .../guidebook/drawing/VisualText.java | 3 +- .../guidebook/guidebook/elements/Element.java | 75 ++++++------------ .../guidebook/elements/ElementGrid.java | 79 +++++-------------- .../guidebook/elements/ElementImage.java | 2 +- .../guidebook/elements/ElementPanel.java | 2 +- .../guidebook/elements/ElementParagraph.java | 25 +++--- .../guidebook/elements/ElementRecipe.java | 2 +- .../guidebook/elements/ElementStack.java | 2 +- .../guidebook/guidebook/util/Length.java | 30 +++++++ 17 files changed, 133 insertions(+), 139 deletions(-) create mode 100644 src/main/java/dev/gigaherz/guidebook/guidebook/util/Length.java diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/IBookGraphics.java b/src/main/java/dev/gigaherz/guidebook/guidebook/IBookGraphics.java index 67b7e54..000daf1 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/IBookGraphics.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/IBookGraphics.java @@ -4,6 +4,7 @@ import dev.gigaherz.guidebook.guidebook.book.BookDocument; import dev.gigaherz.guidebook.guidebook.book.SectionRef; import dev.gigaherz.guidebook.guidebook.drawing.VisualElement; +import dev.gigaherz.guidebook.guidebook.elements.Element; import dev.gigaherz.guidebook.guidebook.util.Size; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.FormattedText; @@ -63,7 +64,7 @@ public interface IBookGraphics Size measure(FormattedText text); - List measure(FormattedText text, int width, int firstLineWidth, float scale, int position, float baseline, int verticalAlignment); + List measure(FormattedText text, int width, int firstLineWidth, float scale, Element.Position position, float baseline, Element.VerticalAlignment verticalAlignment); int getActualBookHeight(); diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/book/IParseable.java b/src/main/java/dev/gigaherz/guidebook/guidebook/book/IParseable.java index efa0b23..a1e6933 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/book/IParseable.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/book/IParseable.java @@ -4,6 +4,7 @@ import dev.gigaherz.guidebook.guidebook.elements.TextStyle; import dev.gigaherz.guidebook.guidebook.templates.TemplateDefinition; import dev.gigaherz.guidebook.guidebook.util.Color; +import dev.gigaherz.guidebook.guidebook.util.Length; import net.minecraft.resources.ResourceLocation; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; @@ -129,4 +130,24 @@ static Color getAttribute(NamedNodeMap attributes, String name, Color def) return def; } } + + static Length getAttribute(NamedNodeMap attributes, String name, Length def) + { + Node attr = attributes.getNamedItem(name); + if (attr != null) + { + String text = attr.getTextContent(); + if (text != null) + { + try + { + return Length.parse(text); + } + catch (IllegalArgumentException ignored) + { + } + } + } + return def; + } } diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/client/BookRendering.java b/src/main/java/dev/gigaherz/guidebook/guidebook/client/BookRendering.java index 3a06dde..21d9845 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/client/BookRendering.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/client/BookRendering.java @@ -16,6 +16,7 @@ import dev.gigaherz.guidebook.guidebook.drawing.VisualElement; import dev.gigaherz.guidebook.guidebook.drawing.VisualPage; import dev.gigaherz.guidebook.guidebook.drawing.VisualText; +import dev.gigaherz.guidebook.guidebook.elements.Element; import dev.gigaherz.guidebook.guidebook.util.Point2D; import dev.gigaherz.guidebook.guidebook.util.Size; import net.minecraft.client.Minecraft; @@ -789,7 +790,7 @@ public Size measure(FormattedText text) } @Override - public List measure(FormattedText text, int width, int firstLineWidth, float scale, int position, float baseline, int verticalAlignment) + public List measure(FormattedText text, int width, int firstLineWidth, float scale, Element.Position position, float baseline, Element.VerticalAlignment verticalAlignment) { Font font = gui.getFontRenderer(); List sizes = Lists.newArrayList(); diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualElement.java b/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualElement.java index 695426d..129b447 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualElement.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualElement.java @@ -4,6 +4,7 @@ import dev.gigaherz.guidebook.guidebook.HoverContext; import dev.gigaherz.guidebook.guidebook.IBookGraphics; import dev.gigaherz.guidebook.guidebook.client.BookRendering; +import dev.gigaherz.guidebook.guidebook.elements.Element; import dev.gigaherz.guidebook.guidebook.util.Rect; import dev.gigaherz.guidebook.guidebook.util.Size; import net.minecraft.client.gui.GuiComponent; @@ -12,19 +13,19 @@ public abstract class VisualElement extends Rect { - public static final VisualElement EMPTY = new VisualElement(new Size(), 0, 0, 0) + public static final VisualElement EMPTY = new VisualElement(new Size(), Element.Position.RELATIVE, 0, Element.VerticalAlignment.TOP) { }; ; - // Only position modes 1 and 2 are valid here, mode 0 will have been handled by reflow - public int positionMode = 1; + // Only position modes ABSOLUTE and FIXED are valid here, mode RELATIVE will have been handled by reflow + public Element.Position positionMode; - public int verticalAlign = 1; + public Element.VerticalAlignment verticalAlign; public float baseline = 0; - public VisualElement(Size size, int positionMode, float baseline, int verticalAlign) + public VisualElement(Size size, Element.Position positionMode, float baseline, Element.VerticalAlignment verticalAlign) { this.size = size; this.positionMode = positionMode; diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualImage.java b/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualImage.java index e773cfc..f7d62a3 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualImage.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualImage.java @@ -3,6 +3,7 @@ import com.mojang.blaze3d.vertex.PoseStack; import dev.gigaherz.guidebook.guidebook.HoverContext; import dev.gigaherz.guidebook.guidebook.IBookGraphics; +import dev.gigaherz.guidebook.guidebook.elements.Element; import dev.gigaherz.guidebook.guidebook.elements.LinkContext; import dev.gigaherz.guidebook.guidebook.util.LinkHelper; import dev.gigaherz.guidebook.guidebook.util.Size; @@ -21,8 +22,8 @@ public class VisualImage extends VisualElement implements LinkHelper.ILinkable public LinkContext linkContext = null; - public VisualImage(Size size, int positionMode, float baseline, int verticalAlign, ResourceLocation textureLocation, - int tx, int ty, int tw, int th, int w, int h, float scale) + public VisualImage(Size size, Element.Position positionMode, float baseline, Element.VerticalAlignment verticalAlign, + ResourceLocation textureLocation, int tx, int ty, int tw, int th, int w, int h, float scale) { super(size, positionMode, baseline, verticalAlign); this.textureLocation = textureLocation; diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualPageBreak.java b/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualPageBreak.java index 91c650e..1873755 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualPageBreak.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualPageBreak.java @@ -2,13 +2,14 @@ import com.mojang.blaze3d.vertex.PoseStack; import dev.gigaherz.guidebook.guidebook.IBookGraphics; +import dev.gigaherz.guidebook.guidebook.elements.Element; import dev.gigaherz.guidebook.guidebook.util.Size; public class VisualPageBreak extends VisualElement { public VisualPageBreak(Size size) { - super(size, 0, 0, 0); + super(size, Element.Position.RELATIVE, 0, Element.VerticalAlignment.TOP); } @Override diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualPanel.java b/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualPanel.java index 635f3e4..37150fc 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualPanel.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualPanel.java @@ -4,6 +4,7 @@ import com.mojang.blaze3d.vertex.PoseStack; import dev.gigaherz.guidebook.guidebook.HoverContext; import dev.gigaherz.guidebook.guidebook.IBookGraphics; +import dev.gigaherz.guidebook.guidebook.elements.Element; import dev.gigaherz.guidebook.guidebook.util.Size; import java.util.List; @@ -12,7 +13,7 @@ public class VisualPanel extends VisualElement { public final List children = Lists.newArrayList(); - public VisualPanel(Size size, int positionMode, float baseline, int verticalAlign) + public VisualPanel(Size size, Element.Position positionMode, float baseline, Element.VerticalAlignment verticalAlign) { super(size, positionMode, baseline, verticalAlign); } diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualStack.java b/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualStack.java index e2215d5..3485e0c 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualStack.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualStack.java @@ -4,6 +4,7 @@ import dev.gigaherz.guidebook.guidebook.HoverContext; import dev.gigaherz.guidebook.guidebook.IBookGraphics; import dev.gigaherz.guidebook.guidebook.book.SectionRef; +import dev.gigaherz.guidebook.guidebook.elements.Element; import dev.gigaherz.guidebook.guidebook.util.Size; import net.minecraft.core.NonNullList; import net.minecraft.world.item.ItemStack; @@ -16,7 +17,7 @@ public class VisualStack extends VisualElement public float scale = 1.0f; public int z; - public VisualStack(NonNullList stacks, Size size, int positionMode, float baseline, int verticalAlign, float scale, int z) + public VisualStack(NonNullList stacks, Size size, Element.Position positionMode, float baseline, Element.VerticalAlignment verticalAlign, float scale, int z) { super(size, positionMode, baseline, verticalAlign); this.stacks = stacks.toArray(new ItemStack[0]); diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualText.java b/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualText.java index 0ae4645..4bfbf35 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualText.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/drawing/VisualText.java @@ -3,6 +3,7 @@ import com.mojang.blaze3d.vertex.PoseStack; import dev.gigaherz.guidebook.guidebook.HoverContext; import dev.gigaherz.guidebook.guidebook.IBookGraphics; +import dev.gigaherz.guidebook.guidebook.elements.Element; import dev.gigaherz.guidebook.guidebook.elements.LinkContext; import dev.gigaherz.guidebook.guidebook.util.Color; import dev.gigaherz.guidebook.guidebook.util.LinkHelper; @@ -18,7 +19,7 @@ public class VisualText extends VisualElement implements LinkHelper.ILinkable public LinkContext linkContext = null; - public VisualText(Component text, Size size, int positionMode, float baseline, int verticalAlign, float scale) + public VisualText(Component text, Size size, Element.Position positionMode, float baseline, Element.VerticalAlignment verticalAlign, float scale) { super(size, positionMode, baseline, verticalAlign); this.text = text; diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/Element.java b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/Element.java index 7842cee..a15f791 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/Element.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/Element.java @@ -23,21 +23,28 @@ public abstract class Element implements IParseable { - public static final int VA_TOP = 0; + public enum VerticalAlignment + { + TOP, + MIDDLE, + BASELINE, + BOTTOM + } + + public enum Position + { + /* relative to the computed position (offset) */ + RELATIVE, + /* relative to the containing Panel */ + ABSOLUTE, + /* relative to the section */ + FIXED + } public static final int VA_MIDDLE = 1; public static final int VA_BASELINE = 2; public static final int VA_BOTTOM = 3; - public static final int POS_RELATIVE = 0; - public static final int POS_ABSOLUTE = 1; - public static final int POS_FIXED = 2; - - /* Positioning mode: - * 0 = "relative" -- relative to the computed position (offset) - * 1 = "absolute" -- relative to the containing Panel - * 2 = "fixed" -- relative to the section - */ - public int position = 0; + public Position position = Position.RELATIVE; public int x = 0; public int y = 0; @@ -49,13 +56,8 @@ public abstract class Element implements IParseable // in proportion to the element's calculated height public float baseline = 7 / 9f; // vanilla font has a baseline 7 pixels from the bottom, with 9px total height - /* Vertical align mode -- only applicable within a paragraph - * 0 = top - * 1 = middle - * 2 = baseline - * 3 = bottom - */ - public int verticalAlignment = VA_BASELINE; + /* Vertical align mode -- only applicable within a paragraph */ + public VerticalAlignment verticalAlignment = VerticalAlignment.BASELINE; public Predicate condition; public boolean conditionResult; @@ -117,10 +119,9 @@ public Point2I applyPosition(Point2I point, Point2I parent) { return switch (position) { - case POS_RELATIVE -> new Point2I(point.x() + x, point.y() + y); - case POS_ABSOLUTE -> new Point2I(parent.x() + x, parent.y() + y); - case POS_FIXED -> new Point2I(x, y); - default -> new Point2I(point); + case RELATIVE -> new Point2I(point.x() + x, point.y() + y); + case ABSOLUTE -> new Point2I(parent.x() + x, parent.y() + y); + case FIXED -> new Point2I(x, y); }; } @@ -143,35 +144,11 @@ public void parse(ParsingContext context, NamedNodeMap attributes) z = IParseable.getAttribute(attributes, "z", z); w = IParseable.getAttribute(attributes, "w", w); h = IParseable.getAttribute(attributes, "h", h); - baseline = IParseable.getAttribute(attributes, "baseline", baseline); + position = IParseable.getAttribute(attributes, "position", position, Position.class); + verticalAlignment = IParseable.getAttribute(attributes, "verticalAlignment", verticalAlignment, VerticalAlignment.class); - Node attr = attributes.getNamedItem("align"); - if (attr != null) - { - position = switch (attr.getTextContent()) - { - case "relative" -> 0; - case "absolute" -> 1; - case "fixed" -> 2; - default -> position; - }; - } - - attr = attributes.getNamedItem("vertical-align"); - if (attr != null) - { - verticalAlignment = switch (attr.getTextContent()) - { - case "top" -> VA_TOP; - case "middle" -> VA_MIDDLE; - case "baseline" -> VA_BASELINE; - case "bottom" -> VA_BOTTOM; - default -> verticalAlignment; - }; - } - - attr = attributes.getNamedItem("condition"); + Node attr = attributes.getNamedItem("condition"); if (attr != null) { condition = context.getCondition(attr.getTextContent()); diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementGrid.java b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementGrid.java index a854f7f..48d9e42 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementGrid.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementGrid.java @@ -5,11 +5,13 @@ import dev.gigaherz.guidebook.guidebook.BookParsingException; import dev.gigaherz.guidebook.guidebook.IBookGraphics; import dev.gigaherz.guidebook.guidebook.book.BookDocumentParser; +import dev.gigaherz.guidebook.guidebook.book.IParseable; import dev.gigaherz.guidebook.guidebook.book.ParsingContext; import dev.gigaherz.guidebook.guidebook.conditions.ConditionContext; import dev.gigaherz.guidebook.guidebook.drawing.VisualElement; import dev.gigaherz.guidebook.guidebook.drawing.VisualPanel; import dev.gigaherz.guidebook.guidebook.templates.TemplateDefinition; +import dev.gigaherz.guidebook.guidebook.util.Length; import dev.gigaherz.guidebook.guidebook.util.Point2I; import dev.gigaherz.guidebook.guidebook.util.Rect; import dev.gigaherz.guidebook.guidebook.util.Size; @@ -178,9 +180,9 @@ public int reflow(List list, IBookGraphics nav, Rect bounds, Rect var explicitHeight = 0; for (var row : rows) { - if (row.height != null && !row.heightPercent) + if (row.height != null && row.height.unit().equals("px")) { - row.computedHeight = row.height; + row.computedHeight = row.height.value(); explicitHeight += row.computedHeight; } } @@ -190,7 +192,7 @@ public int reflow(List list, IBookGraphics nav, Rect bounds, Rect { row.computedHeight = adjustedBounds.size.height() / rows.size(); if (row.height != null) - row.computedHeight = (row.heightPercent ? (row.height * bounds.size.height() / 100) : row.height); + row.computedHeight = (int) row.height.getValue(bounds.size.height()); accHeight += row.computedHeight; } if (accHeight > adjustedBounds.size.height()) @@ -209,7 +211,7 @@ public int reflow(List list, IBookGraphics nav, Rect bounds, Rect { col.computedWidth = adjustedBounds.size.width() / cols.size(); if (col.width != null) - col.computedWidth = (col.widthPercent ? (col.width * bounds.size.width() / 100) : col.width); + col.computedWidth = (int) col.width.getValue(bounds.size.width()); accWidth += col.computedWidth; } if (accWidth > adjustedBounds.size.width()) @@ -248,7 +250,7 @@ public int reflow(List list, IBookGraphics nav, Rect bounds, Rect top += rowHeight; } - if (position != POS_RELATIVE) + if (position != Element.Position.RELATIVE) { top = bounds.position.y(); } @@ -312,7 +314,6 @@ public Element applyTemplate(ParsingContext context, List sourceElement { var row1 = new Row(); row1.height = row.height; - row1.heightPercent = row.heightPercent; for(var cell : row.cells) { @@ -333,7 +334,6 @@ public Element applyTemplate(ParsingContext context, List sourceElement { var col1 = new Column(); col1.width = col.width; - col1.widthPercent = col.widthPercent; grid.cols.add(col1); } @@ -349,75 +349,38 @@ public boolean supportsPageLevel() return true; } - private static class Column + private static class Row { - public boolean widthPercent; - public Integer width; - public int computedWidth; + public Length height; + public List cells = new ArrayList<>(); + public int computedHeight; public void parse(NamedNodeMap attributes) { - var attr = attributes.getNamedItem("width"); - if (attr != null) - { - String t = attr.getTextContent(); - if (t.endsWith("%")) - { - widthPercent = true; - t = t.substring(0, t.length() - 1); - } - - width = Ints.tryParse(t); - } + height = IParseable.getAttribute(attributes, "height", height); } } - private static class Cell + private static class Column { - public Integer colspan = 1; - @Nullable - public Element content; + public Length width; + public int computedWidth; public void parse(NamedNodeMap attributes) { - Node attr = attributes.getNamedItem("colspan"); - if (attr != null) - { - String t = attr.getTextContent(); - colspan = Ints.tryParse(t); - } + width = IParseable.getAttribute(attributes, "width", width); } } - private static class Row + private static class Cell { - public boolean heightPercent; - public Integer height; - public List cells = new ArrayList<>(); - public int computedHeight; + public int colspan = 1; + @Nullable + public Element content; public void parse(NamedNodeMap attributes) { - Node attr = attributes.getNamedItem("height"); - if (attr != null) - { - String t = attr.getTextContent(); - if (t.endsWith("%")) - { - heightPercent = true; - t = t.substring(0, t.length() - 1); - } - - height = Ints.tryParse(t); - } + colspan = IParseable.getAttribute(attributes, "colspan", colspan); } } - - public record NumberWithUnits(float number, SizeUnits units){} - - public enum SizeUnits { - PIXELS, - PERCENT, - - } } diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementImage.java b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementImage.java index 7587e22..edb60db 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementImage.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementImage.java @@ -54,7 +54,7 @@ public int reflow(List paragraph, IBookGraphics nav, Rect bounds, VisualImage element = getVisual(); element.position = applyPosition(bounds.position, bounds.position); paragraph.add(element); - if (position != POS_RELATIVE) + if (position != Position.RELATIVE) return bounds.position.y(); return bounds.position.y() + element.size.height(); } diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementPanel.java b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementPanel.java index 6ceaddb..6489df7 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementPanel.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementPanel.java @@ -142,7 +142,7 @@ public int reflow(List list, IBookGraphics nav, Rect bounds, Rect } } - if (position != POS_RELATIVE) + if (position != Position.RELATIVE) { top = bounds.position.y(); } diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementParagraph.java b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementParagraph.java index 78f0ba3..26bcc76 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementParagraph.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementParagraph.java @@ -110,7 +110,7 @@ public int reflow(List paragraph, IBookGraphics nav, Rect bounds, processAlignment(paragraph, bounds.size.width() - currentIndent, currentLineLeft, firstInLine); - if (position != POS_RELATIVE) + if (position != Element.Position.RELATIVE) return bounds.position.y(); return currentLineTop + currentLineHeight + space; } @@ -133,7 +133,7 @@ private void processAlignment(List paragraph, int width, int curr for (int i = firstInLine; i < paragraph.size(); i++) { VisualElement e = paragraph.get(i); - if (e.positionMode == 0) + if (e.positionMode == Position.RELATIVE) { e.position = new Point2I(e.position.x() + leftOffset, e.position.y()); @@ -148,20 +148,15 @@ private void processAlignment(List paragraph, int width, int curr for (int i = firstInLine; i < paragraph.size(); i++) { VisualElement e = paragraph.get(i); - if (e.positionMode == 0) + if (e.positionMode == Position.RELATIVE) { - if (e.verticalAlign == VA_MIDDLE) + e.position = switch (e.verticalAlign) { - e.position = new Point2I(e.position.x(), yMin + (yHeight - e.size.height()) / 2); - } - else if (e.verticalAlign == VA_BASELINE) - { - e.position = new Point2I(e.position.x(), yBaseline - (int) (e.size.height() * e.baseline)); - } - else if (e.verticalAlign == VA_BOTTOM) - { - e.position = new Point2I(e.position.x(), yMax - e.size.height()); - } + case MIDDLE -> new Point2I(e.position.x(), yMin + (yHeight - e.size.height()) / 2); + case BASELINE -> new Point2I(e.position.x(), yBaseline - (int) (e.size.height() * e.baseline)); + case BOTTOM -> new Point2I(e.position.x(), yMax - e.size.height()); + case TOP -> e.position; + }; yMin2 = Math.min(yMin2, e.position.y()); } @@ -173,7 +168,7 @@ else if (e.verticalAlign == VA_BOTTOM) for (int i = firstInLine; i < paragraph.size(); i++) { VisualElement e = paragraph.get(i); - if (e.positionMode == 0) + if (e.positionMode == Position.RELATIVE) { e.position = new Point2I(e.position.x(), e.position.y() + yOffset); } diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementRecipe.java b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementRecipe.java index ffc448b..6389a22 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementRecipe.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementRecipe.java @@ -95,7 +95,7 @@ else if (recipeOutput instanceof ElementStack) background.reflow(list, nav, adjustedBounds, pageBounds); if (additionalRenderer != null) list.add(additionalRenderer); - if (position != POS_RELATIVE) + if (position != Position.RELATIVE) return bounds.position.y(); return adjustedPosition.y() + height; } diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementStack.java b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementStack.java index 89353f3..a10c1ab 100644 --- a/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementStack.java +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/elements/ElementStack.java @@ -64,7 +64,7 @@ public int reflow(List paragraph, IBookGraphics nav, Rect bounds, VisualStack element = getVisual(); element.position = applyPosition(bounds.position, bounds.position); paragraph.add(element); - if (position != POS_RELATIVE) + if (position != Position.RELATIVE) return bounds.position.y(); return bounds.position.y() + element.size.height(); } diff --git a/src/main/java/dev/gigaherz/guidebook/guidebook/util/Length.java b/src/main/java/dev/gigaherz/guidebook/guidebook/util/Length.java new file mode 100644 index 0000000..444cdff --- /dev/null +++ b/src/main/java/dev/gigaherz/guidebook/guidebook/util/Length.java @@ -0,0 +1,30 @@ +package dev.gigaherz.guidebook.guidebook.util; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public record Length(int value, String unit) +{ + private static final Pattern PATTERN = Pattern.compile("^(?\\d+)(?px|%|)$"); + + public float getValue(int parentValue/*, float fontSize*/) // TODO: make context object that can handle more units + { + return switch (unit) + { + case "px" -> value; + //case "em" -> value * fontSize; + case "%" -> value * parentValue / 100f; + default -> throw new IllegalArgumentException("Unknown length unit " + unit); + }; + } + + public static Length parse(String s) + { + Matcher matcher = PATTERN.matcher(s); + if (!matcher.matches()) throw new IllegalArgumentException("Invalid length: " + s); + int num = Integer.parseInt(matcher.group("num")); + String unit = matcher.group("unit"); + if (unit.isEmpty()) unit = "px"; + return new Length(num, unit); + } +} From 9474de012ea6a84b8a519333427c76e2daf02ee0 Mon Sep 17 00:00:00 2001 From: Minecraftschurli Date: Wed, 29 Jun 2022 12:34:58 +0200 Subject: [PATCH 8/8] update jei --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index ad5c14f..65f30d5 100644 --- a/build.gradle +++ b/build.gradle @@ -109,8 +109,8 @@ dependencies { minecraft 'net.minecraftforge:forge:1.19-41.0.17' - compileOnly fg.deobf("mezz.jei:jei-1.18.2-common-api:10.0.0.191") - //runtimeOnly fg.deobf("mezz.jei:jei-1.19-forge:10.0.0.191") + compileOnly fg.deobf("mezz.jei:jei-1.19-common-api:11.0.0.206") + runtimeOnly fg.deobf("mezz.jei:jei-1.19-forge:11.0.0.206") implementation fg.deobf( "net.darkhax.gamestages:GameStages-Forge-1.19:9.0.1") implementation fg.deobf( "net.darkhax.bookshelf:Bookshelf-Forge-1.19:14.0.2")