From ec95cac4c1fb8291caa4c943c0934af587b9f73a Mon Sep 17 00:00:00 2001 From: lukasabbe <67807954+lukasabbe@users.noreply.github.com> Date: Tue, 20 Jan 2026 23:44:17 +0100 Subject: [PATCH] Init --- .gitignore | 119 ++++++++++++++++++ LICENSE.txt | 21 ++++ build.gradle | 88 +++++++++++++ gradle.properties | 11 ++ gradle/wrapper/gradle-wrapper.properties | 1 + settings.gradle | 9 ++ .../notenoughpages/Notenoughpages.java | 86 +++++++++++++ .../mixin/BookEditScreenAccessor.java | 19 +++ .../mixin/BookEditScreenMixin.java | 8 ++ .../mixin/MultiLineEditBoxAccessor.java | 12 ++ .../mixin/MultilineTextFieldMixin.java | 24 ++++ .../mixin/PasteContentMixin.java | 18 +++ src/main/resources/fabric.mod.json | 24 ++++ src/main/resources/notenoughpages.mixins.json | 21 ++++ 14 files changed, 461 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE.txt create mode 100644 build.gradle create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 settings.gradle create mode 100644 src/main/java/com/lukasabbe/notenoughpages/Notenoughpages.java create mode 100644 src/main/java/com/lukasabbe/notenoughpages/mixin/BookEditScreenAccessor.java create mode 100644 src/main/java/com/lukasabbe/notenoughpages/mixin/BookEditScreenMixin.java create mode 100644 src/main/java/com/lukasabbe/notenoughpages/mixin/MultiLineEditBoxAccessor.java create mode 100644 src/main/java/com/lukasabbe/notenoughpages/mixin/MultilineTextFieldMixin.java create mode 100644 src/main/java/com/lukasabbe/notenoughpages/mixin/PasteContentMixin.java create mode 100644 src/main/resources/fabric.mod.json create mode 100644 src/main/resources/notenoughpages.mixins.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..93a8da9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,119 @@ +# User-specific stuff +.idea/ + +*.iml +*.ipr +*.iws + +# IntelliJ +out/ +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +.gradle +build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Cache of project +.gradletasknamecache + +**/build/ + +# Common working directory +run/ +runs/ + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..20d9344 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2026 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..0d95b47 --- /dev/null +++ b/build.gradle @@ -0,0 +1,88 @@ +plugins { + id 'fabric-loom' version '1.15-SNAPSHOT' + id 'maven-publish' +} + +version = project.mod_version +group = project.maven_group + +base { + archivesName = project.archives_base_name +} + + +repositories { + // Add repositories to retrieve artifacts from in here. + // You should only use this when depending on other mods because + // Loom adds the essential maven repositories to download Minecraft and libraries from automatically. + // See https://docs.gradle.org/current/userguide/declaring_repositories.html + // for more information about repositories. +} + +dependencies { + // To change the versions see the gradle.properties file + minecraft "com.mojang:minecraft:${project.minecraft_version}" + mappings loom.officialMojangMappings() + modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" + +} + +processResources { + inputs.property "version", project.version + inputs.property "minecraft_version", project.minecraft_version + inputs.property "loader_version", project.loader_version + filteringCharset "UTF-8" + + filesMatching("fabric.mod.json") { + expand "version": project.version, + "minecraft_version": project.minecraft_version, + "loader_version": project.loader_version + } +} + +def targetJavaVersion = 21 +tasks.withType(JavaCompile).configureEach { + // ensure that the encoding is set to UTF-8, no matter what the system default is + // this fixes some edge cases with special characters not displaying correctly + // see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html + // If Javadoc is generated, this must be specified in that task too. + it.options.encoding = "UTF-8" + if (targetJavaVersion >= 10 || JavaVersion.current().isJava10Compatible()) { + it.options.release.set(targetJavaVersion) + } +} + +java { + def javaVersion = JavaVersion.toVersion(targetJavaVersion) + if (JavaVersion.current() < javaVersion) { + toolchain.languageVersion = JavaLanguageVersion.of(targetJavaVersion) + } + // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task + // if it is present. + // If you remove this line, sources will not be generated. + withSourcesJar() +} + +jar { + from("LICENSE") { + rename { "${it}_${project.archives_base_name}" } + } +} + +// configure the maven publication +publishing { + publications { + create("mavenJava", MavenPublication) { + artifactId = project.archives_base_name + from components.java + } + } + + // See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing. + repositories { + // Add repositories to publish to here. + // Notice: This block does NOT have the same function as the block in the top level. + // The repositories here will be used for publishing your artifact, not for + // retrieving dependencies. + } +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..bbdcafb --- /dev/null +++ b/gradle.properties @@ -0,0 +1,11 @@ +# Done to increase the memory available to gradle. +org.gradle.jvmargs=-Xmx1G +# Fabric Properties +# check these on https://modmuss50.me/fabric.html +minecraft_version=1.21.11 +loader_version=0.18.4 +# Mod Properties +mod_version=1.0+1.21.1 +maven_group=com.lukasabbe +archives_base_name=NotEnoughPages + diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..3c0465a --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1 @@ +distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..f91a4fe --- /dev/null +++ b/settings.gradle @@ -0,0 +1,9 @@ +pluginManagement { + repositories { + maven { + name = 'Fabric' + url = 'https://maven.fabricmc.net/' + } + gradlePluginPortal() + } +} diff --git a/src/main/java/com/lukasabbe/notenoughpages/Notenoughpages.java b/src/main/java/com/lukasabbe/notenoughpages/Notenoughpages.java new file mode 100644 index 0000000..dd70546 --- /dev/null +++ b/src/main/java/com/lukasabbe/notenoughpages/Notenoughpages.java @@ -0,0 +1,86 @@ +package com.lukasabbe.notenoughpages; + +import com.lukasabbe.notenoughpages.mixin.BookEditScreenAccessor; +import com.lukasabbe.notenoughpages.mixin.MultiLineEditBoxAccessor; +import com.lukasabbe.notenoughpages.mixin.MultilineTextFieldMixin; +import net.fabricmc.api.ModInitializer; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.components.MultiLineEditBox; +import net.minecraft.client.gui.components.MultilineTextField; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.inventory.BookEditScreen; +import net.minecraft.util.StringUtil; + +public class Notenoughpages implements ModInitializer { + @Override + public void onInitialize() {} + + public static void handlePaste(String content){ + Screen guiScreen = Minecraft.getInstance().screen; + if(guiScreen == null) return; + if(guiScreen instanceof BookEditScreen bookEditScreen){ + MultiLineEditBox page = ((BookEditScreenAccessor) bookEditScreen).getPage(); + MultilineTextField textField = ((MultiLineEditBoxAccessor) page).getTextField(); + + if(((MultilineTextFieldMixin) textField).getSelecting()) return; + if(textField.cursor() != ((MultilineTextFieldMixin) textField).getSelectCursor()) return; + if(IsContentCorrectLength(content, textField)) return; + + while(true){ + System.out.println(((BookEditScreenAccessor) bookEditScreen).getPagesAmount()); + if(((BookEditScreenAccessor) bookEditScreen).getPagesAmount() == 99){ + return; + } + + if(IsContentCorrectLength(content, textField)){ + textField.insertText(content); + return; + } + + String[] split = splitString(content, textField); + + textField.insertText(split[0]); + content = split[1]; + + ((BookEditScreenAccessor) bookEditScreen).nextPage(); + page = ((BookEditScreenAccessor) bookEditScreen).getPage(); + textField = ((MultiLineEditBoxAccessor) page).getTextField(); + } + + } + } + + public static String[] splitString(String content, MultilineTextField field){ + int low = 0; + int high = content.length(); + int splitIndex = 0; + + while(low <= high){ + int mid = low + (high - low) / 2; + + String sub = content.substring(0, mid); + + if (((MultilineTextFieldMixin)field).overflowsLineLimitInvoker(sub)){ + high = mid - 1; + } else { + splitIndex = mid; + low = mid + 1; + } + } + + String insertString = content.substring(0, splitIndex); + String overflow = content.substring(splitIndex); + return new String[] { insertString, overflow }; + } + + public static boolean IsContentCorrectLength(String content, MultilineTextField field){ + String truncated = ((MultilineTextFieldMixin) field).truncateInsertionTextInvoker(StringUtil.filterText(content, true)); + int selectCursor = ((MultilineTextFieldMixin) field).getSelectCursor(); + int cursor = field.cursor(); + int beginIndex = Math.min(selectCursor, cursor); + int endIndex = Math.max(selectCursor, cursor); + String bookContent = (new StringBuilder(((MultilineTextFieldMixin)field).getValue())).replace(beginIndex, endIndex, truncated).toString(); + + return !((MultilineTextFieldMixin) field).overflowsLineLimitInvoker(bookContent); + } +} diff --git a/src/main/java/com/lukasabbe/notenoughpages/mixin/BookEditScreenAccessor.java b/src/main/java/com/lukasabbe/notenoughpages/mixin/BookEditScreenAccessor.java new file mode 100644 index 0000000..ece724a --- /dev/null +++ b/src/main/java/com/lukasabbe/notenoughpages/mixin/BookEditScreenAccessor.java @@ -0,0 +1,19 @@ +package com.lukasabbe.notenoughpages.mixin; + +import net.minecraft.client.gui.components.MultiLineEditBox; +import net.minecraft.client.gui.screens.inventory.BookEditScreen; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(BookEditScreen.class) +public interface BookEditScreenAccessor { + @Accessor("page") + MultiLineEditBox getPage(); + + @Invoker("pageForward") + void nextPage(); + + @Invoker("getNumPages") + int getPagesAmount(); +} diff --git a/src/main/java/com/lukasabbe/notenoughpages/mixin/BookEditScreenMixin.java b/src/main/java/com/lukasabbe/notenoughpages/mixin/BookEditScreenMixin.java new file mode 100644 index 0000000..e613ce1 --- /dev/null +++ b/src/main/java/com/lukasabbe/notenoughpages/mixin/BookEditScreenMixin.java @@ -0,0 +1,8 @@ +package com.lukasabbe.notenoughpages.mixin; + +import net.minecraft.client.gui.screens.inventory.BookEditScreen; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(BookEditScreen.class) +public class BookEditScreenMixin { +} diff --git a/src/main/java/com/lukasabbe/notenoughpages/mixin/MultiLineEditBoxAccessor.java b/src/main/java/com/lukasabbe/notenoughpages/mixin/MultiLineEditBoxAccessor.java new file mode 100644 index 0000000..6db47ea --- /dev/null +++ b/src/main/java/com/lukasabbe/notenoughpages/mixin/MultiLineEditBoxAccessor.java @@ -0,0 +1,12 @@ +package com.lukasabbe.notenoughpages.mixin; + +import net.minecraft.client.gui.components.MultiLineEditBox; +import net.minecraft.client.gui.components.MultilineTextField; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(MultiLineEditBox.class) +public interface MultiLineEditBoxAccessor { + @Accessor("textField") + MultilineTextField getTextField(); +} diff --git a/src/main/java/com/lukasabbe/notenoughpages/mixin/MultilineTextFieldMixin.java b/src/main/java/com/lukasabbe/notenoughpages/mixin/MultilineTextFieldMixin.java new file mode 100644 index 0000000..f8e817d --- /dev/null +++ b/src/main/java/com/lukasabbe/notenoughpages/mixin/MultilineTextFieldMixin.java @@ -0,0 +1,24 @@ +package com.lukasabbe.notenoughpages.mixin; + +import net.minecraft.client.gui.components.MultilineTextField; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(MultilineTextField.class) +public interface MultilineTextFieldMixin { + @Invoker("truncateInsertionText") + String truncateInsertionTextInvoker(String string); + + @Invoker("overflowsLineLimit") + boolean overflowsLineLimitInvoker(String string); + + @Accessor("value") + String getValue(); + + @Accessor("selectCursor") + int getSelectCursor(); + + @Accessor("selecting") + boolean getSelecting(); +} diff --git a/src/main/java/com/lukasabbe/notenoughpages/mixin/PasteContentMixin.java b/src/main/java/com/lukasabbe/notenoughpages/mixin/PasteContentMixin.java new file mode 100644 index 0000000..355016d --- /dev/null +++ b/src/main/java/com/lukasabbe/notenoughpages/mixin/PasteContentMixin.java @@ -0,0 +1,18 @@ +package com.lukasabbe.notenoughpages.mixin; + +import com.lukasabbe.notenoughpages.Notenoughpages; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.components.MultilineTextField; +import net.minecraft.client.input.KeyEvent; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(MultilineTextField.class) +public class PasteContentMixin { + @Inject(method = "keyPressed",at= @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/components/MultilineTextField;insertText(Ljava/lang/String;)V", ordinal = 0)) + public void getPasteContent(KeyEvent keyEvent, CallbackInfoReturnable cir){ + Notenoughpages.handlePaste(Minecraft.getInstance().keyboardHandler.getClipboard()); + } +} diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..83cb514 --- /dev/null +++ b/src/main/resources/fabric.mod.json @@ -0,0 +1,24 @@ +{ + "schemaVersion": 1, + "id": "notenoughpages", + "version": "${version}", + "name": "NotEnoughPages", + "description": "", + "authors": [], + "contact": {}, + "license": "MIT", + "icon": "assets/notenoughpages/icon.png", + "environment": "*", + "entrypoints": { + "main": [ + "com.lukasabbe.notenoughpages.Notenoughpages" + ] + }, + "mixins": [ + "notenoughpages.mixins.json" + ], + "depends": { + "fabricloader": ">=${loader_version}", + "minecraft": "${minecraft_version}" + } +} diff --git a/src/main/resources/notenoughpages.mixins.json b/src/main/resources/notenoughpages.mixins.json new file mode 100644 index 0000000..5216f8d --- /dev/null +++ b/src/main/resources/notenoughpages.mixins.json @@ -0,0 +1,21 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "com.lukasabbe.notenoughpages.mixin", + "compatibilityLevel": "JAVA_21", + "mixins": [ + "PasteContentMixin" + ], + "client": [ + "BookEditScreenAccessor", + "BookEditScreenMixin", + "MultiLineEditBoxAccessor", + "MultilineTextFieldMixin" + ], + "injectors": { + "defaultRequire": 1 + }, + "overwrites": { + "requireAnnotations": true + } +}