diff --git a/Pagination/build.gradle b/Pagination/build.gradle index 75f7707..e69de29 100644 --- a/Pagination/build.gradle +++ b/Pagination/build.gradle @@ -1,35 +0,0 @@ -plugins { - id 'fabric-loom' -} - -dependencies { - minecraft "com.mojang:minecraft:${project.minecraft_version}" - mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" - modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" - - modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" -} - -processResources { - inputs.property "version", project.version - - filesMatching("fabric.mod.json") { - expand "version": project.version - } -} - -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" - - // The Minecraft launcher currently installs Java 8 for users, so your mod probably wants to target Java 8 too - // JDK 9 introduced a new way of specifying this that will make sure no newer classes or methods are used. - // We'll use that if it's available, but otherwise we'll use the older option. - def targetVersion = 17 - if (JavaVersion.current().isJava9Compatible()) { - it.options.release = targetVersion - } -} \ No newline at end of file diff --git a/Pagination/src/main/java/fr/altarik/toolbox/pagination/PaginatedContent.java b/Pagination/src/main/java/fr/altarik/toolbox/pagination/PaginatedContent.java index ca07c3a..95ac763 100644 --- a/Pagination/src/main/java/fr/altarik/toolbox/pagination/PaginatedContent.java +++ b/Pagination/src/main/java/fr/altarik/toolbox/pagination/PaginatedContent.java @@ -1,4 +1,93 @@ package fr.altarik.toolbox.pagination; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.ClickEvent; +import net.minecraft.text.MutableText; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + public class PaginatedContent { + + private final List pages; + private final String header; + + public PaginatedContent(String header, String content) { + this.header = buildHeader(header); + pages = new ArrayList<>(); + List secondSplit = new ArrayList<>(); + for(String elem : Stream.of(content.split("\n")).collect(Collectors.toCollection(ArrayList::new))) { + if(elem.length() > 50) { + secondSplit.add(elem.substring(0, 50)); + secondSplit.add(elem.substring(51, elem.length() - 1)); + } else { + secondSplit.add(elem); + } + } + int line = 0; + List currentPage = new ArrayList<>(); + for(String elem : secondSplit) { + line++; + if(!elem.isEmpty()) + currentPage.add(elem); + if(line == 8 || elem.isEmpty()) { + pages.add(new Page(currentPage)); + line = 0; + currentPage = new ArrayList<>(); + } + } + pages.add(new Page(currentPage)); + } + + private String buildHeader(String header) { + int numberOfEq = (50 - header.length()) / 2; + return "=".repeat(numberOfEq) + header + "=".repeat(numberOfEq); + } + + public void display(ServerPlayerEntity playerEntity, int page) { + if(page >= this.pages.size()) { + throw new IllegalArgumentException("There's " + this.pages.size() + " paginated pages but you wanted page n°" + (page + 1)); + } else if(page < 0) { + throw new IllegalArgumentException("argument page is lower than 0"); + } else { + playerEntity.sendMessage(Text.literal(header)); + for(String s : pages.get(page).lines) { + playerEntity.sendMessage(Text.literal(s)); + } + + playerEntity.sendMessage(buildFooter(page)); + } + } + + private Text buildFooter(int page) { + String strPage = String.valueOf(page + 1); + int numberOfEq = (46 - strPage.length()) / 2; + MutableText left = Text.literal("<").styled( + style -> style + .withColor(Formatting.YELLOW) + .withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/table page " + (page - 1))) + ); + MutableText middle = Text.literal(" " + strPage + " ").styled(style -> style.withColor(Formatting.RESET)); + MutableText right = Text.literal(">").styled( + style -> style + .withColor(Formatting.YELLOW) + .withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/table page " + (page + 1))) + ); + return Text.literal("=".repeat(numberOfEq)) + .append(left) + .append(middle) + .append(right) + .append( + Text.literal("=".repeat(numberOfEq)) + .styled(style -> style.withColor(Formatting.RESET)) + ); + } + + private record Page(List lines) { + } + } diff --git a/Pagination/src/main/java/fr/altarik/toolbox/pagination/Pagination.java b/Pagination/src/main/java/fr/altarik/toolbox/pagination/Pagination.java index 009e005..8e4b19e 100644 --- a/Pagination/src/main/java/fr/altarik/toolbox/pagination/Pagination.java +++ b/Pagination/src/main/java/fr/altarik/toolbox/pagination/Pagination.java @@ -19,7 +19,7 @@ public class Pagination implements ModInitializer { @Override public void onInitialize() { - CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> new CommandsRegister().register(dispatcher, environment.dedicated)); + CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> new CommandsRegister(this).register(dispatcher, environment.dedicated)); } public @NotNull PaginationApi getApi() { diff --git a/Pagination/src/main/java/fr/altarik/toolbox/pagination/api/PaginationApi.java b/Pagination/src/main/java/fr/altarik/toolbox/pagination/api/PaginationApi.java index 3adb373..34f8f23 100644 --- a/Pagination/src/main/java/fr/altarik/toolbox/pagination/api/PaginationApi.java +++ b/Pagination/src/main/java/fr/altarik/toolbox/pagination/api/PaginationApi.java @@ -2,6 +2,7 @@ package fr.altarik.toolbox.pagination.api; import net.minecraft.server.network.ServerPlayerEntity; +@SuppressWarnings("unused") // Api usage public interface PaginationApi { /** @@ -16,10 +17,20 @@ public interface PaginationApi { *
  • empty String if you want just the header to be filled only with "="
  • * @throws IllegalArgumentException if one of its conditions is met:
      *
    1. header length is more than 50 characters
    2. - *
    3. content is empty
    4. + *
    5. content is empty/blank
    6. *
    7. playerEntity or content are null
    8. *
    */ void createTable(ServerPlayerEntity playerEntity, String content, String header); + /** + * Display the given page for the given player + * @param player display the content of this player + * @param page display this page + * @throws IllegalArgumentException if page is invalid + * @throws NullPointerException if player is null or paginated content for the player doesn't exist (or have expired) + * @see fr.altarik.toolbox.pagination.PaginatedContent#display(ServerPlayerEntity, int) + */ + void display(ServerPlayerEntity player, int page); + } diff --git a/Pagination/src/main/java/fr/altarik/toolbox/pagination/api/PaginationApiImpl.java b/Pagination/src/main/java/fr/altarik/toolbox/pagination/api/PaginationApiImpl.java index 2d0477d..8a2abf9 100644 --- a/Pagination/src/main/java/fr/altarik/toolbox/pagination/api/PaginationApiImpl.java +++ b/Pagination/src/main/java/fr/altarik/toolbox/pagination/api/PaginationApiImpl.java @@ -1,18 +1,64 @@ package fr.altarik.toolbox.pagination.api; import fr.altarik.toolbox.pagination.PaginatedContent; +import fr.altarik.toolbox.pagination.precondition.ContentCondition; +import fr.altarik.toolbox.pagination.precondition.HeaderCondition; +import fr.altarik.toolbox.pagination.precondition.NullPlayerCondition; +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; +import net.minecraft.server.MinecraftServer; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.util.Pair; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.function.Predicate; public class PaginationApiImpl implements PaginationApi { + /** + * Integer represent relative tts of the paginated content, decreased by 1 every seconds + */ + public final Map> paginatedContent = new HashMap<>(); + private final Predicate playerCondition = new NullPlayerCondition().negate(); + private final Predicate headerCondition = new HeaderCondition().negate(); + private final Predicate contentCondition = new ContentCondition().negate(); - Map> paginatedContent = new HashMap<>(); + public PaginationApiImpl() { + ServerTickEvents.START_SERVER_TICK.register(this::serverTick); + } @Override public void createTable(ServerPlayerEntity playerEntity, String content, String header) { - // TODO: 01/03/2023 + if(playerCondition.test(playerEntity) || headerCondition.test(header) || contentCondition.test(content)) { + throw new IllegalArgumentException("Preconditions aren't satisfied"); + } + PaginatedContent paginatedContent1 = new PaginatedContent(header, content); + paginatedContent.put(playerEntity, new Pair<>(18000, paginatedContent1)); + paginatedContent1.display(playerEntity, 0); + } + + @Override + public void display(ServerPlayerEntity player, int page) { + if(player == null) + throw new NullPointerException("Player is null"); + Pair pair = paginatedContent.get(player); + if(pair == null) + throw new NullPointerException("No paginated page for player " + player.getCustomName()); + pair.getRight().display(player, page); + } + + private void serverTick(MinecraftServer server) { + List toRemove = new ArrayList<>(); + for(Map.Entry> content : paginatedContent.entrySet()) { + if(content.getValue().getLeft() == 0) { + toRemove.add(content.getKey()); + } else { + content.getValue().setLeft(content.getValue().getLeft() - 1); + } + } + for(ServerPlayerEntity player : toRemove) { + paginatedContent.remove(player); + } } } diff --git a/Pagination/src/main/java/fr/altarik/toolbox/pagination/command/CommandsRegister.java b/Pagination/src/main/java/fr/altarik/toolbox/pagination/command/CommandsRegister.java index ae295a4..8c32487 100644 --- a/Pagination/src/main/java/fr/altarik/toolbox/pagination/command/CommandsRegister.java +++ b/Pagination/src/main/java/fr/altarik/toolbox/pagination/command/CommandsRegister.java @@ -2,19 +2,68 @@ package fr.altarik.toolbox.pagination.command; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.arguments.IntegerArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import fr.altarik.toolbox.pagination.Pagination; +import fr.altarik.toolbox.pagination.api.PaginationApi; import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.text.Text; import static net.minecraft.server.command.CommandManager.argument; import static net.minecraft.server.command.CommandManager.literal; public class CommandsRegister { + private final PaginationApi api; + + public CommandsRegister(Pagination instance) { + this.api = instance.getApi(); + } + public void register(CommandDispatcher dispatcher, boolean dedicated) { dispatcher.register(literal("table") .then(literal("page") - .then(argument("page", IntegerArgumentType.integer())) + .then(argument("page", IntegerArgumentType.integer()) + .executes(this::selectPageCommand) + ) + ).then(literal("test") + .requires(source -> source.isExecutedByPlayer() && source.hasPermissionLevel(3)) + .executes(this::testPageCommand) ) ); } + /** + * Simply a debug command + */ + private int testPageCommand(CommandContext context) { + api.createTable(context.getSource().getPlayer(), """ + first line + Second line + + second page + dqdq + dqdqd + qdqdq + dqdq + dqdq + dqdq + dqdqd + third page + dqdqd + dqdqd + d""", "My header"); + return 0; + } + + private int selectPageCommand(CommandContext context) throws CommandSyntaxException { + try { + int page = IntegerArgumentType.getInteger(context, "page"); + api.display(context.getSource().getPlayerOrThrow(), page); + } catch(NullPointerException | IllegalArgumentException e) { + context.getSource().sendFeedback(Text.literal("Error: " + e.getMessage()), false); + } + return 0; + } + } diff --git a/Pagination/src/main/java/fr/altarik/toolbox/pagination/precondition/ContentCondition.java b/Pagination/src/main/java/fr/altarik/toolbox/pagination/precondition/ContentCondition.java new file mode 100644 index 0000000..a5d2542 --- /dev/null +++ b/Pagination/src/main/java/fr/altarik/toolbox/pagination/precondition/ContentCondition.java @@ -0,0 +1,15 @@ +package fr.altarik.toolbox.pagination.precondition; + +import java.util.function.Predicate; + +/** + * This predicate returns true if the String is not null or + * if its content is not blank (empty or only contains whitespaces) + */ +public class ContentCondition implements Predicate { + @Override + public boolean test(String s) { + return s != null && !s.isBlank(); + } + +} diff --git a/Pagination/src/main/java/fr/altarik/toolbox/pagination/precondition/HeaderCondition.java b/Pagination/src/main/java/fr/altarik/toolbox/pagination/precondition/HeaderCondition.java new file mode 100644 index 0000000..9b9ee5e --- /dev/null +++ b/Pagination/src/main/java/fr/altarik/toolbox/pagination/precondition/HeaderCondition.java @@ -0,0 +1,13 @@ +package fr.altarik.toolbox.pagination.precondition; + +import java.util.function.Predicate; + +/** + * This predicate returns true if its length doesn't exceed 50 characters. + */ +public class HeaderCondition implements Predicate { + @Override + public boolean test(String header) { + return header.length() <= 50; + } +} diff --git a/Pagination/src/main/java/fr/altarik/toolbox/pagination/precondition/NullPlayerCondition.java b/Pagination/src/main/java/fr/altarik/toolbox/pagination/precondition/NullPlayerCondition.java new file mode 100644 index 0000000..16e8dfb --- /dev/null +++ b/Pagination/src/main/java/fr/altarik/toolbox/pagination/precondition/NullPlayerCondition.java @@ -0,0 +1,15 @@ +package fr.altarik.toolbox.pagination.precondition; + +import net.minecraft.server.network.ServerPlayerEntity; + +import java.util.function.Predicate; + +/** + * This predicate returns true if the player isn't null, false otherwise + */ +public class NullPlayerCondition implements Predicate { + @Override + public boolean test(ServerPlayerEntity player) { + return player != null; + } +} diff --git a/Tasks/build.gradle b/Tasks/build.gradle index 77c4a5a..e69de29 100644 --- a/Tasks/build.gradle +++ b/Tasks/build.gradle @@ -1,36 +0,0 @@ -plugins { - id 'fabric-loom' - -} - -dependencies { - minecraft "com.mojang:minecraft:${project.minecraft_version}" - mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" - modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" - - modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" -} - -processResources { - inputs.property "version", project.version - - filesMatching("fabric.mod.json") { - expand "version": project.version - } -} - -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" - - // The Minecraft launcher currently installs Java 8 for users, so your mod probably wants to target Java 8 too - // JDK 9 introduced a new way of specifying this that will make sure no newer classes or methods are used. - // We'll use that if it's available, but otherwise we'll use the older option. - def targetVersion = 17 - if (JavaVersion.current().isJava9Compatible()) { - it.options.release = targetVersion - } -} diff --git a/build.gradle b/build.gradle index 7ab39e6..d168d1d 100644 --- a/build.gradle +++ b/build.gradle @@ -1,11 +1,10 @@ plugins { - id 'java' id 'fabric-loom' version '1.1-SNAPSHOT' apply false } allprojects { - apply plugin: 'java' apply plugin: 'maven-publish' + apply plugin: 'fabric-loom' group = project.maven_group version = project.maven_version @@ -34,7 +33,7 @@ allprojects { mavenJava(MavenPublication) { from components.java } - } + } repositories { maven { name 'altarik' @@ -46,13 +45,38 @@ allprojects { } } } -} -subprojects { + processResources { + inputs.property "version", project.version + + filesMatching("fabric.mod.json") { + expand "version": project.version + } + } + + 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" + + // The Minecraft launcher currently installs Java 8 for users, so your mod probably wants to target Java 8 too + // JDK 9 introduced a new way of specifying this that will make sure no newer classes or methods are used. + // We'll use that if it's available, but otherwise we'll use the older option. + def targetVersion = 17 + if (JavaVersion.current().isJava9Compatible()) { + it.options.release = targetVersion + } + } dependencies { testImplementation "org.junit.jupiter:junit-jupiter-api:${project.junit_version}" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${project.junit_version}" + minecraft "com.mojang:minecraft:${project.minecraft_version}" + mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" + modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" + modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" } java { @@ -66,11 +90,15 @@ subprojects { } -jar { +dependencies { + include subprojects.collect { project -> project } +} + +/*jar { dependsOn subprojects.jar subprojects.each { project -> from(project.jar) { into("META-INF/jars/") } } -} +}*/ diff --git a/gradle.properties b/gradle.properties index f76810d..16c0d2a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -org.gradle.jvmargs=-Xmx4G +org.gradle.jvmargs=-Xmx2G junit_version=5.9.0 diff --git a/settings.gradle b/settings.gradle index 16f164b..3f9b534 100644 --- a/settings.gradle +++ b/settings.gradle @@ -10,4 +10,4 @@ pluginManagement { } rootProject.name = 'Toolbox' -include(':Tasks', ':Database', /* ':Pagination' */) +include(':Tasks', ':Database', ':Pagination')