diff --git a/src/generated/resources/assets/thavma/lang/en_us.json b/src/generated/resources/assets/thavma/lang/en_us.json index bddd0d24..be0b84e5 100644 --- a/src/generated/resources/assets/thavma/lang/en_us.json +++ b/src/generated/resources/assets/thavma/lang/en_us.json @@ -85,7 +85,7 @@ "item.thavma.basic_amulet": "Basic Amulet", "item.thavma.basic_belt": "Basic Belt", "item.thavma.basic_ring": "Basic Ring", - "item.thavma.book": "Elements of Thavma", + "item.thavma.book": "Elements", "item.thavma.charm_of_the_dawn": "Charm of the Dawn", "item.thavma.eye_of_warden": "Eye of Warden", "item.thavma.fabric": "Infused Fabric", @@ -157,7 +157,7 @@ "recipe_viewer.thavma.description.greatwood": "Greatwoods are very tall, ancient trees. They are somewhat rare, but they can spawn in all overworld biomes.", "recipe_viewer.thavma.description.infused_stones": "A piece of stone, infused with a primal element. Found in the overworld, at any height.", "recipe_viewer.thavma.description.pillar": "Formed by right clicking the Infusion Matrix, after completing the Infusion Multiblock.", - "recipe_viewer.thavma.description.research_scroll": "Obtained by clicking any unknown entry in the \"Elements of Thavma\"", + "recipe_viewer.thavma.description.research_scroll": "Obtained by clicking any unknown entry in the \"Elements\"", "recipe_viewer.thavma.description.research_table": "Can be formed by placing 2 tables next to each other, and right clicking one with a wand.", "recipe_viewer.thavma.description.rotten_brain": "Sometimes dropped by angry zombies.", "recipe_viewer.thavma.description.silverwood": "Silverwoods are magical trees, with uniquely blue leaves. They are very rare, but they can spawn in all overworld biomes.", @@ -169,15 +169,16 @@ "research/category.thavma.thavma": "Thavma", "research/entry.thavma.alchemy.alchemy": "Alchemy", "research/entry.thavma.story.story1": "A Courtesy Call", - "research/entry.thavma.story.story1.page0.paragraph0": "Lorem ipsum %s 1 sit amet,", - "research/entry.thavma.story.story1.page0.paragraph1": "this story a great meaning haveth.", - "research/entry.thavma.story.story1.page0.title": "A Courtesy Call 1", - "research/entry.thavma.story.story1.page1.paragraph0": "Lorem dolor 2 sit amet,", - "research/entry.thavma.story.story1.page1.paragraph1": "this story a great meaning haveth.", - "research/entry.thavma.story.story1.page1.title": "A Courtesy Call 2", - "research/entry.thavma.story.story1.page2.paragraph0": "Lorem lotrumatum dolor 3 sit amet,", - "research/entry.thavma.story.story1.page2.paragraph1": "this story a great meaning haveth.", - "research/entry.thavma.story.story1.page2.title": "A Courtesy Call 3", + "research/entry.thavma.story.story1.figure_feature0": "A short caption for the figure just to show the custom style ", + "research/entry.thavma.story.story1.paragraph_feature0": "This is a short paragraph just to showcase that the feature exists.", + "research/entry.thavma.story.story1.paragraph_feature1": "This is a longer paragraph to highlight the importance of splicing longer pieces of text over multiple pages. If you do not splice the paragraph to go over multiple pages, the text will spill out of the bottom of the screen and we don't want that to happen, hence DynamicRenderingHelper.kt. I will continue with some lorem ipsum. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque dapibus mattis lectus, quis aliquet ex. In hac habitasse platea dictumst. Praesent dignissim urna at feugiat pulvinar. Suspendisse laoreet lorem ut velit venenatis gravida. Donec posuere diam est, ac malesuada libero fermentum sed. Phasellus ac cursus nibh, eget pharetra leo. Maecenas scelerisque velit massa, sit amet tincidunt nulla dictum non. Sed egestas congue bibendum. Aenean facilisis nunc vitae purus tincidunt, sit amet dignissim libero gravida. Mauris vel tortor elit. Curabitur sit amet nisi sagittis, ullamcorper diam sed, condimentum est. Etiam blandit ac magna sit amet luctus. Duis nec mi tincidunt nunc.", + "research/entry.thavma.story.story1.paragraph_feature2": "This paragraph should start a new page always.", + "research/entry.thavma.story.story1.paragraph_feature3": "Just another random little paragraph :D", + "research/entry.thavma.story.story1.paragraph_feature4": "This paragraph has a pre-set page index of 2", + "research/entry.thavma.story.story1.title_feature0": "This title starts the page", + "research/entry.thavma.story.story1.title_feature1": "This might appear in the middle", + "research/entry.thavma.story.story1.title_feature2": "(start of page)", + "research/entry.thavma.story.story1.title_feature3": "This is page number 1!", "research/entry.thavma.thavma.alchemy": "Alchemy", "research/entry.thavma.thavma.arcane_lens": "The Arcane Lens", "research/entry.thavma.thavma.arcane_lens.page0.paragraph0": "The part of the book I can read describes an arcane tool that \"allows the user to see\", whatever that might mean. I have a feeling that crafting it could assist my work in unsealing the other pages.", @@ -191,7 +192,7 @@ "research/entry.thavma.thavma.technology": "Technology", "research/entry.thavma.thavma.thavma": "Thavma", "research/entry.thavma.thavma.thavma.page0.paragraph0": "I was merely toying with that wand -if it can even be called that- when this tome flew into my hands! I can sense great power within it.", - "research/entry.thavma.thavma.thavma.page0.paragraph1": "The cover reads \"Elements of Thavma\", but a lot of its pages appear blank, sealed by some magic.", + "research/entry.thavma.thavma.thavma.page0.paragraph1": "The cover reads \"Elements\", but a lot of its pages appear blank, sealed by some magic.", "research/entry.thavma.thavma.thavma.page0.paragraph2": "To read them, I will first need to break that seal. It won't be easy... but I have a feeling it will be worth my efforts.", "research/entry.thavma.thavma.thavma.page0.title": "Thavma", "research/entry.thavma.thavma.thavma.page1.paragraph0": "I will document all my findings inside the book, so that I can recall them later.", diff --git a/src/generated/resources/data/thavma/thavma/research/entry/alchemy/alchemy.json b/src/generated/resources/data/thavma/thavma/research/entry/alchemy/alchemy.json index e5abb074..4c760f17 100644 --- a/src/generated/resources/data/thavma/thavma/research/entry/alchemy/alchemy.json +++ b/src/generated/resources/data/thavma/thavma/research/entry/alchemy/alchemy.json @@ -26,7 +26,7 @@ "count": 1, "id": "thavma:crucible" }, - "pages": [], + "pageFeatures": [], "position": [ 0, 0 diff --git a/src/generated/resources/data/thavma/thavma/research/entry/story/story1.json b/src/generated/resources/data/thavma/thavma/research/entry/story/story1.json index 0cdc3892..b86ff040 100644 --- a/src/generated/resources/data/thavma/thavma/research/entry/story/story1.json +++ b/src/generated/resources/data/thavma/thavma/research/entry/story/story1.json @@ -7,50 +7,93 @@ "count": 1, "id": "minecraft:turtle_helmet" }, - "pages": [ + "pageFeatures": [ { - "type": "thavma:text", - "paragraphs": [ - { - "translate": "research/entry.thavma.story.story1.page0.paragraph0" - }, - { - "translate": "research/entry.thavma.story.story1.page0.paragraph1" - } - ], - "title": { + "type": "thavma:title", + "text": { "bold": true, - "translate": "research/entry.thavma.story.story1.page0.title" + "translate": "research/entry.thavma.story.story1.title_feature0" } }, { - "type": "thavma:text", - "paragraphs": [ - { - "translate": "research/entry.thavma.story.story1.page1.paragraph0" - }, - { - "translate": "research/entry.thavma.story.story1.page1.paragraph1" - } - ], - "title": { + "type": "thavma:paragraph", + "text": { + "translate": "research/entry.thavma.story.story1.paragraph_feature0" + } + }, + { + "type": "thavma:paragraph", + "text": { + "translate": "research/entry.thavma.story.story1.paragraph_feature1" + } + }, + { + "type": "thavma:figure", + "caption": { + "color": "dark_aqua", + "italic": true, + "translate": "research/entry.thavma.story.story1.figure_feature0" + }, + "force_index": 1, + "image": { + "canvas_height": 101, + "canvas_width": 180, + "height": 101, + "location": "thavma:textures/gui/images/haybales.png", + "width": 180 + } + }, + { + "type": "thavma:title", + "text": { "bold": true, - "translate": "research/entry.thavma.story.story1.page1.title" + "translate": "research/entry.thavma.story.story1.title_feature1" + } + }, + { + "type": "thavma:paragraph", + "starts_page": true, + "text": { + "translate": "research/entry.thavma.story.story1.paragraph_feature2" } }, { - "type": "thavma:text", - "paragraphs": [ - { - "translate": "research/entry.thavma.story.story1.page2.paragraph0" - }, - { - "translate": "research/entry.thavma.story.story1.page2.paragraph1" - } - ], - "title": { + "type": "thavma:title", + "text": { "bold": true, - "translate": "research/entry.thavma.story.story1.page2.title" + "translate": "research/entry.thavma.story.story1.title_feature2" + } + }, + { + "type": "thavma:title", + "force_index": 0, + "text": { + "bold": true, + "translate": "research/entry.thavma.story.story1.title_feature3" + } + }, + { + "type": "thavma:paragraph", + "text": { + "translate": "research/entry.thavma.story.story1.paragraph_feature3" + } + }, + { + "type": "thavma:figure", + "force_index": 2, + "image": { + "canvas_height": 77, + "canvas_width": 87, + "height": 77, + "location": "thavma:textures/gui/images/smileyface.png", + "width": 87 + } + }, + { + "type": "thavma:paragraph", + "force_index": 2, + "text": { + "translate": "research/entry.thavma.story.story1.paragraph_feature4" } } ], diff --git a/src/generated/resources/data/thavma/thavma/research/entry/thavma/alchemy.json b/src/generated/resources/data/thavma/thavma/research/entry/thavma/alchemy.json index cf144174..9af0e3d1 100644 --- a/src/generated/resources/data/thavma/thavma/research/entry/thavma/alchemy.json +++ b/src/generated/resources/data/thavma/thavma/research/entry/thavma/alchemy.json @@ -26,7 +26,7 @@ "count": 1, "id": "thavma:crucible" }, - "pages": [], + "pageFeatures": [], "position": [ -2, 2 diff --git a/src/generated/resources/data/thavma/thavma/research/entry/thavma/arcane_lens.json b/src/generated/resources/data/thavma/thavma/research/entry/thavma/arcane_lens.json index b1cf4745..33183a96 100644 --- a/src/generated/resources/data/thavma/thavma/research/entry/thavma/arcane_lens.json +++ b/src/generated/resources/data/thavma/thavma/research/entry/thavma/arcane_lens.json @@ -36,26 +36,7 @@ "count": 1, "id": "thavma:arcane_lens" }, - "pages": [ - { - "type": "thavma:text", - "paragraphs": [ - { - "translate": "research/entry.thavma.thavma.arcane_lens.page0.paragraph0" - }, - { - "translate": "research/entry.thavma.thavma.arcane_lens.page0.paragraph1" - }, - { - "translate": "research/entry.thavma.thavma.arcane_lens.page0.paragraph2" - } - ], - "title": { - "bold": true, - "translate": "research/entry.thavma.thavma.arcane_lens.page0.title" - } - } - ], + "pageFeatures": [], "position": [ 2, -2 diff --git a/src/generated/resources/data/thavma/thavma/research/entry/thavma/infusion.json b/src/generated/resources/data/thavma/thavma/research/entry/thavma/infusion.json index ca774a8a..fa0d7078 100644 --- a/src/generated/resources/data/thavma/thavma/research/entry/thavma/infusion.json +++ b/src/generated/resources/data/thavma/thavma/research/entry/thavma/infusion.json @@ -26,7 +26,7 @@ "count": 1, "id": "thavma:infusion_matrix" }, - "pages": [], + "pageFeatures": [], "position": [ 2, 2 diff --git a/src/generated/resources/data/thavma/thavma/research/entry/thavma/ores.json b/src/generated/resources/data/thavma/thavma/research/entry/thavma/ores.json index 2dee4be2..ea1a35f3 100644 --- a/src/generated/resources/data/thavma/thavma/research/entry/thavma/ores.json +++ b/src/generated/resources/data/thavma/thavma/research/entry/thavma/ores.json @@ -28,7 +28,7 @@ "count": 1, "id": "thavma:aqua_shard" }, - "pages": [], + "pageFeatures": [], "position": [ 2, -4 diff --git a/src/generated/resources/data/thavma/thavma/research/entry/thavma/research_proficiency.json b/src/generated/resources/data/thavma/thavma/research/entry/thavma/research_proficiency.json index 382dde7e..36d325ae 100644 --- a/src/generated/resources/data/thavma/thavma/research/entry/thavma/research_proficiency.json +++ b/src/generated/resources/data/thavma/thavma/research/entry/thavma/research_proficiency.json @@ -26,7 +26,7 @@ "count": 1, "id": "thavma:research_table" }, - "pages": [], + "pageFeatures": [], "position": [ -1, -1 diff --git a/src/generated/resources/data/thavma/thavma/research/entry/thavma/research_table.json b/src/generated/resources/data/thavma/thavma/research/entry/thavma/research_table.json index 1edfaf76..928ed808 100644 --- a/src/generated/resources/data/thavma/thavma/research/entry/thavma/research_table.json +++ b/src/generated/resources/data/thavma/thavma/research/entry/thavma/research_table.json @@ -32,12 +32,7 @@ "count": 1, "id": "thavma:research_table" }, - "pages": [ - { - "type": "thavma:crafting", - "recipeRL": "minecraft:chest" - } - ], + "pageFeatures": [], "position": [ 0, 0 diff --git a/src/generated/resources/data/thavma/thavma/research/entry/thavma/technology.json b/src/generated/resources/data/thavma/thavma/research/entry/thavma/technology.json index 03f96e16..e7999939 100644 --- a/src/generated/resources/data/thavma/thavma/research/entry/thavma/technology.json +++ b/src/generated/resources/data/thavma/thavma/research/entry/thavma/technology.json @@ -26,7 +26,7 @@ "count": 1, "id": "thavma:goggles" }, - "pages": [], + "pageFeatures": [], "position": [ 2, 4 diff --git a/src/generated/resources/data/thavma/thavma/research/entry/thavma/thavma.json b/src/generated/resources/data/thavma/thavma/research/entry/thavma/thavma.json index 8c91c2af..a4906b9e 100644 --- a/src/generated/resources/data/thavma/thavma/research/entry/thavma/thavma.json +++ b/src/generated/resources/data/thavma/thavma/research/entry/thavma/thavma.json @@ -29,34 +29,7 @@ "count": 1, "id": "thavma:book" }, - "pages": [ - { - "type": "thavma:text", - "paragraphs": [ - { - "translate": "research/entry.thavma.thavma.thavma.page0.paragraph0" - }, - { - "translate": "research/entry.thavma.thavma.thavma.page0.paragraph1" - }, - { - "translate": "research/entry.thavma.thavma.thavma.page0.paragraph2" - } - ], - "title": { - "bold": true, - "translate": "research/entry.thavma.thavma.thavma.page0.title" - } - }, - { - "type": "thavma:text", - "paragraphs": [ - { - "translate": "research/entry.thavma.thavma.thavma.page1.paragraph0" - } - ] - } - ], + "pageFeatures": [], "position": [ 0, -6 diff --git a/src/generated/resources/data/thavma/thavma/research/entry/thavma/trees.json b/src/generated/resources/data/thavma/thavma/research/entry/thavma/trees.json index 1d03df95..b47d0111 100644 --- a/src/generated/resources/data/thavma/thavma/research/entry/thavma/trees.json +++ b/src/generated/resources/data/thavma/thavma/research/entry/thavma/trees.json @@ -28,7 +28,7 @@ "count": 1, "id": "thavma:greatwood_log" }, - "pages": [], + "pageFeatures": [], "position": [ 0, -3 diff --git a/src/generated/resources/data/thavma/thavma/research/entry/thavma/wands.json b/src/generated/resources/data/thavma/thavma/research/entry/thavma/wands.json index 77ccd882..6dff452d 100644 --- a/src/generated/resources/data/thavma/thavma/research/entry/thavma/wands.json +++ b/src/generated/resources/data/thavma/thavma/research/entry/thavma/wands.json @@ -26,7 +26,7 @@ "count": 1, "id": "thavma:thavmite_silverwood_wand" }, - "pages": [], + "pageFeatures": [], "position": [ -2, 4 diff --git a/src/main/java/me/alegian/thavma/impl/Thavma.kt b/src/main/java/me/alegian/thavma/impl/Thavma.kt index b14253ac..d97a950a 100644 --- a/src/main/java/me/alegian/thavma/impl/Thavma.kt +++ b/src/main/java/me/alegian/thavma/impl/Thavma.kt @@ -36,6 +36,7 @@ object Thavma { T7Attributes.REGISTRAR.register(KFF_MOD_BUS) T7GlobalLootModifierSerializers.REGISTRAR.register(KFF_MOD_BUS) PageTypes.REGISTRAR.register(KFF_MOD_BUS) + PageFeatureTypes.REGISTRAR.register(KFF_MOD_BUS) T7Features.REGISTRAR.register(KFF_MOD_BUS) registerCommonModEvents() diff --git a/src/main/java/me/alegian/thavma/impl/client/event/RegisterPageFeatureRenderersEvent.kt b/src/main/java/me/alegian/thavma/impl/client/event/RegisterPageFeatureRenderersEvent.kt new file mode 100644 index 00000000..77b10989 --- /dev/null +++ b/src/main/java/me/alegian/thavma/impl/client/event/RegisterPageFeatureRenderersEvent.kt @@ -0,0 +1,14 @@ +package me.alegian.thavma.impl.client.event + +import me.alegian.thavma.impl.client.gui.book.PAGE_FEATURE_RENDERERS +import me.alegian.thavma.impl.client.gui.book.PageFeatureRenderer +import me.alegian.thavma.impl.common.book.PageFeature +import me.alegian.thavma.impl.common.book.PageFeatureType +import net.neoforged.bus.api.Event +import net.neoforged.fml.event.IModBusEvent + +class RegisterPageFeatureRenderersEvent : Event(), IModBusEvent { + fun register(pageFeatureType: PageFeatureType, pageFeatureRenderer: PageFeatureRenderer) { + PAGE_FEATURE_RENDERERS[pageFeatureType] = pageFeatureRenderer + } +} \ No newline at end of file diff --git a/src/main/java/me/alegian/thavma/impl/client/event/T7ClientModEvents.kt b/src/main/java/me/alegian/thavma/impl/client/event/T7ClientModEvents.kt index 2dddd63a..491ad516 100644 --- a/src/main/java/me/alegian/thavma/impl/client/event/T7ClientModEvents.kt +++ b/src/main/java/me/alegian/thavma/impl/client/event/T7ClientModEvents.kt @@ -5,8 +5,7 @@ import me.alegian.thavma.impl.client.extension.ArcaneLensItemExtensions import me.alegian.thavma.impl.client.extension.BEWLRItemExtensionFactory import me.alegian.thavma.impl.client.extension.WandItemExtensions import me.alegian.thavma.impl.client.gui.WorkbenchScreen -import me.alegian.thavma.impl.client.gui.book.CraftingPageRenderer -import me.alegian.thavma.impl.client.gui.book.TextPageRenderer +import me.alegian.thavma.impl.client.gui.book.* import me.alegian.thavma.impl.client.gui.layer.ArcaneLensLayer import me.alegian.thavma.impl.client.gui.layer.WandLayer import me.alegian.thavma.impl.client.gui.research_table.ResearchScreen @@ -42,6 +41,7 @@ import thedarkcolour.kotlinforforge.neoforge.forge.MOD_BUS as KFF_MOD_BUS private fun clientSetup(event: FMLClientSetupEvent) { ModLoader.postEvent(RegisterPageRenderersEvent()) + ModLoader.postEvent(RegisterPageFeatureRenderersEvent()) ItemProperties.register(T7Items.RESEARCH_SCROLL.get(), T7ItemProperties.COMPLETED) { stack, level, entity, seed -> val completed = stack.get(T7DataComponents.RESEARCH_STATE)?.completed ?: false if (completed) 1f else 0f @@ -226,6 +226,13 @@ private fun registerPageRenderers(event: RegisterPageRenderersEvent) { event.register(PageTypes.CRAFTING.get(), CraftingPageRenderer) } +private fun registerPageFeatureRenderers(event: RegisterPageFeatureRenderersEvent) { + event.register(PageFeatureTypes.PARAGRAPH.get(), ParagraphFeatureRenderer) + event.register(PageFeatureTypes.TITLE.get(), TitleFeatureRenderer) + event.register(PageFeatureTypes.FIGURE.get(), FigureFeatureRenderer) + event.register(PageFeatureTypes.RECIPE.get(), RecipeFeatureRenderer) +} + private fun registerKeyMappings(event: RegisterKeyMappingsEvent) { event.register(T7KeyMappings.FOCI) } @@ -251,6 +258,7 @@ fun registerClientModEvents() { KFF_MOD_BUS.addListener(::registerClientTooltipComponentFactories) KFF_MOD_BUS.addListener(::registerScreens) KFF_MOD_BUS.addListener(::registerPageRenderers) + KFF_MOD_BUS.addListener(::registerPageFeatureRenderers) KFF_MOD_BUS.addListener(::registerKeyMappings) KFF_MOD_BUS.addListener(::registerRenderBuffers) } \ No newline at end of file diff --git a/src/main/java/me/alegian/thavma/impl/client/gui/book/DynamicRenderingHelper.kt b/src/main/java/me/alegian/thavma/impl/client/gui/book/DynamicRenderingHelper.kt new file mode 100644 index 00000000..2f1840d6 --- /dev/null +++ b/src/main/java/me/alegian/thavma/impl/client/gui/book/DynamicRenderingHelper.kt @@ -0,0 +1,7 @@ +package me.alegian.thavma.impl.client.gui.book + +import net.minecraft.client.Minecraft + +val LINE_HEIGHT = Minecraft.getInstance().font.lineHeight + 2 +const val PARAGRAPH_OFFSET = 2 / 3f +val PRG_OFFSET_OTHER = LINE_HEIGHT * 2 / 3 diff --git a/src/main/java/me/alegian/thavma/impl/client/gui/book/EntryScreen.kt b/src/main/java/me/alegian/thavma/impl/client/gui/book/EntryScreen.kt index 12eb73e2..1403ae65 100644 --- a/src/main/java/me/alegian/thavma/impl/client/gui/book/EntryScreen.kt +++ b/src/main/java/me/alegian/thavma/impl/client/gui/book/EntryScreen.kt @@ -2,19 +2,22 @@ package me.alegian.thavma.impl.client.gui.book import me.alegian.thavma.impl.client.gui.layout.* import me.alegian.thavma.impl.client.texture.Texture -import me.alegian.thavma.impl.common.book.Page +import me.alegian.thavma.impl.common.book.PageFeature import me.alegian.thavma.impl.common.research.ResearchEntry import net.minecraft.client.gui.GuiGraphics import net.minecraft.client.gui.screens.Screen import net.minecraft.core.Holder import net.minecraft.network.chat.Component -class EntryScreen(private val entry: Holder) : Screen(Component.literal("Book Entry")) { +class EntryScreen(_entry: Holder) : Screen(Component.literal("Book Entry")) { companion object { private val BG = Texture("gui/book/background", 510, 282, 512, 512) } private var currentPage = 0 + private val entry = _entry.value() + + var pages = listOf>() override fun init() { super.init() @@ -27,56 +30,90 @@ class EntryScreen(private val entry: Holder) : Screen(Component.l align = Alignment.CENTER }) { TextureBox(BG) { - Row({ + Column({ size = grow() - paddingTop = 32 - paddingX = 32 - paddingBottom = 42 - gap = 48 }) { Row({ size = grow() + paddingY = PageTurningWidget.LEFT_TEXTURE.height + 8 + paddingX = 32 + paddingBottom = 42 + gap = 48 }) { - initPage(entry.value().pages.getOrNull(currentPage)) - if (currentPage != 0) { - Box({ - width = fixed(PageTurningWidget.LEFT_TEXTURE.width) - height = fixed(PageTurningWidget.LEFT_TEXTURE.height) + Row({ + size = grow() + }) { + Column({ + size = grow() + gap = 4 }) { - afterLayout { - addRenderableWidget(PageTurningWidget(position, false) { - // rerender the screen for the new page(s) - turnPage(false) - }) + if (pages.isEmpty()) { + pages = entry.pageFeatures.map { listOf(it) } + } + val features = pages.getOrNull(currentPage) + if (features != null) { + for (feature in features) initPageFeature(feature) } } } - } - Row({ - size = grow() - }) { - initPage(entry.value().pages.getOrNull(currentPage + 1)) - if (entry.value().pages.getOrNull(currentPage + 2) != null) { - Box({ - width = fixed(PageTurningWidget.RIGHT_TEXTURE.width) - height = fixed(PageTurningWidget.RIGHT_TEXTURE.height) + Row({ + size = grow() + }) { + Column({ + size = grow() + gap = 4 }) { - afterLayout { - addRenderableWidget(PageTurningWidget(position, true) { - // rerender the screen for the new page(s) - turnPage(true) - }) + val features = pages.getOrNull(currentPage + 1) + if (features != null) { + for (feature in features) initPageFeature(feature) } } } } + PageTurnerRow() + } + } + } + } + + private fun PageTurnerRow() { + Row({ + width = grow() + paddingX = 30 + paddingY = 15 + }) { + if (currentPage != 0) { + Box({ + width = fixed(PageTurningWidget.LEFT_TEXTURE.width) + height = fixed(PageTurningWidget.LEFT_TEXTURE.height) + }) { + afterLayout { + addRenderableWidget(PageTurningWidget(position, false) { + // rerender the screen for the new page(s) + turnPage(false) + }) + } + } + } + Box({ width = grow() }) {} + if (pages.getOrNull(currentPage + 2) != null) { + Box({ + width = fixed(PageTurningWidget.RIGHT_TEXTURE.width) + height = fixed(PageTurningWidget.RIGHT_TEXTURE.height) + }) { + afterLayout { + addRenderableWidget(PageTurningWidget(position, true) { + // rerender the screen for the new page(s) + turnPage(true) + }) + } } } } } - fun turnPage(right: Boolean){ + fun turnPage(right: Boolean) { if (right) currentPage += 2 else currentPage -= 2 init() @@ -87,11 +124,12 @@ class EntryScreen(private val entry: Holder) : Screen(Component.l } // wrapper around unchecked cast - private fun initPage(page: T) { - if (page == null) return - val renderer = PAGE_RENDERERS[page.type] as PageRenderer - renderer.initPage(this, page) + private fun initPageFeature(feature: T) { + if (feature != null) { + val renderer = PAGE_FEATURE_RENDERERS[feature.type] as PageFeatureRenderer + renderer.initPageFeature(this, feature, this.font) + } } override fun isPauseScreen() = false -} \ No newline at end of file +} diff --git a/src/main/java/me/alegian/thavma/impl/client/gui/book/FigureFeatureRenderer.kt b/src/main/java/me/alegian/thavma/impl/client/gui/book/FigureFeatureRenderer.kt new file mode 100644 index 00000000..d5d5c170 --- /dev/null +++ b/src/main/java/me/alegian/thavma/impl/client/gui/book/FigureFeatureRenderer.kt @@ -0,0 +1,24 @@ +package me.alegian.thavma.impl.client.gui.book + +import me.alegian.thavma.impl.client.gui.layout.CenteredTextureBox +import me.alegian.thavma.impl.client.gui.layout.Row +import me.alegian.thavma.impl.client.gui.layout.fixed +import me.alegian.thavma.impl.client.gui.layout.grow +import me.alegian.thavma.impl.common.book.FigureFeature +import net.minecraft.client.gui.Font + +object FigureFeatureRenderer : PageFeatureRenderer { + + override fun initPageFeature( + screen: EntryScreen, + feature: FigureFeature, + font: Font + ) { + Row({ + width = grow() + height = fixed(feature.textureHeight) + }) { + CenteredTextureBox(feature.image) + } + } +} diff --git a/src/main/java/me/alegian/thavma/impl/client/gui/book/PageFeatureRenderer.kt b/src/main/java/me/alegian/thavma/impl/client/gui/book/PageFeatureRenderer.kt new file mode 100644 index 00000000..fe1366db --- /dev/null +++ b/src/main/java/me/alegian/thavma/impl/client/gui/book/PageFeatureRenderer.kt @@ -0,0 +1,11 @@ +package me.alegian.thavma.impl.client.gui.book + +import me.alegian.thavma.impl.common.book.PageFeature +import me.alegian.thavma.impl.common.book.PageFeatureType +import net.minecraft.client.gui.Font + +val PAGE_FEATURE_RENDERERS = mutableMapOf, PageFeatureRenderer<*>>() + +interface PageFeatureRenderer { + fun initPageFeature(screen: EntryScreen, feature: T, font: Font) +} diff --git a/src/main/java/me/alegian/thavma/impl/client/gui/book/ParagraphFeatureRenderer.kt b/src/main/java/me/alegian/thavma/impl/client/gui/book/ParagraphFeatureRenderer.kt new file mode 100644 index 00000000..c59a7914 --- /dev/null +++ b/src/main/java/me/alegian/thavma/impl/client/gui/book/ParagraphFeatureRenderer.kt @@ -0,0 +1,44 @@ +package me.alegian.thavma.impl.client.gui.book + +import me.alegian.thavma.impl.client.gui.layout.Row +import me.alegian.thavma.impl.client.gui.layout.derived +import me.alegian.thavma.impl.client.gui.layout.draw +import me.alegian.thavma.impl.client.gui.layout.grow +import me.alegian.thavma.impl.client.util.drawString +import me.alegian.thavma.impl.client.util.translateXY +import me.alegian.thavma.impl.client.util.usePose +import me.alegian.thavma.impl.common.book.ParagraphFeature +import net.minecraft.client.gui.Font +import net.minecraft.client.gui.components.Renderable +import net.minecraft.util.FormattedCharSequence + +object ParagraphFeatureRenderer : PageFeatureRenderer { + + override fun initPageFeature( + screen: EntryScreen, + feature: ParagraphFeature, + font: Font + ) { + + var lines: List = listOf() + Row({ + width = grow() + height = derived { w -> + lines = font.split(feature.text, w.toInt()) + LINE_HEIGHT * (lines.size + PARAGRAPH_OFFSET) + } + }) { + draw { + Renderable { guiGraphics, _, _, _ -> + guiGraphics.usePose { + for (line in lines) { + guiGraphics.drawString(font, line) + translateXY(0, LINE_HEIGHT) + } + translateXY(0, PRG_OFFSET_OTHER) + } + } + } + } + } +} diff --git a/src/main/java/me/alegian/thavma/impl/client/gui/book/RecipeFeatureRenderer.kt b/src/main/java/me/alegian/thavma/impl/client/gui/book/RecipeFeatureRenderer.kt new file mode 100644 index 00000000..5f85ffbc --- /dev/null +++ b/src/main/java/me/alegian/thavma/impl/client/gui/book/RecipeFeatureRenderer.kt @@ -0,0 +1,52 @@ +package me.alegian.thavma.impl.client.gui.book + +import me.alegian.thavma.impl.client.gui.layout.* +import me.alegian.thavma.impl.client.texture.Texture +import me.alegian.thavma.impl.client.util.drawCenteredString +import me.alegian.thavma.impl.common.book.RecipeFeature +import me.alegian.thavma.impl.common.recipe.translationId +import net.minecraft.client.Minecraft +import net.minecraft.client.gui.Font +import net.minecraft.client.gui.components.Renderable +import net.minecraft.network.chat.Component +import net.minecraft.world.item.crafting.CraftingRecipe +import net.minecraft.world.item.crafting.RecipeType +import kotlin.jvm.optionals.getOrNull + +object RecipeFeatureRenderer : PageFeatureRenderer { + private val GRID = Texture("gui/book/crafting", 96, 96, 96, 96) + private val RESULT = Texture("gui/book/result", 32, 32, 32, 32) + private val TITLE = Component.translatable(RecipeType.CRAFTING.translationId) + private const val GAP = 12 + + override fun initPageFeature(screen: EntryScreen, feature: RecipeFeature, font: Font) { + val recipe = Minecraft.getInstance().level?.recipeManager?.byKey(feature.recipeRL)?.getOrNull()?.value + if (recipe !is CraftingRecipe) return // TODO: support other recipe types + + Column({ + alignCross = Alignment.CENTER + size = grow() + gap = GAP + }) { + Title() + + TextureBox(RESULT) {} + + TextureBox(GRID) {} + } + } + + private fun Title() { + val font = Minecraft.getInstance().font + + Row({ + height = fixed(font.lineHeight) + }) { + draw { + Renderable { guiGraphics, _, _, _ -> + guiGraphics.drawCenteredString(font, TITLE, size.x / 2) + } + } + } + } +} diff --git a/src/main/java/me/alegian/thavma/impl/client/gui/book/TitleFeatureRenderer.kt b/src/main/java/me/alegian/thavma/impl/client/gui/book/TitleFeatureRenderer.kt new file mode 100644 index 00000000..123c0b77 --- /dev/null +++ b/src/main/java/me/alegian/thavma/impl/client/gui/book/TitleFeatureRenderer.kt @@ -0,0 +1,61 @@ +package me.alegian.thavma.impl.client.gui.book + +import me.alegian.thavma.impl.client.gui.layout.* +import me.alegian.thavma.impl.client.texture.Texture +import me.alegian.thavma.impl.client.util.drawCenteredString +import me.alegian.thavma.impl.client.util.translateXY +import me.alegian.thavma.impl.client.util.usePose +import me.alegian.thavma.impl.common.book.TitleFeature +import net.minecraft.client.gui.Font +import net.minecraft.client.gui.components.Renderable +import net.minecraft.util.FormattedCharSequence + +object TitleFeatureRenderer : PageFeatureRenderer { + + private val SEPARATOR = Texture("gui/book/separator", 128, 16, 128, 16) + + override fun initPageFeature( + screen: EntryScreen, + feature: TitleFeature, + font: Font + ) { + Title(feature, font) + Separator() + } + + private fun Separator() { + Row({ + width = grow() + alignMain = Alignment.CENTER + }) { + TextureBox(SEPARATOR) {} + } + } + + private fun Title(title: TitleFeature, font: Font) { + + var lines: List = listOf() + + Row({ + width = grow() + height = derived { w -> + lines = font.split(title.text, w.toInt()) + (LINE_HEIGHT * lines.size).toFloat() + } + }) { + draw { + Renderable { guiGraphics, _, _, _ -> + guiGraphics.usePose { + for ((index, line) in lines.withIndex()) { + guiGraphics.drawCenteredString( + font, line, size.x / 2 + ) + translateXY(0, LINE_HEIGHT) + if (index != lines.size - 1) translateXY(0, PRG_OFFSET_OTHER) + } + } + } + } + } + } +} diff --git a/src/main/java/me/alegian/thavma/impl/client/gui/layout/LayoutExtensions.kt b/src/main/java/me/alegian/thavma/impl/client/gui/layout/LayoutExtensions.kt index 4855f0e0..c433a72d 100644 --- a/src/main/java/me/alegian/thavma/impl/client/gui/layout/LayoutExtensions.kt +++ b/src/main/java/me/alegian/thavma/impl/client/gui/layout/LayoutExtensions.kt @@ -4,7 +4,6 @@ import com.mojang.blaze3d.systems.RenderSystem import me.alegian.thavma.impl.client.texture.Texture import me.alegian.thavma.impl.client.util.blit import me.alegian.thavma.impl.client.util.drawString -import me.alegian.thavma.impl.client.util.transformOrigin import me.alegian.thavma.impl.client.util.translateXY import me.alegian.thavma.impl.client.util.usePose import me.alegian.thavma.impl.common.menu.slot.DynamicSlot @@ -41,13 +40,13 @@ private fun renderableTexture(texture: Texture) = Renderable { guiGraphics: GuiG } fun draw(getRenderable: T7LayoutElement.() -> Renderable) { - val screen = LayoutExtensions.currScreen ?: throw IllegalStateException("Thavma Exception: cannot add renderable without setting LayoutExtensions.currScreen first!") + val screen = LayoutExtensions.currScreen + ?: throw IllegalStateException("Thavma Exception: cannot add renderable without setting LayoutExtensions.currScreen first!") afterLayout { - val renderable = getRenderable() screen.renderables.add(Renderable { guiGraphics, mouseX, mouseY, partialTick -> guiGraphics.usePose { translateXY(position.x, position.y) - renderable.render(guiGraphics, mouseX, mouseY, partialTick) + getRenderable(this@afterLayout).render(guiGraphics, mouseX, mouseY, partialTick) } }) } @@ -62,6 +61,24 @@ fun TextureBox(texture: Texture, children: T7LayoutElement.() -> Unit) = children() } +fun CenteredTextureBox(texture: Texture) { + val screen = LayoutExtensions.currScreen + ?: throw IllegalStateException("Thavma Exception: cannot add renderable without setting LayoutExtensions.currScreen first!") + Row({ + width = fixed(texture.width) + height = fixed(texture.height) + }) { + afterLayout { + screen.renderables.add(Renderable { guiGraphics, mouseX, mouseY, partialTick -> + guiGraphics.usePose { + translateXY(position.x + (size.x - texture.width) / 2, position.y) + renderableTexture(texture).render(guiGraphics, mouseX, mouseY, partialTick) + } + }) + } + } +} + private fun T7LayoutElement.slotSetup(slot: Slot) { if (slot !is DynamicSlot<*>) return slot.actualX = position.x @@ -79,7 +96,14 @@ fun Slot(slot: Slot, texture: Texture? = null, slotSize: Int? = null) = afterLayout { slotSetup(slot) } } -fun Grid(rows: Int, columns: Int, elements: List, bgLayers: List = listOf(), gapSize: Int = 0, child: (T) -> Unit) = +fun Grid( + rows: Int, + columns: Int, + elements: List, + bgLayers: List = listOf(), + gapSize: Int = 0, + child: (T) -> Unit +) = Column({ gap = gapSize }) { for (layer in bgLayers) draw { renderableTexture(layer) } diff --git a/src/main/java/me/alegian/thavma/impl/client/texture/Texture.kt b/src/main/java/me/alegian/thavma/impl/client/texture/Texture.kt index dd6eb418..82f30752 100644 --- a/src/main/java/me/alegian/thavma/impl/client/texture/Texture.kt +++ b/src/main/java/me/alegian/thavma/impl/client/texture/Texture.kt @@ -1,5 +1,7 @@ package me.alegian.thavma.impl.client.texture +import com.mojang.serialization.Codec +import com.mojang.serialization.codecs.RecordCodecBuilder import me.alegian.thavma.impl.rl import net.minecraft.resources.ResourceLocation import net.minecraft.world.phys.Vec2 @@ -8,11 +10,29 @@ import net.minecraft.world.phys.Vec2 * Width and height refer to the useful part of the texture, not its entirety. * In practice many textures (like inventories) have huge empty spaces we don't care about */ -class Texture(val location: ResourceLocation, val width: Int, val height: Int, val canvasWidth: Int, val canvasHeight: Int) { +data class Texture( + val location: ResourceLocation, + val width: Int, + val height: Int, + val canvasWidth: Int, + val canvasHeight: Int +) { constructor(path: String, width: Int, height: Int) : this(rl("textures/$path.png"), width, height, width, height) constructor(path: String, width: Int, height: Int, canvasWidth: Int, canvasHeight: Int) : this(rl("textures/$path.png"), width, height, canvasWidth, canvasHeight) val size: Vec2 get() = Vec2(width.toFloat(), height.toFloat()) + + companion object { + val CODEC: Codec = RecordCodecBuilder.create { instance -> + instance.group( + ResourceLocation.CODEC.fieldOf("location").forGetter(Texture::location), + Codec.INT.fieldOf("width").forGetter(Texture::width), + Codec.INT.fieldOf("height").forGetter(Texture::height), + Codec.INT.fieldOf("canvas_width").forGetter(Texture::canvasWidth), + Codec.INT.fieldOf("canvas_height").forGetter(Texture::canvasHeight) + ).apply(instance, ::Texture) + } + } } diff --git a/src/main/java/me/alegian/thavma/impl/client/util/GuiGraphicsExtensions.kt b/src/main/java/me/alegian/thavma/impl/client/util/GuiGraphicsExtensions.kt index ed8fffed..08290a54 100644 --- a/src/main/java/me/alegian/thavma/impl/client/util/GuiGraphicsExtensions.kt +++ b/src/main/java/me/alegian/thavma/impl/client/util/GuiGraphicsExtensions.kt @@ -18,6 +18,10 @@ fun GuiGraphics.drawCenteredString(font: Font, text: Component, centerX: Float, drawString(font, text, (centerX - font.width(text) / 2f).toInt(), 0, color, false) } +fun GuiGraphics.drawCenteredString(font: Font, text: FormattedCharSequence, centerX: Float, color: Int = 0) { + drawString(font, text, (centerX - font.width(text) / 2f).toInt(), 0, color, false) +} + fun GuiGraphics.drawString(font: Font, text: Component, color: Int = 0) { drawString(font, text, 0, 0, color, false) } diff --git a/src/main/java/me/alegian/thavma/impl/common/book/FigureFeature.kt b/src/main/java/me/alegian/thavma/impl/common/book/FigureFeature.kt new file mode 100644 index 00000000..21c2224f --- /dev/null +++ b/src/main/java/me/alegian/thavma/impl/common/book/FigureFeature.kt @@ -0,0 +1,37 @@ +package me.alegian.thavma.impl.common.book + +import com.mojang.serialization.Codec +import com.mojang.serialization.codecs.RecordCodecBuilder +import me.alegian.thavma.impl.client.texture.Texture +import me.alegian.thavma.impl.init.registries.deferred.PageFeatureTypes +import net.minecraft.network.chat.Component +import net.minecraft.network.chat.ComponentSerialization +import java.util.* + +class FigureFeature( + val image: Texture, + val caption: Component?, + override val startsPage: Boolean = false, + override val forceIndex: Int = -1 +) : PageFeature { + override val type: PageFeatureType<*> + get() = PageFeatureTypes.FIGURE.get() + + val textureHeight = image.height + + companion object { + val CODEC = RecordCodecBuilder.mapCodec { builder -> + builder.group( + Texture.CODEC.fieldOf("image").forGetter(FigureFeature::image), + ComponentSerialization.CODEC.optionalFieldOf("caption").forGetter { p -> Optional.ofNullable(p.caption) }, + Codec.BOOL.optionalFieldOf("starts_page", false).forGetter(FigureFeature::startsPage), + Codec.INT.optionalFieldOf("force_index", -1).forGetter(FigureFeature::forceIndex) + ).apply(builder) { img, cap, start, index -> + FigureFeature(img, cap.orElse(Component.literal("")), start, index) + } + } + + fun translationId(baseId: String, featureIndex: Int) = "$baseId.figure_feature$featureIndex" + } + +} \ No newline at end of file diff --git a/src/main/java/me/alegian/thavma/impl/common/book/PageFeature.kt b/src/main/java/me/alegian/thavma/impl/common/book/PageFeature.kt new file mode 100644 index 00000000..2bc145a5 --- /dev/null +++ b/src/main/java/me/alegian/thavma/impl/common/book/PageFeature.kt @@ -0,0 +1,17 @@ +package me.alegian.thavma.impl.common.book + +import me.alegian.thavma.impl.init.registries.T7Registries + +interface PageFeature { + + val startsPage: Boolean + val forceIndex: Int? + get() = null + + val type: PageFeatureType<*> + + companion object { + val CODEC = + T7Registries.PAGE_FEATURE_TYPE.byNameCodec().dispatch({ pageFeature -> pageFeature.type }, { type -> type.codec }) + } +} diff --git a/src/main/java/me/alegian/thavma/impl/common/book/PageFeatureType.kt b/src/main/java/me/alegian/thavma/impl/common/book/PageFeatureType.kt new file mode 100644 index 00000000..83b3ca40 --- /dev/null +++ b/src/main/java/me/alegian/thavma/impl/common/book/PageFeatureType.kt @@ -0,0 +1,12 @@ +package me.alegian.thavma.impl.common.book + +import com.mojang.serialization.MapCodec +import net.minecraft.resources.ResourceLocation + +class PageFeatureType(name: ResourceLocation, val codec: MapCodec) { + val stringName = name.toString() + + override fun toString(): String { + return stringName + } +} \ No newline at end of file diff --git a/src/main/java/me/alegian/thavma/impl/common/book/ParagraphFeature.kt b/src/main/java/me/alegian/thavma/impl/common/book/ParagraphFeature.kt new file mode 100644 index 00000000..7958e191 --- /dev/null +++ b/src/main/java/me/alegian/thavma/impl/common/book/ParagraphFeature.kt @@ -0,0 +1,28 @@ +package me.alegian.thavma.impl.common.book + +import com.mojang.serialization.Codec +import com.mojang.serialization.codecs.RecordCodecBuilder +import me.alegian.thavma.impl.init.registries.deferred.PageFeatureTypes +import net.minecraft.network.chat.Component +import net.minecraft.network.chat.ComponentSerialization + +class ParagraphFeature( + val text: Component, + override val startsPage: Boolean = false, + override val forceIndex: Int = -1 +) : PageFeature { + override val type: PageFeatureType<*> + get() = PageFeatureTypes.PARAGRAPH.get() + + companion object { + val CODEC = RecordCodecBuilder.mapCodec { builder -> + builder.group( + ComponentSerialization.CODEC.fieldOf("text").forGetter(ParagraphFeature::text), + Codec.BOOL.optionalFieldOf("starts_page", false).forGetter(ParagraphFeature::startsPage), + Codec.INT.optionalFieldOf("force_index", -1).forGetter(ParagraphFeature::forceIndex) + ).apply(builder, ::ParagraphFeature) + } + + fun translationId(baseId: String, featureIndex: Int) = "$baseId.paragraph_feature$featureIndex" + } +} \ No newline at end of file diff --git a/src/main/java/me/alegian/thavma/impl/common/book/RecipeFeature.kt b/src/main/java/me/alegian/thavma/impl/common/book/RecipeFeature.kt new file mode 100644 index 00000000..23fb9908 --- /dev/null +++ b/src/main/java/me/alegian/thavma/impl/common/book/RecipeFeature.kt @@ -0,0 +1,25 @@ +package me.alegian.thavma.impl.common.book + +import com.mojang.serialization.Codec +import com.mojang.serialization.codecs.RecordCodecBuilder +import me.alegian.thavma.impl.init.registries.deferred.PageFeatureTypes +import net.minecraft.resources.ResourceLocation + +class RecipeFeature( + val recipeRL: ResourceLocation, override val startsPage: Boolean = true, override val forceIndex: Int = 1 +) : PageFeature { + override val type: PageFeatureType<*> + get() = PageFeatureTypes.RECIPE.get() + + companion object { + val CODEC = RecordCodecBuilder.mapCodec { builder -> + builder.group( + ResourceLocation.CODEC.fieldOf("recipeRL").forGetter(RecipeFeature::recipeRL), + Codec.BOOL.optionalFieldOf("starts_page", true).forGetter(RecipeFeature::startsPage), + Codec.INT.optionalFieldOf("force_index", 1).forGetter(RecipeFeature::forceIndex) + ).apply(builder, ::RecipeFeature) + } + + fun translationId(baseId: String, featureIndex: Int) = "$baseId.recipe_feature$featureIndex" + } +} \ No newline at end of file diff --git a/src/main/java/me/alegian/thavma/impl/common/book/TitleFeature.kt b/src/main/java/me/alegian/thavma/impl/common/book/TitleFeature.kt new file mode 100644 index 00000000..6bd19522 --- /dev/null +++ b/src/main/java/me/alegian/thavma/impl/common/book/TitleFeature.kt @@ -0,0 +1,25 @@ +package me.alegian.thavma.impl.common.book + +import com.mojang.serialization.Codec +import com.mojang.serialization.codecs.RecordCodecBuilder +import me.alegian.thavma.impl.init.registries.deferred.PageFeatureTypes +import net.minecraft.network.chat.Component +import net.minecraft.network.chat.ComponentSerialization + +class TitleFeature(val text: Component, override val startsPage: Boolean = true, override val forceIndex: Int = -1) : + PageFeature { + override val type: PageFeatureType<*> + get() = PageFeatureTypes.TITLE.get() + + companion object { + val CODEC = RecordCodecBuilder.mapCodec { builder -> + builder.group( + ComponentSerialization.CODEC.fieldOf("text").forGetter(TitleFeature::text), + Codec.BOOL.optionalFieldOf("starts_page", true).forGetter(TitleFeature::startsPage), + Codec.INT.optionalFieldOf("force_index", -1).forGetter(TitleFeature::forceIndex) + ).apply(builder, ::TitleFeature) + } + + fun translationId(baseId: String, featureIndex: Int) = "$baseId.title_feature$featureIndex" + } +} \ No newline at end of file diff --git a/src/main/java/me/alegian/thavma/impl/common/event/T7CommonModEvents.kt b/src/main/java/me/alegian/thavma/impl/common/event/T7CommonModEvents.kt index c8e153a9..48736e27 100644 --- a/src/main/java/me/alegian/thavma/impl/common/event/T7CommonModEvents.kt +++ b/src/main/java/me/alegian/thavma/impl/common/event/T7CommonModEvents.kt @@ -40,6 +40,7 @@ private fun registerRegistries(event: NewRegistryEvent) { event.register(T7Registries.WAND_CORE) event.register(T7Registries.ASPECT) event.register(T7Registries.PAGE_TYPE) + event.register(T7Registries.PAGE_FEATURE_TYPE) } private fun registerDatapackRegistries(event: DataPackRegistryEvent.NewRegistry) { diff --git a/src/main/java/me/alegian/thavma/impl/common/research/ResearchEntry.kt b/src/main/java/me/alegian/thavma/impl/common/research/ResearchEntry.kt index d069b396..612cff5e 100644 --- a/src/main/java/me/alegian/thavma/impl/common/research/ResearchEntry.kt +++ b/src/main/java/me/alegian/thavma/impl/common/research/ResearchEntry.kt @@ -3,7 +3,7 @@ package me.alegian.thavma.impl.common.research import com.mojang.serialization.Codec import com.mojang.serialization.codecs.RecordCodecBuilder import me.alegian.thavma.impl.Thavma -import me.alegian.thavma.impl.common.book.Page +import me.alegian.thavma.impl.common.book.PageFeature import me.alegian.thavma.impl.common.util.T7ExtraCodecs import me.alegian.thavma.impl.common.util.registry import me.alegian.thavma.impl.init.registries.T7DatapackRegistries @@ -24,7 +24,7 @@ class ResearchEntry( val position: Vector2i, val preferX: Boolean, val children: List>, - val pages: List, + val pageFeatures: List, val icon: ItemStack, val title: Component, val defaultResearchState: List, @@ -45,7 +45,7 @@ class ResearchEntry( Codec.BOOL.fieldOf("preferX").forGetter(ResearchEntry::preferX), RegistryFileCodec.create(T7DatapackRegistries.RESEARCH_ENTRY, CODEC).listOf().fieldOf("children") .forGetter(ResearchEntry::children), - Page.CODEC.listOf().fieldOf("pages").forGetter(ResearchEntry::pages), + PageFeature.CODEC.listOf().fieldOf("pageFeatures").forGetter(ResearchEntry::pageFeatures), ItemStack.STRICT_CODEC.fieldOf("icon").forGetter(ResearchEntry::icon), ComponentSerialization.CODEC.fieldOf("title").forGetter(ResearchEntry::title), SocketState.CODEC.listOf().fieldOf("defaultResearchState").forGetter(ResearchEntry::defaultResearchState), diff --git a/src/main/java/me/alegian/thavma/impl/init/data/providers/T7DatapackBuiltinEntriesProvider.kt b/src/main/java/me/alegian/thavma/impl/init/data/providers/T7DatapackBuiltinEntriesProvider.kt index a74a11a7..4393d743 100644 --- a/src/main/java/me/alegian/thavma/impl/init/data/providers/T7DatapackBuiltinEntriesProvider.kt +++ b/src/main/java/me/alegian/thavma/impl/init/data/providers/T7DatapackBuiltinEntriesProvider.kt @@ -1,16 +1,14 @@ package me.alegian.thavma.impl.init.data.providers import me.alegian.thavma.impl.Thavma +import me.alegian.thavma.impl.client.texture.Texture import me.alegian.thavma.impl.common.aspect.Aspect -import me.alegian.thavma.impl.common.book.CraftingPage -import me.alegian.thavma.impl.common.book.Page -import me.alegian.thavma.impl.common.book.TextPage +import me.alegian.thavma.impl.common.book.* import me.alegian.thavma.impl.common.enchantment.ShriekResistance.LOCATION import me.alegian.thavma.impl.common.research.ResearchCategory import me.alegian.thavma.impl.common.research.ResearchEntry import me.alegian.thavma.impl.common.research.SocketState import me.alegian.thavma.impl.common.util.Indices -import me.alegian.thavma.impl.init.data.Recipes import me.alegian.thavma.impl.init.data.worldgen.Node import me.alegian.thavma.impl.init.data.worldgen.ore.InfusedOre import me.alegian.thavma.impl.init.data.worldgen.ore.InfusedStoneOre @@ -33,6 +31,7 @@ import net.minecraft.data.PackOutput import net.minecraft.data.worldgen.BootstrapContext import net.minecraft.network.chat.Component import net.minecraft.resources.ResourceKey +import net.minecraft.resources.ResourceLocation import net.minecraft.tags.ItemTags import net.minecraft.world.entity.EquipmentSlotGroup import net.minecraft.world.item.ItemStack @@ -127,8 +126,6 @@ class T7DatapackBuiltinEntriesProvider(output: PackOutput, registries: Completab T7Items.BOOK.get().defaultInstance ) .research(lockedAspect(2, 0, Aspects.AETHER), lockedAspect(2, 4, Aspects.AETHER)) - .addPage(simpleTextPage(3, true)) - .addPage(simpleTextPage(1, false)) .addChild(ResearchEntries.Thavma.TREES) .addChild(ResearchEntries.Thavma.ORES) .defaultKnown() @@ -141,9 +138,26 @@ class T7DatapackBuiltinEntriesProvider(output: PackOutput, registries: Completab Items.TURTLE_HELMET.defaultInstance ) .research() - .addPage(simpleTextPage(2, true)) - .addPage(simpleTextPage(2, true)) - .addPage(simpleTextPage(2, true)) + .addPageFeature(makeTitleFeature()) + .addPageFeature(makeParagraphFeature(false)) + .addPageFeature(makeParagraphFeature()) + .addPageFeature( + makeFigureFeature( + Texture("gui/images/haybales", 180, 101, 180, 101), + true, + false, + 1, + ChatFormatting.DARK_AQUA, + ChatFormatting.ITALIC + ) + ) + .addPageFeature(makeTitleFeature()) + .addPageFeature(makeParagraphFeature(true)) + .addPageFeature(makeTitleFeature(true)) + .addPageFeature(makeTitleFeature(true, 0)) + .addPageFeature(makeParagraphFeature()) + .addPageFeature(makeFigureFeature(Texture("gui/images/smileyface", 87, 77, 87, 77), false, false, 2)) + .addPageFeature(makeParagraphFeature(false, 2)) .defaultKnown() .build(ctx) @@ -175,7 +189,6 @@ class T7DatapackBuiltinEntriesProvider(output: PackOutput, registries: Completab ) .research(lockedAspect(2, 0, Aspects.LUX), lockedAspect(2, 4, Aspects.AETHER), broken(2, 2)) .addChild(ResearchEntries.Thavma.RESEARCH_TABLE) - .addPage(simpleTextPage(3, true)) .build(ctx) ResearchEntryBuilder( @@ -185,7 +198,6 @@ class T7DatapackBuiltinEntriesProvider(output: PackOutput, registries: Completab T7Blocks.RESEARCH_TABLE.get().asItem().defaultInstance ) .research(lockedAspect(2, 0, Aspects.AETHER), lockedAspect(2, 4, Aspects.HERBA)) - .addPage { _, _ -> CraftingPage(Recipes.CHEST) } .addChild(ResearchEntries.Thavma.WANDS) .addChild(ResearchEntries.Thavma.TECHNOLOGY) .addChild(ResearchEntries.Thavma.ALCHEMY) @@ -261,7 +273,9 @@ private class ResearchEntryBuilder( private val icon: ItemStack ) { private val children = mutableListOf>() + private val pages = mutableListOf() + private val pageFeatures = mutableListOf() private val socketStates = mutableListOf() private var defaultKnown = false @@ -270,8 +284,8 @@ private class ResearchEntryBuilder( return this } - fun addPage(makePage: (ResourceKey, Int) -> Page): ResearchEntryBuilder { - pages.add(makePage(key, pages.size)) + inline fun addPageFeature(crossinline makeFeature: (ResourceKey, Int) -> T): ResearchEntryBuilder { + pageFeatures.add(makeFeature(key, pageFeatures.filterIsInstance().size)) return this } @@ -297,7 +311,7 @@ private class ResearchEntryBuilder( pos, preferX, childrenHolders, - pages, + pageFeatures, icon, Component.translatable(ResearchEntry.translationId(key)).withStyle(Rarity.UNCOMMON.styleModifier), socketStates, @@ -325,6 +339,87 @@ private fun simpleTextPage(paragraphCount: Int, hasTitle: Boolean): (ResourceKey } } +private fun makeParagraphFeature( + startsPage: Boolean = false, + forceIndex: Int = -1 +): (ResourceKey, Int) -> ParagraphFeature { + return { entryKey, paragraphIndex -> + val baseId = ResearchEntry.translationId(entryKey) + ParagraphFeature( + Component.translatable(ParagraphFeature.translationId(baseId, paragraphIndex)), + startsPage, forceIndex + ) + } +} + +private fun makeTitleFeature( + startsPage: Boolean = true, + forceIndex: Int = -1 +): (ResourceKey, Int) -> TitleFeature { + return { entryKey, titleIndex -> + val baseId = ResearchEntry.translationId(entryKey) + TitleFeature( + Component.translatable(TitleFeature.translationId(baseId, titleIndex)).withStyle(ChatFormatting.BOLD), + startsPage, forceIndex + ) + } +} + + +private fun makeFigureFeature( + image: Texture, + giveCaption: Boolean, + startsPage: Boolean = false, + forceIndex: Int = -1, + vararg styles: ChatFormatting? +): (ResourceKey, Int) -> FigureFeature { + return if (giveCaption) { entryKey, figureIndex -> + val baseId = ResearchEntry.translationId(entryKey) + val content = Component.translatable(FigureFeature.translationId(baseId, figureIndex)) + for (i in styles) { + content.apply { + if (i != null) { + this.withStyle(i) + } + } + } + FigureFeature(image, content, startsPage, forceIndex) + } else { _, _ -> + FigureFeature(image, null, startsPage, forceIndex) + } +} + +private fun makeRecipeFeature( + recipeRL: ResourceLocation, + startsPage: Boolean = true, + forceIndex: Int = 1 +): (ResourceKey, Int) -> RecipeFeature { + return { _, _ -> + RecipeFeature( + recipeRL, startsPage, forceIndex + ) + } +} + +private fun makeStyledParagraphFeature( + startsPage: Boolean = false, + forceIndex: Int = -1, + vararg styles: ChatFormatting? +): (ResourceKey, Int) -> ParagraphFeature { + return { entryKey, paragraphIndex -> + val baseId = ResearchEntry.translationId(entryKey) + val content = Component.translatable(ParagraphFeature.translationId(baseId, paragraphIndex)) + for (i in styles) { + content.apply { + if (i != null) { + this.withStyle(i) + } + } + } + ParagraphFeature(content, startsPage, forceIndex) + } +} + private fun simpleTitle(pageIndex: Int, baseId: String) = Component.translatable(TextPage.titleTranslationId(baseId, pageIndex)).withStyle(ChatFormatting.BOLD) diff --git a/src/main/java/me/alegian/thavma/impl/init/data/providers/T7LanguageProvider.kt b/src/main/java/me/alegian/thavma/impl/init/data/providers/T7LanguageProvider.kt index dcb04a86..629c2920 100644 --- a/src/main/java/me/alegian/thavma/impl/init/data/providers/T7LanguageProvider.kt +++ b/src/main/java/me/alegian/thavma/impl/init/data/providers/T7LanguageProvider.kt @@ -11,23 +11,14 @@ import me.alegian.thavma.impl.client.gui.tooltip.AspectClientTooltipComponent import me.alegian.thavma.impl.common.block.HungryChestBlock import me.alegian.thavma.impl.common.block.ResearchTableBlock import me.alegian.thavma.impl.common.block.WorkbenchBlock -import me.alegian.thavma.impl.common.book.TextPage +import me.alegian.thavma.impl.common.book.* import me.alegian.thavma.impl.common.recipe.translationId import me.alegian.thavma.impl.common.research.ResearchCategory import me.alegian.thavma.impl.common.research.ResearchEntry import me.alegian.thavma.impl.common.wand.WandCoreMaterial import me.alegian.thavma.impl.common.wand.WandPlatingMaterial import me.alegian.thavma.impl.init.registries.T7Tags -import me.alegian.thavma.impl.init.registries.deferred.Aspects -import me.alegian.thavma.impl.init.registries.deferred.T7Blocks -import me.alegian.thavma.impl.init.registries.deferred.T7Items -import me.alegian.thavma.impl.init.registries.deferred.T7EntityTypes -import me.alegian.thavma.impl.init.registries.deferred.ResearchEntries -import me.alegian.thavma.impl.init.registries.deferred.ResearchCategories -import me.alegian.thavma.impl.init.registries.deferred.T7Attributes -import me.alegian.thavma.impl.init.registries.deferred.T7RecipeTypes -import me.alegian.thavma.impl.init.registries.deferred.WandCoreMaterials -import me.alegian.thavma.impl.init.registries.deferred.WandPlatingMaterials +import me.alegian.thavma.impl.init.registries.deferred.* import me.alegian.thavma.impl.integration.RecipeViewerAliases import me.alegian.thavma.impl.integration.RecipeViewerDescriptions import net.minecraft.Util @@ -68,7 +59,7 @@ class T7LanguageProvider(output: PackOutput, locale: String) : LanguageProvider( add(T7Items.ORICHALCUM_NUGGET.get(), "Orichalcum Nugget") add(T7Items.RESEARCH_SCROLL.get(), "Research Scroll") add(T7Items.ARCANE_LENS.get(), "Arcane Lens") - add(T7Items.BOOK.get(), "Elements of Thavma") + add(T7Items.BOOK.get(), "Elements") add(T7Items.BASIC_AMULET.get(), "Basic Amulet") add(T7Items.BASIC_BELT.get(), "Basic Belt") @@ -207,25 +198,39 @@ class T7LanguageProvider(output: PackOutput, locale: String) : LanguageProvider( addCategory(ResearchCategories.STORY, "???") addEntry(ResearchEntries.Story.STORY1, "A Courtesy Call") - addTextPage( - ResearchEntries.Story.STORY1, 0, - "A Courtesy Call 1", - "Lorem ipsum %s 1 sit amet,", - "this story a great meaning haveth." + addPageFeature(TITLE, ResearchEntries.Story.STORY1, 0, "This title starts the page") + addPageFeature( + PARAGRAPH, + ResearchEntries.Story.STORY1, 0, """ + This is a short paragraph just to showcase that the feature exists. + """ ) - - addTextPage( - ResearchEntries.Story.STORY1, 1, - "A Courtesy Call 2", - "Lorem dolor 2 sit amet,", - "this story a great meaning haveth." + addPageFeature( + PARAGRAPH, + ResearchEntries.Story.STORY1, 1, """ + This is a longer paragraph to highlight the importance of splicing longer pieces of text over multiple pages. If you do not splice the paragraph to go over multiple pages, the text will spill out of the bottom of the screen and we don't want that to happen, hence DynamicRenderingHelper.kt. I will continue with some lorem ipsum. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque dapibus mattis lectus, quis aliquet ex. In hac habitasse platea dictumst. Praesent dignissim urna at feugiat pulvinar. Suspendisse laoreet lorem ut velit venenatis gravida. + Donec posuere diam est, ac malesuada libero fermentum sed. Phasellus ac cursus nibh, eget pharetra leo. Maecenas scelerisque velit massa, sit amet tincidunt nulla dictum non. Sed egestas congue bibendum. Aenean facilisis nunc vitae purus tincidunt, + sit amet dignissim libero gravida. Mauris vel tortor elit. Curabitur sit amet nisi sagittis, ullamcorper diam sed, condimentum est. Etiam blandit ac magna sit amet luctus. Duis nec mi tincidunt nunc. + """.trimIndent() ) - - addTextPage( - ResearchEntries.Story.STORY1, 2, - "A Courtesy Call 3", - "Lorem lotrumatum dolor 3 sit amet,", - "this story a great meaning haveth." + addPageFeature( + FIGURE, + ResearchEntries.Story.STORY1, 0, """ A short caption for the figure just to show the custom style """.trimIndent() + ) + addPageFeature(TITLE, ResearchEntries.Story.STORY1, 1, "This might appear in the middle") + addPageFeature( + PARAGRAPH, + ResearchEntries.Story.STORY1, 2, """ + This paragraph should start a new page always. + """.trimIndent() + ) + addPageFeature(TITLE, ResearchEntries.Story.STORY1, 2, "(start of page)") + addPageFeature(TITLE, ResearchEntries.Story.STORY1, 3, "This is page number 1!") + addPageFeature(PARAGRAPH, ResearchEntries.Story.STORY1, 3, "Just another random little paragraph :D") + addPageFeature( + PARAGRAPH, ResearchEntries.Story.STORY1, 4, """ + This paragraph has a pre-set page index of 2 + """.trimIndent() ) addTextPage( @@ -236,7 +241,7 @@ class T7LanguageProvider(output: PackOutput, locale: String) : LanguageProvider( flew into my hands! I can sense great power within it. """, """ - The cover reads "Elements of Thavma", but a lot of its pages appear blank, sealed by some magic. + The cover reads "Elements", but a lot of its pages appear blank, sealed by some magic. """, """ To read them, I will first need to break that seal. It won't be easy... but @@ -310,7 +315,7 @@ class T7LanguageProvider(output: PackOutput, locale: String) : LanguageProvider( ) add( RecipeViewerDescriptions.RESEARCH_SCROLL, - "Obtained by clicking any unknown entry in the \"Elements of Thavma\"" + "Obtained by clicking any unknown entry in the \"Elements\"" ) add(RecipeViewerAliases.BOOK, "Book") @@ -359,4 +364,22 @@ class T7LanguageProvider(output: PackOutput, locale: String) : LanguageProvider( paragraphs[parIndex].trimIndent().replace("\n", " ") ) } + + private fun addPageFeature(identifier: Char, entryKey: ResourceKey, featureIndex: Int, text: String) { + val baseId = ResearchEntry.translationId(entryKey) + when (identifier) { + 'P' -> add(ParagraphFeature.translationId(baseId, featureIndex), text.trimIndent().replace("\n", " ")) + 'T' -> add(TitleFeature.translationId(baseId, featureIndex), text.trimIndent().replace("\n", " ")) + 'F' -> add(FigureFeature.translationId(baseId, featureIndex), text.trimIndent().replace("\n", " ")) + 'R' -> add(RecipeFeature.translationId(baseId, featureIndex), text.trimIndent().replace("\n", " ")) + } + } + + companion object { + val PARAGRAPH = 'P' + val TITLE = 'T' + val FIGURE = 'F' + val RECIPE = 'R' + } + } diff --git a/src/main/java/me/alegian/thavma/impl/init/registries/T7Registries.kt b/src/main/java/me/alegian/thavma/impl/init/registries/T7Registries.kt index 74aac755..b13ad482 100644 --- a/src/main/java/me/alegian/thavma/impl/init/registries/T7Registries.kt +++ b/src/main/java/me/alegian/thavma/impl/init/registries/T7Registries.kt @@ -1,6 +1,7 @@ package me.alegian.thavma.impl.init.registries import me.alegian.thavma.impl.common.aspect.Aspect +import me.alegian.thavma.impl.common.book.PageFeatureType import me.alegian.thavma.impl.common.book.PageType import me.alegian.thavma.impl.common.wand.WandCoreMaterial import me.alegian.thavma.impl.common.wand.WandPlatingMaterial @@ -25,4 +26,8 @@ object T7Registries { val PAGE_TYPE = RegistryBuilder(ResourceKey.createRegistryKey>(rl("page_type"))) .maxId(Int.MAX_VALUE) .create() + + val PAGE_FEATURE_TYPE = RegistryBuilder(ResourceKey.createRegistryKey>(rl("page_feature_type"))) + .maxId(Int.MAX_VALUE) + .create() } diff --git a/src/main/java/me/alegian/thavma/impl/init/registries/deferred/PageFeatureTypes.kt b/src/main/java/me/alegian/thavma/impl/init/registries/deferred/PageFeatureTypes.kt new file mode 100644 index 00000000..01ddd273 --- /dev/null +++ b/src/main/java/me/alegian/thavma/impl/init/registries/deferred/PageFeatureTypes.kt @@ -0,0 +1,17 @@ +package me.alegian.thavma.impl.init.registries.deferred + +import me.alegian.thavma.impl.Thavma +import me.alegian.thavma.impl.common.book.* +import me.alegian.thavma.impl.init.registries.T7Registries +import me.alegian.thavma.impl.rl +import net.neoforged.neoforge.registries.DeferredRegister + +object PageFeatureTypes { + val REGISTRAR = DeferredRegister.create(T7Registries.PAGE_FEATURE_TYPE.key(), Thavma.MODID) + + val PARAGRAPH = + REGISTRAR.register("paragraph") { -> PageFeatureType(rl("paragraph"), ParagraphFeature.CODEC) } + val TITLE = REGISTRAR.register("title") { -> PageFeatureType(rl("title"), TitleFeature.CODEC) } + val FIGURE = REGISTRAR.register("figure") { -> PageFeatureType(rl("figure"), FigureFeature.CODEC) } + val RECIPE = REGISTRAR.register("recipe") { -> PageFeatureType(rl("recipe"), RecipeFeature.CODEC) } +} \ No newline at end of file diff --git a/src/main/resources/assets/thavma/textures/gui/images/haybales.png b/src/main/resources/assets/thavma/textures/gui/images/haybales.png new file mode 100644 index 00000000..a8e1cd2f Binary files /dev/null and b/src/main/resources/assets/thavma/textures/gui/images/haybales.png differ diff --git a/src/main/resources/assets/thavma/textures/gui/images/smileyface.png b/src/main/resources/assets/thavma/textures/gui/images/smileyface.png new file mode 100644 index 00000000..96ec3598 Binary files /dev/null and b/src/main/resources/assets/thavma/textures/gui/images/smileyface.png differ