diff --git a/src/generated/resources/assets/thavma/lang/en_us.json b/src/generated/resources/assets/thavma/lang/en_us.json index 802e4628..890d70ac 100644 --- a/src/generated/resources/assets/thavma/lang/en_us.json +++ b/src/generated/resources/assets/thavma/lang/en_us.json @@ -82,7 +82,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", @@ -162,25 +162,49 @@ "research.thavma.scroll_given": "You have received a research scroll", "research.thavma.toast": "Research Complete!", "research/category.thavma.alchemy": "Alchemy", + "research/category.thavma.story": "???", "research/category.thavma.thavma": "Thavma", "research/entry.thavma.alchemy.alchemy": "Alchemy", + "research/entry.thavma.story.story_test": "A Courtesy Call", + "research/entry.thavma.story.story_test.figure_feature0": "We're no strangers to love You know the rules and so do I A full commitment's what I'm thinking of You wouldn't get this from any other guy I just wanna tell you how I'm feeling Gotta make you understand Never gonna give you up Never gonna let you down Never gonna run around and desert you Never gonna make you cry Never gonna say goodbye Never gonna tell a lie and hurt you We've known each other for so long Your heart's been aching, but you're too shy to say it Inside, we both know what's been going on We know the game, and we're gonna play it And if you ask me how I'm feeling Don't tell me you're too blind to see Never gonna give you up Never gonna let you down Never gonna run around and desert you Never gonna make you cry Never gonna say goodbye Never gonna tell a lie and hurt you Never gonna give you up Never gonna let you down Never gonna run around and desert you Never gonna make you cry Never gonna say goodbye Never gonna tell a lie and hurt you Ooh (Give you up) Ooh-ooh (Give you up) Ooh (Never gonna give, never gonna give) Give you up Ooh-ooh (Never gonna give, never gonna give) Give you up We've known each other for so long Your heart's been aching, but you're too shy to say it Inside, we both know what's been going on We know the game, and we're gonna play it I just wanna tell you how I'm feeling Gotta make you understand Never gonna give you up Never gonna let you down Never gonna run around and desert you Never gonna make you cry Never gonna say goodbye Never gonna tell a lie and hurt you Never gonna give you up Never gonna let you down Never gonna run around and desert you Never gonna make you cry Never gonna say goodbye Never gonna tell a lie and hurt you Never gonna give you up Never gonna let you down Never gonna run around and desert you Never gonna make you cry Never gonna say goodbye Never gonna tell a lie and hurt you Never gonna give you up Never gonna let you down Never gonna run around and desert you Never gonna make you cry Never gonna say goodbye Never gonna tell a lie and hurt you", + "research/entry.thavma.story.story_test.page0.paragraph0": "Lorem ipsum %s 1 sit amet,", + "research/entry.thavma.story.story_test.page0.paragraph1": "this story a great meaning haveth.", + "research/entry.thavma.story.story_test.page0.title": "A Courtesy Call 1", + "research/entry.thavma.story.story_test.page1.paragraph0": "Lorem dolor 2 sit amet,", + "research/entry.thavma.story.story_test.page1.paragraph1": "this story a great meaning haveth.", + "research/entry.thavma.story.story_test.page1.paragraph2": "", + "research/entry.thavma.story.story_test.page1.title": "A Courtesy Call 2", + "research/entry.thavma.story.story_test.page2.paragraph0": "Lorem lotrumatum dolor 3 sit amet,", + "research/entry.thavma.story.story_test.page2.paragraph1": "this story a great meaning haveth.", + "research/entry.thavma.story.story_test.page2.title": "A Courtesy Call 3", + "research/entry.thavma.story.story_test.paragraph_feature0": "As fate would have it, this paragraph will probably not start a page because it does not have the mustStartPage flag set to true, which is actually rather a worrisome tragedy. Somebody had better do something about it soon.", + "research/entry.thavma.story.story_test.paragraph_feature1": "This is an experiment simply due to the fact that I am testing out double-trim-indent behaviour! If this fails and I am left to contemplate my existence in the bottomless abyss that my mind is, I will be making phone calls real fast real soon. (I got my Karen haircut done yesterday so while you mongrels crawl about, I will bee the queen out of every damn bastard who makes me think badly of me, myself included.)", + "research/entry.thavma.story.story_test.paragraph_feature2": "On the other hand, this paragraph should start a new page always. It has the mustStartPage property set to true :3", + "research/entry.thavma.story.story_test.paragraph_feature3": "Just another random little paragraph :D", + "research/entry.thavma.story.story_test.paragraph_feature4": "And BAM! smack that paragraph right in the middle without it being an image caption! (Both the image and this have a preferred page index set to 5 -> always page number 6)", + "research/entry.thavma.story.story_test.title_feature0": "A courtesy call starts the page", + "research/entry.thavma.story.story_test.title_feature1": "This title might appear in the middle", + "research/entry.thavma.story.story_test.title_feature2": "(start of page)", + "research/entry.thavma.story.story_test.title_feature3": "this is page number 1! Surprise! Even though this Title is added as the fourth one in the DataPackBuiltinEntriesProvider and LanguageProvider after a ton of paragraphs and titles and figures etc., it has a preferred page index 0!", + "research/entry.thavma.story.story_test2": "I will not be denied", + "research/entry.thavma.story.story_test2.paragraph_feature0": "When faced with setback, we must challenge our assumptions.", "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.", - "research/entry.thavma.thavma.arcane_lens.page0.paragraph1": "The blueprint describes a hexagonal device, much like a prism, made with those colorful crystals I found lying in a cave.", - "research/entry.thavma.thavma.arcane_lens.page0.paragraph2": "I should look at the world through its lens, maybe it will uncover something useful.", - "research/entry.thavma.thavma.arcane_lens.page0.title": "The Arcane Lens", + "research/entry.thavma.thavma.arcane_lens.paragraph_feature0": "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.", + "research/entry.thavma.thavma.arcane_lens.paragraph_feature1": "The blueprint describes a hexagonal device, much like a prism, made with those colorful crystals I found lying in a cave.", + "research/entry.thavma.thavma.arcane_lens.paragraph_feature2": "I should look at the world through its lens, maybe it will uncover something useful.", + "research/entry.thavma.thavma.arcane_lens.title_feature0": "The Arcane Lens", "research/entry.thavma.thavma.infusion": "Infusion", "research/entry.thavma.thavma.ores": "Ores", "research/entry.thavma.thavma.research_proficiency": "Research Proficiency", "research/entry.thavma.thavma.research_table": "Research Table", "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.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.", + "research/entry.thavma.thavma.thavma.paragraph_feature0": "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.paragraph_feature1": "The cover reads \"Elements\", but a lot of its pages appear blank, sealed by some magic.", + "research/entry.thavma.thavma.thavma.paragraph_feature2": "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.paragraph_feature3": "I will document all my findings inside the book, so that I can recall them later.", + "research/entry.thavma.thavma.thavma.title_feature0": "Thavma", "research/entry.thavma.thavma.trees": "Trees", "research/entry.thavma.thavma.wands": "Wands", "tag.block.thavma.crucible_heat_sources": "Crucible Block Heat Sources", diff --git a/src/generated/resources/data/thavma/thavma/research/category/story.json b/src/generated/resources/data/thavma/thavma/research/category/story.json new file mode 100644 index 00000000..26df1d1e --- /dev/null +++ b/src/generated/resources/data/thavma/thavma/research/category/story.json @@ -0,0 +1,10 @@ +{ + "icon": { + "count": 1, + "id": "minecraft:writable_book" + }, + "index": 2.0, + "title": { + "translate": "research/category.thavma.story" + } +} \ No newline at end of file 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/story_test.json b/src/generated/resources/data/thavma/thavma/research/entry/story/story_test.json new file mode 100644 index 00000000..c1e8e5b8 --- /dev/null +++ b/src/generated/resources/data/thavma/thavma/research/entry/story/story_test.json @@ -0,0 +1,116 @@ +{ + "category": "thavma:story", + "children": [ + "thavma:story/story_test2" + ], + "defaultKnown": true, + "defaultResearchState": [], + "icon": { + "count": 1, + "id": "minecraft:turtle_helmet" + }, + "pageFeatures": [ + { + "type": "thavma:title", + "starts_page": true, + "text": { + "bold": true, + "translate": "research/entry.thavma.story.story_test.title_feature0" + } + }, + { + "type": "thavma:paragraph", + "text": { + "translate": "research/entry.thavma.story.story_test.paragraph_feature0" + } + }, + { + "type": "thavma:paragraph", + "text": { + "translate": "research/entry.thavma.story.story_test.paragraph_feature1" + } + }, + { + "type": "thavma:figure", + "caption": { + "color": "dark_aqua", + "italic": true, + "translate": "research/entry.thavma.story.story_test.figure_feature0" + }, + "image": { + "canvas_height": 101, + "canvas_width": 180, + "height": 101, + "location": "thavma:textures/gui/images/important_image.png", + "width": 180 + } + }, + { + "type": "thavma:title", + "text": { + "bold": true, + "translate": "research/entry.thavma.story.story_test.title_feature1" + } + }, + { + "type": "thavma:paragraph", + "starts_page": true, + "text": { + "translate": "research/entry.thavma.story.story_test.paragraph_feature2" + } + }, + { + "type": "thavma:title", + "starts_page": true, + "text": { + "bold": true, + "translate": "research/entry.thavma.story.story_test.title_feature2" + } + }, + { + "type": "thavma:title", + "has_set_page": true, + "preferred_page": 0, + "starts_page": true, + "text": { + "bold": true, + "translate": "research/entry.thavma.story.story_test.title_feature3" + } + }, + { + "type": "thavma:paragraph", + "text": { + "translate": "research/entry.thavma.story.story_test.paragraph_feature3" + } + }, + { + "type": "thavma:figure", + "has_set_page": true, + "image": { + "canvas_height": 77, + "canvas_width": 87, + "height": 77, + "location": "thavma:textures/gui/images/important_image2.png", + "width": 87 + }, + "preferred_page": 5 + }, + { + "type": "thavma:paragraph", + "has_set_page": true, + "preferred_page": 5, + "text": { + "translate": "research/entry.thavma.story.story_test.paragraph_feature4" + } + } + ], + "position": [ + 0, + 0 + ], + "preferX": false, + "title": { + "color": "yellow", + "translate": "research/entry.thavma.story.story_test" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/thavma/thavma/research/entry/story/story_test2.json b/src/generated/resources/data/thavma/thavma/research/entry/story/story_test2.json new file mode 100644 index 00000000..7b12ea55 --- /dev/null +++ b/src/generated/resources/data/thavma/thavma/research/entry/story/story_test2.json @@ -0,0 +1,27 @@ +{ + "category": "thavma:story", + "children": [], + "defaultKnown": false, + "defaultResearchState": [], + "icon": { + "count": 1, + "id": "minecraft:fishing_rod" + }, + "pageFeatures": [ + { + "type": "thavma:paragraph", + "text": { + "translate": "research/entry.thavma.story.story_test2.paragraph_feature0" + } + } + ], + "position": [ + 0, + 3 + ], + "preferX": false, + "title": { + "color": "yellow", + "translate": "research/entry.thavma.story.story_test2" + } +} \ No newline at end of file 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..642ed273 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 @@ -1,7 +1,7 @@ { "category": "thavma:thavma", "children": [], - "defaultKnown": false, + "defaultKnown": true, "defaultResearchState": [ { "aspect": "thavma:aqua", @@ -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..97d93c82 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 @@ -3,7 +3,7 @@ "children": [ "thavma:thavma/research_table" ], - "defaultKnown": false, + "defaultKnown": true, "defaultResearchState": [ { "aspect": "thavma:lux", @@ -36,23 +36,31 @@ "count": 1, "id": "thavma:arcane_lens" }, - "pages": [ + "pageFeatures": [ { - "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": { + "type": "thavma:title", + "starts_page": true, + "text": { "bold": true, - "translate": "research/entry.thavma.thavma.arcane_lens.page0.title" + "translate": "research/entry.thavma.thavma.arcane_lens.title_feature0" + } + }, + { + "type": "thavma:paragraph", + "text": { + "translate": "research/entry.thavma.thavma.arcane_lens.paragraph_feature0" + } + }, + { + "type": "thavma:paragraph", + "text": { + "translate": "research/entry.thavma.thavma.arcane_lens.paragraph_feature1" + } + }, + { + "type": "thavma:paragraph", + "text": { + "translate": "research/entry.thavma.thavma.arcane_lens.paragraph_feature2" } } ], 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..04c01e92 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 @@ -1,7 +1,7 @@ { "category": "thavma:thavma", "children": [], - "defaultKnown": false, + "defaultKnown": true, "defaultResearchState": [ { "aspect": "thavma:terra", @@ -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..41a0ced4 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,12 +28,12 @@ "count": 1, "id": "thavma:aqua_shard" }, - "pages": [], + "pageFeatures": [], "position": [ 2, -4 ], - "preferX": false, + "preferX": true, "title": { "color": "yellow", "translate": "research/entry.thavma.thavma.ores" 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..652b2c49 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 @@ -1,7 +1,9 @@ { "category": "thavma:thavma", - "children": [], - "defaultKnown": false, + "children": [ + "thavma:thavma/research_table" + ], + "defaultKnown": true, "defaultResearchState": [ { "aspect": "thavma:aether", @@ -26,10 +28,10 @@ "count": 1, "id": "thavma:research_table" }, - "pages": [], + "pageFeatures": [], "position": [ - -1, - -1 + -2, + -2 ], "preferX": false, "title": { 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..cf612293 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 @@ -4,10 +4,9 @@ "thavma:thavma/wands", "thavma:thavma/technology", "thavma:thavma/alchemy", - "thavma:thavma/infusion", - "thavma:thavma/research_proficiency" + "thavma:thavma/infusion" ], - "defaultKnown": false, + "defaultKnown": true, "defaultResearchState": [ { "aspect": "thavma:aether", @@ -32,12 +31,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..e1db149b 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 @@ -1,7 +1,7 @@ { "category": "thavma:thavma", "children": [], - "defaultKnown": false, + "defaultKnown": true, "defaultResearchState": [ { "aspect": "thavma:instrumentum", @@ -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..2f9591fa 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,37 +29,44 @@ "count": 1, "id": "thavma:book" }, - "pages": [ + "pageFeatures": [ { - "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": { + "type": "thavma:title", + "starts_page": true, + "text": { "bold": true, - "translate": "research/entry.thavma.thavma.thavma.page0.title" + "translate": "research/entry.thavma.thavma.thavma.title_feature0" } }, { - "type": "thavma:text", - "paragraphs": [ - { - "translate": "research/entry.thavma.thavma.thavma.page1.paragraph0" - } - ] + "type": "thavma:paragraph", + "text": { + "translate": "research/entry.thavma.thavma.thavma.paragraph_feature0" + } + }, + { + "type": "thavma:paragraph", + "text": { + "translate": "research/entry.thavma.thavma.thavma.paragraph_feature1" + } + }, + { + "type": "thavma:paragraph", + "text": { + "translate": "research/entry.thavma.thavma.thavma.paragraph_feature2" + } + }, + { + "type": "thavma:paragraph", + "starts_page": true, + "text": { + "translate": "research/entry.thavma.thavma.thavma.paragraph_feature3" + } } ], "position": [ 0, - -6 + -5 ], "preferX": false, "title": { 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..267f2959 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 @@ -1,7 +1,7 @@ { "category": "thavma:thavma", "children": [ - "thavma:thavma/research_table" + "thavma:thavma/research_proficiency" ], "defaultKnown": false, "defaultResearchState": [ @@ -28,10 +28,10 @@ "count": 1, "id": "thavma:greatwood_log" }, - "pages": [], + "pageFeatures": [], "position": [ - 0, - -3 + -2, + -4 ], "preferX": false, "title": { 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..28fae594 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 @@ -1,7 +1,7 @@ { "category": "thavma:thavma", "children": [], - "defaultKnown": false, + "defaultKnown": true, "defaultResearchState": [ { "aspect": "thavma:aether", @@ -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/config/Config.kt b/src/main/java/me/alegian/thavma/config/Config.kt new file mode 100644 index 00000000..586fc3b8 --- /dev/null +++ b/src/main/java/me/alegian/thavma/config/Config.kt @@ -0,0 +1,22 @@ +package me.alegian.thavma.config + +import net.neoforged.neoforge.common.ModConfigSpec + +object Config { + private val BUILDER = ModConfigSpec.Builder() + + val SPEC: ModConfigSpec + var FONT_SIZE_MULTIPLIER: ModConfigSpec.DoubleValue + + + init { + BUILDER.push("general_settings") + + FONT_SIZE_MULTIPLIER = BUILDER + .comment("A number to multiply font size with") + .defineInRange("fontSizeMultiplier", 1.0, 0.1, 2.0) + + BUILDER.pop() + SPEC = BUILDER.build() + } +} \ No newline at end of file diff --git a/src/main/java/me/alegian/thavma/impl/Thavma.kt b/src/main/java/me/alegian/thavma/impl/Thavma.kt index b14253ac..b6f2f415 100644 --- a/src/main/java/me/alegian/thavma/impl/Thavma.kt +++ b/src/main/java/me/alegian/thavma/impl/Thavma.kt @@ -16,6 +16,8 @@ import thedarkcolour.kotlinforforge.neoforge.forge.MOD_BUS as KFF_MOD_BUS object Thavma { const val MODID: String = "thavma" + //modContainer.registerConfig(ModConfig.Type.COMMON, MyModConfig.SPEC) + init { T7ArmorMaterials.REGISTRAR.register(KFF_MOD_BUS) T7Blocks.REGISTRAR.register(KFF_MOD_BUS) @@ -36,6 +38,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..41254976 --- /dev/null +++ b/src/main/java/me/alegian/thavma/impl/client/event/RegisterPageFeatureRenderersEvent.kt @@ -0,0 +1,12 @@ +package me.alegian.thavma.impl.client.event + +import me.alegian.thavma.impl.client.gui.book.PageFeatureRenderer +import me.alegian.thavma.impl.common.book.PageFeature +import net.neoforged.bus.api.Event +import net.neoforged.fml.event.IModBusEvent + +class RegisterPageFeatureRenderersEvent: Event(), IModBusEvent { + fun register(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/RegisterPageRenderersEvent.kt b/src/main/java/me/alegian/thavma/impl/client/event/RegisterPageRenderersEvent.kt index 89591982..c3c90808 100644 --- a/src/main/java/me/alegian/thavma/impl/client/event/RegisterPageRenderersEvent.kt +++ b/src/main/java/me/alegian/thavma/impl/client/event/RegisterPageRenderersEvent.kt @@ -8,7 +8,8 @@ import net.neoforged.bus.api.Event import net.neoforged.fml.event.IModBusEvent class RegisterPageRenderersEvent : Event(), IModBusEvent { - fun register(pageType:PageType, pageRenderer: PageRenderer) { + fun register(pageType: PageType, pageRenderer: PageRenderer) { PAGE_RENDERERS[pageType] = pageRenderer + } } \ 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 35f385ad..6b391fa5 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 @@ -6,6 +6,7 @@ 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.DynamicFeaturesRenderer import me.alegian.thavma.impl.client.gui.book.TextPageRenderer import me.alegian.thavma.impl.client.gui.layer.ArcaneLensLayer import me.alegian.thavma.impl.client.gui.layer.WandLayer @@ -219,6 +220,10 @@ private fun registerPageRenderers(event: RegisterPageRenderersEvent) { event.register(PageTypes.CRAFTING.get(), CraftingPageRenderer) } +private fun registerPageFeatureRenderers(event: RegisterPageFeatureRenderersEvent){ + event.register(DynamicFeaturesRenderer) +} + private fun registerKeyMappings(event: RegisterKeyMappingsEvent) { event.register(T7KeyMappings.FOCI) } @@ -244,6 +249,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/BookScreen.kt b/src/main/java/me/alegian/thavma/impl/client/gui/book/BookScreen.kt index 6099f4bd..7f995315 100644 --- a/src/main/java/me/alegian/thavma/impl/client/gui/book/BookScreen.kt +++ b/src/main/java/me/alegian/thavma/impl/client/gui/book/BookScreen.kt @@ -1,7 +1,6 @@ package me.alegian.thavma.impl.client.gui.book import me.alegian.thavma.impl.client.clientRegistry -import me.alegian.thavma.impl.common.entity.knowsResearch import me.alegian.thavma.impl.common.research.ResearchCategory import me.alegian.thavma.impl.init.registries.T7DatapackRegistries import me.alegian.thavma.impl.init.registries.deferred.ResearchCategories @@ -22,29 +21,52 @@ class BookScreen : Screen(Component.literal("book")) { private var selectorOffset = 0 private val entryWidgets = mutableListOf() + private val entries = clientRegistry(T7DatapackRegistries.RESEARCH_ENTRY)?.holders()?.toList() + private var currentEntries = entries?.filter { it.value().category.value() == currentCategory } + var currentWidgets = entryWidgets.filter { entryWidget -> + currentEntries?.map { it.value() }?.contains(entryWidget.entry.value()) == true + } + override fun init() { super.init() val player = Minecraft.getInstance().player ?: return + println("the list of actual entries is") + println(entries) + println("the current category is $currentCategory") + + entryWidgets.clear() selectorOffset = cornerHeight + selectorGap val categoryRegistry = clientRegistry(T7DatapackRegistries.RESEARCH_CATEGORY) - currentCategory = categoryRegistry?.getOrThrow(ResearchCategories.THAVMA) - categoryRegistry?.forEach { - tabs[it] = addRenderableOnly(TabRenderable(this)) - } - clientRegistry(T7DatapackRegistries.RESEARCH_ENTRY)?.holders()?.forEach { - val tab = tabs[it.value().category.value()] - var shown = player.knowsResearch(it) - for (p in it.value().parents(player.level())) - if (player.knowsResearch(p)) shown = true - - if (tab != null && shown) - entryWidgets.add(addRenderableWidget(EntryWidget(this, tab, it))) + currentCategory = categoryRegistry?.getOrThrow(ResearchCategories.STORY) + currentEntries = entries?.filter { it.value().category.value() == currentCategory } + + println("and current entries are") + println(currentEntries) + categoryRegistry?.forEach { category -> + tabs[category] = addRenderableOnly( + TabRenderable( + this, + category, + entries?.filter { it.value().category.value() == category }, + player + ) + ) } + + // moved EntryWidget creation logic into TabRenderable.kt, here only adding them via + // the protected method addRenderableWidget + tabs.forEach { tab -> entryWidgets.addAll(tab.value.entryWidgets.map { addRenderableWidget(it) }) } + println("And the entry widgets added are") + println(entryWidgets) updateEntryWidgets() + currentWidgets = entryWidgets.filter { entryWidget -> + currentEntries?.map { it.value() }?.contains(entryWidget.entry.value()) == true + } + addRenderableOnly(FrameRenderable) clientRegistry(T7DatapackRegistries.RESEARCH_CATEGORY) ?.sortedBy { it.index } @@ -54,6 +76,10 @@ class BookScreen : Screen(Component.literal("book")) { private fun addSelectorWidget(category: ResearchCategory) { addRenderableWidget(TabSelectorWidget(0, selectorOffset, category) { currentCategory = category + currentEntries = entries?.filter { it.value().category.value() == currentCategory } + currentWidgets = entryWidgets.filter { entryWidget -> + currentEntries?.map { it.value() }?.contains(entryWidget.entry.value()) == true + } updateEntryWidgets() }) selectorOffset += TabSelectorWidget.TEXTURE.height + selectorGap @@ -68,6 +94,7 @@ class BookScreen : Screen(Component.literal("book")) { } override fun mouseDragged(mouseX: Double, mouseY: Double, button: Int, dragX: Double, dragY: Double): Boolean { + if (button != 0) { this.isScrolling = false return false diff --git a/src/main/java/me/alegian/thavma/impl/client/gui/book/DynamicFeaturesRenderer.kt b/src/main/java/me/alegian/thavma/impl/client/gui/book/DynamicFeaturesRenderer.kt new file mode 100644 index 00000000..9f6b8531 --- /dev/null +++ b/src/main/java/me/alegian/thavma/impl/client/gui/book/DynamicFeaturesRenderer.kt @@ -0,0 +1,166 @@ +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.drawString +import me.alegian.thavma.impl.client.util.translateXY +import me.alegian.thavma.impl.client.util.usePose +import me.alegian.thavma.impl.common.book.FigureFeature +import me.alegian.thavma.impl.common.book.FormattedTextFeature +import me.alegian.thavma.impl.common.book.PageFeature +import me.alegian.thavma.impl.common.book.ParagraphFeature +import me.alegian.thavma.impl.common.book.TitleFeature +import net.minecraft.client.Minecraft +import net.minecraft.client.gui.Font +import net.minecraft.util.Mth.ceil +import javax.sound.sampled.Line + +object DynamicFeaturesRenderer : PageFeatureRenderer { + private val SEPARATOR = Texture("gui/book/separator", 128, 16, 128, 16) + + override fun initPageFeatures( + screen: EntryScreen, + features: List, + maxWidth: Int, + font: Font, + scale: Float + ) { + + //val font = Minecraft.getInstance().font + val LINE_HEIGHT = ceil((font.lineHeight * scale + 2)) + + + Column({ + //println("size before setting initial column is $size") + size = grow() + gap = 4 + //println("size after initial column is $size") + }) { + for (feature in features) { + when (feature) { + is TitleFeature -> { + Title(feature, maxWidth, font, scale) + Separator() + } + + is FormattedTextFeature -> Row({ + //println("size before setting row of FormattedTextFeature is $size") + //size = grow() + width = grow() + //height = fixed(LINE_HEIGHT * feature.text.size + ceil(LINE_HEIGHT.toFloat() * (scale+1)) * 2f / 3) + height = fixed(LINE_HEIGHT * (feature.text.size + 0.5f)) + //println("size after FormattedTextFeature is $size") + }) { + relativeRenderable { guiGraphics, _, _, _ -> + //guiGraphics.pose().pushPose() + guiGraphics.pose().scale(scale, scale, 1.0f) + guiGraphics.usePose { + for (line in feature.text) { + //guiGraphics.drawString(feature.font, line) + guiGraphics.drawString(font, line) + //translateXY(0, feature.font.lineHeight) + translateXY(0, LINE_HEIGHT/scale) + } + //translateXY(0, feature.font.lineHeight * 2 / 3) + //guiGraphics.pose().popPose() + translateXY(0, LINE_HEIGHT * 2 / 3) + } + + } + } + + + is FigureFeature -> Image(feature, maxWidth) + + is ParagraphFeature -> Row({ + //println("size before setting row of FormattedTextFeature is $size") + //size = grow() + val lines = font.split(feature.text, (maxWidth / scale).toInt()) + width = grow() + //height = fixed(LINE_HEIGHT * lines.size + ceil(LINE_HEIGHT.toFloat() * (scale+1)) * 2f / 3) + height = fixed(LINE_HEIGHT * (lines.size + 0.5f)) + //println("size after FormattedTextFeature is $size") + }) { + relativeRenderable { guiGraphics, _, _, _ -> + //guiGraphics.pose().pushPose() + //val scale = 1f + guiGraphics.pose().scale(scale, scale, 1.0f) + guiGraphics.usePose { + for (line in font.split(feature.text, (maxWidth / scale).toInt())) { + //guiGraphics.drawString(feature.font, line) + guiGraphics.drawString(font, line) + //translateXY(0, feature.font.lineHeight) + translateXY(0, LINE_HEIGHT/scale) + } + //translateXY(0, feature.font.lineHeight * 2 / 3) + //guiGraphics.pose().popPose() + translateXY(0, LINE_HEIGHT * 2 / 3) + } + } + } + } + } + } + } + + + private fun Separator() { + Row({ + //println("width before setting row of SEPARATOR is $width") + width = grow() + //println("width after separator is $width") + alignMain = Alignment.CENTER + }) { + TextureBox(SEPARATOR) {} + } + } + + private fun Title(title: TitleFeature, maxWidth: Int, font: Font, scale: Float) { + val lines = font.split(title.text, (maxWidth / scale).toInt()) + + Row({ + //println("width before setting row of TitleFeature is $width") + width = grow() + //println("width after TitleFeature is $width") + height = fixed(ceil((font.lineHeight * scale + 2)) * lines.size) + }) { + relativeRenderable { guiGraphics, _, _, _ -> + guiGraphics.pose().scale(scale, scale, 1.0f) + guiGraphics.usePose { + for ((index, line) in lines.withIndex()) { + guiGraphics.drawCenteredString(font, line, size.x/scale / 2) + if (index != lines.size - 1) translateXY(0, ceil((font.lineHeight * scale + 2))/scale) + } + } + } + } + } + +// private fun Image(figure: FigureFeature, maxWidth: Int) { +// Row({ +// width = grow() +// height = fixed(figure.textureHeight) +// }) { +// relativeRenderable { guiGraphics, _, _, _ -> +// guiGraphics.usePose { +// translateXY((maxWidth - figure.image.width) / 2, 0) +// TextureBox(figure.image) {} +// } +// } +// } +// } +//} + + private fun Image(figure: FigureFeature, maxWidth: Int) { + Row({ + width = grow() + height = fixed(figure.textureHeight) + }) { + CenteredTextureBox(figure.image, maxWidth) {} + } + } +} + + + 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..8ca507cf --- /dev/null +++ b/src/main/java/me/alegian/thavma/impl/client/gui/book/DynamicRenderingHelper.kt @@ -0,0 +1,314 @@ +package me.alegian.thavma.impl.client.gui.book + +import me.alegian.thavma.config.Config +import me.alegian.thavma.impl.common.book.FigureFeature +import me.alegian.thavma.impl.common.book.FormattedTextFeature +import me.alegian.thavma.impl.common.book.PageFeature +import me.alegian.thavma.impl.common.book.ParagraphFeature +import me.alegian.thavma.impl.common.book.RecipeFeature +import me.alegian.thavma.impl.common.book.TitleFeature +import net.minecraft.client.gui.Font +import net.minecraft.util.Mth.ceil +import net.minecraft.util.Mth.floor +import kotlin.math.min + +private fun PageFeature.renderedHeight(pageWidth: Int, font: Font, scale: Float): Int { + val lineHeight = ceil((font.lineHeight * scale) + 2) + return when (this) { + is ParagraphFeature -> font.split(this.text, floor(pageWidth/scale)).size * lineHeight + is TitleFeature -> font.split(this.text, (pageWidth/scale).toInt()).size * lineHeight + 16 + is FigureFeature -> if (caption != null) font.split( + this.caption, + (pageWidth/scale).toInt() + ).size * lineHeight + this.textureHeight else this.textureHeight + is RecipeFeature -> 96 + is FormattedTextFeature -> text.size * lineHeight + else -> throw IllegalArgumentException("This PageFeature $this does not have renderedHeight() implemented yet") + } +} + +/** + * Return a list of PageFeatures containing a list of lines - FormattedCharSequence + * or possibly a Figure with just the image and its processed caption - FormattedCharSequence, + * so that they all fit on their + * respective pages (represented by list indices) + */ +fun spliceParagraphOrFigure( + input: PageFeature, maxPageHeight: Int, + currentHeight: Int, maxPageWidth: Int, font: Font, scale: Float +): List { + val result = mutableListOf() + println("maxHeight is $maxPageHeight, pageWidth is $maxPageWidth, processing page feature $input, current height is $currentHeight") + + if (input is ParagraphFeature) { + // how many lines fit in the current page + val lineHeight = ceil((font.lineHeight * scale + 2)) //* Config.FONT_SIZE_MULTIPLIER.get() + println("lineheight is $lineHeight") + + // so that we get at least 2 lines at the end of the first page + val linesRemainingAtStart: Int = (maxPageHeight - currentHeight) / lineHeight + println("lines remaining until end of page are $linesRemainingAtStart") + + + // so that we get at least 2 lines at the start of the last page + // (making use of rounding down when dividing integers) + val numOfLinesCoveringFullPages: Int = + (input.renderedHeight( + maxPageWidth, + font, + scale + ) - linesRemainingAtStart * lineHeight) / maxPageHeight * maxPageHeight / lineHeight + println("number of lines covering whole pages is $numOfLinesCoveringFullPages") + var linesCroppingOutAtEnd: Int = + (input.renderedHeight( + maxPageWidth, + font, + scale + ) - linesRemainingAtStart * lineHeight - numOfLinesCoveringFullPages * lineHeight) / lineHeight + if (linesCroppingOutAtEnd < 0) linesCroppingOutAtEnd = 0 + println("number of lines cropping out at end are $linesCroppingOutAtEnd") + val maxLinesPerPage = maxPageHeight / lineHeight + println("max lines per page is $maxLinesPerPage") + val numOfFullPagesCovered = numOfLinesCoveringFullPages / maxLinesPerPage + println("number of full pages is $numOfFullPagesCovered") + val lines = font.split(input.text, (maxPageWidth/scale).toInt()) + println("the text was split into this number of lines: ${lines.size}") + val realLinesRemaining: Int = min(linesRemainingAtStart, lines.size) + println("given the length of the text, this many lines are at the start: ${realLinesRemaining}") + + when { + lines.size <= linesRemainingAtStart && currentHeight + lineHeight * lines.size <= maxPageHeight -> result += FormattedTextFeature( + lines + ) + + linesRemainingAtStart != 1 && linesCroppingOutAtEnd != 1 -> { + // separate into "underhang", middle and overhang + val start = lines.slice(0 until realLinesRemaining) + result += FormattedTextFeature(start) + + for (i in 0 until numOfFullPagesCovered) { + val fullPage = + lines.slice(linesRemainingAtStart + i * maxLinesPerPage until linesRemainingAtStart + (i + 1) * maxLinesPerPage) + result += FormattedTextFeature(fullPage) + } + + val end = + lines.slice(lines.size - linesCroppingOutAtEnd until lines.size) + result += FormattedTextFeature(end) + } + + else -> { + // add an empty paragraph to current page and continue on the next + result += FormattedTextFeature(listOf()) + for (i in 0 until numOfFullPagesCovered) { + val fullPage = lines.slice(i * maxLinesPerPage until (i + 1) * maxLinesPerPage) + result += FormattedTextFeature(fullPage) + } + val finish = + lines.slice(numOfFullPagesCovered * maxLinesPerPage until lines.size) + result += FormattedTextFeature(finish) + } + } + return result + } + + if (input is FigureFeature) { + with(input) { + when { + caption == null && currentHeight + textureHeight <= maxPageHeight -> result += input + caption == null -> { + result += FormattedTextFeature(listOf()) + result += this + } + + currentHeight + textureHeight <= maxPageHeight -> { + //result += FigureFeature(image, null, input.mustStartPage, input.mustOccupySetPage, input.preferredPageIndex) + result += this + result.addAll( + spliceParagraphOrFigure( + ParagraphFeature(caption), + maxPageHeight, + currentHeight + textureHeight, + maxPageWidth, font, scale + ) + ) + } + + else -> { + result += FormattedTextFeature(listOf()) + //result += FigureFeature(image, null, input.mustStartPage, input.mustOccupySetPage, input.preferredPageIndex) + result += this + result.addAll( + spliceParagraphOrFigure( + ParagraphFeature(caption), + maxPageHeight, + textureHeight, + maxPageWidth, + font, + scale + ) + ) + } + } + } + return result + } + throw IllegalArgumentException("The supplied input $input is not a Paragraph or Figure") +} + +/** + * Returns a list of lists of features where every index represents a page. + * Features in the same list belong together on one page. + */ +fun pagifyFeatures(features: List, maxHeight: Int, pageWidth: Int, font: Font, scale: Float): List> { + println("maxHeight is $maxHeight, pageWidth is $pageWidth") + val partition = features.partition { !it.mustOccupySetPage } + val pages = mutableListOf>() + val buffer = mutableListOf() + fun currentHeight() = buffer.sumOf { it.renderedHeight(pageWidth, font, scale) } + fun submitBufferAndClear() { + pages.add(buffer.toList()) + println("===== Just submitted from buffer =====") + buffer.forEach { println(it) } + buffer.clear() + } + + println("The list of features contains:") + for (i in features) println(i) + println("Divided into partitions of length ${partition.first.size} and ${partition.second.size}") + println(partition.first) + println(partition.second) + + // deal with elements without predetermined order (bulk of the logic) + for (feature in partition.first) { + println("Processing feature $feature in initial pagifyFeatures(), current height ${currentHeight()}") + with(feature) { + when { + (this !is ParagraphFeature && this !is FigureFeature) && renderedHeight( + pageWidth, + font, + scale + ) > maxHeight -> throw IllegalArgumentException( + "The size of the element ${this::class.simpleName} is too large at ${ + renderedHeight( + pageWidth, + font, + scale + ) + } while allowed $maxHeight." + ) + + coversOneWholePage -> { + if (buffer.isNotEmpty()) submitBufferAndClear() + pages += listOf(this) + } + + mustStartPage -> { + if (buffer.isNotEmpty()) submitBufferAndClear() + if (this is ParagraphFeature || this is FigureFeature) { + println("Currently have this in the result: $pages") + val processed = spliceParagraphOrFigure(this, maxHeight, currentHeight(), pageWidth, font, scale) + if (processed.size < 2) buffer += processed.first() + // only need to check this much since buffer is empty (starts page) + else if (this is ParagraphFeature) { + processed.slice(0 until processed.size - 1).forEach { pages += listOf(it) } + buffer += processed.last() + } + // we are dealing with figure features now + else { + buffer += processed.first() + buffer += processed[1] + if (processed.size > 2) { + submitBufferAndClear() + for (j in 2 until processed.size - 1) { + pages += listOf(processed[j]) + } + buffer += processed.last() + } + } + } else buffer += this + } + + (this is ParagraphFeature || this is FigureFeature) -> { + val processed = spliceParagraphOrFigure(this, maxHeight, currentHeight(), pageWidth, font, scale) + if (processed.size < 2) buffer += processed.first() + else if (this is ParagraphFeature) { + buffer += processed.first() + submitBufferAndClear() + if (processed.size > 2) processed.slice(1 until processed.size - 1).forEach { pages += listOf(it) } + buffer += processed.last() + } else { + // we are dealing with figure features now + when { + // Size 1 is already taken care of above. The result is at least size 2. + // If the first thing in a processed Figure is a FormattedTextFeature, + // it's an empty one to signify end of page. Size 2 means + // there is only this emptiness + image. + processed.first() is FormattedTextFeature && processed.size == 2 -> { + submitBufferAndClear() + buffer += processed.last() + } + // Now there are either exactly 2 elements and the first one is an image + // that fits in the page and the second one is text, + // or there are more than 2 elements and they can be anything. + else -> { + var i = 0 + // address possible page break + if (processed.first() is FormattedTextFeature) { + submitBufferAndClear() + i++ + } + // always takes the image next + buffer += processed[i] + // the check whether the start of the caption fits in the page with the + // image is done by the Paragraph half of the function, so just add + // all that remains + buffer += processed[i + 1] + if (processed.size > 2 + i) { + submitBufferAndClear() + for (j in 2 + i until processed.size - 1) { + pages += listOf(processed[j]) + } + buffer += processed.last() + } + } + } + } + } + + currentHeight() + renderedHeight(pageWidth, font, scale) <= maxHeight -> buffer += this + // the next check might be redundant: + buffer.isEmpty() -> throw IllegalArgumentException( + "The size of the element ${this::class.simpleName} is too large at ${ + renderedHeight( + pageWidth, + font, + scale + ) + } while allowed $maxHeight." + ) + + else -> { + submitBufferAndClear() + buffer += this + } + } + } + } + + // add anything left over in the buffer + if (buffer.isNotEmpty()) submitBufferAndClear() + + println("current state of pages before adding predetermined stuff is") + for (i in pages) println(i) + + // finally add features with pre-determined positions (cannot be long paragraphs) + // these features have to be ordered correctly in the Research Entry builder + println("The grouping of the second partition is ${partition.second.groupBy { it.preferredPageIndex }}") + partition.second.groupBy { it.preferredPageIndex }.forEach { pages.add(it.key, it.value) } + + println("the final state of pages is") + for (i in pages) println(i) + + return pages +} \ No newline at end of file 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 72fbf7c7..b9245a1a 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 @@ -3,18 +3,30 @@ 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.Minecraft import net.minecraft.client.gui.GuiGraphics import net.minecraft.client.gui.screens.Screen import net.minecraft.core.Holder import net.minecraft.network.chat.Component +import net.minecraft.world.phys.Vec2 -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 val currentPage = 0 + private var currentPage = 0 + private val fontify = Minecraft.getInstance().font + + private var maxWidth = BG.width/2 - 65 + private var maxHeight = BG.height - 90 + + private val scale = 1.75f + + // maxHeight is height of background texture minus padding (32 top 42 bottom) + var pages = pagifyFeatures(entry.value().pageFeatures, maxHeight, maxWidth, fontify, scale) override fun init() { super.init() @@ -36,13 +48,50 @@ class EntryScreen(private val entry: Holder) : Screen(Component.l Row({ size = grow() }) { - initPage(entry.value().pages.getOrNull(currentPage)) + initPageFeatures(pages.getOrNull(currentPage)) + if (currentPage != 0) { + Box({ + width = fixed(PageTurningWidget.LEFT_TEXTURE.width) + height = fixed(PageTurningWidget.LEFT_TEXTURE.height) + }) { + afterLayout { + + //addRenderableWidget(PageTurningWidget(position, false) { + addRenderableWidget(PageTurningWidget(Vec2(position.x - maxWidth + 40, position.y + maxHeight + 30), false) { + // reinitiate the screen for this research entry when clicked + // with an updated page + // clearWidgets() is essential, also clears underline formatting! + currentPage -= 2 + clearWidgets() + init() + }) + } + } + } } Row({ size = grow() }) { - initPage(entry.value().pages.getOrNull(currentPage + 1)) + initPageFeatures(pages.getOrNull(currentPage + 1)) + if (pages.getOrNull(currentPage + 2) != null) { + Box({ + width = fixed(PageTurningWidget.RIGHT_TEXTURE.width) + height = fixed(PageTurningWidget.RIGHT_TEXTURE.height) + }) { + afterLayout { + + addRenderableWidget(PageTurningWidget(Vec2(position.x - 10, position.y + maxHeight + 30), true) { + // reinitiate the screen for this research entry when clicked + // with an updated page + // clearWidgets() is essential, also clears underline formatting! + currentPage += 2 + clearWidgets() + init() + }) + } + } + } } } } @@ -60,5 +109,12 @@ class EntryScreen(private val entry: Holder) : Screen(Component.l renderer.initPage(this, page) } + private fun initPageFeatures(features: List?) { + if (features != null) { + val renderer = DynamicFeaturesRenderer + renderer.initPageFeatures(this, features, maxWidth, fontify, scale) + } + } + override fun isPauseScreen() = false } \ No newline at end of file diff --git a/src/main/java/me/alegian/thavma/impl/client/gui/book/EntryWidget.kt b/src/main/java/me/alegian/thavma/impl/client/gui/book/EntryWidget.kt index 17b13116..4fa0a676 100644 --- a/src/main/java/me/alegian/thavma/impl/client/gui/book/EntryWidget.kt +++ b/src/main/java/me/alegian/thavma/impl/client/gui/book/EntryWidget.kt @@ -6,14 +6,10 @@ import me.alegian.thavma.impl.client.clientSound import me.alegian.thavma.impl.client.gui.tooltip.T7Tooltip import me.alegian.thavma.impl.client.pushScreen import me.alegian.thavma.impl.client.texture.Texture -import me.alegian.thavma.impl.client.util.resetRenderSystemColor -import me.alegian.thavma.impl.client.util.scaleXY -import me.alegian.thavma.impl.client.util.translateXY -import me.alegian.thavma.impl.client.util.usePose +import me.alegian.thavma.impl.client.util.* import me.alegian.thavma.impl.common.entity.knowsResearch import me.alegian.thavma.impl.common.payload.ResearchScrollPayload import me.alegian.thavma.impl.common.research.ResearchEntry -import me.alegian.thavma.impl.common.util.minus import net.minecraft.ChatFormatting import net.minecraft.client.gui.GuiGraphics import net.minecraft.client.gui.components.AbstractWidget @@ -24,14 +20,22 @@ import net.minecraft.core.Holder import net.minecraft.network.chat.Component import net.minecraft.sounds.SoundEvents import net.minecraft.sounds.SoundSource +import net.minecraft.world.entity.player.Player import net.neoforged.neoforge.network.PacketDistributor +import kotlin.math.abs +import kotlin.math.sin /** * By default, connections prefer to connect to children along the Y axis. * entry.preferX makes connections prefer the X axis. * Straight lines will ignore this preference */ -class EntryWidget(private val screen: BookScreen, val tab: TabRenderable, val entry: Holder) : +class EntryWidget( + private val screen: BookScreen, + val tab: TabRenderable, + val entry: Holder, + val player: Player +) : AbstractWidget(0, 0, CELL_SIZE, CELL_SIZE, entry.value().title) { private var gaveScroll = false val knowsResearch = @@ -45,18 +49,20 @@ class EntryWidget(private val screen: BookScreen, val tab: TabRenderable, val en init { val components = mutableListOf(entry.value().title) - if (!knowsParents) components.add(Component.translatable(ResearchEntry.PARENTS_UNKNOWN_TRANSLATION).withStyle(ChatFormatting.GRAY)) + if (!knowsParents) components.add( + Component.translatable(ResearchEntry.PARENTS_UNKNOWN_TRANSLATION).withStyle(ChatFormatting.GRAY) + ) tooltip = T7Tooltip(components) } private val pos = entry.value().position override fun getX(): Int { - return ((pos.x * CELL_SIZE - CELL_SIZE / 2 - tab.scrollX) / tab.zoomFactor() + screen.width / 2).toInt() + return ((pos.x * CELL_SIZE - CELL_SIZE / 2 - tab.scrollX / (300 / (tab.average * 1.5 + 10))) / tab.zoomFactor() + screen.width / 2).toInt() } override fun getY(): Int { - return ((pos.y * CELL_SIZE - CELL_SIZE / 2 - tab.scrollY) / tab.zoomFactor() + screen.height / 2).toInt() + return ((pos.y * CELL_SIZE - CELL_SIZE / 2 - tab.scrollY / (300 / (tab.average * 1.5 + 10))) / tab.zoomFactor() + screen.height / 2).toInt() } override fun getWidth(): Int { @@ -69,15 +75,22 @@ class EntryWidget(private val screen: BookScreen, val tab: TabRenderable, val en override fun renderWidget(guiGraphics: GuiGraphics, mouseX: Int, mouseY: Int, partialTick: Float) { this.isHovered = guiGraphics.containsPointInScissor(mouseX, mouseY) - && mouseX >= x - && mouseY >= y - && mouseX < x + getWidth() - && mouseY < y + getHeight() + && mouseX >= x + && mouseY >= y + && mouseX < x + getWidth() + && mouseY < y + getHeight() + + val corner = FrameRenderable.CORNER_TEXTURE + val edge = FrameRenderable.EDGE_TEXTURE + guiGraphics.enableCrop(corner.width / 2 + edge.height / 2, corner.height / 2 + edge.height / 2) guiGraphics.usePose { translateXY(screen.width / 2, screen.height / 2) scaleXY(1 / tab.zoomFactor()) - translateXY(-tab.scrollX, -tab.scrollY) + translateXY( + -tab.scrollX / (300 / (tab.average * 1.5 + 10)), + -tab.scrollY / (300 / (tab.average * 1.5 + 10)) + ) scaleXY(CELL_SIZE) translateXY(pos.x, pos.y) @@ -87,13 +100,17 @@ class EntryWidget(private val screen: BookScreen, val tab: TabRenderable, val en // allows negative size drawing, which greatly simplifies math RenderSystem.disableCull() for (child in children) { - val dv = child.value().position - pos + val dvx = child.value().position.x - pos.x + val dvy = child.value().position.y - pos.y + val knowsChild = ClientHelper.player()?.knowsResearch(child) ?: false guiGraphics.usePose { - renderConnectionRecursive(dv.x, dv.y, guiGraphics, child.value().preferX, false) + renderConnectionRecursive(dvx, dvy, guiGraphics, child.value().preferX, false, player, entry, knowsChild) } } + guiGraphics.flush() RenderSystem.enableCull() } + guiGraphics.disableCrop() } override fun onClick(mouseX: Double, mouseY: Double, button: Int) { @@ -101,7 +118,10 @@ class EntryWidget(private val screen: BookScreen, val tab: TabRenderable, val en PacketDistributor.sendToServer(ResearchScrollPayload(entry)) clientSound(SoundEvents.BOOK_PAGE_TURN, SoundSource.AMBIENT, 1f, 1f) gaveScroll = true - tooltip = T7Tooltip(entry.value().title, Component.translatable(ResearchEntry.SCROLL_GIVEN_TRANSLATION).withStyle(ChatFormatting.GRAY)) + tooltip = T7Tooltip( + entry.value().title, + Component.translatable(ResearchEntry.SCROLL_GIVEN_TRANSLATION).withStyle(ChatFormatting.GRAY) + ) return } if (knowsResearch) @@ -113,24 +133,32 @@ class EntryWidget(private val screen: BookScreen, val tab: TabRenderable, val en private fun renderEntry(guiGraphics: GuiGraphics) { var brightness = 1f - if (!knowsResearch) brightness = 0.4f - RenderSystem.setShaderColor(brightness, brightness, brightness, 1f) + var alpha = 1f + if (!knowsResearch) brightness = 0.55f + if (!knowsResearch) alpha = (abs(sin(player.level().gameTime / 8.0f)) / 4 * 3 + 0.25f) renderGridElement( guiGraphics, 1f, 1f, TEXTURE.location, - false + false, + player, + knowsResearch ) + RenderSystem.enableBlend() + RenderSystem.defaultBlendFunc() + guiGraphics.setColor(brightness, brightness, brightness, alpha) + guiGraphics.usePose { scaleXY(1f / CELL_SIZE) // back to pixel space scaleXY(2 * 0.7) // items are 16x, nodes are 32x, but we don't want full size guiGraphics.renderItem(entry.value().icon, -8, -8) } - resetRenderSystemColor() + guiGraphics.setColor(1f, 1f, 1f, 1f) + RenderSystem.disableBlend() } override fun playDownSound(handler: SoundManager) { diff --git a/src/main/java/me/alegian/thavma/impl/client/gui/book/GridHelper.kt b/src/main/java/me/alegian/thavma/impl/client/gui/book/GridHelper.kt index 72f50fcc..b2472ba9 100644 --- a/src/main/java/me/alegian/thavma/impl/client/gui/book/GridHelper.kt +++ b/src/main/java/me/alegian/thavma/impl/client/gui/book/GridHelper.kt @@ -1,15 +1,20 @@ package me.alegian.thavma.impl.client.gui.book +import com.mojang.blaze3d.systems.RenderSystem import com.mojang.blaze3d.vertex.PoseStack import com.mojang.math.Axis import me.alegian.thavma.impl.client.texture.Texture import me.alegian.thavma.impl.client.util.translateXY import me.alegian.thavma.impl.client.util.usePose +import me.alegian.thavma.impl.common.research.ResearchEntry import net.minecraft.client.gui.GuiGraphics +import net.minecraft.core.Holder import net.minecraft.resources.ResourceLocation +import net.minecraft.world.entity.player.Player import org.joml.Vector3f import kotlin.math.abs import kotlin.math.sign +import kotlin.math.sin val CELL_SIZE = EntryWidget.TEXTURE.width val ARROW_HEAD = Texture("gui/book/arrow_head", 32, 32) @@ -25,7 +30,16 @@ val CORNER_2X2 = Texture("gui/book/corner_2x2", 96, 96) * along x or y axis) * Uses recursion to draw long connections. */ -fun PoseStack.renderConnectionRecursive(dx: Int, dy: Int, guiGraphics: GuiGraphics, preferX: Boolean, invert: Boolean) { +fun PoseStack.renderConnectionRecursive( + dx: Int, + dy: Int, + guiGraphics: GuiGraphics, + preferX: Boolean, + invert: Boolean, + player: Player, + entry: Holder, + knowsChild: Boolean +) { val absDx = abs(dx) val absDy = abs(dy) val signX = dx.sign @@ -34,22 +48,22 @@ fun PoseStack.renderConnectionRecursive(dx: Int, dy: Int, guiGraphics: GuiGraphi val preference = if (preferX) -1f else 1f if (absDx + absDy <= 1f) return - else if (absDx > 2 && absDy > 2) throw IllegalStateException() + else if (absDx > 2 && absDy > 2) throw IllegalStateException("Yup the problem is here in GridHelper.kt") else if (!invert && (preferX && absDx > absDy && absDy > 0 || !preferX && absDy > absDx && absDx > 0)) { translateXY(dx, dy) - renderConnectionRecursive(-dx, -dy, guiGraphics, preferX, true) + renderConnectionRecursive(-dx, -dy, guiGraphics, preferX, true, player, entry, knowsChild) } else if (absDx == absDy) { translateXY(dx / 2f, dy / 2f) translateXY(preference * signX * inversion / 2f, -preference * signY * inversion / 2f) - renderCorner(guiGraphics, dx * inversion, dy * inversion, preferX) + renderCorner(guiGraphics, dx * inversion, dy * inversion, preferX, player, knowsChild) } else if (absDx > absDy) { translateXY(signX, 0) - renderLine(guiGraphics, signX * inversion, 1f, false) - renderConnectionRecursive(dx - signX, dy, guiGraphics, preferX, invert) + renderLine(guiGraphics, signX * inversion, 1f, false, player, knowsChild) + renderConnectionRecursive(dx - signX, dy, guiGraphics, preferX, invert, player, entry, knowsChild) } else { translateXY(0, signY) - renderLine(guiGraphics, 1f, signY * inversion, true) - renderConnectionRecursive(dx, dy - signY, guiGraphics, preferX, invert) + renderLine(guiGraphics, 1f, signY * inversion, true, player, knowsChild) + renderConnectionRecursive(dx, dy - signY, guiGraphics, preferX, invert, player, entry, knowsChild) } } @@ -58,20 +72,38 @@ fun PoseStack.renderConnectionRecursive(dx: Int, dy: Int, guiGraphics: GuiGraphi * Vertical lines are reflected horizontals. * Uses negative dimensions for orientation. */ -private fun renderLine(guiGraphics: GuiGraphics, signX: Float, signY: Float, vertical: Boolean) = +private fun renderLine( + guiGraphics: GuiGraphics, + signX: Float, + signY: Float, + vertical: Boolean, + player: Player, + knowsChild: Boolean +) { renderGridElement( guiGraphics, signX, signY, LINE.location, - vertical + vertical, + player, + knowsChild ) +} + /** * Only 2x2 and 1x1 corners are supported. Only one texture * is ever used. Uses negative dimensions & reflections for orientation. */ -private fun renderCorner(guiGraphics: GuiGraphics, dx: Float, dy: Float, reflect: Boolean) { +private fun renderCorner( + guiGraphics: GuiGraphics, + dx: Float, + dy: Float, + reflect: Boolean, + player: Player, + knowsChild: Boolean +) { val textureLoc = if (abs(dx) == 1f) CORNER_1X1.location else CORNER_2X2.location @@ -81,8 +113,11 @@ private fun renderCorner(guiGraphics: GuiGraphics, dx: Float, dy: Float, reflect dx, dy, textureLoc, - reflect + reflect, + player, + knowsChild ) + } /** @@ -92,11 +127,30 @@ private fun renderCorner(guiGraphics: GuiGraphics, dx: Float, dy: Float, reflect * The reflect param reflects the object across the y=x axis. * It supports negative size drawing, and adjusts the reflection axis accordingly */ -fun renderGridElement(graphics: GuiGraphics, width: Float, height: Float, textureLoc: ResourceLocation, reflect: Boolean) { +fun renderGridElement( + graphics: GuiGraphics, + width: Float, + height: Float, + textureLoc: ResourceLocation, + reflect: Boolean, + player: Player, + knowsResearch: Boolean +) { + var brightness = 1f + var alpha = 1f + if (!knowsResearch) brightness = 0.55f + if (!knowsResearch) alpha = (abs(sin(player.level().gameTime / 8.0f)) / 4 * 3 + 0.25f) + RenderSystem.enableBlend() + RenderSystem.defaultBlendFunc() + graphics.setColor(brightness, brightness, brightness, alpha) + graphics.usePose { if (reflect) mulPose(Axis.of(Vector3f(sign(width), sign(height), 0f)).rotationDegrees(180f)) scale(width, height, 1f) translateXY(-0.5f, -0.5f) graphics.blit(textureLoc, 0, 0, 0, 0f, 0f, 1, 1, 1, 1) } + + graphics.setColor(1f, 1f, 1f, 1f) + RenderSystem.disableBlend() } 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..15fdeccb --- /dev/null +++ b/src/main/java/me/alegian/thavma/impl/client/gui/book/PageFeatureRenderer.kt @@ -0,0 +1,8 @@ +package me.alegian.thavma.impl.client.gui.book + +import me.alegian.thavma.impl.common.book.PageFeature +import net.minecraft.client.gui.Font + +interface PageFeatureRenderer{ + fun initPageFeatures(screen: EntryScreen, features: List, maxWidth: Int, font: Font, scale: Float) +} \ No newline at end of file diff --git a/src/main/java/me/alegian/thavma/impl/client/gui/book/PageTurningWidget.kt b/src/main/java/me/alegian/thavma/impl/client/gui/book/PageTurningWidget.kt new file mode 100644 index 00000000..0128d77c --- /dev/null +++ b/src/main/java/me/alegian/thavma/impl/client/gui/book/PageTurningWidget.kt @@ -0,0 +1,61 @@ +package me.alegian.thavma.impl.client.gui.book + +import com.mojang.blaze3d.systems.RenderSystem +import me.alegian.thavma.impl.client.gui.research_table.ButtonWidget +import me.alegian.thavma.impl.client.gui.research_table.ButtonWidget.Companion.LEFT_TEXTURE +import me.alegian.thavma.impl.client.gui.research_table.ButtonWidget.Companion.leftTranslationId +import me.alegian.thavma.impl.client.gui.research_table.ButtonWidget.Companion.rightTranslationId +import me.alegian.thavma.impl.client.texture.Texture +import me.alegian.thavma.impl.client.util.blit +import me.alegian.thavma.impl.client.util.translateXY +import me.alegian.thavma.impl.client.util.usePose +import me.alegian.thavma.impl.common.block.ResearchTableBlock +import net.minecraft.client.gui.GuiGraphics +import net.minecraft.client.gui.components.AbstractWidget +import net.minecraft.client.gui.components.Tooltip +import net.minecraft.client.gui.narration.NarrationElementOutput +import net.minecraft.network.chat.Component +import net.minecraft.world.phys.Vec2 + +class PageTurningWidget(position: Vec2, private val invert: Boolean, private val handleClick: () -> Unit) : + AbstractWidget(position.x.toInt(), position.y.toInt(), LEFT_TEXTURE.width, LEFT_TEXTURE.height, Component.translatable(if (invert) rightTranslationId else leftTranslationId)) { + + init { + tooltip = Tooltip.create(message) + } + + + override fun renderWidget( + guiGraphics: GuiGraphics, + mouseX: Int, + mouseY: Int, + partialTick: Float + ) { + RenderSystem.disableCull() + guiGraphics.usePose { + translateXY(x, y) + val texture = if (invert) ButtonWidget.Companion.RIGHT_TEXTURE else ButtonWidget.Companion.LEFT_TEXTURE + guiGraphics.blit(texture) + } + RenderSystem.enableCull() + } + + override fun onClick(mouseX: Double, mouseY: Double, button: Int) { + //handleClick() + } + + override fun onRelease(mouseX: Double, mouseY: Double) { + handleClick() + } + + companion object { + val LEFT_TEXTURE = Texture("gui/research_table/left_button", 35, 12, 35, 12) + val RIGHT_TEXTURE = Texture("gui/research_table/right_button", 35, 12, 35, 12) + private val namespace = ".buttonWidget" + val leftTranslationId = ResearchTableBlock.CONTAINER_TITLE + namespace + ".left" + val rightTranslationId = ResearchTableBlock.CONTAINER_TITLE + namespace + ".right" + } + + override fun updateWidgetNarration(narrationElementOutput: NarrationElementOutput) { + } +} \ No newline at end of file diff --git a/src/main/java/me/alegian/thavma/impl/client/gui/book/TabRenderable.kt b/src/main/java/me/alegian/thavma/impl/client/gui/book/TabRenderable.kt index 674cda24..d7bd4bb2 100644 --- a/src/main/java/me/alegian/thavma/impl/client/gui/book/TabRenderable.kt +++ b/src/main/java/me/alegian/thavma/impl/client/gui/book/TabRenderable.kt @@ -2,30 +2,56 @@ package me.alegian.thavma.impl.client.gui.book import me.alegian.thavma.impl.client.texture.Texture import me.alegian.thavma.impl.client.util.* +import me.alegian.thavma.impl.common.entity.knowsResearch +import me.alegian.thavma.impl.common.research.ResearchCategory +import me.alegian.thavma.impl.common.research.ResearchEntry import net.minecraft.client.gui.GuiGraphics import net.minecraft.client.gui.components.Renderable +import net.minecraft.core.Holder +import net.minecraft.world.entity.player.Player import kotlin.math.pow // represents the renderable content of a tab in the book -class TabRenderable(val screen: BookScreen) : Renderable { - companion object{ +class TabRenderable( + val screen: BookScreen, + val category: ResearchCategory, + val entries: List>?, + val player: Player +) : Renderable { + companion object { private const val ZOOM_MULTIPLIER = 1.25 - private const val maxScrollX = 300.0 - private const val maxScrollY = 300.0 + const val maxScrollX = 600.0 + const val maxScrollY = 300.0 private const val minZoom = 0.0 private const val maxZoom = 5.0 val TEXTURE: Texture = Texture("gui/book/tab_bg", 512, 512) } + val entryWidgets = mutableListOf() + + init { + entries?.forEach { + var shown = player.knowsResearch(it) + for (p in it.value().parents(player.level())) + if (player.knowsResearch(p)) shown = true + if (shown) + entryWidgets.add(EntryWidget(screen, this, it, player)) + } + } + var scrollX = 0.0 private set var scrollY = 0.0 private set private var zoom = 2.0 // TODO: this is actually inverse zoom + val dimensionX = entryWidgets.maxOf { it.x } - entryWidgets.minOf { it.x } + val dimensionY = entryWidgets.maxOf { it.y } - entryWidgets.minOf { it.y } + val average = (dimensionY + dimensionX) / 2 + fun drag(x: Double, y: Double) { - val rawScrollX = scrollX - zoomFactor() * x - val rawScrollY = scrollY - zoomFactor() * y + val rawScrollX = scrollX - zoomFactor() * x * 1200 / (average * 10 + 50) + val rawScrollY = scrollY - zoomFactor() * y * 1200 / (average * 10 + 50) scrollX = rawScrollX.coerceIn(-maxScrollX, maxScrollX) scrollY = rawScrollY.coerceIn(-maxScrollY, maxScrollY) @@ -69,4 +95,4 @@ class TabRenderable(val screen: BookScreen) : Renderable { graphics.disableCrop() } -} \ No newline at end of file +} diff --git a/src/main/java/me/alegian/thavma/impl/client/gui/book/TextPageRenderer.kt b/src/main/java/me/alegian/thavma/impl/client/gui/book/TextPageRenderer.kt index 249277e8..43841f5f 100644 --- a/src/main/java/me/alegian/thavma/impl/client/gui/book/TextPageRenderer.kt +++ b/src/main/java/me/alegian/thavma/impl/client/gui/book/TextPageRenderer.kt @@ -7,8 +7,11 @@ 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.TextPage +import net.minecraft.ChatFormatting import net.minecraft.client.Minecraft import net.minecraft.network.chat.Component +import net.minecraft.network.chat.Style +import net.minecraft.util.FormattedCharSequence object TextPageRenderer : PageRenderer { private val SEPARATOR = Texture("gui/book/separator", 128, 16, 128, 16) @@ -31,11 +34,11 @@ object TextPageRenderer : PageRenderer { relativeRenderable { guiGraphics, _, _, _ -> guiGraphics.usePose { for (paragraph in page.paragraphs) { - for (line in font.split(paragraph, size.x.toInt())) { - guiGraphics.drawString(Minecraft.getInstance().font, line) + for (line in font.splitter.splitLines(paragraph, size.x.toInt(), Style.EMPTY)) { + guiGraphics.drawString(Minecraft.getInstance().font, Component.literal(line.string)) translateXY(0, LINE_HEIGHT) } - translateXY(0, LINE_HEIGHT) + translateXY(0, LINE_HEIGHT * 2 / 3) } } } 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 13425938..88591884 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 @@ -52,6 +52,19 @@ fun relativeRenderable(renderable: Renderable) { } } +fun relativeCenteredRenderable(renderable: Renderable, maxWidth: Int, texture: Texture) { + val screen = LayoutExtensions.currScreen ?: throw IllegalStateException("Thavma Exception: cannot add renderable without setting LayoutExtensions.currScreen first!") + afterLayout { + screen.renderables.add(Renderable { guiGraphics, mouseX, mouseY, partialTick -> + guiGraphics.usePose { + translateXY(position.x + (maxWidth - texture.width)/2, position.y) + renderable.render(guiGraphics, mouseX, mouseY, partialTick) + } + }) + } +} + + fun TextureBox(texture: Texture, children: T7LayoutElement.() -> Unit) = Row({ width = fixed(texture.width) @@ -61,6 +74,15 @@ fun TextureBox(texture: Texture, children: T7LayoutElement.() -> Unit) = children() } +fun CenteredTextureBox(texture: Texture, maxWidth: Int ,children: T7LayoutElement.() -> Unit) = + Row({ + width = fixed(texture.width) + height = fixed(texture.height) + }) { + relativeCenteredRenderable(renderableTexture(texture), maxWidth, texture) + children() + } + private fun T7LayoutElement.slotSetup(slot: Slot) { if (slot !is DynamicSlot<*>) return slot.actualX = position.x 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..ab0b28bd 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,36 @@ 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) + 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/DynamicPage.kt b/src/main/java/me/alegian/thavma/impl/common/book/DynamicPage.kt new file mode 100644 index 00000000..fecf0139 --- /dev/null +++ b/src/main/java/me/alegian/thavma/impl/common/book/DynamicPage.kt @@ -0,0 +1,22 @@ +package me.alegian.thavma.impl.common.book + +import com.mojang.serialization.codecs.RecordCodecBuilder +import me.alegian.thavma.impl.init.registries.deferred.PageTypes +import net.minecraft.network.chat.ComponentSerialization +import java.util.Optional + +class DynamicPage(val pageFeatures: List): Page { + // this might be a problem but for a future Tobias + override val type: PageType<*> + get() = PageTypes.TEXT.get() + + +// companion object { +// val CODEC = RecordCodecBuilder.mapCodec { builder -> +// builder.group( +// ComponentSerialization.CODEC.fieldOf("text").forGetter(ParagraphFeature::text) +// ).apply(builder, ::ParagraphFeature) +// } +// +// } +} \ No newline at end of file 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..ec5079ef --- /dev/null +++ b/src/main/java/me/alegian/thavma/impl/common/book/FigureFeature.kt @@ -0,0 +1,57 @@ +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 mustStartPage: Boolean = false, override val mustOccupySetPage: Boolean = false, override val preferredPageIndex: Int = 1) : PageFeature { + override val type: PageFeatureType<*> + get() = PageFeatureTypes.FIGURE.get() + + override val coversOneWholePage = false + + override fun toString(): String { + return "FigureFeature with caption $caption, mustOccupySetPage set to $mustOccupySetPage and preferred page index $preferredPageIndex" + } + + +// +// override val pageWidth: Int +// get() = 256 + + + //val font: Font = Minecraft.getInstance().font + + // if a recalibrated font size is used, I can multiply or divide by rendering scaling factor + //val LINE_HEIGHT = font.lineHeight + 2 + //val LINE_HEIGHT = 11 + + //val lines = if (caption != null) font.splitter.splitLines(caption, pageWidth - 25, Style.EMPTY) else listOf() + + val textureHeight = image.height + //val captionHeight = LINE_HEIGHT * lines.size + LINE_HEIGHT * 4 / 3 + + //val captionHeight = if (caption != null) LINE_HEIGHT * caption.string.length*5/115 + LINE_HEIGHT * 4 / 3 else 0 + //override val renderedHeight = textureHeight + captionHeight + + 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::mustStartPage), + Codec.BOOL.optionalFieldOf("has_set_page", false).forGetter(FigureFeature::mustOccupySetPage), + Codec.INT.optionalFieldOf("preferred_page", 1).forGetter(FigureFeature::preferredPageIndex) + ).apply(builder) { img, cap, start, index, pref -> + FigureFeature(img, cap.orElse(null), start, index, pref) + } + } + + 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/FormattedTextFeature.kt b/src/main/java/me/alegian/thavma/impl/common/book/FormattedTextFeature.kt new file mode 100644 index 00000000..8d263093 --- /dev/null +++ b/src/main/java/me/alegian/thavma/impl/common/book/FormattedTextFeature.kt @@ -0,0 +1,37 @@ +package me.alegian.thavma.impl.common.book + +import me.alegian.thavma.impl.init.registries.deferred.PageFeatureTypes +import net.minecraft.util.FormattedCharSequence + +/** + * Is only ever used in EntryScreen.kt to break ParagraphFeatures into segments + * so that they fit in their respective pages + */ + +class FormattedTextFeature(val text: List, val isTitle: Boolean = false) : PageFeature { + override val coversOneWholePage: Boolean + get() = false + override val mustStartPage: Boolean + get() = false + override val mustOccupySetPage: Boolean + get() = false + + override val type: PageFeatureType<*> + get() = PageFeatureTypes.PARAGRAPH.get() + + override fun toString(): String { + return "FormattedTextFeature with number of lines ${text.size}" + } + + //val font: Font = Minecraft.getInstance().font + //val DEFAULT_FONT = ResourceLocation.fromNamespaceAndPath("thavma","font:default.ttf") + //val x: Font? = null + + + // if a recalibrated font size is used, I can multiply or divide by rendering scaling factor + //val LINE_HEIGHT = font.lineHeight + 2 + //val LINE_HEIGHT = 11 + //val lines = font.splitter.splitLines(text, pageWidth - 25, Style.EMPTY) + + //override val renderedHeight = LINE_HEIGHT * text.size + LINE_HEIGHT * 2 / 3 +} \ 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..9255cd37 --- /dev/null +++ b/src/main/java/me/alegian/thavma/impl/common/book/PageFeature.kt @@ -0,0 +1,22 @@ +package me.alegian.thavma.impl.common.book + +import me.alegian.thavma.impl.init.registries.T7Registries + +interface PageFeature { + val coversOneWholePage: Boolean + val mustStartPage: Boolean + val mustOccupySetPage: Boolean + val preferredPageIndex: Int + get() = 1 + //val renderedHeight: Int + //val pageWidth: Int + //get() = 256 - 25 + + val type: PageFeatureType<*> + + companion object{ + val CODEC = T7Registries.PAGE_FEATURE_TYPE.byNameCodec().dispatch({ pageFeature -> pageFeature.type }, { type -> type.codec }) + + //fun translationId(baseId: String, featureIndex: Int) = "$baseId.page_feature$featureIndex" + } +} \ No newline at end of file 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..df95f3c4 --- /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..f554253d --- /dev/null +++ b/src/main/java/me/alegian/thavma/impl/common/book/ParagraphFeature.kt @@ -0,0 +1,47 @@ +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 mustStartPage: Boolean = false, override val mustOccupySetPage: Boolean = false, override val preferredPageIndex: Int = 1) : PageFeature { + override val type: PageFeatureType<*> + get() = PageFeatureTypes.PARAGRAPH.get() + + override val coversOneWholePage = false + + override fun toString(): String { + return "ParagraphFeature with text $text" + } + + //val font: Font = Minecraft.getInstance().font + + + // if a recalibrated font size is used, I can multiply or divide by rendering scaling factor + //val LINE_HEIGHT = font.lineHeight + 2 + //val LINE_HEIGHT = 11 + //val lines = font.splitter.splitLines(text, pageWidth, Style.EMPTY) + + //override val renderedHeight = LINE_HEIGHT * lines.size + LINE_HEIGHT * 2 / 3 + //override val renderedHeight = LINE_HEIGHT * text.string.length*5/115 + LINE_HEIGHT * 2 / 3 + + companion object { + val CODEC = RecordCodecBuilder.mapCodec { builder -> + builder.group( + ComponentSerialization.CODEC.fieldOf("text").forGetter(ParagraphFeature::text), + //ResourceLocation.CODEC.optionalFieldOf("font", ResourceLocation.withDefaultNamespace("default")).forGetter(ParagraphFeature::font), + Codec.BOOL.optionalFieldOf("starts_page", false).forGetter(ParagraphFeature::mustStartPage), + Codec.BOOL.optionalFieldOf("has_set_page", false).forGetter(ParagraphFeature::mustOccupySetPage), + Codec.INT.optionalFieldOf("preferred_page", 1).forGetter(ParagraphFeature::preferredPageIndex) + ).apply(builder, ::ParagraphFeature) + } + + fun translationId(baseId: String, featureIndex: Int) = "$baseId.paragraph_feature$featureIndex" + } + + //fun titleTranslationId(baseId: String, pageIndex: Int) = Page.translationId(baseId, pageIndex) + ".title" + //fun paragraphFeatureTranslationId(baseId: String, index: Int) = Page.translationId(baseId, pageIndex) + ".paragraph$index" + +} \ 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..d49e3297 --- /dev/null +++ b/src/main/java/me/alegian/thavma/impl/common/book/RecipeFeature.kt @@ -0,0 +1,32 @@ +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 coversOneWholePage: Boolean = true, override val mustStartPage: Boolean = true, override val mustOccupySetPage: Boolean = true, + override val preferredPageIndex: Int = 1) : PageFeature { + override val type: PageFeatureType<*> + get() = PageFeatureTypes.RECIPE.get() + + //val font: Font = Minecraft.getInstance().font + +// override val renderedHeight: Int +// get() = 96 + + companion object { + val CODEC = RecordCodecBuilder.mapCodec { builder -> + builder.group( + ResourceLocation.CODEC.fieldOf("recipeRL").forGetter(RecipeFeature::recipeRL), + Codec.BOOL.optionalFieldOf("covers_whole_page", true).forGetter(RecipeFeature::coversOneWholePage), + Codec.BOOL.optionalFieldOf("starts_page", true).forGetter(RecipeFeature::mustStartPage), + Codec.BOOL.optionalFieldOf("has_set_page", true).forGetter(RecipeFeature::mustOccupySetPage), + Codec.INT.optionalFieldOf("preferred_page", 1).forGetter(RecipeFeature::preferredPageIndex) + ).apply(builder, ::RecipeFeature) + } + + 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/TitleFeature.kt b/src/main/java/me/alegian/thavma/impl/common/book/TitleFeature.kt new file mode 100644 index 00000000..48eab757 --- /dev/null +++ b/src/main/java/me/alegian/thavma/impl/common/book/TitleFeature.kt @@ -0,0 +1,44 @@ +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 mustStartPage: Boolean = false, override val mustOccupySetPage: Boolean = false, + override val preferredPageIndex: Int = 1): PageFeature { + + override val type: PageFeatureType<*> + get() = PageFeatureTypes.TITLE.get() + + override val coversOneWholePage = false + + override fun toString(): String { + return "TitleFeature with text $text" + } + + + + //val font: Font = Minecraft.getInstance().font + // if a recalibrated font size is used, I can multiply or divide by rendering scaling factor + //val LINE_HEIGHT = font.lineHeight + 2 + //val LINE_HEIGHT = 11 + //val lines = font.splitter.splitLines(text, pageWidth, Style.EMPTY) + + //override val renderedHeight = LINE_HEIGHT * lines.size + 16 + //override val renderedHeight = 11 + 16 + + companion object { + val CODEC = RecordCodecBuilder.mapCodec { builder -> + builder.group( + ComponentSerialization.CODEC.fieldOf("text").forGetter(TitleFeature::text), + Codec.BOOL.optionalFieldOf("starts_page", false).forGetter(TitleFeature::mustStartPage), + Codec.BOOL.optionalFieldOf("has_set_page", false).forGetter(TitleFeature::mustOccupySetPage), + Codec.INT.optionalFieldOf("preferred_page", 1).forGetter(TitleFeature::preferredPageIndex) + ).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/OriginalCodeHolderCuzImLazy.kt b/src/main/java/me/alegian/thavma/impl/common/research/OriginalCodeHolderCuzImLazy.kt new file mode 100644 index 00000000..70297783 --- /dev/null +++ b/src/main/java/me/alegian/thavma/impl/common/research/OriginalCodeHolderCuzImLazy.kt @@ -0,0 +1,389 @@ +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.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.enchantment.ShriekResistance.LOCATION +import me.alegian.thavma.impl.common.util.Indices +import me.alegian.thavma.impl.common.util.T7ExtraCodecs +import me.alegian.thavma.impl.common.util.registry +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 +import me.alegian.thavma.impl.init.data.worldgen.spawn.AngryZombieSpawn +import me.alegian.thavma.impl.init.data.worldgen.tree.GreatwoodTree +import me.alegian.thavma.impl.init.data.worldgen.tree.SilverwoodTree +import me.alegian.thavma.impl.init.registries.T7DatapackRegistries +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.ResearchCategories +import me.alegian.thavma.impl.init.registries.deferred.ResearchEntries +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.WandCoreMaterials +import me.alegian.thavma.impl.init.registries.deferred.WandPlatingMaterials +import me.alegian.thavma.impl.init.registries.deferred.util.DeferredAspect +import net.minecraft.ChatFormatting +import net.minecraft.Util +import net.minecraft.advancements.critereon.DamageSourcePredicate +import net.minecraft.advancements.critereon.TagPredicate +import net.minecraft.core.Holder +import net.minecraft.core.HolderLookup +import net.minecraft.core.HolderSet +import net.minecraft.core.RegistrySetBuilder +import net.minecraft.core.component.DataComponentMap +import net.minecraft.core.registries.Registries +import net.minecraft.data.PackOutput +import net.minecraft.data.worldgen.BootstrapContext +import net.minecraft.network.chat.Component +import net.minecraft.network.chat.ComponentSerialization +import net.minecraft.resources.RegistryFileCodec +import net.minecraft.resources.ResourceKey +import net.minecraft.tags.ItemTags +import net.minecraft.world.entity.EquipmentSlotGroup +import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.Items +import net.minecraft.world.item.Rarity +import net.minecraft.world.item.enchantment.ConditionalEffect +import net.minecraft.world.item.enchantment.Enchantment +import net.minecraft.world.item.enchantment.Enchantment.Cost +import net.minecraft.world.item.enchantment.Enchantment.EnchantmentDefinition +import net.minecraft.world.item.enchantment.EnchantmentEffectComponents +import net.minecraft.world.item.enchantment.LevelBasedValue +import net.minecraft.world.item.enchantment.effects.AddValue +import net.minecraft.world.level.Level +import net.minecraft.world.level.storage.loot.predicates.DamageSourceCondition +import net.neoforged.neoforge.common.data.DatapackBuiltinEntriesProvider +import net.neoforged.neoforge.registries.NeoForgeRegistries +import org.joml.Vector2i +import java.util.Optional +import java.util.concurrent.CompletableFuture + +object OriginalCodeHolderCuzImLazy { + + +// 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.util.T7ExtraCodecs +// import me.alegian.thavma.impl.common.util.registry +// import me.alegian.thavma.impl.init.registries.T7DatapackRegistries +// import net.minecraft.Util +// import net.minecraft.core.Holder +// import net.minecraft.network.chat.Component +// import net.minecraft.network.chat.ComponentSerialization +// import net.minecraft.resources.RegistryFileCodec +// import net.minecraft.resources.ResourceKey +// import net.minecraft.world.item.ItemStack +// import net.minecraft.world.level.Level +// import org.joml.Vector2i +// +// private val parentsMap = mutableMapOf>>() +// +// class ResearchEntry( +// val category: Holder, +// val position: Vector2i, +// val preferX: Boolean, +// val children: List>, +// val pages: List, +// val icon: ItemStack, +// val title: Component, +// val defaultResearchState: List, +// val defaultKnown: Boolean +// ) { +// fun parents(level: Level) = +// parentsMap.computeIfAbsent(this) { _ -> +// val registry = level.registry(T7DatapackRegistries.RESEARCH_ENTRY) +// registry.holders().filter { e -> e.value().children.map{it.value()}.contains(this) }.toList() +// } +// +// companion object { +// val CODEC: Codec = RecordCodecBuilder.create { +// it.group( +// RegistryFileCodec.create(T7DatapackRegistries.RESEARCH_CATEGORY, ResearchCategory.CODEC).fieldOf("category").forGetter(ResearchEntry::category), +// T7ExtraCodecs.VECTOR2I.fieldOf("position").forGetter(ResearchEntry::position), +// 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), +// ItemStack.STRICT_CODEC.fieldOf("icon").forGetter(ResearchEntry::icon), +// ComponentSerialization.CODEC.fieldOf("title").forGetter(ResearchEntry::title), +// SocketState.CODEC.listOf().fieldOf("defaultResearchState").forGetter(ResearchEntry::defaultResearchState), +// Codec.BOOL.fieldOf("defaultKnown").forGetter(ResearchEntry::defaultKnown), +// ).apply(it, ::ResearchEntry) +// } +// +// fun translationId(entryKey: ResourceKey) = Util.makeDescriptionId(T7DatapackRegistries.RESEARCH_ENTRY.location().path, entryKey.location()) +// +// val TOAST_TRANSLATION = "research." + Thavma.MODID + ".toast" +// val SCROLL_GIVEN_TRANSLATION = "research." + Thavma.MODID + ".scroll_given" +// val PARENTS_UNKNOWN_TRANSLATION = "research." + Thavma.MODID + ".parents_unknown" +// } +// } + + + +// package me.alegian.thavma.impl.init.data.providers +// +// import me.alegian.thavma.impl.Thavma +// 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.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 +// import me.alegian.thavma.impl.init.data.worldgen.spawn.AngryZombieSpawn +// import me.alegian.thavma.impl.init.data.worldgen.tree.GreatwoodTree +// import me.alegian.thavma.impl.init.data.worldgen.tree.SilverwoodTree +// import me.alegian.thavma.impl.init.registries.T7DatapackRegistries +// import me.alegian.thavma.impl.init.registries.T7Tags +// import me.alegian.thavma.impl.init.registries.deferred.* +// import me.alegian.thavma.impl.init.registries.deferred.util.DeferredAspect +// import net.minecraft.ChatFormatting +// import net.minecraft.advancements.critereon.DamageSourcePredicate +// import net.minecraft.advancements.critereon.TagPredicate +// import net.minecraft.core.HolderLookup +// import net.minecraft.core.HolderSet +// import net.minecraft.core.RegistrySetBuilder +// import net.minecraft.core.component.DataComponentMap +// import net.minecraft.core.registries.Registries +// 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.tags.ItemTags +// import net.minecraft.world.entity.EquipmentSlotGroup +// import net.minecraft.world.item.ItemStack +// import net.minecraft.world.item.Items +// import net.minecraft.world.item.Rarity +// import net.minecraft.world.item.enchantment.ConditionalEffect +// import net.minecraft.world.item.enchantment.Enchantment +// import net.minecraft.world.item.enchantment.Enchantment.Cost +// import net.minecraft.world.item.enchantment.Enchantment.EnchantmentDefinition +// import net.minecraft.world.item.enchantment.EnchantmentEffectComponents +// import net.minecraft.world.item.enchantment.LevelBasedValue +// import net.minecraft.world.item.enchantment.effects.AddValue +// import net.minecraft.world.level.storage.loot.predicates.DamageSourceCondition +// import net.neoforged.neoforge.common.data.DatapackBuiltinEntriesProvider +// import net.neoforged.neoforge.registries.NeoForgeRegistries +// import org.joml.Vector2i +// import java.util.* +// import java.util.concurrent.CompletableFuture +// +// class T7DatapackBuiltinEntriesProvider(output: PackOutput, registries: CompletableFuture) : DatapackBuiltinEntriesProvider(output, registries, builder, setOf(Thavma.MODID)) { +// companion object { +// private val builder: RegistrySetBuilder = RegistrySetBuilder() +// .add(Registries.CONFIGURED_FEATURE) { ctx -> +// GreatwoodTree.registerConfigured(ctx) +// SilverwoodTree.registerConfigured(ctx) +// InfusedOre.registerConfigured(ctx) +// InfusedStoneOre.registerConfigured(ctx) +// Node.registerConfigured(ctx) +// } +// .add(Registries.PLACED_FEATURE) { ctx -> +// GreatwoodTree.registerPlaced(ctx) +// SilverwoodTree.registerPlaced(ctx) +// InfusedOre.registerPlaced(ctx) +// InfusedStoneOre.registerPlaced(ctx) +// Node.registerPlaced(ctx) +// } +// .add(NeoForgeRegistries.Keys.BIOME_MODIFIERS) { ctx -> +// GreatwoodTree.registerBiomeModifier(ctx) +// SilverwoodTree.registerBiomeModifier(ctx) +// InfusedStoneOre.registerBiomeModifier(ctx) +// AngryZombieSpawn.registerBiomeModifier(ctx) +// Node.registerBiomeModifier(ctx) +// } +// .add(Registries.ENCHANTMENT) { bootstrap -> +// val itemRegistry = bootstrap.lookup(Registries.ITEM) +// bootstrap.register( +// ResourceKey.create( +// Registries.ENCHANTMENT, +// LOCATION +// ), +// Enchantment( +// Component.literal("Shriek Resistance"), +// EnchantmentDefinition( +// itemRegistry.getOrThrow(ItemTags.ARMOR_ENCHANTABLE), +// Optional.empty(), +// 5, +// 4, +// Cost(10, 8), +// Cost(18, 8), +// 2, +// listOf(EquipmentSlotGroup.ARMOR) +// ), +// HolderSet.empty(), +// DataComponentMap.builder() +// .set( +// EnchantmentEffectComponents.DAMAGE_PROTECTION, listOf( +// ConditionalEffect( +// AddValue(LevelBasedValue.perLevel(2.0f)), +// Optional.of( +// DamageSourceCondition.hasDamageSource( +// DamageSourcePredicate.Builder.damageType().tag(TagPredicate.`is`(T7Tags.DamageTypes.SONIC)) +// ).build() +// ) +// ) +// ) +// ).build() +// ) +// ) +// } +// .add(T7DatapackRegistries.RESEARCH_CATEGORY) { ctx -> +// ctx.registerCategory(ResearchCategories.THAVMA, T7Items.BOOK.get().defaultInstance, 0f) +// ctx.registerCategory(ResearchCategories.ALCHEMY, T7Blocks.CRUCIBLE.get().asItem().defaultInstance, 1f) +// ctx.registerCategory(ResearchCategories.STORY, Items.WRITABLE_BOOK.defaultInstance, 2f) +// } +// .add(T7DatapackRegistries.RESEARCH_ENTRY) { ctx -> +// ResearchEntryBuilder(ResearchEntries.Thavma.THAVMA, Vector2i(0, -6), false, 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() +// .build(ctx) +// +// ResearchEntryBuilder(ResearchEntries.Story.TEST, Vector2i(0, -3), false, Items.TURTLE_HELMET.defaultInstance) +// .research() +// .addPage(simpleTextPage(2, true)) +// .addPage(simpleTextPage(2, true)) +// .addPage(simpleTextPage(2, true)) +// .defaultKnown() +// .build(ctx) +// +// ResearchEntryBuilder(ResearchEntries.Thavma.TREES, Vector2i(0, -3), false, T7Blocks.GREATWOOD_LOG.get().asItem().defaultInstance) +// .research(lockedAspect(2, 0, Aspects.HERBA), lockedAspect(2, 4, Aspects.HERBA)) +// .addChild(ResearchEntries.Thavma.RESEARCH_TABLE) +// .build(ctx) +// +// ResearchEntryBuilder(ResearchEntries.Thavma.ORES, Vector2i(2, -4), false, T7Items.SHARDS[Aspects.AQUA]!!.get().defaultInstance) +// .research(lockedAspect(2, 0, Aspects.TERRA), lockedAspect(2, 4, Aspects.AETHER)) +// .addChild(ResearchEntries.Thavma.ARCANE_LENS) +// .build(ctx) +// +// ResearchEntryBuilder(ResearchEntries.Thavma.ARCANE_LENS, Vector2i(2, -2), false, T7Items.ARCANE_LENS.get().defaultInstance) +// .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(ResearchEntries.Thavma.RESEARCH_TABLE, Vector2i(0, 0), true, 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) +// .addChild(ResearchEntries.Thavma.INFUSION) +// .addChild(ResearchEntries.Thavma.RESEARCH_PROFICIENCY) +// .build(ctx) +// +// ResearchEntryBuilder(ResearchEntries.Thavma.RESEARCH_PROFICIENCY, Vector2i(-1, -1), false, T7Blocks.RESEARCH_TABLE.get().asItem().defaultInstance) +// .research(lockedAspect(2, 0, Aspects.AETHER), lockedAspect(2, 4, Aspects.HERBA)) +// .build(ctx) +// +// ResearchEntryBuilder(ResearchEntries.Thavma.ALCHEMY, Vector2i(-2, 2), true, T7Blocks.CRUCIBLE.get().asItem().defaultInstance) +// .research(lockedAspect(2, 0, Aspects.AQUA), lockedAspect(2, 4, Aspects.ALKIMIA)) +// .build(ctx) +// +// ResearchEntryBuilder(ResearchEntries.Thavma.WANDS, Vector2i(-2, 4), true, T7Items.wandOrThrow(WandPlatingMaterials.THAVMITE.get(), WandCoreMaterials.SILVERWOOD.get()).defaultInstance) +// .research(lockedAspect(2, 0, Aspects.AETHER), lockedAspect(2, 4, Aspects.INSTRUMENTUM)) +// .build(ctx) +// +// ResearchEntryBuilder(ResearchEntries.Thavma.INFUSION, Vector2i(2, 2), true, T7Blocks.MATRIX.get().asItem().defaultInstance) +// .research(lockedAspect(2, 0, Aspects.TERRA), lockedAspect(2, 4, Aspects.AETHER)) +// .build(ctx) +// +// ResearchEntryBuilder(ResearchEntries.Thavma.TECHNOLOGY, Vector2i(2, 4), true, T7Items.GOGGLES.get().defaultInstance) +// .research(lockedAspect(2, 0, Aspects.INSTRUMENTUM), lockedAspect(2, 4, Aspects.CIVILIS)) +// .build(ctx) +// +// ResearchEntryBuilder(ResearchEntries.Alchemy.ALCHEMY, Vector2i(0, 0), false, T7Blocks.CRUCIBLE.get().asItem().defaultInstance) +// .research(lockedAspect(2, 0, Aspects.AQUA), lockedAspect(2, 4, Aspects.ALKIMIA)) +// .defaultKnown() +// .build(ctx) +// } +// } +// } +// +// private class ResearchEntryBuilder( +// private val key: ResourceKey, +// private val pos: Vector2i, +// private val preferX: Boolean, +// private val icon: ItemStack +// ) { +// private val children = mutableListOf>() +// private val pages = mutableListOf() +// private val socketStates = mutableListOf() +// private var defaultKnown = false +// +// fun addChild(entryKey: ResourceKey): ResearchEntryBuilder { +// children.add(entryKey) +// return this +// } +// +// fun addPage(makePage: (ResourceKey, Int) -> Page): ResearchEntryBuilder { +// pages.add(makePage(key, pages.size)) +// return this +// } +// +// fun research(vararg states: SocketState): ResearchEntryBuilder { +// socketStates.addAll(states) +// return this +// } +// +// fun defaultKnown(): ResearchEntryBuilder { +// defaultKnown = true +// return this +// } +// +// fun build(ctx: BootstrapContext) = ResearchEntries.CATEGORIES[key]?.let { cat -> +// val categoryRegistry = ctx.lookup(T7DatapackRegistries.RESEARCH_CATEGORY) +// val entryRegistry = ctx.lookup(T7DatapackRegistries.RESEARCH_ENTRY) +// val categoryHolder = categoryRegistry.getOrThrow(cat) +// val childrenHolders = children.map { entryRegistry.getOrThrow(it) } +// ctx.register(key, ResearchEntry(categoryHolder, pos, preferX, childrenHolders, pages, icon, Component.translatable(ResearchEntry.translationId(key)).withStyle(Rarity.UNCOMMON.styleModifier), socketStates, defaultKnown)) +// } +// } +// +// private fun BootstrapContext.registerCategory(key: ResourceKey, icon: ItemStack, sortIndex: Float) { +// register(key, ResearchCategory(Component.translatable(ResearchCategory.translationId(key)), sortIndex, icon)) +// } +// +// private fun simpleTextPage(paragraphCount: Int, hasTitle: Boolean): (ResourceKey, Int) -> Page { +// return { entryKey, pageIndex -> +// val baseId = ResearchEntry.translationId(entryKey) +// TextPage( +// if (hasTitle) simpleTitle(pageIndex, baseId) else null, +// simpleParagraphs(paragraphCount, pageIndex, baseId) +// ) +// } +// } +// +// private fun simpleTitle(pageIndex: Int, baseId: String) = +// Component.translatable(TextPage.titleTranslationId(baseId, pageIndex)).withStyle(ChatFormatting.BOLD) +// +// private fun simpleParagraphs(count: Int, pageIndex: Int, baseId: String) = List(count) { Component.translatable(TextPage.paragraphTranslationId(baseId, pageIndex, it)) } +// +// private fun lockedAspect(row: Int, col: Int, a: DeferredAspect) = SocketState(Indices(row, col), a.get(), false, true) +// private fun broken(row: Int, col: Int) = SocketState(Indices(row, col), null, true, true) + + + + +} \ No newline at end of file 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 e38fff18..324203e0 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,26 +24,32 @@ 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, val defaultKnown: Boolean ) { + override fun toString(): String { + return "Entry ${title.string} in ${this.category.value().title}" + } + fun parents(level: Level) = parentsMap.computeIfAbsent(this) { _ -> val registry = level.registry(T7DatapackRegistries.RESEARCH_ENTRY) - registry.holders().filter { e -> e.value().children.map{it.value()}.contains(this) }.toList() + registry.holders().filter { e -> e.value().children.map { it.value() }.contains(this) }.toList() } companion object { val CODEC: Codec = RecordCodecBuilder.create { it.group( - RegistryFileCodec.create(T7DatapackRegistries.RESEARCH_CATEGORY, ResearchCategory.CODEC).fieldOf("category").forGetter(ResearchEntry::category), + RegistryFileCodec.create(T7DatapackRegistries.RESEARCH_CATEGORY, ResearchCategory.CODEC).fieldOf("category") + .forGetter(ResearchEntry::category), T7ExtraCodecs.VECTOR2I.fieldOf("position").forGetter(ResearchEntry::position), 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), + RegistryFileCodec.create(T7DatapackRegistries.RESEARCH_ENTRY, CODEC).listOf().fieldOf("children") + .forGetter(ResearchEntry::children), + 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), @@ -51,7 +57,8 @@ class ResearchEntry( ).apply(it, ::ResearchEntry) } - fun translationId(entryKey: ResourceKey) = Util.makeDescriptionId(T7DatapackRegistries.RESEARCH_ENTRY.location().path, entryKey.location()) + fun translationId(entryKey: ResourceKey) = + Util.makeDescriptionId(T7DatapackRegistries.RESEARCH_ENTRY.location().path, entryKey.location()) val TOAST_TRANSLATION = "research." + Thavma.MODID + ".toast" val SCROLL_GIVEN_TRANSLATION = "research." + Thavma.MODID + ".scroll_given" 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 14da7e58..d21fc9b8 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,10 +1,9 @@ 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 @@ -33,9 +32,11 @@ 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 +import net.minecraft.world.item.Items import net.minecraft.world.item.Rarity import net.minecraft.world.item.enchantment.ConditionalEffect import net.minecraft.world.item.enchantment.Enchantment @@ -51,7 +52,8 @@ import org.joml.Vector2i import java.util.* import java.util.concurrent.CompletableFuture -class T7DatapackBuiltinEntriesProvider(output: PackOutput, registries: CompletableFuture) : DatapackBuiltinEntriesProvider(output, registries, builder, setOf(Thavma.MODID)) { +class T7DatapackBuiltinEntriesProvider(output: PackOutput, registries: CompletableFuture) : + DatapackBuiltinEntriesProvider(output, registries, builder, setOf(Thavma.MODID)) { companion object { private val builder: RegistrySetBuilder = RegistrySetBuilder() .add(Registries.CONFIGURED_FEATURE) { ctx -> @@ -114,64 +116,174 @@ class T7DatapackBuiltinEntriesProvider(output: PackOutput, registries: Completab .add(T7DatapackRegistries.RESEARCH_CATEGORY) { ctx -> ctx.registerCategory(ResearchCategories.THAVMA, T7Items.BOOK.get().defaultInstance, 0f) ctx.registerCategory(ResearchCategories.ALCHEMY, T7Blocks.CRUCIBLE.get().asItem().defaultInstance, 1f) + ctx.registerCategory(ResearchCategories.STORY, Items.WRITABLE_BOOK.defaultInstance, 2f) } .add(T7DatapackRegistries.RESEARCH_ENTRY) { ctx -> - ResearchEntryBuilder(ResearchEntries.Thavma.THAVMA, Vector2i(0, -6), false, T7Items.BOOK.get().defaultInstance) + + ResearchEntryBuilder(ResearchEntries.Story.TEST, Vector2i(0, 0), false, Items.TURTLE_HELMET.defaultInstance) + .research() + .addPageFeature(makeTitleFeature()) + .addPageFeature(makeParagraphFeature(false, false)) + .addPageFeature(makeParagraphFeature()) + .addPageFeature( + makeFigureFeature( + Texture("gui/images/important_image", 180, 101, 180, 101), + true, + false, + false, + 1, + ChatFormatting.DARK_AQUA, + ChatFormatting.ITALIC + ) + ) + .addPageFeature(makeTitleFeature(false)) + .addPageFeature(makeParagraphFeature(true)) + .addPageFeature(makeTitleFeature(true, false)) + .addPageFeature(makeTitleFeature(true, true, 0)) + .addPageFeature(makeParagraphFeature()) + .addPageFeature( + makeFigureFeature( + Texture("gui/images/important_image2", 87, 77, 87, 77), + false, + false, + true, + 5 + ) + ) + .addPageFeature(makeParagraphFeature(false, true, 5)) + .defaultKnown() + .addChild(ResearchEntries.Story.TEST2) + .build(ctx) + + ResearchEntryBuilder(ResearchEntries.Story.TEST2, Vector2i(0, 3), false, Items.FISHING_ROD.defaultInstance) + .research() + .addPageFeature(makeParagraphFeature()) + //.defaultKnown() + .build(ctx) + + ResearchEntryBuilder(ResearchEntries.Thavma.THAVMA, Vector2i(0, -5), false, T7Items.BOOK.get().defaultInstance) .research(lockedAspect(2, 0, Aspects.AETHER), lockedAspect(2, 4, Aspects.AETHER)) - .addPage(simpleTextPage(3, true)) - .addPage(simpleTextPage(1, false)) + .addPageFeature(makeTitleFeature()) + .addPageFeature(makeParagraphFeature()) + .addPageFeature(makeParagraphFeature()) + .addPageFeature(makeParagraphFeature()) + .addPageFeature(makeParagraphFeature(true)) + //.addPage(simpleTextPage(3, true)) + //.addPage(simpleTextPage(1, false)) .addChild(ResearchEntries.Thavma.TREES) .addChild(ResearchEntries.Thavma.ORES) .defaultKnown() .build(ctx) - ResearchEntryBuilder(ResearchEntries.Thavma.TREES, Vector2i(0, -3), false, T7Blocks.GREATWOOD_LOG.get().asItem().defaultInstance) + ResearchEntryBuilder( + ResearchEntries.Thavma.TREES, + Vector2i(-2, -4), + false, + T7Blocks.GREATWOOD_LOG.get().asItem().defaultInstance + ) .research(lockedAspect(2, 0, Aspects.HERBA), lockedAspect(2, 4, Aspects.HERBA)) - .addChild(ResearchEntries.Thavma.RESEARCH_TABLE) + .addChild(ResearchEntries.Thavma.RESEARCH_PROFICIENCY) .build(ctx) - ResearchEntryBuilder(ResearchEntries.Thavma.ORES, Vector2i(2, -4), false, T7Items.SHARDS[Aspects.AQUA]!!.get().defaultInstance) + ResearchEntryBuilder( + ResearchEntries.Thavma.ORES, + Vector2i(2, -4), + true, + T7Items.SHARDS[Aspects.AQUA]!!.get().defaultInstance + ) .research(lockedAspect(2, 0, Aspects.TERRA), lockedAspect(2, 4, Aspects.AETHER)) .addChild(ResearchEntries.Thavma.ARCANE_LENS) .build(ctx) - ResearchEntryBuilder(ResearchEntries.Thavma.ARCANE_LENS, Vector2i(2, -2), false, T7Items.ARCANE_LENS.get().defaultInstance) + ResearchEntryBuilder( + ResearchEntries.Thavma.ARCANE_LENS, + Vector2i(2, -2), + false, + T7Items.ARCANE_LENS.get().defaultInstance + ) .research(lockedAspect(2, 0, Aspects.LUX), lockedAspect(2, 4, Aspects.AETHER), broken(2, 2)) + .addPageFeature(makeTitleFeature()) + .addPageFeature(makeParagraphFeature()) + .addPageFeature(makeParagraphFeature()) + .addPageFeature(makeParagraphFeature()) + .defaultKnown() + //.addPage(simpleTextPage(3, true)) .addChild(ResearchEntries.Thavma.RESEARCH_TABLE) - .addPage(simpleTextPage(3, true)) .build(ctx) - ResearchEntryBuilder(ResearchEntries.Thavma.RESEARCH_TABLE, Vector2i(0, 0), true, T7Blocks.RESEARCH_TABLE.get().asItem().defaultInstance) + ResearchEntryBuilder( + ResearchEntries.Thavma.RESEARCH_TABLE, + Vector2i(0, 0), + true, + 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) .addChild(ResearchEntries.Thavma.INFUSION) - .addChild(ResearchEntries.Thavma.RESEARCH_PROFICIENCY) + //.addChild(ResearchEntries.Thavma.RESEARCH_PROFICIENCY) + .defaultKnown() .build(ctx) - ResearchEntryBuilder(ResearchEntries.Thavma.RESEARCH_PROFICIENCY, Vector2i(-1, -1), false, T7Blocks.RESEARCH_TABLE.get().asItem().defaultInstance) + ResearchEntryBuilder( + ResearchEntries.Thavma.RESEARCH_PROFICIENCY, + Vector2i(-2, -2), + false, + T7Blocks.RESEARCH_TABLE.get().asItem().defaultInstance + ) .research(lockedAspect(2, 0, Aspects.AETHER), lockedAspect(2, 4, Aspects.HERBA)) + .addChild(ResearchEntries.Thavma.RESEARCH_TABLE) + .defaultKnown() .build(ctx) - ResearchEntryBuilder(ResearchEntries.Thavma.ALCHEMY, Vector2i(-2, 2), true, T7Blocks.CRUCIBLE.get().asItem().defaultInstance) + ResearchEntryBuilder( + ResearchEntries.Thavma.ALCHEMY, + Vector2i(-2, 2), + true, + T7Blocks.CRUCIBLE.get().asItem().defaultInstance + ) .research(lockedAspect(2, 0, Aspects.AQUA), lockedAspect(2, 4, Aspects.ALKIMIA)) + .defaultKnown() .build(ctx) - ResearchEntryBuilder(ResearchEntries.Thavma.WANDS, Vector2i(-2, 4), true, T7Items.wandOrThrow(WandPlatingMaterials.THAVMITE.get(), WandCoreMaterials.SILVERWOOD.get()).defaultInstance) + ResearchEntryBuilder( + ResearchEntries.Thavma.WANDS, + Vector2i(-2, 4), + true, + T7Items.wandOrThrow(WandPlatingMaterials.THAVMITE.get(), WandCoreMaterials.SILVERWOOD.get()).defaultInstance + ) .research(lockedAspect(2, 0, Aspects.AETHER), lockedAspect(2, 4, Aspects.INSTRUMENTUM)) + .defaultKnown() .build(ctx) - ResearchEntryBuilder(ResearchEntries.Thavma.INFUSION, Vector2i(2, 2), true, T7Blocks.MATRIX.get().asItem().defaultInstance) + ResearchEntryBuilder( + ResearchEntries.Thavma.INFUSION, + Vector2i(2, 2), + true, + T7Blocks.MATRIX.get().asItem().defaultInstance + ) .research(lockedAspect(2, 0, Aspects.TERRA), lockedAspect(2, 4, Aspects.AETHER)) + .defaultKnown() .build(ctx) - ResearchEntryBuilder(ResearchEntries.Thavma.TECHNOLOGY, Vector2i(2, 4), true, T7Items.GOGGLES.get().defaultInstance) + ResearchEntryBuilder( + ResearchEntries.Thavma.TECHNOLOGY, + Vector2i(2, 4), + true, + T7Items.GOGGLES.get().defaultInstance + ) .research(lockedAspect(2, 0, Aspects.INSTRUMENTUM), lockedAspect(2, 4, Aspects.CIVILIS)) + .defaultKnown() .build(ctx) - ResearchEntryBuilder(ResearchEntries.Alchemy.ALCHEMY, Vector2i(0, 0), false, T7Blocks.CRUCIBLE.get().asItem().defaultInstance) + ResearchEntryBuilder( + ResearchEntries.Alchemy.ALCHEMY, + Vector2i(0, 0), + false, + T7Blocks.CRUCIBLE.get().asItem().defaultInstance + ) .research(lockedAspect(2, 0, Aspects.AQUA), lockedAspect(2, 4, Aspects.ALKIMIA)) .defaultKnown() .build(ctx) @@ -186,6 +298,7 @@ private class ResearchEntryBuilder( private val icon: ItemStack ) { private val children = mutableListOf>() + private val pageFeatures = mutableListOf() private val pages = mutableListOf() private val socketStates = mutableListOf() private var defaultKnown = false @@ -200,6 +313,11 @@ private class ResearchEntryBuilder( return this } + inline fun addPageFeature(crossinline makeFeature: (ResourceKey, Int) -> T): ResearchEntryBuilder { + pageFeatures.add(makeFeature(key, pageFeatures.filterIsInstance().size)) + return this + } + fun research(vararg states: SocketState): ResearchEntryBuilder { socketStates.addAll(states) return this @@ -215,11 +333,28 @@ private class ResearchEntryBuilder( val entryRegistry = ctx.lookup(T7DatapackRegistries.RESEARCH_ENTRY) val categoryHolder = categoryRegistry.getOrThrow(cat) val childrenHolders = children.map { entryRegistry.getOrThrow(it) } - ctx.register(key, ResearchEntry(categoryHolder, pos, preferX, childrenHolders, pages, icon, Component.translatable(ResearchEntry.translationId(key)).withStyle(Rarity.UNCOMMON.styleModifier), socketStates, defaultKnown)) + ctx.register( + key, + ResearchEntry( + categoryHolder, + pos, + preferX, + childrenHolders, + pageFeatures, + icon, + Component.translatable(ResearchEntry.translationId(key)).withStyle(Rarity.UNCOMMON.styleModifier), + socketStates, + defaultKnown + ) + ) } } -private fun BootstrapContext.registerCategory(key: ResourceKey, icon: ItemStack, sortIndex: Float) { +private fun BootstrapContext.registerCategory( + key: ResourceKey, + icon: ItemStack, + sortIndex: Float +) { register(key, ResearchCategory(Component.translatable(ResearchCategory.translationId(key)), sortIndex, icon)) } @@ -233,10 +368,100 @@ private fun simpleTextPage(paragraphCount: Int, hasTitle: Boolean): (ResourceKey } } +private fun makeParagraphFeature( + mustStartPage: Boolean = false, + mustOccupySetPage: Boolean = false, + preferredPageIndex: Int = 1 +): (ResourceKey, Int) -> ParagraphFeature { + return { entryKey, paragraphIndex -> + val baseId = ResearchEntry.translationId(entryKey) + ParagraphFeature( + Component.translatable(ParagraphFeature.translationId(baseId, paragraphIndex)), + mustStartPage, mustOccupySetPage, preferredPageIndex + ) + } +} + +private fun makeStyledParagraphFeature( + mustStartPage: Boolean = false, + mustOccupySetPage: Boolean = false, + preferredPageIndex: 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, mustStartPage, mustOccupySetPage, preferredPageIndex) + } +} + +private fun makeTitleFeature( + mustStartPage: Boolean = true, + mustOccupySetPage: Boolean = false, + preferredPageIndex: Int = 1 +): (ResourceKey, Int) -> TitleFeature { + return { entryKey, titleIndex -> + val baseId = ResearchEntry.translationId(entryKey) + TitleFeature( + Component.translatable(TitleFeature.translationId(baseId, titleIndex)).withStyle(ChatFormatting.BOLD), + mustStartPage, mustOccupySetPage, preferredPageIndex + ) + } +} + +private fun makeFigureFeature( + image: Texture, + giveCaption: Boolean, + mustStartPage: Boolean = false, + mustOccupySetPage: Boolean = false, + preferredPageIndex: 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, mustStartPage, mustOccupySetPage, preferredPageIndex) + } else { _, _ -> + FigureFeature(image, null, mustStartPage, mustOccupySetPage, preferredPageIndex) + } +} + +private fun makeRecipeFeature( + recipeRL: ResourceLocation, + coversOneWholePage: Boolean = true, + mustStartPage: Boolean = true, + mustOccupySetPage: Boolean = true, + preferredPageIndex: Int = 1 +): (ResourceKey, Int) -> RecipeFeature { + return { _, _ -> + RecipeFeature( + recipeRL, coversOneWholePage, mustStartPage, mustOccupySetPage, + preferredPageIndex + ) + } +} + private fun simpleTitle(pageIndex: Int, baseId: String) = Component.translatable(TextPage.titleTranslationId(baseId, pageIndex)).withStyle(ChatFormatting.BOLD) -private fun simpleParagraphs(count: Int, pageIndex: Int, baseId: String) = List(count) { Component.translatable(TextPage.paragraphTranslationId(baseId, pageIndex, it)) } +private fun simpleParagraphs(count: Int, pageIndex: Int, baseId: String) = + List(count) { Component.translatable(TextPage.paragraphTranslationId(baseId, pageIndex, it)) } + +private fun lockedAspect(row: Int, col: Int, a: DeferredAspect) = + SocketState(Indices(row, col), a.get(), false, true) -private fun lockedAspect(row: Int, col: Int, a: DeferredAspect) = SocketState(Indices(row, col), a.get(), false, true) private fun broken(row: Int, col: Int) = SocketState(Indices(row, col), null, true, true) 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 2ac38300..71e1e330 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 @@ -5,13 +5,15 @@ import me.alegian.thavma.impl.client.T7KeyMappings import me.alegian.thavma.impl.client.gui.layer.ArcaneLensLayer import me.alegian.thavma.impl.client.gui.research_table.AspectWidget import me.alegian.thavma.impl.client.gui.research_table.ButtonWidget -import me.alegian.thavma.impl.client.gui.research_table.ResearchScreen import me.alegian.thavma.impl.client.gui.research_table.SocketWidget 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.FigureFeature +import me.alegian.thavma.impl.common.book.ParagraphFeature import me.alegian.thavma.impl.common.book.TextPage +import me.alegian.thavma.impl.common.book.TitleFeature import me.alegian.thavma.impl.common.recipe.translationId import me.alegian.thavma.impl.common.research.ResearchCategory import me.alegian.thavma.impl.common.research.ResearchEntry @@ -138,7 +140,7 @@ class T7LanguageProvider(output: PackOutput, locale: String) : LanguageProvider( add(ORICHALCUM_NUGGET.get(), "Orichalcum Nugget") add(RESEARCH_SCROLL.get(), "Research Scroll") add(ARCANE_LENS.get(), "Arcane Lens") - add(BOOK.get(), "Elements of Thavma") + add(BOOK.get(), "Elements") add(T7Items.BASIC_AMULET.get(), "Basic Amulet") add(T7Items.BASIC_BELT.get(), "Basic Belt") @@ -271,47 +273,230 @@ class T7LanguageProvider(output: PackOutput, locale: String) : LanguageProvider( addCategory(ResearchCategories.ALCHEMY, "Alchemy") addEntry(ResearchEntries.Alchemy.ALCHEMY, "Alchemy") + addCategory(ResearchCategories.STORY, "???") + addEntry(ResearchEntries.Story.TEST, "A Courtesy Call") + addTextPage( - ResearchEntries.Thavma.THAVMA, 0, - "Thavma", - """ + ResearchEntries.Story.TEST, 0, + "A Courtesy Call 1", + "Lorem ipsum %s 1 sit amet,", + "this story a great meaning haveth." + ) + + addTextPage( + ResearchEntries.Story.TEST, 1, + "A Courtesy Call 2", + "Lorem dolor 2 sit amet,", + "this story a great meaning haveth.", + "" + ) + + addTextPage( + ResearchEntries.Story.TEST, 2, + "A Courtesy Call 3", + "Lorem lotrumatum dolor 3 sit amet,", + "this story a great meaning haveth." + ) + + addTitleFeature(ResearchEntries.Story.TEST, 0, "A courtesy call starts the page") + addParagraphFeature( + ResearchEntries.Story.TEST, 0, """ + As fate would have it, this paragraph will probably not start a page because it does not + have the mustStartPage flag set to true, which is actually rather a worrisome tragedy. + Somebody had better do something about it soon. + """ + ) + addParagraphFeature( + ResearchEntries.Story.TEST, 1, """ + This is an experiment simply due to the fact that I am testing out double-trim-indent behaviour! + If this fails and I am left to contemplate my existence in the bottomless abyss that my mind is, + I will be making phone calls real fast real soon. + (I got my Karen haircut done yesterday so while you mongrels crawl about, + I will bee the queen out of every damn bastard who makes me think badly of me, myself included.) + """.trimIndent() + ) + addFigureFeature( + ResearchEntries.Story.TEST, 0, """ +We're no strangers to love +You know the rules and so do I +A full commitment's what I'm thinking of +You wouldn't get this from any other guy +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +We've known each other for so long +Your heart's been aching, but you're too shy to say it +Inside, we both know what's been going on +We know the game, and we're gonna play it +And if you ask me how I'm feeling +Don't tell me you're too blind to see +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Ooh (Give you up) +Ooh-ooh (Give you up) +Ooh (Never gonna give, never gonna give) +Give you up +Ooh-ooh (Never gonna give, never gonna give) +Give you up +We've known each other for so long +Your heart's been aching, but you're too shy to say it +Inside, we both know what's been going on +We know the game, and we're gonna play it +I just wanna tell you how I'm feeling +Gotta make you understand +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you + """.trimIndent() + ) + addTitleFeature(ResearchEntries.Story.TEST, 1, "This title might appear in the middle") + addParagraphFeature( + ResearchEntries.Story.TEST, 2, """ + On the other hand, this paragraph should start a new page always. It has the mustStartPage property set to true :3 + """.trimIndent() + ) + addTitleFeature(ResearchEntries.Story.TEST, 2, "(start of page)") + addTitleFeature( + ResearchEntries.Story.TEST, 3, """ + this is page number 1! Surprise! Even though this Title is added as the + fourth one in the DataPackBuiltinEntriesProvider and LanguageProvider + after a ton of paragraphs and titles and figures etc., + it has a preferred page index 0! + """.trimIndent() + ) + addParagraphFeature(ResearchEntries.Story.TEST, 3, "Just another random little paragraph :D") + addParagraphFeature( + ResearchEntries.Story.TEST, 4, """ + And BAM! smack that paragraph right in the middle without it + being an image caption! (Both the image and this have a + preferred page index set to 5 -> always page number 6) + """.trimIndent() + ) + + addEntry(ResearchEntries.Story.TEST2, "I will not be denied") + addParagraphFeature(ResearchEntries.Story.TEST2, 0, "When faced with setback, we must challenge our assumptions.") + + addTitleFeature(ResearchEntries.Thavma.THAVMA, 0, "Thavma") + addParagraphFeature( + ResearchEntries.Thavma.THAVMA, 0, """ 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. - """, """ - The cover reads "Elements of Thavma", but a lot of its pages appear blank, sealed by some magic. - """, + ) + addParagraphFeature( + ResearchEntries.Thavma.THAVMA, 1, """ + The cover reads "Elements", but a lot of its pages appear blank, sealed by some magic. """ + ) + addParagraphFeature( + ResearchEntries.Thavma.THAVMA, 2, """ 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. """ ) - - addTextPage( - ResearchEntries.Thavma.THAVMA, 1, - null, - """ + addParagraphFeature( + ResearchEntries.Thavma.THAVMA, 3, """ I will document all my findings inside the book, so that I can recall them later. """ ) - addTextPage( - ResearchEntries.Thavma.ARCANE_LENS, 0, - "The Arcane Lens", - """ +// addTextPage( +// ResearchEntries.Thavma.THAVMA, 0, +// "Thavma", +// """ +// 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. +// """, +// """ +// 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 +// I have a feeling it will be worth my efforts. +// """ +// ) + +// addTextPage( +// ResearchEntries.Thavma.THAVMA, 1, +// null, +// """ +// I will document all my findings inside the book, so that I can recall them later. +// """ +// ) + + addTitleFeature(ResearchEntries.Thavma.ARCANE_LENS, 0, "The Arcane Lens") + addParagraphFeature( + ResearchEntries.Thavma.ARCANE_LENS, 0, """ 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. - """, """ + ) + addParagraphFeature( + ResearchEntries.Thavma.ARCANE_LENS, 1, """ The blueprint describes a hexagonal device, much like a prism, made with those colorful crystals I found lying in a cave. - """, """ + ) + addParagraphFeature( + ResearchEntries.Thavma.ARCANE_LENS, 2, """ I should look at the world through its lens, maybe it will uncover something useful. """ ) +// addTextPage( +// ResearchEntries.Thavma.ARCANE_LENS, 0, +// "The Arcane Lens", +// """ +// 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. +// """, +// """ +// The blueprint describes a hexagonal device, much like a prism, +// made with those colorful crystals I found lying in a cave. +// """, +// """ +// I should look at the world through its lens, maybe it will uncover something useful. +// """ +// ) + add(RESEARCH_SCROLL.get().completedTranslation(), "Completed Research") add(ResearchEntry.TOAST_TRANSLATION, "Research Complete!") add(ResearchEntry.SCROLL_GIVEN_TRANSLATION, "You have received a research scroll") @@ -326,14 +511,35 @@ class T7LanguageProvider(output: PackOutput, locale: String) : LanguageProvider( add(RecipeViewerDescriptions.ROTTEN_BRAIN, "Sometimes dropped by angry zombies.") add(RecipeViewerDescriptions.BOOK, "Right click a bookcase with a wand to obtain!") - add(RecipeViewerDescriptions.ARCANE_WORKBENCH, "Right click a crafting table with a wand to convert it to an arcane workbench.") + add( + RecipeViewerDescriptions.ARCANE_WORKBENCH, + "Right click a crafting table with a wand to convert it to an arcane workbench." + ) add(RecipeViewerDescriptions.CRUCIBLE, "Right click a cauldron with a wand to convert it to a crucible.") - add(RecipeViewerDescriptions.RESEARCH_TABLE, "Can be formed by placing 2 tables next to each other, and right clicking one with a wand.") - add(RecipeViewerDescriptions.INFUSED_STONES, "A piece of stone, infused with a primal element. Found in the overworld, at any height.") - add(RecipeViewerDescriptions.GREATWOOD, "Greatwoods are very tall, ancient trees. They are somewhat rare, but they can spawn in all overworld biomes.") - add(RecipeViewerDescriptions.SILVERWOOD, "Silverwoods are magical trees, with uniquely blue leaves. They are very rare, but they can spawn in all overworld biomes.") - add(RecipeViewerDescriptions.PILLAR, "Formed by right clicking the Infusion Matrix, after completing the Infusion Multiblock.") - add(RecipeViewerDescriptions.RESEARCH_SCROLL, "Obtained by clicking any unknown entry in the \"Elements of Thavma\"") + add( + RecipeViewerDescriptions.RESEARCH_TABLE, + "Can be formed by placing 2 tables next to each other, and right clicking one with a wand." + ) + add( + RecipeViewerDescriptions.INFUSED_STONES, + "A piece of stone, infused with a primal element. Found in the overworld, at any height." + ) + add( + RecipeViewerDescriptions.GREATWOOD, + "Greatwoods are very tall, ancient trees. They are somewhat rare, but they can spawn in all overworld biomes." + ) + add( + RecipeViewerDescriptions.SILVERWOOD, + "Silverwoods are magical trees, with uniquely blue leaves. They are very rare, but they can spawn in all overworld biomes." + ) + add( + RecipeViewerDescriptions.PILLAR, + "Formed by right clicking the Infusion Matrix, after completing the Infusion Multiblock." + ) + add( + RecipeViewerDescriptions.RESEARCH_SCROLL, + "Obtained by clicking any unknown entry in the \"Elements of Thavma\"" + ) add(RecipeViewerAliases.BOOK, "Book") add(RecipeViewerAliases.ORE, "Ore") @@ -367,10 +573,33 @@ class T7LanguageProvider(output: PackOutput, locale: String) : LanguageProvider( add(ResearchCategory.translationId(key), name) } - private fun addTextPage(entryKey: ResourceKey, pageIndex: Int, title: String?, vararg paragraphs: String) { + private fun addTextPage( + entryKey: ResourceKey, + pageIndex: Int, + title: String?, + vararg paragraphs: String + ) { val baseId = ResearchEntry.translationId(entryKey) if (title != null) add(TextPage.titleTranslationId(baseId, pageIndex), title) for (parIndex in paragraphs.indices) - add(TextPage.paragraphTranslationId(baseId, pageIndex, parIndex), paragraphs[parIndex].trimIndent().replace("\n", " ")) + add( + TextPage.paragraphTranslationId(baseId, pageIndex, parIndex), + paragraphs[parIndex].trimIndent().replace("\n", " ") + ) + } + + private fun addParagraphFeature(entryKey: ResourceKey, featureIndex: Int, text: String) { + val baseId = ResearchEntry.translationId(entryKey) + add(ParagraphFeature.translationId(baseId, featureIndex), text.trimIndent().replace("\n", " ")) + } + + private fun addTitleFeature(entryKey: ResourceKey, featureIndex: Int, text: String) { + val baseId = ResearchEntry.translationId(entryKey) + add(TitleFeature.translationId(baseId, featureIndex), text.trimIndent().replace("\n", " ")) + } + + private fun addFigureFeature(entryKey: ResourceKey, featureIndex: Int, text: String) { + val baseId = ResearchEntry.translationId(entryKey) + add(FigureFeature.translationId(baseId, featureIndex), text.trimIndent().replace("\n", " ")) } } 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..e9c61a7d 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..251de20a --- /dev/null +++ b/src/main/java/me/alegian/thavma/impl/init/registries/deferred/PageFeatureTypes.kt @@ -0,0 +1,20 @@ +package me.alegian.thavma.impl.init.registries.deferred + +import me.alegian.thavma.impl.Thavma +import me.alegian.thavma.impl.common.book.FigureFeature +import me.alegian.thavma.impl.common.book.PageFeatureType +import me.alegian.thavma.impl.common.book.ParagraphFeature +import me.alegian.thavma.impl.common.book.RecipeFeature +import me.alegian.thavma.impl.common.book.TitleFeature +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("figure"), RecipeFeature.CODEC) } +} \ No newline at end of file diff --git a/src/main/java/me/alegian/thavma/impl/init/registries/deferred/PageTypes.kt b/src/main/java/me/alegian/thavma/impl/init/registries/deferred/PageTypes.kt index bec6449b..e0f0e06c 100644 --- a/src/main/java/me/alegian/thavma/impl/init/registries/deferred/PageTypes.kt +++ b/src/main/java/me/alegian/thavma/impl/init/registries/deferred/PageTypes.kt @@ -2,6 +2,8 @@ package me.alegian.thavma.impl.init.registries.deferred import me.alegian.thavma.impl.Thavma import me.alegian.thavma.impl.common.book.CraftingPage +import me.alegian.thavma.impl.common.book.DynamicPage +import me.alegian.thavma.impl.common.book.PageFeature import me.alegian.thavma.impl.common.book.PageType import me.alegian.thavma.impl.common.book.TextPage import me.alegian.thavma.impl.init.registries.T7Registries @@ -13,4 +15,5 @@ object PageTypes { val TEXT = REGISTRAR.register("text") { -> PageType(rl("text"), TextPage.CODEC) } val CRAFTING = REGISTRAR.register("crafting") { -> PageType(rl("crafting"), CraftingPage.CODEC) } + //val DYNAMIC = REGISTRAR.register("dynamic") { -> PageType(rl("dynamic"), DynamicPage.CODEC) } } \ No newline at end of file diff --git a/src/main/java/me/alegian/thavma/impl/init/registries/deferred/ResearchCategories.kt b/src/main/java/me/alegian/thavma/impl/init/registries/deferred/ResearchCategories.kt index 43c8a571..390ef405 100644 --- a/src/main/java/me/alegian/thavma/impl/init/registries/deferred/ResearchCategories.kt +++ b/src/main/java/me/alegian/thavma/impl/init/registries/deferred/ResearchCategories.kt @@ -7,4 +7,5 @@ import net.minecraft.resources.ResourceKey object ResearchCategories { val THAVMA = ResourceKey.create(T7DatapackRegistries.RESEARCH_CATEGORY, rl("thavma")) val ALCHEMY = ResourceKey.create(T7DatapackRegistries.RESEARCH_CATEGORY, rl("alchemy")) + val STORY = ResourceKey.create(T7DatapackRegistries.RESEARCH_CATEGORY, rl("story")) } \ No newline at end of file diff --git a/src/main/java/me/alegian/thavma/impl/init/registries/deferred/ResearchEntries.kt b/src/main/java/me/alegian/thavma/impl/init/registries/deferred/ResearchEntries.kt index a236d3f1..10a237d2 100644 --- a/src/main/java/me/alegian/thavma/impl/init/registries/deferred/ResearchEntries.kt +++ b/src/main/java/me/alegian/thavma/impl/init/registries/deferred/ResearchEntries.kt @@ -25,6 +25,12 @@ object ResearchEntries { object Alchemy { val ALCHEMY = register("alchemy", ResearchCategories.ALCHEMY) } + + object Story { + val TEST = register("story_test", ResearchCategories.STORY) + val TEST2 = register("story_test2", ResearchCategories.STORY) + } + } // prepend category id to entry id to avoid duplicates diff --git a/src/main/resources/assets/thavma/font/default.json b/src/main/resources/assets/thavma/font/default.json new file mode 100644 index 00000000..dbad25b0 --- /dev/null +++ b/src/main/resources/assets/thavma/font/default.json @@ -0,0 +1,11 @@ +{ + "providers": [ + { + "type": "ttf", + "file": "thavma:default.ttf", + "shift": [0, 0], + "size": 11.0, + "oversample": 2.0 + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/thavma/font/default.ttf b/src/main/resources/assets/thavma/font/default.ttf new file mode 100644 index 00000000..85c14725 Binary files /dev/null and b/src/main/resources/assets/thavma/font/default.ttf differ diff --git a/src/main/resources/assets/thavma/textures/gui/images/important_image.png b/src/main/resources/assets/thavma/textures/gui/images/important_image.png new file mode 100644 index 00000000..1de24135 Binary files /dev/null and b/src/main/resources/assets/thavma/textures/gui/images/important_image.png differ diff --git a/src/main/resources/assets/thavma/textures/gui/images/important_image2.png b/src/main/resources/assets/thavma/textures/gui/images/important_image2.png new file mode 100644 index 00000000..1afe2ccd Binary files /dev/null and b/src/main/resources/assets/thavma/textures/gui/images/important_image2.png differ