commit 290cf3fd22f5845aefcefbd61238cc93a2f262df Author: JFronny Date: Tue Jun 27 23:31:57 2023 +0200 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..3c37caf --- /dev/null +++ b/.gitignore @@ -0,0 +1,118 @@ +# 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/ + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar diff --git a/.woodpecker.yml b/.woodpecker.yml new file mode 100755 index 0000000..f2c1117 --- /dev/null +++ b/.woodpecker.yml @@ -0,0 +1 @@ +#link https://pages.frohnmeyer-wds.de/scripts/jfmod.yml \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100755 index 0000000..4dac429 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2023 + +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/README.md b/README.md new file mode 100644 index 0000000..7b8d37a --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +AsyncPackScan makes pack scanning in the resource pack organizer screen asynchronous. + +This has unintended consequences because no proper support for concurrency is in place, but massively speeds up the screen with some mod combinations. \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..0ce8d0b --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,14 @@ +import io.gitlab.jfronny.scripts.* + +plugins { + id("jfmod") version "1.3-SNAPSHOT" +} + +dependencies { + modImplementation("io.gitlab.jfronny.libjf:libjf-base:${prop("libjf_version")}") + + // For testing in dev environment + modLocalRuntime("net.fabricmc.fabric-api:fabric-api:0.83.0+1.20") + modLocalRuntime("io.gitlab.jfronny.libjf:libjf-devutil:${prop("libjf_version")}") + modLocalRuntime("com.terraformersmc:modmenu:7.0.1") +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..1f74513 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,16 @@ +# https://fabricmc.net/develop/ +minecraft_version=1.20 +yarn_mappings=build.1 +loader_version=0.14.21 + +maven_group=io.gitlab.jfronny +archives_base_name=async-pack-scan + +#modrinth_id=slyde +#modrinth_required_dependencies=libjf +#modrinth_optional_dependencies=modmenu +#curseforge_id=411386 +#curseforge_required_dependencies=libjf +#curseforge_optional_dependencies=modmenu + +libjf_version=3.8.0 diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000..381ab48 --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,9 @@ +pluginManagement { + repositories { + maven("https://maven.fabricmc.net/") // FabricMC + maven("https://maven.frohnmeyer-wds.de/artifacts") // scripts + gradlePluginPortal() + } +} + +rootProject.name = "async-pack-scan" diff --git a/src/client/java/io/gitlab/jfronny/aps/client/mixin/ResourcePackOrganizerMixin.java b/src/client/java/io/gitlab/jfronny/aps/client/mixin/ResourcePackOrganizerMixin.java new file mode 100644 index 0000000..c4b7716 --- /dev/null +++ b/src/client/java/io/gitlab/jfronny/aps/client/mixin/ResourcePackOrganizerMixin.java @@ -0,0 +1,53 @@ +package io.gitlab.jfronny.aps.client.mixin; + +import io.gitlab.jfronny.libjf.LibJf; +import net.minecraft.client.gui.screen.pack.ResourcePackOrganizer; +import net.minecraft.resource.ResourcePackManager; +import net.minecraft.resource.ResourcePackProfile; +import org.spongepowered.asm.mixin.*; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +@Mixin(ResourcePackOrganizer.class) +public class ResourcePackOrganizerMixin { + @Shadow + @Final + private ResourcePackManager resourcePackManager; + @Shadow @Final private List enabledPacks; + @Shadow @Final private List disabledPacks; + + @Unique private Future aps$packScan = null; + + /** + * @author JFronny + * @reason Make reloading asynchronous + */ + @Overwrite + public void refresh() { + if (aps$packScan != null) aps$packScan.cancel(true); + Future[] task = new Future[1]; + aps$packScan = task[0] = resourcePackManager.scanPacksAsync(() -> { + enabledPacks.retainAll(resourcePackManager.getProfiles()); + disabledPacks.clear(); + disabledPacks.addAll(resourcePackManager.getProfiles()); + disabledPacks.removeAll(enabledPacks); + if (aps$packScan == task[0]) aps$packScan = null; + }); + } + + @Inject(method = "apply()V", at = @At("HEAD")) + void onApply(CallbackInfo ci) { + if (aps$packScan != null) { + try { + aps$packScan.get(); + } catch (InterruptedException | ExecutionException e) { + LibJf.LOGGER.error("Pack scan was interrupted", e); + } + } + } +} diff --git a/src/client/resources/assets/async-pack-scan/icon.png b/src/client/resources/assets/async-pack-scan/icon.png new file mode 100644 index 0000000..cda9b84 Binary files /dev/null and b/src/client/resources/assets/async-pack-scan/icon.png differ diff --git a/src/client/resources/async-pack-scan.client.mixins.json b/src/client/resources/async-pack-scan.client.mixins.json new file mode 100644 index 0000000..2640283 --- /dev/null +++ b/src/client/resources/async-pack-scan.client.mixins.json @@ -0,0 +1,12 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "io.gitlab.jfronny.aps.client.mixin", + "compatibilityLevel": "JAVA_16", + "client": [ + "ResourcePackOrganizerMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/src/main/java/io/gitlab/jfronny/aps/AsyncResourcePackManager.java b/src/main/java/io/gitlab/jfronny/aps/AsyncResourcePackManager.java new file mode 100644 index 0000000..4429242 --- /dev/null +++ b/src/main/java/io/gitlab/jfronny/aps/AsyncResourcePackManager.java @@ -0,0 +1,9 @@ +package io.gitlab.jfronny.aps; + +import java.util.concurrent.Future; + +public interface AsyncResourcePackManager { + default Future scanPacksAsync(Runnable callback) { + throw new IllegalStateException("Async pack scan not injected"); + } +} diff --git a/src/main/java/io/gitlab/jfronny/aps/impl/VoidFuture.java b/src/main/java/io/gitlab/jfronny/aps/impl/VoidFuture.java new file mode 100644 index 0000000..7d0a570 --- /dev/null +++ b/src/main/java/io/gitlab/jfronny/aps/impl/VoidFuture.java @@ -0,0 +1,34 @@ +package io.gitlab.jfronny.aps.impl; + +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.*; + +public record VoidFuture(Future future) implements Future { + @Override + public boolean cancel(boolean mayInterruptIfRunning) { + return future.cancel(mayInterruptIfRunning); + } + + @Override + public boolean isCancelled() { + return future.isCancelled(); + } + + @Override + public boolean isDone() { + return future.isDone(); + } + + @Override + public Void get() throws InterruptedException, ExecutionException { + future.get(); + return null; + } + + @Override + public Void get(long timeout, @NotNull TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + future.get(timeout, unit); + return null; + } +} diff --git a/src/main/java/io/gitlab/jfronny/aps/mixin/ResourcePackManagerMixin.java b/src/main/java/io/gitlab/jfronny/aps/mixin/ResourcePackManagerMixin.java new file mode 100644 index 0000000..ddebf31 --- /dev/null +++ b/src/main/java/io/gitlab/jfronny/aps/mixin/ResourcePackManagerMixin.java @@ -0,0 +1,25 @@ +package io.gitlab.jfronny.aps.mixin; + +import io.gitlab.jfronny.aps.AsyncResourcePackManager; +import io.gitlab.jfronny.aps.impl.VoidFuture; +import net.minecraft.resource.ResourcePackManager; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.Future; + +@Mixin(ResourcePackManager.class) +public abstract class ResourcePackManagerMixin implements AsyncResourcePackManager { + private static final ForkJoinPool APS$POOL = ForkJoinPool.commonPool(); + @Shadow + public abstract void scanPacks(); + + @Override + public Future scanPacksAsync(Runnable callback) { + return new VoidFuture(APS$POOL.submit(() -> { + scanPacks(); + callback.run(); + })); + } +} diff --git a/src/main/resources/async-pack-scan.mixins.json b/src/main/resources/async-pack-scan.mixins.json new file mode 100644 index 0000000..5ce5911 --- /dev/null +++ b/src/main/resources/async-pack-scan.mixins.json @@ -0,0 +1,12 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "io.gitlab.jfronny.aps.mixin", + "compatibilityLevel": "JAVA_16", + "mixins": [ + "ResourcePackManagerMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..2e4584f --- /dev/null +++ b/src/main/resources/fabric.mod.json @@ -0,0 +1,34 @@ +{ + "schemaVersion": 1, + "id": "async-pack-scan", + "version": "${version}", + "name": "Async Pack Scan", + "description": "Speeds up the resource pack organizer screen", + "authors": ["JFronny"], + "contact": { + "email": "projects.contact@frohnmeyer-wds.de", + "homepage": "https://jfronny.gitlab.io", + "issues": "https://git.frohnmeyer-wds.de/JfMods/Slyde/issues", + "sources": "https://git.frohnmeyer-wds.de/JfMods/Slyde" + }, + "license": "MIT", + "environment": "*", + "icon": "assets/async-pack-scan/icon.png", + "mixins": [ + "async-pack-scan.mixins.json", + { + "config": "async-pack-scan.client.mixins.json", + "environment": "client" + } + ], + "depends": { + "fabricloader": ">=0.12.0", + "minecraft": "*", + "libjf-base": ">=2.1.3" + }, + "custom": { + "loom:injected_interfaces": { + "net/minecraft/class_3283": ["io/gitlab/jfronny/aps/AsyncResourcePackManager"] + } + } +} diff --git a/src/testmod/java/io/gitlab/jfronny/aps/testmod/mixin/ResourcePackManagerMixin.java b/src/testmod/java/io/gitlab/jfronny/aps/testmod/mixin/ResourcePackManagerMixin.java new file mode 100644 index 0000000..dcd74fd --- /dev/null +++ b/src/testmod/java/io/gitlab/jfronny/aps/testmod/mixin/ResourcePackManagerMixin.java @@ -0,0 +1,17 @@ +package io.gitlab.jfronny.aps.testmod.mixin; + +import io.gitlab.jfronny.libjf.LibJf; +import net.minecraft.resource.ResourcePackManager; +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.CallbackInfo; + +@Mixin(ResourcePackManager.class) +public class ResourcePackManagerMixin { + @Inject(at = @At("TAIL"), method = "scanPacks()V") + private void scanPacks(CallbackInfo info) throws InterruptedException { + Thread.sleep(100); + LibJf.LOGGER.info("Scanned Packs"); + } +} diff --git a/src/testmod/resources/async-pack-scan-testmod.mixins.json b/src/testmod/resources/async-pack-scan-testmod.mixins.json new file mode 100644 index 0000000..b10244b --- /dev/null +++ b/src/testmod/resources/async-pack-scan-testmod.mixins.json @@ -0,0 +1,12 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "io.gitlab.jfronny.aps.testmod.mixin", + "compatibilityLevel": "JAVA_16", + "mixins": [ + "ResourcePackManagerMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/src/testmod/resources/fabric.mod.json b/src/testmod/resources/fabric.mod.json new file mode 100644 index 0000000..231d9bd --- /dev/null +++ b/src/testmod/resources/fabric.mod.json @@ -0,0 +1,9 @@ +{ + "schemaVersion": 1, + "id": "async-pack-scan-testmod", + "name": "Async Pack Scan Testmod", + "version": "1.0", + "environment": "*", + "entrypoints": {}, + "mixins": ["async-pack-scan-testmod.mixins.json"] +} \ No newline at end of file