diff --git a/build.gradle b/build.gradle index 8f4ca0ec..0d07f630 100644 --- a/build.gradle +++ b/build.gradle @@ -202,6 +202,8 @@ def setUpLibrary(project) { implementation "org.apache.logging.log4j:log4j-api:2.19.0" implementation "org.apache.logging.log4j:log4j-core:2.19.0" + implementation "org.quiltmc.parsers:json:${project.rootProject.quilt_parsers_version}" + implementation project.dependencies.project(path: ':libraries:core', configuration: 'namedElements') libraries.each { libraryPath -> diff --git a/libraries/core/src/main/java/net/ornithemc/osl/core/api/util/Unit.java b/libraries/core/src/main/java/net/ornithemc/osl/core/api/util/Unit.java new file mode 100644 index 00000000..40887c58 --- /dev/null +++ b/libraries/core/src/main/java/net/ornithemc/osl/core/api/util/Unit.java @@ -0,0 +1,7 @@ +package net.ornithemc.osl.core.api.util; + +public enum Unit { + + INSTANCE + +} diff --git a/libraries/core/src/main/java/net/ornithemc/osl/core/api/util/function/IOSupplier.java b/libraries/core/src/main/java/net/ornithemc/osl/core/api/util/function/IOSupplier.java new file mode 100644 index 00000000..4fc2b8b2 --- /dev/null +++ b/libraries/core/src/main/java/net/ornithemc/osl/core/api/util/function/IOSupplier.java @@ -0,0 +1,9 @@ +package net.ornithemc.osl.core.api.util.function; + +import java.io.IOException; + +public interface IOSupplier { + + T get() throws IOException; + +} diff --git a/libraries/core/src/main/java/net/ornithemc/osl/core/impl/util/Util.java b/libraries/core/src/main/java/net/ornithemc/osl/core/impl/util/Util.java new file mode 100644 index 00000000..68b10627 --- /dev/null +++ b/libraries/core/src/main/java/net/ornithemc/osl/core/impl/util/Util.java @@ -0,0 +1,30 @@ +package net.ornithemc.osl.core.impl.util; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +public final class Util { + + public static CompletableFuture> sequence(List> futures) { + List results = new ArrayList<>(futures.size()); + + CompletableFuture[] sequence = new CompletableFuture[futures.size()]; + CompletableFuture failure = new CompletableFuture<>(); + + futures.forEach(future -> { + int i = results.size(); + results.add(null); + + sequence[i] = future.whenComplete((result, exception) -> { + if (exception != null) { + failure.completeExceptionally(exception); + } else { + results.set(i, result); + } + }); + }); + + return CompletableFuture.allOf(sequence).applyToEither(failure, v -> results); + } +} diff --git a/libraries/localization/README.md b/libraries/localization/README.md new file mode 100644 index 00000000..2ff3ca0a --- /dev/null +++ b/libraries/localization/README.md @@ -0,0 +1,3 @@ +# Localization API + +The Localization API provides a consistent access point for localized text, and adds support for localization in versions that do not natively do so. diff --git a/libraries/localization/build.gradle b/libraries/localization/build.gradle new file mode 100644 index 00000000..7bb43400 --- /dev/null +++ b/libraries/localization/build.gradle @@ -0,0 +1,5 @@ +setUpLibrary(project) + +dependencies { + implementation 'com.google.code.gson:gson:2.8.0' +} diff --git a/libraries/localization/gradle.properties b/libraries/localization/gradle.properties new file mode 100644 index 00000000..2fd44926 --- /dev/null +++ b/libraries/localization/gradle.properties @@ -0,0 +1,6 @@ +library_id = localization +library_name = Localization +library_description = Localization API and events. +library_version = 0.1.0-alpha.1 + +osl_dependencies = core:>=0.7.0,text-components:>=0.1.0-,resource-loader:>=0.6.0 diff --git a/libraries/resource-loader/resource-loader-mc11w49a-mc1.2.5/build.gradle b/libraries/localization/localization-mc11w49a-mc1.5.2/build.gradle similarity index 100% rename from libraries/resource-loader/resource-loader-mc11w49a-mc1.2.5/build.gradle rename to libraries/localization/localization-mc11w49a-mc1.5.2/build.gradle diff --git a/libraries/localization/localization-mc11w49a-mc1.5.2/gradle.properties b/libraries/localization/localization-mc11w49a-mc1.5.2/gradle.properties new file mode 100644 index 00000000..5cde7a60 --- /dev/null +++ b/libraries/localization/localization-mc11w49a-mc1.5.2/gradle.properties @@ -0,0 +1,6 @@ +min_mc_version = 11w49a +max_mc_version = 1.5.2 +minecraft_dependency = >=1.1-alpha.11.49.a <=1.5.2 + +minecraft_version = 1.5.2 +client_nests_build = 6 diff --git a/libraries/localization/localization-mc11w49a-mc1.5.2/src/main/java/net/ornithemc/osl/localization/impl/mixin/client/LanguageAccess.java b/libraries/localization/localization-mc11w49a-mc1.5.2/src/main/java/net/ornithemc/osl/localization/impl/mixin/client/LanguageAccess.java new file mode 100644 index 00000000..5a103f5d --- /dev/null +++ b/libraries/localization/localization-mc11w49a-mc1.5.2/src/main/java/net/ornithemc/osl/localization/impl/mixin/client/LanguageAccess.java @@ -0,0 +1,16 @@ +package net.ornithemc.osl.localization.impl.mixin.client; + +import java.util.Properties; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import net.minecraft.locale.Language; + +@Mixin(Language.class) +public interface LanguageAccess { + + @Accessor("translations") + Properties accessTranslations(); + +} diff --git a/libraries/localization/localization-mc11w49a-mc1.5.2/src/main/java/net/ornithemc/osl/localization/impl/mixin/client/LanguageMixin.java b/libraries/localization/localization-mc11w49a-mc1.5.2/src/main/java/net/ornithemc/osl/localization/impl/mixin/client/LanguageMixin.java new file mode 100644 index 00000000..d5506ceb --- /dev/null +++ b/libraries/localization/localization-mc11w49a-mc1.5.2/src/main/java/net/ornithemc/osl/localization/impl/mixin/client/LanguageMixin.java @@ -0,0 +1,57 @@ +package net.ornithemc.osl.localization.impl.mixin.client; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.locale.Language; + +import net.ornithemc.osl.localization.impl.Localization; + +@Mixin(Language.class) +public class LanguageMixin { + + @Shadow + private static Language INSTANCE; + + @Shadow + private String currentCode; + + @Inject( + method = "", + at = @At( + value = "TAIL" + ) + ) + private static void osl$localization$initLocale(CallbackInfo ci) { + Localization.getLocale().wrap(((LanguageAccess) INSTANCE).accessTranslations()); + } + + @Inject( + method = "load", + at = @At( + value = "TAIL" + ) + ) + private void osl$localization$reloadLanguageManager(CallbackInfo ci) { + // each ServerPlayerEntity also holds an instance of this class + if ((Language) (Object) this == INSTANCE) { + Localization.reloadLanguageManager(); + } + } + + @Inject( + method = "loadLanguage", + at = @At( + value = "TAIL" + ) + ) + private void osl$localization$setLanguage(CallbackInfo ci) { + // each ServerPlayerEntity also holds an instance of this class + if ((Language) (Object) this == INSTANCE) { + Localization.getLanguageManager().setSelectedLanguage(this.currentCode); + } + } +} diff --git a/libraries/localization/localization-mc11w49a-mc1.5.2/src/main/resources/fabric.mod.json b/libraries/localization/localization-mc11w49a-mc1.5.2/src/main/resources/fabric.mod.json new file mode 100644 index 00000000..2089d03d --- /dev/null +++ b/libraries/localization/localization-mc11w49a-mc1.5.2/src/main/resources/fabric.mod.json @@ -0,0 +1,27 @@ +{ + "schemaVersion": 1, + "id": "osl-localization", + "version": "0.1.0-alpha.1+mc11w49a-mc1.5.2", + "environment": "*", + "mixins": [ + "osl.localization.mixins.json" + ], + "depends": { + "fabricloader": "\u003e\u003d0.18.0", + "minecraft": "\u003e\u003d1.1-alpha.11.49.a \u003c\u003d1.5.2", + "osl-core": "\u003e\u003d0.7.0", + "osl-text-components": "\u003e\u003d0.1.0-", + "osl-resource-loader": "\u003e\u003d0.6.0" + }, + "name": "OSL Localization", + "description": "Localization API and events.", + "authors": [ + "OrnitheMC" + ], + "contact": { + "homepage": "https://ornithemc.net/", + "issues": "https://github.com/OrnitheMC/ornithe-standard-libraries/issues", + "sources": "https://github.com/OrnitheMC/ornithe-standard-libraries" + }, + "license": "Apache-2.0" +} \ No newline at end of file diff --git a/libraries/resource-loader/resource-loader-mca1.2.2-mc11w48a/src/main/resources/osl.resource-loader.mixins.json b/libraries/localization/localization-mc11w49a-mc1.5.2/src/main/resources/osl.localization.mixins.json similarity index 68% rename from libraries/resource-loader/resource-loader-mca1.2.2-mc11w48a/src/main/resources/osl.resource-loader.mixins.json rename to libraries/localization/localization-mc11w49a-mc1.5.2/src/main/resources/osl.localization.mixins.json index 59663fcd..35f377fb 100644 --- a/libraries/resource-loader/resource-loader-mca1.2.2-mc11w48a/src/main/resources/osl.resource-loader.mixins.json +++ b/libraries/localization/localization-mc11w49a-mc1.5.2/src/main/resources/osl.localization.mixins.json @@ -1,12 +1,12 @@ { "required": true, "minVersion": "0.8", - "package": "net.ornithemc.osl.resource.loader.impl.mixin", + "package": "net.ornithemc.osl.localization.impl.mixin", "compatibilityLevel": "JAVA_8", "mixins": [ ], "client": [ - "client.TexturePackMixin", + "client.LanguageAccess", "client.LanguageMixin" ], "server": [ diff --git a/libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/build.gradle b/libraries/localization/localization-mc13w26a-mc18w01a/build.gradle similarity index 100% rename from libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/build.gradle rename to libraries/localization/localization-mc13w26a-mc18w01a/build.gradle diff --git a/libraries/localization/localization-mc13w26a-mc18w01a/gradle.properties b/libraries/localization/localization-mc13w26a-mc18w01a/gradle.properties new file mode 100644 index 00000000..175faf2d --- /dev/null +++ b/libraries/localization/localization-mc13w26a-mc18w01a/gradle.properties @@ -0,0 +1,8 @@ +min_mc_version = 13w26a +max_mc_version = 18w01a +minecraft_dependency = >=1.6-alpha.13.26.a <=1.13-alpha.18.1.a + +minecraft_version = 1.8.2-pre4 +raven_build = 1 +sparrow_build = 1 +nests_build = 3 diff --git a/libraries/localization/localization-mc13w26a-mc18w01a/src/main/java/net/ornithemc/osl/localization/impl/access/SimpleResourceAccess.java b/libraries/localization/localization-mc13w26a-mc18w01a/src/main/java/net/ornithemc/osl/localization/impl/access/SimpleResourceAccess.java new file mode 100644 index 00000000..716de1f9 --- /dev/null +++ b/libraries/localization/localization-mc13w26a-mc18w01a/src/main/java/net/ornithemc/osl/localization/impl/access/SimpleResourceAccess.java @@ -0,0 +1,9 @@ +package net.ornithemc.osl.localization.impl.access; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; + +public interface SimpleResourceAccess { + + NamespacedIdentifier osl$localization$getLocation(); + +} diff --git a/libraries/localization/localization-mc13w26a-mc18w01a/src/main/java/net/ornithemc/osl/localization/impl/mixin/client/LanguageManagerMixin.java b/libraries/localization/localization-mc13w26a-mc18w01a/src/main/java/net/ornithemc/osl/localization/impl/mixin/client/LanguageManagerMixin.java new file mode 100644 index 00000000..6c87eab9 --- /dev/null +++ b/libraries/localization/localization-mc13w26a-mc18w01a/src/main/java/net/ornithemc/osl/localization/impl/mixin/client/LanguageManagerMixin.java @@ -0,0 +1,44 @@ +package net.ornithemc.osl.localization.impl.mixin.client; + +import java.util.Map; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.client.resource.language.LanguageManager; + +import net.ornithemc.osl.localization.api.language.Language; +import net.ornithemc.osl.localization.impl.Localization; + +@Mixin(LanguageManager.class) +public class LanguageManagerMixin { + + @Shadow + private Map languages; + + @Shadow + private String currentCode; + + @Inject( + method = "", + at = @At( + value = "TAIL" + ) + ) + private void osl$localization$initLanguageManager(CallbackInfo ci) { + Localization.getLanguageManager().wrap(this.languages, net.minecraft.client.resource.language.Language::new); + } + + @Inject( + method = "setLanguage", + at = @At( + value = "TAIL" + ) + ) + private void osl$localization$setLanguage(CallbackInfo ci) { + Localization.getLanguageManager().setSelectedLanguage(this.currentCode); + } +} diff --git a/libraries/localization/localization-mc13w26a-mc18w01a/src/main/java/net/ornithemc/osl/localization/impl/mixin/client/LanguageMixin.java b/libraries/localization/localization-mc13w26a-mc18w01a/src/main/java/net/ornithemc/osl/localization/impl/mixin/client/LanguageMixin.java new file mode 100644 index 00000000..08c38f07 --- /dev/null +++ b/libraries/localization/localization-mc13w26a-mc18w01a/src/main/java/net/ornithemc/osl/localization/impl/mixin/client/LanguageMixin.java @@ -0,0 +1,39 @@ +package net.ornithemc.osl.localization.impl.mixin.client; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import net.ornithemc.osl.localization.api.language.Language; + +@Mixin(net.minecraft.client.resource.language.Language.class) +public class LanguageMixin implements Language { + + @Shadow + private String code; + @Shadow + private String region; + @Shadow + private String name; + @Shadow + private boolean bidirectional; + + @Override + public String code() { + return this.code; + } + + @Override + public String name() { + return this.name; + } + + @Override + public String region() { + return this.region; + } + + @Override + public boolean bidirectional() { + return this.bidirectional; + } +} diff --git a/libraries/localization/localization-mc13w26a-mc18w01a/src/main/java/net/ornithemc/osl/localization/impl/mixin/client/LocaleMixin.java b/libraries/localization/localization-mc13w26a-mc18w01a/src/main/java/net/ornithemc/osl/localization/impl/mixin/client/LocaleMixin.java new file mode 100644 index 00000000..dbba71f3 --- /dev/null +++ b/libraries/localization/localization-mc13w26a-mc18w01a/src/main/java/net/ornithemc/osl/localization/impl/mixin/client/LocaleMixin.java @@ -0,0 +1,118 @@ +package net.ornithemc.osl.localization.impl.mixin.client; + +import java.io.IOException; +import java.io.InputStream; +import java.util.List; +import java.util.Map; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.llamalad7.mixinextras.sugar.Local; + +import net.minecraft.client.resource.Resource; +import net.minecraft.client.resource.language.Locale; +import net.minecraft.client.resource.manager.ResourceManager; +import net.minecraft.resource.Identifier; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.localization.impl.Localization; +import net.ornithemc.osl.resource.loader.impl.resource.ResourceLocationAccess; +import net.ornithemc.osl.resource.loader.impl.resource.pack.ResourcePacks; + +@Mixin(Locale.class) +public class LocaleMixin { + + @Shadow + private Map translations; + + @Shadow + private void load(List resources) { } + + @Inject( + method = "", + at = @At( + value = "TAIL" + ) + ) + private void osl$localization$initLocale(CallbackInfo ci) { + Localization.getLocale().wrap(this.translations); + } + + @Inject( + method = "load(Lnet/minecraft/client/resource/manager/ResourceManager;Ljava/util/List;)V", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/resource/manager/ResourceManager;getResources(Lnet/minecraft/resource/Identifier;)Ljava/util/List;" + ) + ) + private void osl$localization$loadExtraTranslations(ResourceManager resourceManager, List languageCodes, CallbackInfo ci, + @Local(ordinal = 0) String languageCode, @Local(ordinal = 2) String namespace) { + String pathFormat = "lang/%s%s"; + String[] paths; + + if (ResourcePacks.getSupportedFormat() < 3) { + paths = new String[] { + String.format(pathFormat, languageCode, ".json"), + String.format(pathFormat, languageCode.toLowerCase(java.util.Locale.ROOT), ".lang"), + String.format(pathFormat, languageCode.toLowerCase(java.util.Locale.ROOT), ".json") + }; + } else { + paths = new String[] { + String.format(pathFormat, languageCode, ".json") + }; + } + + + for (String path : paths) { + try { + load(resourceManager.getResources(new Identifier(namespace, path))); + } catch (IOException ignored) { + } + } + } + + @Inject( + method = "load(Lnet/minecraft/client/resource/manager/ResourceManager;Ljava/util/List;)V", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/resource/manager/ResourceManager;getResources(Lnet/minecraft/resource/Identifier;)Ljava/util/List;" + ) + ) + private void osl$localization$localeReloaded(CallbackInfo ci) { + Localization.getLocale().setLastUpdateTime(); + } + + @WrapOperation( + method = "load(Ljava/util/List;)V", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/resource/language/Locale;load(Ljava/io/InputStream;)V" + ) + ) + private void osl$localization$loadTranslationsFromJsonFile(Locale instance, InputStream is, Operation original, @Local Resource resource) throws IOException{ + NamespacedIdentifier location = this.resourceLocation(resource); + + if (location.identifier().endsWith(".json")){ + Localization.getLocale().loadFromJson(is); + } else { + original.call(instance, is); // load from .lang + } + } + + @Unique + private NamespacedIdentifier resourceLocation(Resource resource) throws IOException { + // in 14w21b and earlier, there is no accessor method in Vanilla! + if (resource instanceof ResourceLocationAccess) { + return ((ResourceLocationAccess) resource).resourceLocation(); + } else { + return (NamespacedIdentifier) resource.getLocation(); + } + } +} diff --git a/libraries/localization/localization-mc13w26a-mc18w01a/src/main/resources/fabric.mod.json b/libraries/localization/localization-mc13w26a-mc18w01a/src/main/resources/fabric.mod.json new file mode 100644 index 00000000..7ad77836 --- /dev/null +++ b/libraries/localization/localization-mc13w26a-mc18w01a/src/main/resources/fabric.mod.json @@ -0,0 +1,28 @@ +{ + "schemaVersion": 1, + "id": "osl-localization", + "version": "0.1.0-alpha.1+mc13w26a-mc18w01a", + "environment": "*", + "mixins": [ + "osl.localization.mixins.json" + ], + "accessWidener": "osl.localization.classtweaker", + "depends": { + "fabricloader": "\u003e\u003d0.18.0", + "minecraft": "\u003e\u003d1.6-alpha.13.26.a \u003c\u003d1.13-alpha.18.1.a", + "osl-core": "\u003e\u003d0.7.0", + "osl-text-components": "\u003e\u003d0.1.0-", + "osl-resource-loader": "\u003e\u003d0.6.0" + }, + "name": "OSL Localization", + "description": "Localization API and events.", + "authors": [ + "OrnitheMC" + ], + "contact": { + "homepage": "https://ornithemc.net/", + "issues": "https://github.com/OrnitheMC/ornithe-standard-libraries/issues", + "sources": "https://github.com/OrnitheMC/ornithe-standard-libraries" + }, + "license": "Apache-2.0" +} \ No newline at end of file diff --git a/libraries/localization/localization-mc13w26a-mc18w01a/src/main/resources/osl.localization.classtweaker b/libraries/localization/localization-mc13w26a-mc18w01a/src/main/resources/osl.localization.classtweaker new file mode 100644 index 00000000..c90e8a5d --- /dev/null +++ b/libraries/localization/localization-mc13w26a-mc18w01a/src/main/resources/osl.localization.classtweaker @@ -0,0 +1,3 @@ +classTweaker v1 named + +inject-interface net/minecraft/client/resource/language/Language net/ornithemc/osl/localization/api/language/Language \ No newline at end of file diff --git a/libraries/resource-loader/resource-loader-mc16w32a-mc1.12.2/src/main/resources/osl.resource-loader.mixins.json b/libraries/localization/localization-mc13w26a-mc18w01a/src/main/resources/osl.localization.mixins.json similarity index 53% rename from libraries/resource-loader/resource-loader-mc16w32a-mc1.12.2/src/main/resources/osl.resource-loader.mixins.json rename to libraries/localization/localization-mc13w26a-mc18w01a/src/main/resources/osl.localization.mixins.json index d6d51dc8..219f3ccb 100644 --- a/libraries/resource-loader/resource-loader-mc16w32a-mc1.12.2/src/main/resources/osl.resource-loader.mixins.json +++ b/libraries/localization/localization-mc13w26a-mc18w01a/src/main/resources/osl.localization.mixins.json @@ -1,14 +1,14 @@ { "required": true, "minVersion": "0.8", - "package": "net.ornithemc.osl.resource.loader.impl.mixin", + "package": "net.ornithemc.osl.localization.impl.mixin", "compatibilityLevel": "JAVA_8", "mixins": [ ], "client": [ - "client.CustomResourcePackInvoker", - "client.LocaleMixin", - "client.MinecraftMixin" + "client.LanguageManagerMixin", + "client.LanguageMixin", + "client.LocaleMixin" ], "server": [ ], diff --git a/libraries/resource-loader/resource-loader-mc16w32a-mc1.12.2/build.gradle b/libraries/localization/localization-mc18w02a-mc1.14.4/build.gradle similarity index 100% rename from libraries/resource-loader/resource-loader-mc16w32a-mc1.12.2/build.gradle rename to libraries/localization/localization-mc18w02a-mc1.14.4/build.gradle diff --git a/libraries/localization/localization-mc18w02a-mc1.14.4/gradle.properties b/libraries/localization/localization-mc18w02a-mc1.14.4/gradle.properties new file mode 100644 index 00000000..09201156 --- /dev/null +++ b/libraries/localization/localization-mc18w02a-mc1.14.4/gradle.properties @@ -0,0 +1,5 @@ +min_mc_version = 18w02a +max_mc_version = 1.14.4 +minecraft_dependency = >=1.13-alpha.18.2.a <=1.14.4 + +minecraft_version = 1.14.4 diff --git a/libraries/localization/localization-mc18w02a-mc1.14.4/src/main/java/net/ornithemc/osl/localization/impl/mixin/client/LanguageManagerMixin.java b/libraries/localization/localization-mc18w02a-mc1.14.4/src/main/java/net/ornithemc/osl/localization/impl/mixin/client/LanguageManagerMixin.java new file mode 100644 index 00000000..6c87eab9 --- /dev/null +++ b/libraries/localization/localization-mc18w02a-mc1.14.4/src/main/java/net/ornithemc/osl/localization/impl/mixin/client/LanguageManagerMixin.java @@ -0,0 +1,44 @@ +package net.ornithemc.osl.localization.impl.mixin.client; + +import java.util.Map; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.client.resource.language.LanguageManager; + +import net.ornithemc.osl.localization.api.language.Language; +import net.ornithemc.osl.localization.impl.Localization; + +@Mixin(LanguageManager.class) +public class LanguageManagerMixin { + + @Shadow + private Map languages; + + @Shadow + private String currentCode; + + @Inject( + method = "", + at = @At( + value = "TAIL" + ) + ) + private void osl$localization$initLanguageManager(CallbackInfo ci) { + Localization.getLanguageManager().wrap(this.languages, net.minecraft.client.resource.language.Language::new); + } + + @Inject( + method = "setLanguage", + at = @At( + value = "TAIL" + ) + ) + private void osl$localization$setLanguage(CallbackInfo ci) { + Localization.getLanguageManager().setSelectedLanguage(this.currentCode); + } +} diff --git a/libraries/localization/localization-mc18w02a-mc1.14.4/src/main/java/net/ornithemc/osl/localization/impl/mixin/client/LanguageMixin.java b/libraries/localization/localization-mc18w02a-mc1.14.4/src/main/java/net/ornithemc/osl/localization/impl/mixin/client/LanguageMixin.java new file mode 100644 index 00000000..08c38f07 --- /dev/null +++ b/libraries/localization/localization-mc18w02a-mc1.14.4/src/main/java/net/ornithemc/osl/localization/impl/mixin/client/LanguageMixin.java @@ -0,0 +1,39 @@ +package net.ornithemc.osl.localization.impl.mixin.client; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import net.ornithemc.osl.localization.api.language.Language; + +@Mixin(net.minecraft.client.resource.language.Language.class) +public class LanguageMixin implements Language { + + @Shadow + private String code; + @Shadow + private String region; + @Shadow + private String name; + @Shadow + private boolean bidirectional; + + @Override + public String code() { + return this.code; + } + + @Override + public String name() { + return this.name; + } + + @Override + public String region() { + return this.region; + } + + @Override + public boolean bidirectional() { + return this.bidirectional; + } +} diff --git a/libraries/localization/localization-mc18w02a-mc1.14.4/src/main/java/net/ornithemc/osl/localization/impl/mixin/client/LocaleMixin.java b/libraries/localization/localization-mc18w02a-mc1.14.4/src/main/java/net/ornithemc/osl/localization/impl/mixin/client/LocaleMixin.java new file mode 100644 index 00000000..b2b8d313 --- /dev/null +++ b/libraries/localization/localization-mc18w02a-mc1.14.4/src/main/java/net/ornithemc/osl/localization/impl/mixin/client/LocaleMixin.java @@ -0,0 +1,90 @@ +package net.ornithemc.osl.localization.impl.mixin.client; + +import java.io.IOException; +import java.io.InputStream; +import java.util.List; +import java.util.Map; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.llamalad7.mixinextras.sugar.Local; + +import net.minecraft.client.resource.language.Locale; +import net.minecraft.resource.Identifier; +import net.minecraft.resource.Resource; +import net.minecraft.resource.manager.ResourceManager; + +import net.ornithemc.osl.localization.impl.Localization; + +@Mixin(Locale.class) +public class LocaleMixin { + + @Final + @Shadow + private Map translations; + + @Shadow + private void load(List resources) { } + + @Inject( + method = "", + at = @At( + value = "TAIL" + ) + ) + private void osl$localization$initLocale(CallbackInfo ci) { + // ensure OSL's Locale is backed by the same map + // this way changes to one are reflected in the other + Localization.getLocale().wrap(this.translations); + } + + @Inject( + method = "load(Lnet/minecraft/resource/manager/ResourceManager;Ljava/util/List;)V", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/resource/manager/ResourceManager;getResources(Lnet/minecraft/resource/Identifier;)Ljava/util/List;" + ) + ) + private void osl$localization$loadExtraTranslations(ResourceManager resourceManager, List languageCodes, CallbackInfo ci, + @Local(ordinal = 0) String languageCode, @Local(ordinal = 2) String namespace) { + String path = String.format("lang/%s.lang", languageCode); + + try { + load(resourceManager.getResources(new Identifier(namespace, path))); + } catch (IOException ignored) { + } + } + + @Inject( + method = "load(Lnet/minecraft/resource/manager/ResourceManager;Ljava/util/List;)V", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/resource/manager/ResourceManager;getResources(Lnet/minecraft/resource/Identifier;)Ljava/util/List;" + ) + ) + private void osl$localization$localeReloaded(CallbackInfo ci) { + Localization.getLocale().setLastUpdateTime(); + } + + @WrapOperation( + method = "load(Ljava/util/List;)V", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/resource/language/Locale;load(Ljava/io/InputStream;)V" + ) + ) + private void osl$localization$loadTranslationsFromLangFile(Locale instance, InputStream is, Operation original, @Local Resource resource) throws IOException{ + if (resource.getLocation().getPath().endsWith(".lang")){ + Localization.getLocale().loadFromLang(is); + } else { + original.call(instance, is); // load from .json + } + } +} diff --git a/libraries/localization/localization-mc18w02a-mc1.14.4/src/main/resources/fabric.mod.json b/libraries/localization/localization-mc18w02a-mc1.14.4/src/main/resources/fabric.mod.json new file mode 100644 index 00000000..ac4b0636 --- /dev/null +++ b/libraries/localization/localization-mc18w02a-mc1.14.4/src/main/resources/fabric.mod.json @@ -0,0 +1,28 @@ +{ + "schemaVersion": 1, + "id": "osl-localization", + "version": "0.1.0-alpha.1+mc18w02a-mc1.14.4", + "environment": "*", + "mixins": [ + "osl.localization.mixins.json" + ], + "accessWidener": "osl.localization.classtweaker", + "depends": { + "fabricloader": "\u003e\u003d0.18.0", + "minecraft": "\u003e\u003d1.13-alpha.18.2.a \u003c\u003d1.14.4", + "osl-core": "\u003e\u003d0.7.0", + "osl-text-components": "\u003e\u003d0.1.0-", + "osl-resource-loader": "\u003e\u003d0.6.0" + }, + "name": "OSL Localization", + "description": "Localization API and events.", + "authors": [ + "OrnitheMC" + ], + "contact": { + "homepage": "https://ornithemc.net/", + "issues": "https://github.com/OrnitheMC/ornithe-standard-libraries/issues", + "sources": "https://github.com/OrnitheMC/ornithe-standard-libraries" + }, + "license": "Apache-2.0" +} \ No newline at end of file diff --git a/libraries/localization/localization-mc18w02a-mc1.14.4/src/main/resources/osl.localization.classtweaker b/libraries/localization/localization-mc18w02a-mc1.14.4/src/main/resources/osl.localization.classtweaker new file mode 100644 index 00000000..c90e8a5d --- /dev/null +++ b/libraries/localization/localization-mc18w02a-mc1.14.4/src/main/resources/osl.localization.classtweaker @@ -0,0 +1,3 @@ +classTweaker v1 named + +inject-interface net/minecraft/client/resource/language/Language net/ornithemc/osl/localization/api/language/Language \ No newline at end of file diff --git a/libraries/localization/localization-mc18w02a-mc1.14.4/src/main/resources/osl.localization.mixins.json b/libraries/localization/localization-mc18w02a-mc1.14.4/src/main/resources/osl.localization.mixins.json new file mode 100644 index 00000000..219f3ccb --- /dev/null +++ b/libraries/localization/localization-mc18w02a-mc1.14.4/src/main/resources/osl.localization.mixins.json @@ -0,0 +1,18 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "net.ornithemc.osl.localization.impl.mixin", + "compatibilityLevel": "JAVA_8", + "mixins": [ + ], + "client": [ + "client.LanguageManagerMixin", + "client.LanguageMixin", + "client.LocaleMixin" + ], + "server": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/build.gradle b/libraries/localization/localization-mcb1.0-mc11w48a/build.gradle similarity index 100% rename from libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/build.gradle rename to libraries/localization/localization-mcb1.0-mc11w48a/build.gradle diff --git a/libraries/localization/localization-mcb1.0-mc11w48a/gradle.properties b/libraries/localization/localization-mcb1.0-mc11w48a/gradle.properties new file mode 100644 index 00000000..d6ad959b --- /dev/null +++ b/libraries/localization/localization-mcb1.0-mc11w48a/gradle.properties @@ -0,0 +1,6 @@ +min_mc_version = b1.0 +max_mc_version = 11w48a +minecraft_dependency = >=1.0.0-beta.0 <=1.1-alpha.11.48.a + +minecraft_version = 11w48a +client_nests_build = 11 diff --git a/libraries/localization/localization-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/localization/impl/mixin/client/LanguageMixin.java b/libraries/localization/localization-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/localization/impl/mixin/client/LanguageMixin.java new file mode 100644 index 00000000..0d3a7e3c --- /dev/null +++ b/libraries/localization/localization-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/localization/impl/mixin/client/LanguageMixin.java @@ -0,0 +1,34 @@ +package net.ornithemc.osl.localization.impl.mixin.client; + +import java.io.IOException; +import java.util.Properties; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.locale.Language; + +import net.ornithemc.osl.localization.impl.Localization; + +@Mixin(Language.class) +public class LanguageMixin { + + @Shadow + private Properties translations; + + @Inject( + method = "", + at = @At( + value = "TAIL" + ) + ) + private void osl$localization$initLocalization(CallbackInfo ci) throws IOException { + Localization.getLocale().wrap(this.translations); + + Localization.reloadLanguageManager(); + Localization.reloadLocale(); + } +} diff --git a/libraries/localization/localization-mcb1.0-mc11w48a/src/main/resources/fabric.mod.json b/libraries/localization/localization-mcb1.0-mc11w48a/src/main/resources/fabric.mod.json new file mode 100644 index 00000000..562143f7 --- /dev/null +++ b/libraries/localization/localization-mcb1.0-mc11w48a/src/main/resources/fabric.mod.json @@ -0,0 +1,27 @@ +{ + "schemaVersion": 1, + "id": "osl-localization", + "version": "0.1.0-alpha.1+mcb1.0-mc11w48a", + "environment": "*", + "mixins": [ + "osl.localization.mixins.json" + ], + "depends": { + "fabricloader": "\u003e\u003d0.18.0", + "minecraft": "\u003e\u003d1.0.0-beta.0 \u003c\u003d1.1-alpha.11.48.a", + "osl-core": "\u003e\u003d0.7.0", + "osl-text-components": "\u003e\u003d0.1.0-", + "osl-resource-loader": "\u003e\u003d0.6.0" + }, + "name": "OSL Localization", + "description": "Localization API and events.", + "authors": [ + "OrnitheMC" + ], + "contact": { + "homepage": "https://ornithemc.net/", + "issues": "https://github.com/OrnitheMC/ornithe-standard-libraries/issues", + "sources": "https://github.com/OrnitheMC/ornithe-standard-libraries" + }, + "license": "Apache-2.0" +} \ No newline at end of file diff --git a/libraries/localization/localization-mcb1.0-mc11w48a/src/main/resources/osl.localization.mixins.json b/libraries/localization/localization-mcb1.0-mc11w48a/src/main/resources/osl.localization.mixins.json new file mode 100644 index 00000000..b75a5ba4 --- /dev/null +++ b/libraries/localization/localization-mcb1.0-mc11w48a/src/main/resources/osl.localization.mixins.json @@ -0,0 +1,16 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "net.ornithemc.osl.localization.impl.mixin", + "compatibilityLevel": "JAVA_8", + "mixins": [ + ], + "client": [ + "client.LanguageMixin" + ], + "server": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/libraries/localization/src/main/java/net/ornithemc/osl/localization/api/L10n.java b/libraries/localization/src/main/java/net/ornithemc/osl/localization/api/L10n.java new file mode 100644 index 00000000..e694041e --- /dev/null +++ b/libraries/localization/src/main/java/net/ornithemc/osl/localization/api/L10n.java @@ -0,0 +1,47 @@ +package net.ornithemc.osl.localization.api; + +import net.ornithemc.osl.localization.api.language.Language; +import net.ornithemc.osl.localization.impl.Localization; + +/** + * Utility methods for localization. + */ +public final class L10n { + + /** + * @return the currently selected language for localization. + */ + public static Language getLanguage() { + return Localization.getLanguage(); + } + + /** + * @return the localization of the given translation key. + */ + public static String get(String key) { + return Localization.get(key); + } + + /** + * @return the localization of the given translation key, + * with the given arguments applied. + */ + public static String get(String key, Object... args) { + return Localization.get(key, args); + } + + /** + * @return the localization of the given translation key, + * or the given default value if none exists. + */ + public static String getOrDefault(String key, String defaultLocalization) { + return Localization.getOrDefault(key, defaultLocalization); + } + + /** + * @return whether a localization exists for the given translation key. + */ + public static boolean has(String key) { + return Localization.has(key); + } +} diff --git a/libraries/localization/src/main/java/net/ornithemc/osl/localization/api/language/Language.java b/libraries/localization/src/main/java/net/ornithemc/osl/localization/api/language/Language.java new file mode 100644 index 00000000..e95b19ad --- /dev/null +++ b/libraries/localization/src/main/java/net/ornithemc/osl/localization/api/language/Language.java @@ -0,0 +1,18 @@ +package net.ornithemc.osl.localization.api.language; + +public interface Language { + + String code(); + + String name(); + + String region(); + + boolean bidirectional(); + + interface Factory { + + Language create(String code, String name, String region, boolean bidirectional); + + } +} diff --git a/libraries/localization/src/main/java/net/ornithemc/osl/localization/api/language/LanguageMetadata.java b/libraries/localization/src/main/java/net/ornithemc/osl/localization/api/language/LanguageMetadata.java new file mode 100644 index 00000000..26ac4d02 --- /dev/null +++ b/libraries/localization/src/main/java/net/ornithemc/osl/localization/api/language/LanguageMetadata.java @@ -0,0 +1,16 @@ +package net.ornithemc.osl.localization.api.language; + +import java.util.Collection; + +import net.ornithemc.osl.localization.impl.language.SimpleLanguageMetadata; +import net.ornithemc.osl.resource.loader.api.resource.ResourceMetadata; + +public interface LanguageMetadata { + + String NAME = "language"; + ResourceMetadata.Section.Serializer SERIALIZER = SimpleLanguageMetadata.SERIALIZER; + ResourceMetadata.Section SECTION = ResourceMetadata.Section.of(NAME, SERIALIZER); + + Collection getLanguages(); + +} diff --git a/libraries/localization/src/main/java/net/ornithemc/osl/localization/impl/Locale.java b/libraries/localization/src/main/java/net/ornithemc/osl/localization/impl/Locale.java new file mode 100644 index 00000000..69c453f6 --- /dev/null +++ b/libraries/localization/src/main/java/net/ornithemc/osl/localization/impl/Locale.java @@ -0,0 +1,208 @@ +package net.ornithemc.osl.localization.impl; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import org.quiltmc.parsers.json.JsonReader; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.NamespacedIdentifiers; +import net.ornithemc.osl.resource.loader.api.resource.Resource; +import net.ornithemc.osl.resource.loader.api.resource.manager.ResourceManager; +import net.ornithemc.osl.resource.loader.impl.resource.pack.ResourcePacks; + +public final class Locale implements net.ornithemc.osl.text.impl.Locale { + + private static final Locale INSTANCE = new Locale(); + + public static Locale instance() { + return INSTANCE; + } + + private boolean wrapper; + // java.util.Map <=1.12.2, java.util.Properties >1.12.2 + private Map map; + private Properties properties; + + private long lastUpdateTime; + + private Locale() { + this.map = new HashMap<>(); + } + + public void wrap(Map map) { + this.init(map, null); + } + + public void wrap(Properties properties) { + this.init(null, properties); + } + + private void init(Map map, Properties properties) { + if (this.wrapper) { + throw new IllegalStateException("Attempted to initialize Locale multiple times!"); + } else { + this.wrapper = true; + this.map = map; + this.properties = properties; + } + } + + public String get(String key) { + if (this.map != null) { + return this.map.get(key); + } else if (this.properties != null) { + return this.properties.getProperty(key); + } else { + return null; + } + } + + public String getOrDefault(String key, String defaultValue) { + if (this.map != null) { + return this.map.getOrDefault(key, defaultValue); + } else if (this.properties != null) { + return this.properties.getProperty(key, defaultValue); + } else { + return defaultValue; + } + } + + public boolean containsKey(String key) { + if (this.map != null) { + return this.map.containsKey(key); + } else if (this.properties != null) { + return this.properties.containsKey(key); + } else { + return false; + } + } + + private void set(String key, String translation) { + if (this.map != null) { + this.map.put(key, translation); + } else if (this.properties != null) { + this.properties.setProperty(key, translation); + } + } + + public long getLastUpdateTime() { + return this.lastUpdateTime; + } + + public void setLastUpdateTime() { + this.lastUpdateTime = System.currentTimeMillis(); + } + + public void reload(ResourceManager resourceManager, List languages) { + this.setLastUpdateTime(); + + for (String language : languages) { + String pathFormat = "lang/%s%s"; + String[] paths; + + if (ResourcePacks.getSupportedFormat() < 3) { + String languageLowercase = language.toLowerCase(java.util.Locale.ROOT); + + paths = new String[] { + String.format(pathFormat, language, ".lang"), + String.format(pathFormat, language, ".json"), + String.format(pathFormat, languageLowercase, ".lang"), + String.format(pathFormat, languageLowercase, ".json") + }; + } else { + paths = new String[] { + String.format(pathFormat, language, ".lang"), + String.format(pathFormat, language, ".json") + }; + } + + for (String path : paths) { + try { + this.loadFromResources(path, resourceManager.getResourceStack(path)); + } catch (IOException ignored) { + } + + for (String namespace : resourceManager.getNamespaces()) { + NamespacedIdentifier location = NamespacedIdentifiers.from(namespace, path); + List resources = resourceManager.getResourceStack(location); + + this.loadFromResources(resources); + } + } + } + } + + public void loadFromResources(String path, List resources) { + for (InputStream resource : resources) { + try { + this.loadFromResource(path, resource); + } catch (IOException e) { + Localization.LOGGER.warn("Error parsing language file {}: {}", path, e); + } + } + } + + public void loadFromResources(List resources) { + for (Resource resource : resources) { + try { + this.loadFromResource(resource.location(), resource.open()); + } catch (IOException e) { + Localization.LOGGER.warn("Error parsing language file {} ({}): {}", resource.location(), resource.sourceName(), e); + } + } + } + + public void loadFromResource(String path, InputStream resource) throws IOException { + if (path.endsWith(".lang")) { + this.loadFromLang(resource); + } else if (path.endsWith(".json")) { + this.loadFromJson(resource); + } else { + Localization.LOGGER.warn("Skipping language file of unknown type: {}", path); + } + } + + public void loadFromResource(NamespacedIdentifier location, InputStream resource) throws IOException { + if (location.identifier().endsWith(".lang")) { + this.loadFromLang(resource); + } else if (location.identifier().endsWith(".json")) { + this.loadFromJson(resource); + } else { + Localization.LOGGER.warn("Skipping language file of unknown type: {}", location); + } + } + + public void loadFromLang(InputStream is) throws IOException { + try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) { + String line; + while ((line = br.readLine()) != null) { + line = line.trim(); + if (line.isEmpty() || line.startsWith("#")) { + continue; + } + String[] args = line.split("=", 2); + if (args.length != 2) { + continue; + } + this.set(args[0], args[1]); + } + } + } + + public void loadFromJson(InputStream is) throws IOException { + try (JsonReader reader = JsonReader.json(new InputStreamReader(is))) { + reader.beginObject(); + while (reader.hasNext()) { + this.set(reader.nextName() , reader.nextString()); + } + reader.endObject(); + } + } +} diff --git a/libraries/localization/src/main/java/net/ornithemc/osl/localization/impl/Localization.java b/libraries/localization/src/main/java/net/ornithemc/osl/localization/impl/Localization.java new file mode 100644 index 00000000..8a44f7fb --- /dev/null +++ b/libraries/localization/src/main/java/net/ornithemc/osl/localization/impl/Localization.java @@ -0,0 +1,57 @@ +package net.ornithemc.osl.localization.impl; + +import java.util.IllegalFormatException; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import net.ornithemc.osl.localization.api.language.Language; +import net.ornithemc.osl.localization.impl.language.LanguageManager; + +public final class Localization { + + public static final Logger LOGGER = LogManager.getLogger("OSL|Localization"); + + private static LanguageManager languageManager = LanguageManager.instance(); + private static Locale translations = Locale.instance(); + + public static LanguageManager getLanguageManager() { + return languageManager; + } + + public static Locale getLocale() { + return translations; + } + + public static Language getLanguage() { + return languageManager.getSelectedLanguage(); + } + + public static void setLanguage(Language language) { + languageManager.setSelectedLanguage(language); + } + + public static void reloadLanguageManager() { +// languageManager.reload(); + } + + public static void reloadLocale() { +// languageManager.reloadLocale(); + } + + public static String get(String key, Object... args) { + try { + return String.format(key = translations.get(key), args); + } catch (IllegalFormatException e) { + return "format error: " + key; + } + } + + public static String getOrDefault(String key, String defaultLocalization) { + return translations.getOrDefault(key, defaultLocalization); + } + + public static boolean has(String key) { + return translations.containsKey(key); + } +} diff --git a/libraries/localization/src/main/java/net/ornithemc/osl/localization/impl/language/LanguageManager.java b/libraries/localization/src/main/java/net/ornithemc/osl/localization/impl/language/LanguageManager.java new file mode 100644 index 00000000..221a62e7 --- /dev/null +++ b/libraries/localization/src/main/java/net/ornithemc/osl/localization/impl/language/LanguageManager.java @@ -0,0 +1,110 @@ +package net.ornithemc.osl.localization.impl.language; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.SortedSet; +import java.util.TreeSet; + +import net.ornithemc.osl.localization.api.language.Language; +import net.ornithemc.osl.localization.api.language.LanguageMetadata; +import net.ornithemc.osl.localization.impl.Locale; +import net.ornithemc.osl.localization.impl.Localization; +import net.ornithemc.osl.resource.loader.api.resource.ResourceMetadata; +import net.ornithemc.osl.resource.loader.api.resource.manager.ResourceManager; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePack; +import net.ornithemc.osl.resource.loader.impl.resource.pack.ResourcePacks; + +public final class LanguageManager { + + private static final LanguageManager INSTANCE = new LanguageManager(); + + public static final LanguageManager instance() { + return INSTANCE; + } + + public static final String EN_US = ResourcePacks.getSupportedFormat() < 3 ? "en_US" : "en_us"; + public static final String DEFAULT_LANGUAGE = EN_US; + public static final String BACKUP_LANGUAGE = EN_US; + + private final Locale locale = Locale.instance(); + + private boolean wrapper; + private Map languages; + private ResourceMetadata.Section metadataSection; + + private String selectedLanguage; + + private LanguageManager() { + this.languages = new HashMap<>(); + this.metadataSection = LanguageMetadata.SECTION; + + this.selectedLanguage = DEFAULT_LANGUAGE; + } + + public void wrap(Map map, Language.Factory languageFactory) { + if (this.wrapper) { + throw new IllegalStateException("Attempted to initialize LanguageManager multiple times!"); + } else { + ResourceMetadata.Section.Serializer serializer = SimpleLanguageMetadata.serializer(languageFactory); + + this.languages = map; + this.metadataSection = ResourceMetadata.Section.of(LanguageMetadata.NAME, serializer); + } + } + + public Language getSelectedLanguage() { + String code = this.selectedLanguage; + if (!this.languages.containsKey(code)) { + code = DEFAULT_LANGUAGE; + } + + return this.languages.get(code); + } + + public void setSelectedLanguage(Language language) { + this.selectedLanguage = language.code(); + } + + public void setSelectedLanguage(String language) { + this.selectedLanguage = language; + } + + public SortedSet getLanguages() { + return new TreeSet<>(this.languages.values()); + } + + public Language getLanguage(String code) { + return this.languages.get(code); + } + + public void reload(List resourcePacks) { + this.languages.clear(); + + for (ResourcePack resourcePack : resourcePacks) { + try { + LanguageMetadata metadata = resourcePack.getMetadata(this.metadataSection); + + if (metadata != null) { + for (Language language : metadata.getLanguages()) { + this.languages.putIfAbsent(language.code(), language); + } + } + } catch (Exception e) { + Localization.LOGGER.warn("Unable to parse language metadata from resource pack: {}", resourcePack.getId(), e); + } + } + } + + public void reloadLocale(ResourceManager resourceManager) { + List languageCodes = new ArrayList<>(); + + if (BACKUP_LANGUAGE.equals(this.selectedLanguage)) { + languageCodes.add(BACKUP_LANGUAGE); + } + languageCodes.add(this.selectedLanguage); + + this.locale.reload(resourceManager, languageCodes); + } +} diff --git a/libraries/localization/src/main/java/net/ornithemc/osl/localization/impl/language/SimpleLanguage.java b/libraries/localization/src/main/java/net/ornithemc/osl/localization/impl/language/SimpleLanguage.java new file mode 100644 index 00000000..a1fd71fe --- /dev/null +++ b/libraries/localization/src/main/java/net/ornithemc/osl/localization/impl/language/SimpleLanguage.java @@ -0,0 +1,64 @@ +package net.ornithemc.osl.localization.impl.language; + +import net.ornithemc.osl.localization.api.language.Language; + +public class SimpleLanguage implements Language, Comparable { + + public static final Factory FACTORY = SimpleLanguage::new; + + private final String code; + private final String region; + private final String name; + private final boolean bidirectional; + + public SimpleLanguage(String code, String region, String name, boolean bidirectional) { + this.code = code; + this.region = region; + this.name = name; + this.bidirectional = bidirectional; + } + + @Override + public boolean equals(Object that) { + if (this == that) { + return true; + } + if (!(that instanceof Language)) { + return false; + } + + Language lang = (Language) that; + return this.code.equals(lang.code()); + } + + @Override + public int hashCode() { + return this.code.hashCode(); + } + + @Override + public String toString() { + return String.format("%s (%s)", this.name, this.region); + } + + @Override + public int compareTo(Language language) { + return this.code.compareTo(language.code()); + } + + public String code() { + return this.code; + } + + public String name() { + return this.name; + } + + public String region() { + return this.region; + } + + public boolean bidirectional() { + return this.bidirectional; + } +} diff --git a/libraries/localization/src/main/java/net/ornithemc/osl/localization/impl/language/SimpleLanguageMetadata.java b/libraries/localization/src/main/java/net/ornithemc/osl/localization/impl/language/SimpleLanguageMetadata.java new file mode 100644 index 00000000..fc87658f --- /dev/null +++ b/libraries/localization/src/main/java/net/ornithemc/osl/localization/impl/language/SimpleLanguageMetadata.java @@ -0,0 +1,92 @@ +package net.ornithemc.osl.localization.impl.language; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; + +import net.ornithemc.osl.localization.api.language.Language; +import net.ornithemc.osl.localization.api.language.LanguageMetadata; +import net.ornithemc.osl.resource.loader.api.resource.ResourceMetadata; + +public class SimpleLanguageMetadata implements LanguageMetadata { + + public static final Serializer SERIALIZER = serializer(SimpleLanguage.FACTORY); + + public static Serializer serializer(Language.Factory languageFactory) { + return new Serializer(languageFactory); + } + + private final Collection languages; + + public SimpleLanguageMetadata(Collection languages) { + this.languages = languages; + } + + @Override + public Collection getLanguages() { + return this.languages; + } + + public static class Serializer implements ResourceMetadata.Section.Serializer { + + private static final String REGION = "region"; + private static final String NAME = "name"; + private static final String BIDIRECTIONAL = "bidirectional"; + + private static final int LANGUAGE_CODE_MAX_LENGTH = 16; + + private final Language.Factory languageFactory; + + public Serializer(Language.Factory languageFactory) { + this.languageFactory = languageFactory; + } + + @Override + public LanguageMetadata deserialize(JsonObject json) { + Set languages = new HashSet<>(); + + for (Map.Entry entry : json.entrySet()) { + String code = entry.getKey(); + JsonElement element = entry.getValue(); + + if (code.length() > LANGUAGE_CODE_MAX_LENGTH) { + throw new JsonParseException("Invalid language code '" + code + "': cannot be more than " + LANGUAGE_CODE_MAX_LENGTH + " characters long"); + } + if (!element.isJsonObject()) { + throw new JsonParseException("Invalid language '" + code + "': expected object"); + } + + JsonObject languageJson = element.getAsJsonObject(); + + if (!languageJson.has(REGION)) { + throw new JsonParseException("Invalid language '" + code + "': no region!"); + } + if (!languageJson.has(NAME)) { + throw new JsonParseException("Invalid language '" + code + "': no name!"); + } + + String region = languageJson.getAsJsonPrimitive(REGION).getAsString(); + String name = languageJson.getAsJsonPrimitive(NAME).getAsString(); + boolean bidirectional = languageJson.has(BIDIRECTIONAL) && languageJson.getAsJsonPrimitive(BIDIRECTIONAL).getAsBoolean(); + + if (region.isEmpty()) { + throw new JsonParseException("Invalid language '" + code + "': region cannot be empty"); + } + if (name.isEmpty()) { + throw new JsonParseException("Invalid language '" + code + "' name cannot be empty"); + } + + if (!languages.add(this.languageFactory.create(code, region, name, bidirectional))) { + throw new JsonParseException("Duplicate language '" + code + "' defined"); + } + } + + return new SimpleLanguageMetadata(languages); + } + } +} diff --git a/libraries/resource-loader/README.md b/libraries/resource-loader/README.md index c58b6e1d..7ed738bf 100644 --- a/libraries/resource-loader/README.md +++ b/libraries/resource-loader/README.md @@ -1,3 +1,161 @@ # Resource Loader API -The Resource Loader API allows mods to load their own resources into the game. The mod's resources are wrapped in a "built-in resource pack" which allows the game to find them. +The Resource Loader API allows mods to load their own resources into the game. On top of that, it provides its own access layer for resource packs and resource management. + +## Loading Your Mod's Resources + +Mods do not need to manually load their resources into the game. OSL wraps each mod's resources in a resource pack and loads all those resource packs in under the `fabric-mod-resources` pack. You can check that this is working by opening the Resource Packs screen and checking that `fabric-mod-resources` appears in the selected packs list. + +## Resource Loader Events + +The API provides several events for both the client and server, for initializing resource management and listening for resource reloads. Event listeners for these events should be registered in your mod's entrypoint. + +```java +package com.example; + +import net.ornithemc.osl.entrypoints.api.client.ClientModInitializer; +import net.ornithemc.osl.networking.api.client.ClientPlayNetworking; + +public class ExampleInitializer implements ClientModInitializer { + + @Override + public void initClient() { + ClientResourceLoaderEvents.INIT_RESOURCE_PACK_REPOSITORY.register(packRepository -> { + // register resource pack repository sources here + }); + ClientResourceLoaderEvents.INIT_RESOURCE_MANAGER.register(resourceManager -> { + // register resource reloaders and reload listeners here + }); + ClientResourceLoaderEvents.START_RESOURCE_PACKS_RELOAD.register(() -> { + // this code is run before the resource pack repository is reloaded + }); + ClientResourceLoaderEvents.START_RESOURCE_RELOAD.register(() -> { + // this code is run before a resource reload is started + }); + } +} +``` + +## Bundled Mod Resource Packs + +The API provides a way for mods to provide multiple bundled resource packs. You can do this by using sub-directories in your project resources. This is useful if you want to separate client assets from server data, or if you want to organize resources into bundles for specific feature sets or project modules. + +To ensure these resources are loaded properly, register them in your mod's entrypoint. + +```java +package com.example; + +import net.ornithemc.osl.entrypoints.api.client.ClientModInitializer; +import net.ornithemc.osl.networking.api.client.ClientPlayNetworking; + +public class ExampleInitializer implements ClientModInitializer { + + private static final ModContainer MOD = FabricLoader.getInstance().getModContainer("example").get() + + @Override + public void initClient() { + ResourcePackRepository.registerBundledModResources("cookie-assets", MOD, "client/cookies/") + } +} +``` + +## Resource Pack Repositories + +The client and server each have their own resource pack repositories. You can add a custom source to load in custom resource packs. + +```java +package com.example; + +import net.ornithemc.osl.entrypoints.api.client.ClientModInitializer; +import net.ornithemc.osl.networking.api.client.ClientPlayNetworking; + +public class ExampleRepositorySource implements ResourcePackRepository.Source { + + @Override + public void loadResourcePacks(Consumer consumer) { + // Load your custom resource packs here. + // These can be virtual resource packs, or packs loaded + // from a special file directory. + ... + } +} +``` + +```java +ClientResourceLoaderEvents.INIT_RESOURCE_PACK_REPOSITORY.register(packRepository -> { + packRepository.addSource(new ExampleRepositorySource()); +}); +``` + +## Resource Management + +The client and server each has their own resource manager. You can use this to access resources and register resource reloaders or reload listeners. + + +```java +ResourceManager resourceManager = ResourceManager.client(); + +// Get resource as an InputStream using a direct String path. +// Use this to access Vanilla resources in versions before 1.6. +// For custom resources you add, it is recommended to lay them +// out in namespaced directories like Vanilla in 1.6 and later. +resourceManager.getResource("/path/to/resource"); + +// Get resource as an Optional using a namespaced location. +// Use this to access Vanilla resources in versions 1.6 and later. +// It is recommended to lay out custom resources in namespaced +// directories for improved compatibility and extra features. +resourceManager.getResource(NamespacedIdentifiers.from("example", "path/to/resource")); + +// Get all resources as a Map +// in the specified directory that match the specified filter. +// NOTE: the specified directory is not resolved from the root +// of the resource packs, but from the namespaced directories! +// For example: a file at /directory/to/resources/example.json +// will NOT be found, but +// a file at `/assets/example/directory/to/resources/example.json +// WILL be found.` +resourceManager.findResources("directory/to/resources/", FileNameFilter.JSON); +``` + +```java +public class CookiesManager implements SimpleResourceReloader { + + private Cookies cookies; + + @Override + public Cookies reloadResources(ResourceManager manager) { + // Load resources from the resource manager here, parse them + // as necessary, and package them up. This code may not run + // on the main game thread, so it is imperative that you do + // not modify the world or render state here! + Cookies cookies = ... + return cookies; + } + + @Override + public void applyResources(Cookies cookies, ResourceManager manager) { + // Use the resources you loaded, and parsed above to modify + // the world or render state as necessary. + this.cookies = cookies; + } +} +``` + +```java +public class ExampleReloadListener implements ResourceReloadListener { + + @Override + public void resourcesReloaded(ResourceManager manager) { + // + ... + } +} +``` + +```java +ClientResourceLoaderEvents.INIT_RESOURCE_MANAGER.register(resourceManager -> { + resourceManager.addReloader(new CookiesManager()); + resourceManager.addReloader(new ExampleReloadListener()); +}); +``` diff --git a/libraries/resource-loader/build.gradle b/libraries/resource-loader/build.gradle index e98ba2c6..7bb43400 100644 --- a/libraries/resource-loader/build.gradle +++ b/libraries/resource-loader/build.gradle @@ -1 +1,5 @@ setUpLibrary(project) + +dependencies { + implementation 'com.google.code.gson:gson:2.8.0' +} diff --git a/libraries/resource-loader/gradle.properties b/libraries/resource-loader/gradle.properties index 6421e6f8..156cdcd9 100644 --- a/libraries/resource-loader/gradle.properties +++ b/libraries/resource-loader/gradle.properties @@ -3,4 +3,4 @@ library_name = Resource Loader library_description = Resource loading API and events. library_version = 0.6.1 -osl_dependencies = core:>=0.7.0 +osl_dependencies = core:>=0.7.0,executors:>=0.1.0-,text-components:>=0.1.0- diff --git a/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/build.gradle b/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/build.gradle similarity index 100% rename from libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/build.gradle rename to libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/build.gradle diff --git a/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/gradle.properties b/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/gradle.properties new file mode 100644 index 00000000..87a25c25 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/gradle.properties @@ -0,0 +1,6 @@ +environment = client +min_mc_version = 1.8.2-pre5 +max_mc_version = 1.12.2 +minecraft_dependency = >=1.8.2-rc.5 <=1.12.2 + +minecraft_version = 1.12.2 diff --git a/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/ClientResourcePacks.java b/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/ClientResourcePacks.java new file mode 100644 index 00000000..ffb8d0ea --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/ClientResourcePacks.java @@ -0,0 +1,47 @@ +package net.ornithemc.osl.resource.loader.impl; + +import java.util.function.Consumer; + +import net.minecraft.client.resource.pack.ResourcePacks; + +import net.ornithemc.osl.resource.loader.api.resource.pack.PackPosition; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePack; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackRepository; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackSummary; +import net.ornithemc.osl.resource.loader.impl.adapter.WrappedResourcePack; + +public class ClientResourcePacks implements ResourcePackRepository.Source { + + private final ResourcePacks resourcePacks; + + public ClientResourcePacks(ResourcePacks resourcePacks) { + this.resourcePacks = resourcePacks; + } + + @Override + public void loadResourcePacks(Consumer consumer) { + ResourcePack pack = new WrappedResourcePack(this.resourcePacks.defaultPack); + ResourcePackSummary summary = ResourcePackSummary.create( + pack, + true, + false, + PackPosition.BOTTOM + ); + + consumer.accept(summary); + + if (this.resourcePacks.getServerPack() != null) { + ResourcePack serverPack = new WrappedResourcePack(this.resourcePacks.getServerPack()); + ResourcePackSummary serverSummary = ResourcePackSummary.create( + serverPack, + true, + true, + PackPosition.TOP + ); + + if (serverSummary != null) { + consumer.accept(serverSummary); + } + } + } +} diff --git a/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/Adapters.java b/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/Adapters.java new file mode 100644 index 00000000..484aac7d --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/Adapters.java @@ -0,0 +1,69 @@ +package net.ornithemc.osl.resource.loader.impl.adapter; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import net.minecraft.client.resource.metadata.ResourceMetadataSerializerRegistry; +import net.minecraft.resource.Identifier; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.resource.loader.api.resource.Resource; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePack; + +class Adapters { + + static Identifier identifier(NamespacedIdentifier id) { + return id instanceof Identifier ? (Identifier) id : new Identifier(id.namespace(), id.identifier()); + } + + static net.minecraft.client.resource.Resource resource(ResourceMetadataSerializerRegistry metadataSerializers, Resource resource) throws IOException { + return new ResourceAdapter(metadataSerializers, resource); + } + + static net.minecraft.client.resource.Resource resource(ResourceMetadataSerializerRegistry metadataSerializers, NamespacedIdentifier location, Optional resource) throws IOException { + if (resource.isPresent()) { + return resource(metadataSerializers, resource.get()); + } + + throw new FileNotFoundException(location.toString()); + } + + static List resources(ResourceMetadataSerializerRegistry metadataSerializers, List resources) throws IOException { + List rs = new ArrayList<>(); + + for (Resource resource : resources) { + rs.add(resource(metadataSerializers, resource)); + } + + return Collections.unmodifiableList(rs); + } + + static net.minecraft.client.resource.pack.ResourcePack resourcePack(ResourcePack pack) { + if (pack instanceof WrappedResourcePack) { + return ((WrappedResourcePack) pack).pack; + } else { + return new ResourcePackAdapter(pack); + } + } + + static ResourcePack resourcePack(net.minecraft.client.resource.pack.ResourcePack pack) { + if (pack instanceof ResourcePackAdapter) { + return ((ResourcePackAdapter) pack).pack; + } else { + return new WrappedResourcePack(pack); + } + } + + static List packs(List packs) { + return packs.stream().map(Adapters::resourcePack).collect(Collectors.toList()); + } + + static List resourcePacks(List packs) { + return packs.stream().map(Adapters::resourcePack).collect(Collectors.toList()); + } +} diff --git a/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourceAdapter.java b/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourceAdapter.java new file mode 100644 index 00000000..e5245c73 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourceAdapter.java @@ -0,0 +1,76 @@ +package net.ornithemc.osl.resource.loader.impl.adapter; + +import java.io.IOException; +import java.io.InputStream; + +import com.google.gson.JsonObject; + +import net.minecraft.client.resource.metadata.ResourceMetadataSection; +import net.minecraft.client.resource.metadata.ResourceMetadataSerializerRegistry; +import net.minecraft.resource.Identifier; + +import net.ornithemc.osl.resource.loader.api.resource.Resource; +import net.ornithemc.osl.resource.loader.api.resource.ResourceMetadata; +import net.ornithemc.osl.resource.loader.impl.resource.JsonResourceMetadata; + +class ResourceAdapter implements net.minecraft.client.resource.Resource { + + private final ResourceMetadataSerializerRegistry metadataSerializers; + private final Identifier location; + private final InputStream resource; + private final ResourceMetadata metadata; + private String sourceName; + + ResourceAdapter(ResourceMetadataSerializerRegistry metadataSerializers, Resource resource) throws IOException { + ResourceMetadata metadata; + + try { + metadata = resource.metadata(); + } catch (IOException e) { + metadata = ResourceMetadata.EMPTY; + } + + this.metadataSerializers = metadataSerializers; + this.location = Adapters.identifier(resource.location()); + this.resource = resource.open(); + this.metadata = metadata; + this.sourceName = resource.sourceName(); + } + + @Override + public Identifier getLocation() { + return this.location; + } + + @Override + public InputStream asStream() { + return this.resource; + } + + @Override + public T getMetadata(String name) { + if (this.metadata instanceof JsonResourceMetadata) { + JsonResourceMetadata meta = (JsonResourceMetadata) this.metadata; + JsonObject metadataJson = meta.asJsonObject(); + + return this.metadataSerializers.readMetadata(name, metadataJson); + } else { + return null; + } + } + + @Override + public boolean hasMetadata() { + return this.metadata != ResourceMetadata.EMPTY; + } + + @Override + public String getSourceName() { + return this.sourceName; + } + + @Override + public void close() throws IOException { + this.resource.close(); + } +} diff --git a/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourceManagerAdapter.java b/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourceManagerAdapter.java new file mode 100644 index 00000000..d33284da --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourceManagerAdapter.java @@ -0,0 +1,73 @@ +package net.ornithemc.osl.resource.loader.impl.adapter; + +import java.io.IOException; +import java.util.List; +import java.util.Set; + +import net.minecraft.client.resource.Resource; +import net.minecraft.client.resource.metadata.ResourceMetadataSerializerRegistry; +import net.minecraft.client.resource.pack.ResourcePack; +import net.minecraft.resource.Identifier; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.resource.loader.api.resource.manager.ReloadableResourceManager; +import net.ornithemc.osl.resource.loader.api.resource.manager.ResourceManager; +import net.ornithemc.osl.resource.loader.api.resource.reload.ResourceReloadListener; + +public class ResourceManagerAdapter implements net.minecraft.client.resource.manager.ReloadableResourceManager { + + private final ResourceMetadataSerializerRegistry metadataSerializers; + private final ReloadableResourceManager resourceManager; + + public ResourceManagerAdapter(ResourceMetadataSerializerRegistry metadataSerializers, ReloadableResourceManager resourceManager) { + this.metadataSerializers = metadataSerializers; + this.resourceManager = resourceManager; + } + + @Override + public Set getNamespaces() { + return this.resourceManager.getNamespaces(); + } + + @Override + public Resource getResource(Identifier location) throws IOException { + return Adapters.resource(this.metadataSerializers, (NamespacedIdentifier) location, this.resourceManager.getResource((NamespacedIdentifier) location)); + } + + @Override + public List getResources(Identifier location) throws IOException { + return Adapters.resources(this.metadataSerializers, this.resourceManager.getResourceStack((NamespacedIdentifier) location)); + } + + @Override + public void addListener(net.minecraft.client.resource.manager.ResourceReloadListener listener) { + this.resourceManager.addReloader(new WrappedResourceReloadListener(listener)); + } + + @Override + public void reload(List packs) { + this.resourceManager.reload(Adapters.resourcePacks(packs)); + } + + private class WrappedResourceReloadListener implements ResourceReloadListener { + + private final net.minecraft.client.resource.manager.ResourceReloadListener listener; + + private WrappedResourceReloadListener(net.minecraft.client.resource.manager.ResourceReloadListener listener) { + this.listener = listener; + + // Vanilla's reload listeners are triggered immediately after registering + // We must emulate this or the game's initialization will fail + this.listener.reload(ResourceManagerAdapter.this); + } + + @Override + public void resourcesReloaded(ResourceManager manager) { + if (manager == ResourceManagerAdapter.this.resourceManager) { + this.listener.reload(ResourceManagerAdapter.this); + } else { + throw new IllegalStateException("Woah there, who hijacked the resource manager?"); + } + } + } +} diff --git a/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourcePackAdapter.java b/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourcePackAdapter.java new file mode 100644 index 00000000..bc8bca71 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourcePackAdapter.java @@ -0,0 +1,64 @@ +package net.ornithemc.osl.resource.loader.impl.adapter; + +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.InputStream; +import java.util.Set; + +import net.minecraft.client.render.texture.TextureUtil; +import net.minecraft.client.resource.metadata.ResourceMetadataSection; +import net.minecraft.client.resource.metadata.ResourceMetadataSerializerRegistry; +import net.minecraft.resource.Identifier; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.function.IOSupplier; +import net.ornithemc.osl.resource.loader.api.resource.ResourcePath; +import net.ornithemc.osl.resource.loader.api.resource.ResourceType; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePack; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePackFileNotFoundException; +import net.ornithemc.osl.resource.loader.impl.mixin.client.CustomResourcePackAccess; + +class ResourcePackAdapter implements net.minecraft.client.resource.pack.ResourcePack { + + final ResourcePack pack; + + ResourcePackAdapter(ResourcePack pack) { + this.pack = pack; + } + + @Override + public InputStream getResource(Identifier location) throws IOException { + IOSupplier resource = this.pack.getResource(ResourceType.CLIENT_ASSETS, (NamespacedIdentifier) location); // TODO: interface injection + + if (resource != null) { + return resource.get(); + } + + throw new ResourcePackFileNotFoundException(this.pack, ResourcePath.nameOf(ResourceType.CLIENT_ASSETS, (NamespacedIdentifier) location)); + } + + @Override + public boolean hasResource(Identifier location) { + return this.pack.hasResource(ResourceType.CLIENT_ASSETS, (NamespacedIdentifier) location); + } + + @Override + public Set getNamespaces() { + return this.pack.getNamespaces(ResourceType.CLIENT_ASSETS); + } + + @Override + public T getMetadataSection(ResourceMetadataSerializerRegistry metadataSerializers, String name) throws IOException { + return CustomResourcePackAccess.invokeGetMetadataSection(metadataSerializers, this.pack.getResource(ResourcePack.METADATA_FILE), name); + } + + @Override + public BufferedImage getIcon() throws IOException { + return TextureUtil.readImage(this.pack.getResource(ResourcePack.ICON_FILE)); + } + + @Override + public String getName() { + return this.pack.getId(); + } +} diff --git a/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourcePackLists.java b/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourcePackLists.java new file mode 100644 index 00000000..d7b6d172 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourcePackLists.java @@ -0,0 +1,111 @@ +package net.ornithemc.osl.resource.loader.impl.adapter; + +import java.util.Collection; +import java.util.List; +import java.util.function.BiFunction; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screen.ResourcePacksScreen; +import net.minecraft.client.gui.screen.resourcepack.ResourcePackEntry; +import net.minecraft.client.gui.screen.resourcepack.ServerResourcePackEntry; +import net.minecraft.client.resource.pack.ResourcePacks; + +import net.ornithemc.osl.resource.loader.api.resource.pack.PackPosition; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePack; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackRepository; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackSummary; + +public final class ResourcePackLists { + + public static final boolean ADD_SERVER_PACK_TO_GUI; + + static { + boolean exists; + + try { + exists = ServerResourcePackEntry.class != null; + } catch (Throwable t) { + exists = false; + } + + ADD_SERVER_PACK_TO_GUI = !exists; + } + + public static void fixSelection(List packs, boolean reversed) { + fixSelection( + packs, + (summary, pack) -> Adapters.resourcePack(pack), + reversed + ); + } + + public static void fixSelection(ResourcePacksScreen screen, List entries, boolean reversed) { + Minecraft minecraft = Minecraft.getInstance(); + ResourcePacks resourcePacks = minecraft.getResourcePacks(); + + // add server pack entry manually since vanilla doesn't + if (ADD_SERVER_PACK_TO_GUI && resourcePacks.getServerPack() != null) { + String id = resourcePacks.getServerPack().getName(); + ResourcePackSummary summary = ResourcePackRepository.client().getPack(id); + + if (summary != null) { + entries.add(reversed ? 0 : entries.size(), new ResourcePackSummaryEntry(screen, summary)); + } + } + + fixSelection( + entries, + (summary, pack) -> new ResourcePackSummaryEntry(screen, summary), + reversed + ); + } + + /** + * insert any missing required packs into the list, preserving their ordering + */ + public static void fixSelection(List entries, BiFunction entryGetter, boolean reversed) { + Minecraft minecraft = Minecraft.getInstance(); + ResourcePacks resourcePacks = minecraft.getResourcePacks(); + ResourcePackRepository packRepository = ResourcePackRepository.client(); + + Collection selection = packRepository.getSelectedPacks(); + + boolean serverPackSelected = (resourcePacks.getServerPack() != null); + boolean defaultPackInserted = false; + boolean serverPackInserted = false; + + // if you keep inserting at index 0 you invert the ordering + // so we increment an offset to counteract that effect + int offset = 0; + + for (ResourcePackSummary summary : selection) { + ResourcePack pack = summary.open(); + + if (summary.isRequired()) { + if (pack instanceof WrappedResourcePack) { + net.minecraft.client.resource.pack.ResourcePack resourcePack = ((WrappedResourcePack) pack).pack; + + defaultPackInserted |= (resourcePack == resourcePacks.defaultPack); + serverPackInserted |= (resourcePack == resourcePacks.getServerPack()); + } else { + T entry = entryGetter.apply(summary, pack); + + if (summary.getDefaultPosition() == PackPosition.TOP) { + if (!serverPackSelected || serverPackInserted) { + entries.add(reversed ? offset++ : entries.size(), entry); + } else { + entries.add(reversed ? ++offset : (entries.size() - 1), entry); + } + } + if (summary.getDefaultPosition() == PackPosition.BOTTOM) { + if (defaultPackInserted) { + entries.add(reversed ? (entries.size() - 1 ) : ++offset, entry); + } else { + entries.add(reversed ? entries.size() : offset++, entry); + } + } + } + } + } + } +} diff --git a/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourcePackSummaryEntry.java b/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourcePackSummaryEntry.java new file mode 100644 index 00000000..be0f78ce --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourcePackSummaryEntry.java @@ -0,0 +1,88 @@ +package net.ornithemc.osl.resource.loader.impl.adapter; + +import java.io.IOException; + +import net.minecraft.client.gui.screen.ResourcePacksScreen; +import net.minecraft.client.gui.screen.resourcepack.ResourcePackEntry; +import net.minecraft.client.render.texture.DynamicTexture; +import net.minecraft.client.render.texture.TextureUtil; +import net.minecraft.client.resource.pack.ResourcePack; +import net.minecraft.resource.Identifier; + +import net.ornithemc.osl.resource.loader.api.resource.pack.PackPosition; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackSummary; + +class ResourcePackSummaryEntry extends ResourcePackEntry { + + private final ResourcePackSummary summary; + private final ResourcePack pack; + + private final Identifier iconLocation; + + ResourcePackSummaryEntry(ResourcePacksScreen parent, ResourcePackSummary summary) { + super(parent); + + this.summary = summary; + this.pack = Adapters.resourcePack(summary.open()); + + DynamicTexture icon; + + try { + icon = new DynamicTexture(this.pack.getIcon()); + } catch (IOException e) { + icon = TextureUtil.MISSING_TEXTURE; + } + + this.iconLocation = this.minecraft.getTextureManager().register("texturepackicon", icon); + } + + @Override + protected int getFormat() { + return this.summary.getCompatibility().asFormat(); + } + + @Override + protected String getDescription() { + return this.summary.getDescription().buildFormattedString(); + } + + @Override + protected void bindIcon() { + this.minecraft.getTextureManager().bind(this.iconLocation); + } + + @Override + protected String getName() { + return this.summary.getId(); + } + + @Override + protected boolean canMove() { + return !this.summary.isRequired() && !this.summary.isFixedPosition(); + } + + @Override + protected boolean canMoveRight() { + return !this.summary.isRequired(); + } + + @Override + protected boolean canMoveLeft() { + return !this.summary.isRequired(); + } + + @Override + protected boolean canMoveUp() { + return !this.summary.isRequired() && !this.summary.isFixedPosition(); + } + + @Override + protected boolean canMoveDown() { + return !this.summary.isRequired() && !this.summary.isFixedPosition(); + } + + @Override + public boolean m_42427629() { + return this.summary.isFixedPosition() && this.summary.getDefaultPosition() == PackPosition.TOP; + } +} diff --git a/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/WrappedResourcePack.java b/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/WrappedResourcePack.java new file mode 100644 index 00000000..27aac287 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/WrappedResourcePack.java @@ -0,0 +1,154 @@ +package net.ornithemc.osl.resource.loader.impl.adapter; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.util.Collections; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.api.ModContainer; + +import net.minecraft.client.resource.pack.BuiltInResourcePack; +import net.minecraft.client.resource.pack.CustomResourcePack; +import net.minecraft.client.resource.pack.DirectoryResourcePack; +import net.minecraft.client.resource.pack.LegacyResourcePack; +import net.minecraft.client.resource.pack.ZippedResourcePack; +import net.minecraft.resource.Identifier; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.function.IOSupplier; +import net.ornithemc.osl.resource.loader.api.resource.ResourceType; +import net.ornithemc.osl.resource.loader.api.resource.pack.AbstractResourcePack; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourceConsumer; +import net.ornithemc.osl.resource.loader.impl.mixin.client.CustomResourcePackAccess; +import net.ornithemc.osl.resource.loader.impl.mixin.client.LegacyResourcePackAccess; +import net.ornithemc.osl.resource.loader.impl.resource.pack.ResourcePacks; + +public class WrappedResourcePack extends AbstractResourcePack { + + final net.minecraft.client.resource.pack.ResourcePack pack; + + public WrappedResourcePack(net.minecraft.client.resource.pack.ResourcePack pack) { + this.pack = pack; + } + + @Override + public String getId() { + return this.pack.getName(); + } + + @Override + public boolean hasResource(String path) { + return this.hasResourceFromPack(this.pack, path); + } + + private boolean hasResourceFromPack(net.minecraft.client.resource.pack.ResourcePack pack, String path) { + if (ResourcePacks.getSupportedFormat() > 2 && pack instanceof LegacyResourcePack) { + return this.hasResourceFromPack(((LegacyResourcePackAccess) pack).accessPack(), path); + } else if (pack instanceof BuiltInResourcePack) { + return ((BuiltInResourcePack) pack).hasResource(new PathIdentifier(path)) + || ((BuiltInResourcePack) pack).hasResource(new Identifier(path)); + } else if (pack instanceof CustomResourcePack) { + return ((CustomResourcePackAccess) pack).invokeHasResource(path); + } else if (pack instanceof ResourcePackAdapter) { + return ((ResourcePackAdapter) pack).pack.hasResource(path); + } else { + return false; + } + } + + @Override + public InputStream getResource(String path) throws IOException { + return this.getResourceFromPack(this.pack, path); + } + + private InputStream getResourceFromPack(net.minecraft.client.resource.pack.ResourcePack pack, String path) throws IOException { + if (ResourcePacks.getSupportedFormat() > 2 && pack instanceof LegacyResourcePack) { + return this.getResourceFromPack(((LegacyResourcePackAccess) pack).accessPack(), path); + } else if (pack instanceof BuiltInResourcePack) { + return ((BuiltInResourcePack) pack).hasResource(new PathIdentifier(path)) + ? ((BuiltInResourcePack) pack).getResource(new PathIdentifier(path)) + : ((BuiltInResourcePack) pack).getResource(new Identifier(path)); + } else if (pack instanceof CustomResourcePack) { + return ((CustomResourcePackAccess) pack).invokeOpenResource(path); + } else if (pack instanceof ResourcePackAdapter) { + return ((ResourcePackAdapter) pack).pack.getResource(path); + } else { + return null; + } + } + + @Override + protected Map> findNamespaces() { + return new EnumMap<>(Collections.singletonMap(ResourceType.CLIENT_ASSETS, this.pack.getNamespaces())); + } + + @Override + public boolean hasResource(ResourceType type, NamespacedIdentifier location) { + return type == ResourceType.CLIENT_ASSETS && this.pack.hasResource(Adapters.identifier(location)); + } + + @Override + public IOSupplier getResource(ResourceType type, NamespacedIdentifier location) { + return type == ResourceType.CLIENT_ASSETS && this.pack.hasResource(Adapters.identifier(location)) ? () -> this.pack.getResource(Adapters.identifier(location)) : null; + } + + @Override + public void findResources(ResourceType type, String namespace, String directory, ResourceConsumer consumer) { + if (type == ResourceType.CLIENT_ASSETS) { + this.findResourcesInPack(this.pack, type, namespace, directory, consumer); + } + } + + private void findResourcesInPack(net.minecraft.client.resource.pack.ResourcePack pack, ResourceType type, String namespace, String directory, ResourceConsumer consumer) { + if (ResourcePacks.getSupportedFormat() > 2 && pack instanceof LegacyResourcePack) { + this.findResourcesInPack(((LegacyResourcePackAccess) pack).accessPack(), type, namespace, directory, consumer); + } else if (pack instanceof BuiltInResourcePack) { + ModContainer mod = FabricLoader.getInstance().getModContainer("minecraft").get(); + List rootPaths = ResourcePacks.getRootPaths(mod.getRootPaths(), "."); + + ResourcePacks.findResources(this, rootPaths, type, namespace, directory, consumer); + } else if (pack instanceof DirectoryResourcePack) { + CustomResourcePackAccess directoryPack = (CustomResourcePackAccess) pack; + List rootPaths = ResourcePacks.getRootPaths(directoryPack.accessFile().toPath(), "."); + + if (!rootPaths.isEmpty()) { + ResourcePacks.findResources(this, rootPaths, type, namespace, directory, consumer); + } + } else if (pack instanceof ZippedResourcePack) { + CustomResourcePackAccess zippedPack = (CustomResourcePackAccess) pack; + + try (FileSystem zipFs = FileSystems.newFileSystem(zippedPack.accessFile().toPath(), (ClassLoader) null)) { + List rootPaths = ResourcePacks.getRootPaths(zipFs.getRootDirectories(), "."); + + if (!rootPaths.isEmpty()) { + ResourcePacks.findResources(this, rootPaths, type, namespace, directory, consumer); + } + } catch (IOException e) { + } + } else if (pack instanceof ResourcePackAdapter) { + ((ResourcePackAdapter) pack).pack.findResources(type, namespace, directory, consumer); + } + } + + /** + * Path-only Identifier impl for accessing direct-path resources from the assets index. + */ + private static class PathIdentifier extends Identifier { + + private PathIdentifier(String path) { + super(path); + } + + @Override + public String toString() { + return this.getPath(); + } + } +} diff --git a/libraries/resource-loader/resource-loader-mc16w32a-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/CustomResourcePackInvoker.java b/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/CustomResourcePackAccess.java similarity index 66% rename from libraries/resource-loader/resource-loader-mc16w32a-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/CustomResourcePackInvoker.java rename to libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/CustomResourcePackAccess.java index 94c4de06..665a6c67 100644 --- a/libraries/resource-loader/resource-loader-mc16w32a-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/CustomResourcePackInvoker.java +++ b/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/CustomResourcePackAccess.java @@ -1,8 +1,11 @@ package net.ornithemc.osl.resource.loader.impl.mixin.client; +import java.io.File; +import java.io.IOException; import java.io.InputStream; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; import org.spongepowered.asm.mixin.gen.Invoker; import net.minecraft.client.resource.metadata.ResourceMetadataSection; @@ -10,7 +13,16 @@ import net.minecraft.client.resource.pack.CustomResourcePack; @Mixin(CustomResourcePack.class) -public interface CustomResourcePackInvoker { +public interface CustomResourcePackAccess { + + @Accessor("file") + File accessFile(); + + @Invoker("openResource") + InputStream invokeOpenResource(String path) throws IOException; + + @Invoker("hasResource") + boolean invokeHasResource(String path); @Invoker("getMetadataSection") public static T invokeGetMetadataSection(ResourceMetadataSerializerRegistry metadataSerializers, InputStream is, String name) { diff --git a/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/LegacyResourcePackAccess.java b/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/LegacyResourcePackAccess.java new file mode 100644 index 00000000..579bbb7e --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/LegacyResourcePackAccess.java @@ -0,0 +1,17 @@ +package net.ornithemc.osl.resource.loader.impl.mixin.client; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Pseudo; +import org.spongepowered.asm.mixin.gen.Accessor; + +import net.minecraft.client.resource.pack.LegacyResourcePack; +import net.minecraft.client.resource.pack.ResourcePack; + +@Pseudo // class only exists in 15w31a+ +@Mixin(LegacyResourcePack.class) +public interface LegacyResourcePackAccess { + + @Accessor("pack") + ResourcePack accessPack(); + +} diff --git a/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/MinecraftMixin.java b/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/MinecraftMixin.java new file mode 100644 index 00000000..a33fe44e --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/MinecraftMixin.java @@ -0,0 +1,103 @@ +package net.ornithemc.osl.resource.loader.impl.mixin.client; + +import java.io.IOException; +import java.util.List; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.At.Shift; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import com.llamalad7.mixinextras.sugar.Local; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.resource.manager.ReloadableResourceManager; +import net.minecraft.client.resource.metadata.ResourceMetadataSerializerRegistry; +import net.minecraft.client.resource.metadata.ResourcePackMetadata; +import net.minecraft.client.resource.pack.BuiltInResourcePack; +import net.minecraft.client.resource.pack.ResourcePack; + +import net.ornithemc.osl.resource.loader.impl.ResourceLoader; +import net.ornithemc.osl.resource.loader.impl.adapter.ResourceManagerAdapter; +import net.ornithemc.osl.resource.loader.impl.adapter.ResourcePackLists; +import net.ornithemc.osl.resource.loader.impl.resource.manager.SimpleReloadableResourceManager; +import net.ornithemc.osl.resource.loader.impl.resource.pack.ResourcePacks; + +@Mixin(Minecraft.class) +public class MinecraftMixin { + + @Shadow @Final + private ResourceMetadataSerializerRegistry resourceMetadataSerializerRegistry; + @Shadow @Final + private List defaultResourcePacks; + @Shadow @Final + private BuiltInResourcePack defaultResourcePack; + @Shadow + private ReloadableResourceManager resourceManager; + + @Unique + private final SimpleReloadableResourceManager actualResourceManager = SimpleReloadableResourceManager.client(); + + @Inject( + method = "init", + at = @At( + value = "NEW", + target = "net/minecraft/client/resource/pack/ResourcePacks" + ) + ) + private void osl$resource_loader$detectPackFormat(CallbackInfo ci) { + // TODO: detect pack format for server resources! + // it'll be the same pack number but we need detection on the server + try { + ResourcePackMetadata metadata = defaultResourcePack.getMetadataSection(resourceMetadataSerializerRegistry, "pack"); + int format = metadata.getFormat(); + + ResourcePacks.setSupportedFormat(format); + } catch (IOException e) { + ResourceLoader.LOGGER.info("unable to parse pack format from default resource pack", e); + } + } + + @Inject( + method = "init", + at = @At( + value = "FIELD", + target = "Lnet/minecraft/client/Minecraft;resourceManager:Lnet/minecraft/client/resource/manager/ReloadableResourceManager;", + ordinal = 0, + shift = Shift.AFTER + ) + ) + private void osl$resource_loader$setResourceManager(CallbackInfo ci) { + this.resourceManager = new ResourceManagerAdapter(this.resourceMetadataSerializerRegistry, this.actualResourceManager); + } + + @Inject( + method = "init", + at = @At( + value = "NEW", + target = "net/minecraft/client/gui/GameGui" // after all Vanilla reload listeners + ) + ) + private void osl$resource_loader$initResourceManager(CallbackInfo ci) { + this.actualResourceManager.init(); + } + + @Inject( + method = "reloadResources", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/resource/manager/ReloadableResourceManager;reload(Ljava/util/List;)V" + ) + ) + private void osl$resource_loader$fixSelection(CallbackInfo ci, @Local List selection) { + // ResourcePacks.getSelectedPacks only contains directory or zip packs + // The default pack and server pack are added in the target method, so + // we must add any other required packs manually as well + + ResourcePackLists.fixSelection(selection, false); + } +} diff --git a/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/ResourcePacksMixin.java b/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/ResourcePacksMixin.java new file mode 100644 index 00000000..4b057946 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/ResourcePacksMixin.java @@ -0,0 +1,165 @@ +package net.ornithemc.osl.resource.loader.impl.mixin.client; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.client.resource.pack.ResourcePacks; + +import net.ornithemc.osl.resource.loader.api.resource.pack.PackPosition; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePack; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackRepository; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackSummary; +import net.ornithemc.osl.resource.loader.impl.ClientResourcePacks; +import net.ornithemc.osl.resource.loader.impl.adapter.WrappedResourcePack; +import net.ornithemc.osl.resource.loader.impl.resource.repository.BundledModResourcePacks; +import net.ornithemc.osl.resource.loader.impl.resource.repository.SimpleResourcePackRepository; + +@Mixin(ResourcePacks.class) +public class ResourcePacksMixin implements ResourcePackRepository.Source { + + @Shadow @Final + private List availablePacks; + @Shadow @Final + private List appliedPacks; + + @Unique + private final SimpleResourcePackRepository resourcePacks = SimpleResourcePackRepository.client(); + @Unique + private final Map availablePacksById = new HashMap<>(); + + @Unique + private boolean vanillaReloading; + @Unique + private boolean reloading; + + @Shadow + private void load() { } + + @Inject( + method = "", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/resource/pack/ResourcePacks;load()V" + ) + ) + private void osl$resource_loader$initAvailable(CallbackInfo ci) { + this.resourcePacks.setCallbacks(null, this::selectionChanged); + + this.resourcePacks.addSource(new ClientResourcePacks((ResourcePacks) (Object) this)); + this.resourcePacks.addSource(new BundledModResourcePacks()); + this.resourcePacks.addSource(this); // resourcepacks/ directory source + + this.resourcePacks.init(); + } + + @Inject( + method = "", + at = @At( + value = "TAIL" + ) + ) + private void osl$resource_loader$initSelection(CallbackInfo ci) { + this.updateSelection(); + } + + @Inject( + method = "load", + cancellable = true, + at = @At( + value = "HEAD" + ) + ) + private void osl$resource_loader$startReload(CallbackInfo ci) { + if (!this.vanillaReloading) { + this.vanillaReloading = true; + + if (!this.reloading) { + this.resourcePacks.reload(); + + // cancel this call as the pack repository will trigger + // another recursive call through this.loadResourcePacks + ci.cancel(); + } + } + } + + @Inject( + method = "load", + at = @At( + value = "TAIL" + ) + ) + private void osl$resource_loader$endReload(CallbackInfo ci) { + this.vanillaReloading = false; + } + + @Inject( + method = "apply", + at = @At( + value = "TAIL" + ) + ) + private void osl$resource_loader$updateSelection(CallbackInfo ci) { + this.updateSelection(); + } + + @Override + public void loadResourcePacks(Consumer consumer) { + this.reloading = true; + this.load(); + this.reloading = false; + + this.availablePacksById.clear(); + + for (ResourcePacks.Entry pack : this.availablePacks) { + ResourcePack resourcePack = new WrappedResourcePack(pack.get()); + ResourcePackSummary summary = ResourcePackSummary.create( + resourcePack, + false, + false, + PackPosition.TOP + ); + + this.availablePacksById.put(summary.getId(), pack); + + if (summary != null) { + consumer.accept(summary); + } + } + } + + @Unique + private void updateSelection() { + List selection = new ArrayList<>(); + + for (ResourcePacks.Entry pack : this.appliedPacks) { + selection.add(pack.getName()); + } + + this.resourcePacks.setSelectedPacks(selection); + } + + @Unique + private void selectionChanged() { + this.appliedPacks.clear(); + + for (ResourcePackSummary summary : this.resourcePacks.getSelectedPacks()) { + ResourcePacks.Entry pack = this.availablePacksById.get(summary.getId()); + + if (pack != null) { + this.appliedPacks.add(pack); + } + } + } +} diff --git a/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/ResourcePacksScreenMixin.java b/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/ResourcePacksScreenMixin.java new file mode 100644 index 00000000..7597bf5c --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/ResourcePacksScreenMixin.java @@ -0,0 +1,50 @@ +package net.ornithemc.osl.resource.loader.impl.mixin.client; + +import java.util.List; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.At.Shift; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Slice; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.client.gui.screen.ResourcePacksScreen; +import net.minecraft.client.gui.screen.resourcepack.ResourcePackEntry; + +import net.ornithemc.osl.resource.loader.impl.adapter.ResourcePackLists; + +@Mixin(ResourcePacksScreen.class) +public class ResourcePacksScreenMixin { + + @Shadow + private List appliedPacks; + + @Inject( + method = "init", + slice = @Slice( + from = @At( + value = "NEW", + target = "net/minecraft/client/gui/screen/resourcepack/DefaultResourcePackEntry" + ) + ), + at = @At( + value = "INVOKE", + target = "Ljava/util/List;add(Ljava/lang/Object;)Z", + ordinal = 0, + shift = Shift.AFTER + ) + ) + private void osl$resource_loader$fixSelection(CallbackInfo ci) { + // ResourcePacks.getSelectedPacks only contains directory or zip packs + // The default pack and server pack are added in the target method, so + // we must add any other required packs manually as well + + ResourcePackLists.fixSelection( + (ResourcePacksScreen) (Object) this, + this.appliedPacks, + true + ); + } +} diff --git a/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/common/AdvancementManagerMixin.java b/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/common/AdvancementManagerMixin.java new file mode 100644 index 00000000..3bca641e --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/common/AdvancementManagerMixin.java @@ -0,0 +1,51 @@ +package net.ornithemc.osl.resource.loader.impl.mixin.common; + +import java.net.URI; +import java.nio.file.FileSystem; +import java.nio.file.Path; +import java.util.Map; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Pseudo; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.api.ModContainer; + +import net.minecraft.server.AdvancementManager; + +import net.ornithemc.osl.resource.loader.api.resource.ResourcePath; + +@Pseudo // 17w13a+ +@Mixin(AdvancementManager.class) +public class AdvancementManagerMixin { + + private static final ModContainer MINECRAFT = FabricLoader.getInstance().getModContainer("minecraft").get(); + + @Redirect( + method = "loadBuiltIn", + at = @At( + value = "INVOKE", + target = "Ljava/nio/file/FileSystems;newFileSystem(Ljava/net/URI;Ljava/util/Map;)Ljava/nio/file/FileSystem;" + ) + ) + private FileSystem osl$resource_loader$noNewFileSystem(URI uri, Map env) { + // the mod container also opens file systems on the game jars + // as the resource loader uses it to find and open resources + // this call leads to FileSystemAlreadyExists exceptions so + // we cancel it + return null; + } + + @Redirect( + method = "loadBuiltIn", + at = @At( + value = "INVOKE", + target = "Ljava/nio/file/FileSystem;getPath(Ljava/lang/String;[Ljava/lang/String;)Ljava/nio/file/Path;" + ) + ) + private Path osl$resource_loader$getPathFromJar(FileSystem fs, String path, String... paths) { + return MINECRAFT.findPath(ResourcePath.nameOf(path)).orElse(null); + } +} diff --git a/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/common/CraftingManagerMixin.java b/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/common/CraftingManagerMixin.java new file mode 100644 index 00000000..12b77201 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/common/CraftingManagerMixin.java @@ -0,0 +1,51 @@ +package net.ornithemc.osl.resource.loader.impl.mixin.common; + +import java.net.URI; +import java.nio.file.FileSystem; +import java.nio.file.Path; +import java.util.Map; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Pseudo; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.api.ModContainer; + +import net.minecraft.crafting.CraftingManager; + +import net.ornithemc.osl.resource.loader.api.resource.ResourcePath; + +@Pseudo // 17w13a+ +@Mixin(CraftingManager.class) +public class CraftingManagerMixin { + + private static final ModContainer MINECRAFT = FabricLoader.getInstance().getModContainer("minecraft").get(); + + @Redirect( + method = "load", + at = @At( + value = "INVOKE", + target = "Ljava/nio/file/FileSystems;newFileSystem(Ljava/net/URI;Ljava/util/Map;)Ljava/nio/file/FileSystem;" + ) + ) + private static FileSystem osl$resource_loader$noNewFileSystem(URI uri, Map env) { + // the mod container also opens file systems on the game jars + // as the resource loader uses it to find and open resources + // this call leads to FileSystemAlreadyExists exceptions so + // we cancel it + return null; + } + + @Redirect( + method = "load", + at = @At( + value = "INVOKE", + target = "Ljava/nio/file/FileSystem;getPath(Ljava/lang/String;[Ljava/lang/String;)Ljava/nio/file/Path;" + ) + ) + private static Path osl$resource_loader$getPathFromJar(FileSystem fs, String path, String... paths) { + return MINECRAFT.findPath(ResourcePath.nameOf(path)).orElse(null); + } +} diff --git a/libraries/resource-loader/resource-loader-mc11w49a-mc1.2.5/src/main/resources/fabric.mod.json b/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/resources/fabric.mod.json similarity index 70% rename from libraries/resource-loader/resource-loader-mc11w49a-mc1.2.5/src/main/resources/fabric.mod.json rename to libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/resources/fabric.mod.json index e33ce5a3..9a29f52c 100644 --- a/libraries/resource-loader/resource-loader-mc11w49a-mc1.2.5/src/main/resources/fabric.mod.json +++ b/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/resources/fabric.mod.json @@ -1,15 +1,17 @@ { "schemaVersion": 1, "id": "osl-resource-loader", - "version": "0.6.1+mc11w49a-mc1.2.5", + "version": "0.6.1+mc1.8.2-pre5-mc1.12.2", "environment": "client", "mixins": [ "osl.resource-loader.mixins.json" ], "depends": { "fabricloader": "\u003e\u003d0.18.0", - "minecraft": "\u003e\u003d1.1-alpha.11.49.a \u003c\u003d1.2.5", - "osl-core": "\u003e\u003d0.7.0" + "minecraft": "\u003e\u003d1.8.2-rc.5 \u003c\u003d1.12.2", + "osl-core": "\u003e\u003d0.7.0", + "osl-executors": "\u003e\u003d0.1.0-", + "osl-text-components": "\u003e\u003d0.1.0-" }, "name": "OSL Resource Loader", "description": "Resource loading API and events.", diff --git a/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/resources/osl.resource-loader.mixins.json b/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/resources/osl.resource-loader.mixins.json new file mode 100644 index 00000000..155688be --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc1.8.2-pre5-mc1.12.2/src/main/resources/osl.resource-loader.mixins.json @@ -0,0 +1,22 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "net.ornithemc.osl.resource.loader.impl.mixin", + "compatibilityLevel": "JAVA_8", + "mixins": [ + "common.AdvancementManagerMixin", + "common.CraftingManagerMixin" + ], + "client": [ + "client.CustomResourcePackAccess", + "client.LegacyResourcePackAccess", + "client.MinecraftMixin", + "client.ResourcePacksMixin", + "client.ResourcePacksScreenMixin" + ], + "server": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/libraries/resource-loader/resource-loader-mc11w49a-mc1.2.5/gradle.properties b/libraries/resource-loader/resource-loader-mc11w49a-mc1.2.5/gradle.properties deleted file mode 100644 index fdcb7c90..00000000 --- a/libraries/resource-loader/resource-loader-mc11w49a-mc1.2.5/gradle.properties +++ /dev/null @@ -1,8 +0,0 @@ -environment = client -min_mc_version = 11w49a -max_mc_version = 1.2.5 -minecraft_dependency = >=1.1-alpha.11.49.a <=1.2.5 - -minecraft_version = 1.2.5 -feather_build = 1 -client_nests_build = 10 diff --git a/libraries/resource-loader/resource-loader-mc11w49a-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/api/ModTexturePack.java b/libraries/resource-loader/resource-loader-mc11w49a-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/api/ModTexturePack.java deleted file mode 100644 index 1e9f0960..00000000 --- a/libraries/resource-loader/resource-loader-mc11w49a-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/api/ModTexturePack.java +++ /dev/null @@ -1,11 +0,0 @@ -package net.ornithemc.osl.resource.loader.api; - -import net.fabricmc.loader.api.metadata.ModMetadata; - -import net.minecraft.client.resource.pack.TexturePack; - -public abstract class ModTexturePack extends TexturePack { - - public abstract ModMetadata getModMetadata(); - -} diff --git a/libraries/resource-loader/resource-loader-mc11w49a-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/api/ResourceLoaderEvents.java b/libraries/resource-loader/resource-loader-mc11w49a-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/api/ResourceLoaderEvents.java deleted file mode 100644 index b3fc8b24..00000000 --- a/libraries/resource-loader/resource-loader-mc11w49a-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/api/ResourceLoaderEvents.java +++ /dev/null @@ -1,30 +0,0 @@ -package net.ornithemc.osl.resource.loader.api; - -import java.util.function.Consumer; - -import net.ornithemc.osl.core.api.events.Event; - -/** - * Events related to resource loading. - */ -public class ResourceLoaderEvents { - - /** - * This event is invoked upon game start-up, giving mod developers the - * opportunity to register custom built-in texture packs. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ResourceLoaderEvents.ADD_DEFAULT_TEXTURE_PACKS.register(adder -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event>> ADD_DEFAULT_TEXTURE_PACKS = Event.consumer(); - -} diff --git a/libraries/resource-loader/resource-loader-mc11w49a-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/BuiltInModTexturePack.java b/libraries/resource-loader/resource-loader-mc11w49a-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/BuiltInModTexturePack.java deleted file mode 100644 index a1e15829..00000000 --- a/libraries/resource-loader/resource-loader-mc11w49a-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/BuiltInModTexturePack.java +++ /dev/null @@ -1,84 +0,0 @@ -package net.ornithemc.osl.resource.loader.impl; - -import java.io.IOException; -import java.io.InputStream; -import java.io.UncheckedIOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; - -import net.fabricmc.loader.api.ModContainer; -import net.fabricmc.loader.api.metadata.ModMetadata; - -import net.minecraft.client.resource.pack.TexturePack; - -import net.ornithemc.osl.resource.loader.api.ModTexturePack; - -public class BuiltInModTexturePack extends ModTexturePack { - - private final ModContainer mod; - - private final List roots; - - public BuiltInModTexturePack(ModContainer mod) { - super(); - - this.key = mod.getMetadata().getId(); - this.name = mod.getMetadata().getName(); - - this.mod = mod; - - this.roots = this.mod.getRootPaths(); - } - - @Override - public InputStream getResource(String location) { - Path path = getPath(location); - - if (path == null || !Files.exists(path)) { - if ("/pack.png".equals(location) || "/pack.txt".equals(location)) { - return TexturePack.class.getResourceAsStream(location); - } - - return null; - } - - // a bit of a hack to re-throw a checked exception - // because proguard stripped the exceptions off this method - try { - return Files.newInputStream(path); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - -// @Override - public boolean hasResource(String location) { - Path path = getPath(location); - return path != null && Files.exists(path); - } - - @Override - public ModMetadata getModMetadata() { - return mod.getMetadata(); - } - - private Path getPath(String location) { - // the game accesses all resources with a leading '/' - location = location.substring(1); - - if (!"pack.png".equals(location) && !"pack.txt".equals(location)) { - for (Path root : roots) { - String separator = root.getFileSystem().getSeparator(); - String pathName = location.replace("/", separator); - Path path = root.resolve(pathName); - - if (Files.exists(path)) { - return path; - } - } - } - - return null; - } -} diff --git a/libraries/resource-loader/resource-loader-mc11w49a-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/ResourceLoader.java b/libraries/resource-loader/resource-loader-mc11w49a-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/ResourceLoader.java deleted file mode 100644 index 8c1837b4..00000000 --- a/libraries/resource-loader/resource-loader-mc11w49a-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/ResourceLoader.java +++ /dev/null @@ -1,43 +0,0 @@ -package net.ornithemc.osl.resource.loader.impl; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import net.fabricmc.loader.api.FabricLoader; -import net.fabricmc.loader.api.ModContainer; - -import net.ornithemc.osl.resource.loader.api.ModTexturePack; -import net.ornithemc.osl.resource.loader.api.ResourceLoaderEvents; - -public class ResourceLoader { - - public static final Logger LOGGER = LogManager.getLogger("OSL|Resource Loader"); - - private static List DEFAULT_MOD_TEXTURE_PACKS; - - public static void resetDefaultTexturePacks() { - DEFAULT_MOD_TEXTURE_PACKS = null; - } - - public static List getDefaultModResourcePacks() { - if (DEFAULT_MOD_TEXTURE_PACKS == null) { - DEFAULT_MOD_TEXTURE_PACKS = new ArrayList<>(); - - for (ModContainer mod : FabricLoader.getInstance().getAllMods()) { - if ("builtin".equals(mod.getMetadata().getType())) { - continue; - } - - DEFAULT_MOD_TEXTURE_PACKS.add(new BuiltInModTexturePack(mod)); - } - - ResourceLoaderEvents.ADD_DEFAULT_TEXTURE_PACKS.invoker().accept(DEFAULT_MOD_TEXTURE_PACKS::add); - } - - return Collections.unmodifiableList(DEFAULT_MOD_TEXTURE_PACKS); - } -} diff --git a/libraries/resource-loader/resource-loader-mc11w49a-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/LanguageMixin.java b/libraries/resource-loader/resource-loader-mc11w49a-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/LanguageMixin.java deleted file mode 100644 index e9de9f74..00000000 --- a/libraries/resource-loader/resource-loader-mc11w49a-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/LanguageMixin.java +++ /dev/null @@ -1,78 +0,0 @@ -package net.ornithemc.osl.resource.loader.impl.mixin.client; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.Locale; -import java.util.Properties; - -import org.quiltmc.parsers.json.JsonReader; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import net.fabricmc.loader.api.metadata.ModMetadata; - -import net.minecraft.locale.Language; - -import net.ornithemc.osl.resource.loader.api.ModTexturePack; -import net.ornithemc.osl.resource.loader.impl.ResourceLoader; - -@Mixin(Language.class) -public class LanguageMixin { - - @Inject( - method = "loadTranslations(Ljava/util/Properties;Ljava/lang/String;)V", - at = @At( - value = "TAIL" - ) - ) - private void osl$resource_loader$loadModTranslations(Properties translations, String lang, CallbackInfo ci) throws IOException { - String path = "/assets/%s/lang/%s.%s"; - - for (ModTexturePack pack : ResourceLoader.getDefaultModResourcePacks()) { - ModMetadata mod = pack.getModMetadata(); - - loadTranslationsJson(translations, pack.getResource(String.format(path, mod.getId(), lang, "json"))); - loadTranslationsJson(translations, pack.getResource(String.format(path, mod.getId(), lang.toLowerCase(Locale.ROOT), "json"))); - loadTranslationsLang(translations, pack.getResource(String.format(path, mod.getId(), lang, "lang"))); - loadTranslationsLang(translations, pack.getResource(String.format(path, mod.getId(), lang.toLowerCase(Locale.ROOT), "lang"))); - } - } - - @Unique - private void loadTranslationsJson(Properties translations, InputStream is) throws IOException { - if (is != null){ - try (JsonReader reader = JsonReader.json(new InputStreamReader(is))) { - reader.beginObject(); - while (reader.hasNext()) { - translations.setProperty(reader.nextName(), reader.nextString()); - } - reader.endObject(); - } - } - } - - @Unique - private void loadTranslationsLang(Properties translations, InputStream is) throws IOException { - if (is != null){ - try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) { - String line; - while ((line = br.readLine()) != null) { - line = line.trim(); - if (line.isEmpty() || line.startsWith("#")) { - continue; - } - String[] args = line.split("=", 2); - if (args.length != 2) { - continue; - } - translations.setProperty(args[0], args[1]); - } - } - } - } -} diff --git a/libraries/resource-loader/resource-loader-mc11w49a-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TexturePackMixin.java b/libraries/resource-loader/resource-loader-mc11w49a-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TexturePackMixin.java deleted file mode 100644 index 865a51a1..00000000 --- a/libraries/resource-loader/resource-loader-mc11w49a-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TexturePackMixin.java +++ /dev/null @@ -1,54 +0,0 @@ -package net.ornithemc.osl.resource.loader.impl.mixin.client; - -import java.io.InputStream; -import java.util.LinkedHashSet; -import java.util.Set; - -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; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -import net.minecraft.client.resource.pack.TexturePack; - -import net.ornithemc.osl.resource.loader.api.ModTexturePack; -import net.ornithemc.osl.resource.loader.impl.ResourceLoader; - -@Mixin(TexturePack.class) -public class TexturePackMixin { - - private final Set modTextures = new LinkedHashSet<>(); - - @Inject( - method = "()V", - at = @At( - value = "TAIL" - ) - ) - private void osl$resource_loader$init(CallbackInfo ci) { - if (!((TexturePack)(Object)this instanceof ModTexturePack)) { - modTextures.addAll(ResourceLoader.getDefaultModResourcePacks()); - } - } - - @Inject( - method = "getResource(Ljava/lang/String;)Ljava/io/InputStream;", - cancellable = true, - at = @At( - value = "HEAD" - ) - ) - private void osl$resource_loader$getResource(String path, CallbackInfoReturnable cir) { - for (ModTexturePack textures : modTextures) { - try { - InputStream resource = textures.getResource(path); - - if (resource != null) { - cir.setReturnValue(resource); - } - } catch (Exception e) { - } - } - } -} diff --git a/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/gradle.properties b/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/gradle.properties index 63aec020..1c721c7e 100644 --- a/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/gradle.properties +++ b/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/gradle.properties @@ -4,5 +4,5 @@ max_mc_version = 13w07a minecraft_dependency = >=1.2-alpha.12.15.a <=1.5-alpha.13.7.a minecraft_version = 13w07a -feather_build = 1 +raven_build = 1 nests_build = 7 diff --git a/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/api/ModTexturePack.java b/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/api/ModTexturePack.java deleted file mode 100644 index dd3307f2..00000000 --- a/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/api/ModTexturePack.java +++ /dev/null @@ -1,11 +0,0 @@ -package net.ornithemc.osl.resource.loader.api; - -import net.fabricmc.loader.api.metadata.ModMetadata; - -import net.minecraft.client.resource.pack.TexturePack; - -public interface ModTexturePack extends TexturePack { - - ModMetadata getModMetadata(); - -} diff --git a/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/api/ResourceLoaderEvents.java b/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/api/ResourceLoaderEvents.java deleted file mode 100644 index b3fc8b24..00000000 --- a/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/api/ResourceLoaderEvents.java +++ /dev/null @@ -1,30 +0,0 @@ -package net.ornithemc.osl.resource.loader.api; - -import java.util.function.Consumer; - -import net.ornithemc.osl.core.api.events.Event; - -/** - * Events related to resource loading. - */ -public class ResourceLoaderEvents { - - /** - * This event is invoked upon game start-up, giving mod developers the - * opportunity to register custom built-in texture packs. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ResourceLoaderEvents.ADD_DEFAULT_TEXTURE_PACKS.register(adder -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event>> ADD_DEFAULT_TEXTURE_PACKS = Event.consumer(); - -} diff --git a/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/BuiltInModTexturePack.java b/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/BuiltInModTexturePack.java deleted file mode 100644 index 60c03bc6..00000000 --- a/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/BuiltInModTexturePack.java +++ /dev/null @@ -1,87 +0,0 @@ -package net.ornithemc.osl.resource.loader.impl; - -import java.io.IOException; -import java.io.InputStream; -import java.io.UncheckedIOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; - -import net.fabricmc.loader.api.ModContainer; -import net.fabricmc.loader.api.metadata.ModMetadata; - -import net.minecraft.client.resource.pack.AbstractTexturePack; -import net.minecraft.client.resource.pack.TexturePack; - -import net.ornithemc.osl.resource.loader.api.ModTexturePack; - -public class BuiltInModTexturePack extends AbstractTexturePack implements ModTexturePack { - - private final ModContainer mod; - - private final List roots; - - public BuiltInModTexturePack(ModContainer mod) { - super(mod.getMetadata().getId(), mod.getMetadata().getName()); - - this.mod = mod; - - this.roots = this.mod.getRootPaths(); - } - - @Override - public InputStream getResource(String location) { - Path path = getPath(location); - - if (path == null || !Files.exists(path)) { - if ("/pack.png".equals(location) || "/pack.txt".equals(location)) { - return TexturePack.class.getResourceAsStream(location); - } - - return null; - } - - // a bit of a hack to re-throw a checked exception - // because proguard stripped the exceptions off this method - try { - return Files.newInputStream(path); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - -// @Override - public boolean hasResource(String location) { - Path path = getPath(location); - return path != null && Files.exists(path); - } - - @Override - public boolean checkCompatibility() { - return true; - } - - @Override - public ModMetadata getModMetadata() { - return mod.getMetadata(); - } - - private Path getPath(String location) { - // the game accesses all resources with a leading '/' - location = location.substring(1); - - if (!"pack.png".equals(location) && !"pack.txt".equals(location)) { - for (Path root : roots) { - String separator = root.getFileSystem().getSeparator(); - String pathName = location.replace("/", separator); - Path path = root.resolve(pathName); - - if (Files.exists(path)) { - return path; - } - } - } - - return null; - } -} diff --git a/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/ClientResourcePacks.java b/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/ClientResourcePacks.java new file mode 100644 index 00000000..9d691a28 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/ClientResourcePacks.java @@ -0,0 +1,32 @@ +package net.ornithemc.osl.resource.loader.impl; + +import java.util.function.Consumer; + +import net.minecraft.client.resource.pack.TexturePack; + +import net.ornithemc.osl.resource.loader.api.resource.pack.PackPosition; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePack; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackRepository; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackSummary; + +public class ClientResourcePacks implements ResourcePackRepository.Source { + + private final TexturePack defaultPack; + + public ClientResourcePacks(TexturePack defaultPack) { + this.defaultPack = defaultPack; + } + + @Override + public void loadResourcePacks(Consumer consumer) { + ResourcePack pack = new WrappedTexturePack(this.defaultPack); + ResourcePackSummary summary = ResourcePackSummary.create( + pack, + true, + false, + PackPosition.BOTTOM + ); + + consumer.accept(summary); + } +} diff --git a/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/ResourceLoader.java b/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/ResourceLoader.java deleted file mode 100644 index 8c1837b4..00000000 --- a/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/ResourceLoader.java +++ /dev/null @@ -1,43 +0,0 @@ -package net.ornithemc.osl.resource.loader.impl; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import net.fabricmc.loader.api.FabricLoader; -import net.fabricmc.loader.api.ModContainer; - -import net.ornithemc.osl.resource.loader.api.ModTexturePack; -import net.ornithemc.osl.resource.loader.api.ResourceLoaderEvents; - -public class ResourceLoader { - - public static final Logger LOGGER = LogManager.getLogger("OSL|Resource Loader"); - - private static List DEFAULT_MOD_TEXTURE_PACKS; - - public static void resetDefaultTexturePacks() { - DEFAULT_MOD_TEXTURE_PACKS = null; - } - - public static List getDefaultModResourcePacks() { - if (DEFAULT_MOD_TEXTURE_PACKS == null) { - DEFAULT_MOD_TEXTURE_PACKS = new ArrayList<>(); - - for (ModContainer mod : FabricLoader.getInstance().getAllMods()) { - if ("builtin".equals(mod.getMetadata().getType())) { - continue; - } - - DEFAULT_MOD_TEXTURE_PACKS.add(new BuiltInModTexturePack(mod)); - } - - ResourceLoaderEvents.ADD_DEFAULT_TEXTURE_PACKS.invoker().accept(DEFAULT_MOD_TEXTURE_PACKS::add); - } - - return Collections.unmodifiableList(DEFAULT_MOD_TEXTURE_PACKS); - } -} diff --git a/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/ResourceManagerAdapter.java b/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/ResourceManagerAdapter.java new file mode 100644 index 00000000..483cd0b6 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/ResourceManagerAdapter.java @@ -0,0 +1,66 @@ +package net.ornithemc.osl.resource.loader.impl; + +import java.io.IOException; +import java.io.InputStream; + +import net.minecraft.client.render.texture.TextureManager; +import net.minecraft.client.resource.pack.TexturePack; + +import net.ornithemc.osl.resource.loader.api.resource.manager.ResourceManager; + +// one heck of a hack to inject OSL's resource manager +// as uninvasively as possible: turn it into a texture +// pack and select it in the texture pack manager +// TODO: switch to extends AbstractTexturePack once Ploceus is fixed +// it does not properly remap .excs files for method overrides +public class ResourceManagerAdapter implements TexturePack { + + private final ResourceManager resourceManager; + + public ResourceManagerAdapter(ResourceManager resourceManager) { + this.resourceManager = resourceManager; + } + + @Override + public void unload(TextureManager manager) { + } + + @Override + public void bindIcon(TextureManager manager) { + } + + @Override + public InputStream getResource(String path) throws IOException { + return this.resourceManager.getResource(path); + } + + @Override + public String getKey() { + return "osl:resource_manager"; + } + + @Override + public String getName() { + return "OSL Resource Manager"; + } + + @Override + public String getDescriptionLine1() { + return "Adapter for OSL's Resource Manager"; + } + + @Override + public String getDescriptionLine2() { + return null; + } + + @Override + public int getResolution() { + return 16; + } + + @Override + public boolean isCompatible() { + return true; + } +} diff --git a/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/WrappedTexturePack.java b/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/WrappedTexturePack.java new file mode 100644 index 00000000..53a89a68 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/WrappedTexturePack.java @@ -0,0 +1,89 @@ +package net.ornithemc.osl.resource.loader.impl; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +import net.minecraft.client.resource.pack.TexturePack; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.function.IOSupplier; +import net.ornithemc.osl.resource.loader.api.resource.ResourceType; +import net.ornithemc.osl.resource.loader.api.resource.pack.AbstractResourcePack; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourceConsumer; +import net.ornithemc.osl.resource.loader.impl.resource.pack.ResourcePacks; +import net.ornithemc.osl.text.api.TextComponents; + +public class WrappedTexturePack extends AbstractResourcePack { + + private final TexturePack pack; + private final IOSupplier metadata; + + public WrappedTexturePack(TexturePack pack) { + String description = pack.getDescriptionLine1(); + if (pack.getDescriptionLine2() != null) { + description += "\n" + pack.getDescriptionLine2(); + } + + this.pack = pack; + this.metadata = ResourcePacks.generateMetadataFile( + TextComponents.literal(description) + ); + } + + public static String getId(TexturePack pack) { + return "texturepack/" + pack.getName(); + } + + @Override + public String getId() { + return getId(this.pack); + } + + @Override + public boolean hasResource(String path) { + try { + return this.pack.getResource(path) != null; + } catch (IOException e) { + return false; + } + } + + @Override + public InputStream getResource(String path) throws IOException { + if (METADATA_FILE.equals(path)) { + return this.metadata.get(); + } + + return this.pack.getResource(path); + } + + @Override + protected Map> findNamespaces() { + return Collections.emptyMap(); + } + + @Override + public boolean hasResource(ResourceType type, NamespacedIdentifier location) { + return false; + } + + @Override + public IOSupplier getResource(ResourceType type, NamespacedIdentifier location) { + return null; + } + + @Override + public void findResources(ResourceType type, String namespace, String directory, ResourceConsumer consumer) { + } + + @Override + public void open() { + } + + @Override + public void close() { + } +} diff --git a/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/access/TexturePacksAccess.java b/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/access/TexturePacksAccess.java new file mode 100644 index 00000000..c6734a8a --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/access/TexturePacksAccess.java @@ -0,0 +1,9 @@ +package net.ornithemc.osl.resource.loader.impl.access; + +import net.minecraft.client.resource.pack.TexturePack; + +public interface TexturePacksAccess { + + TexturePack osl$resource_loader$getActuallySelected(); + +} diff --git a/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/AbstractTexturePackMixin.java b/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/AbstractTexturePackMixin.java index 3d0e5229..e4403a8d 100644 --- a/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/AbstractTexturePackMixin.java +++ b/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/AbstractTexturePackMixin.java @@ -1,55 +1,32 @@ package net.ornithemc.osl.resource.loader.impl.mixin.client; import java.io.InputStream; -import java.util.LinkedHashSet; -import java.util.Set; 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; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import net.minecraft.client.resource.pack.AbstractTexturePack; - -import net.ornithemc.osl.resource.loader.api.ModTexturePack; -import net.ornithemc.osl.resource.loader.impl.ResourceLoader; +import net.minecraft.client.resource.pack.BuiltInTexturePack; @Mixin(AbstractTexturePack.class) public class AbstractTexturePackMixin { - private final Set modTextures = new LinkedHashSet<>(); - - @Inject( - method = "(Ljava/lang/String;Ljava/io/File;Ljava/lang/String;)V", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/client/resource/pack/AbstractTexturePack;loadIcon()V" - ) - ) - private void osl$resource_loader$init(CallbackInfo ci) { - if (!(this instanceof ModTexturePack)) { - modTextures.addAll(ResourceLoader.getDefaultModResourcePacks()); - } - } - @Inject( - method = "getResource(Ljava/lang/String;)Ljava/io/InputStream;", + method = "getResource", cancellable = true, at = @At( - value = "HEAD" + value = "INVOKE", + target = "Ljava/lang/Class;getResourceAsStream(Ljava/lang/String;)Ljava/io/InputStream;" ) ) private void osl$resource_loader$getResource(String path, CallbackInfoReturnable cir) { - for (ModTexturePack textures : modTextures) { - try { - InputStream resource = textures.getResource(path); - - if (resource != null) { - cir.setReturnValue(resource); - } - } catch (Exception e) { - } + // the call to Class::getResourceAsStream is used as a fallback + // in case custom texture packs do not contain a resource + // we handle this by layering multiple packs + if (!((Object) this instanceof BuiltInTexturePack)) { + cir.setReturnValue(null); } } } diff --git a/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/LanguageMixin.java b/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/LanguageMixin.java deleted file mode 100644 index e9de9f74..00000000 --- a/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/LanguageMixin.java +++ /dev/null @@ -1,78 +0,0 @@ -package net.ornithemc.osl.resource.loader.impl.mixin.client; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.Locale; -import java.util.Properties; - -import org.quiltmc.parsers.json.JsonReader; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import net.fabricmc.loader.api.metadata.ModMetadata; - -import net.minecraft.locale.Language; - -import net.ornithemc.osl.resource.loader.api.ModTexturePack; -import net.ornithemc.osl.resource.loader.impl.ResourceLoader; - -@Mixin(Language.class) -public class LanguageMixin { - - @Inject( - method = "loadTranslations(Ljava/util/Properties;Ljava/lang/String;)V", - at = @At( - value = "TAIL" - ) - ) - private void osl$resource_loader$loadModTranslations(Properties translations, String lang, CallbackInfo ci) throws IOException { - String path = "/assets/%s/lang/%s.%s"; - - for (ModTexturePack pack : ResourceLoader.getDefaultModResourcePacks()) { - ModMetadata mod = pack.getModMetadata(); - - loadTranslationsJson(translations, pack.getResource(String.format(path, mod.getId(), lang, "json"))); - loadTranslationsJson(translations, pack.getResource(String.format(path, mod.getId(), lang.toLowerCase(Locale.ROOT), "json"))); - loadTranslationsLang(translations, pack.getResource(String.format(path, mod.getId(), lang, "lang"))); - loadTranslationsLang(translations, pack.getResource(String.format(path, mod.getId(), lang.toLowerCase(Locale.ROOT), "lang"))); - } - } - - @Unique - private void loadTranslationsJson(Properties translations, InputStream is) throws IOException { - if (is != null){ - try (JsonReader reader = JsonReader.json(new InputStreamReader(is))) { - reader.beginObject(); - while (reader.hasNext()) { - translations.setProperty(reader.nextName(), reader.nextString()); - } - reader.endObject(); - } - } - } - - @Unique - private void loadTranslationsLang(Properties translations, InputStream is) throws IOException { - if (is != null){ - try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) { - String line; - while ((line = br.readLine()) != null) { - line = line.trim(); - if (line.isEmpty() || line.startsWith("#")) { - continue; - } - String[] args = line.split("=", 2); - if (args.length != 2) { - continue; - } - translations.setProperty(args[0], args[1]); - } - } - } - } -} diff --git a/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TextureManagerMixin.java b/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TextureManagerMixin.java new file mode 100644 index 00000000..c3e6a7a7 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TextureManagerMixin.java @@ -0,0 +1,91 @@ +package net.ornithemc.osl.resource.loader.impl.mixin.client; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.client.render.texture.TextureManager; + +import net.ornithemc.osl.resource.loader.api.resource.manager.ResourceManager; +import net.ornithemc.osl.resource.loader.api.resource.reload.ResourceReloadListener; +import net.ornithemc.osl.resource.loader.impl.resource.manager.SimpleReloadableResourceManager; +import net.ornithemc.osl.resource.loader.impl.resource.repository.SimpleResourcePackRepository; + +@Mixin(TextureManager.class) +public class TextureManagerMixin implements ResourceReloadListener { + + @Unique + private SimpleResourcePackRepository packRepository; + @Unique + private SimpleReloadableResourceManager resourceManager; + + @Unique + private boolean vanillaReloading; + @Unique + private boolean reloading; + + @Shadow + private void reload() { } + + @Inject( + method = "", + at = @At( + value = "FIELD", + target = "Lnet/minecraft/client/render/texture/TextureManager;texturePacks:Lnet/minecraft/client/resource/pack/TexturePacks;", + ordinal = 0 + ) + ) + private void osl$resource_loader$initResourceManager(CallbackInfo ci) { + this.packRepository = SimpleResourcePackRepository.client(); + this.resourceManager = SimpleReloadableResourceManager.client(); + + // ensure the selected packs have been applied + this.resourceManager.reload(this.packRepository.openSelectedPacks()); + + // let this class act as the texture reloader + this.resourceManager.addReloader(this); + + this.resourceManager.init(); + } + + @Inject( + method = "reload", + cancellable = true, + at = @At( + value = "HEAD" + ) + ) + private void osl$resource_loader$startReload(CallbackInfo ci) { + if (!this.vanillaReloading) { + this.vanillaReloading = true; + + if (!this.reloading) { + this.resourceManager.reload(this.packRepository.openSelectedPacks()); + + // cancel this call as the resource manager will trigger + // another recursive call through this.resourcesReloaded + ci.cancel(); + } + } + } + + @Inject( + method = "reload", + at = @At( + value = "TAIL" + ) + ) + private void osl$resource_loader$endReload(CallbackInfo ci) { + this.vanillaReloading = false; + } + + @Override + public void resourcesReloaded(ResourceManager manager) { + this.reloading = true; + this.reload(); + this.reloading = false; + } +} diff --git a/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TexturePackListMixin.java b/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TexturePackListMixin.java new file mode 100644 index 00000000..ab0dab2e --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TexturePackListMixin.java @@ -0,0 +1,25 @@ +package net.ornithemc.osl.resource.loader.impl.mixin.client; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import net.minecraft.client.resource.pack.TexturePack; +import net.minecraft.client.resource.pack.TexturePacks; + +import net.ornithemc.osl.resource.loader.impl.access.TexturePacksAccess; + +@Mixin(targets = "net/minecraft/client/gui/screen/TexturePacksScreen$TexturePackList") +public class TexturePackListMixin { + + @Redirect( + method = "isEntrySelected", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/resource/pack/TexturePacks;getSelected()Lnet/minecraft/client/resource/pack/TexturePack;" + ) + ) + private TexturePack osl$resource_loader$getSelectedPack(TexturePacks texturePacks) { + return ((TexturePacksAccess) texturePacks).osl$resource_loader$getActuallySelected(); + } +} diff --git a/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TexturePacksMixin.java b/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TexturePacksMixin.java new file mode 100644 index 00000000..76e2019d --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TexturePacksMixin.java @@ -0,0 +1,194 @@ +package net.ornithemc.osl.resource.loader.impl.mixin.client; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import net.minecraft.client.resource.pack.TexturePack; +import net.minecraft.client.resource.pack.TexturePacks; + +import net.ornithemc.osl.resource.loader.api.resource.manager.ResourceManager; +import net.ornithemc.osl.resource.loader.api.resource.pack.PackPosition; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePack; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackRepository; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackSummary; +import net.ornithemc.osl.resource.loader.impl.ClientResourcePacks; +import net.ornithemc.osl.resource.loader.impl.ResourceManagerAdapter; +import net.ornithemc.osl.resource.loader.impl.WrappedTexturePack; +import net.ornithemc.osl.resource.loader.impl.access.TexturePacksAccess; +import net.ornithemc.osl.resource.loader.impl.resource.repository.BundledModResourcePacks; +import net.ornithemc.osl.resource.loader.impl.resource.repository.SimpleResourcePackRepository; + +@Mixin(TexturePacks.class) +public class TexturePacksMixin implements TexturePacksAccess, ResourcePackRepository.Source { + + @Shadow @Final + private static TexturePack DEFAULT_PACK; + + @Shadow + private List availablePacks; + @Shadow + private Map availablePacksByKey; + @Shadow + private TexturePack selected; + + @Unique + private SimpleResourcePackRepository resourcePacks; + @Unique + private TexturePack resourceManager; + + @Unique + private TexturePack actuallySelected; + @Unique + private boolean vanillaReloading; + @Unique + private boolean reloading; + + @Shadow + private void reload() { } + + @Inject( + method = "", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/resource/pack/TexturePacks;reload()V" + ) + ) + private void osl$resource_loader$initResourcePackRepository(CallbackInfo ci) { + this.resourcePacks = SimpleResourcePackRepository.client(); + // wrap the ResourceManager into a texture pack, and set this as selected + // this way we don't have to redirect every call to TexturePack::getResource! + this.resourceManager = new ResourceManagerAdapter(ResourceManager.client()); + + this.resourcePacks.setCallbacks(null, this::selectionChanged); + + this.resourcePacks.addSource(new ClientResourcePacks(DEFAULT_PACK)); + this.resourcePacks.addSource(new BundledModResourcePacks()); + this.resourcePacks.addSource(this); // texturepacks/ directory source + + this.resourcePacks.init(); + } + + @Inject( + method = "select", + cancellable = true, + at = @At( + value = "HEAD" + ) + ) + private void osl$resource_loader$select(TexturePack pack, CallbackInfoReturnable cir) { + if (pack == this.actuallySelected) { + cir.setReturnValue(false); + } + } + + @Inject( + method = "select", + at = @At( + value = "RETURN", + ordinal = 1 // only on texture pack change + ) + ) + private void osl$resource_loader$selected(TexturePack pack, CallbackInfoReturnable cir) { + this.selectPack(this.selected); + } + + @Inject( + method = "reload", + cancellable = true, + at = @At( + value = "HEAD" + ) + ) + private void osl$resource_loader$startReload(CallbackInfo ci) { + if (!this.vanillaReloading) { + this.vanillaReloading = true; + + if (!this.reloading) { + this.resourcePacks.reload(); + + // cancel this call as the pack repository will trigger + // another recursive call through this.loadResourcePacks + ci.cancel(); + } + } + } + + @Inject( + method = "reload", + at = @At( + value = "TAIL" + ) + ) + private void osl$resource_loader$endReload(CallbackInfo ci) { + this.vanillaReloading = false; + + if (this.actuallySelected != this.resourceManager) { + this.actuallySelected = this.selected; + this.selected = this.resourceManager; + } + } + + @Override + public void loadResourcePacks(Consumer consumer) { + this.reloading = true; + this.reload(); + this.reloading = false; + + for (TexturePack pack : this.availablePacks) { + if (pack != DEFAULT_PACK) { + ResourcePack resourcePack = new WrappedTexturePack(pack); + ResourcePackSummary summary = ResourcePackSummary.create( + resourcePack, + false, + false, + PackPosition.TOP + ); + + if (summary != null) { + consumer.accept(summary); + } + } + } + } + + @Override + public TexturePack osl$resource_loader$getActuallySelected() { + return this.actuallySelected; + } + + @Unique + private void selectPack(TexturePack pack) { + if (pack == null || pack == DEFAULT_PACK) { + this.resourcePacks.setSelectedPacks(Collections.emptyList()); + } else { + this.resourcePacks.setSelectedPacks(Collections.singletonList(WrappedTexturePack.getId(pack))); + } + + this.actuallySelected = pack; + this.selected = this.resourceManager; + } + + @Unique + private void selectionChanged() { + this.actuallySelected = DEFAULT_PACK; + + for (ResourcePackSummary summary : this.resourcePacks.getSelectedPacks()) { + TexturePack pack = this.availablePacksByKey.get(summary.getId()); + + if (pack != null) { + this.actuallySelected = pack; + } + } + } +} diff --git a/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/resources/fabric.mod.json b/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/resources/fabric.mod.json index 6e712288..f2307943 100644 --- a/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/resources/fabric.mod.json +++ b/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/resources/fabric.mod.json @@ -9,7 +9,9 @@ "depends": { "fabricloader": "\u003e\u003d0.18.0", "minecraft": "\u003e\u003d1.2-alpha.12.15.a \u003c\u003d1.5-alpha.13.7.a", - "osl-core": "\u003e\u003d0.7.0" + "osl-core": "\u003e\u003d0.7.0", + "osl-executors": "\u003e\u003d0.1.0-", + "osl-text-components": "\u003e\u003d0.1.0-" }, "name": "OSL Resource Loader", "description": "Resource loading API and events.", diff --git a/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/resources/osl.resource-loader.mixins.json b/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/resources/osl.resource-loader.mixins.json index b8089b92..b397b3db 100644 --- a/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/resources/osl.resource-loader.mixins.json +++ b/libraries/resource-loader/resource-loader-mc12w15a-mc13w07a/src/main/resources/osl.resource-loader.mixins.json @@ -7,7 +7,9 @@ ], "client": [ "client.AbstractTexturePackMixin", - "client.LanguageMixin" + "client.TextureManagerMixin", + "client.TexturePackListMixin", + "client.TexturePacksMixin" ], "server": [ ], diff --git a/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/gradle.properties b/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/gradle.properties index 7e8049ca..a1f81e8c 100644 --- a/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/gradle.properties +++ b/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/gradle.properties @@ -4,5 +4,5 @@ max_mc_version = 1.5.2 minecraft_dependency = >=1.5-alpha.13.9.a <=1.5.2 minecraft_version = 1.5.2 -feather_build = 1 +raven_build = 3 nests_build = 6 diff --git a/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/api/ModTexturePack.java b/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/api/ModTexturePack.java deleted file mode 100644 index dd3307f2..00000000 --- a/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/api/ModTexturePack.java +++ /dev/null @@ -1,11 +0,0 @@ -package net.ornithemc.osl.resource.loader.api; - -import net.fabricmc.loader.api.metadata.ModMetadata; - -import net.minecraft.client.resource.pack.TexturePack; - -public interface ModTexturePack extends TexturePack { - - ModMetadata getModMetadata(); - -} diff --git a/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/api/ResourceLoaderEvents.java b/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/api/ResourceLoaderEvents.java deleted file mode 100644 index b3fc8b24..00000000 --- a/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/api/ResourceLoaderEvents.java +++ /dev/null @@ -1,30 +0,0 @@ -package net.ornithemc.osl.resource.loader.api; - -import java.util.function.Consumer; - -import net.ornithemc.osl.core.api.events.Event; - -/** - * Events related to resource loading. - */ -public class ResourceLoaderEvents { - - /** - * This event is invoked upon game start-up, giving mod developers the - * opportunity to register custom built-in texture packs. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ResourceLoaderEvents.ADD_DEFAULT_TEXTURE_PACKS.register(adder -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event>> ADD_DEFAULT_TEXTURE_PACKS = Event.consumer(); - -} diff --git a/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/impl/BuiltInModTexturePack.java b/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/impl/BuiltInModTexturePack.java deleted file mode 100644 index e5dbcca4..00000000 --- a/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/impl/BuiltInModTexturePack.java +++ /dev/null @@ -1,87 +0,0 @@ -package net.ornithemc.osl.resource.loader.impl; - -import java.io.IOException; -import java.io.InputStream; -import java.io.UncheckedIOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; - -import net.fabricmc.loader.api.ModContainer; -import net.fabricmc.loader.api.metadata.ModMetadata; - -import net.minecraft.client.resource.pack.AbstractTexturePack; -import net.minecraft.client.resource.pack.TexturePack; - -import net.ornithemc.osl.resource.loader.api.ModTexturePack; - -public class BuiltInModTexturePack extends AbstractTexturePack implements ModTexturePack { - - private final ModContainer mod; - - private final List roots; - - public BuiltInModTexturePack(ModContainer mod) { - super(mod.getMetadata().getId(), null, mod.getMetadata().getName(), null); - - this.mod = mod; - - this.roots = this.mod.getRootPaths(); - } - - @Override - public InputStream openResource(String location) { - Path path = getPath(location); - - if (path == null || !Files.exists(path)) { - if ("/pack.png".equals(location) || "/pack.txt".equals(location)) { - return TexturePack.class.getResourceAsStream(location); - } - - return null; - } - - // a bit of a hack to re-throw a checked exception - // because proguard stripped the exceptions off this method - try { - return Files.newInputStream(path); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - @Override - public boolean hasResource(String location) { - Path path = getPath(location); - return path != null && Files.exists(path); - } - - @Override - public boolean isCompatible() { - return true; - } - - @Override - public ModMetadata getModMetadata() { - return mod.getMetadata(); - } - - private Path getPath(String location) { - // the game accesses all resources with a leading '/' - location = location.substring(1); - - if (!"pack.png".equals(location) && !"pack.txt".equals(location)) { - for (Path root : roots) { - String separator = root.getFileSystem().getSeparator(); - String pathName = location.replace("/", separator); - Path path = root.resolve(pathName); - - if (Files.exists(path)) { - return path; - } - } - } - - return null; - } -} diff --git a/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/impl/ClientResourcePacks.java b/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/impl/ClientResourcePacks.java new file mode 100644 index 00000000..9d691a28 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/impl/ClientResourcePacks.java @@ -0,0 +1,32 @@ +package net.ornithemc.osl.resource.loader.impl; + +import java.util.function.Consumer; + +import net.minecraft.client.resource.pack.TexturePack; + +import net.ornithemc.osl.resource.loader.api.resource.pack.PackPosition; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePack; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackRepository; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackSummary; + +public class ClientResourcePacks implements ResourcePackRepository.Source { + + private final TexturePack defaultPack; + + public ClientResourcePacks(TexturePack defaultPack) { + this.defaultPack = defaultPack; + } + + @Override + public void loadResourcePacks(Consumer consumer) { + ResourcePack pack = new WrappedTexturePack(this.defaultPack); + ResourcePackSummary summary = ResourcePackSummary.create( + pack, + true, + false, + PackPosition.BOTTOM + ); + + consumer.accept(summary); + } +} diff --git a/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/impl/ResourceLoader.java b/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/impl/ResourceLoader.java deleted file mode 100644 index 8c1837b4..00000000 --- a/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/impl/ResourceLoader.java +++ /dev/null @@ -1,43 +0,0 @@ -package net.ornithemc.osl.resource.loader.impl; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import net.fabricmc.loader.api.FabricLoader; -import net.fabricmc.loader.api.ModContainer; - -import net.ornithemc.osl.resource.loader.api.ModTexturePack; -import net.ornithemc.osl.resource.loader.api.ResourceLoaderEvents; - -public class ResourceLoader { - - public static final Logger LOGGER = LogManager.getLogger("OSL|Resource Loader"); - - private static List DEFAULT_MOD_TEXTURE_PACKS; - - public static void resetDefaultTexturePacks() { - DEFAULT_MOD_TEXTURE_PACKS = null; - } - - public static List getDefaultModResourcePacks() { - if (DEFAULT_MOD_TEXTURE_PACKS == null) { - DEFAULT_MOD_TEXTURE_PACKS = new ArrayList<>(); - - for (ModContainer mod : FabricLoader.getInstance().getAllMods()) { - if ("builtin".equals(mod.getMetadata().getType())) { - continue; - } - - DEFAULT_MOD_TEXTURE_PACKS.add(new BuiltInModTexturePack(mod)); - } - - ResourceLoaderEvents.ADD_DEFAULT_TEXTURE_PACKS.invoker().accept(DEFAULT_MOD_TEXTURE_PACKS::add); - } - - return Collections.unmodifiableList(DEFAULT_MOD_TEXTURE_PACKS); - } -} diff --git a/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/impl/ResourceManagerAdapter.java b/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/impl/ResourceManagerAdapter.java new file mode 100644 index 00000000..6f5e442e --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/impl/ResourceManagerAdapter.java @@ -0,0 +1,52 @@ +package net.ornithemc.osl.resource.loader.impl; + +import java.io.IOException; +import java.io.InputStream; + +import net.minecraft.client.resource.pack.AbstractTexturePack; + +import net.ornithemc.osl.resource.loader.api.resource.manager.ResourceManager; + +// one heck of a hack to inject OSL's resource manager +// as uninvasively as possible: turn it into a texture +// pack and select it in the texture pack manager +public class ResourceManagerAdapter extends AbstractTexturePack { + + private final ResourceManager resourceManager; + + public ResourceManagerAdapter(ResourceManager resourceManager) { + super( + "osl:resource_manager", + null, + "OSL Resource Manager", + null + ); + + this.resourceManager = resourceManager; + } + + @Override + public InputStream openResource(String path) throws IOException { + return this.resourceManager.getResource(path); + } + + @Override + public boolean hasResource(String path) { + return this.resourceManager.hasResource(path); + } + + @Override + public boolean isCompatible() { + return true; + } + + @Override + protected void loadIcon() { + } + + @Override + protected void loadDescription() { + this.descriptionLine1 = "Adapter for OSL's Resource Manager"; + this.descriptionLine2 = null; + } +} diff --git a/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/impl/WrappedTexturePack.java b/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/impl/WrappedTexturePack.java new file mode 100644 index 00000000..ec7702b9 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/impl/WrappedTexturePack.java @@ -0,0 +1,85 @@ +package net.ornithemc.osl.resource.loader.impl; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +import net.minecraft.client.resource.pack.TexturePack; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.function.IOSupplier; +import net.ornithemc.osl.resource.loader.api.resource.ResourceType; +import net.ornithemc.osl.resource.loader.api.resource.pack.AbstractResourcePack; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourceConsumer; +import net.ornithemc.osl.resource.loader.impl.resource.pack.ResourcePacks; +import net.ornithemc.osl.text.api.TextComponents; + +public class WrappedTexturePack extends AbstractResourcePack { + + private final TexturePack pack; + private final IOSupplier metadata; + + public WrappedTexturePack(TexturePack pack) { + String description = pack.getDescriptionLine1(); + if (pack.getDescriptionLine2() != null) { + description += "\n" + pack.getDescriptionLine2(); + } + + this.pack = pack; + this.metadata = ResourcePacks.generateMetadataFile( + TextComponents.literal(description) + ); + } + + public static String getId(TexturePack pack) { + return "texturepack/" + pack.getName(); + } + + @Override + public String getId() { + return getId(this.pack); + } + + @Override + public boolean hasResource(String path) { + return this.pack.hasResource(path, false); + } + + @Override + public InputStream getResource(String path) throws IOException { + if (METADATA_FILE.equals(path)) { + return this.metadata.get(); + } + + return this.pack.getResource(path, false); + } + + @Override + protected Map> findNamespaces() { + return Collections.emptyMap(); + } + + @Override + public boolean hasResource(ResourceType type, NamespacedIdentifier location) { + return false; + } + + @Override + public IOSupplier getResource(ResourceType type, NamespacedIdentifier location) { + return null; + } + + @Override + public void findResources(ResourceType type, String namespace, String directory, ResourceConsumer consumer) { + } + + @Override + public void open() { + } + + @Override + public void close() { + } +} diff --git a/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/impl/access/TexturePacksAccess.java b/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/impl/access/TexturePacksAccess.java new file mode 100644 index 00000000..c6734a8a --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/impl/access/TexturePacksAccess.java @@ -0,0 +1,9 @@ +package net.ornithemc.osl.resource.loader.impl.access; + +import net.minecraft.client.resource.pack.TexturePack; + +public interface TexturePacksAccess { + + TexturePack osl$resource_loader$getActuallySelected(); + +} diff --git a/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/AbstractTexturePackMixin.java b/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/AbstractTexturePackMixin.java index 2435fbfa..80a9c951 100644 --- a/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/AbstractTexturePackMixin.java +++ b/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/AbstractTexturePackMixin.java @@ -1,83 +1,27 @@ package net.ornithemc.osl.resource.loader.impl.mixin.client; -import java.io.InputStream; -import java.util.LinkedHashSet; -import java.util.Set; - 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; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.ModifyVariable; import net.minecraft.client.resource.pack.AbstractTexturePack; - -import net.ornithemc.osl.resource.loader.api.ModTexturePack; -import net.ornithemc.osl.resource.loader.impl.ResourceLoader; +import net.minecraft.client.resource.pack.TexturePack; @Mixin(AbstractTexturePack.class) public class AbstractTexturePackMixin { - private final Set modTextures = new LinkedHashSet<>(); - - @Inject( + @ModifyVariable( method = "", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/client/resource/pack/AbstractTexturePack;loadIcon()V" - ) - ) - private void osl$resource_loader$init(CallbackInfo ci) { - if (!(this instanceof ModTexturePack)) { - modTextures.addAll(ResourceLoader.getDefaultModResourcePacks()); - } - } - - @Inject( - method = "getResource(Ljava/lang/String;Z)Ljava/io/InputStream;", - cancellable = true, + argsOnly = true, at = @At( value = "FIELD", - ordinal = 0, target = "Lnet/minecraft/client/resource/pack/AbstractTexturePack;defaultTextures:Lnet/minecraft/client/resource/pack/TexturePack;" ) ) - private void osl$resource_loader$getResource(String path, boolean orDefault, CallbackInfoReturnable cir) { - if (orDefault) { - for (ModTexturePack textures : modTextures) { - try { - InputStream resource = textures.getResource(path, orDefault); - - if (resource != null) { - cir.setReturnValue(resource); - } - } catch (Exception e) { - } - } - } - } - - @Inject( - method = "hasResource(Ljava/lang/String;Z)Z", - cancellable = true, - at = @At( - value = "FIELD", - ordinal = 0, - target = "Lnet/minecraft/client/resource/pack/AbstractTexturePack;defaultTextures:Lnet/minecraft/client/resource/pack/TexturePack;" - ) - ) - private void osl$resource_loader$hasResource(String path, boolean orDefault, CallbackInfoReturnable cir) { - if (orDefault) { - for (ModTexturePack textures : modTextures) { - try { - boolean hasResource = textures.hasResource(path, orDefault); - - if (hasResource) { - cir.setReturnValue(hasResource); - } - } catch (Exception e) { - } - } - } + private TexturePack osl$resource_loader$removeFallbackTextures(TexturePack fallbackTextures) { + // the fallback texture pack is used in case custom + // texture packs do not contain a resource + // we handle this by layering multiple packs + return null; } } diff --git a/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/LanguageMixin.java b/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/LanguageMixin.java deleted file mode 100644 index e9de9f74..00000000 --- a/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/LanguageMixin.java +++ /dev/null @@ -1,78 +0,0 @@ -package net.ornithemc.osl.resource.loader.impl.mixin.client; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.Locale; -import java.util.Properties; - -import org.quiltmc.parsers.json.JsonReader; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import net.fabricmc.loader.api.metadata.ModMetadata; - -import net.minecraft.locale.Language; - -import net.ornithemc.osl.resource.loader.api.ModTexturePack; -import net.ornithemc.osl.resource.loader.impl.ResourceLoader; - -@Mixin(Language.class) -public class LanguageMixin { - - @Inject( - method = "loadTranslations(Ljava/util/Properties;Ljava/lang/String;)V", - at = @At( - value = "TAIL" - ) - ) - private void osl$resource_loader$loadModTranslations(Properties translations, String lang, CallbackInfo ci) throws IOException { - String path = "/assets/%s/lang/%s.%s"; - - for (ModTexturePack pack : ResourceLoader.getDefaultModResourcePacks()) { - ModMetadata mod = pack.getModMetadata(); - - loadTranslationsJson(translations, pack.getResource(String.format(path, mod.getId(), lang, "json"))); - loadTranslationsJson(translations, pack.getResource(String.format(path, mod.getId(), lang.toLowerCase(Locale.ROOT), "json"))); - loadTranslationsLang(translations, pack.getResource(String.format(path, mod.getId(), lang, "lang"))); - loadTranslationsLang(translations, pack.getResource(String.format(path, mod.getId(), lang.toLowerCase(Locale.ROOT), "lang"))); - } - } - - @Unique - private void loadTranslationsJson(Properties translations, InputStream is) throws IOException { - if (is != null){ - try (JsonReader reader = JsonReader.json(new InputStreamReader(is))) { - reader.beginObject(); - while (reader.hasNext()) { - translations.setProperty(reader.nextName(), reader.nextString()); - } - reader.endObject(); - } - } - } - - @Unique - private void loadTranslationsLang(Properties translations, InputStream is) throws IOException { - if (is != null){ - try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) { - String line; - while ((line = br.readLine()) != null) { - line = line.trim(); - if (line.isEmpty() || line.startsWith("#")) { - continue; - } - String[] args = line.split("=", 2); - if (args.length != 2) { - continue; - } - translations.setProperty(args[0], args[1]); - } - } - } - } -} diff --git a/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TextureManagerMixin.java b/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TextureManagerMixin.java new file mode 100644 index 00000000..c3e6a7a7 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TextureManagerMixin.java @@ -0,0 +1,91 @@ +package net.ornithemc.osl.resource.loader.impl.mixin.client; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.client.render.texture.TextureManager; + +import net.ornithemc.osl.resource.loader.api.resource.manager.ResourceManager; +import net.ornithemc.osl.resource.loader.api.resource.reload.ResourceReloadListener; +import net.ornithemc.osl.resource.loader.impl.resource.manager.SimpleReloadableResourceManager; +import net.ornithemc.osl.resource.loader.impl.resource.repository.SimpleResourcePackRepository; + +@Mixin(TextureManager.class) +public class TextureManagerMixin implements ResourceReloadListener { + + @Unique + private SimpleResourcePackRepository packRepository; + @Unique + private SimpleReloadableResourceManager resourceManager; + + @Unique + private boolean vanillaReloading; + @Unique + private boolean reloading; + + @Shadow + private void reload() { } + + @Inject( + method = "", + at = @At( + value = "FIELD", + target = "Lnet/minecraft/client/render/texture/TextureManager;texturePacks:Lnet/minecraft/client/resource/pack/TexturePacks;", + ordinal = 0 + ) + ) + private void osl$resource_loader$initResourceManager(CallbackInfo ci) { + this.packRepository = SimpleResourcePackRepository.client(); + this.resourceManager = SimpleReloadableResourceManager.client(); + + // ensure the selected packs have been applied + this.resourceManager.reload(this.packRepository.openSelectedPacks()); + + // let this class act as the texture reloader + this.resourceManager.addReloader(this); + + this.resourceManager.init(); + } + + @Inject( + method = "reload", + cancellable = true, + at = @At( + value = "HEAD" + ) + ) + private void osl$resource_loader$startReload(CallbackInfo ci) { + if (!this.vanillaReloading) { + this.vanillaReloading = true; + + if (!this.reloading) { + this.resourceManager.reload(this.packRepository.openSelectedPacks()); + + // cancel this call as the resource manager will trigger + // another recursive call through this.resourcesReloaded + ci.cancel(); + } + } + } + + @Inject( + method = "reload", + at = @At( + value = "TAIL" + ) + ) + private void osl$resource_loader$endReload(CallbackInfo ci) { + this.vanillaReloading = false; + } + + @Override + public void resourcesReloaded(ResourceManager manager) { + this.reloading = true; + this.reload(); + this.reloading = false; + } +} diff --git a/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TexturePackListMixin.java b/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TexturePackListMixin.java new file mode 100644 index 00000000..ab0dab2e --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TexturePackListMixin.java @@ -0,0 +1,25 @@ +package net.ornithemc.osl.resource.loader.impl.mixin.client; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import net.minecraft.client.resource.pack.TexturePack; +import net.minecraft.client.resource.pack.TexturePacks; + +import net.ornithemc.osl.resource.loader.impl.access.TexturePacksAccess; + +@Mixin(targets = "net/minecraft/client/gui/screen/TexturePacksScreen$TexturePackList") +public class TexturePackListMixin { + + @Redirect( + method = "isEntrySelected", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/resource/pack/TexturePacks;getSelected()Lnet/minecraft/client/resource/pack/TexturePack;" + ) + ) + private TexturePack osl$resource_loader$getSelectedPack(TexturePacks texturePacks) { + return ((TexturePacksAccess) texturePacks).osl$resource_loader$getActuallySelected(); + } +} diff --git a/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TexturePacksMixin.java b/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TexturePacksMixin.java new file mode 100644 index 00000000..76e2019d --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TexturePacksMixin.java @@ -0,0 +1,194 @@ +package net.ornithemc.osl.resource.loader.impl.mixin.client; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import net.minecraft.client.resource.pack.TexturePack; +import net.minecraft.client.resource.pack.TexturePacks; + +import net.ornithemc.osl.resource.loader.api.resource.manager.ResourceManager; +import net.ornithemc.osl.resource.loader.api.resource.pack.PackPosition; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePack; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackRepository; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackSummary; +import net.ornithemc.osl.resource.loader.impl.ClientResourcePacks; +import net.ornithemc.osl.resource.loader.impl.ResourceManagerAdapter; +import net.ornithemc.osl.resource.loader.impl.WrappedTexturePack; +import net.ornithemc.osl.resource.loader.impl.access.TexturePacksAccess; +import net.ornithemc.osl.resource.loader.impl.resource.repository.BundledModResourcePacks; +import net.ornithemc.osl.resource.loader.impl.resource.repository.SimpleResourcePackRepository; + +@Mixin(TexturePacks.class) +public class TexturePacksMixin implements TexturePacksAccess, ResourcePackRepository.Source { + + @Shadow @Final + private static TexturePack DEFAULT_PACK; + + @Shadow + private List availablePacks; + @Shadow + private Map availablePacksByKey; + @Shadow + private TexturePack selected; + + @Unique + private SimpleResourcePackRepository resourcePacks; + @Unique + private TexturePack resourceManager; + + @Unique + private TexturePack actuallySelected; + @Unique + private boolean vanillaReloading; + @Unique + private boolean reloading; + + @Shadow + private void reload() { } + + @Inject( + method = "", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/resource/pack/TexturePacks;reload()V" + ) + ) + private void osl$resource_loader$initResourcePackRepository(CallbackInfo ci) { + this.resourcePacks = SimpleResourcePackRepository.client(); + // wrap the ResourceManager into a texture pack, and set this as selected + // this way we don't have to redirect every call to TexturePack::getResource! + this.resourceManager = new ResourceManagerAdapter(ResourceManager.client()); + + this.resourcePacks.setCallbacks(null, this::selectionChanged); + + this.resourcePacks.addSource(new ClientResourcePacks(DEFAULT_PACK)); + this.resourcePacks.addSource(new BundledModResourcePacks()); + this.resourcePacks.addSource(this); // texturepacks/ directory source + + this.resourcePacks.init(); + } + + @Inject( + method = "select", + cancellable = true, + at = @At( + value = "HEAD" + ) + ) + private void osl$resource_loader$select(TexturePack pack, CallbackInfoReturnable cir) { + if (pack == this.actuallySelected) { + cir.setReturnValue(false); + } + } + + @Inject( + method = "select", + at = @At( + value = "RETURN", + ordinal = 1 // only on texture pack change + ) + ) + private void osl$resource_loader$selected(TexturePack pack, CallbackInfoReturnable cir) { + this.selectPack(this.selected); + } + + @Inject( + method = "reload", + cancellable = true, + at = @At( + value = "HEAD" + ) + ) + private void osl$resource_loader$startReload(CallbackInfo ci) { + if (!this.vanillaReloading) { + this.vanillaReloading = true; + + if (!this.reloading) { + this.resourcePacks.reload(); + + // cancel this call as the pack repository will trigger + // another recursive call through this.loadResourcePacks + ci.cancel(); + } + } + } + + @Inject( + method = "reload", + at = @At( + value = "TAIL" + ) + ) + private void osl$resource_loader$endReload(CallbackInfo ci) { + this.vanillaReloading = false; + + if (this.actuallySelected != this.resourceManager) { + this.actuallySelected = this.selected; + this.selected = this.resourceManager; + } + } + + @Override + public void loadResourcePacks(Consumer consumer) { + this.reloading = true; + this.reload(); + this.reloading = false; + + for (TexturePack pack : this.availablePacks) { + if (pack != DEFAULT_PACK) { + ResourcePack resourcePack = new WrappedTexturePack(pack); + ResourcePackSummary summary = ResourcePackSummary.create( + resourcePack, + false, + false, + PackPosition.TOP + ); + + if (summary != null) { + consumer.accept(summary); + } + } + } + } + + @Override + public TexturePack osl$resource_loader$getActuallySelected() { + return this.actuallySelected; + } + + @Unique + private void selectPack(TexturePack pack) { + if (pack == null || pack == DEFAULT_PACK) { + this.resourcePacks.setSelectedPacks(Collections.emptyList()); + } else { + this.resourcePacks.setSelectedPacks(Collections.singletonList(WrappedTexturePack.getId(pack))); + } + + this.actuallySelected = pack; + this.selected = this.resourceManager; + } + + @Unique + private void selectionChanged() { + this.actuallySelected = DEFAULT_PACK; + + for (ResourcePackSummary summary : this.resourcePacks.getSelectedPacks()) { + TexturePack pack = this.availablePacksByKey.get(summary.getId()); + + if (pack != null) { + this.actuallySelected = pack; + } + } + } +} diff --git a/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/resources/fabric.mod.json b/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/resources/fabric.mod.json index f03c27a7..b32b6842 100644 --- a/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/resources/fabric.mod.json +++ b/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/resources/fabric.mod.json @@ -6,10 +6,13 @@ "mixins": [ "osl.resource-loader.mixins.json" ], + "accessWidener": "osl.resource-loader.classtweaker", "depends": { "fabricloader": "\u003e\u003d0.18.0", "minecraft": "\u003e\u003d1.5-alpha.13.9.a \u003c\u003d1.5.2", - "osl-core": "\u003e\u003d0.7.0" + "osl-core": "\u003e\u003d0.7.0", + "osl-executors": "\u003e\u003d0.1.0-", + "osl-text-components": "\u003e\u003d0.1.0-" }, "name": "OSL Resource Loader", "description": "Resource loading API and events.", diff --git a/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/resources/osl.resource-loader.classtweaker b/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/resources/osl.resource-loader.classtweaker new file mode 100644 index 00000000..0b0c6173 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/resources/osl.resource-loader.classtweaker @@ -0,0 +1,3 @@ +classTweaker v1 named + +extendable method net/minecraft/client/resource/pack/AbstractTexturePack loadIcon ()V \ No newline at end of file diff --git a/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/resources/osl.resource-loader.mixins.json b/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/resources/osl.resource-loader.mixins.json index b8089b92..b397b3db 100644 --- a/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/resources/osl.resource-loader.mixins.json +++ b/libraries/resource-loader/resource-loader-mc13w09a-mc1.5.2/src/main/resources/osl.resource-loader.mixins.json @@ -7,7 +7,9 @@ ], "client": [ "client.AbstractTexturePackMixin", - "client.LanguageMixin" + "client.TextureManagerMixin", + "client.TexturePackListMixin", + "client.TexturePacksMixin" ], "server": [ ], diff --git a/libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/gradle.properties b/libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/gradle.properties deleted file mode 100644 index cbce933a..00000000 --- a/libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/gradle.properties +++ /dev/null @@ -1,7 +0,0 @@ -environment = client -min_mc_version = 13w26a -max_mc_version = 1.10.2 -minecraft_dependency = >=1.6-alpha.13.26.a <=1.10.2 - -minecraft_version = 1.10.2 -feather_build = 1 diff --git a/libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/src/main/java/net/ornithemc/osl/resource/loader/api/ModResourcePack.java b/libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/src/main/java/net/ornithemc/osl/resource/loader/api/ModResourcePack.java deleted file mode 100644 index 53c86d73..00000000 --- a/libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/src/main/java/net/ornithemc/osl/resource/loader/api/ModResourcePack.java +++ /dev/null @@ -1,11 +0,0 @@ -package net.ornithemc.osl.resource.loader.api; - -import net.fabricmc.loader.api.metadata.ModMetadata; - -import net.minecraft.client.resource.pack.ResourcePack; - -public interface ModResourcePack extends ResourcePack { - - ModMetadata getModMetadata(); - -} diff --git a/libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/src/main/java/net/ornithemc/osl/resource/loader/api/ResourceLoaderEvents.java b/libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/src/main/java/net/ornithemc/osl/resource/loader/api/ResourceLoaderEvents.java deleted file mode 100644 index 8f8909c9..00000000 --- a/libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/src/main/java/net/ornithemc/osl/resource/loader/api/ResourceLoaderEvents.java +++ /dev/null @@ -1,63 +0,0 @@ -package net.ornithemc.osl.resource.loader.api; - -import java.util.function.Consumer; - -import net.ornithemc.osl.core.api.events.Event; - -/** - * Events related to resource loading. - */ -public class ResourceLoaderEvents { - - /** - * This event is invoked upon game start-up, giving mod developers the - * opportunity to register custom built-in resource packs. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ResourceLoaderEvents.ADD_DEFAULT_RESOURCE_PACKS.register(adder -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event>> ADD_DEFAULT_RESOURCE_PACKS = Event.consumer(); - - /** - * This event is invoked before resources are reloaded. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ResourceLoaderEvents.START_RESOURCE_RELOAD.register(() -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event START_RESOURCE_RELOAD = Event.runnable(); - /** - * This event is invoked after resources are reloaded. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ResourceLoaderEvents.END_RESOURCE_RELOAD.register(() -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event END_RESOURCE_RELOAD = Event.runnable(); - -} diff --git a/libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/src/main/java/net/ornithemc/osl/resource/loader/api/ResourceUtils.java b/libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/src/main/java/net/ornithemc/osl/resource/loader/api/ResourceUtils.java deleted file mode 100644 index 32dcaf62..00000000 --- a/libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/src/main/java/net/ornithemc/osl/resource/loader/api/ResourceUtils.java +++ /dev/null @@ -1,12 +0,0 @@ -package net.ornithemc.osl.resource.loader.api; - -public class ResourceUtils { - - public static boolean isValidNamespace(String namespace) { - return namespace.chars().allMatch(chr -> chr == '-' || chr == '.' || chr == '_' || (chr >= 'a' && chr <= 'z') || (chr >= 'A' && chr <= 'Z') || (chr >= '0' && chr <= '9')); - } - - public static boolean isValidPath(String namespace) { - return namespace.chars().allMatch(chr -> chr == '-' || chr == '.' || chr == '_' || chr == '/' || (chr >= 'a' && chr <= 'z') || (chr >= 'A' && chr <= 'Z') || (chr >= '0' && chr <= '9')); - } -} diff --git a/libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/src/main/java/net/ornithemc/osl/resource/loader/impl/BuiltInModResourcePack.java b/libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/src/main/java/net/ornithemc/osl/resource/loader/impl/BuiltInModResourcePack.java deleted file mode 100644 index 475c9291..00000000 --- a/libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/src/main/java/net/ornithemc/osl/resource/loader/impl/BuiltInModResourcePack.java +++ /dev/null @@ -1,160 +0,0 @@ -package net.ornithemc.osl.resource.loader.impl; - -import java.awt.image.BufferedImage; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.nio.file.DirectoryStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import javax.imageio.ImageIO; - -import com.google.gson.JsonObject; - -import net.fabricmc.loader.api.ModContainer; -import net.fabricmc.loader.api.metadata.ModMetadata; - -import net.minecraft.client.resource.metadata.ResourceMetadataSection; -import net.minecraft.client.resource.metadata.ResourceMetadataSerializerRegistry; -import net.minecraft.client.resource.pack.ResourcePack; -import net.minecraft.resource.Identifier; - -import net.ornithemc.osl.resource.loader.api.ModResourcePack; -import net.ornithemc.osl.resource.loader.api.ResourceUtils; -import net.ornithemc.osl.resource.loader.impl.mixin.client.CustomResourcePackInvoker; - -public class BuiltInModResourcePack implements ModResourcePack { - - private final ModContainer mod; - private final Set namespaces; - - private final List roots; - //private final String separator; - - private JsonObject generatedPackMetadata; - - public BuiltInModResourcePack(ModContainer mod) { - this.mod = mod; - this.namespaces = new HashSet<>(); - - this.roots = this.mod.getRootPaths(); - - findNamespaces(); - } - - private void findNamespaces() { - for (Path root : roots) { - Path assets = root.resolve("assets"); - - if (Files.isDirectory(assets)) { - String separator = root.getFileSystem().getSeparator(); - - try (DirectoryStream ds = Files.newDirectoryStream(assets)) { - for (Path p : ds) { - String s = p.getFileName().toString(); - String namespace = s.replace(separator, ""); - - if (ResourceUtils.isValidNamespace(namespace)) { - namespaces.add(namespace); - } - } - } catch (IOException e) { - ResourceLoader.LOGGER.warn("failed to parse namespaces for built-in resource pack for mod " + mod.getMetadata().getId(), e); - } - } - } - } - - @Override - public InputStream getResource(Identifier location) throws IOException { - Path path = getPath(location); - - if (path == null || !Files.exists(path)) { - if ("pack.mcmeta".equals(location.getPath())) { - JsonObject metadata = generatePackMetadata(); - String serializedMetadata = metadata.toString(); - - return new ByteArrayInputStream(serializedMetadata.getBytes(StandardCharsets.UTF_8)); - } - if ("pack.png".equals(location.getPath())) { - return ResourcePack.class.getResourceAsStream("/" + location.getPath()); - } - - return null; - } - - return Files.newInputStream(path); - } - - @Override - public boolean hasResource(Identifier location) { - Path path = getPath(location); - return path != null && Files.exists(path); - } - - @Override - public Set getNamespaces() { - return namespaces; - } - - @Override - public T getMetadataSection(ResourceMetadataSerializerRegistry metadataSerializers, String name) throws IOException { - try (InputStream is = getResource(new Identifier("pack.mcmeta"))) { - return CustomResourcePackInvoker.invokeGetMetadataSection(metadataSerializers, is, name); - } - } - - @Override - public BufferedImage getIcon() throws IOException { - return ImageIO.read(getResource(new Identifier("pack.png"))); - } - - @Override - public String getName() { - return getModMetadata().getName(); - } - - @Override - public ModMetadata getModMetadata() { - return mod.getMetadata(); - } - - private Path getPath(Identifier location) { - return getPath(getPathName(location)); - } - - private Path getPath(String path) { - for (Path root : roots) { - String separator = root.getFileSystem().getSeparator(); - String pathName = path.replace("/", separator); - Path p = root.resolve(pathName); - - if (Files.exists(p)) { - return p; - } - } - - return null; - } - - private String getPathName(Identifier location) { - return String.format("assets/%s/%s", location.getNamespace(), location.getPath()); - } - - private JsonObject generatePackMetadata() { - if (generatedPackMetadata == null) { - generatedPackMetadata = new JsonObject(); - JsonObject pack = new JsonObject(); - pack.addProperty("pack_format", ResourceLoader.getPackFormat()); - pack.addProperty("description", getModMetadata().getDescription()); - generatedPackMetadata.add("pack", pack); - } - - return generatedPackMetadata; - } -} diff --git a/libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/src/main/java/net/ornithemc/osl/resource/loader/impl/ResourceLoader.java b/libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/src/main/java/net/ornithemc/osl/resource/loader/impl/ResourceLoader.java deleted file mode 100644 index 92375b37..00000000 --- a/libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/src/main/java/net/ornithemc/osl/resource/loader/impl/ResourceLoader.java +++ /dev/null @@ -1,37 +0,0 @@ -package net.ornithemc.osl.resource.loader.impl; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import net.ornithemc.osl.resource.loader.api.ModResourcePack; - -public class ResourceLoader { - - public static final Logger LOGGER = LogManager.getLogger("OSL|Resource Loader"); - - private static final List DEFAULT_MOD_RESOURCE_PACKS = new ArrayList<>(); - - private static int packFormat = -1; - - public static void setPackFormat(int format) { - if (packFormat < 0) { - packFormat = format; - } - } - - public static boolean addDefaultModResourcePack(ModResourcePack pack) { - return DEFAULT_MOD_RESOURCE_PACKS.add(pack); - } - - public static List getDefaultModResourcePacks() { - return Collections.unmodifiableList(DEFAULT_MOD_RESOURCE_PACKS); - } - - public static int getPackFormat() { - return packFormat; - } -} diff --git a/libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/LocaleMixin.java b/libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/LocaleMixin.java deleted file mode 100644 index 1f3438a7..00000000 --- a/libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/LocaleMixin.java +++ /dev/null @@ -1,107 +0,0 @@ -package net.ornithemc.osl.resource.loader.impl.mixin.client; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.quiltmc.parsers.json.JsonReader; - -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import com.llamalad7.mixinextras.injector.wrapoperation.Operation; -import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; -import com.llamalad7.mixinextras.sugar.Local; - -import net.minecraft.client.resource.Resource; -import net.minecraft.client.resource.SimpleResource; -import net.minecraft.client.resource.language.Locale; -import net.minecraft.client.resource.manager.ResourceManager; -import net.minecraft.resource.Identifier; - -@Mixin(Locale.class) -public abstract class LocaleMixin { - - @Final - @Shadow - private Map translations; - - @Shadow - protected abstract void load(List resources); - - @Inject( - method = "load(Lnet/minecraft/client/resource/manager/ResourceManager;Ljava/util/List;)V", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/client/resource/manager/ResourceManager;getResources(Lnet/minecraft/resource/Identifier;)Ljava/util/List;" - ) - ) - private void osl$resource_loader$loadTranslationFiles(CallbackInfo ci, - @Local(argsOnly = true) ResourceManager resourceManager, - @Local(ordinal = 0) String languageCode, - @Local(ordinal = 2) String namespace) { - String[] paths = new String[] { - String.format("lang/%s.json", languageCode), - String.format("lang/%s.lang", languageCode.toLowerCase(java.util.Locale.ROOT)), - String.format("lang/%s.json", languageCode.toLowerCase(java.util.Locale.ROOT)) - }; - for (String path : paths) { - try { - this.load(resourceManager.getResources(new Identifier(namespace, path))); - } catch (IOException ignored) { - } - } - } - - @WrapOperation( - method = "load(Ljava/util/List;)V", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/client/resource/language/Locale;load(Ljava/io/InputStream;)V" - ) - ) - private void osl$resource_loader$loadTranslationFiles(Locale instance, InputStream is, Operation original, @Local Resource resource) throws IOException{ - boolean loadAsJson = false; - - if (resource instanceof SimpleResource) { - Identifier location = ((SimpleResourceAccessor)resource).osl$resource_loader$getLocation(); - - if (location.getPath().endsWith(".json")) { - loadAsJson = true; - } - } - - if (loadAsJson){ - loadJson(is); - } else { - original.call(instance, is); // load .lang - } - } - - @Unique - private void loadJson(InputStream stream) { - if (stream == null) { - return; - } - JsonReader reader = JsonReader.json(new InputStreamReader(stream)); - - Map entries = new HashMap<>(); - try { - reader.beginObject(); - while (reader.hasNext()) { - entries.put(reader.nextName(), reader.nextString()); - } - reader.endObject(); - } catch (IOException ignored) { - } - translations.putAll(entries); - } -} diff --git a/libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/MinecraftMixin.java b/libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/MinecraftMixin.java deleted file mode 100644 index f041c92b..00000000 --- a/libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/MinecraftMixin.java +++ /dev/null @@ -1,91 +0,0 @@ -package net.ornithemc.osl.resource.loader.impl.mixin.client; - -import java.io.IOException; -import java.util.List; - -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import net.fabricmc.loader.api.FabricLoader; -import net.fabricmc.loader.api.ModContainer; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.resource.metadata.ResourceMetadataSerializerRegistry; -import net.minecraft.client.resource.metadata.ResourcePackMetadata; -import net.minecraft.client.resource.pack.BuiltInResourcePack; -import net.minecraft.client.resource.pack.ResourcePack; - -import net.ornithemc.osl.resource.loader.api.ModResourcePack; -import net.ornithemc.osl.resource.loader.api.ResourceLoaderEvents; -import net.ornithemc.osl.resource.loader.impl.BuiltInModResourcePack; -import net.ornithemc.osl.resource.loader.impl.ResourceLoader; - -@Mixin(Minecraft.class) -public class MinecraftMixin { - - @Shadow @Final - private ResourceMetadataSerializerRegistry resourceMetadataSerializerRegistry; - @Shadow @Final - private List defaultResourcePacks; - @Shadow @Final - private BuiltInResourcePack defaultResourcePack; - - - @Inject( - method = "init", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/client/Minecraft;reloadResources()V" - ) - ) - private void osl$resource_loader$addDefaultResourcePacks(CallbackInfo ci) { - try { - ResourcePackMetadata metadata = defaultResourcePack.getMetadataSection(resourceMetadataSerializerRegistry, "pack"); - int format = metadata.getFormat(); - - ResourceLoader.setPackFormat(format); - } catch (IOException e) { - ResourceLoader.LOGGER.info("unable to parse resource pack format from default resource pack", e); - } - - for (ModContainer mod : FabricLoader.getInstance().getAllMods()) { - if ("builtin".equals(mod.getMetadata().getType())) { - continue; - } - - osl$resource_loader$addDefaultResourcePack(new BuiltInModResourcePack(mod)); - } - - ResourceLoaderEvents.ADD_DEFAULT_RESOURCE_PACKS.invoker().accept(this::osl$resource_loader$addDefaultResourcePack); - } - - @Inject( - method = "reloadResources", - at = @At( - value = "HEAD" - ) - ) - private void osl$resource_loader$startResourceReload(CallbackInfo ci) { - ResourceLoaderEvents.START_RESOURCE_RELOAD.invoker().run(); - } - - @Inject( - method = "reloadResources", - at = @At( - value = "TAIL" - ) - ) - private void osl$resource_loader$endResourceReload(CallbackInfo ci) { - ResourceLoaderEvents.END_RESOURCE_RELOAD.invoker().run(); - } - - private void osl$resource_loader$addDefaultResourcePack(ModResourcePack pack) { - if (ResourceLoader.addDefaultModResourcePack(pack)) { - defaultResourcePacks.add(pack); - } - } -} diff --git a/libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/SimpleResourceAccessor.java b/libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/SimpleResourceAccessor.java deleted file mode 100644 index fd2f248b..00000000 --- a/libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/SimpleResourceAccessor.java +++ /dev/null @@ -1,16 +0,0 @@ -package net.ornithemc.osl.resource.loader.impl.mixin.client; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -import net.minecraft.client.resource.SimpleResource; -import net.minecraft.resource.Identifier; - -@Mixin(SimpleResource.class) -public interface SimpleResourceAccessor { - - // the SimpleResource#getLocation method only exists in 14w25a and above - @Accessor("location") - Identifier osl$resource_loader$getLocation(); - -} diff --git a/libraries/resource-loader/resource-loader-mca1.2.2-mc11w48a/build.gradle b/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/build.gradle similarity index 100% rename from libraries/resource-loader/resource-loader-mca1.2.2-mc11w48a/build.gradle rename to libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/build.gradle diff --git a/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/gradle.properties b/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/gradle.properties new file mode 100644 index 00000000..35726568 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/gradle.properties @@ -0,0 +1,9 @@ +environment = client +min_mc_version = 13w26a +max_mc_version = 1.8.2-pre4 +minecraft_dependency = >=1.6-alpha.13.26.a <=1.8.2-rc.4 + +minecraft_version = 1.8.2-pre4 +raven_build = 1 +sparrow_build = 1 +nests_build = 3 diff --git a/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/ClientResourcePacks.java b/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/ClientResourcePacks.java new file mode 100644 index 00000000..8bf51d4d --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/ClientResourcePacks.java @@ -0,0 +1,62 @@ +package net.ornithemc.osl.resource.loader.impl; + +import java.util.function.Consumer; + +import net.minecraft.client.gui.screen.resourcepack.ResourcePackEntry; +import net.minecraft.client.resource.pack.ResourcePacks; + +import net.ornithemc.osl.resource.loader.api.resource.pack.PackPosition; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePack; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackRepository; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackSummary; +import net.ornithemc.osl.resource.loader.impl.adapter.WrappedResourcePack; + +public class ClientResourcePacks implements ResourcePackRepository.Source { + + public static final boolean NEW_RESOURCE_PACKS_GUI; + + static { + boolean exists; + + try { + exists = ResourcePackEntry.class != null; + } catch (Throwable t) { + exists = false; + } + + NEW_RESOURCE_PACKS_GUI = exists; + } + + private final ResourcePacks resourcePacks; + + public ClientResourcePacks(ResourcePacks resourcePacks) { + this.resourcePacks = resourcePacks; + } + + @Override + public void loadResourcePacks(Consumer consumer) { + ResourcePack pack = new WrappedResourcePack(this.resourcePacks.defaultPack); + ResourcePackSummary summary = ResourcePackSummary.create( + pack, + true, + false, + PackPosition.BOTTOM + ); + + consumer.accept(summary); + + if (NEW_RESOURCE_PACKS_GUI && this.resourcePacks.getServerPack() != null) { + ResourcePack serverPack = new WrappedResourcePack(this.resourcePacks.getServerPack()); + ResourcePackSummary serverSummary = ResourcePackSummary.create( + serverPack, + true, + true, + PackPosition.TOP + ); + + if (serverSummary != null) { + consumer.accept(serverSummary); + } + } + } +} diff --git a/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/Adapters.java b/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/Adapters.java new file mode 100644 index 00000000..484aac7d --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/Adapters.java @@ -0,0 +1,69 @@ +package net.ornithemc.osl.resource.loader.impl.adapter; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import net.minecraft.client.resource.metadata.ResourceMetadataSerializerRegistry; +import net.minecraft.resource.Identifier; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.resource.loader.api.resource.Resource; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePack; + +class Adapters { + + static Identifier identifier(NamespacedIdentifier id) { + return id instanceof Identifier ? (Identifier) id : new Identifier(id.namespace(), id.identifier()); + } + + static net.minecraft.client.resource.Resource resource(ResourceMetadataSerializerRegistry metadataSerializers, Resource resource) throws IOException { + return new ResourceAdapter(metadataSerializers, resource); + } + + static net.minecraft.client.resource.Resource resource(ResourceMetadataSerializerRegistry metadataSerializers, NamespacedIdentifier location, Optional resource) throws IOException { + if (resource.isPresent()) { + return resource(metadataSerializers, resource.get()); + } + + throw new FileNotFoundException(location.toString()); + } + + static List resources(ResourceMetadataSerializerRegistry metadataSerializers, List resources) throws IOException { + List rs = new ArrayList<>(); + + for (Resource resource : resources) { + rs.add(resource(metadataSerializers, resource)); + } + + return Collections.unmodifiableList(rs); + } + + static net.minecraft.client.resource.pack.ResourcePack resourcePack(ResourcePack pack) { + if (pack instanceof WrappedResourcePack) { + return ((WrappedResourcePack) pack).pack; + } else { + return new ResourcePackAdapter(pack); + } + } + + static ResourcePack resourcePack(net.minecraft.client.resource.pack.ResourcePack pack) { + if (pack instanceof ResourcePackAdapter) { + return ((ResourcePackAdapter) pack).pack; + } else { + return new WrappedResourcePack(pack); + } + } + + static List packs(List packs) { + return packs.stream().map(Adapters::resourcePack).collect(Collectors.toList()); + } + + static List resourcePacks(List packs) { + return packs.stream().map(Adapters::resourcePack).collect(Collectors.toList()); + } +} diff --git a/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourceAdapter.java b/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourceAdapter.java new file mode 100644 index 00000000..5206b146 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourceAdapter.java @@ -0,0 +1,78 @@ +package net.ornithemc.osl.resource.loader.impl.adapter; + +import java.io.IOException; +import java.io.InputStream; + +import com.google.gson.JsonObject; + +import net.minecraft.client.resource.metadata.ResourceMetadataSection; +import net.minecraft.client.resource.metadata.ResourceMetadataSerializerRegistry; +import net.minecraft.resource.Identifier; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.resource.loader.api.resource.Resource; +import net.ornithemc.osl.resource.loader.api.resource.ResourceMetadata; +import net.ornithemc.osl.resource.loader.impl.resource.JsonResourceMetadata; +import net.ornithemc.osl.resource.loader.impl.resource.ResourceLocationAccess; + +class ResourceAdapter implements net.minecraft.client.resource.Resource, ResourceLocationAccess { + + private final ResourceMetadataSerializerRegistry metadataSerializers; + private final Identifier location; + private final InputStream resource; + private final ResourceMetadata metadata; + private String sourceName; + + ResourceAdapter(ResourceMetadataSerializerRegistry metadataSerializers, Resource resource) throws IOException { + ResourceMetadata metadata; + + try { + metadata = resource.metadata(); + } catch (IOException e) { + metadata = ResourceMetadata.EMPTY; + } + + this.metadataSerializers = metadataSerializers; + this.location = Adapters.identifier(resource.location()); + this.resource = resource.open(); + this.metadata = metadata; + this.sourceName = resource.sourceName(); + } + + @Override + public Identifier getLocation() { + return this.location; + } + + @Override + public NamespacedIdentifier resourceLocation() { + return (NamespacedIdentifier) this.location; + } + + @Override + public InputStream asStream() { + return this.resource; + } + + @Override + public T getMetadata(String name) { + if (this.metadata instanceof JsonResourceMetadata) { + JsonResourceMetadata meta = (JsonResourceMetadata) this.metadata; + JsonObject metadataJson = meta.asJsonObject(); + + return this.metadataSerializers.readMetadata(name, metadataJson); + } else { + return null; + } + } + + @Override + public boolean hasMetadata() { + return this.metadata != ResourceMetadata.EMPTY; + } + + @Override + public String getSourceName() { + return this.sourceName; + } +} diff --git a/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourceManagerAdapter.java b/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourceManagerAdapter.java new file mode 100644 index 00000000..d33284da --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourceManagerAdapter.java @@ -0,0 +1,73 @@ +package net.ornithemc.osl.resource.loader.impl.adapter; + +import java.io.IOException; +import java.util.List; +import java.util.Set; + +import net.minecraft.client.resource.Resource; +import net.minecraft.client.resource.metadata.ResourceMetadataSerializerRegistry; +import net.minecraft.client.resource.pack.ResourcePack; +import net.minecraft.resource.Identifier; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.resource.loader.api.resource.manager.ReloadableResourceManager; +import net.ornithemc.osl.resource.loader.api.resource.manager.ResourceManager; +import net.ornithemc.osl.resource.loader.api.resource.reload.ResourceReloadListener; + +public class ResourceManagerAdapter implements net.minecraft.client.resource.manager.ReloadableResourceManager { + + private final ResourceMetadataSerializerRegistry metadataSerializers; + private final ReloadableResourceManager resourceManager; + + public ResourceManagerAdapter(ResourceMetadataSerializerRegistry metadataSerializers, ReloadableResourceManager resourceManager) { + this.metadataSerializers = metadataSerializers; + this.resourceManager = resourceManager; + } + + @Override + public Set getNamespaces() { + return this.resourceManager.getNamespaces(); + } + + @Override + public Resource getResource(Identifier location) throws IOException { + return Adapters.resource(this.metadataSerializers, (NamespacedIdentifier) location, this.resourceManager.getResource((NamespacedIdentifier) location)); + } + + @Override + public List getResources(Identifier location) throws IOException { + return Adapters.resources(this.metadataSerializers, this.resourceManager.getResourceStack((NamespacedIdentifier) location)); + } + + @Override + public void addListener(net.minecraft.client.resource.manager.ResourceReloadListener listener) { + this.resourceManager.addReloader(new WrappedResourceReloadListener(listener)); + } + + @Override + public void reload(List packs) { + this.resourceManager.reload(Adapters.resourcePacks(packs)); + } + + private class WrappedResourceReloadListener implements ResourceReloadListener { + + private final net.minecraft.client.resource.manager.ResourceReloadListener listener; + + private WrappedResourceReloadListener(net.minecraft.client.resource.manager.ResourceReloadListener listener) { + this.listener = listener; + + // Vanilla's reload listeners are triggered immediately after registering + // We must emulate this or the game's initialization will fail + this.listener.reload(ResourceManagerAdapter.this); + } + + @Override + public void resourcesReloaded(ResourceManager manager) { + if (manager == ResourceManagerAdapter.this.resourceManager) { + this.listener.reload(ResourceManagerAdapter.this); + } else { + throw new IllegalStateException("Woah there, who hijacked the resource manager?"); + } + } + } +} diff --git a/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourcePackAdapter.java b/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourcePackAdapter.java new file mode 100644 index 00000000..aa11936f --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourcePackAdapter.java @@ -0,0 +1,78 @@ +package net.ornithemc.osl.resource.loader.impl.adapter; + +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.InputStream; +import java.util.Set; + +import javax.imageio.ImageIO; + +import net.minecraft.client.resource.metadata.ResourceMetadataSection; +import net.minecraft.client.resource.metadata.ResourceMetadataSerializerRegistry; +import net.minecraft.resource.Identifier; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.function.IOSupplier; +import net.ornithemc.osl.resource.loader.api.resource.ResourcePath; +import net.ornithemc.osl.resource.loader.api.resource.ResourceType; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePack; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePackFileNotFoundException; +import net.ornithemc.osl.resource.loader.impl.mixin.client.CustomResourcePackAccess; + +class ResourcePackAdapter implements net.minecraft.client.resource.pack.ResourcePack { + + final ResourcePack pack; + + ResourcePackAdapter(ResourcePack pack) { + this.pack = pack; + } + + @Override + public InputStream getResource(Identifier location) throws IOException { + IOSupplier resource = this.pack.getResource(ResourceType.CLIENT_ASSETS, (NamespacedIdentifier) location); // TODO: interface injection + + if (resource != null) { + return resource.get(); + } + + throw new ResourcePackFileNotFoundException(this.pack, ResourcePath.nameOf(ResourceType.CLIENT_ASSETS, (NamespacedIdentifier) location)); + } + + @Override + public boolean hasResource(Identifier location) { + return this.pack.hasResource(ResourceType.CLIENT_ASSETS, (NamespacedIdentifier) location); + } + + @Override + public Set getNamespaces() { + return this.pack.getNamespaces(ResourceType.CLIENT_ASSETS); + } + + @Override + public T getMetadataSection(ResourceMetadataSerializerRegistry metadataSerializers, String name) throws IOException { + return CustomResourcePackAccess.invokeGetMetadataSection(metadataSerializers, this.pack.getResource(ResourcePack.METADATA_FILE), name); + } + + @Override + public BufferedImage getIcon() throws IOException { + return this.getIcon(this.pack.getResource(ResourcePack.ICON_FILE)); + } + + private BufferedImage getIcon(InputStream is) throws IOException { + try { + return ImageIO.read(is); + } finally { + try { + if (is != null) { + is.close(); + } + } catch (IOException e) { + } + } + } + + @Override + public String getName() { + return this.pack.getId(); + } +} diff --git a/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourcePackLists.java b/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourcePackLists.java new file mode 100644 index 00000000..d3b66a9f --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourcePackLists.java @@ -0,0 +1,99 @@ +package net.ornithemc.osl.resource.loader.impl.adapter; + +import java.util.Collection; +import java.util.List; +import java.util.function.BiFunction; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screen.ResourcePacksScreen; +import net.minecraft.client.gui.screen.resourcepack.ResourcePackEntry; +import net.minecraft.client.resource.pack.ResourcePacks; + +import net.ornithemc.osl.resource.loader.api.resource.pack.PackPosition; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePack; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackRepository; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackSummary; +import net.ornithemc.osl.resource.loader.impl.ClientResourcePacks; + +public final class ResourcePackLists { + + public static void fixSelection(List packs, boolean reversed) { + fixSelection( + packs, + (summary, pack) -> Adapters.resourcePack(pack), + reversed + ); + } + + public static class Gui { + public static void fixSelection(ResourcePacksScreen screen, List entries, boolean reversed) { + Minecraft minecraft = Minecraft.getInstance(); + ResourcePacks resourcePacks = minecraft.getResourcePacks(); + + // add server pack entry manually since vanilla doesn't + if (ClientResourcePacks.NEW_RESOURCE_PACKS_GUI && resourcePacks.getServerPack() != null) { + String id = resourcePacks.getServerPack().getName(); + ResourcePackSummary summary = ResourcePackRepository.client().getPack(id); + + if (summary != null) { + entries.add(reversed ? 0 : entries.size(), new ResourcePackSummaryEntry(screen, summary)); + } + } + + ResourcePackLists.fixSelection( + entries, + (summary, pack) -> new ResourcePackSummaryEntry(screen, summary), + reversed + ); + } + } + + /** + * insert any missing required packs into the list, preserving their ordering + */ + public static void fixSelection(List entries, BiFunction entryGetter, boolean reversed) { + Minecraft minecraft = Minecraft.getInstance(); + ResourcePacks resourcePacks = minecraft.getResourcePacks(); + ResourcePackRepository packRepository = ResourcePackRepository.client(); + + Collection selection = packRepository.getSelectedPacks(); + + boolean serverPackSelected = ClientResourcePacks.NEW_RESOURCE_PACKS_GUI && (resourcePacks.getServerPack() != null); + boolean defaultPackInserted = false; + boolean serverPackInserted = false; + + // if you keep inserting at index 0 you invert the ordering + // so we increment an offset to counteract that effect + int offset = 0; + + for (ResourcePackSummary summary : selection) { + ResourcePack pack = summary.open(); + + if (summary.isRequired()) { + if (pack instanceof WrappedResourcePack) { + net.minecraft.client.resource.pack.ResourcePack resourcePack = ((WrappedResourcePack) pack).pack; + + defaultPackInserted |= (resourcePack == resourcePacks.defaultPack); + serverPackInserted |= serverPackSelected && (resourcePack == resourcePacks.getServerPack()); + } else { + T entry = entryGetter.apply(summary, pack); + + if (summary.getDefaultPosition() == PackPosition.TOP) { + if (!serverPackSelected || serverPackInserted) { + entries.add(reversed ? offset++ : entries.size(), entry); + } else { + entries.add(reversed ? ++offset : (entries.size() - 1), entry); + } + } + if (summary.getDefaultPosition() == PackPosition.BOTTOM) { + if (defaultPackInserted) { + entries.add(reversed ? (entries.size() - 1 ) : ++offset, entry); + } else { + entries.add(reversed ? entries.size() : offset++, entry); + } + } + } + } + } + } +} diff --git a/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourcePackSummaryEntry.java b/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourcePackSummaryEntry.java new file mode 100644 index 00000000..64a419f1 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourcePackSummaryEntry.java @@ -0,0 +1,77 @@ +package net.ornithemc.osl.resource.loader.impl.adapter; + +import java.io.IOException; + +import net.minecraft.client.gui.screen.ResourcePacksScreen; +import net.minecraft.client.gui.screen.resourcepack.ResourcePackEntry; +import net.minecraft.client.render.texture.DynamicTexture; +import net.minecraft.client.render.texture.TextureUtil; +import net.minecraft.client.resource.pack.ResourcePack; +import net.minecraft.resource.Identifier; + +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackSummary; + +class ResourcePackSummaryEntry extends ResourcePackEntry { + + private final ResourcePackSummary summary; + private final ResourcePack pack; + + private final Identifier iconLocation; + + ResourcePackSummaryEntry(ResourcePacksScreen parent, ResourcePackSummary summary) { + super(parent); + + this.summary = summary; + this.pack = Adapters.resourcePack(summary.open()); + + DynamicTexture icon; + + try { + icon = new DynamicTexture(this.pack.getIcon()); + } catch (IOException e) { + icon = TextureUtil.MISSING_TEXTURE; + } + + this.iconLocation = this.minecraft.getTextureManager().register("texturepackicon", icon); + } + + @Override + protected String getDescription() { + return this.summary.getDescription().buildFormattedString(); + } + + @Override + protected void bindIcon() { + this.minecraft.getTextureManager().bind(this.iconLocation); + } + + @Override + protected String getName() { + return this.summary.getId(); + } + + @Override + protected boolean canMove() { + return !this.summary.isRequired() && !this.summary.isFixedPosition(); + } + + @Override + protected boolean canMoveRight() { + return !this.summary.isRequired(); + } + + @Override + protected boolean canMoveLeft() { + return !this.summary.isRequired(); + } + + @Override + protected boolean canMoveUp() { + return !this.summary.isRequired() && !this.summary.isFixedPosition(); + } + + @Override + protected boolean canMoveDown() { + return !this.summary.isRequired() && !this.summary.isFixedPosition(); + } +} diff --git a/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/WrappedResourcePack.java b/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/WrappedResourcePack.java new file mode 100644 index 00000000..2a3625ff --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/WrappedResourcePack.java @@ -0,0 +1,146 @@ +package net.ornithemc.osl.resource.loader.impl.adapter; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.util.Collections; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.api.ModContainer; + +import net.minecraft.client.resource.pack.BuiltInResourcePack; +import net.minecraft.client.resource.pack.CustomResourcePack; +import net.minecraft.client.resource.pack.DirectoryResourcePack; +import net.minecraft.client.resource.pack.ZippedResourcePack; +import net.minecraft.resource.Identifier; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.function.IOSupplier; +import net.ornithemc.osl.resource.loader.api.resource.ResourceType; +import net.ornithemc.osl.resource.loader.api.resource.pack.AbstractResourcePack; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourceConsumer; +import net.ornithemc.osl.resource.loader.impl.mixin.client.CustomResourcePackAccess; +import net.ornithemc.osl.resource.loader.impl.resource.pack.ResourcePacks; + +public class WrappedResourcePack extends AbstractResourcePack { + + final net.minecraft.client.resource.pack.ResourcePack pack; + + public WrappedResourcePack(net.minecraft.client.resource.pack.ResourcePack pack) { + this.pack = pack; + } + + @Override + public String getId() { + return this.pack.getName(); + } + + @Override + public boolean hasResource(String path) { + return this.hasResourceFromPack(this.pack, path); + } + + private boolean hasResourceFromPack(net.minecraft.client.resource.pack.ResourcePack pack, String path) { + if (pack instanceof BuiltInResourcePack) { + return ((BuiltInResourcePack) pack).hasResource(new PathIdentifier(path)) + || ((BuiltInResourcePack) pack).hasResource(new Identifier(path)); + } else if (pack instanceof CustomResourcePack) { + return ((CustomResourcePackAccess) pack).invokeHasResource(path); + } else if (pack instanceof ResourcePackAdapter) { + return ((ResourcePackAdapter) pack).pack.hasResource(path); + } else { + return false; + } + } + + @Override + public InputStream getResource(String path) throws IOException { + return this.getResourceFromPack(this.pack, path); + } + + private InputStream getResourceFromPack(net.minecraft.client.resource.pack.ResourcePack pack, String path) throws IOException { + if (pack instanceof BuiltInResourcePack) { + return ((BuiltInResourcePack) pack).hasResource(new PathIdentifier(path)) + ? ((BuiltInResourcePack) pack).getResource(new PathIdentifier(path)) + : ((BuiltInResourcePack) pack).getResource(new Identifier(path)); + } else if (pack instanceof CustomResourcePack) { + return ((CustomResourcePackAccess) pack).invokeOpenResource(path); + } else if (pack instanceof ResourcePackAdapter) { + return ((ResourcePackAdapter) pack).pack.getResource(path); + } else { + return null; + } + } + + @Override + protected Map> findNamespaces() { + return new EnumMap<>(Collections.singletonMap(ResourceType.CLIENT_ASSETS, this.pack.getNamespaces())); + } + + @Override + public boolean hasResource(ResourceType type, NamespacedIdentifier location) { + return type == ResourceType.CLIENT_ASSETS && this.pack.hasResource(Adapters.identifier(location)); + } + + @Override + public IOSupplier getResource(ResourceType type, NamespacedIdentifier location) { + return type == ResourceType.CLIENT_ASSETS && this.pack.hasResource(Adapters.identifier(location)) ? () -> this.pack.getResource(Adapters.identifier(location)) : null; + } + + @Override + public void findResources(ResourceType type, String namespace, String directory, ResourceConsumer consumer) { + if (type == ResourceType.CLIENT_ASSETS) { + this.findResourcesInPack(this.pack, type, namespace, directory, consumer); + } + } + + private void findResourcesInPack(net.minecraft.client.resource.pack.ResourcePack pack, ResourceType type, String namespace, String directory, ResourceConsumer consumer) { + if (pack instanceof BuiltInResourcePack) { + ModContainer mod = FabricLoader.getInstance().getModContainer("minecraft").get(); + List rootPaths = ResourcePacks.getRootPaths(mod.getRootPaths(), "."); + + ResourcePacks.findResources(this, rootPaths, type, namespace, directory, consumer); + } else if (pack instanceof DirectoryResourcePack) { + CustomResourcePackAccess directoryPack = (CustomResourcePackAccess) pack; + List rootPaths = ResourcePacks.getRootPaths(directoryPack.accessFile().toPath(), "."); + + if (!rootPaths.isEmpty()) { + ResourcePacks.findResources(this, rootPaths, type, namespace, directory, consumer); + } + } else if (pack instanceof ZippedResourcePack) { + CustomResourcePackAccess zippedPack = (CustomResourcePackAccess) pack; + + try (FileSystem zipFs = FileSystems.newFileSystem(zippedPack.accessFile().toPath(), (ClassLoader) null)) { + List rootPaths = ResourcePacks.getRootPaths(zipFs.getRootDirectories(), "."); + + if (!rootPaths.isEmpty()) { + ResourcePacks.findResources(this, rootPaths, type, namespace, directory, consumer); + } + } catch (IOException e) { + } + } else if (pack instanceof ResourcePackAdapter) { + ((ResourcePackAdapter) pack).pack.findResources(type, namespace, directory, consumer); + } + } + + /** + * Path-only Identifier impl for accessing direct-path resources from the assets index. + */ + private static class PathIdentifier extends Identifier { + + private PathIdentifier(String path) { + super(path); + } + + @Override + public String toString() { + return this.getPath(); + } + } +} diff --git a/libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/CustomResourcePackInvoker.java b/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/CustomResourcePackAccess.java similarity index 66% rename from libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/CustomResourcePackInvoker.java rename to libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/CustomResourcePackAccess.java index 94c4de06..665a6c67 100644 --- a/libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/CustomResourcePackInvoker.java +++ b/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/CustomResourcePackAccess.java @@ -1,8 +1,11 @@ package net.ornithemc.osl.resource.loader.impl.mixin.client; +import java.io.File; +import java.io.IOException; import java.io.InputStream; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; import org.spongepowered.asm.mixin.gen.Invoker; import net.minecraft.client.resource.metadata.ResourceMetadataSection; @@ -10,7 +13,16 @@ import net.minecraft.client.resource.pack.CustomResourcePack; @Mixin(CustomResourcePack.class) -public interface CustomResourcePackInvoker { +public interface CustomResourcePackAccess { + + @Accessor("file") + File accessFile(); + + @Invoker("openResource") + InputStream invokeOpenResource(String path) throws IOException; + + @Invoker("hasResource") + boolean invokeHasResource(String path); @Invoker("getMetadataSection") public static T invokeGetMetadataSection(ResourceMetadataSerializerRegistry metadataSerializers, InputStream is, String name) { diff --git a/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/MinecraftMixin.java b/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/MinecraftMixin.java new file mode 100644 index 00000000..b93ac131 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/MinecraftMixin.java @@ -0,0 +1,104 @@ +package net.ornithemc.osl.resource.loader.impl.mixin.client; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.At.Shift; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import com.llamalad7.mixinextras.sugar.Local; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.resource.manager.ReloadableResourceManager; +import net.minecraft.client.resource.metadata.ResourceMetadataSerializerRegistry; +import net.minecraft.client.resource.metadata.ResourcePackMetadata; +import net.minecraft.client.resource.pack.BuiltInResourcePack; +import net.minecraft.client.resource.pack.ResourcePack; + +import net.ornithemc.osl.resource.loader.impl.ResourceLoader; +import net.ornithemc.osl.resource.loader.impl.adapter.ResourceManagerAdapter; +import net.ornithemc.osl.resource.loader.impl.adapter.ResourcePackLists; +import net.ornithemc.osl.resource.loader.impl.resource.manager.SimpleReloadableResourceManager; +import net.ornithemc.osl.resource.loader.impl.resource.pack.ResourcePacks; + +@Mixin(Minecraft.class) +public class MinecraftMixin { + + @Shadow @Final + private ResourceMetadataSerializerRegistry resourceMetadataSerializerRegistry; + @Shadow @Final + private List defaultResourcePacks; + @Shadow @Final + private BuiltInResourcePack defaultResourcePack; + @Shadow + private ReloadableResourceManager resourceManager; + + @Unique + private final SimpleReloadableResourceManager actualResourceManager = SimpleReloadableResourceManager.client(); + + @Inject( + method = "init", + at = @At( + value = "NEW", + target = "net/minecraft/client/resource/pack/ResourcePacks" + ) + ) + private void osl$resource_loader$detectPackFormat(CallbackInfo ci) { + // TODO: detect pack format for server resources! + // it'll be the same pack number but we need detection on the server + try { + ResourcePackMetadata metadata = ((ResourcePack) defaultResourcePack).getMetadataSection(resourceMetadataSerializerRegistry, "pack"); + int format = metadata.getFormat(); + + ResourcePacks.setSupportedFormat(format); + } catch (IOException e) { + ResourceLoader.LOGGER.info("unable to parse pack format from default resource pack", e); + } + } + + @Inject( + method = "init", + at = @At( + value = "FIELD", + target = "Lnet/minecraft/client/Minecraft;resourceManager:Lnet/minecraft/client/resource/manager/ReloadableResourceManager;", + ordinal = 0, + shift = Shift.AFTER + ) + ) + private void osl$resource_loader$setResourceManager(CallbackInfo ci) { + this.resourceManager = new ResourceManagerAdapter(this.resourceMetadataSerializerRegistry, this.actualResourceManager); + } + + @Inject( + method = "init", + at = @At( + value = "NEW", + target = "net/minecraft/client/gui/GameGui" // after all Vanilla reload listeners + ) + ) + private void osl$resource_loader$initResourceManager(CallbackInfo ci) { + this.actualResourceManager.init(); + } + + @Inject( + method = "reloadResources", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/resource/manager/ReloadableResourceManager;reload(Ljava/util/List;)V" + ) + ) + private void osl$resource_loader$fixSelection(CallbackInfo ci, @Local ArrayList selection) { + // ResourcePacks.getSelectedPacks only contains directory or zip packs + // The default pack and server pack are added in the target method, so + // we must add any other required packs manually as well + + ResourcePackLists.fixSelection(selection, false); + } +} diff --git a/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/ResourcePacksMixin.java b/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/ResourcePacksMixin.java new file mode 100644 index 00000000..4b057946 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/ResourcePacksMixin.java @@ -0,0 +1,165 @@ +package net.ornithemc.osl.resource.loader.impl.mixin.client; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.client.resource.pack.ResourcePacks; + +import net.ornithemc.osl.resource.loader.api.resource.pack.PackPosition; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePack; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackRepository; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackSummary; +import net.ornithemc.osl.resource.loader.impl.ClientResourcePacks; +import net.ornithemc.osl.resource.loader.impl.adapter.WrappedResourcePack; +import net.ornithemc.osl.resource.loader.impl.resource.repository.BundledModResourcePacks; +import net.ornithemc.osl.resource.loader.impl.resource.repository.SimpleResourcePackRepository; + +@Mixin(ResourcePacks.class) +public class ResourcePacksMixin implements ResourcePackRepository.Source { + + @Shadow @Final + private List availablePacks; + @Shadow @Final + private List appliedPacks; + + @Unique + private final SimpleResourcePackRepository resourcePacks = SimpleResourcePackRepository.client(); + @Unique + private final Map availablePacksById = new HashMap<>(); + + @Unique + private boolean vanillaReloading; + @Unique + private boolean reloading; + + @Shadow + private void load() { } + + @Inject( + method = "", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/resource/pack/ResourcePacks;load()V" + ) + ) + private void osl$resource_loader$initAvailable(CallbackInfo ci) { + this.resourcePacks.setCallbacks(null, this::selectionChanged); + + this.resourcePacks.addSource(new ClientResourcePacks((ResourcePacks) (Object) this)); + this.resourcePacks.addSource(new BundledModResourcePacks()); + this.resourcePacks.addSource(this); // resourcepacks/ directory source + + this.resourcePacks.init(); + } + + @Inject( + method = "", + at = @At( + value = "TAIL" + ) + ) + private void osl$resource_loader$initSelection(CallbackInfo ci) { + this.updateSelection(); + } + + @Inject( + method = "load", + cancellable = true, + at = @At( + value = "HEAD" + ) + ) + private void osl$resource_loader$startReload(CallbackInfo ci) { + if (!this.vanillaReloading) { + this.vanillaReloading = true; + + if (!this.reloading) { + this.resourcePacks.reload(); + + // cancel this call as the pack repository will trigger + // another recursive call through this.loadResourcePacks + ci.cancel(); + } + } + } + + @Inject( + method = "load", + at = @At( + value = "TAIL" + ) + ) + private void osl$resource_loader$endReload(CallbackInfo ci) { + this.vanillaReloading = false; + } + + @Inject( + method = "apply", + at = @At( + value = "TAIL" + ) + ) + private void osl$resource_loader$updateSelection(CallbackInfo ci) { + this.updateSelection(); + } + + @Override + public void loadResourcePacks(Consumer consumer) { + this.reloading = true; + this.load(); + this.reloading = false; + + this.availablePacksById.clear(); + + for (ResourcePacks.Entry pack : this.availablePacks) { + ResourcePack resourcePack = new WrappedResourcePack(pack.get()); + ResourcePackSummary summary = ResourcePackSummary.create( + resourcePack, + false, + false, + PackPosition.TOP + ); + + this.availablePacksById.put(summary.getId(), pack); + + if (summary != null) { + consumer.accept(summary); + } + } + } + + @Unique + private void updateSelection() { + List selection = new ArrayList<>(); + + for (ResourcePacks.Entry pack : this.appliedPacks) { + selection.add(pack.getName()); + } + + this.resourcePacks.setSelectedPacks(selection); + } + + @Unique + private void selectionChanged() { + this.appliedPacks.clear(); + + for (ResourcePackSummary summary : this.resourcePacks.getSelectedPacks()) { + ResourcePacks.Entry pack = this.availablePacksById.get(summary.getId()); + + if (pack != null) { + this.appliedPacks.add(pack); + } + } + } +} diff --git a/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/ResourcePacksScreenMixin.java b/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/ResourcePacksScreenMixin.java new file mode 100644 index 00000000..6b51f77f --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/ResourcePacksScreenMixin.java @@ -0,0 +1,48 @@ +package net.ornithemc.osl.resource.loader.impl.mixin.client; + +import java.util.List; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.At.Shift; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Slice; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.client.gui.screen.ResourcePacksScreen; +import net.minecraft.client.gui.screen.resourcepack.ResourcePackEntry; + +import net.ornithemc.osl.resource.loader.impl.ClientResourcePacks; +import net.ornithemc.osl.resource.loader.impl.adapter.ResourcePackLists; + +@Mixin(ResourcePacksScreen.class) +public class ResourcePacksScreenMixin { + + @Inject( + method = "init", + slice = @Slice( + from = @At( + value = "NEW", + target = "net/minecraft/client/gui/screen/resourcepack/DefaultResourcePackEntry" + ) + ), + at = @At( + value = "INVOKE", + target = "Ljava/util/List;add(Ljava/lang/Object;)Z", + ordinal = 0, + shift = Shift.AFTER + ) + ) + private void osl$resource_loader$fixSelection(CallbackInfo ci) { + // ResourcePacks.getSelectedPacks only contains directory or zip packs + // The default pack and server pack are added in the target method, so + // we must add any other required packs manually as well + + if (ClientResourcePacks.NEW_RESOURCE_PACKS_GUI) { + ResourcePacksScreen screen = (ResourcePacksScreen) (Object) this; + List selected = screen.getAppliedPacks(); + + ResourcePackLists.Gui.fixSelection(screen, selected, true); + } + } +} diff --git a/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/SimpleResourceMixin.java b/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/SimpleResourceMixin.java new file mode 100644 index 00000000..ca4c98a6 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/SimpleResourceMixin.java @@ -0,0 +1,22 @@ +package net.ornithemc.osl.resource.loader.impl.mixin.client; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import net.minecraft.client.resource.SimpleResource; +import net.minecraft.resource.Identifier; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.resource.loader.impl.resource.ResourceLocationAccess; + +@Mixin(SimpleResource.class) +public class SimpleResourceMixin implements ResourceLocationAccess { + + @Shadow + private Identifier location; + + @Override + public NamespacedIdentifier resourceLocation() { + return (NamespacedIdentifier) location; + } +} diff --git a/libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/src/main/resources/fabric.mod.json b/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/resources/fabric.mod.json similarity index 69% rename from libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/src/main/resources/fabric.mod.json rename to libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/resources/fabric.mod.json index a50b8d4e..074d04b6 100644 --- a/libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/src/main/resources/fabric.mod.json +++ b/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/resources/fabric.mod.json @@ -1,15 +1,17 @@ { "schemaVersion": 1, "id": "osl-resource-loader", - "version": "0.6.1+mc13w26a-mc1.10.2", + "version": "0.6.1+mc13w26a-mc1.8.2-pre4", "environment": "client", "mixins": [ "osl.resource-loader.mixins.json" ], "depends": { "fabricloader": "\u003e\u003d0.18.0", - "minecraft": "\u003e\u003d1.6-alpha.13.26.a \u003c\u003d1.10.2", - "osl-core": "\u003e\u003d0.7.0" + "minecraft": "\u003e\u003d1.6-alpha.13.26.a \u003c\u003d1.8.2-rc.4", + "osl-core": "\u003e\u003d0.7.0", + "osl-executors": "\u003e\u003d0.1.0-", + "osl-text-components": "\u003e\u003d0.1.0-" }, "name": "OSL Resource Loader", "description": "Resource loading API and events.", diff --git a/libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/src/main/resources/osl.resource-loader.mixins.json b/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/resources/osl.resource-loader.mixins.json similarity index 65% rename from libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/src/main/resources/osl.resource-loader.mixins.json rename to libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/resources/osl.resource-loader.mixins.json index 443d6829..e7e810b6 100644 --- a/libraries/resource-loader/resource-loader-mc13w26a-mc1.10.2/src/main/resources/osl.resource-loader.mixins.json +++ b/libraries/resource-loader/resource-loader-mc13w26a-mc1.8.2-pre4/src/main/resources/osl.resource-loader.mixins.json @@ -6,10 +6,11 @@ "mixins": [ ], "client": [ - "client.CustomResourcePackInvoker", - "client.LocaleMixin", + "client.CustomResourcePackAccess", "client.MinecraftMixin", - "client.SimpleResourceAccessor" + "client.ResourcePacksMixin", + "client.ResourcePacksScreenMixin", + "client.SimpleResourceMixin" ], "server": [ ], diff --git a/libraries/resource-loader/resource-loader-mc16w32a-mc1.12.2/gradle.properties b/libraries/resource-loader/resource-loader-mc16w32a-mc1.12.2/gradle.properties deleted file mode 100644 index 1ab54f3b..00000000 --- a/libraries/resource-loader/resource-loader-mc16w32a-mc1.12.2/gradle.properties +++ /dev/null @@ -1,7 +0,0 @@ -environment = client -min_mc_version = 16w32a -max_mc_version = 1.12.2 -minecraft_dependency = >=1.11-alpha.16.32.a <=1.12.2 - -minecraft_version = 1.12.2 -feather_build = 1 diff --git a/libraries/resource-loader/resource-loader-mc16w32a-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/api/ModResourcePack.java b/libraries/resource-loader/resource-loader-mc16w32a-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/api/ModResourcePack.java deleted file mode 100644 index 53c86d73..00000000 --- a/libraries/resource-loader/resource-loader-mc16w32a-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/api/ModResourcePack.java +++ /dev/null @@ -1,11 +0,0 @@ -package net.ornithemc.osl.resource.loader.api; - -import net.fabricmc.loader.api.metadata.ModMetadata; - -import net.minecraft.client.resource.pack.ResourcePack; - -public interface ModResourcePack extends ResourcePack { - - ModMetadata getModMetadata(); - -} diff --git a/libraries/resource-loader/resource-loader-mc16w32a-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/api/ResourceLoaderEvents.java b/libraries/resource-loader/resource-loader-mc16w32a-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/api/ResourceLoaderEvents.java deleted file mode 100644 index 8f8909c9..00000000 --- a/libraries/resource-loader/resource-loader-mc16w32a-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/api/ResourceLoaderEvents.java +++ /dev/null @@ -1,63 +0,0 @@ -package net.ornithemc.osl.resource.loader.api; - -import java.util.function.Consumer; - -import net.ornithemc.osl.core.api.events.Event; - -/** - * Events related to resource loading. - */ -public class ResourceLoaderEvents { - - /** - * This event is invoked upon game start-up, giving mod developers the - * opportunity to register custom built-in resource packs. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ResourceLoaderEvents.ADD_DEFAULT_RESOURCE_PACKS.register(adder -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event>> ADD_DEFAULT_RESOURCE_PACKS = Event.consumer(); - - /** - * This event is invoked before resources are reloaded. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ResourceLoaderEvents.START_RESOURCE_RELOAD.register(() -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event START_RESOURCE_RELOAD = Event.runnable(); - /** - * This event is invoked after resources are reloaded. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ResourceLoaderEvents.END_RESOURCE_RELOAD.register(() -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event END_RESOURCE_RELOAD = Event.runnable(); - -} diff --git a/libraries/resource-loader/resource-loader-mc16w32a-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/api/ResourceUtils.java b/libraries/resource-loader/resource-loader-mc16w32a-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/api/ResourceUtils.java deleted file mode 100644 index cc1974f1..00000000 --- a/libraries/resource-loader/resource-loader-mc16w32a-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/api/ResourceUtils.java +++ /dev/null @@ -1,12 +0,0 @@ -package net.ornithemc.osl.resource.loader.api; - -public class ResourceUtils { - - public static boolean isValidNamespace(String namespace) { - return namespace.chars().allMatch(chr -> chr == '-' || chr == '.' || chr == '_' || (chr >= 'a' && chr <= 'z') || (chr >= '0' && chr <= '9')); - } - - public static boolean isValidPath(String namespace) { - return namespace.chars().allMatch(chr -> chr == '-' || chr == '.' || chr == '_' || chr == '/' || (chr >= 'a' && chr <= 'z') || (chr >= '0' && chr <= '9')); - } -} diff --git a/libraries/resource-loader/resource-loader-mc16w32a-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/BuiltInModResourcePack.java b/libraries/resource-loader/resource-loader-mc16w32a-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/BuiltInModResourcePack.java deleted file mode 100644 index 475c9291..00000000 --- a/libraries/resource-loader/resource-loader-mc16w32a-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/BuiltInModResourcePack.java +++ /dev/null @@ -1,160 +0,0 @@ -package net.ornithemc.osl.resource.loader.impl; - -import java.awt.image.BufferedImage; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.nio.file.DirectoryStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import javax.imageio.ImageIO; - -import com.google.gson.JsonObject; - -import net.fabricmc.loader.api.ModContainer; -import net.fabricmc.loader.api.metadata.ModMetadata; - -import net.minecraft.client.resource.metadata.ResourceMetadataSection; -import net.minecraft.client.resource.metadata.ResourceMetadataSerializerRegistry; -import net.minecraft.client.resource.pack.ResourcePack; -import net.minecraft.resource.Identifier; - -import net.ornithemc.osl.resource.loader.api.ModResourcePack; -import net.ornithemc.osl.resource.loader.api.ResourceUtils; -import net.ornithemc.osl.resource.loader.impl.mixin.client.CustomResourcePackInvoker; - -public class BuiltInModResourcePack implements ModResourcePack { - - private final ModContainer mod; - private final Set namespaces; - - private final List roots; - //private final String separator; - - private JsonObject generatedPackMetadata; - - public BuiltInModResourcePack(ModContainer mod) { - this.mod = mod; - this.namespaces = new HashSet<>(); - - this.roots = this.mod.getRootPaths(); - - findNamespaces(); - } - - private void findNamespaces() { - for (Path root : roots) { - Path assets = root.resolve("assets"); - - if (Files.isDirectory(assets)) { - String separator = root.getFileSystem().getSeparator(); - - try (DirectoryStream ds = Files.newDirectoryStream(assets)) { - for (Path p : ds) { - String s = p.getFileName().toString(); - String namespace = s.replace(separator, ""); - - if (ResourceUtils.isValidNamespace(namespace)) { - namespaces.add(namespace); - } - } - } catch (IOException e) { - ResourceLoader.LOGGER.warn("failed to parse namespaces for built-in resource pack for mod " + mod.getMetadata().getId(), e); - } - } - } - } - - @Override - public InputStream getResource(Identifier location) throws IOException { - Path path = getPath(location); - - if (path == null || !Files.exists(path)) { - if ("pack.mcmeta".equals(location.getPath())) { - JsonObject metadata = generatePackMetadata(); - String serializedMetadata = metadata.toString(); - - return new ByteArrayInputStream(serializedMetadata.getBytes(StandardCharsets.UTF_8)); - } - if ("pack.png".equals(location.getPath())) { - return ResourcePack.class.getResourceAsStream("/" + location.getPath()); - } - - return null; - } - - return Files.newInputStream(path); - } - - @Override - public boolean hasResource(Identifier location) { - Path path = getPath(location); - return path != null && Files.exists(path); - } - - @Override - public Set getNamespaces() { - return namespaces; - } - - @Override - public T getMetadataSection(ResourceMetadataSerializerRegistry metadataSerializers, String name) throws IOException { - try (InputStream is = getResource(new Identifier("pack.mcmeta"))) { - return CustomResourcePackInvoker.invokeGetMetadataSection(metadataSerializers, is, name); - } - } - - @Override - public BufferedImage getIcon() throws IOException { - return ImageIO.read(getResource(new Identifier("pack.png"))); - } - - @Override - public String getName() { - return getModMetadata().getName(); - } - - @Override - public ModMetadata getModMetadata() { - return mod.getMetadata(); - } - - private Path getPath(Identifier location) { - return getPath(getPathName(location)); - } - - private Path getPath(String path) { - for (Path root : roots) { - String separator = root.getFileSystem().getSeparator(); - String pathName = path.replace("/", separator); - Path p = root.resolve(pathName); - - if (Files.exists(p)) { - return p; - } - } - - return null; - } - - private String getPathName(Identifier location) { - return String.format("assets/%s/%s", location.getNamespace(), location.getPath()); - } - - private JsonObject generatePackMetadata() { - if (generatedPackMetadata == null) { - generatedPackMetadata = new JsonObject(); - JsonObject pack = new JsonObject(); - pack.addProperty("pack_format", ResourceLoader.getPackFormat()); - pack.addProperty("description", getModMetadata().getDescription()); - generatedPackMetadata.add("pack", pack); - } - - return generatedPackMetadata; - } -} diff --git a/libraries/resource-loader/resource-loader-mc16w32a-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/ResourceLoader.java b/libraries/resource-loader/resource-loader-mc16w32a-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/ResourceLoader.java deleted file mode 100644 index 92375b37..00000000 --- a/libraries/resource-loader/resource-loader-mc16w32a-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/ResourceLoader.java +++ /dev/null @@ -1,37 +0,0 @@ -package net.ornithemc.osl.resource.loader.impl; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import net.ornithemc.osl.resource.loader.api.ModResourcePack; - -public class ResourceLoader { - - public static final Logger LOGGER = LogManager.getLogger("OSL|Resource Loader"); - - private static final List DEFAULT_MOD_RESOURCE_PACKS = new ArrayList<>(); - - private static int packFormat = -1; - - public static void setPackFormat(int format) { - if (packFormat < 0) { - packFormat = format; - } - } - - public static boolean addDefaultModResourcePack(ModResourcePack pack) { - return DEFAULT_MOD_RESOURCE_PACKS.add(pack); - } - - public static List getDefaultModResourcePacks() { - return Collections.unmodifiableList(DEFAULT_MOD_RESOURCE_PACKS); - } - - public static int getPackFormat() { - return packFormat; - } -} diff --git a/libraries/resource-loader/resource-loader-mc16w32a-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/LocaleMixin.java b/libraries/resource-loader/resource-loader-mc16w32a-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/LocaleMixin.java deleted file mode 100644 index 53212912..00000000 --- a/libraries/resource-loader/resource-loader-mc16w32a-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/LocaleMixin.java +++ /dev/null @@ -1,96 +0,0 @@ -package net.ornithemc.osl.resource.loader.impl.mixin.client; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.quiltmc.parsers.json.JsonReader; - -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import com.llamalad7.mixinextras.injector.wrapoperation.Operation; -import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; -import com.llamalad7.mixinextras.sugar.Local; - -import net.minecraft.client.resource.Resource; -import net.minecraft.client.resource.language.Locale; -import net.minecraft.client.resource.manager.ResourceManager; -import net.minecraft.resource.Identifier; - -@Mixin(Locale.class) -public abstract class LocaleMixin { - - @Final - @Shadow - private Map translations; - - @Shadow - protected abstract void load(List resources); - - @Inject( - method = "load(Lnet/minecraft/client/resource/manager/ResourceManager;Ljava/util/List;)V", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/client/resource/manager/ResourceManager;getResources(Lnet/minecraft/resource/Identifier;)Ljava/util/List;" - ) - ) - private void osl$resource_loader$loadTranslationFiles(CallbackInfo ci, - @Local(argsOnly = true) ResourceManager resourceManager, - @Local(ordinal = 0) String languageCode, - @Local(ordinal = 2) String namespace) { - String[] paths = new String[] { - String.format("lang/%s.json", languageCode), - String.format("lang/%s.lang", languageCode.toLowerCase(java.util.Locale.ROOT)), - String.format("lang/%s.json", languageCode.toLowerCase(java.util.Locale.ROOT)) - }; - for (String path : paths) { - try { - this.load(resourceManager.getResources(new Identifier(namespace, path))); - } catch (IOException ignored) { - } - } - } - - @WrapOperation( - method = "load(Ljava/util/List;)V", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/client/resource/language/Locale;load(Ljava/io/InputStream;)V" - ) - ) - private void osl$resource_loader$loadTranslationFiles(Locale instance, InputStream is, Operation original, @Local Resource resource) throws IOException{ - if (resource.getLocation().getPath().endsWith(".lang")){ - original.call(instance, is); // load .lang - } else { - loadJson(is); - } - } - - @Unique - private void loadJson(InputStream stream) { - if (stream == null) { - return; - } - JsonReader reader = JsonReader.json(new InputStreamReader(stream)); - - Map entries = new HashMap<>(); - try { - reader.beginObject(); - while (reader.hasNext()) { - entries.put(reader.nextName(), reader.nextString()); - } - reader.endObject(); - } catch (IOException ignored) { - } - translations.putAll(entries); - } -} diff --git a/libraries/resource-loader/resource-loader-mc16w32a-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/MinecraftMixin.java b/libraries/resource-loader/resource-loader-mc16w32a-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/MinecraftMixin.java deleted file mode 100644 index f041c92b..00000000 --- a/libraries/resource-loader/resource-loader-mc16w32a-mc1.12.2/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/MinecraftMixin.java +++ /dev/null @@ -1,91 +0,0 @@ -package net.ornithemc.osl.resource.loader.impl.mixin.client; - -import java.io.IOException; -import java.util.List; - -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import net.fabricmc.loader.api.FabricLoader; -import net.fabricmc.loader.api.ModContainer; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.resource.metadata.ResourceMetadataSerializerRegistry; -import net.minecraft.client.resource.metadata.ResourcePackMetadata; -import net.minecraft.client.resource.pack.BuiltInResourcePack; -import net.minecraft.client.resource.pack.ResourcePack; - -import net.ornithemc.osl.resource.loader.api.ModResourcePack; -import net.ornithemc.osl.resource.loader.api.ResourceLoaderEvents; -import net.ornithemc.osl.resource.loader.impl.BuiltInModResourcePack; -import net.ornithemc.osl.resource.loader.impl.ResourceLoader; - -@Mixin(Minecraft.class) -public class MinecraftMixin { - - @Shadow @Final - private ResourceMetadataSerializerRegistry resourceMetadataSerializerRegistry; - @Shadow @Final - private List defaultResourcePacks; - @Shadow @Final - private BuiltInResourcePack defaultResourcePack; - - - @Inject( - method = "init", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/client/Minecraft;reloadResources()V" - ) - ) - private void osl$resource_loader$addDefaultResourcePacks(CallbackInfo ci) { - try { - ResourcePackMetadata metadata = defaultResourcePack.getMetadataSection(resourceMetadataSerializerRegistry, "pack"); - int format = metadata.getFormat(); - - ResourceLoader.setPackFormat(format); - } catch (IOException e) { - ResourceLoader.LOGGER.info("unable to parse resource pack format from default resource pack", e); - } - - for (ModContainer mod : FabricLoader.getInstance().getAllMods()) { - if ("builtin".equals(mod.getMetadata().getType())) { - continue; - } - - osl$resource_loader$addDefaultResourcePack(new BuiltInModResourcePack(mod)); - } - - ResourceLoaderEvents.ADD_DEFAULT_RESOURCE_PACKS.invoker().accept(this::osl$resource_loader$addDefaultResourcePack); - } - - @Inject( - method = "reloadResources", - at = @At( - value = "HEAD" - ) - ) - private void osl$resource_loader$startResourceReload(CallbackInfo ci) { - ResourceLoaderEvents.START_RESOURCE_RELOAD.invoker().run(); - } - - @Inject( - method = "reloadResources", - at = @At( - value = "TAIL" - ) - ) - private void osl$resource_loader$endResourceReload(CallbackInfo ci) { - ResourceLoaderEvents.END_RESOURCE_RELOAD.invoker().run(); - } - - private void osl$resource_loader$addDefaultResourcePack(ModResourcePack pack) { - if (ResourceLoader.addDefaultModResourcePack(pack)) { - defaultResourcePacks.add(pack); - } - } -} diff --git a/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/build.gradle b/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/build.gradle new file mode 100644 index 00000000..0a350fdb --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/build.gradle @@ -0,0 +1 @@ +setUpModule(project) diff --git a/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/gradle.properties b/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/gradle.properties new file mode 100644 index 00000000..df44104f --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/gradle.properties @@ -0,0 +1,5 @@ +min_mc_version = 17w43a +max_mc_version = 19w05a +minecraft_dependency = >=1.13-alpha.17.43.a <=1.14-alpha.19.5.a + +minecraft_version = 19w05a diff --git a/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/Adapters.java b/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/Adapters.java new file mode 100644 index 00000000..fd69d2af --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/Adapters.java @@ -0,0 +1,164 @@ +package net.ornithemc.osl.resource.loader.impl.adapter; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import net.minecraft.resource.Identifier; +import net.minecraft.resource.pack.Pack; +import net.minecraft.resource.pack.PackType; +import net.minecraft.resource.pack.repository.UnopenedPack; +import net.minecraft.resource.pack.repository.UnopenedPack.Position; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.resource.loader.api.resource.Resource; +import net.ornithemc.osl.resource.loader.api.resource.ResourceType; +import net.ornithemc.osl.resource.loader.api.resource.pack.PackCompatibility; +import net.ornithemc.osl.resource.loader.api.resource.pack.PackPosition; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePack; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackSummary; + +class Adapters { + + static Identifier identifier(NamespacedIdentifier id) { + return id instanceof Identifier ? (Identifier) id : new Identifier(id.namespace(), id.identifier()); + } + + static PackType packType(ResourceType type) { + switch (type) { + case CLIENT_ASSETS: + return PackType.CLIENT_RESOURCES; + case SERVER_DATA: + return PackType.SERVER_DATA; + default: + throw new IllegalStateException("unknown resource type " + type); + } + } + + static ResourceType resourceType(PackType type) { + switch (type) { + case CLIENT_RESOURCES: + return ResourceType.CLIENT_ASSETS; + case SERVER_DATA: + return ResourceType.SERVER_DATA; + default: + throw new IllegalStateException("unknown pack type " + type); + } + } + + static net.minecraft.resource.Resource resource(Resource resource) throws IOException { + return new ResourceAdapter(resource); + } + + static net.minecraft.resource.Resource resource(NamespacedIdentifier location, Optional resource) throws IOException { + if (resource.isPresent()) { + return resource(resource.get()); + } + + throw new FileNotFoundException(location.toString()); + } + + static List resources(List resources) throws IOException { + List rs = new ArrayList<>(); + + for (Resource resource : resources) { + rs.add(resource(resource)); + } + + return Collections.unmodifiableList(rs); + } + + static Pack pack(ResourcePack pack) { + if (pack instanceof WrappedPack) { + return ((WrappedPack) pack).pack; + } else { + return new ResourcePackAdapter(pack); + } + } + + static ResourcePack resourcePack(Pack pack) { + if (pack instanceof ResourcePackAdapter) { + return ((ResourcePackAdapter) pack).pack; + } else { + return new WrappedPack(pack); + } + } + + static List packs(List packs) { + return packs.stream().map(Adapters::pack).collect(Collectors.toList()); + } + + static List resourcePacks(List packs) { + return packs.stream().map(Adapters::resourcePack).collect(Collectors.toList()); + } + + static Position position(PackPosition pos) { + switch (pos) { + case BOTTOM: + return Position.BOTTOM; + case TOP: + return Position.TOP; + default: + throw new IllegalStateException("unknown pack position " + pos); + } + } + + static PackPosition packPosition(Position pos) { + switch (pos) { + case BOTTOM: + return PackPosition.BOTTOM; + case TOP: + return PackPosition.TOP; + default: + throw new IllegalStateException("unknown unopened pack position " + pos); + } + } + + static net.minecraft.resource.pack.PackCompatibility packCompatibility(PackCompatibility pos) { + switch (pos) { + case COMPATIBLE: + return net.minecraft.resource.pack.PackCompatibility.COMPATIBLE; + case TOO_OLD: + return net.minecraft.resource.pack.PackCompatibility.TOO_OLD; + case TOO_NEW: + return net.minecraft.resource.pack.PackCompatibility.TOO_NEW; + default: + throw new IllegalStateException("unknown pack compatibility " + pos); + } + } + + static PackCompatibility packCompatibility(net.minecraft.resource.pack.PackCompatibility pos) { + switch (pos) { + case COMPATIBLE: + return PackCompatibility.COMPATIBLE; + case TOO_OLD: + return PackCompatibility.TOO_OLD; + case TOO_NEW: + return PackCompatibility.TOO_NEW; + default: + throw new IllegalStateException("unknown pack compatibility " + pos); + } + } + + static ResourcePackSummary resourcePackSummary(UnopenedPack unopenedPack) { + return new WrappedUnopenedPack<>(unopenedPack); + } + + static T unopenedPack(ResourcePackSummary summary, UnopenedPack.Factory factory) { + if (summary instanceof WrappedUnopenedPack) { + return (T) ((WrappedUnopenedPack) summary).pack; + } else { + return UnopenedPack.create( + summary.getId(), + summary.isRequired(), + () -> pack(summary.open()), + factory, + position(summary.getDefaultPosition()) + ); + } + } +} diff --git a/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourceAdapter.java b/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourceAdapter.java new file mode 100644 index 00000000..331b1e41 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourceAdapter.java @@ -0,0 +1,41 @@ +package net.ornithemc.osl.resource.loader.impl.adapter; + +import java.io.IOException; + +import net.minecraft.client.resource.metadata.serializer.ResourceMetadataSerializer; +import net.minecraft.resource.SimpleResource; + +import net.ornithemc.osl.resource.loader.api.resource.Resource; + +class ResourceAdapter extends SimpleResource { + + private final Resource resource; + + ResourceAdapter(Resource resource) throws IOException { + super( + resource.sourceName(), + Adapters.identifier(resource.location()), + resource.open(), + null + ); + + this.resource = resource; + + // parse now in case of exceptions (vanilla does not support lazy resources) + this.resource.metadata(); + } + + @Override + public T getMetadata(ResourceMetadataSerializer serializer) { + try { + return this.resource.metadata().getSection(serializer.getName(), serializer::deserialize); + } catch (IOException e) { + return null; + } + } + + @Override + public void close() throws IOException { + this.resource.close(); + } +} diff --git a/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourceManagerAdapter.java b/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourceManagerAdapter.java new file mode 100644 index 00000000..5cb83d64 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourceManagerAdapter.java @@ -0,0 +1,78 @@ +package net.ornithemc.osl.resource.loader.impl.adapter; + +import java.io.IOException; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import net.minecraft.resource.Identifier; +import net.minecraft.resource.Resource; +import net.minecraft.resource.pack.Pack; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.resource.loader.api.resource.manager.ResourceManager; +import net.ornithemc.osl.resource.loader.api.resource.reload.ResourceReloadListener; +import net.ornithemc.osl.resource.loader.impl.resource.manager.SimpleReloadableResourceManager; + +public class ResourceManagerAdapter implements net.minecraft.resource.manager.ReloadableResourceManager { + + final SimpleReloadableResourceManager resourceManager; + + public ResourceManagerAdapter(SimpleReloadableResourceManager resourceManager) { + this.resourceManager = resourceManager; + } + + @Override + public Set getNamespaces() { + return this.resourceManager.getNamespaces(); + } + + @Override + public Resource getResource(Identifier location) throws IOException { + return Adapters.resource((NamespacedIdentifier) location, this.resourceManager.getResource((NamespacedIdentifier) location)); + } + + @Override + public List getResources(Identifier location) throws IOException { + return Adapters.resources(this.resourceManager.getResourceStack((NamespacedIdentifier) location)); + } + + @Override + public Collection listResources(String directory, Predicate filter) { + return this.resourceManager.findResources(directory, location -> filter.test(location.identifier())).keySet().stream().map(Adapters::identifier).collect(Collectors.toList()); + } + + @Override + public void addListener(net.minecraft.resource.manager.ResourceReloadListener listener) { + this.resourceManager.addReloader(new WrappedResourceReloadListener(listener)); + } + + @Override + public void reload(List packs) { + this.resourceManager.reload(Adapters.resourcePacks(packs)); + } + + private class WrappedResourceReloadListener implements ResourceReloadListener { + + private final net.minecraft.resource.manager.ResourceReloadListener listener; + + private WrappedResourceReloadListener(net.minecraft.resource.manager.ResourceReloadListener listener) { + this.listener = listener; + + // Vanilla's reload listeners are triggered immediately after registering + // We must emulate this or the game's initialization will fail + this.listener.reload(ResourceManagerAdapter.this); + } + + @Override + public void resourcesReloaded(ResourceManager manager) { + if (manager == ResourceManagerAdapter.this.resourceManager) { + this.listener.reload(ResourceManagerAdapter.this); + } else { + throw new IllegalStateException("Woah there, who hijacked the resource manager?"); + } + } + } +} diff --git a/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourcePackAdapter.java b/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourcePackAdapter.java new file mode 100644 index 00000000..89d07afc --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourcePackAdapter.java @@ -0,0 +1,89 @@ +package net.ornithemc.osl.resource.loader.impl.adapter; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.function.Predicate; + +import net.minecraft.client.resource.metadata.serializer.ResourceMetadataSerializer; +import net.minecraft.resource.Identifier; +import net.minecraft.resource.pack.Pack; +import net.minecraft.resource.pack.PackType; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.function.IOSupplier; +import net.ornithemc.osl.resource.loader.api.resource.ResourcePath; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePack; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePackFileNotFoundException; + +class ResourcePackAdapter implements Pack { + + final ResourcePack pack; + + ResourcePackAdapter(ResourcePack pack) { + this.pack = pack; + } + + @Override + public InputStream getRootResource(String path) throws IOException { + if (path.contains("/") || path.contains("\\")) { + throw new IllegalArgumentException("Root resources can only be filenames, not paths (no / allowed!)"); + } + + return this.pack.getResource(path); + } + + @Override + public InputStream getResource(PackType type, Identifier location) throws IOException { + IOSupplier resource = this.pack.getResource(Adapters.resourceType(type), (NamespacedIdentifier) location); // TODO: interface injection + + if (resource != null) { + return resource.get(); + } + + throw new ResourcePackFileNotFoundException(this.pack, ResourcePath.nameOf(Adapters.resourceType(type), (NamespacedIdentifier) location)); + } + + @Override + public boolean hasResource(PackType type, Identifier location) { + return this.pack.hasResource(Adapters.resourceType(type), (NamespacedIdentifier) location); + } + + @Override + public Collection findResources(PackType type, String directory, int depth, Predicate filter) { + List locations = new ArrayList<>(); + + for (String namespace : this.getNamespaces(type)) { + this.pack.findResources(Adapters.resourceType(type), namespace, directory, (location, resource) -> { + if (filter.test(location.identifier())) { + locations.add(Adapters.identifier(location)); + } + }); + } + + return locations; + } + + @Override + public void close() throws IOException { + this.pack.close(); + } + + @Override + public Set getNamespaces(PackType type) { + return this.pack.getNamespaces(Adapters.resourceType(type)); + } + + @Override + public T getMetadataSection(ResourceMetadataSerializer serializer) throws IOException { + return this.pack.getMetadata(serializer.getName(), serializer::deserialize); + } + + @Override + public String getName() { + return this.pack.getId(); + } +} diff --git a/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourcePackRepositoryAdapter.java b/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourcePackRepositoryAdapter.java new file mode 100644 index 00000000..e0784b02 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourcePackRepositoryAdapter.java @@ -0,0 +1,75 @@ +package net.ornithemc.osl.resource.loader.impl.adapter; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; + +import net.minecraft.resource.pack.repository.PackRepository; +import net.minecraft.resource.pack.repository.RepositorySource; +import net.minecraft.resource.pack.repository.UnopenedPack; +import net.minecraft.resource.pack.repository.UnopenedPack.Factory; + +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackRepository; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackSummary; + +public class ResourcePackRepositoryAdapter extends PackRepository { + + private final UnopenedPack.Factory factory; + private final Map packs; + + final ResourcePackRepository repository; + + public ResourcePackRepositoryAdapter(Factory factory, ResourcePackRepository repository) { + super(factory); + + this.factory = factory; + this.packs = new HashMap<>(); + + this.repository = repository; + } + + private T summaryToPack(ResourcePackSummary summary) { + return this.packs.get(summary.getId()); + } + + @Override + public void reload() { + this.packs.clear(); + this.repository.reload(); + + for (ResourcePackSummary summary : this.repository.getAvailablePacks()) { + this.packs.put(summary.getId(), Adapters.unopenedPack(summary, this.factory)); + } + } + + @Override + public void select(Collection packs) { + this.repository.setSelectedPacks(packs.stream().map(T::getId).collect(Collectors.toList())); + } + + @Override + public Collection getAvailable() { + return this.repository.getAvailablePacks().stream().map(this::summaryToPack).collect(Collectors.toList()); + } + + @Override + public Collection getUnselected() { + return this.repository.getUnselectedPacks().stream().map(this::summaryToPack).collect(Collectors.toList()); + } + + @Override + public Collection getSelected() { + return this.repository.getSelectedPacks().stream().map(this::summaryToPack).collect(Collectors.toList()); + } + + @Override + public T getPack(String id) { + return this.packs.get(id); + } + + @Override + public void addSource(RepositorySource source) { + this.repository.addSource(new WrappedRepositorySource<>(this.factory, source)); + } +} \ No newline at end of file diff --git a/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/WrappedPack.java b/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/WrappedPack.java new file mode 100644 index 00000000..adf06f04 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/WrappedPack.java @@ -0,0 +1,103 @@ +package net.ornithemc.osl.resource.loader.impl.adapter; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.util.Set; + +import com.google.gson.JsonObject; + +import net.minecraft.client.resource.metadata.serializer.ResourceMetadataSerializer; +import net.minecraft.resource.pack.Pack; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.function.IOSupplier; +import net.ornithemc.osl.resource.loader.api.resource.ResourceMetadata.Section.Serializer; +import net.ornithemc.osl.resource.loader.api.resource.ResourceType; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourceConsumer; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePack; + +class WrappedPack implements ResourcePack { + + final Pack pack; + + WrappedPack(Pack pack) { + this.pack = pack; + } + + @Override + public String getId() { + return this.pack.getName(); + } + + @Override + public boolean hasResource(String path) { + try { + return this.getResource(path) != null; + } catch (IOException e) { + return false; + } + } + + @Override + public InputStream getResource(String path) throws IOException { + if (path.contains("/") || path.contains("\\")) { + return null; + } else { + return this.pack.getRootResource(path); + } + } + + @Override + public Set getNamespaces(ResourceType type) { + return this.pack.getNamespaces(Adapters.packType(type)); + } + + @Override + public boolean hasResource(ResourceType type, NamespacedIdentifier location) { + return this.pack.hasResource(Adapters.packType(type), Adapters.identifier(location)); + } + + @Override + public IOSupplier getResource(ResourceType type, NamespacedIdentifier location) { + return this.pack.hasResource(Adapters.packType(type), Adapters.identifier(location)) ? () -> this.pack.getResource(Adapters.packType(type), Adapters.identifier(location)) : null; + } + + @Override + public void findResources(ResourceType type, String namespace, String directory, ResourceConsumer consumer) { + this.pack.findResources(Adapters.packType(type), directory, Integer.MAX_VALUE, fileName -> true).forEach(location -> { + if (location.getNamespace().equals(namespace)) { + consumer.accept((NamespacedIdentifier) location, () -> this.pack.getResource(Adapters.packType(type), location)); + } + }); + } + + @Override + public T getMetadata(String name, Serializer serializer) throws IOException { + return this.pack.getMetadataSection(new ResourceMetadataSerializer() { + + @Override + public T deserialize(JsonObject json) { + return serializer.deserialize(json); + } + + @Override + public String getName() { + return name; + } + }); + } + + @Override + public void open() { + } + + @Override + public void close() { + try { + this.pack.close(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } +} diff --git a/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/WrappedRepositorySource.java b/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/WrappedRepositorySource.java new file mode 100644 index 00000000..a826e82d --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/WrappedRepositorySource.java @@ -0,0 +1,31 @@ +package net.ornithemc.osl.resource.loader.impl.adapter; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.function.Consumer; + +import net.minecraft.resource.pack.repository.RepositorySource; +import net.minecraft.resource.pack.repository.UnopenedPack; + +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackRepository; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackSummary; + +class WrappedRepositorySource implements ResourcePackRepository.Source { + + private final UnopenedPack.Factory factory; + private final RepositorySource source; + + WrappedRepositorySource(UnopenedPack.Factory factory, RepositorySource source) { + this.factory = factory; + this.source = source; + } + + @Override + public void loadResourcePacks(Consumer consumer) { + Map packs = new LinkedHashMap<>(); + this.source.loadPacks(packs, this.factory); + packs.values().forEach(pack -> { + consumer.accept(Adapters.resourcePackSummary(pack)); + }); + } +} diff --git a/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/WrappedUnopenedPack.java b/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/WrappedUnopenedPack.java new file mode 100644 index 00000000..97257719 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/WrappedUnopenedPack.java @@ -0,0 +1,71 @@ +package net.ornithemc.osl.resource.loader.impl.adapter; + +import net.minecraft.client.resource.pack.UnopenedResourcePack; +import net.minecraft.resource.pack.repository.UnopenedPack; + +import net.ornithemc.osl.resource.loader.api.resource.pack.PackCompatibility; +import net.ornithemc.osl.resource.loader.api.resource.pack.PackPosition; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePack; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackSummary; +import net.ornithemc.osl.text.api.TextComponent; + +class WrappedUnopenedPack implements ResourcePackSummary { + + final T pack; + + WrappedUnopenedPack(T pack) { + this.pack = pack; + } + + @Override + public TextComponent getTitle() { + if (this.pack instanceof UnopenedResourcePack) { + // TODO: convert Vanilla Text -> OSL TextComponent + } + + return null; + } + + @Override + public TextComponent getDescription() { + if (this.pack instanceof UnopenedResourcePack) { + // TODO: convert Vanilla Text -> OSL TextComponent + } + + return null; + } + + @Override + public String getId() { + return this.pack.getId(); + } + + @Override + public boolean isRequired() { + return this.pack.isRequired(); + } + + @Override + public boolean isFixedPosition() { + return this.pack.isFixed(); + } + + @Override + public PackPosition getDefaultPosition() { + return Adapters.packPosition(this.pack.getPosition()); + } + + @Override + public PackCompatibility getCompatibility() { + return Adapters.packCompatibility(this.pack.getCompatibility()); + } + + @Override + public ResourcePack open() { + return Adapters.resourcePack(this.pack.build()); + } + + @Override + public void close() { + } +} diff --git a/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/MinecraftMixin.java b/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/MinecraftMixin.java new file mode 100644 index 00000000..c2c39be6 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/MinecraftMixin.java @@ -0,0 +1,101 @@ +package net.ornithemc.osl.resource.loader.impl.mixin.client; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.At.Shift; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.resource.pack.UnopenedResourcePack; +import net.minecraft.resource.manager.ReloadableResourceManager; +import net.minecraft.resource.pack.repository.PackRepository; + +import net.ornithemc.osl.resource.loader.impl.adapter.ResourceManagerAdapter; +import net.ornithemc.osl.resource.loader.impl.adapter.ResourcePackRepositoryAdapter; +import net.ornithemc.osl.resource.loader.impl.resource.manager.SimpleReloadableResourceManager; +import net.ornithemc.osl.resource.loader.impl.resource.repository.BundledModResourcePacks; +import net.ornithemc.osl.resource.loader.impl.resource.repository.SimpleResourcePackRepository; + +@Mixin(Minecraft.class) +public class MinecraftMixin { + + @Shadow @Final @Mutable + private PackRepository packRepository; + @Shadow + private ReloadableResourceManager resourceManager; + + @Unique + private SimpleResourcePackRepository actualPackRepository; + @Unique + private SimpleReloadableResourceManager actualResourceManager; + + @Inject( + method = "", + at = @At( + value = "FIELD", + target = "Lnet/minecraft/client/Minecraft;packRepository:Lnet/minecraft/resource/pack/repository/PackRepository;", + ordinal = 0, + shift = Shift.AFTER + ) + ) + private void osl$resource_loader$setPackRepository(CallbackInfo ci) { + this.actualPackRepository = SimpleResourcePackRepository.client(); + this.packRepository = new ResourcePackRepositoryAdapter<>(this.packRepository.factory, this.actualPackRepository); + } + + @Inject( + method = "", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/resource/pack/repository/PackRepository;addSource(Lnet/minecraft/resource/pack/repository/RepositorySource;)V", + ordinal = 0, + shift = Shift.AFTER // after built-in Vanilla resources + ) + ) + private void osl$resource_loader$registerModResources(CallbackInfo ci) { + this.actualPackRepository.addSource(new BundledModResourcePacks()); + } + + @Inject( + method = "", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/resource/pack/repository/PackRepository;addSource(Lnet/minecraft/resource/pack/repository/RepositorySource;)V", + ordinal = 1, + shift = Shift.AFTER // after directory pack source + ) + ) + private void osl$resource_loader$initResourcePackRepository(CallbackInfo ci) { + this.actualPackRepository.init(); + } + + @Inject( + method = "init", + at = @At( + value = "FIELD", + target = "Lnet/minecraft/client/Minecraft;resourceManager:Lnet/minecraft/resource/manager/ReloadableResourceManager;", + ordinal = 0, + shift = Shift.AFTER + ) + ) + private void osl$resource_loader$setResourceManager(CallbackInfo ci) { + this.actualResourceManager = SimpleReloadableResourceManager.client(); + this.resourceManager = new ResourceManagerAdapter(this.actualResourceManager); + } + + @Inject( + method = "init", + at = @At( + value = "NEW", + target = "Lnet/minecraft/client/gui/GameGui;" // after all Vanilla reload listeners + ) + ) + private void osl$resource_loader$initResourceManager(CallbackInfo ci) { + this.actualResourceManager.init(); + } +} diff --git a/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/ResourcePacksMixin.java b/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/ResourcePacksMixin.java new file mode 100644 index 00000000..f3eeb7dc --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/ResourcePacksMixin.java @@ -0,0 +1,39 @@ +package net.ornithemc.osl.resource.loader.impl.mixin.client; + +import java.io.IOException; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.resource.pack.BuiltInPack; +import net.minecraft.resource.pack.metadata.PackMetadataSection; + +import net.ornithemc.osl.resource.loader.impl.ResourceLoader; +import net.ornithemc.osl.resource.loader.impl.resource.pack.ResourcePacks; + +@Mixin(net.minecraft.client.resource.pack.ResourcePacks.class) +public class ResourcePacksMixin { + + @Shadow + private BuiltInPack defaultPack; + + @Inject( + method = "", + at = @At( + value = "TAIL" + ) + ) + private void osl$resource_loader$detetectPackFormat(CallbackInfo ci) { + try { + PackMetadataSection metadata = defaultPack.getMetadataSection(PackMetadataSection.SERIALIZER); + int format = metadata.getFormat(); + + ResourcePacks.setSupportedFormat(format); + } catch (IOException e) { + ResourceLoader.LOGGER.info("unable to parse pack format from default resource pack", e); + } + } +} diff --git a/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/common/DataPacksMixin.java b/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/common/DataPacksMixin.java new file mode 100644 index 00000000..8287a714 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/common/DataPacksMixin.java @@ -0,0 +1,40 @@ +package net.ornithemc.osl.resource.loader.impl.mixin.common; + +import java.io.IOException; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.resource.pack.BuiltInPack; +import net.minecraft.resource.pack.metadata.PackMetadataSection; +import net.minecraft.server.resource.pack.DataPacks; + +import net.ornithemc.osl.resource.loader.impl.ResourceLoader; +import net.ornithemc.osl.resource.loader.impl.resource.pack.ResourcePacks; + +@Mixin(DataPacks.class) +public class DataPacksMixin { + + @Shadow + private BuiltInPack defaultPack; + + @Inject( + method = "", + at = @At( + value = "TAIL" + ) + ) + private void osl$resource_loader$detetectPackFormat(CallbackInfo ci) { + try { + PackMetadataSection metadata = defaultPack.getMetadataSection(PackMetadataSection.SERIALIZER); + int format = metadata.getFormat(); + + ResourcePacks.setSupportedFormat(format); + } catch (IOException e) { + ResourceLoader.LOGGER.info("unable to parse pack format from default data pack", e); + } + } +} diff --git a/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/common/MinecraftServerMixin.java b/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/common/MinecraftServerMixin.java new file mode 100644 index 00000000..2ff0dc52 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/common/MinecraftServerMixin.java @@ -0,0 +1,100 @@ +package net.ornithemc.osl.resource.loader.impl.mixin.common; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.At.Shift; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.resource.manager.ReloadableResourceManager; +import net.minecraft.resource.pack.repository.PackRepository; +import net.minecraft.resource.pack.repository.UnopenedPack; +import net.minecraft.server.MinecraftServer; + +import net.ornithemc.osl.resource.loader.impl.adapter.ResourceManagerAdapter; +import net.ornithemc.osl.resource.loader.impl.adapter.ResourcePackRepositoryAdapter; +import net.ornithemc.osl.resource.loader.impl.resource.manager.SimpleReloadableResourceManager; +import net.ornithemc.osl.resource.loader.impl.resource.repository.BundledModResourcePacks; +import net.ornithemc.osl.resource.loader.impl.resource.repository.SimpleResourcePackRepository; + +@Mixin(MinecraftServer.class) +public class MinecraftServerMixin { + + @Shadow @Final @Mutable + private PackRepository packRepository; + @Shadow @Final @Mutable + private ReloadableResourceManager resourceManager; + + @Unique + private SimpleResourcePackRepository actualPackRepository; + @Unique + private SimpleReloadableResourceManager actualResourceManager; + + @Inject( + method = "", + at = @At( + value = "FIELD", + target = "Lnet/minecraft/server/MinecraftServer;packRepository:Lnet/minecraft/resource/pack/repository/PackRepository;", + ordinal = 0, + shift = Shift.AFTER + ) + ) + private void osl$resource_loader$setPackRepository(CallbackInfo ci) { + this.actualPackRepository = SimpleResourcePackRepository.server(); + this.packRepository = new ResourcePackRepositoryAdapter<>(this.packRepository.factory, this.actualPackRepository); + } + + @Inject( + method = "", + at = @At( + value = "FIELD", + target = "Lnet/minecraft/server/MinecraftServer;resourceManager:Lnet/minecraft/resource/manager/ReloadableResourceManager;", + ordinal = 0, + shift = Shift.AFTER + ) + ) + private void osl$resource_loader$setResourceManager(CallbackInfo ci) { + this.actualResourceManager = SimpleReloadableResourceManager.server(); + this.resourceManager = new ResourceManagerAdapter(this.actualResourceManager); + } + + @Inject( + method = "", + at = @At( + value = "TAIL" // after last resource reloader is registered + ) + ) + private void osl$resource_loader$initResourceManager(CallbackInfo ci) { + this.actualResourceManager.init(); + } + + @Inject( + method = "loadDataPacks", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/resource/pack/repository/PackRepository;addSource(Lnet/minecraft/resource/pack/repository/RepositorySource;)V", + ordinal = 0, + shift = Shift.AFTER // after built-in Vanilla resources + ) + ) + private void osl$resource_loader$registerModResources(CallbackInfo ci) { + this.actualPackRepository.addSource(new BundledModResourcePacks()); + } + + @Inject( + method = "loadDataPacks", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/resource/pack/repository/PackRepository;addSource(Lnet/minecraft/resource/pack/repository/RepositorySource;)V", + ordinal = 1, + shift = Shift.AFTER // after directory pack source + ) + ) + private void osl$resource_loader$initResourcePackRepository(CallbackInfo ci) { + this.actualPackRepository.init(); + } +} diff --git a/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/resources/fabric.mod.json b/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/resources/fabric.mod.json similarity index 72% rename from libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/resources/fabric.mod.json rename to libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/resources/fabric.mod.json index 28f70d13..0697a04b 100644 --- a/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/resources/fabric.mod.json +++ b/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/resources/fabric.mod.json @@ -1,15 +1,18 @@ { "schemaVersion": 1, "id": "osl-resource-loader", - "version": "0.6.1+mc17w43a-mc19w07a", + "version": "0.6.1+mc17w43a-mc19w05a", "environment": "*", "mixins": [ "osl.resource-loader.mixins.json" ], + "accessWidener": "osl.resource-loader.classtweaker", "depends": { "fabricloader": "\u003e\u003d0.18.0", - "minecraft": "\u003e\u003d1.13-alpha.17.43.a \u003c\u003d1.14-alpha.19.7.a", - "osl-core": "\u003e\u003d0.7.0" + "minecraft": "\u003e\u003d1.13-alpha.17.43.a \u003c\u003d1.14-alpha.19.5.a", + "osl-core": "\u003e\u003d0.7.0", + "osl-executors": "\u003e\u003d0.1.0-", + "osl-text-components": "\u003e\u003d0.1.0-" }, "name": "OSL Resource Loader", "description": "Resource loading API and events.", diff --git a/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/resources/osl.resource-loader.classtweaker b/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/resources/osl.resource-loader.classtweaker new file mode 100644 index 00000000..903b1a2c --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/resources/osl.resource-loader.classtweaker @@ -0,0 +1,3 @@ +classTweaker v1 named + +accessible field net/minecraft/resource/pack/repository/PackRepository factory Lnet/minecraft/resource/pack/repository/UnopenedPack$Factory; \ No newline at end of file diff --git a/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/resources/osl.resource-loader.mixins.json b/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/resources/osl.resource-loader.mixins.json similarity index 93% rename from libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/resources/osl.resource-loader.mixins.json rename to libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/resources/osl.resource-loader.mixins.json index 8032b214..d516d571 100644 --- a/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/resources/osl.resource-loader.mixins.json +++ b/libraries/resource-loader/resource-loader-mc17w43a-mc19w05a/src/main/resources/osl.resource-loader.mixins.json @@ -8,7 +8,6 @@ "common.MinecraftServerMixin" ], "client": [ - "client.LocaleMixin", "client.MinecraftMixin", "client.ResourcePacksMixin" ], diff --git a/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/gradle.properties b/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/gradle.properties deleted file mode 100644 index 80106f44..00000000 --- a/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/gradle.properties +++ /dev/null @@ -1,6 +0,0 @@ -min_mc_version = 17w43a -max_mc_version = 19w07a -minecraft_dependency = >=1.13-alpha.17.43.a <=1.14-alpha.19.7.a - -minecraft_version = 19w07a -feather_build = 1 diff --git a/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/java/net/ornithemc/osl/resource/loader/api/ModPack.java b/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/java/net/ornithemc/osl/resource/loader/api/ModPack.java deleted file mode 100644 index 72a9f6d6..00000000 --- a/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/java/net/ornithemc/osl/resource/loader/api/ModPack.java +++ /dev/null @@ -1,11 +0,0 @@ -package net.ornithemc.osl.resource.loader.api; - -import net.fabricmc.loader.api.metadata.ModMetadata; - -import net.minecraft.resource.pack.Pack; - -public interface ModPack extends Pack { - - ModMetadata getModMetadata(); - -} diff --git a/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/java/net/ornithemc/osl/resource/loader/api/ResourceUtils.java b/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/java/net/ornithemc/osl/resource/loader/api/ResourceUtils.java deleted file mode 100644 index cc1974f1..00000000 --- a/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/java/net/ornithemc/osl/resource/loader/api/ResourceUtils.java +++ /dev/null @@ -1,12 +0,0 @@ -package net.ornithemc.osl.resource.loader.api; - -public class ResourceUtils { - - public static boolean isValidNamespace(String namespace) { - return namespace.chars().allMatch(chr -> chr == '-' || chr == '.' || chr == '_' || (chr >= 'a' && chr <= 'z') || (chr >= '0' && chr <= '9')); - } - - public static boolean isValidPath(String namespace) { - return namespace.chars().allMatch(chr -> chr == '-' || chr == '.' || chr == '_' || chr == '/' || (chr >= 'a' && chr <= 'z') || (chr >= '0' && chr <= '9')); - } -} diff --git a/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/java/net/ornithemc/osl/resource/loader/api/client/ClientResourceLoaderEvents.java b/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/java/net/ornithemc/osl/resource/loader/api/client/ClientResourceLoaderEvents.java deleted file mode 100644 index 31d893b7..00000000 --- a/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/java/net/ornithemc/osl/resource/loader/api/client/ClientResourceLoaderEvents.java +++ /dev/null @@ -1,64 +0,0 @@ -package net.ornithemc.osl.resource.loader.api.client; - -import java.util.function.Consumer; - -import net.ornithemc.osl.core.api.events.Event; -import net.ornithemc.osl.resource.loader.api.ModPack; - -/** - * Events related to client side resource loading. - */ -public class ClientResourceLoaderEvents { - - /** - * This event is invoked upon game start-up, giving mod developers the - * opportunity to register custom built-in resource packs. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ClientResourceLoaderEvents.ADD_DEFAULT_RESOURCE_PACKS.register(adder -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event>> ADD_DEFAULT_RESOURCE_PACKS = Event.consumer(); - - /** - * This event is invoked before resources are reloaded. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ClientResourceLoaderEvents.START_RESOURCE_RELOAD.register(() -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event START_RESOURCE_RELOAD = Event.runnable(); - /** - * This event is invoked after resources are reloaded. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ClientResourceLoaderEvents.END_RESOURCE_RELOAD.register(() -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event END_RESOURCE_RELOAD = Event.runnable(); - -} diff --git a/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/java/net/ornithemc/osl/resource/loader/api/server/ServerResourceLoaderEvents.java b/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/java/net/ornithemc/osl/resource/loader/api/server/ServerResourceLoaderEvents.java deleted file mode 100644 index 95802d8a..00000000 --- a/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/java/net/ornithemc/osl/resource/loader/api/server/ServerResourceLoaderEvents.java +++ /dev/null @@ -1,64 +0,0 @@ -package net.ornithemc.osl.resource.loader.api.server; - -import java.util.function.Consumer; - -import net.ornithemc.osl.core.api.events.Event; -import net.ornithemc.osl.resource.loader.api.ModPack; - -/** - * Events related to server side resource loading. - */ -public class ServerResourceLoaderEvents { - - /** - * This event is invoked upon server start-up, giving mod developers the - * opportunity to register custom built-in data packs. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ServerResourceLoaderEvents.ADD_DEFAULT_RESOURCE_PACKS.register(adder -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event>> ADD_DEFAULT_DATA_PACKS = Event.consumer(); - - /** - * This event is invoked before resources are reloaded. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ServerResourceLoaderEvents.START_RESOURCE_RELOAD.register(() -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event START_RESOURCE_RELOAD = Event.runnable(); - /** - * This event is invoked after resources are reloaded. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ServerResourceLoaderEvents.END_RESOURCE_RELOAD.register(() -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event END_RESOURCE_RELOAD = Event.runnable(); - -} diff --git a/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/BuiltInModPack.java b/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/BuiltInModPack.java deleted file mode 100644 index e2c491df..00000000 --- a/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/BuiltInModPack.java +++ /dev/null @@ -1,241 +0,0 @@ -package net.ornithemc.osl.resource.loader.impl; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.nio.file.DirectoryStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Predicate; -import java.util.stream.Stream; - -import com.google.gson.JsonObject; - -import net.fabricmc.loader.api.FabricLoader; -import net.fabricmc.loader.api.ModContainer; -import net.fabricmc.loader.api.metadata.ModMetadata; - -import net.minecraft.client.resource.metadata.serializer.ResourceMetadataSerializer; -import net.minecraft.resource.Identifier; -import net.minecraft.resource.pack.CustomPack; -import net.minecraft.resource.pack.Pack; -import net.minecraft.resource.pack.PackType; - -import net.ornithemc.osl.resource.loader.api.ModPack; -import net.ornithemc.osl.resource.loader.api.ResourceUtils; - -public class BuiltInModPack implements ModPack { - - private static final boolean DEBUG = FabricLoader.getInstance().isDevelopmentEnvironment(); - - private final ModContainer mod; - private final PackType type; - private final Map> namespaces; - - private final List roots; - //private final String separator; - - private JsonObject generatedPackMetadata; - - public BuiltInModPack(ModContainer mod, PackType type) { - this.mod = mod; - this.type = type; - this.namespaces = new HashMap<>(); - - this.roots = this.mod.getRootPaths(); - - findNamespaces(); - } - - private void findNamespaces() { - for (Path root : roots) { - String separator = root.getFileSystem().getSeparator(); - - for (PackType type : PackType.values()) { - Path dir = root.resolve(type.getDirectory()); - Set ns = new HashSet<>(); - - if (Files.isDirectory(dir)) { - try (DirectoryStream ds = Files.newDirectoryStream(dir)) { - for (Path p : ds) { - String s = p.getFileName().toString(); - String namespace = s.replace(separator, ""); - - if (ResourceUtils.isValidNamespace(namespace)) { - ns.add(namespace); - } - } - } catch (IOException e) { - ResourceLoader.LOGGER.warn("failed to parse namespaces for built-in resource pack for mod " + mod.getMetadata().getId(), e); - } - } - - namespaces.put(type, ns); - } - } - } - - @Override - public InputStream getRootResource(String path) throws IOException { - if (path.contains("/") || path.contains("\\")) { - throw new IllegalArgumentException("Root resources can only be filenames, not paths (no / allowed!)"); - } - - Path p = getPath(path); - - if (p == null || !Files.exists(p)) { - if ("pack.mcmeta".equals(path)) { - JsonObject metadata = generatePackMetadata(); - String serializedMetadata = metadata.toString(); - - return new ByteArrayInputStream(serializedMetadata.getBytes(StandardCharsets.UTF_8)); - } - if ("pack.png".equals(path)) { - return Pack.class.getResourceAsStream("/" + path); - } - - return null; - } - - return Files.newInputStream(p); - } - - @Override - public InputStream getResource(PackType type, Identifier location) throws IOException { - Path path = getPath(type, location); - - if (path == null || !Files.exists(path)) { - if ("pack.mcmeta".equals(location.getPath())) { - JsonObject metadata = generatePackMetadata(); - String serializedMetadata = metadata.toString(); - - return new ByteArrayInputStream(serializedMetadata.getBytes(StandardCharsets.UTF_8)); - } - if ("pack.png".equals(location.getPath())) { - return Pack.class.getResourceAsStream("/" + location.getPath()); - } - - return null; - } - - return Files.newInputStream(path); - } - - @Override - public boolean hasResource(PackType type, Identifier location) { - Path path = getPath(type, location); - return path != null && Files.exists(path); - } - - @Override - public Collection findResources(PackType type, String path, int maxDepth, Predicate filter) { - Collection locations = new LinkedHashSet<>(); - - for (String namespace : namespaces.get(type)) { - try { - locations.addAll(getResources(type, maxDepth, namespace, path, filter)); - } catch (IOException e) { - } - } - - return locations; - } - - private Collection getResources(PackType type, int maxDepth, String namespace, String path, Predicate filter) throws IOException { - List locations = new ArrayList<>(); - - for (Path root : roots) { - String separator = root.getFileSystem().getSeparator(); - Path dir = root.resolve(type.getDirectory()).resolve(namespace); - Path start = dir.resolve(path.replace("/", separator)); - - if (!Files.isDirectory(start)) { - continue; - } - - try (Stream paths = Files.find( - start, - Integer.MAX_VALUE, - (p, attributes) -> attributes.isRegularFile() - && !p.toString().endsWith(".mcmeta") - && (DEBUG || !p.endsWith(".ds_store")) - && filter.test(p.getFileName().toString()) - )) { - paths.forEach(p -> { - locations.add(new Identifier(namespace, dir.relativize(p).toString().replaceAll(separator, "/"))); - }); - } - } - - return locations; - } - - @Override - public void close() throws IOException { - } - - @Override - public Set getNamespaces(PackType type) { - return namespaces.get(type); - } - - @Override - public T getMetadataSection(ResourceMetadataSerializer serializer) throws IOException { - try (InputStream is = getRootResource("pack.mcmeta")) { - return CustomPack.getMetadataSection(serializer, is); - } - } - - @Override - public String getName() { - return getModMetadata().getName(); - } - - @Override - public ModMetadata getModMetadata() { - return mod.getMetadata(); - } - - private Path getPath(PackType type, Identifier location) { - return getPath(getPathName(type, location)); - } - - private Path getPath(String path) { - for (Path root : roots) { - String separator = root.getFileSystem().getSeparator(); - String pathName = path.replace("/", separator); - Path p = root.resolve(pathName); - - if (Files.exists(p)) { - return p; - } - } - - return null; - } - - private String getPathName(PackType type, Identifier location) { - return String.format("%s/%s/%s", type.getDirectory(), location.getNamespace(), location.getPath()); - } - - private JsonObject generatePackMetadata() { - if (generatedPackMetadata == null) { - generatedPackMetadata = new JsonObject(); - JsonObject pack = new JsonObject(); - pack.addProperty("pack_format", ResourceLoader.getPackFormat(type)); - pack.addProperty("description", getModMetadata().getDescription()); - generatedPackMetadata.add("pack", pack); - } - - return generatedPackMetadata; - } -} diff --git a/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/ResourceLoader.java b/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/ResourceLoader.java deleted file mode 100644 index 7f28b6b4..00000000 --- a/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/ResourceLoader.java +++ /dev/null @@ -1,61 +0,0 @@ -package net.ornithemc.osl.resource.loader.impl; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import net.minecraft.resource.pack.PackType; - -import net.ornithemc.osl.resource.loader.api.ModPack; - -public class ResourceLoader { - - public static final Logger LOGGER = LogManager.getLogger("OSL|Resource Loader"); - - private static final List DEFAULT_MOD_PACKS = new ArrayList<>(); - - private static int resourcePackFormat = -1; - private static int dataPackFormat = -1; - - public static void setResourcePackFormat(int format) { - if (resourcePackFormat < 0) { - resourcePackFormat = format; - } - } - - public static void setDataPackFormat(int format) { - if (dataPackFormat < 0) { - dataPackFormat = format; - } - } - - public static boolean addDefaultModPack(ModPack pack) { - return DEFAULT_MOD_PACKS.add(pack); - } - - public static List getDefaultModPacks() { - return Collections.unmodifiableList(DEFAULT_MOD_PACKS); - } - - public static int getPackFormat(PackType type) { - switch (type) { - case CLIENT_RESOURCES: - return getResourcePackFormat(); - case SERVER_DATA: - return getDataPackFormat(); - default: - throw new IllegalStateException("unable to get format for unknown pack type " + type); - } - } - - public static int getResourcePackFormat() { - return resourcePackFormat; - } - - public static int getDataPackFormat() { - return dataPackFormat; - } -} diff --git a/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/LocaleMixin.java b/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/LocaleMixin.java deleted file mode 100644 index 2bcfb606..00000000 --- a/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/LocaleMixin.java +++ /dev/null @@ -1,90 +0,0 @@ -package net.ornithemc.osl.resource.loader.impl.mixin.client; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.List; -import java.util.Map; - -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import com.llamalad7.mixinextras.injector.wrapoperation.Operation; -import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; -import com.llamalad7.mixinextras.sugar.Local; - -import net.minecraft.client.resource.language.Locale; -import net.minecraft.resource.Identifier; -import net.minecraft.resource.Resource; -import net.minecraft.resource.manager.ResourceManager; - -@Mixin(Locale.class) -public abstract class LocaleMixin { - - @Final - @Shadow - private Map translations; - - @Shadow - protected abstract void load(List resources); - - @Inject( - method = "load(Lnet/minecraft/resource/manager/ResourceManager;Ljava/util/List;)V", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/resource/manager/ResourceManager;getResources(Lnet/minecraft/resource/Identifier;)Ljava/util/List;" - ) - ) - private void osl$resource_loader$loadTranslationFiles(CallbackInfo ci, - @Local(argsOnly = true) ResourceManager resourceManager, - @Local(ordinal = 0) String languageCode, - @Local(ordinal = 2) String namespace) { - String[] paths = new String[] { - String.format("lang/%s.lang", languageCode), - String.format("lang/%s.json", languageCode.toLowerCase(java.util.Locale.ROOT)), - String.format("lang/%s.lang", languageCode.toLowerCase(java.util.Locale.ROOT)) - }; - for (String path : paths) { - try { - this.load(resourceManager.getResources(new Identifier(namespace, path))); - } catch (IOException ignored) { - } - } - } - - @WrapOperation( - method = "load(Ljava/util/List;)V", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/client/resource/language/Locale;load(Ljava/io/InputStream;)V" - ) - ) - private void osl$resource_loader$loadTranslationFiles(Locale instance, InputStream is, Operation original, @Local Resource resource) throws IOException{ - if (resource.getLocation().getPath().endsWith(".lang")){ - loadLang(is); - } else { - original.call(instance, is); // load .json - } - } - - @Unique - private void loadLang(InputStream stream) throws IOException { - if (stream == null) { - return; - } - - try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream))) { - reader - .lines() - .filter(l -> !l.startsWith("#")) - .map(line -> line.split("=", 2)) - .forEach(key -> translations.put(key[0], key[1])); - } - } -} diff --git a/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/MinecraftMixin.java b/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/MinecraftMixin.java deleted file mode 100644 index 2b222dec..00000000 --- a/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/MinecraftMixin.java +++ /dev/null @@ -1,34 +0,0 @@ -package net.ornithemc.osl.resource.loader.impl.mixin.client; - -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; - -import net.minecraft.client.Minecraft; - -import net.ornithemc.osl.resource.loader.api.client.ClientResourceLoaderEvents; - -@Mixin(Minecraft.class) -public class MinecraftMixin { - - @Inject( - method = "reloadResources", - at = @At( - value = "HEAD" - ) - ) - private void osl$resource_loader$startResourceReload(CallbackInfo ci) { - ClientResourceLoaderEvents.START_RESOURCE_RELOAD.invoker().run(); - } - - @Inject( - method = "reloadResources", - at = @At( - value = "TAIL" - ) - ) - private void osl$resource_loader$endResourceReload(CallbackInfo ci) { - ClientResourceLoaderEvents.END_RESOURCE_RELOAD.invoker().run(); - } -} diff --git a/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/ResourcePacksMixin.java b/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/ResourcePacksMixin.java deleted file mode 100644 index 56f6edcd..00000000 --- a/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/ResourcePacksMixin.java +++ /dev/null @@ -1,72 +0,0 @@ -package net.ornithemc.osl.resource.loader.impl.mixin.client; - -import java.io.IOException; -import java.util.Map; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import net.fabricmc.loader.api.FabricLoader; -import net.fabricmc.loader.api.ModContainer; - -import net.minecraft.client.resource.pack.ResourcePacks; -import net.minecraft.resource.pack.BuiltInPack; -import net.minecraft.resource.pack.PackType; -import net.minecraft.resource.pack.metadata.PackMetadataSection; -import net.minecraft.resource.pack.repository.UnopenedPack; - -import net.ornithemc.osl.resource.loader.api.ModPack; -import net.ornithemc.osl.resource.loader.api.client.ClientResourceLoaderEvents; -import net.ornithemc.osl.resource.loader.impl.BuiltInModPack; -import net.ornithemc.osl.resource.loader.impl.ResourceLoader; - -@Mixin(ResourcePacks.class) -public class ResourcePacksMixin { - - @Shadow - private BuiltInPack defaultPack; - - @Inject( - method = "", - at = @At( - value = "TAIL" - ) - ) - private void osl$resource_loader$detetectPackFormat(CallbackInfo ci) { - try { - PackMetadataSection metadata = defaultPack.getMetadataSection(PackMetadataSection.SERIALIZER); - int format = metadata.getFormat(); - - ResourceLoader.setResourcePackFormat(format); - } catch (IOException e) { - ResourceLoader.LOGGER.info("unable to parse resource pack format from default resource pack", e); - } - } - - @Inject( - method = "loadPacks", - at = @At( - value = "TAIL" - ) - ) - private void osl$resource_loader$addDefaultResourcePacks(Map packs, UnopenedPack.Factory factory, CallbackInfo ci) { - for (ModContainer mod : FabricLoader.getInstance().getAllMods()) { - if ("builtin".equals(mod.getMetadata().getType())) { - continue; - } - - osl$resource_loader$addDefaultResourcePack(packs, factory, new BuiltInModPack(mod, PackType.CLIENT_RESOURCES)); - } - - ClientResourceLoaderEvents.ADD_DEFAULT_RESOURCE_PACKS.invoker().accept(pack -> osl$resource_loader$addDefaultResourcePack(packs, factory, pack)); - } - - private void osl$resource_loader$addDefaultResourcePack(Map packs, UnopenedPack.Factory factory, ModPack pack) { - if (ResourceLoader.addDefaultModPack(pack)) { - packs.put(pack.getName(), UnopenedPack.create(pack.getName(), true, () -> pack, factory, UnopenedPack.Position.BOTTOM)); - } - } -} diff --git a/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/common/DataPacksMixin.java b/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/common/DataPacksMixin.java deleted file mode 100644 index 9bb1b855..00000000 --- a/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/common/DataPacksMixin.java +++ /dev/null @@ -1,72 +0,0 @@ -package net.ornithemc.osl.resource.loader.impl.mixin.common; - -import java.io.IOException; -import java.util.Map; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import net.fabricmc.loader.api.FabricLoader; -import net.fabricmc.loader.api.ModContainer; - -import net.minecraft.resource.pack.BuiltInPack; -import net.minecraft.resource.pack.PackType; -import net.minecraft.resource.pack.metadata.PackMetadataSection; -import net.minecraft.resource.pack.repository.UnopenedPack; -import net.minecraft.server.resource.pack.DataPacks; - -import net.ornithemc.osl.resource.loader.api.ModPack; -import net.ornithemc.osl.resource.loader.api.server.ServerResourceLoaderEvents; -import net.ornithemc.osl.resource.loader.impl.BuiltInModPack; -import net.ornithemc.osl.resource.loader.impl.ResourceLoader; - -@Mixin(DataPacks.class) -public class DataPacksMixin { - - @Shadow - private BuiltInPack defaultPack; - - @Inject( - method = "", - at = @At( - value = "TAIL" - ) - ) - private void osl$resource_loader$detetectPackFormat(CallbackInfo ci) { - try { - PackMetadataSection metadata = defaultPack.getMetadataSection(PackMetadataSection.SERIALIZER); - int format = metadata.getFormat(); - - ResourceLoader.setDataPackFormat(format); - } catch (IOException e) { - ResourceLoader.LOGGER.info("unable to parse data pack format from default data pack", e); - } - } - - @Inject( - method = "loadPacks", - at = @At( - value = "TAIL" - ) - ) - private void osl$resource_loader$addDefaultDataPacks(Map packs, UnopenedPack.Factory factory, CallbackInfo ci) { - for (ModContainer mod : FabricLoader.getInstance().getAllMods()) { - if ("builtin".equals(mod.getMetadata().getType())) { - continue; - } - - osl$resource_loader$addDefaultDataPack(packs, factory, new BuiltInModPack(mod, PackType.SERVER_DATA)); - } - - ServerResourceLoaderEvents.ADD_DEFAULT_DATA_PACKS.invoker().accept(pack -> osl$resource_loader$addDefaultDataPack(packs, factory, pack)); - } - - private void osl$resource_loader$addDefaultDataPack(Map packs, UnopenedPack.Factory factory, ModPack pack) { - if (ResourceLoader.addDefaultModPack(pack)) { - packs.put(pack.getName(), UnopenedPack.create(pack.getName(), true, () -> pack, factory, UnopenedPack.Position.BOTTOM)); - } - } -} diff --git a/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/common/MinecraftServerMixin.java b/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/common/MinecraftServerMixin.java deleted file mode 100644 index fbfc5173..00000000 --- a/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/common/MinecraftServerMixin.java +++ /dev/null @@ -1,34 +0,0 @@ -package net.ornithemc.osl.resource.loader.impl.mixin.common; - -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; - -import net.minecraft.server.MinecraftServer; - -import net.ornithemc.osl.resource.loader.api.server.ServerResourceLoaderEvents; - -@Mixin(MinecraftServer.class) -public class MinecraftServerMixin { - - @Inject( - method = "reloadResources", - at = @At( - value = "HEAD" - ) - ) - private void osl$resource_loader$startResourceReload(CallbackInfo ci) { - ServerResourceLoaderEvents.START_RESOURCE_RELOAD.invoker().run(); - } - - @Inject( - method = "reloadResources", - at = @At( - value = "TAIL" - ) - ) - private void osl$resource_loader$endResourceReload(CallbackInfo ci) { - ServerResourceLoaderEvents.END_RESOURCE_RELOAD.invoker().run(); - } -} diff --git a/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/build.gradle b/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/build.gradle new file mode 100644 index 00000000..0a350fdb --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/build.gradle @@ -0,0 +1 @@ +setUpModule(project) diff --git a/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/gradle.properties b/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/gradle.properties new file mode 100644 index 00000000..dd249fd9 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/gradle.properties @@ -0,0 +1,5 @@ +min_mc_version = 19w07a +max_mc_version = 1.14.4 +minecraft_dependency = >=1.14-alpha.19.7.a <=1.14.4 + +minecraft_version = 1.14.4 diff --git a/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/Adapters.java b/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/Adapters.java new file mode 100644 index 00000000..fd69d2af --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/Adapters.java @@ -0,0 +1,164 @@ +package net.ornithemc.osl.resource.loader.impl.adapter; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import net.minecraft.resource.Identifier; +import net.minecraft.resource.pack.Pack; +import net.minecraft.resource.pack.PackType; +import net.minecraft.resource.pack.repository.UnopenedPack; +import net.minecraft.resource.pack.repository.UnopenedPack.Position; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.resource.loader.api.resource.Resource; +import net.ornithemc.osl.resource.loader.api.resource.ResourceType; +import net.ornithemc.osl.resource.loader.api.resource.pack.PackCompatibility; +import net.ornithemc.osl.resource.loader.api.resource.pack.PackPosition; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePack; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackSummary; + +class Adapters { + + static Identifier identifier(NamespacedIdentifier id) { + return id instanceof Identifier ? (Identifier) id : new Identifier(id.namespace(), id.identifier()); + } + + static PackType packType(ResourceType type) { + switch (type) { + case CLIENT_ASSETS: + return PackType.CLIENT_RESOURCES; + case SERVER_DATA: + return PackType.SERVER_DATA; + default: + throw new IllegalStateException("unknown resource type " + type); + } + } + + static ResourceType resourceType(PackType type) { + switch (type) { + case CLIENT_RESOURCES: + return ResourceType.CLIENT_ASSETS; + case SERVER_DATA: + return ResourceType.SERVER_DATA; + default: + throw new IllegalStateException("unknown pack type " + type); + } + } + + static net.minecraft.resource.Resource resource(Resource resource) throws IOException { + return new ResourceAdapter(resource); + } + + static net.minecraft.resource.Resource resource(NamespacedIdentifier location, Optional resource) throws IOException { + if (resource.isPresent()) { + return resource(resource.get()); + } + + throw new FileNotFoundException(location.toString()); + } + + static List resources(List resources) throws IOException { + List rs = new ArrayList<>(); + + for (Resource resource : resources) { + rs.add(resource(resource)); + } + + return Collections.unmodifiableList(rs); + } + + static Pack pack(ResourcePack pack) { + if (pack instanceof WrappedPack) { + return ((WrappedPack) pack).pack; + } else { + return new ResourcePackAdapter(pack); + } + } + + static ResourcePack resourcePack(Pack pack) { + if (pack instanceof ResourcePackAdapter) { + return ((ResourcePackAdapter) pack).pack; + } else { + return new WrappedPack(pack); + } + } + + static List packs(List packs) { + return packs.stream().map(Adapters::pack).collect(Collectors.toList()); + } + + static List resourcePacks(List packs) { + return packs.stream().map(Adapters::resourcePack).collect(Collectors.toList()); + } + + static Position position(PackPosition pos) { + switch (pos) { + case BOTTOM: + return Position.BOTTOM; + case TOP: + return Position.TOP; + default: + throw new IllegalStateException("unknown pack position " + pos); + } + } + + static PackPosition packPosition(Position pos) { + switch (pos) { + case BOTTOM: + return PackPosition.BOTTOM; + case TOP: + return PackPosition.TOP; + default: + throw new IllegalStateException("unknown unopened pack position " + pos); + } + } + + static net.minecraft.resource.pack.PackCompatibility packCompatibility(PackCompatibility pos) { + switch (pos) { + case COMPATIBLE: + return net.minecraft.resource.pack.PackCompatibility.COMPATIBLE; + case TOO_OLD: + return net.minecraft.resource.pack.PackCompatibility.TOO_OLD; + case TOO_NEW: + return net.minecraft.resource.pack.PackCompatibility.TOO_NEW; + default: + throw new IllegalStateException("unknown pack compatibility " + pos); + } + } + + static PackCompatibility packCompatibility(net.minecraft.resource.pack.PackCompatibility pos) { + switch (pos) { + case COMPATIBLE: + return PackCompatibility.COMPATIBLE; + case TOO_OLD: + return PackCompatibility.TOO_OLD; + case TOO_NEW: + return PackCompatibility.TOO_NEW; + default: + throw new IllegalStateException("unknown pack compatibility " + pos); + } + } + + static ResourcePackSummary resourcePackSummary(UnopenedPack unopenedPack) { + return new WrappedUnopenedPack<>(unopenedPack); + } + + static T unopenedPack(ResourcePackSummary summary, UnopenedPack.Factory factory) { + if (summary instanceof WrappedUnopenedPack) { + return (T) ((WrappedUnopenedPack) summary).pack; + } else { + return UnopenedPack.create( + summary.getId(), + summary.isRequired(), + () -> pack(summary.open()), + factory, + position(summary.getDefaultPosition()) + ); + } + } +} diff --git a/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourceAdapter.java b/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourceAdapter.java new file mode 100644 index 00000000..331b1e41 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourceAdapter.java @@ -0,0 +1,41 @@ +package net.ornithemc.osl.resource.loader.impl.adapter; + +import java.io.IOException; + +import net.minecraft.client.resource.metadata.serializer.ResourceMetadataSerializer; +import net.minecraft.resource.SimpleResource; + +import net.ornithemc.osl.resource.loader.api.resource.Resource; + +class ResourceAdapter extends SimpleResource { + + private final Resource resource; + + ResourceAdapter(Resource resource) throws IOException { + super( + resource.sourceName(), + Adapters.identifier(resource.location()), + resource.open(), + null + ); + + this.resource = resource; + + // parse now in case of exceptions (vanilla does not support lazy resources) + this.resource.metadata(); + } + + @Override + public T getMetadata(ResourceMetadataSerializer serializer) { + try { + return this.resource.metadata().getSection(serializer.getName(), serializer::deserialize); + } catch (IOException e) { + return null; + } + } + + @Override + public void close() throws IOException { + this.resource.close(); + } +} diff --git a/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourceManagerAdapter.java b/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourceManagerAdapter.java new file mode 100644 index 00000000..2be4a663 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourceManagerAdapter.java @@ -0,0 +1,102 @@ +package net.ornithemc.osl.resource.loader.impl.adapter; + +import java.io.IOException; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import net.minecraft.resource.Identifier; +import net.minecraft.resource.Resource; +import net.minecraft.resource.pack.Pack; +import net.minecraft.unmapped.C_17695012; +import net.minecraft.unmapped.C_75765617; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.resource.loader.api.resource.reload.ReloadStep; +import net.ornithemc.osl.resource.loader.api.resource.reload.ResourceReloader; +import net.ornithemc.osl.resource.loader.impl.resource.manager.SimpleReloadableResourceManager; + +public class ResourceManagerAdapter implements net.minecraft.resource.manager.ReloadableResourceManager { + + final SimpleReloadableResourceManager resourceManager; + + public ResourceManagerAdapter(SimpleReloadableResourceManager resourceManager) { + this.resourceManager = resourceManager; + } + + @Override + public void add(Pack pack) { + this.resourceManager.add(Adapters.resourcePack(pack)); + } + + @Override + public Set getNamespaces() { + return this.resourceManager.getNamespaces(); + } + + @Override + public Resource getResource(Identifier location) throws IOException { + return Adapters.resource((NamespacedIdentifier) location, this.resourceManager.getResource((NamespacedIdentifier) location)); + } + + @Override + public List getResources(Identifier location) throws IOException { + return Adapters.resources(this.resourceManager.getResourceStack((NamespacedIdentifier) location)); + } + + @Override + public Collection listResources(String directory, Predicate filter) { + return this.resourceManager.findResources(directory, location -> filter.test(location.identifier())).keySet().stream().map(Adapters::identifier).collect(Collectors.toList()); + } + + @Override + public boolean m_12351820(Identifier location) { + return this.resourceManager.hasResource((NamespacedIdentifier) location); + } + + @Override + public void addListener(net.minecraft.resource.manager.ResourceReloadListener listener) { + this.resourceManager.addReloader(new WrappedResourceReloadListener(listener)); + } + + @Override + public C_17695012 m_24284863(Executor backgroundExecutor, Executor mainThreadExecutor, CompletableFuture initialTask) { + return new ResourceReloadAdapter(this.resourceManager.startPartialReload(backgroundExecutor, mainThreadExecutor, initialTask)); + } + + @Override + public C_17695012 m_73356589(Executor backgroundExecutor, Executor mainThreadExecutor, CompletableFuture initialTask, List selectedPacks) { + return new ResourceReloadAdapter(this.resourceManager.startReload(Adapters.resourcePacks(selectedPacks), backgroundExecutor, mainThreadExecutor, initialTask)); + } + + @Override + public CompletableFuture reload(Executor backgroundExecutor, Executor mainThreadExecutor, List selectedPacks, CompletableFuture initialTask) { + return this.resourceManager.startReload(Adapters.resourcePacks(selectedPacks), backgroundExecutor, mainThreadExecutor, initialTask).result().thenApply(u -> C_75765617.INSTANCE); + } + + private class WrappedResourceReloadListener implements ResourceReloader { + + private final net.minecraft.resource.manager.ResourceReloadListener listener; + + private WrappedResourceReloadListener(net.minecraft.resource.manager.ResourceReloadListener listener) { + this.listener = listener; + } + + @Override + public void prepareSharedState(SharedState state) { + } + + @Override + public CompletableFuture reloadResources(SharedState state, ReloadStep previousStep, Executor reloadExecutor, Executor applyExecutor) { + if (state.resourceManager() == ResourceManagerAdapter.this.resourceManager) { + return this.listener.m_24588393(previousStep::await, ResourceManagerAdapter.this, net.minecraft.unmapped.C_45729948.f_29046737, net.minecraft.unmapped.C_45729948.f_29046737, reloadExecutor, applyExecutor); + } else { + throw new IllegalStateException("Woah there, who hijacked the resource manager?"); + } + } + } +} diff --git a/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourcePackAdapter.java b/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourcePackAdapter.java new file mode 100644 index 00000000..89d07afc --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourcePackAdapter.java @@ -0,0 +1,89 @@ +package net.ornithemc.osl.resource.loader.impl.adapter; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.function.Predicate; + +import net.minecraft.client.resource.metadata.serializer.ResourceMetadataSerializer; +import net.minecraft.resource.Identifier; +import net.minecraft.resource.pack.Pack; +import net.minecraft.resource.pack.PackType; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.function.IOSupplier; +import net.ornithemc.osl.resource.loader.api.resource.ResourcePath; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePack; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePackFileNotFoundException; + +class ResourcePackAdapter implements Pack { + + final ResourcePack pack; + + ResourcePackAdapter(ResourcePack pack) { + this.pack = pack; + } + + @Override + public InputStream getRootResource(String path) throws IOException { + if (path.contains("/") || path.contains("\\")) { + throw new IllegalArgumentException("Root resources can only be filenames, not paths (no / allowed!)"); + } + + return this.pack.getResource(path); + } + + @Override + public InputStream getResource(PackType type, Identifier location) throws IOException { + IOSupplier resource = this.pack.getResource(Adapters.resourceType(type), (NamespacedIdentifier) location); // TODO: interface injection + + if (resource != null) { + return resource.get(); + } + + throw new ResourcePackFileNotFoundException(this.pack, ResourcePath.nameOf(Adapters.resourceType(type), (NamespacedIdentifier) location)); + } + + @Override + public boolean hasResource(PackType type, Identifier location) { + return this.pack.hasResource(Adapters.resourceType(type), (NamespacedIdentifier) location); + } + + @Override + public Collection findResources(PackType type, String directory, int depth, Predicate filter) { + List locations = new ArrayList<>(); + + for (String namespace : this.getNamespaces(type)) { + this.pack.findResources(Adapters.resourceType(type), namespace, directory, (location, resource) -> { + if (filter.test(location.identifier())) { + locations.add(Adapters.identifier(location)); + } + }); + } + + return locations; + } + + @Override + public void close() throws IOException { + this.pack.close(); + } + + @Override + public Set getNamespaces(PackType type) { + return this.pack.getNamespaces(Adapters.resourceType(type)); + } + + @Override + public T getMetadataSection(ResourceMetadataSerializer serializer) throws IOException { + return this.pack.getMetadata(serializer.getName(), serializer::deserialize); + } + + @Override + public String getName() { + return this.pack.getId(); + } +} diff --git a/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourcePackRepositoryAdapter.java b/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourcePackRepositoryAdapter.java new file mode 100644 index 00000000..5479c2f1 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourcePackRepositoryAdapter.java @@ -0,0 +1,80 @@ +package net.ornithemc.osl.resource.loader.impl.adapter; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; + +import net.minecraft.resource.pack.repository.PackRepository; +import net.minecraft.resource.pack.repository.RepositorySource; +import net.minecraft.resource.pack.repository.UnopenedPack; +import net.minecraft.resource.pack.repository.UnopenedPack.Factory; + +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackRepository; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackSummary; + +public class ResourcePackRepositoryAdapter extends PackRepository { + + private final UnopenedPack.Factory factory; + private final Map packs; + + final ResourcePackRepository repository; + + public ResourcePackRepositoryAdapter(Factory factory, ResourcePackRepository repository) { + super(factory); + + this.factory = factory; + this.packs = new HashMap<>(); + + this.repository = repository; + } + + private T summaryToPack(ResourcePackSummary summary) { + return this.packs.get(summary.getId()); + } + + @Override + public void reload() { + this.packs.clear(); + this.repository.reload(); + + for (ResourcePackSummary summary : this.repository.getAvailablePacks()) { + this.packs.put(summary.getId(), Adapters.unopenedPack(summary, this.factory)); + } + } + + @Override + public void select(Collection packs) { + this.repository.setSelectedPacks(packs.stream().map(T::getId).collect(Collectors.toList())); + } + + @Override + public Collection getAvailable() { + return this.repository.getAvailablePacks().stream().map(this::summaryToPack).collect(Collectors.toList()); + } + + @Override + public Collection getUnselected() { + return this.repository.getUnselectedPacks().stream().map(this::summaryToPack).collect(Collectors.toList()); + } + + @Override + public Collection getSelected() { + return this.repository.getSelectedPacks().stream().map(this::summaryToPack).collect(Collectors.toList()); + } + + @Override + public T getPack(String id) { + return this.packs.get(id); + } + + @Override + public void addSource(RepositorySource source) { + this.repository.addSource(new WrappedRepositorySource<>(this.factory, source)); + } + + @Override + public void close() { + this.repository.close(); + } +} \ No newline at end of file diff --git a/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourceReloadAdapter.java b/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourceReloadAdapter.java new file mode 100644 index 00000000..ba64d070 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/ResourceReloadAdapter.java @@ -0,0 +1,42 @@ +package net.ornithemc.osl.resource.loader.impl.adapter; + +import java.util.concurrent.CompletableFuture; + +import net.minecraft.unmapped.C_17695012; +import net.minecraft.unmapped.C_75765617; + +import net.ornithemc.osl.resource.loader.api.resource.reload.ResourceReload; + +class ResourceReloadAdapter implements C_17695012 { + + private final ResourceReload resourceReload; + + ResourceReloadAdapter(ResourceReload resourceReload) { + this.resourceReload = resourceReload; + } + + @Override + public boolean m_16882347() { + return this.resourceReload.isApplying(); + } + + @Override + public void m_29451477() { + this.resourceReload.checkExceptions(); + } + + @Override + public CompletableFuture m_58614058() { + return this.resourceReload.result().thenApply(u -> C_75765617.INSTANCE); + } + + @Override + public boolean m_77649850() { + return this.resourceReload.isDone(); + } + + @Override + public float m_98266169() { + return this.resourceReload.getProgress(); + } +} diff --git a/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/WrappedPack.java b/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/WrappedPack.java new file mode 100644 index 00000000..adf06f04 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/WrappedPack.java @@ -0,0 +1,103 @@ +package net.ornithemc.osl.resource.loader.impl.adapter; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.util.Set; + +import com.google.gson.JsonObject; + +import net.minecraft.client.resource.metadata.serializer.ResourceMetadataSerializer; +import net.minecraft.resource.pack.Pack; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.function.IOSupplier; +import net.ornithemc.osl.resource.loader.api.resource.ResourceMetadata.Section.Serializer; +import net.ornithemc.osl.resource.loader.api.resource.ResourceType; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourceConsumer; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePack; + +class WrappedPack implements ResourcePack { + + final Pack pack; + + WrappedPack(Pack pack) { + this.pack = pack; + } + + @Override + public String getId() { + return this.pack.getName(); + } + + @Override + public boolean hasResource(String path) { + try { + return this.getResource(path) != null; + } catch (IOException e) { + return false; + } + } + + @Override + public InputStream getResource(String path) throws IOException { + if (path.contains("/") || path.contains("\\")) { + return null; + } else { + return this.pack.getRootResource(path); + } + } + + @Override + public Set getNamespaces(ResourceType type) { + return this.pack.getNamespaces(Adapters.packType(type)); + } + + @Override + public boolean hasResource(ResourceType type, NamespacedIdentifier location) { + return this.pack.hasResource(Adapters.packType(type), Adapters.identifier(location)); + } + + @Override + public IOSupplier getResource(ResourceType type, NamespacedIdentifier location) { + return this.pack.hasResource(Adapters.packType(type), Adapters.identifier(location)) ? () -> this.pack.getResource(Adapters.packType(type), Adapters.identifier(location)) : null; + } + + @Override + public void findResources(ResourceType type, String namespace, String directory, ResourceConsumer consumer) { + this.pack.findResources(Adapters.packType(type), directory, Integer.MAX_VALUE, fileName -> true).forEach(location -> { + if (location.getNamespace().equals(namespace)) { + consumer.accept((NamespacedIdentifier) location, () -> this.pack.getResource(Adapters.packType(type), location)); + } + }); + } + + @Override + public T getMetadata(String name, Serializer serializer) throws IOException { + return this.pack.getMetadataSection(new ResourceMetadataSerializer() { + + @Override + public T deserialize(JsonObject json) { + return serializer.deserialize(json); + } + + @Override + public String getName() { + return name; + } + }); + } + + @Override + public void open() { + } + + @Override + public void close() { + try { + this.pack.close(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } +} diff --git a/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/WrappedRepositorySource.java b/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/WrappedRepositorySource.java new file mode 100644 index 00000000..a826e82d --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/WrappedRepositorySource.java @@ -0,0 +1,31 @@ +package net.ornithemc.osl.resource.loader.impl.adapter; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.function.Consumer; + +import net.minecraft.resource.pack.repository.RepositorySource; +import net.minecraft.resource.pack.repository.UnopenedPack; + +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackRepository; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackSummary; + +class WrappedRepositorySource implements ResourcePackRepository.Source { + + private final UnopenedPack.Factory factory; + private final RepositorySource source; + + WrappedRepositorySource(UnopenedPack.Factory factory, RepositorySource source) { + this.factory = factory; + this.source = source; + } + + @Override + public void loadResourcePacks(Consumer consumer) { + Map packs = new LinkedHashMap<>(); + this.source.loadPacks(packs, this.factory); + packs.values().forEach(pack -> { + consumer.accept(Adapters.resourcePackSummary(pack)); + }); + } +} diff --git a/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/WrappedUnopenedPack.java b/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/WrappedUnopenedPack.java new file mode 100644 index 00000000..dc1501f4 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/adapter/WrappedUnopenedPack.java @@ -0,0 +1,72 @@ +package net.ornithemc.osl.resource.loader.impl.adapter; + +import net.minecraft.client.resource.pack.UnopenedResourcePack; +import net.minecraft.resource.pack.repository.UnopenedPack; + +import net.ornithemc.osl.resource.loader.api.resource.pack.PackCompatibility; +import net.ornithemc.osl.resource.loader.api.resource.pack.PackPosition; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePack; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackSummary; +import net.ornithemc.osl.text.api.TextComponent; + +class WrappedUnopenedPack implements ResourcePackSummary { + + final T pack; + + WrappedUnopenedPack(T pack) { + this.pack = pack; + } + + @Override + public TextComponent getTitle() { + if (this.pack instanceof UnopenedResourcePack) { + // TODO: convert Vanilla Text -> OSL TextComponent + } + + return null; + } + + @Override + public TextComponent getDescription() { + if (this.pack instanceof UnopenedResourcePack) { + // TODO: convert Vanilla Text -> OSL TextComponent + } + + return null; + } + + @Override + public String getId() { + return this.pack.getId(); + } + + @Override + public boolean isRequired() { + return this.pack.isRequired(); + } + + @Override + public boolean isFixedPosition() { + return this.pack.isFixed(); + } + + @Override + public PackPosition getDefaultPosition() { + return Adapters.packPosition(this.pack.getPosition()); + } + + @Override + public PackCompatibility getCompatibility() { + return Adapters.packCompatibility(this.pack.getCompatibility()); + } + + @Override + public ResourcePack open() { + return Adapters.resourcePack(this.pack.build()); + } + + @Override + public void close() { + this.pack.close(); + } +} diff --git a/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/MinecraftMixin.java b/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/MinecraftMixin.java new file mode 100644 index 00000000..c2c39be6 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/MinecraftMixin.java @@ -0,0 +1,101 @@ +package net.ornithemc.osl.resource.loader.impl.mixin.client; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.At.Shift; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.resource.pack.UnopenedResourcePack; +import net.minecraft.resource.manager.ReloadableResourceManager; +import net.minecraft.resource.pack.repository.PackRepository; + +import net.ornithemc.osl.resource.loader.impl.adapter.ResourceManagerAdapter; +import net.ornithemc.osl.resource.loader.impl.adapter.ResourcePackRepositoryAdapter; +import net.ornithemc.osl.resource.loader.impl.resource.manager.SimpleReloadableResourceManager; +import net.ornithemc.osl.resource.loader.impl.resource.repository.BundledModResourcePacks; +import net.ornithemc.osl.resource.loader.impl.resource.repository.SimpleResourcePackRepository; + +@Mixin(Minecraft.class) +public class MinecraftMixin { + + @Shadow @Final @Mutable + private PackRepository packRepository; + @Shadow + private ReloadableResourceManager resourceManager; + + @Unique + private SimpleResourcePackRepository actualPackRepository; + @Unique + private SimpleReloadableResourceManager actualResourceManager; + + @Inject( + method = "", + at = @At( + value = "FIELD", + target = "Lnet/minecraft/client/Minecraft;packRepository:Lnet/minecraft/resource/pack/repository/PackRepository;", + ordinal = 0, + shift = Shift.AFTER + ) + ) + private void osl$resource_loader$setPackRepository(CallbackInfo ci) { + this.actualPackRepository = SimpleResourcePackRepository.client(); + this.packRepository = new ResourcePackRepositoryAdapter<>(this.packRepository.factory, this.actualPackRepository); + } + + @Inject( + method = "", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/resource/pack/repository/PackRepository;addSource(Lnet/minecraft/resource/pack/repository/RepositorySource;)V", + ordinal = 0, + shift = Shift.AFTER // after built-in Vanilla resources + ) + ) + private void osl$resource_loader$registerModResources(CallbackInfo ci) { + this.actualPackRepository.addSource(new BundledModResourcePacks()); + } + + @Inject( + method = "", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/resource/pack/repository/PackRepository;addSource(Lnet/minecraft/resource/pack/repository/RepositorySource;)V", + ordinal = 1, + shift = Shift.AFTER // after directory pack source + ) + ) + private void osl$resource_loader$initResourcePackRepository(CallbackInfo ci) { + this.actualPackRepository.init(); + } + + @Inject( + method = "init", + at = @At( + value = "FIELD", + target = "Lnet/minecraft/client/Minecraft;resourceManager:Lnet/minecraft/resource/manager/ReloadableResourceManager;", + ordinal = 0, + shift = Shift.AFTER + ) + ) + private void osl$resource_loader$setResourceManager(CallbackInfo ci) { + this.actualResourceManager = SimpleReloadableResourceManager.client(); + this.resourceManager = new ResourceManagerAdapter(this.actualResourceManager); + } + + @Inject( + method = "init", + at = @At( + value = "NEW", + target = "Lnet/minecraft/client/gui/GameGui;" // after all Vanilla reload listeners + ) + ) + private void osl$resource_loader$initResourceManager(CallbackInfo ci) { + this.actualResourceManager.init(); + } +} diff --git a/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/ResourcePacksMixin.java b/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/ResourcePacksMixin.java new file mode 100644 index 00000000..f3eeb7dc --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/ResourcePacksMixin.java @@ -0,0 +1,39 @@ +package net.ornithemc.osl.resource.loader.impl.mixin.client; + +import java.io.IOException; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.resource.pack.BuiltInPack; +import net.minecraft.resource.pack.metadata.PackMetadataSection; + +import net.ornithemc.osl.resource.loader.impl.ResourceLoader; +import net.ornithemc.osl.resource.loader.impl.resource.pack.ResourcePacks; + +@Mixin(net.minecraft.client.resource.pack.ResourcePacks.class) +public class ResourcePacksMixin { + + @Shadow + private BuiltInPack defaultPack; + + @Inject( + method = "", + at = @At( + value = "TAIL" + ) + ) + private void osl$resource_loader$detetectPackFormat(CallbackInfo ci) { + try { + PackMetadataSection metadata = defaultPack.getMetadataSection(PackMetadataSection.SERIALIZER); + int format = metadata.getFormat(); + + ResourcePacks.setSupportedFormat(format); + } catch (IOException e) { + ResourceLoader.LOGGER.info("unable to parse pack format from default resource pack", e); + } + } +} diff --git a/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/common/DataPacksMixin.java b/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/common/DataPacksMixin.java new file mode 100644 index 00000000..8287a714 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/common/DataPacksMixin.java @@ -0,0 +1,40 @@ +package net.ornithemc.osl.resource.loader.impl.mixin.common; + +import java.io.IOException; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.resource.pack.BuiltInPack; +import net.minecraft.resource.pack.metadata.PackMetadataSection; +import net.minecraft.server.resource.pack.DataPacks; + +import net.ornithemc.osl.resource.loader.impl.ResourceLoader; +import net.ornithemc.osl.resource.loader.impl.resource.pack.ResourcePacks; + +@Mixin(DataPacks.class) +public class DataPacksMixin { + + @Shadow + private BuiltInPack defaultPack; + + @Inject( + method = "", + at = @At( + value = "TAIL" + ) + ) + private void osl$resource_loader$detetectPackFormat(CallbackInfo ci) { + try { + PackMetadataSection metadata = defaultPack.getMetadataSection(PackMetadataSection.SERIALIZER); + int format = metadata.getFormat(); + + ResourcePacks.setSupportedFormat(format); + } catch (IOException e) { + ResourceLoader.LOGGER.info("unable to parse pack format from default data pack", e); + } + } +} diff --git a/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/common/MinecraftServerMixin.java b/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/common/MinecraftServerMixin.java new file mode 100644 index 00000000..2ff0dc52 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/common/MinecraftServerMixin.java @@ -0,0 +1,100 @@ +package net.ornithemc.osl.resource.loader.impl.mixin.common; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.At.Shift; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.resource.manager.ReloadableResourceManager; +import net.minecraft.resource.pack.repository.PackRepository; +import net.minecraft.resource.pack.repository.UnopenedPack; +import net.minecraft.server.MinecraftServer; + +import net.ornithemc.osl.resource.loader.impl.adapter.ResourceManagerAdapter; +import net.ornithemc.osl.resource.loader.impl.adapter.ResourcePackRepositoryAdapter; +import net.ornithemc.osl.resource.loader.impl.resource.manager.SimpleReloadableResourceManager; +import net.ornithemc.osl.resource.loader.impl.resource.repository.BundledModResourcePacks; +import net.ornithemc.osl.resource.loader.impl.resource.repository.SimpleResourcePackRepository; + +@Mixin(MinecraftServer.class) +public class MinecraftServerMixin { + + @Shadow @Final @Mutable + private PackRepository packRepository; + @Shadow @Final @Mutable + private ReloadableResourceManager resourceManager; + + @Unique + private SimpleResourcePackRepository actualPackRepository; + @Unique + private SimpleReloadableResourceManager actualResourceManager; + + @Inject( + method = "", + at = @At( + value = "FIELD", + target = "Lnet/minecraft/server/MinecraftServer;packRepository:Lnet/minecraft/resource/pack/repository/PackRepository;", + ordinal = 0, + shift = Shift.AFTER + ) + ) + private void osl$resource_loader$setPackRepository(CallbackInfo ci) { + this.actualPackRepository = SimpleResourcePackRepository.server(); + this.packRepository = new ResourcePackRepositoryAdapter<>(this.packRepository.factory, this.actualPackRepository); + } + + @Inject( + method = "", + at = @At( + value = "FIELD", + target = "Lnet/minecraft/server/MinecraftServer;resourceManager:Lnet/minecraft/resource/manager/ReloadableResourceManager;", + ordinal = 0, + shift = Shift.AFTER + ) + ) + private void osl$resource_loader$setResourceManager(CallbackInfo ci) { + this.actualResourceManager = SimpleReloadableResourceManager.server(); + this.resourceManager = new ResourceManagerAdapter(this.actualResourceManager); + } + + @Inject( + method = "", + at = @At( + value = "TAIL" // after last resource reloader is registered + ) + ) + private void osl$resource_loader$initResourceManager(CallbackInfo ci) { + this.actualResourceManager.init(); + } + + @Inject( + method = "loadDataPacks", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/resource/pack/repository/PackRepository;addSource(Lnet/minecraft/resource/pack/repository/RepositorySource;)V", + ordinal = 0, + shift = Shift.AFTER // after built-in Vanilla resources + ) + ) + private void osl$resource_loader$registerModResources(CallbackInfo ci) { + this.actualPackRepository.addSource(new BundledModResourcePacks()); + } + + @Inject( + method = "loadDataPacks", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/resource/pack/repository/PackRepository;addSource(Lnet/minecraft/resource/pack/repository/RepositorySource;)V", + ordinal = 1, + shift = Shift.AFTER // after directory pack source + ) + ) + private void osl$resource_loader$initResourcePackRepository(CallbackInfo ci) { + this.actualPackRepository.init(); + } +} diff --git a/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/resources/fabric.mod.json b/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/resources/fabric.mod.json new file mode 100644 index 00000000..9556923b --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/resources/fabric.mod.json @@ -0,0 +1,28 @@ +{ + "schemaVersion": 1, + "id": "osl-resource-loader", + "version": "0.6.1+mc19w07a-mc1.14.4", + "environment": "*", + "mixins": [ + "osl.resource-loader.mixins.json" + ], + "accessWidener": "osl.resource-loader.classtweaker", + "depends": { + "fabricloader": "\u003e\u003d0.18.0", + "minecraft": "\u003e\u003d1.14-alpha.19.7.a \u003c\u003d1.14.4", + "osl-core": "\u003e\u003d0.7.0", + "osl-executors": "\u003e\u003d0.1.0-", + "osl-text-components": "\u003e\u003d0.1.0-" + }, + "name": "OSL Resource Loader", + "description": "Resource loading API and events.", + "authors": [ + "OrnitheMC" + ], + "contact": { + "homepage": "https://ornithemc.net/", + "issues": "https://github.com/OrnitheMC/ornithe-standard-libraries/issues", + "sources": "https://github.com/OrnitheMC/ornithe-standard-libraries" + }, + "license": "Apache-2.0" +} \ No newline at end of file diff --git a/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/resources/osl.resource-loader.classtweaker b/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/resources/osl.resource-loader.classtweaker new file mode 100644 index 00000000..903b1a2c --- /dev/null +++ b/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/resources/osl.resource-loader.classtweaker @@ -0,0 +1,3 @@ +classTweaker v1 named + +accessible field net/minecraft/resource/pack/repository/PackRepository factory Lnet/minecraft/resource/pack/repository/UnopenedPack$Factory; \ No newline at end of file diff --git a/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/resources/osl.resource-loader.mixins.json b/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/resources/osl.resource-loader.mixins.json similarity index 93% rename from libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/resources/osl.resource-loader.mixins.json rename to libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/resources/osl.resource-loader.mixins.json index 8032b214..d516d571 100644 --- a/libraries/resource-loader/resource-loader-mc17w43a-mc19w07a/src/main/resources/osl.resource-loader.mixins.json +++ b/libraries/resource-loader/resource-loader-mc19w07a-mc1.14.4/src/main/resources/osl.resource-loader.mixins.json @@ -8,7 +8,6 @@ "common.MinecraftServerMixin" ], "client": [ - "client.LocaleMixin", "client.MinecraftMixin", "client.ResourcePacksMixin" ], diff --git a/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/gradle.properties b/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/gradle.properties deleted file mode 100644 index ceb08f80..00000000 --- a/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/gradle.properties +++ /dev/null @@ -1,6 +0,0 @@ -min_mc_version = 19w08a -max_mc_version = 1.14.4 -minecraft_dependency = >=1.14-alpha.19.8.a <=1.14.4 - -minecraft_version = 1.14.4 -feather_build = 1 diff --git a/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/api/ModPack.java b/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/api/ModPack.java deleted file mode 100644 index 72a9f6d6..00000000 --- a/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/api/ModPack.java +++ /dev/null @@ -1,11 +0,0 @@ -package net.ornithemc.osl.resource.loader.api; - -import net.fabricmc.loader.api.metadata.ModMetadata; - -import net.minecraft.resource.pack.Pack; - -public interface ModPack extends Pack { - - ModMetadata getModMetadata(); - -} diff --git a/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/api/ResourceUtils.java b/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/api/ResourceUtils.java deleted file mode 100644 index cc1974f1..00000000 --- a/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/api/ResourceUtils.java +++ /dev/null @@ -1,12 +0,0 @@ -package net.ornithemc.osl.resource.loader.api; - -public class ResourceUtils { - - public static boolean isValidNamespace(String namespace) { - return namespace.chars().allMatch(chr -> chr == '-' || chr == '.' || chr == '_' || (chr >= 'a' && chr <= 'z') || (chr >= '0' && chr <= '9')); - } - - public static boolean isValidPath(String namespace) { - return namespace.chars().allMatch(chr -> chr == '-' || chr == '.' || chr == '_' || chr == '/' || (chr >= 'a' && chr <= 'z') || (chr >= '0' && chr <= '9')); - } -} diff --git a/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/api/client/ClientResourceLoaderEvents.java b/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/api/client/ClientResourceLoaderEvents.java deleted file mode 100644 index 31d893b7..00000000 --- a/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/api/client/ClientResourceLoaderEvents.java +++ /dev/null @@ -1,64 +0,0 @@ -package net.ornithemc.osl.resource.loader.api.client; - -import java.util.function.Consumer; - -import net.ornithemc.osl.core.api.events.Event; -import net.ornithemc.osl.resource.loader.api.ModPack; - -/** - * Events related to client side resource loading. - */ -public class ClientResourceLoaderEvents { - - /** - * This event is invoked upon game start-up, giving mod developers the - * opportunity to register custom built-in resource packs. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ClientResourceLoaderEvents.ADD_DEFAULT_RESOURCE_PACKS.register(adder -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event>> ADD_DEFAULT_RESOURCE_PACKS = Event.consumer(); - - /** - * This event is invoked before resources are reloaded. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ClientResourceLoaderEvents.START_RESOURCE_RELOAD.register(() -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event START_RESOURCE_RELOAD = Event.runnable(); - /** - * This event is invoked after resources are reloaded. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ClientResourceLoaderEvents.END_RESOURCE_RELOAD.register(() -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event END_RESOURCE_RELOAD = Event.runnable(); - -} diff --git a/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/api/server/ServerResourceLoaderEvents.java b/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/api/server/ServerResourceLoaderEvents.java deleted file mode 100644 index 95802d8a..00000000 --- a/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/api/server/ServerResourceLoaderEvents.java +++ /dev/null @@ -1,64 +0,0 @@ -package net.ornithemc.osl.resource.loader.api.server; - -import java.util.function.Consumer; - -import net.ornithemc.osl.core.api.events.Event; -import net.ornithemc.osl.resource.loader.api.ModPack; - -/** - * Events related to server side resource loading. - */ -public class ServerResourceLoaderEvents { - - /** - * This event is invoked upon server start-up, giving mod developers the - * opportunity to register custom built-in data packs. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ServerResourceLoaderEvents.ADD_DEFAULT_RESOURCE_PACKS.register(adder -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event>> ADD_DEFAULT_DATA_PACKS = Event.consumer(); - - /** - * This event is invoked before resources are reloaded. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ServerResourceLoaderEvents.START_RESOURCE_RELOAD.register(() -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event START_RESOURCE_RELOAD = Event.runnable(); - /** - * This event is invoked after resources are reloaded. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ServerResourceLoaderEvents.END_RESOURCE_RELOAD.register(() -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event END_RESOURCE_RELOAD = Event.runnable(); - -} diff --git a/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/BuiltInModPack.java b/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/BuiltInModPack.java deleted file mode 100644 index e2c491df..00000000 --- a/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/BuiltInModPack.java +++ /dev/null @@ -1,241 +0,0 @@ -package net.ornithemc.osl.resource.loader.impl; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.nio.file.DirectoryStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Predicate; -import java.util.stream.Stream; - -import com.google.gson.JsonObject; - -import net.fabricmc.loader.api.FabricLoader; -import net.fabricmc.loader.api.ModContainer; -import net.fabricmc.loader.api.metadata.ModMetadata; - -import net.minecraft.client.resource.metadata.serializer.ResourceMetadataSerializer; -import net.minecraft.resource.Identifier; -import net.minecraft.resource.pack.CustomPack; -import net.minecraft.resource.pack.Pack; -import net.minecraft.resource.pack.PackType; - -import net.ornithemc.osl.resource.loader.api.ModPack; -import net.ornithemc.osl.resource.loader.api.ResourceUtils; - -public class BuiltInModPack implements ModPack { - - private static final boolean DEBUG = FabricLoader.getInstance().isDevelopmentEnvironment(); - - private final ModContainer mod; - private final PackType type; - private final Map> namespaces; - - private final List roots; - //private final String separator; - - private JsonObject generatedPackMetadata; - - public BuiltInModPack(ModContainer mod, PackType type) { - this.mod = mod; - this.type = type; - this.namespaces = new HashMap<>(); - - this.roots = this.mod.getRootPaths(); - - findNamespaces(); - } - - private void findNamespaces() { - for (Path root : roots) { - String separator = root.getFileSystem().getSeparator(); - - for (PackType type : PackType.values()) { - Path dir = root.resolve(type.getDirectory()); - Set ns = new HashSet<>(); - - if (Files.isDirectory(dir)) { - try (DirectoryStream ds = Files.newDirectoryStream(dir)) { - for (Path p : ds) { - String s = p.getFileName().toString(); - String namespace = s.replace(separator, ""); - - if (ResourceUtils.isValidNamespace(namespace)) { - ns.add(namespace); - } - } - } catch (IOException e) { - ResourceLoader.LOGGER.warn("failed to parse namespaces for built-in resource pack for mod " + mod.getMetadata().getId(), e); - } - } - - namespaces.put(type, ns); - } - } - } - - @Override - public InputStream getRootResource(String path) throws IOException { - if (path.contains("/") || path.contains("\\")) { - throw new IllegalArgumentException("Root resources can only be filenames, not paths (no / allowed!)"); - } - - Path p = getPath(path); - - if (p == null || !Files.exists(p)) { - if ("pack.mcmeta".equals(path)) { - JsonObject metadata = generatePackMetadata(); - String serializedMetadata = metadata.toString(); - - return new ByteArrayInputStream(serializedMetadata.getBytes(StandardCharsets.UTF_8)); - } - if ("pack.png".equals(path)) { - return Pack.class.getResourceAsStream("/" + path); - } - - return null; - } - - return Files.newInputStream(p); - } - - @Override - public InputStream getResource(PackType type, Identifier location) throws IOException { - Path path = getPath(type, location); - - if (path == null || !Files.exists(path)) { - if ("pack.mcmeta".equals(location.getPath())) { - JsonObject metadata = generatePackMetadata(); - String serializedMetadata = metadata.toString(); - - return new ByteArrayInputStream(serializedMetadata.getBytes(StandardCharsets.UTF_8)); - } - if ("pack.png".equals(location.getPath())) { - return Pack.class.getResourceAsStream("/" + location.getPath()); - } - - return null; - } - - return Files.newInputStream(path); - } - - @Override - public boolean hasResource(PackType type, Identifier location) { - Path path = getPath(type, location); - return path != null && Files.exists(path); - } - - @Override - public Collection findResources(PackType type, String path, int maxDepth, Predicate filter) { - Collection locations = new LinkedHashSet<>(); - - for (String namespace : namespaces.get(type)) { - try { - locations.addAll(getResources(type, maxDepth, namespace, path, filter)); - } catch (IOException e) { - } - } - - return locations; - } - - private Collection getResources(PackType type, int maxDepth, String namespace, String path, Predicate filter) throws IOException { - List locations = new ArrayList<>(); - - for (Path root : roots) { - String separator = root.getFileSystem().getSeparator(); - Path dir = root.resolve(type.getDirectory()).resolve(namespace); - Path start = dir.resolve(path.replace("/", separator)); - - if (!Files.isDirectory(start)) { - continue; - } - - try (Stream paths = Files.find( - start, - Integer.MAX_VALUE, - (p, attributes) -> attributes.isRegularFile() - && !p.toString().endsWith(".mcmeta") - && (DEBUG || !p.endsWith(".ds_store")) - && filter.test(p.getFileName().toString()) - )) { - paths.forEach(p -> { - locations.add(new Identifier(namespace, dir.relativize(p).toString().replaceAll(separator, "/"))); - }); - } - } - - return locations; - } - - @Override - public void close() throws IOException { - } - - @Override - public Set getNamespaces(PackType type) { - return namespaces.get(type); - } - - @Override - public T getMetadataSection(ResourceMetadataSerializer serializer) throws IOException { - try (InputStream is = getRootResource("pack.mcmeta")) { - return CustomPack.getMetadataSection(serializer, is); - } - } - - @Override - public String getName() { - return getModMetadata().getName(); - } - - @Override - public ModMetadata getModMetadata() { - return mod.getMetadata(); - } - - private Path getPath(PackType type, Identifier location) { - return getPath(getPathName(type, location)); - } - - private Path getPath(String path) { - for (Path root : roots) { - String separator = root.getFileSystem().getSeparator(); - String pathName = path.replace("/", separator); - Path p = root.resolve(pathName); - - if (Files.exists(p)) { - return p; - } - } - - return null; - } - - private String getPathName(PackType type, Identifier location) { - return String.format("%s/%s/%s", type.getDirectory(), location.getNamespace(), location.getPath()); - } - - private JsonObject generatePackMetadata() { - if (generatedPackMetadata == null) { - generatedPackMetadata = new JsonObject(); - JsonObject pack = new JsonObject(); - pack.addProperty("pack_format", ResourceLoader.getPackFormat(type)); - pack.addProperty("description", getModMetadata().getDescription()); - generatedPackMetadata.add("pack", pack); - } - - return generatedPackMetadata; - } -} diff --git a/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/ResourceLoader.java b/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/ResourceLoader.java deleted file mode 100644 index 7f28b6b4..00000000 --- a/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/ResourceLoader.java +++ /dev/null @@ -1,61 +0,0 @@ -package net.ornithemc.osl.resource.loader.impl; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import net.minecraft.resource.pack.PackType; - -import net.ornithemc.osl.resource.loader.api.ModPack; - -public class ResourceLoader { - - public static final Logger LOGGER = LogManager.getLogger("OSL|Resource Loader"); - - private static final List DEFAULT_MOD_PACKS = new ArrayList<>(); - - private static int resourcePackFormat = -1; - private static int dataPackFormat = -1; - - public static void setResourcePackFormat(int format) { - if (resourcePackFormat < 0) { - resourcePackFormat = format; - } - } - - public static void setDataPackFormat(int format) { - if (dataPackFormat < 0) { - dataPackFormat = format; - } - } - - public static boolean addDefaultModPack(ModPack pack) { - return DEFAULT_MOD_PACKS.add(pack); - } - - public static List getDefaultModPacks() { - return Collections.unmodifiableList(DEFAULT_MOD_PACKS); - } - - public static int getPackFormat(PackType type) { - switch (type) { - case CLIENT_RESOURCES: - return getResourcePackFormat(); - case SERVER_DATA: - return getDataPackFormat(); - default: - throw new IllegalStateException("unable to get format for unknown pack type " + type); - } - } - - public static int getResourcePackFormat() { - return resourcePackFormat; - } - - public static int getDataPackFormat() { - return dataPackFormat; - } -} diff --git a/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/LocaleMixin.java b/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/LocaleMixin.java deleted file mode 100644 index 2bcfb606..00000000 --- a/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/LocaleMixin.java +++ /dev/null @@ -1,90 +0,0 @@ -package net.ornithemc.osl.resource.loader.impl.mixin.client; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.List; -import java.util.Map; - -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import com.llamalad7.mixinextras.injector.wrapoperation.Operation; -import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; -import com.llamalad7.mixinextras.sugar.Local; - -import net.minecraft.client.resource.language.Locale; -import net.minecraft.resource.Identifier; -import net.minecraft.resource.Resource; -import net.minecraft.resource.manager.ResourceManager; - -@Mixin(Locale.class) -public abstract class LocaleMixin { - - @Final - @Shadow - private Map translations; - - @Shadow - protected abstract void load(List resources); - - @Inject( - method = "load(Lnet/minecraft/resource/manager/ResourceManager;Ljava/util/List;)V", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/resource/manager/ResourceManager;getResources(Lnet/minecraft/resource/Identifier;)Ljava/util/List;" - ) - ) - private void osl$resource_loader$loadTranslationFiles(CallbackInfo ci, - @Local(argsOnly = true) ResourceManager resourceManager, - @Local(ordinal = 0) String languageCode, - @Local(ordinal = 2) String namespace) { - String[] paths = new String[] { - String.format("lang/%s.lang", languageCode), - String.format("lang/%s.json", languageCode.toLowerCase(java.util.Locale.ROOT)), - String.format("lang/%s.lang", languageCode.toLowerCase(java.util.Locale.ROOT)) - }; - for (String path : paths) { - try { - this.load(resourceManager.getResources(new Identifier(namespace, path))); - } catch (IOException ignored) { - } - } - } - - @WrapOperation( - method = "load(Ljava/util/List;)V", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/client/resource/language/Locale;load(Ljava/io/InputStream;)V" - ) - ) - private void osl$resource_loader$loadTranslationFiles(Locale instance, InputStream is, Operation original, @Local Resource resource) throws IOException{ - if (resource.getLocation().getPath().endsWith(".lang")){ - loadLang(is); - } else { - original.call(instance, is); // load .json - } - } - - @Unique - private void loadLang(InputStream stream) throws IOException { - if (stream == null) { - return; - } - - try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream))) { - reader - .lines() - .filter(l -> !l.startsWith("#")) - .map(line -> line.split("=", 2)) - .forEach(key -> translations.put(key[0], key[1])); - } - } -} diff --git a/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/MinecraftMixin.java b/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/MinecraftMixin.java deleted file mode 100644 index 42b9bf0f..00000000 --- a/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/MinecraftMixin.java +++ /dev/null @@ -1,34 +0,0 @@ -package net.ornithemc.osl.resource.loader.impl.mixin.client; - -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; - -import net.minecraft.client.Minecraft; - -import net.ornithemc.osl.resource.loader.api.client.ClientResourceLoaderEvents; - -@Mixin(Minecraft.class) -public class MinecraftMixin { - - @Inject( - method = "reloadResources", - at = @At( - value = "HEAD" - ) - ) - private void osl$resource_loader$startResourceReload(CallbackInfoReturnable ci) { - ClientResourceLoaderEvents.START_RESOURCE_RELOAD.invoker().run(); - } - - @Inject( - method = "reloadResources", - at = @At( - value = "TAIL" - ) - ) - private void osl$resource_loader$endResourceReload(CallbackInfoReturnable ci) { - ClientResourceLoaderEvents.END_RESOURCE_RELOAD.invoker().run(); - } -} diff --git a/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/ResourcePacksMixin.java b/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/ResourcePacksMixin.java deleted file mode 100644 index 56f6edcd..00000000 --- a/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/ResourcePacksMixin.java +++ /dev/null @@ -1,72 +0,0 @@ -package net.ornithemc.osl.resource.loader.impl.mixin.client; - -import java.io.IOException; -import java.util.Map; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import net.fabricmc.loader.api.FabricLoader; -import net.fabricmc.loader.api.ModContainer; - -import net.minecraft.client.resource.pack.ResourcePacks; -import net.minecraft.resource.pack.BuiltInPack; -import net.minecraft.resource.pack.PackType; -import net.minecraft.resource.pack.metadata.PackMetadataSection; -import net.minecraft.resource.pack.repository.UnopenedPack; - -import net.ornithemc.osl.resource.loader.api.ModPack; -import net.ornithemc.osl.resource.loader.api.client.ClientResourceLoaderEvents; -import net.ornithemc.osl.resource.loader.impl.BuiltInModPack; -import net.ornithemc.osl.resource.loader.impl.ResourceLoader; - -@Mixin(ResourcePacks.class) -public class ResourcePacksMixin { - - @Shadow - private BuiltInPack defaultPack; - - @Inject( - method = "", - at = @At( - value = "TAIL" - ) - ) - private void osl$resource_loader$detetectPackFormat(CallbackInfo ci) { - try { - PackMetadataSection metadata = defaultPack.getMetadataSection(PackMetadataSection.SERIALIZER); - int format = metadata.getFormat(); - - ResourceLoader.setResourcePackFormat(format); - } catch (IOException e) { - ResourceLoader.LOGGER.info("unable to parse resource pack format from default resource pack", e); - } - } - - @Inject( - method = "loadPacks", - at = @At( - value = "TAIL" - ) - ) - private void osl$resource_loader$addDefaultResourcePacks(Map packs, UnopenedPack.Factory factory, CallbackInfo ci) { - for (ModContainer mod : FabricLoader.getInstance().getAllMods()) { - if ("builtin".equals(mod.getMetadata().getType())) { - continue; - } - - osl$resource_loader$addDefaultResourcePack(packs, factory, new BuiltInModPack(mod, PackType.CLIENT_RESOURCES)); - } - - ClientResourceLoaderEvents.ADD_DEFAULT_RESOURCE_PACKS.invoker().accept(pack -> osl$resource_loader$addDefaultResourcePack(packs, factory, pack)); - } - - private void osl$resource_loader$addDefaultResourcePack(Map packs, UnopenedPack.Factory factory, ModPack pack) { - if (ResourceLoader.addDefaultModPack(pack)) { - packs.put(pack.getName(), UnopenedPack.create(pack.getName(), true, () -> pack, factory, UnopenedPack.Position.BOTTOM)); - } - } -} diff --git a/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/common/DataPacksMixin.java b/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/common/DataPacksMixin.java deleted file mode 100644 index 9bb1b855..00000000 --- a/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/common/DataPacksMixin.java +++ /dev/null @@ -1,72 +0,0 @@ -package net.ornithemc.osl.resource.loader.impl.mixin.common; - -import java.io.IOException; -import java.util.Map; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import net.fabricmc.loader.api.FabricLoader; -import net.fabricmc.loader.api.ModContainer; - -import net.minecraft.resource.pack.BuiltInPack; -import net.minecraft.resource.pack.PackType; -import net.minecraft.resource.pack.metadata.PackMetadataSection; -import net.minecraft.resource.pack.repository.UnopenedPack; -import net.minecraft.server.resource.pack.DataPacks; - -import net.ornithemc.osl.resource.loader.api.ModPack; -import net.ornithemc.osl.resource.loader.api.server.ServerResourceLoaderEvents; -import net.ornithemc.osl.resource.loader.impl.BuiltInModPack; -import net.ornithemc.osl.resource.loader.impl.ResourceLoader; - -@Mixin(DataPacks.class) -public class DataPacksMixin { - - @Shadow - private BuiltInPack defaultPack; - - @Inject( - method = "", - at = @At( - value = "TAIL" - ) - ) - private void osl$resource_loader$detetectPackFormat(CallbackInfo ci) { - try { - PackMetadataSection metadata = defaultPack.getMetadataSection(PackMetadataSection.SERIALIZER); - int format = metadata.getFormat(); - - ResourceLoader.setDataPackFormat(format); - } catch (IOException e) { - ResourceLoader.LOGGER.info("unable to parse data pack format from default data pack", e); - } - } - - @Inject( - method = "loadPacks", - at = @At( - value = "TAIL" - ) - ) - private void osl$resource_loader$addDefaultDataPacks(Map packs, UnopenedPack.Factory factory, CallbackInfo ci) { - for (ModContainer mod : FabricLoader.getInstance().getAllMods()) { - if ("builtin".equals(mod.getMetadata().getType())) { - continue; - } - - osl$resource_loader$addDefaultDataPack(packs, factory, new BuiltInModPack(mod, PackType.SERVER_DATA)); - } - - ServerResourceLoaderEvents.ADD_DEFAULT_DATA_PACKS.invoker().accept(pack -> osl$resource_loader$addDefaultDataPack(packs, factory, pack)); - } - - private void osl$resource_loader$addDefaultDataPack(Map packs, UnopenedPack.Factory factory, ModPack pack) { - if (ResourceLoader.addDefaultModPack(pack)) { - packs.put(pack.getName(), UnopenedPack.create(pack.getName(), true, () -> pack, factory, UnopenedPack.Position.BOTTOM)); - } - } -} diff --git a/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/common/MinecraftServerMixin.java b/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/common/MinecraftServerMixin.java deleted file mode 100644 index fbfc5173..00000000 --- a/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/common/MinecraftServerMixin.java +++ /dev/null @@ -1,34 +0,0 @@ -package net.ornithemc.osl.resource.loader.impl.mixin.common; - -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; - -import net.minecraft.server.MinecraftServer; - -import net.ornithemc.osl.resource.loader.api.server.ServerResourceLoaderEvents; - -@Mixin(MinecraftServer.class) -public class MinecraftServerMixin { - - @Inject( - method = "reloadResources", - at = @At( - value = "HEAD" - ) - ) - private void osl$resource_loader$startResourceReload(CallbackInfo ci) { - ServerResourceLoaderEvents.START_RESOURCE_RELOAD.invoker().run(); - } - - @Inject( - method = "reloadResources", - at = @At( - value = "TAIL" - ) - ) - private void osl$resource_loader$endResourceReload(CallbackInfo ci) { - ServerResourceLoaderEvents.END_RESOURCE_RELOAD.invoker().run(); - } -} diff --git a/libraries/resource-loader/resource-loader-mca1.0.1_01-mca1.2.1_01/build.gradle b/libraries/resource-loader/resource-loader-mca1.0.1_01-mca1.2.1_01/build.gradle new file mode 100644 index 00000000..0a350fdb --- /dev/null +++ b/libraries/resource-loader/resource-loader-mca1.0.1_01-mca1.2.1_01/build.gradle @@ -0,0 +1 @@ +setUpModule(project) diff --git a/libraries/resource-loader/resource-loader-mca1.0.1_01-mca1.2.1_01/gradle.properties b/libraries/resource-loader/resource-loader-mca1.0.1_01-mca1.2.1_01/gradle.properties new file mode 100644 index 00000000..1ced07e9 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mca1.0.1_01-mca1.2.1_01/gradle.properties @@ -0,0 +1,9 @@ +environment = client +min_mc_version = a1.0.1_01 +max_mc_version = a1.2.1_01 +minecraft_dependency = >=1.0.0-alpha.0.1.1 <=1.0.0-alpha.2.1.1 + +minecraft_version = a1.2.1_01 +client_raven_build = 1 +client_sparrow_build = 1 +client_nests_build = 5 diff --git a/libraries/resource-loader/resource-loader-mca1.0.1_01-mca1.2.1_01/src/main/java/net/ornithemc/osl/resource/loader/impl/ClientResourcePacks.java b/libraries/resource-loader/resource-loader-mca1.0.1_01-mca1.2.1_01/src/main/java/net/ornithemc/osl/resource/loader/impl/ClientResourcePacks.java new file mode 100644 index 00000000..40ca0834 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mca1.0.1_01-mca1.2.1_01/src/main/java/net/ornithemc/osl/resource/loader/impl/ClientResourcePacks.java @@ -0,0 +1,32 @@ +package net.ornithemc.osl.resource.loader.impl; + +import java.util.function.Consumer; + +import net.fabricmc.loader.api.FabricLoader; + +import net.ornithemc.osl.resource.loader.api.resource.pack.PackPosition; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePack; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackRepository; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackSummary; +import net.ornithemc.osl.resource.loader.impl.resource.pack.ModResourcePack; + +public class ClientResourcePacks implements ResourcePackRepository.Source { + + private final ResourcePack defaultPack; + + public ClientResourcePacks() { + this.defaultPack = new ModResourcePack(FabricLoader.getInstance().getModContainer("minecraft").get()); + } + + @Override + public void loadResourcePacks(Consumer consumer) { + ResourcePackSummary summary = ResourcePackSummary.create( + this.defaultPack, + true, + false, + PackPosition.BOTTOM + ); + + consumer.accept(summary); + } +} diff --git a/libraries/resource-loader/resource-loader-mca1.0.1_01-mca1.2.1_01/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/MinecraftMixin.java b/libraries/resource-loader/resource-loader-mca1.0.1_01-mca1.2.1_01/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/MinecraftMixin.java new file mode 100644 index 00000000..aba3a823 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mca1.0.1_01-mca1.2.1_01/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/MinecraftMixin.java @@ -0,0 +1,38 @@ +package net.ornithemc.osl.resource.loader.impl.mixin.client; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.client.Minecraft; + +import net.ornithemc.osl.resource.loader.impl.ClientResourcePacks; +import net.ornithemc.osl.resource.loader.impl.resource.repository.BundledModResourcePacks; +import net.ornithemc.osl.resource.loader.impl.resource.repository.SimpleResourcePackRepository; + +@Mixin(Minecraft.class) +public class MinecraftMixin { + + @Unique + private SimpleResourcePackRepository packRepository; + + @Inject( + method = "init", + at = @At( + value = "NEW", + target = "net/minecraft/client/render/texture/TextureManager" + ) + ) + private void osl$resource_loader$initPackRepository(CallbackInfo ci) { + this.packRepository = SimpleResourcePackRepository.client(); + + this.packRepository.addSource(new ClientResourcePacks()); + this.packRepository.addSource(new BundledModResourcePacks()); +// this.packRepository.addSource(new DirectoryResourcePackSource()); // TODO + + this.packRepository.init(); + this.packRepository.reload(); + } +} diff --git a/libraries/resource-loader/resource-loader-mca1.0.1_01-mca1.2.1_01/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TextureManagerMixin.java b/libraries/resource-loader/resource-loader-mca1.0.1_01-mca1.2.1_01/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TextureManagerMixin.java new file mode 100644 index 00000000..c2ca495d --- /dev/null +++ b/libraries/resource-loader/resource-loader-mca1.0.1_01-mca1.2.1_01/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TextureManagerMixin.java @@ -0,0 +1,123 @@ +package net.ornithemc.osl.resource.loader.impl.mixin.client; + +import java.io.IOException; +import java.io.InputStream; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.client.render.texture.TextureManager; + +import net.ornithemc.osl.resource.loader.api.resource.manager.ResourceManager; +import net.ornithemc.osl.resource.loader.api.resource.reload.ResourceReloadListener; +import net.ornithemc.osl.resource.loader.impl.resource.manager.SimpleReloadableResourceManager; +import net.ornithemc.osl.resource.loader.impl.resource.repository.SimpleResourcePackRepository; + +@Mixin(TextureManager.class) +public class TextureManagerMixin implements ResourceReloadListener { + + @Unique + private SimpleResourcePackRepository packRepository; + @Unique + private SimpleReloadableResourceManager resourceManager; + + @Unique + private boolean vanillaReloading; + @Unique + private boolean reloading; + + @Shadow + private void reload() { } + + @Redirect( + method = "load(Ljava/lang/String;)I", + at = @At( + value = "INVOKE", + target = "Ljava/lang/Class;getResourceAsStream(Ljava/lang/String;)Ljava/io/InputStream;" + ) + ) + private InputStream osl$resource_loader$loadResource(Class cls, String path) { + try { + return this.resourceManager.getResource(path); + } catch (IOException e) { + return null; + } + } + + @Redirect( + method = "reload", + at = @At( + value = "INVOKE", + target = "Ljava/lang/Class;getResourceAsStream(Ljava/lang/String;)Ljava/io/InputStream;" + ) + ) + private InputStream osl$resource_loader$reloadResource(Class cls, String path) { + try { + return this.resourceManager.getResource(path); + } catch (IOException e) { + return null; + } + } + + @Inject( + method = "", + at = @At( + value = "TAIL" + ) + ) + private void osl$resource_loader$initResourceManager(CallbackInfo ci) { + this.packRepository = SimpleResourcePackRepository.client(); + this.resourceManager = SimpleReloadableResourceManager.client(); + + // ensure the selected packs have been applied + this.resourceManager.reload(this.packRepository.openSelectedPacks()); + + // let this class act as the texture reloader + this.resourceManager.addReloader(this); + + this.resourceManager.init(); + } + + @Inject( + method = "reload", + cancellable = true, + at = @At( + value = "HEAD" + ) + ) + private void osl$resource_loader$startReload(CallbackInfo ci) { + if (!this.vanillaReloading) { + this.vanillaReloading = true; + + if (!this.reloading) { + this.resourceManager.reload(this.packRepository.openSelectedPacks()); + + // cancel this call as the resource manager will trigger + // another recursive call through this.resourcesReloaded + ci.cancel(); + } + } + } + + @Inject( + method = "reload", + at = @At( + value = "TAIL" + ) + ) + private void osl$resource_loader$endReload(CallbackInfo ci) { + this.vanillaReloading = false; + } + + @Override + public void resourcesReloaded(ResourceManager manager) { + this.reloading = true; + this.reload(); + this.reloading = false; + } +} diff --git a/libraries/resource-loader/resource-loader-mc16w32a-mc1.12.2/src/main/resources/fabric.mod.json b/libraries/resource-loader/resource-loader-mca1.0.1_01-mca1.2.1_01/src/main/resources/fabric.mod.json similarity index 68% rename from libraries/resource-loader/resource-loader-mc16w32a-mc1.12.2/src/main/resources/fabric.mod.json rename to libraries/resource-loader/resource-loader-mca1.0.1_01-mca1.2.1_01/src/main/resources/fabric.mod.json index db810007..ac05b429 100644 --- a/libraries/resource-loader/resource-loader-mc16w32a-mc1.12.2/src/main/resources/fabric.mod.json +++ b/libraries/resource-loader/resource-loader-mca1.0.1_01-mca1.2.1_01/src/main/resources/fabric.mod.json @@ -1,15 +1,17 @@ { "schemaVersion": 1, "id": "osl-resource-loader", - "version": "0.6.1+mc16w32a-mc1.12.2", + "version": "0.6.1+mca1.0.1_01-mca1.2.1_01", "environment": "client", "mixins": [ "osl.resource-loader.mixins.json" ], "depends": { "fabricloader": "\u003e\u003d0.18.0", - "minecraft": "\u003e\u003d1.11-alpha.16.32.a \u003c\u003d1.12.2", - "osl-core": "\u003e\u003d0.7.0" + "minecraft": "\u003e\u003d1.0.0-alpha.0.1.1 \u003c\u003d1.0.0-alpha.2.1.1", + "osl-core": "\u003e\u003d0.7.0", + "osl-executors": "\u003e\u003d0.1.0-", + "osl-text-components": "\u003e\u003d0.1.0-" }, "name": "OSL Resource Loader", "description": "Resource loading API and events.", diff --git a/libraries/resource-loader/resource-loader-mc11w49a-mc1.2.5/src/main/resources/osl.resource-loader.mixins.json b/libraries/resource-loader/resource-loader-mca1.0.1_01-mca1.2.1_01/src/main/resources/osl.resource-loader.mixins.json similarity index 79% rename from libraries/resource-loader/resource-loader-mc11w49a-mc1.2.5/src/main/resources/osl.resource-loader.mixins.json rename to libraries/resource-loader/resource-loader-mca1.0.1_01-mca1.2.1_01/src/main/resources/osl.resource-loader.mixins.json index 59663fcd..bbcf178a 100644 --- a/libraries/resource-loader/resource-loader-mc11w49a-mc1.2.5/src/main/resources/osl.resource-loader.mixins.json +++ b/libraries/resource-loader/resource-loader-mca1.0.1_01-mca1.2.1_01/src/main/resources/osl.resource-loader.mixins.json @@ -6,8 +6,8 @@ "mixins": [ ], "client": [ - "client.TexturePackMixin", - "client.LanguageMixin" + "client.MinecraftMixin", + "client.TextureManagerMixin" ], "server": [ ], diff --git a/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/build.gradle b/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/build.gradle new file mode 100644 index 00000000..0a350fdb --- /dev/null +++ b/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/build.gradle @@ -0,0 +1 @@ +setUpModule(project) diff --git a/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/gradle.properties b/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/gradle.properties new file mode 100644 index 00000000..dada9984 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/gradle.properties @@ -0,0 +1,7 @@ +min_mc_version = a1.2.2 +max_mc_version = 1.2.5 +minecraft_dependency = >=1.0.0-alpha.2.2 <=1.2.5 + +minecraft_version = 1.2.5 +client_raven_build = 1 +client_nests_build = 10 diff --git a/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/ClientResourcePacks.java b/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/ClientResourcePacks.java new file mode 100644 index 00000000..bf2103c8 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/ClientResourcePacks.java @@ -0,0 +1,34 @@ +package net.ornithemc.osl.resource.loader.impl; + +import java.util.function.Consumer; + +import net.minecraft.client.resource.pack.TexturePack; + +import net.ornithemc.osl.resource.loader.api.resource.pack.PackPosition; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePack; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackRepository; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackSummary; + +public class ClientResourcePacks implements ResourcePackRepository.Source { + + private final TexturePack defaultPack; + + public ClientResourcePacks(TexturePack defaultPack) { + this.defaultPack = defaultPack; + } + + @Override + public void loadResourcePacks(Consumer consumer) { + ResourcePack pack = new WrappedTexturePack(this.defaultPack); + ResourcePackSummary summary = ResourcePackSummary.create( + pack, + true, + false, + PackPosition.BOTTOM + ); + + if (summary != null) { + consumer.accept(summary); + } + } +} diff --git a/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/ResourceManagerAdapter.java b/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/ResourceManagerAdapter.java new file mode 100644 index 00000000..6b19479c --- /dev/null +++ b/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/ResourceManagerAdapter.java @@ -0,0 +1,30 @@ +package net.ornithemc.osl.resource.loader.impl; + +import java.io.IOException; +import java.io.InputStream; + +import net.minecraft.client.resource.pack.TexturePack; + +import net.ornithemc.osl.resource.loader.api.resource.manager.ResourceManager; + +// one heck of a hack to inject OSL's resource manager +// as uninvasively as possible: turn it into a texture +// pack and select it in the texture pack manager +public class ResourceManagerAdapter extends TexturePack { + + private final ResourceManager resourceManager; + + public ResourceManagerAdapter(ResourceManager resourceManager) { + this.key = "osl:resource_manager"; + this.name = "OSL Resource Manager"; + this.descriptionLine1 = "Adapter for OSL's Resource Manager"; + this.descriptionLine1 = null; + + this.resourceManager = resourceManager; + } + + @Override + public InputStream getResource(String path) throws IOException { + return this.resourceManager.getResource(path); + } +} diff --git a/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/WrappedTexturePack.java b/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/WrappedTexturePack.java new file mode 100644 index 00000000..5ff3f9be --- /dev/null +++ b/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/WrappedTexturePack.java @@ -0,0 +1,91 @@ +package net.ornithemc.osl.resource.loader.impl; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +import net.minecraft.client.resource.pack.TexturePack; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.function.IOSupplier; +import net.ornithemc.osl.resource.loader.api.resource.ResourceType; +import net.ornithemc.osl.resource.loader.api.resource.pack.AbstractResourcePack; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourceConsumer; +import net.ornithemc.osl.resource.loader.impl.resource.pack.ResourcePacks; +import net.ornithemc.osl.text.api.TextComponents; + +public class WrappedTexturePack extends AbstractResourcePack { + + private final TexturePack pack; + private final IOSupplier metadata; + + public WrappedTexturePack(TexturePack pack) { + String description = pack.descriptionLine1; + if (pack.descriptionLine2 != null) { + description += "\n" + pack.descriptionLine2; + } + + this.pack = pack; + this.metadata = ResourcePacks.generateMetadataFile( + TextComponents.literal(description) + ); + } + + public static String getId(TexturePack pack) { + return "texturepack/" + pack.name; + } + + @Override + public String getId() { + return getId(this.pack); + } + + @Override + public boolean hasResource(String path) { + try { + return this.pack.getResource(path) != null; + } catch (IOException e) { + return false; + } + } + + @Override + public InputStream getResource(String path) throws IOException { + if (METADATA_FILE.equals(path)) { + return this.metadata.get(); + } + + return this.pack.getResource(path); + } + + @Override + protected Map> findNamespaces() { + return Collections.emptyMap(); + } + + @Override + public boolean hasResource(ResourceType type, NamespacedIdentifier location) { + return false; + } + + @Override + public IOSupplier getResource(ResourceType type, NamespacedIdentifier location) { + return null; + } + + @Override + public void findResources(ResourceType type, String namespace, String directory, ResourceConsumer consumer) { + } + + @Override + public void open() { + this.pack.open(); + } + + @Override + public void close() { + this.pack.close(); + } +} diff --git a/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/access/TexturePacksAccess.java b/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/access/TexturePacksAccess.java new file mode 100644 index 00000000..c6734a8a --- /dev/null +++ b/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/access/TexturePacksAccess.java @@ -0,0 +1,9 @@ +package net.ornithemc.osl.resource.loader.impl.access; + +import net.minecraft.client.resource.pack.TexturePack; + +public interface TexturePacksAccess { + + TexturePack osl$resource_loader$getActuallySelected(); + +} diff --git a/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TextureManagerMixin.java b/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TextureManagerMixin.java new file mode 100644 index 00000000..c3e6a7a7 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TextureManagerMixin.java @@ -0,0 +1,91 @@ +package net.ornithemc.osl.resource.loader.impl.mixin.client; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.client.render.texture.TextureManager; + +import net.ornithemc.osl.resource.loader.api.resource.manager.ResourceManager; +import net.ornithemc.osl.resource.loader.api.resource.reload.ResourceReloadListener; +import net.ornithemc.osl.resource.loader.impl.resource.manager.SimpleReloadableResourceManager; +import net.ornithemc.osl.resource.loader.impl.resource.repository.SimpleResourcePackRepository; + +@Mixin(TextureManager.class) +public class TextureManagerMixin implements ResourceReloadListener { + + @Unique + private SimpleResourcePackRepository packRepository; + @Unique + private SimpleReloadableResourceManager resourceManager; + + @Unique + private boolean vanillaReloading; + @Unique + private boolean reloading; + + @Shadow + private void reload() { } + + @Inject( + method = "", + at = @At( + value = "FIELD", + target = "Lnet/minecraft/client/render/texture/TextureManager;texturePacks:Lnet/minecraft/client/resource/pack/TexturePacks;", + ordinal = 0 + ) + ) + private void osl$resource_loader$initResourceManager(CallbackInfo ci) { + this.packRepository = SimpleResourcePackRepository.client(); + this.resourceManager = SimpleReloadableResourceManager.client(); + + // ensure the selected packs have been applied + this.resourceManager.reload(this.packRepository.openSelectedPacks()); + + // let this class act as the texture reloader + this.resourceManager.addReloader(this); + + this.resourceManager.init(); + } + + @Inject( + method = "reload", + cancellable = true, + at = @At( + value = "HEAD" + ) + ) + private void osl$resource_loader$startReload(CallbackInfo ci) { + if (!this.vanillaReloading) { + this.vanillaReloading = true; + + if (!this.reloading) { + this.resourceManager.reload(this.packRepository.openSelectedPacks()); + + // cancel this call as the resource manager will trigger + // another recursive call through this.resourcesReloaded + ci.cancel(); + } + } + } + + @Inject( + method = "reload", + at = @At( + value = "TAIL" + ) + ) + private void osl$resource_loader$endReload(CallbackInfo ci) { + this.vanillaReloading = false; + } + + @Override + public void resourcesReloaded(ResourceManager manager) { + this.reloading = true; + this.reload(); + this.reloading = false; + } +} diff --git a/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TexturePackListMixin.java b/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TexturePackListMixin.java new file mode 100644 index 00000000..0d8c9832 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TexturePackListMixin.java @@ -0,0 +1,27 @@ +package net.ornithemc.osl.resource.loader.impl.mixin.client; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Pseudo; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import net.minecraft.client.resource.pack.TexturePack; +import net.minecraft.client.resource.pack.TexturePacks; + +import net.ornithemc.osl.resource.loader.impl.access.TexturePacksAccess; + +@Pseudo // b1.3+ +@Mixin(targets = "net/minecraft/client/gui/screen/TexturePacksScreen$TexturePackList") +public class TexturePackListMixin { + + @Redirect( + method = "isEntrySelected", + at = @At( + value = "FIELD", + target = "Lnet/minecraft/client/resource/pack/TexturePacks;selected:Lnet/minecraft/client/resource/pack/TexturePack;" + ) + ) + private TexturePack osl$resource_loader$getSelectedPack(TexturePacks texturePacks) { + return ((TexturePacksAccess) texturePacks).osl$resource_loader$getActuallySelected(); + } +} diff --git a/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TexturePackMixin.java b/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TexturePackMixin.java new file mode 100644 index 00000000..50938c0f --- /dev/null +++ b/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TexturePackMixin.java @@ -0,0 +1,36 @@ +package net.ornithemc.osl.resource.loader.impl.mixin.client; + +import java.io.InputStream; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Pseudo; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import net.minecraft.client.resource.pack.BuiltInTexturePack; +import net.minecraft.client.resource.pack.DirectoryTexturePack; +import net.minecraft.client.resource.pack.TexturePack; +import net.minecraft.client.resource.pack.ZippedTexturePack; + +@Pseudo // directory packs were added in 12w08a +@Mixin({TexturePack.class, DirectoryTexturePack.class, ZippedTexturePack.class}) +public class TexturePackMixin { + + @Inject( + method = "getResource", + cancellable = true, + at = @At( + value = "INVOKE", + target = "Ljava/lang/Class;getResourceAsStream(Ljava/lang/String;)Ljava/io/InputStream;" + ) + ) + private void osl$resource_loader$getResource(String path, CallbackInfoReturnable cir) { + // the call to Class::getResourceAsStream is used as a fallback + // in case custom texture packs do not contain a resource + // we handle this by layering multiple packs + if (!((Object) this instanceof BuiltInTexturePack)) { + cir.setReturnValue(null); + } + } +} diff --git a/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TexturePacksMixin.java b/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TexturePacksMixin.java new file mode 100644 index 00000000..da3db47e --- /dev/null +++ b/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TexturePacksMixin.java @@ -0,0 +1,205 @@ +package net.ornithemc.osl.resource.loader.impl.mixin.client; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import net.minecraft.client.resource.pack.TexturePack; +import net.minecraft.client.resource.pack.TexturePacks; + +import net.ornithemc.osl.resource.loader.api.resource.manager.ResourceManager; +import net.ornithemc.osl.resource.loader.api.resource.pack.PackPosition; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePack; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackRepository; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackSummary; +import net.ornithemc.osl.resource.loader.impl.ClientResourcePacks; +import net.ornithemc.osl.resource.loader.impl.ResourceManagerAdapter; +import net.ornithemc.osl.resource.loader.impl.WrappedTexturePack; +import net.ornithemc.osl.resource.loader.impl.access.TexturePacksAccess; +import net.ornithemc.osl.resource.loader.impl.resource.repository.BundledModResourcePacks; +import net.ornithemc.osl.resource.loader.impl.resource.repository.SimpleResourcePackRepository; + +@Mixin(TexturePacks.class) +public class TexturePacksMixin implements TexturePacksAccess, ResourcePackRepository.Source { + + @Shadow + private List availablePacks; + @Shadow + private Map availablePacksByKey; + @Shadow + private TexturePack defaultPack; + @Shadow + private TexturePack selected; + + @Unique + private SimpleResourcePackRepository resourcePacks; + @Unique + private TexturePack resourceManager; + + @Unique + private TexturePack actuallySelected; + @Unique + private boolean vanillaReloading; + @Unique + private boolean reloading; + + @Shadow + private void reload() { } + + @Inject( + method = "", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/resource/pack/TexturePacks;reload()V" + ) + ) + private void osl$resource_loader$initResourcePackRepository(CallbackInfo ci) { + this.resourcePacks = SimpleResourcePackRepository.client(); + // wrap the ResourceManager into a texture pack, and set this as selected + // this way we don't have to redirect every call to TexturePack::getResource! + this.resourceManager = new ResourceManagerAdapter(ResourceManager.client()); + + this.resourcePacks.setCallbacks(null, this::selectionChanged); + + this.resourcePacks.addSource(new ClientResourcePacks(this.defaultPack)); + this.resourcePacks.addSource(new BundledModResourcePacks()); + this.resourcePacks.addSource(this); // texturepacks/ directory source + + this.resourcePacks.init(); + } + + @Inject( + method = "", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/resource/pack/TexturePack;open()V" + ) + ) + private void osl$resource_loader$initSelected(CallbackInfo ci) { + if (!this.availablePacks.contains(this.actuallySelected)) { + this.selectPack(null); + } + } + + @Inject( + method = "select", + cancellable = true, + at = @At( + value = "HEAD" + ) + ) + private void osl$resource_loader$select(TexturePack pack, CallbackInfoReturnable cir) { + if (pack == this.actuallySelected) { + cir.setReturnValue(false); + } + } + + @Inject( + method = "select", + at = @At( + value = "RETURN", + ordinal = 1 // only on texture pack change + ) + ) + private void osl$resource_loader$selected(TexturePack pack, CallbackInfoReturnable cir) { + this.selectPack(this.selected); + } + + @Inject( + method = "reload", + cancellable = true, + at = @At( + value = "HEAD" + ) + ) + private void osl$resource_loader$startReload(CallbackInfo ci) { + if (!this.vanillaReloading) { + this.vanillaReloading = true; + + if (!this.reloading) { + this.resourcePacks.reload(); + + // cancel this call as the pack repository will trigger + // another recursive call through this.loadResourcePacks + ci.cancel(); + } + } + } + + @Inject( + method = "reload", + at = @At( + value = "TAIL" + ) + ) + private void osl$resource_loader$endReload(CallbackInfo ci) { + this.vanillaReloading = false; + + if (this.actuallySelected != this.resourceManager) { + this.actuallySelected = this.selected; + this.selected = this.resourceManager; + } + } + + @Override + public void loadResourcePacks(Consumer consumer) { + this.reloading = true; + this.reload(); + this.reloading = false; + + for (TexturePack pack : this.availablePacks) { + if (pack != this.defaultPack) { + ResourcePack resourcePack = new WrappedTexturePack(pack); + ResourcePackSummary summary = ResourcePackSummary.create( + resourcePack, + false, + false, + PackPosition.TOP + ); + + if (summary != null) { + consumer.accept(summary); + } + } + } + } + + @Override + public TexturePack osl$resource_loader$getActuallySelected() { + return this.actuallySelected; + } + + @Unique + private void selectPack(TexturePack pack) { + if (pack == null || pack == this.defaultPack) { + this.resourcePacks.setSelectedPacks(Collections.emptyList()); + } else { + this.resourcePacks.setSelectedPacks(Collections.singletonList(WrappedTexturePack.getId(pack))); + } + + this.actuallySelected = pack; + this.selected = this.resourceManager; + } + + @Unique + private void selectionChanged() { + this.actuallySelected = this.defaultPack; + + for (ResourcePackSummary summary : this.resourcePacks.getSelectedPacks()) { + TexturePack pack = this.availablePacksByKey.get(summary.getId()); + + if (pack != null) { + this.actuallySelected = pack; + } + } + } +} diff --git a/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TexturePacksScreenMixin.java b/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TexturePacksScreenMixin.java new file mode 100644 index 00000000..f806a8e4 --- /dev/null +++ b/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TexturePacksScreenMixin.java @@ -0,0 +1,27 @@ +package net.ornithemc.osl.resource.loader.impl.mixin.client; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import net.minecraft.client.gui.screen.TexturePacksScreen; +import net.minecraft.client.resource.pack.TexturePack; +import net.minecraft.client.resource.pack.TexturePacks; + +import net.ornithemc.osl.resource.loader.impl.access.TexturePacksAccess; + +@Mixin(TexturePacksScreen.class) +public class TexturePacksScreenMixin { + + @Redirect( + method = "render", + require = 0, // b1.2- + at = @At( + value = "FIELD", + target = "Lnet/minecraft/client/resource/pack/TexturePacks;selected:Lnet/minecraft/client/resource/pack/TexturePack;" + ) + ) + private TexturePack osl$resource_loader$getSelectedPack(TexturePacks texturePacks) { + return ((TexturePacksAccess) texturePacks).osl$resource_loader$getActuallySelected(); + } +} diff --git a/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/resources/fabric.mod.json b/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/src/main/resources/fabric.mod.json similarity index 70% rename from libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/resources/fabric.mod.json rename to libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/src/main/resources/fabric.mod.json index 87a498df..938a3b65 100644 --- a/libraries/resource-loader/resource-loader-mc19w08a-mc1.14.4/src/main/resources/fabric.mod.json +++ b/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/src/main/resources/fabric.mod.json @@ -1,15 +1,17 @@ { "schemaVersion": 1, "id": "osl-resource-loader", - "version": "0.6.1+mc19w08a-mc1.14.4", + "version": "0.6.1+mca1.2.2-mc1.2.5", "environment": "*", "mixins": [ "osl.resource-loader.mixins.json" ], "depends": { "fabricloader": "\u003e\u003d0.18.0", - "minecraft": "\u003e\u003d1.14-alpha.19.8.a \u003c\u003d1.14.4", - "osl-core": "\u003e\u003d0.7.0" + "minecraft": "\u003e\u003d1.0.0-alpha.2.2 \u003c\u003d1.2.5", + "osl-core": "\u003e\u003d0.7.0", + "osl-executors": "\u003e\u003d0.1.0-", + "osl-text-components": "\u003e\u003d0.1.0-" }, "name": "OSL Resource Loader", "description": "Resource loading API and events.", diff --git a/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/src/main/resources/osl.resource-loader.mixins.json b/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/src/main/resources/osl.resource-loader.mixins.json new file mode 100644 index 00000000..4622511c --- /dev/null +++ b/libraries/resource-loader/resource-loader-mca1.2.2-mc1.2.5/src/main/resources/osl.resource-loader.mixins.json @@ -0,0 +1,20 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "net.ornithemc.osl.resource.loader.impl.mixin", + "compatibilityLevel": "JAVA_8", + "mixins": [ + ], + "client": [ + "client.TextureManagerMixin", + "client.TexturePackListMixin", + "client.TexturePackMixin", + "client.TexturePacksMixin", + "client.TexturePacksScreenMixin" + ], + "server": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/libraries/resource-loader/resource-loader-mca1.2.2-mc11w48a/gradle.properties b/libraries/resource-loader/resource-loader-mca1.2.2-mc11w48a/gradle.properties deleted file mode 100644 index decaf65f..00000000 --- a/libraries/resource-loader/resource-loader-mca1.2.2-mc11w48a/gradle.properties +++ /dev/null @@ -1,8 +0,0 @@ -environment = client -min_mc_version = a1.2.2 -max_mc_version = 11w48a -minecraft_dependency = >=1.0.0-alpha.2.2 <=1.1-alpha.11.48.a - -minecraft_version = 11w48a -feather_build = 1 -client_nests_build = 11 diff --git a/libraries/resource-loader/resource-loader-mca1.2.2-mc11w48a/src/main/java/net/ornithemc/osl/resource/loader/api/ModTexturePack.java b/libraries/resource-loader/resource-loader-mca1.2.2-mc11w48a/src/main/java/net/ornithemc/osl/resource/loader/api/ModTexturePack.java deleted file mode 100644 index 1e9f0960..00000000 --- a/libraries/resource-loader/resource-loader-mca1.2.2-mc11w48a/src/main/java/net/ornithemc/osl/resource/loader/api/ModTexturePack.java +++ /dev/null @@ -1,11 +0,0 @@ -package net.ornithemc.osl.resource.loader.api; - -import net.fabricmc.loader.api.metadata.ModMetadata; - -import net.minecraft.client.resource.pack.TexturePack; - -public abstract class ModTexturePack extends TexturePack { - - public abstract ModMetadata getModMetadata(); - -} diff --git a/libraries/resource-loader/resource-loader-mca1.2.2-mc11w48a/src/main/java/net/ornithemc/osl/resource/loader/api/ResourceLoaderEvents.java b/libraries/resource-loader/resource-loader-mca1.2.2-mc11w48a/src/main/java/net/ornithemc/osl/resource/loader/api/ResourceLoaderEvents.java deleted file mode 100644 index b3fc8b24..00000000 --- a/libraries/resource-loader/resource-loader-mca1.2.2-mc11w48a/src/main/java/net/ornithemc/osl/resource/loader/api/ResourceLoaderEvents.java +++ /dev/null @@ -1,30 +0,0 @@ -package net.ornithemc.osl.resource.loader.api; - -import java.util.function.Consumer; - -import net.ornithemc.osl.core.api.events.Event; - -/** - * Events related to resource loading. - */ -public class ResourceLoaderEvents { - - /** - * This event is invoked upon game start-up, giving mod developers the - * opportunity to register custom built-in texture packs. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ResourceLoaderEvents.ADD_DEFAULT_TEXTURE_PACKS.register(adder -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event>> ADD_DEFAULT_TEXTURE_PACKS = Event.consumer(); - -} diff --git a/libraries/resource-loader/resource-loader-mca1.2.2-mc11w48a/src/main/java/net/ornithemc/osl/resource/loader/impl/BuiltInModTexturePack.java b/libraries/resource-loader/resource-loader-mca1.2.2-mc11w48a/src/main/java/net/ornithemc/osl/resource/loader/impl/BuiltInModTexturePack.java deleted file mode 100644 index a1e15829..00000000 --- a/libraries/resource-loader/resource-loader-mca1.2.2-mc11w48a/src/main/java/net/ornithemc/osl/resource/loader/impl/BuiltInModTexturePack.java +++ /dev/null @@ -1,84 +0,0 @@ -package net.ornithemc.osl.resource.loader.impl; - -import java.io.IOException; -import java.io.InputStream; -import java.io.UncheckedIOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; - -import net.fabricmc.loader.api.ModContainer; -import net.fabricmc.loader.api.metadata.ModMetadata; - -import net.minecraft.client.resource.pack.TexturePack; - -import net.ornithemc.osl.resource.loader.api.ModTexturePack; - -public class BuiltInModTexturePack extends ModTexturePack { - - private final ModContainer mod; - - private final List roots; - - public BuiltInModTexturePack(ModContainer mod) { - super(); - - this.key = mod.getMetadata().getId(); - this.name = mod.getMetadata().getName(); - - this.mod = mod; - - this.roots = this.mod.getRootPaths(); - } - - @Override - public InputStream getResource(String location) { - Path path = getPath(location); - - if (path == null || !Files.exists(path)) { - if ("/pack.png".equals(location) || "/pack.txt".equals(location)) { - return TexturePack.class.getResourceAsStream(location); - } - - return null; - } - - // a bit of a hack to re-throw a checked exception - // because proguard stripped the exceptions off this method - try { - return Files.newInputStream(path); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - -// @Override - public boolean hasResource(String location) { - Path path = getPath(location); - return path != null && Files.exists(path); - } - - @Override - public ModMetadata getModMetadata() { - return mod.getMetadata(); - } - - private Path getPath(String location) { - // the game accesses all resources with a leading '/' - location = location.substring(1); - - if (!"pack.png".equals(location) && !"pack.txt".equals(location)) { - for (Path root : roots) { - String separator = root.getFileSystem().getSeparator(); - String pathName = location.replace("/", separator); - Path path = root.resolve(pathName); - - if (Files.exists(path)) { - return path; - } - } - } - - return null; - } -} diff --git a/libraries/resource-loader/resource-loader-mca1.2.2-mc11w48a/src/main/java/net/ornithemc/osl/resource/loader/impl/ResourceLoader.java b/libraries/resource-loader/resource-loader-mca1.2.2-mc11w48a/src/main/java/net/ornithemc/osl/resource/loader/impl/ResourceLoader.java deleted file mode 100644 index 8c1837b4..00000000 --- a/libraries/resource-loader/resource-loader-mca1.2.2-mc11w48a/src/main/java/net/ornithemc/osl/resource/loader/impl/ResourceLoader.java +++ /dev/null @@ -1,43 +0,0 @@ -package net.ornithemc.osl.resource.loader.impl; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import net.fabricmc.loader.api.FabricLoader; -import net.fabricmc.loader.api.ModContainer; - -import net.ornithemc.osl.resource.loader.api.ModTexturePack; -import net.ornithemc.osl.resource.loader.api.ResourceLoaderEvents; - -public class ResourceLoader { - - public static final Logger LOGGER = LogManager.getLogger("OSL|Resource Loader"); - - private static List DEFAULT_MOD_TEXTURE_PACKS; - - public static void resetDefaultTexturePacks() { - DEFAULT_MOD_TEXTURE_PACKS = null; - } - - public static List getDefaultModResourcePacks() { - if (DEFAULT_MOD_TEXTURE_PACKS == null) { - DEFAULT_MOD_TEXTURE_PACKS = new ArrayList<>(); - - for (ModContainer mod : FabricLoader.getInstance().getAllMods()) { - if ("builtin".equals(mod.getMetadata().getType())) { - continue; - } - - DEFAULT_MOD_TEXTURE_PACKS.add(new BuiltInModTexturePack(mod)); - } - - ResourceLoaderEvents.ADD_DEFAULT_TEXTURE_PACKS.invoker().accept(DEFAULT_MOD_TEXTURE_PACKS::add); - } - - return Collections.unmodifiableList(DEFAULT_MOD_TEXTURE_PACKS); - } -} diff --git a/libraries/resource-loader/resource-loader-mca1.2.2-mc11w48a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/LanguageMixin.java b/libraries/resource-loader/resource-loader-mca1.2.2-mc11w48a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/LanguageMixin.java deleted file mode 100644 index 737976a8..00000000 --- a/libraries/resource-loader/resource-loader-mca1.2.2-mc11w48a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/LanguageMixin.java +++ /dev/null @@ -1,84 +0,0 @@ -package net.ornithemc.osl.resource.loader.impl.mixin.client; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.Locale; -import java.util.Properties; - -import org.quiltmc.parsers.json.JsonReader; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import net.fabricmc.loader.api.metadata.ModMetadata; - -import net.minecraft.locale.Language; - -import net.ornithemc.osl.resource.loader.api.ModTexturePack; -import net.ornithemc.osl.resource.loader.impl.ResourceLoader; - -@Mixin(Language.class) -public class LanguageMixin { - - @Shadow - private Properties translations; - - @Inject( - method = "", - at = @At( - value = "TAIL" - ) - ) - private void osl$resource_loader$loadModTranslations(CallbackInfo ci) throws IOException { - String lang = "en_US"; - String path = "/assets/%s/lang/%s.%s"; - - for (ModTexturePack pack : ResourceLoader.getDefaultModResourcePacks()) { - ModMetadata mod = pack.getModMetadata(); - - loadTranslationsJson(translations, pack.getResource(String.format(path, mod.getId(), lang, "json"))); - loadTranslationsJson(translations, pack.getResource(String.format(path, mod.getId(), lang.toLowerCase(Locale.ROOT), "json"))); - loadTranslationsLang(translations, pack.getResource(String.format(path, mod.getId(), lang, "lang"))); - loadTranslationsLang(translations, pack.getResource(String.format(path, mod.getId(), lang.toLowerCase(Locale.ROOT), "lang"))); - } - } - - @Unique - private void loadTranslationsJson(Properties translations, InputStream is) throws IOException { - if (is != null){ - try (JsonReader reader = JsonReader.json(new InputStreamReader(is))) { - reader.beginObject(); - while (reader.hasNext()) { - translations.setProperty(reader.nextName(), reader.nextString()); - } - reader.endObject(); - } - } - } - - @Unique - private void loadTranslationsLang(Properties translations, InputStream is) throws IOException { - if (is != null){ - try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) { - String line; - while ((line = br.readLine()) != null) { - line = line.trim(); - if (line.isEmpty() || line.startsWith("#")) { - continue; - } - String[] args = line.split("=", 2); - if (args.length != 2) { - continue; - } - translations.setProperty(args[0], args[1]); - } - } - } - } -} diff --git a/libraries/resource-loader/resource-loader-mca1.2.2-mc11w48a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TexturePackMixin.java b/libraries/resource-loader/resource-loader-mca1.2.2-mc11w48a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TexturePackMixin.java deleted file mode 100644 index 865a51a1..00000000 --- a/libraries/resource-loader/resource-loader-mca1.2.2-mc11w48a/src/main/java/net/ornithemc/osl/resource/loader/impl/mixin/client/TexturePackMixin.java +++ /dev/null @@ -1,54 +0,0 @@ -package net.ornithemc.osl.resource.loader.impl.mixin.client; - -import java.io.InputStream; -import java.util.LinkedHashSet; -import java.util.Set; - -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; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -import net.minecraft.client.resource.pack.TexturePack; - -import net.ornithemc.osl.resource.loader.api.ModTexturePack; -import net.ornithemc.osl.resource.loader.impl.ResourceLoader; - -@Mixin(TexturePack.class) -public class TexturePackMixin { - - private final Set modTextures = new LinkedHashSet<>(); - - @Inject( - method = "()V", - at = @At( - value = "TAIL" - ) - ) - private void osl$resource_loader$init(CallbackInfo ci) { - if (!((TexturePack)(Object)this instanceof ModTexturePack)) { - modTextures.addAll(ResourceLoader.getDefaultModResourcePacks()); - } - } - - @Inject( - method = "getResource(Ljava/lang/String;)Ljava/io/InputStream;", - cancellable = true, - at = @At( - value = "HEAD" - ) - ) - private void osl$resource_loader$getResource(String path, CallbackInfoReturnable cir) { - for (ModTexturePack textures : modTextures) { - try { - InputStream resource = textures.getResource(path); - - if (resource != null) { - cir.setReturnValue(resource); - } - } catch (Exception e) { - } - } - } -} diff --git a/libraries/resource-loader/resource-loader-mca1.2.2-mc11w48a/src/main/resources/fabric.mod.json b/libraries/resource-loader/resource-loader-mca1.2.2-mc11w48a/src/main/resources/fabric.mod.json deleted file mode 100644 index 4ea3b3b6..00000000 --- a/libraries/resource-loader/resource-loader-mca1.2.2-mc11w48a/src/main/resources/fabric.mod.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "schemaVersion": 1, - "id": "osl-resource-loader", - "version": "0.6.1+mca1.2.2-mc11w48a", - "environment": "client", - "mixins": [ - "osl.resource-loader.mixins.json" - ], - "depends": { - "fabricloader": "\u003e\u003d0.18.0", - "minecraft": "\u003e\u003d1.0.0-alpha.2.2 \u003c\u003d1.1-alpha.11.48.a", - "osl-core": "\u003e\u003d0.7.0" - }, - "name": "OSL Resource Loader", - "description": "Resource loading API and events.", - "authors": [ - "OrnitheMC" - ], - "contact": { - "homepage": "https://ornithemc.net/", - "issues": "https://github.com/OrnitheMC/ornithe-standard-libraries/issues", - "sources": "https://github.com/OrnitheMC/ornithe-standard-libraries" - }, - "license": "Apache-2.0" -} \ No newline at end of file diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/client/ClientResourceLoaderEvents.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/client/ClientResourceLoaderEvents.java new file mode 100644 index 00000000..16e789c6 --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/client/ClientResourceLoaderEvents.java @@ -0,0 +1,118 @@ +package net.ornithemc.osl.resource.loader.api.client; + +import java.util.function.Consumer; + +import net.ornithemc.osl.core.api.events.Event; +import net.ornithemc.osl.resource.loader.api.resource.manager.ReloadableResourceManager; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackRepository; + +/** + * Events related to client side resource loading. + */ +public final class ClientResourceLoaderEvents { + + /** + * This event is invoked when the ResourcePackRepository is initialized. + * Custom resource pack sources should be registered here. + * + *

+ * Callbacks to this event should be registered in your mod's entrypoint, + * and can be done as follows: + * + *

+	 * {@code
+	 * ClientResourceLoaderEvents.INIT_RESOURCE_PACK_REPOSITORY.register(packRepository -> {
+	 * 	...
+	 * });
+	 * }
+	 * 
+ */ + public static final Event> INIT_RESOURCE_PACK_REPOSITORY = Event.consumer(); + + /** + * This event is invoked when the ResourceManager is initialized. + * Custom resource reloaders should be registered here. + * + *

+ * Callbacks to this event should be registered in your mod's entrypoint, + * and can be done as follows: + * + *

+	 * {@code
+	 * ClientResourceLoaderEvents.INIT_RESOURCE_MANAGER.register(resourceManager -> {
+	 * 	...
+	 * });
+	 * }
+	 * 
+ */ + public static final Event> INIT_RESOURCE_MANAGER = Event.consumer(); + + /** + * This event is invoked before resource packs are reloaded. + * + *

+ * Callbacks to this event should be registered in your mod's entrypoint, + * and can be done as follows: + * + *

+	 * {@code
+	 * ClientResourceLoaderEvents.START_RESOURCE_PACKS_RELOAD.register(() -> {
+	 * 	...
+	 * });
+	 * }
+	 * 
+ */ + public static final Event START_RESOURCE_PACKS_RELOAD = Event.runnable(); + + /** + * This event is invoked after resource packs are reloaded. + * + *

+ * Callbacks to this event should be registered in your mod's entrypoint, + * and can be done as follows: + * + *

+	 * {@code
+	 * ClientResourceLoaderEvents.END_RESOURCE_PACKS_RELOAD.register(() -> {
+	 * 	...
+	 * });
+	 * }
+	 * 
+ */ + public static final Event END_RESOURCE_PACKS_RELOAD = Event.runnable(); + + /** + * This event is invoked before resources are reloaded. + * + *

+ * Callbacks to this event should be registered in your mod's entrypoint, + * and can be done as follows: + * + *

+	 * {@code
+	 * ClientResourceLoaderEvents.START_RESOURCE_RELOAD.register(() -> {
+	 * 	...
+	 * });
+	 * }
+	 * 
+ */ + public static final Event START_RESOURCE_RELOAD = Event.runnable(); + + /** + * This event is invoked after resources are reloaded. + * + *

+ * Callbacks to this event should be registered in your mod's entrypoint, + * and can be done as follows: + * + *

+	 * {@code
+	 * ClientResourceLoaderEvents.END_RESOURCE_RELOAD.register(() -> {
+	 * 	...
+	 * });
+	 * }
+	 * 
+ */ + public static final Event END_RESOURCE_RELOAD = Event.runnable(); + +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/Resource.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/Resource.java new file mode 100644 index 00000000..4c2c5e1c --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/Resource.java @@ -0,0 +1,69 @@ +package net.ornithemc.osl.resource.loader.api.resource; + +import java.io.BufferedReader; +import java.io.Closeable; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.function.IOSupplier; + +/** + * A game resource. + */ +public interface Resource extends Closeable { + + /** + * @return a resource supplier for the file at the given path. + */ + static IOSupplier supplier(Path path) { + return () -> Files.newInputStream(path); + } + + /** + * Gives the name of the source where this resource was found, + * most likely it is the id of a resource pack. + * + * @return the name of the source where this resource was found. + */ + String sourceName(); + + /** + * Gives the location of this resource. The location is given as + * a namespaced path. The path is not resolved directly from the + * root of resource packs, but from the namespaced directory for + * the given resource type. + * + * @return the location of this resource. + * @see ResourcePath + */ + NamespacedIdentifier location(); + + /** + * @return this resource as an {@linkplain InputStream}. + * @throws IOException if an error occurs when opening this resource. + */ + InputStream open() throws IOException; + + /** + * Opens this resource as a UTF-8 text file. + * + * @return this resource as a {@linkplain BufferedReader}. + * @throws IOException if an error occurs when opening this resource. + */ + BufferedReader openAsReader() throws IOException; + + /** + * @return the metadata of this resource. + * @throws IOException if an error occurs when opening the metadata. + */ + ResourceMetadata metadata() throws IOException; + + /** + * @return whether this resource has metadata. + */ + boolean hasMetadata(); + +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/ResourceMetadata.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/ResourceMetadata.java new file mode 100644 index 00000000..d107004a --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/ResourceMetadata.java @@ -0,0 +1,88 @@ +package net.ornithemc.osl.resource.loader.api.resource; + +import java.io.InputStream; + +import com.google.gson.JsonObject; + +import net.ornithemc.osl.core.api.util.function.IOSupplier; +import net.ornithemc.osl.resource.loader.api.resource.ResourceMetadata.Section.Serializer; +import net.ornithemc.osl.resource.loader.impl.resource.JsonResourceMetadata; +import net.ornithemc.osl.resource.loader.impl.resource.ResourceMetadataSection; + +/** + * Metadata of a {@linkplain Resource} + */ +public interface ResourceMetadata { + + /** + * The file extension for resource metadata files. + */ + String FILE_EXTENSION = ".mcmeta"; + + ResourceMetadata EMPTY = new ResourceMetadata() { + + @Override + public T getSection(String name, Serializer serializer) { + return null; + } + }; + IOSupplier EMPTY_SUPPLIER = () -> EMPTY; + + /** + * @return a supplier for the resource metadata parsed from the given {@linkplain InputStream}. + */ + static IOSupplier supplier(IOSupplier inputStream) { + return () -> JsonResourceMetadata.fromInputStream(inputStream); + } + + /** + * Parses the resource metadata section of the given name with the given serializer. + * + * @return the resource metadata section of the given type. + */ + default T getSection(Section section) { + return this.getSection(section.name(), section.serializer()); + } + + /** + * Parses the resource metadata section of the given name with the given serializer. + * + * @return the resource metadata section of the given type. + */ + T getSection(String name, Section.Serializer serializer); + + /** + * A section type of resource metadata. + */ + interface Section { + + /** + * @return the constructed section type with the given name and serializer. + */ + static Section of(String name, Serializer serializer) { + return new ResourceMetadataSection<>(name, serializer); + } + + /** + * @return the name of this section. + */ + String name(); + + /** + * @return the serializer of this section. + */ + Serializer serializer(); + + /** + * A JSON serializer for a resource metadata section. + */ + interface Serializer { + + /** + * @return the resource metadata section parsed from the given JSON object. + */ + T deserialize(JsonObject json); + + } + } +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/ResourcePath.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/ResourcePath.java new file mode 100644 index 00000000..c328417e --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/ResourcePath.java @@ -0,0 +1,76 @@ +package net.ornithemc.osl.resource.loader.api.resource; + +import java.nio.file.Path; +import java.nio.file.Paths; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; + +/** + * Utilities for getting file paths of resources. + */ +public final class ResourcePath { + + /** + * Takes the given resource path and returns it as a relative path. + * + * @return the resource path. + */ + public static String nameOf(String path) { + if (path.charAt(0) == '/') { + path = path.substring(1); + } + + return path; + } + + /** + * @return the resource path for the given resource type and location. + */ + public static String nameOf(ResourceType type, NamespacedIdentifier location) { + return String.format("%s/%s/%s", type.directory(), location.namespace(), location.identifier()); + } + + /** + * Resolves the relative resource path from the given path name. + * + * @return the relative {@linkplain Path} to the resource. + */ + public static Path of(String path) { + return of(Paths.get("."), path); + } + + /** + * Resolves the relative resource path from the given resource type and location. + * + * @return the {relative @linkplain Path} to the resource. + */ + public static Path of(ResourceType type, NamespacedIdentifier location) { + return of(Paths.get("."), type, location); + } + + /** + * Resolves the resource path from the given root and path name. + * + * @return the {@linkplain Path} to the resource. + */ + public static Path of(Path root, String path) { + String separator = root.getFileSystem().getSeparator(); + String pathName = nameOf(path).replace("/", separator); + Path p = root.resolve(pathName).normalize(); + + return p; + } + + /** + * Resolves the resource path from the given root and resource type and location. + * + * @return the {@linkplain Path} to the resource. + */ + public static Path of(Path root, ResourceType type, NamespacedIdentifier location) { + String separator = root.getFileSystem().getSeparator(); + String pathName = nameOf(type, location).replace("/", separator); + Path p = root.resolve(pathName).normalize(); + + return p; + } +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/ResourceType.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/ResourceType.java new file mode 100644 index 00000000..dff81ec5 --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/ResourceType.java @@ -0,0 +1,34 @@ +package net.ornithemc.osl.resource.loader.api.resource; + +/** + * Each resource manager deals with exactly one type of resources. + * Resources of a given type have their own directory in a resource + * pack. + */ +public enum ResourceType { + + /** + * Client assets are things like textures, sounds, and language files. + */ + CLIENT_ASSETS("assets"), + /** + * Server data are things like loot tables, recipes, and command functions. + */ + SERVER_DATA("data"); + + /** + * The directory in a resource pack for this type of resources. + */ + private final String directory; + + private ResourceType(String directory) { + this.directory = directory; + } + + /** + * @return the directory in a resource pack for this type of resources. + */ + public String directory() { + return this.directory; + } +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/manager/ReloadableResourceManager.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/manager/ReloadableResourceManager.java new file mode 100644 index 00000000..d3d7bd4f --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/manager/ReloadableResourceManager.java @@ -0,0 +1,34 @@ +package net.ornithemc.osl.resource.loader.api.resource.manager; + +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; + +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePack; +import net.ornithemc.osl.resource.loader.api.resource.reload.ResourceReload; +import net.ornithemc.osl.resource.loader.api.resource.reload.ResourceReloader; + +/** + * A resource manager that can be reloaded. + */ +public interface ReloadableResourceManager extends ResourceManager { + + /** + * Adds a reloader to this resource manager that will be triggered on every resource reload. + * + * @param reloader + */ + void addReloader(ResourceReloader reloader); + + /** + * Reload all resources, blocking the current thread until finished. + */ + void reload(List packs); + + /** + * Initiate a full resource reload, loading resources on the background thread + * and then applying the newly loaded resources on the main thread executor. + */ + ResourceReload startReload(List packs, Executor backgroundExecutor, Executor mainThreadExecutor, CompletableFuture initialTask); + +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/manager/ResourceManager.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/manager/ResourceManager.java new file mode 100644 index 00000000..b8d9c819 --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/manager/ResourceManager.java @@ -0,0 +1,155 @@ +package net.ornithemc.osl.resource.loader.api.resource.manager; + +import java.io.IOException; +import java.io.InputStream; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.Predicate; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.resource.loader.api.resource.Resource; +import net.ornithemc.osl.resource.loader.impl.resource.manager.SimpleReloadableResourceManager; + +/** + * The resource manager is the access layer for the game's resources. + */ +public interface ResourceManager { + + /** + * @return the resource manager for the Minecraft client. + */ + static ReloadableResourceManager client() { + return SimpleReloadableResourceManager.client(); + } + + /** + * @return the resource manager for the Minecraft server. + */ + static ReloadableResourceManager server() { + return SimpleReloadableResourceManager.server(); + } + + /** + * Checks whether the resource at the given path exists. + *

+ * NOTE: this method expects a direct file path to be given, + * rather than a namespaced path. For this reason, this method + * should only be used to access resources in 1.5.2 and below, + * or special root resources such as pack.mcmeta and pack.png. + * + * @param path the path to the resource. + * @return whether the resource exists. + */ + boolean hasResource(String path); + + /** + * Returns the top resource at the given path. + *

+ * If multiple resource packs contain the resource at the given + * path, the resource from the top-most resource pack is picked. + *

+ * NOTE: this method expects a direct file path to be given, + * rather than a namespaced path. For this reason, this method + * should only be used to access resources in 1.5.2 and below, + * or special root resources such as pack.mcmeta and pack.png. + * + * @param path the path to the resource. + * @return the top resource at the given path. + * @throws IOException if the resource could not be found or read. + */ + InputStream getResource(String path) throws IOException; + + /** + * Returns all resources at the given path. + *

+ * If multiple resource packs contain the resource at the given + * path, the resources are listed in resource pack order. This + * means the resource from the top resource pack appears at the + * top of the stack (i.e. last in the list). + *

+ * NOTE: this method expects a direct file path to be given, + * rather than a namespaced path. For this reason, this method + * should only be used to access resources in 1.5.2 and below, + * or special root resources such as pack.mcmeta and pack.png. + * + * @param path the path to the resources. + * @return the resources at the given path. + * @throws IOException if the resources could not be found or read. + */ + List getResourceStack(String path) throws IOException; + + /** + * @return all namespaces available from the loaded resource packs. + */ + Set getNamespaces(); + + /** + * Checks whether the resource at the given location exists. + * + * @param location the location of the resource. + * @return whether the resource exists. + */ + boolean hasResource(NamespacedIdentifier location); + + /** + * Returns the top resource at the given location. + *

+ * If multiple resource packs contain the resource at the given + * location, the resource from the top-most resource pack is picked. + *

+ * The resource is returned as an {@linkplain Optional} and may + * be empty if the resource could not be found. + * + * @param location the location of the resource. + * @return the top resource at the given location. + */ + Optional getResource(NamespacedIdentifier location); + + /** + * Returns all resources at the given location. + *

+ * If multiple resource packs contain the resource at the given + * location, the resources are listed in resource pack order. This + * means the resource from the top resource pack appears at the + * top of the stack (i.e. last in the list). + * + * @param location the location of the resources. + * @return the resources at the given location. + */ + List getResourceStack(NamespacedIdentifier location); + + /** + * Gives a map of all resources that could be found in the given + * directory or one of its sub-directories (recursively), that + * match the given filter. + *

+ * For each location, only the top resource is given. If multiple + * resource packs contain the resource at a given location, the + * resource from the top-most resource pack is picked. + * + * @param directory the directory in which to start looking for resources. + * @param filter the filter that resource locations must match. + * @return a map of found resource locations to corresponding resources. + */ + Map findResources(String directory, Predicate filter); + + /** + * Gives a map of all resource stacks that could be found in the + * given directory or one of its sub-directories (recursively), + * that match the given filter. + *

+ * For each location, all resources at that location are given. If + * multiple resource packs contain the resource at that location, + * the resources are listed in resource pack order. This means the + * resource from the top resource pack appears at the top of the + * stack (i.e. last in the list). + * + * @param directory the directory in which to start looking for resources. + * @param filter the filter that resource locations must match. + * @return a map of found resource locations to corresponding resource stacks. + */ + Map> findResourceStacks(String directory, Predicate filter); + +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/pack/AbstractResourcePack.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/pack/AbstractResourcePack.java new file mode 100644 index 00000000..7c4dcd56 --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/pack/AbstractResourcePack.java @@ -0,0 +1,65 @@ +package net.ornithemc.osl.resource.loader.api.resource.pack; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +import net.ornithemc.osl.resource.loader.api.resource.ResourceMetadata; +import net.ornithemc.osl.resource.loader.api.resource.ResourceMetadata.Section.Serializer; +import net.ornithemc.osl.resource.loader.api.resource.ResourceType; +import net.ornithemc.osl.resource.loader.impl.ResourceLoader; +import net.ornithemc.osl.resource.loader.impl.resource.JsonResourceMetadata; + +/** + * A partial resource pack implementation that handles namespaces and resource pack metadata sections. + */ +public abstract class AbstractResourcePack implements ResourcePack { + + private Map> namespaces; + + @Override + public Set getNamespaces(ResourceType type) { + if (this.namespaces == null) { + this.namespaces = this.findNamespaces(); + } + + return this.namespaces.getOrDefault(type, Collections.emptySet()); + } + + protected abstract Map> findNamespaces(); + + @Override + public T getMetadata(String name, Serializer serializer) throws IOException { + InputStream resource = this.getResource(METADATA_FILE); + + if (resource != null) { + try { + ResourceMetadata metadata = JsonResourceMetadata.fromInputStream(resource); + + if (metadata != null) { + return metadata.getSection(name, serializer); + } + } catch (Exception e) { + ResourceLoader.LOGGER.error("Could not load {} {} metadata: {}", this.getId(), name, e); + } + } + + return null; + } + + @Override + public void open() { + } + + @Override + public void close() { + this.namespaces = null; + } + + @Override + public void finalize() { + this.close(); + } +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/pack/PackCompatibility.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/pack/PackCompatibility.java new file mode 100644 index 00000000..a58c4ea7 --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/pack/PackCompatibility.java @@ -0,0 +1,43 @@ +package net.ornithemc.osl.resource.loader.api.resource.pack; + +import net.ornithemc.osl.resource.loader.impl.resource.pack.ResourcePacks; + +/** + * The compatibility status of a resource pack. + */ +public enum PackCompatibility { + + COMPATIBLE, TOO_OLD, TOO_NEW; + + /** + * @return a format number representing this compatibility status. + */ + public int asFormat() { + int supportedFormat = ResourcePacks.getSupportedFormat(); + + if (this == TOO_OLD) { + return supportedFormat - 1; + } + if (this == TOO_NEW) { + return supportedFormat + 1; + } + + return supportedFormat; + } + + /** + * @return the compatibility status corresponding to the given format number. + */ + public static PackCompatibility forFormat(int format) { + int supportedFormat = ResourcePacks.getSupportedFormat(); + + if (format < supportedFormat) { + return TOO_OLD; + } + if (format > supportedFormat) { + return TOO_NEW; + } + + return COMPATIBLE; + } +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/pack/PackPosition.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/pack/PackPosition.java new file mode 100644 index 00000000..f9c8a91d --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/pack/PackPosition.java @@ -0,0 +1,47 @@ +package net.ornithemc.osl.resource.loader.api.resource.pack; + +import java.util.List; + +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackSummary; + +/** + * Represents a resource pack's preferred ordering position. + */ +public enum PackPosition { + + TOP, BOTTOM; + + public PackPosition opposite() { + return this == TOP ? BOTTOM : TOP; + } + + public void insert(List resourcePacks, ResourcePackSummary resourcePack, boolean reverse) { + PackPosition pos = reverse ? this.opposite() : this; + + if (pos == BOTTOM) { + int index; + + for (index = 0; index < resourcePacks.size(); index++) { + ResourcePackSummary pack = resourcePacks.get(index); + + if (!pack.isFixedPosition() || pack.getDefaultPosition() != this) { + break; + } + } + + resourcePacks.add(index, resourcePack); + } else { + int index; + + for (index = resourcePacks.size() - 1; index >= 0; index--) { + ResourcePackSummary pack = resourcePacks.get(index); + + if (!pack.isFixedPosition() || pack.getDefaultPosition() != this) { + break; + } + } + + resourcePacks.add(index + 1, resourcePack); + } + } +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/pack/ResourceConsumer.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/pack/ResourceConsumer.java new file mode 100644 index 00000000..82e07ffe --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/pack/ResourceConsumer.java @@ -0,0 +1,11 @@ +package net.ornithemc.osl.resource.loader.api.resource.pack; + +import java.io.InputStream; +import java.util.function.BiConsumer; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.function.IOSupplier; + +@FunctionalInterface +public interface ResourceConsumer extends BiConsumer> { +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/pack/ResourcePack.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/pack/ResourcePack.java new file mode 100644 index 00000000..cb6c536a --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/pack/ResourcePack.java @@ -0,0 +1,136 @@ +package net.ornithemc.osl.resource.loader.api.resource.pack; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Set; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.function.IOSupplier; +import net.ornithemc.osl.resource.loader.api.resource.ResourceMetadata; +import net.ornithemc.osl.resource.loader.api.resource.ResourceMetadata.Section; +import net.ornithemc.osl.resource.loader.api.resource.ResourceType; + +public interface ResourcePack extends AutoCloseable { + + /** + * The path to the pack.mcmeta file. + */ + String METADATA_FILE = "pack" + ResourceMetadata.FILE_EXTENSION; + /** + * The path to the pack.png file. + */ + String ICON_FILE = "pack.png"; + + /** + * @return the ID of this resource pack. + */ + String getId(); + + /** + * Checks whether the resource at the given path exists. + *

+ * NOTE: this method expects a direct file path to be given, + * rather than a namespaced path. For this reason, this method + * should only be used to access resources in 1.5.2 and below, + * or special root resources such as pack.mcmeta and pack.png. + * + * @param path the path to the resource. + * @return whether the resource exists. + */ + boolean hasResource(String path); + + /** + * Returns the resource at the given path. + *

+ * NOTE: this method expects a direct file path to be given, + * rather than a namespaced path. For this reason, this method + * should only be used to access resources in 1.5.2 and below, + * or special root resources such as pack.mcmeta and pack.png. + * + * @param path the path to the resource. + * @return the resource at the given path. + * @throws IOException if the resource could not be found or read. + */ + InputStream getResource(String path) throws IOException; + + /** + * @return all namespaces available for the given type of resources. + */ + Set getNamespaces(ResourceType type); + + /** + * Checks whether the resource of the given type at the given + * location exists. + * + * @param type the resource type. + * @param location the location of the resource. + * @return whether the resource exists. + */ + boolean hasResource(ResourceType type, NamespacedIdentifier location); + + /** + * Returns the resource of the given type at the given location, + * or {@code null} if it does not exist. + * + * @param location the location of the resource. + * @return the top resource at the given location. + */ + IOSupplier getResource(ResourceType type, NamespacedIdentifier location); + + /** + * Finds all resources that could be found in the given directory + * or one of its sub-directories (recursively to the given depth), + * that match the given filter. + * + * @param type the resource type. + * @param namespace the namespace in which to look for resources. + * @param directory the directory in which to start looking for resources. + * @param consumer the consumer of resource locations and corresponding resources. + */ + void findResources(ResourceType type, String namespace, String directory, ResourceConsumer consumer); + + /** + * Loads, parses, and returns the resource pack metadata section + * with the given name, using the given serializer, or {@code null} + * if it does not exist. + * + * @param the value type. + * @param section the metadata section type. + * @return the parsed resource metadata section, or {@code null}. + * @throws IOException if the resource metadata section exists but could not be parsed. + */ + default T getMetadata(Section section) throws IOException { + return this.getMetadata(section.name(), section.serializer()); + } + + /** + * Loads, parses, and returns the resource pack metadata section + * with the given name, using the given serializer, or {@code null} + * if it does not exist. + * + * @param the value type. + * @param name the name of the metadata section. + * @param serializer the serializer of the metadata section. + * @return the parsed resource metadata section, or {@code null}. + * @throws IOException if the resource metadata section exists but could not be parsed. + */ + T getMetadata(String name, Section.Serializer serializer) throws IOException; + + /** + * This method may be called when this resource pack is first discovered, + * or when it is selected. It is here for legacy reasons, to support old + * Minecraft versions where texture packs or resource packs used methods + * like this to load metadata and/or icons. + */ + void open(); + + /** + * This method may be called when this resource pack is no longer present, + * or when it is unselected. It is here for legacy reasons, to support old + * Minecraft versions where texture packs or resource packs used methods + * like this to unload metadata and/or icons. + */ + @Override + void close(); // no exception + +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/pack/ResourcePackFileNotFoundException.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/pack/ResourcePackFileNotFoundException.java new file mode 100644 index 00000000..cbb7738f --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/pack/ResourcePackFileNotFoundException.java @@ -0,0 +1,12 @@ +package net.ornithemc.osl.resource.loader.api.resource.pack; + +import java.io.FileNotFoundException; + +public class ResourcePackFileNotFoundException extends FileNotFoundException { + + private static final long serialVersionUID = 1L; + + public ResourcePackFileNotFoundException(ResourcePack pack, String path) { + super(String.format("'%s' in ResourcePack '%s'", path, pack.getId())); + } +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/pack/ResourcePackMetadata.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/pack/ResourcePackMetadata.java new file mode 100644 index 00000000..55861abf --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/pack/ResourcePackMetadata.java @@ -0,0 +1,32 @@ +package net.ornithemc.osl.resource.loader.api.resource.pack; + +import net.ornithemc.osl.resource.loader.api.resource.ResourceMetadata; +import net.ornithemc.osl.resource.loader.impl.resource.pack.SimpleResourcePackMetadata; +import net.ornithemc.osl.text.api.TextComponent; + +public interface ResourcePackMetadata { + + /** + * The name of this pack.mcmeta section. + */ + String NAME = "pack"; + /** + * The serializer of this pack.mcmeta section. + */ + ResourceMetadata.Section.Serializer SERIALIZER = SimpleResourcePackMetadata.SERIALIZER; + /** + * The section type of this pack.mcmeta section. + */ + ResourceMetadata.Section SECTION = ResourceMetadata.Section.of(NAME, SERIALIZER); + + /** + * @return the format of this resource pack. + */ + int format(); + + /** + * @return the description of this resource pack. + */ + TextComponent description(); + +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/reload/ReloadStep.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/reload/ReloadStep.java new file mode 100644 index 00000000..4ffe624e --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/reload/ReloadStep.java @@ -0,0 +1,9 @@ +package net.ornithemc.osl.resource.loader.api.resource.reload; + +import java.util.concurrent.CompletableFuture; + +public interface ReloadStep { + + CompletableFuture await(T object); + +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/reload/ResourceReload.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/reload/ResourceReload.java new file mode 100644 index 00000000..c0bb412e --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/reload/ResourceReload.java @@ -0,0 +1,58 @@ +package net.ornithemc.osl.resource.loader.api.resource.reload; + +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; + +import net.ornithemc.osl.core.api.util.Unit; +import net.ornithemc.osl.resource.loader.api.resource.manager.ResourceManager; +import net.ornithemc.osl.resource.loader.impl.resource.reload.SimpleResourceReload; + +/** + * Represents a resource reload. + */ +public interface ResourceReload { + + /** + * Starts a resource reload with the given resource reloaders. + * + * @return a new resource reload. + */ + static ResourceReload start(ResourceManager manager, List reloaders, Executor backgroundExecutor, Executor mainThreadExecutor, CompletableFuture initialTask) { + return SimpleResourceReload.of(manager, reloaders, backgroundExecutor, mainThreadExecutor, initialTask); + } + + /** + * @return the result future of this resource reload. + */ + CompletableFuture result(); + + /** + * @return the progress of this resource reload, as a number between 0 and 1. + */ + float getProgress(); + + /** + * @return whether this resource reload is already in the application stage. + */ + boolean isApplying(); + + /** + * @return whether this resource reload is finished. + */ + default boolean isDone() { + return this.result().isDone(); + } + + /** + * Checks whether this resource reload has any exceptions. + * If so, an unchecked exception is thrown. + */ + default void checkExceptions() { + CompletableFuture result = this.result(); + + if (result.isCompletedExceptionally()) { + result.join(); + } + } +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/reload/ResourceReloadListener.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/reload/ResourceReloadListener.java new file mode 100644 index 00000000..05362847 --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/reload/ResourceReloadListener.java @@ -0,0 +1,27 @@ +package net.ornithemc.osl.resource.loader.api.resource.reload; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; + +import net.ornithemc.osl.core.api.util.Unit; +import net.ornithemc.osl.resource.loader.api.resource.manager.ResourceManager; + +/** + * A resource reloader that runs after the reload stage, in the application stage. + */ +public interface ResourceReloadListener extends ResourceReloader { + + @Override + default void prepareSharedState(SharedState state) { + } + + @Override + default CompletableFuture reloadResources(SharedState state, ReloadStep previousStep, Executor reloadExecutor, Executor applyExecutor) { + return previousStep.await(Unit.INSTANCE).thenRunAsync(() -> { + this.resourcesReloaded(state.resourceManager()); + }, applyExecutor); + } + + void resourcesReloaded(ResourceManager manager); + +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/reload/ResourceReloader.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/reload/ResourceReloader.java new file mode 100644 index 00000000..292c9a9e --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/reload/ResourceReloader.java @@ -0,0 +1,65 @@ +package net.ornithemc.osl.resource.loader.api.resource.reload; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; + +import net.ornithemc.osl.resource.loader.api.resource.manager.ResourceManager; + +/** + * A resource reloader handles the actual reloading of specific resources. + */ +public interface ResourceReloader { + + /** + * Prepares the {@linkplain SharedState} that is shared between all reloaders of a resource reload. + * + * @param state the shared state to be prepared. + */ + void prepareSharedState(SharedState state); + + /** + * @param state the shared state of the resource reload. + * @param previousStep the previous reload step that must finish before resources can be applied. + * @param reloadExecutor the executor that runs the reload steps. + * @param applyExecutor the executor that runs the application steps. + * @return the future of the reload performed by this reloader. + */ + CompletableFuture reloadResources(SharedState state, ReloadStep previousStep, Executor reloadExecutor, Executor applyExecutor); + + /** + * A {@code SharedState} holds generic key-value pairs. + */ + interface SharedState { + + /** + * @return the resource manager of this shared state. + */ + ResourceManager resourceManager(); + + /** + * Inserts the given key-value pair into this shared state. + * + * @param the value type. + * @param key the key of the pair. + * @param value the value of the pair. + */ + void set(Key key, T value); + + /** + * Retrieves the value paired with the given key from this shared state. + * + * @param the value type. + * @param key the key of the key-value pair. + * @return the value paired with the given key. + */ + T get(Key key); + + /** + * Represents a key from a key-value pair from a {@linkplain SharedState}. + * + * @param the value type. + */ + interface Key { + } + } +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/reload/SimpleResourceReloader.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/reload/SimpleResourceReloader.java new file mode 100644 index 00000000..8eea6242 --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/reload/SimpleResourceReloader.java @@ -0,0 +1,46 @@ +package net.ornithemc.osl.resource.loader.api.resource.reload; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; + +import net.ornithemc.osl.resource.loader.api.resource.manager.ResourceManager; + +/** + * A simple, two-stage resource reloader. + * + * @param the type of resources to be reloaded. + */ +public interface SimpleResourceReloader extends ResourceReloader { + + @Override + default void prepareSharedState(SharedState state) { + } + + @Override + default CompletableFuture reloadResources(SharedState state, ReloadStep previousStep, Executor reloadExecutor, Executor applyExecutor) { + return CompletableFuture + .supplyAsync(() -> this.reloadResources(state.resourceManager()), reloadExecutor) + .thenCompose(previousStep::await) + .thenAcceptAsync(resources -> this.applyResources(resources, state.resourceManager()), applyExecutor); + } + + /** + * Performs the reload stage for this resource reloader. + *

+ * This stage may not run on the main game thread, so it is + * imperative that the world or render state is not modified. + * + * @param manager + * @return the reloaded resources. + */ + T reloadResources(ResourceManager manager); + + /** + * Performs the application stage for this resource reloader. + * + * @param resources the resources to apply. + * @param manager + */ + void applyResources(T resources, ResourceManager manager); + +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/repository/ResourcePackRepository.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/repository/ResourcePackRepository.java new file mode 100644 index 00000000..b211de0b --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/repository/ResourcePackRepository.java @@ -0,0 +1,106 @@ +package net.ornithemc.osl.resource.loader.api.resource.repository; + +import java.util.Collection; +import java.util.List; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +import net.fabricmc.loader.api.ModContainer; + +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePack; +import net.ornithemc.osl.resource.loader.impl.resource.repository.BundledModResourcePacks; +import net.ornithemc.osl.resource.loader.impl.resource.repository.SimpleResourcePackRepository; + +/** + * A resource pack repository manages resource packs. + */ +public interface ResourcePackRepository extends AutoCloseable { + + static ResourcePackRepository client() { + return SimpleResourcePackRepository.client(); + } + + /** + * @return the pack repository for the Minecraft server. + */ + static ResourcePackRepository server() { + return SimpleResourcePackRepository.server(); + } + + /** + * Registers a custom bundled resource pack for the given mod, + * located at the given directory in the mod's resources. + * + * @param id the ID of the resource pack. + * @param mod the container of the mod that has the resources. + * @param directory the directory at which the resources are located. + */ + static void registerBundledModResourcePack(String id, ModContainer mod, String directory) { + BundledModResourcePacks.registerBundledModResourcePack(id, mod, directory); + } + + /** + * Adds a source from which resource packs are loaded. + */ + void addSource(Source source); + + /** + * Reloads this resource pack repository. All sources will be + * reloaded again, and the collection of available resource + * packs reconstructed. + *

+ * If any of the selected resource packs are no longer available + * after reloading, they will be closed and unselected. + */ + void reload(); + + /** + * @return the summaries of all available resource packs. + */ + Collection getAvailablePacks(); + + /** + * @return the summaries of all selected resource packs. + */ + Collection getSelectedPacks(); + + /** + * @return all selected resource packs. + */ + default List openSelectedPacks() { + return this.getSelectedPacks().stream().map(ResourcePackSummary::open).collect(Collectors.toList()); + } + + /** + * Updates the selected resource packs, closing any that are unselected. + * + * @param packs the IDs of the selected resource packs. + */ + void setSelectedPacks(Collection packs); + + /** + * @return the summaries of all available resource packs that are not selected. + */ + Collection getUnselectedPacks(); + + /** + * @param id the ID of the resource pack. + * @return the summary of the resource pack with the given ID, or {@code null}. + */ + ResourcePackSummary getPack(String id); + + @Override + void close(); // no exception + + /** + * Represents a source from which resource packs are loaded. + */ + interface Source { + + /** + * Loads resource packs from this source and passes them to the given consumer. + */ + void loadResourcePacks(Consumer consumer); + + } +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/repository/ResourcePackSummary.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/repository/ResourcePackSummary.java new file mode 100644 index 00000000..38c4874a --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/resource/repository/ResourcePackSummary.java @@ -0,0 +1,67 @@ +package net.ornithemc.osl.resource.loader.api.resource.repository; + +import java.util.function.Supplier; + +import net.ornithemc.osl.resource.loader.api.resource.pack.PackCompatibility; +import net.ornithemc.osl.resource.loader.api.resource.pack.PackPosition; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePack; +import net.ornithemc.osl.resource.loader.impl.resource.repository.SimpleResourcePackSummary; +import net.ornithemc.osl.text.api.TextComponent; + +/** + * A summary of a resource pack. + */ +public interface ResourcePackSummary extends AutoCloseable { + + static ResourcePackSummary create(ResourcePack pack, boolean required, boolean fixedPosition, PackPosition defaultPosition) { + return SimpleResourcePackSummary.create(pack, required, fixedPosition, defaultPosition); + } + + static ResourcePackSummary create(String id, boolean required, boolean fixedPosition, PackPosition defaultPosition, Supplier opener) { + return SimpleResourcePackSummary.create(id, required, fixedPosition, defaultPosition, opener); + } + + /** + * @return the display title of the resource pack. + */ + TextComponent getTitle(); + + /** + * @return the display description of the resource pack. + */ + TextComponent getDescription(); + + /** + * @return the ID of the resource pack. + */ + String getId(); + + /** + * @return whether the resource pack is required and thus always selected. + */ + boolean isRequired(); + + /** + * @return whether the position of the resource pack in the ordering is fixed. + */ + boolean isFixedPosition(); + + /** + * @return the default position of the resource pack in the ordering. + */ + PackPosition getDefaultPosition(); + + /** + * @return the compatibility status of the resource pack. + */ + PackCompatibility getCompatibility(); + + /** + * @return the resource pack. + */ + ResourcePack open(); + + @Override + void close(); // no exception + +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/server/ServerResourceLoaderEvents.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/server/ServerResourceLoaderEvents.java new file mode 100644 index 00000000..2f7da649 --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/api/server/ServerResourceLoaderEvents.java @@ -0,0 +1,118 @@ +package net.ornithemc.osl.resource.loader.api.server; + +import java.util.function.Consumer; + +import net.ornithemc.osl.core.api.events.Event; +import net.ornithemc.osl.resource.loader.api.resource.manager.ReloadableResourceManager; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackRepository; + +/** + * Events related to server side resource loading. + */ +public final class ServerResourceLoaderEvents { + + /** + * This event is invoked when the ResourcePackRepository is initialized. + * Custom resource pack sources should be registered here. + * + *

+ * Callbacks to this event should be registered in your mod's entrypoint, + * and can be done as follows: + * + *

+	 * {@code
+	 * ServerResourceLoaderEvents.INIT_RESOURCE_PACK_REPOSITORY.register(packRepository -> {
+	 * 	...
+	 * });
+	 * }
+	 * 
+ */ + public static final Event> INIT_RESOURCE_PACK_REPOSITORY = Event.consumer(); + + /** + * This event is invoked when the ResourceManager is initialized. + * Custom resource reloaders should be registered here. + * + *

+ * Callbacks to this event should be registered in your mod's entrypoint, + * and can be done as follows: + * + *

+	 * {@code
+	 * ServerResourceLoaderEvents.INIT_RESOURCE_MANAGER.register(resourceManager -> {
+	 * 	...
+	 * });
+	 * }
+	 * 
+ */ + public static final Event> INIT_RESOURCE_MANAGER = Event.consumer(); + + /** + * This event is invoked before resource packs are reloaded. + * + *

+ * Callbacks to this event should be registered in your mod's entrypoint, + * and can be done as follows: + * + *

+	 * {@code
+	 * ServerResourceLoaderEvents.START_RESOURCE_PACKS_RELOAD.register(() -> {
+	 * 	...
+	 * });
+	 * }
+	 * 
+ */ + public static final Event START_RESOURCE_PACKS_RELOAD = Event.runnable(); + + /** + * This event is invoked after resource packs are reloaded. + * + *

+ * Callbacks to this event should be registered in your mod's entrypoint, + * and can be done as follows: + * + *

+	 * {@code
+	 * ServerResourceLoaderEvents.END_RESOURCE_PACKS_RELOAD.register(() -> {
+	 * 	...
+	 * });
+	 * }
+	 * 
+ */ + public static final Event END_RESOURCE_PACKS_RELOAD = Event.runnable(); + + /** + * This event is invoked before resources are reloaded. + * + *

+ * Callbacks to this event should be registered in your mod's entrypoint, + * and can be done as follows: + * + *

+	 * {@code
+	 * ServerResourceLoaderEvents.START_RESOURCE_RELOAD.register(() -> {
+	 * 	...
+	 * });
+	 * }
+	 * 
+ */ + public static final Event START_RESOURCE_RELOAD = Event.runnable(); + + /** + * This event is invoked after resources are reloaded. + * + *

+ * Callbacks to this event should be registered in your mod's entrypoint, + * and can be done as follows: + * + *

+	 * {@code
+	 * ServerResourceLoaderEvents.END_RESOURCE_RELOAD.register(() -> {
+	 * 	...
+	 * });
+	 * }
+	 * 
+ */ + public static final Event END_RESOURCE_RELOAD = Event.runnable(); + +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/ResourceLoader.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/ResourceLoader.java new file mode 100644 index 00000000..1dbe6b2b --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/ResourceLoader.java @@ -0,0 +1,13 @@ +package net.ornithemc.osl.resource.loader.impl; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import net.fabricmc.loader.api.FabricLoader; + +public class ResourceLoader { + + public static final Logger LOGGER = LogManager.getLogger("OSL|Resource Loader"); + public static final boolean DEBUG = FabricLoader.getInstance().isDevelopmentEnvironment(); + +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/JsonResourceMetadata.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/JsonResourceMetadata.java new file mode 100644 index 00000000..17d562b8 --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/JsonResourceMetadata.java @@ -0,0 +1,81 @@ +package net.ornithemc.osl.resource.loader.impl.resource; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.StandardCharsets; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonObject; + +import net.ornithemc.osl.core.api.util.function.IOSupplier; +import net.ornithemc.osl.resource.loader.api.resource.ResourceMetadata; +import net.ornithemc.osl.resource.loader.api.resource.ResourceMetadata.Section.Serializer; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePackMetadata; +import net.ornithemc.osl.resource.loader.impl.resource.pack.SimpleResourcePackMetadata; + +public class JsonResourceMetadata implements ResourceMetadata { + + private static final Gson GSON = new GsonBuilder().create(); + + public static JsonResourceMetadata fromInputStream(IOSupplier inputStream) throws IOException { + return fromInputStream(inputStream.get()); + } + + public static JsonResourceMetadata fromInputStream(InputStream is) throws IOException { + JsonResourceMetadata resourceMetadata; + + try { + Reader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8)); + JsonObject metadata = GSON.fromJson(reader, JsonObject.class); + + resourceMetadata = new JsonResourceMetadata(metadata); + } catch (Throwable t) { + if (is != null) { + try { + is.close(); + } catch (Throwable ct) { + t.addSuppressed(ct); + } + } + + throw t; + } + + if (is != null) { + is.close(); + } + + return resourceMetadata; + } + + public static IOSupplier asInputStream(ResourcePackMetadata packSection) { + JsonObject json = new JsonObject(); + + json.add( + ResourcePackMetadata.NAME, + SimpleResourcePackMetadata.SERIALIZER.serialize(packSection) + ); + + return () -> new ByteArrayInputStream(json.toString().getBytes(StandardCharsets.UTF_8)); + } + + private final JsonObject metadata; + + public JsonResourceMetadata(JsonObject metadata) { + this.metadata = metadata; + } + + public JsonObject asJsonObject() { + return this.metadata; + } + + @Override + public T getSection(String name, Serializer serializer) { + return !this.metadata.has(name) ? null : serializer.deserialize(this.metadata.getAsJsonObject(name)); + } +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/LazyResource.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/LazyResource.java new file mode 100644 index 00000000..3bcaa8d6 --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/LazyResource.java @@ -0,0 +1,67 @@ +package net.ornithemc.osl.resource.loader.impl.resource; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.function.IOSupplier; +import net.ornithemc.osl.resource.loader.api.resource.Resource; +import net.ornithemc.osl.resource.loader.api.resource.ResourceMetadata; + +public class LazyResource implements Resource { + + private final String sourceName; + private final NamespacedIdentifier location; + private final IOSupplier inputStream; + private final IOSupplier resourceMetadata; + + private ResourceMetadata metadata; + + public LazyResource(String sourceName, NamespacedIdentifier location, IOSupplier inputStream, IOSupplier resourceMetadata) { + this.sourceName = sourceName; + this.location = location; + this.inputStream = inputStream; + this.resourceMetadata = resourceMetadata; + } + + @Override + public String sourceName() { + return this.sourceName; + } + + @Override + public NamespacedIdentifier location() { + return this.location; + } + + @Override + public InputStream open() throws IOException { + return this.inputStream.get(); + } + + @Override + public BufferedReader openAsReader() throws IOException { + return new BufferedReader(new InputStreamReader(this.inputStream.get(), StandardCharsets.UTF_8)); + } + + @Override + public ResourceMetadata metadata() throws IOException { + if (this.metadata == null) { + this.metadata = this.resourceMetadata.get(); + } + + return this.metadata; + } + + @Override + public boolean hasMetadata() { + return this.resourceMetadata != ResourceMetadata.EMPTY_SUPPLIER; + } + + @Override + public void close() throws IOException { + } +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/ResourceLocationAccess.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/ResourceLocationAccess.java new file mode 100644 index 00000000..cc7d4490 --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/ResourceLocationAccess.java @@ -0,0 +1,13 @@ +package net.ornithemc.osl.resource.loader.impl.resource; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; + +/** + * This interface is used in some implementations to access + * the location field of Vanilla's SimpleResource class. + */ +public interface ResourceLocationAccess { + + NamespacedIdentifier resourceLocation(); + +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/ResourceMetadataSection.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/ResourceMetadataSection.java new file mode 100644 index 00000000..05d0d56e --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/ResourceMetadataSection.java @@ -0,0 +1,24 @@ +package net.ornithemc.osl.resource.loader.impl.resource; + +import net.ornithemc.osl.resource.loader.api.resource.ResourceMetadata.Section; + +public class ResourceMetadataSection implements Section { + + private final String name; + private final Section.Serializer serializer; + + public ResourceMetadataSection(String name, Section.Serializer serializer) { + this.name = name; + this.serializer = serializer; + } + + @Override + public String name() { + return this.name; + } + + @Override + public Section.Serializer serializer() { + return this.serializer; + } +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/manager/FallbackResourceManager.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/manager/FallbackResourceManager.java new file mode 100644 index 00000000..5743c5bb --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/manager/FallbackResourceManager.java @@ -0,0 +1,242 @@ +package net.ornithemc.osl.resource.loader.impl.resource.manager; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.TreeMap; +import java.util.function.Predicate; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.NamespacedIdentifiers; +import net.ornithemc.osl.core.api.util.function.IOSupplier; +import net.ornithemc.osl.resource.loader.api.resource.Resource; +import net.ornithemc.osl.resource.loader.api.resource.ResourceMetadata; +import net.ornithemc.osl.resource.loader.api.resource.ResourceType; +import net.ornithemc.osl.resource.loader.api.resource.manager.ResourceManager; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePack; +import net.ornithemc.osl.resource.loader.impl.resource.JsonResourceMetadata; +import net.ornithemc.osl.resource.loader.impl.resource.LazyResource; +import net.ornithemc.osl.resource.loader.impl.resource.pack.ResourcePacks; + +public class FallbackResourceManager implements ResourceManager { + + private final ResourceType type; + private final String namespace; + private final List fallbacks; + + public FallbackResourceManager(ResourceType type, String namespace) { + this.type = type; + this.namespace = namespace; + this.fallbacks = new ArrayList<>(); + } + + public void add(ResourcePack pack) { + this.fallbacks.add(pack); + } + + @Override + public boolean hasResource(String path) { + throw new UnsupportedOperationException("Use LegacyResourceManager!"); + } + + @Override + public InputStream getResource(String path) throws IOException { + throw new UnsupportedOperationException("Use LegacyResourceManager!"); + } + + @Override + public List getResourceStack(String path) throws IOException { + throw new UnsupportedOperationException("Use LegacyResourceManager!"); + } + + @Override + public Set getNamespaces() { + return Collections.singleton(this.namespace); + } + + @Override + public boolean hasResource(NamespacedIdentifier location) { + for (int i = this.fallbacks.size() - 1; i >= 0; i--) { + ResourcePack fallback = this.fallbacks.get(i); + + if (fallback.hasResource(this.type, location)) { + return true; + } + } + + return false; + } + + @Override + public Optional getResource(NamespacedIdentifier location) { + for (int i = this.fallbacks.size() - 1; i >= 0; i--) { + ResourcePack fallback = this.fallbacks.get(i); + IOSupplier resource = fallback.getResource(this.type, location); + + if (resource != null) { + IOSupplier metadata = this.findResourceMetadata(location, i); + return Optional.of(new LazyResource(fallback.getId(), location, resource, metadata)); + } + } + + return Optional.empty(); + } + + private IOSupplier findResourceMetadata(NamespacedIdentifier resourceLocation, int resourceIndex) { + return () -> { + NamespacedIdentifier location = ResourcePacks.getMetadataLocation(resourceLocation); + + for (int i = this.fallbacks.size() - 1; i >= resourceIndex; i--) { + ResourcePack fallback = this.fallbacks.get(i); + IOSupplier resource = fallback.getResource(this.type, location); + + if (resource != null) { + return JsonResourceMetadata.fromInputStream(resource); + } + } + + return ResourceMetadata.EMPTY; + }; + } + + @Override + public List getResourceStack(NamespacedIdentifier location) { + List resources = new ArrayList<>(); + + for (int i = 0; i < this.fallbacks.size(); i++) { + ResourcePack fallback = this.fallbacks.get(i); + IOSupplier resource = fallback.getResource(this.type, location); + + if (resource != null) { + IOSupplier metadata = this.getResourceMetadata(location, i); + resources.add(new LazyResource(fallback.getId(), location, resource, metadata)); + } + } + + return resources; + } + + private IOSupplier getResourceMetadata(NamespacedIdentifier resourceLocation, int resourceIndex) { + return () -> { + ResourcePack fallback = this.fallbacks.get(resourceIndex); + + NamespacedIdentifier location = ResourcePacks.getMetadataLocation(resourceLocation); + IOSupplier resource = fallback.getResource(this.type, location); + + if (resource != null) { + return JsonResourceMetadata.fromInputStream(resource); + } + + return ResourceMetadata.EMPTY; + }; + } + + @Override + public Map findResources(String directory, Predicate filter) { + Map resources = new TreeMap<>(NamespacedIdentifiers.COMPARATOR); + + Map resourceSuppliers = new HashMap<>(); + Map metadataSuppliers = new HashMap<>(); + + for (int i = 0; i < this.fallbacks.size(); i++) { + int fallbackIndex = i; + ResourcePack fallback = this.fallbacks.get(i); + + fallback.findResources(this.type, this.namespace, directory, (location, resource) -> { + if (ResourcePacks.isMetadataLocation(location)) { + NamespacedIdentifier resourceLocation = ResourcePacks.getResourceLocation(location); + + if (filter.test(resourceLocation)) { + metadataSuppliers.put(resourceLocation, new ResourceFromFallback(fallbackIndex, fallback.getId(), resource)); + } + } else { + if (filter.test(location)) { + resourceSuppliers.put(location, new ResourceFromFallback(fallbackIndex, fallback.getId(), resource)); + } + } + }); + } + + resourceSuppliers.forEach((location, resourceFromFallback) -> { + ResourceFromFallback metadataFromFallback = metadataSuppliers.get(location); + IOSupplier resource = resourceFromFallback.resource; + IOSupplier metadata; + + if (metadataFromFallback != null && metadataFromFallback.index >= resourceFromFallback.index) { + metadata = ResourceMetadata.supplier(metadataFromFallback.resource); + } else { + metadata = ResourceMetadata.EMPTY_SUPPLIER; + } + + resources.put(location, new LazyResource(resourceFromFallback.name, location, resource, metadata)); + }); + + return resources; + } + + @Override + public Map> findResourceStacks(String directory, Predicate filter) { + Map> resources = new TreeMap<>(NamespacedIdentifiers.COMPARATOR); + + Map>> resourceSuppliers = new HashMap<>(); + Map>> metadataSuppliers = new HashMap<>(); + + for (int i = 0; i < this.fallbacks.size(); i++) { + ResourcePack fallback = this.fallbacks.get(i); + + fallback.findResources(this.type, this.namespace, directory, (location, resource) -> { + if (ResourcePacks.isMetadataLocation(location)) { + NamespacedIdentifier resourceLocation = ResourcePacks.getResourceLocation(location); + + if (filter.test(resourceLocation)) { + metadataSuppliers.computeIfAbsent(resourceLocation, key -> new LinkedHashMap<>()).put(fallback.getId(), resource); + } + } else { + if (filter.test(location)) { + resourceSuppliers.computeIfAbsent(location, key -> new LinkedHashMap<>()).put(fallback.getId(), resource); + } + } + }); + } + + resourceSuppliers.forEach((location, resourceStack) -> { + Map> metadataStack = metadataSuppliers.get(location); + + for (Map.Entry> e : resourceStack.entrySet()) { + String fallbackId = e.getKey(); + IOSupplier resource = e.getValue(); + IOSupplier metadata; + + if (metadataStack != null && metadataStack.containsKey(fallbackId)) { + metadata = ResourceMetadata.supplier(metadataStack.get(fallbackId)); + } else { + metadata = ResourceMetadata.EMPTY_SUPPLIER; + } + + resources.computeIfAbsent(location, key -> new ArrayList<>()).add(new LazyResource(fallbackId, location, resource, metadata)); + } + }); + + return resources; + } + + private static class ResourceFromFallback { + + public final int index; + public final String name; + public final IOSupplier resource; + + public ResourceFromFallback(int index, String name, IOSupplier resource) { + this.index = index; + this.name = name; + this.resource = resource; + } + } +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/manager/LegacyResourceManager.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/manager/LegacyResourceManager.java new file mode 100644 index 00000000..650e8608 --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/manager/LegacyResourceManager.java @@ -0,0 +1,108 @@ +package net.ornithemc.osl.resource.loader.impl.resource.manager; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.Predicate; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.resource.loader.api.resource.Resource; +import net.ornithemc.osl.resource.loader.api.resource.manager.ResourceManager; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePack; + +public class LegacyResourceManager implements ResourceManager { + + private final List fallbacks; + + public LegacyResourceManager() { + this.fallbacks = new ArrayList<>(); + } + + public void add(ResourcePack pack) { + this.fallbacks.add(pack); + } + + @Override + public boolean hasResource(String path) { + for (int i = 0; i < this.fallbacks.size(); i++) { + ResourcePack fallback = this.fallbacks.get(i); + + if (fallback.hasResource(path)) { + return true; + } + } + + return false; + } + + @Override + public InputStream getResource(String path) throws IOException { + for (int i = this.fallbacks.size() - 1; i >= 0; i--) { + ResourcePack fallback = this.fallbacks.get(i); + + if (fallback.hasResource(path)) { + return fallback.getResource(path); + } + } + + throw new FileNotFoundException(path); + } + + @Override + public List getResourceStack(String path) throws IOException { + List resources = new ArrayList<>(); + + for (int i = 0; i < this.fallbacks.size(); i++) { + ResourcePack fallback = this.fallbacks.get(i); + + if (fallback.hasResource(path)) { + resources.add(fallback.getResource(path)); + } + } + + if (!resources.isEmpty()) { + return resources; + } + + throw new FileNotFoundException(path); + } + + @Override + public Set getNamespaces() { + throw new UnsupportedOperationException("Use FallbackResourceManager!"); + } + + @Override + public boolean hasResource(NamespacedIdentifier location) { + throw new UnsupportedOperationException("Use FallbackResourceManager!"); + } + + @Override + public Optional getResource(NamespacedIdentifier location) { + throw new UnsupportedOperationException("Use FallbackResourceManager!"); + } + + @Override + public List getResourceStack(NamespacedIdentifier location) { + throw new UnsupportedOperationException("Use FallbackResourceManager!"); + } + + @Override + public Map findResources(String directory, Predicate filter) { + throw new UnsupportedOperationException("Use FallbackResourceManager!"); + } + + @Override + public Map> findResourceStacks(String directory, Predicate filter) { + throw new UnsupportedOperationException("Use FallbackResourceManager!"); + } + + public void clear() { + this.fallbacks.clear(); + } +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/manager/SimpleReloadableResourceManager.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/manager/SimpleReloadableResourceManager.java new file mode 100644 index 00000000..089f358f --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/manager/SimpleReloadableResourceManager.java @@ -0,0 +1,201 @@ +package net.ornithemc.osl.resource.loader.impl.resource.manager; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.Unit; +import net.ornithemc.osl.resource.loader.api.client.ClientResourceLoaderEvents; +import net.ornithemc.osl.resource.loader.api.resource.Resource; +import net.ornithemc.osl.resource.loader.api.resource.ResourceType; +import net.ornithemc.osl.resource.loader.api.resource.manager.ReloadableResourceManager; +import net.ornithemc.osl.resource.loader.api.resource.manager.ResourceManager; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePack; +import net.ornithemc.osl.resource.loader.api.resource.reload.ResourceReload; +import net.ornithemc.osl.resource.loader.api.resource.reload.ResourceReloader; +import net.ornithemc.osl.resource.loader.api.server.ServerResourceLoaderEvents; +import net.ornithemc.osl.resource.loader.impl.ResourceLoader; + +public class SimpleReloadableResourceManager implements ReloadableResourceManager { + + private static final Map INSTANCES = new EnumMap<>(ResourceType.class); + + private static SimpleReloadableResourceManager forType(ResourceType type) { + return INSTANCES.computeIfAbsent(type, SimpleReloadableResourceManager::new); + } + + public static SimpleReloadableResourceManager client() { + return forType(ResourceType.CLIENT_ASSETS); + } + + public static SimpleReloadableResourceManager server() { + return forType(ResourceType.SERVER_DATA); + } + + private final ResourceType type; + private final List registeredReloaders; + private final List recentlyRegisteredReloaders; + private final Map resourceManagers; + private final LegacyResourceManager legacyResourceManager; + + public SimpleReloadableResourceManager(ResourceType type) { + this.type = type; + this.registeredReloaders = new ArrayList<>(); + this.recentlyRegisteredReloaders = new ArrayList<>(); + this.resourceManagers = new HashMap<>(); + this.legacyResourceManager = new LegacyResourceManager(); + } + + public void init() { + if (this.type == ResourceType.CLIENT_ASSETS) { + ClientResourceLoaderEvents.INIT_RESOURCE_MANAGER.invoker().accept(this); + } else if (this.type == ResourceType.SERVER_DATA) { + ServerResourceLoaderEvents.INIT_RESOURCE_MANAGER.invoker().accept(this); + } + } + + public void add(ResourcePack pack) { + Set namespaces = pack.getNamespaces(this.type); + + for (String namespace : namespaces) { + FallbackResourceManager manager = this.resourceManagers.get(namespace); + if (manager == null) { + this.resourceManagers.put(namespace, manager = new FallbackResourceManager(this.type, namespace)); + } + + manager.add(pack); + } + + this.legacyResourceManager.add(pack); + } + + @Override + public boolean hasResource(String path) { + return this.legacyResourceManager.hasResource(path); + } + + @Override + public InputStream getResource(String path) throws IOException { + return this.legacyResourceManager.getResource(path); + } + + @Override + public List getResourceStack(String path) throws IOException { + return this.legacyResourceManager.getResourceStack(path); + } + + @Override + public Set getNamespaces() { + return this.resourceManagers.keySet(); + } + + @Override + public boolean hasResource(NamespacedIdentifier location) { + ResourceManager manager = this.resourceManagers.get(location.namespace()); + return manager != null && manager.hasResource(location); + } + + @Override + public Optional getResource(NamespacedIdentifier location) { + ResourceManager manager = this.resourceManagers.get(location.namespace()); + return manager == null ? Optional.empty() : manager.getResource(location); + } + + @Override + public List getResourceStack(NamespacedIdentifier location) { + ResourceManager manager = this.resourceManagers.get(location.namespace()); + return manager == null ? Collections.emptyList() : manager.getResourceStack(location); + } + + @Override + public Map findResources(String directory, Predicate filter) { + Map resources = new HashMap<>(); + + for (ResourceManager manager : this.resourceManagers.values()) { + resources.putAll(manager.findResources(directory, filter)); + } + + return resources; + } + + @Override + public Map> findResourceStacks(String directory, Predicate filter) { + Map> resources = new HashMap<>(); + + for (ResourceManager manager : this.resourceManagers.values()) { + resources.putAll(manager.findResourceStacks(directory, filter)); + } + + return resources; + } + + @Override + public void addReloader(ResourceReloader reloader) { + this.registeredReloaders.add(reloader); + this.recentlyRegisteredReloaders.add(reloader); + } + + @Override + public void reload(List packs) { + ResourceReload reload = this.startReload(packs, Runnable::run, Runnable::run, CompletableFuture.completedFuture(Unit.INSTANCE)); + + while (!reload.isDone()) { + reload.checkExceptions(); + } + } + + @Override + public ResourceReload startReload(List packs, Executor backgroundExecutor, Executor mainThreadExecutor, CompletableFuture initialTask) { + ResourceLoader.LOGGER.info("Reloading ResourceManager: {}", packs.stream().map(ResourcePack::getId).collect(Collectors.joining(", "))); + + this.resourceManagers.clear(); + this.legacyResourceManager.clear(); + + for (ResourcePack pack : packs) { + this.add(pack); + } + + return this.startReload(backgroundExecutor, mainThreadExecutor, initialTask, this.registeredReloaders); + } + + public ResourceReload startPartialReload(Executor backgroundExecutor, Executor mainThreadExecutor, CompletableFuture initialTask) { + return this.startReload(backgroundExecutor, mainThreadExecutor, initialTask, this.recentlyRegisteredReloaders); + } + + private ResourceReload startReload(Executor backgroundExecutor, Executor mainThreadExecutor, CompletableFuture initialTask, List reloaders) { + reloaders = new ArrayList<>(reloaders); + this.recentlyRegisteredReloaders.clear(); + + initialTask = initialTask.thenRun(() -> { + if (this.type == ResourceType.CLIENT_ASSETS) { + ClientResourceLoaderEvents.START_RESOURCE_RELOAD.invoker().run(); + } else if (this.type == ResourceType.SERVER_DATA) { + ServerResourceLoaderEvents.START_RESOURCE_RELOAD.invoker().run(); + } + }); + + ResourceReload reload = ResourceReload.start(this, reloaders, backgroundExecutor, mainThreadExecutor, initialTask); + + reload.result().thenRun(() -> { + if (this.type == ResourceType.CLIENT_ASSETS) { + ClientResourceLoaderEvents.END_RESOURCE_RELOAD.invoker().run(); + } else if (this.type == ResourceType.SERVER_DATA) { + ServerResourceLoaderEvents.END_RESOURCE_RELOAD.invoker().run(); + } + }); + + return reload; + } +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/pack/BuiltInModResourcesPack.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/pack/BuiltInModResourcesPack.java new file mode 100644 index 00000000..2cee7201 --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/pack/BuiltInModResourcesPack.java @@ -0,0 +1,92 @@ +package net.ornithemc.osl.resource.loader.impl.resource.pack; + +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +import net.fabricmc.loader.api.FabricLoader; + +import net.ornithemc.osl.core.api.util.function.IOSupplier; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePack; +import net.ornithemc.osl.text.api.TextComponents; + +public class BuiltInModResourcesPack extends CompositeResourcePack { + + private static final ModLoader MOD_LOADER = ModLoader.get(); + + private final IOSupplier metadata; + private final IOSupplier icon; + + public BuiltInModResourcesPack(List resourcePacks) { + super(resourcePacks); + + this.metadata = ResourcePacks.generateMetadataFile( + TextComponents.literal("Built-in " + MOD_LOADER.displayName() + " Mod Resources") + ); + this.icon = ModContainerResourcePack.getIcon(MOD_LOADER.modId()); + } + + @Override + public String getId() { + return MOD_LOADER.id() + "-mod-resources"; + } + + @Override + public boolean hasResource(String path) { + if (METADATA_FILE.equals(path) || ICON_FILE.equals(path)) { + return true; + } + + return super.hasResource(path); + } + + @Override + public InputStream getResource(String path) throws IOException { + if (METADATA_FILE.equals(path)) { + return this.metadata.get(); + } + if (ICON_FILE.equals(path)) { + return this.icon.get(); + } + + return super.getResource(path); + } + + private enum ModLoader { + + FABRIC("fabric", "fabricloader", "Fabric"), + QUILT ("quilt" , "quilt_loader", "Quilt"); + + private final String id; + private final String modId; + private final String displayName; + + private ModLoader(String id, String modId, String displayName) { + this.id = id; + this.modId = modId; + this.displayName = displayName; + } + + String id() { + return this.id; + } + + String modId() { + return this.modId; + } + + String displayName() { + return this.displayName; + } + + static ModLoader get() { + for (ModLoader loader : values()) { + if (FabricLoader.getInstance().isModLoaded(loader.modId)) { + return loader; + } + } + + throw new RuntimeException("Neither Fabric Loader nor Quilt Loader are loaded?! How is this even running?!"); + } + } +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/pack/CompositeResourcePack.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/pack/CompositeResourcePack.java new file mode 100644 index 00000000..0602f799 --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/pack/CompositeResourcePack.java @@ -0,0 +1,99 @@ +package net.ornithemc.osl.resource.loader.impl.resource.pack; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.function.IOSupplier; +import net.ornithemc.osl.resource.loader.api.resource.ResourceType; +import net.ornithemc.osl.resource.loader.api.resource.pack.AbstractResourcePack; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourceConsumer; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePack; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePackFileNotFoundException; + +public abstract class CompositeResourcePack extends AbstractResourcePack { + + private final List resourcePacks = new ArrayList<>(); + + public CompositeResourcePack(List resourcePacks) { + this.resourcePacks.addAll(resourcePacks); + } + + @Override + public boolean hasResource(String path) { + for (ResourcePack pack : this.resourcePacks) { + if (pack.hasResource(path)) { + return true; + } + } + + return false; + } + + @Override + public InputStream getResource(String path) throws IOException { + for (ResourcePack pack : this.resourcePacks) { + if (pack.hasResource(path)) { + return pack.getResource(path); + } + } + + throw new ResourcePackFileNotFoundException(this, path); + } + + @Override + public boolean hasResource(ResourceType type, NamespacedIdentifier location) { + for (ResourcePack pack : this.resourcePacks) { + if (pack.hasResource(type, location)) { + return true; + } + } + + return false; + } + + @Override + public IOSupplier getResource(ResourceType type, NamespacedIdentifier location) { + for (ResourcePack pack : this.resourcePacks) { + IOSupplier resource = pack.getResource(type, location); + + if (resource != null) { + return resource; + } + } + + return null; + } + + @Override + public void findResources(ResourceType type, String namespace, String directory, ResourceConsumer consumer) { + for (ResourcePack pack : this.resourcePacks) { + pack.findResources(type, namespace, directory, consumer); + } + } + + @Override + protected Map> findNamespaces() { + Map> namespaces = new EnumMap<>(ResourceType.class); + + for (ResourceType type : ResourceType.values()) { + Set ns = new HashSet<>(); + + for (ResourcePack pack : this.resourcePacks) { + ns.addAll(pack.getNamespaces(type)); + } + + if (!ns.isEmpty()) { + namespaces.put(type, ns); + } + } + + return namespaces; + } +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/pack/DirectoryResourcePack.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/pack/DirectoryResourcePack.java new file mode 100644 index 00000000..561dc44b --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/pack/DirectoryResourcePack.java @@ -0,0 +1,23 @@ +package net.ornithemc.osl.resource.loader.impl.resource.pack; + +import java.nio.file.Path; +import java.util.List; + +public class DirectoryResourcePack extends PathResourcePack { + + private final Path directory; + + public DirectoryResourcePack(Path directory) { + this.directory = directory; + } + + @Override + public String getId() { + return "file/" + this.directory.getFileName(); + } + + @Override + protected List findRootPaths() { + return ResourcePacks.getRootPaths(this.directory, "."); + } +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/pack/ModContainerResourcePack.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/pack/ModContainerResourcePack.java new file mode 100644 index 00000000..5d9c47fa --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/pack/ModContainerResourcePack.java @@ -0,0 +1,58 @@ +package net.ornithemc.osl.resource.loader.impl.resource.pack; + +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.Optional; + +import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.api.ModContainer; + +import net.ornithemc.osl.core.api.util.function.IOSupplier; + +class ModContainerResourcePack extends PathResourcePack { + + final ModContainer mod; + final String directory; + + ModContainerResourcePack(ModContainer mod) { + this(mod, "."); + } + + ModContainerResourcePack(ModContainer mod, String directory) { + this.mod = mod; + this.directory = directory; + } + + static IOSupplier getIcon(String modId) { + Optional mod = FabricLoader.getInstance().getModContainer(modId); + + if (mod.isPresent()) { + return getIcon(mod.get()); + } else { + return () -> null; + } + } + + static IOSupplier getIcon(ModContainer mod) { + Optional pathName = mod.getMetadata().getIconPath(128); + Optional path = pathName.flatMap(mod::findPath); + + if (path.isPresent()) { + return () -> Files.newInputStream(path.get()); + } else { + return () -> null; + } + } + + @Override + protected List findRootPaths() { + return ResourcePacks.getRootPaths(this.mod.getRootPaths(), this.directory); + } + + @Override + public String getId() { + return this.mod.getMetadata().getId(); + } +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/pack/ModResourcePack.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/pack/ModResourcePack.java new file mode 100644 index 00000000..aa027782 --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/pack/ModResourcePack.java @@ -0,0 +1,40 @@ +package net.ornithemc.osl.resource.loader.impl.resource.pack; + +import java.io.IOException; +import java.io.InputStream; + +import net.fabricmc.loader.api.ModContainer; + +import net.ornithemc.osl.core.api.util.function.IOSupplier; +import net.ornithemc.osl.text.api.TextComponents; + +public class ModResourcePack extends ModContainerResourcePack { + + private final IOSupplier metadata; + private final IOSupplier icon; + + public ModResourcePack(ModContainer mod) { + this(mod, "."); + } + + public ModResourcePack(ModContainer mod, String directory) { + super(mod, directory); + + this.metadata = ResourcePacks.generateMetadataFile( + TextComponents.literal(mod.getMetadata().getDescription()) + ); + this.icon = ModContainerResourcePack.getIcon(mod); + } + + @Override + public InputStream getResource(String path) throws IOException { + if (METADATA_FILE.equals(path)) { + return this.metadata.get(); + } + if (ICON_FILE.equals(path)) { + return this.icon.get(); + } + + return super.getResource(path); + } +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/pack/PathResourcePack.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/pack/PathResourcePack.java new file mode 100644 index 00000000..8d2b89bc --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/pack/PathResourcePack.java @@ -0,0 +1,127 @@ +package net.ornithemc.osl.resource.loader.impl.resource.pack; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.EnumMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.function.IOSupplier; +import net.ornithemc.osl.resource.loader.api.resource.Resource; +import net.ornithemc.osl.resource.loader.api.resource.ResourcePath; +import net.ornithemc.osl.resource.loader.api.resource.ResourceType; +import net.ornithemc.osl.resource.loader.api.resource.pack.AbstractResourcePack; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourceConsumer; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePackFileNotFoundException; + +public abstract class PathResourcePack extends AbstractResourcePack { + + private static final FileSystem DEFAULT_FS = FileSystems.getDefault(); + + public static boolean fileExists(Path path) { + return path.getFileSystem() == DEFAULT_FS ? path.toFile().exists() : Files.exists(path); + } + + private List rootPaths; + + @Override + public boolean hasResource(String pathName) { + Path path = this.getPathToResource(pathName); + return path != null && fileExists(path); + } + + @Override + public InputStream getResource(String pathName) throws IOException { + Path path = this.getPathToResource(pathName); + + if (path != null && fileExists(path)) { + return Files.newInputStream(path); + } + + throw new ResourcePackFileNotFoundException(this, pathName); + } + + private Path getPathToResource(String pathName) { + pathName = ResourcePath.nameOf(pathName); + + for (Path root : this.getRootPaths()) { + Path path = ResourcePath.of(root, pathName); + + if (fileExists(path)) { + return path; + } + } + + return null; + } + + @Override + protected Map> findNamespaces() { + Map> namespaces = new EnumMap<>(ResourceType.class); + + ResourcePacks.findNamespaces(this, this.getRootPaths(), (type, namespace) -> { + namespaces.computeIfAbsent(type, key -> new HashSet<>()).add(namespace); + }); + + return namespaces; + } + + @Override + public boolean hasResource(ResourceType type, NamespacedIdentifier location) { + Path path = this.getPathToResource(type, location); + return path != null && fileExists(path); + } + + @Override + public IOSupplier getResource(ResourceType type, NamespacedIdentifier location) { + Path path = this.getPathToResource(type, location); + + if (path != null && fileExists(path)) { + return Resource.supplier(path); + } + + return null; + } + + private Path getPathToResource(ResourceType type, NamespacedIdentifier location) { + String pathName = ResourcePath.nameOf(type, location); + + for (Path root : this.getRootPaths()) { + Path path = ResourcePath.of(root, pathName); + + if (fileExists(path)) { + return path; + } + } + + return null; + } + + @Override + public void findResources(ResourceType type, String namespace, String directory, ResourceConsumer consumer) { + ResourcePacks.findResources(this, this.getRootPaths(), type, namespace, directory, consumer); + } + + private List getRootPaths() { + if (this.rootPaths == null) { + this.rootPaths = this.findRootPaths(); + } + + return this.rootPaths; + } + + protected abstract List findRootPaths(); + + @Override + public void close() { + super.close(); + this.rootPaths = null; + } +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/pack/ResourcePacks.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/pack/ResourcePacks.java new file mode 100644 index 00000000..170fdad0 --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/pack/ResourcePacks.java @@ -0,0 +1,152 @@ +package net.ornithemc.osl.resource.loader.impl.resource.pack; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.function.BiConsumer; +import java.util.stream.Stream; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.NamespacedIdentifiers; +import net.ornithemc.osl.core.api.util.function.IOSupplier; +import net.ornithemc.osl.core.impl.util.NamespacedIdentifierException; +import net.ornithemc.osl.resource.loader.api.resource.ResourceMetadata; +import net.ornithemc.osl.resource.loader.api.resource.ResourceType; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourceConsumer; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePack; +import net.ornithemc.osl.resource.loader.impl.ResourceLoader; +import net.ornithemc.osl.resource.loader.impl.resource.JsonResourceMetadata; +import net.ornithemc.osl.text.api.TextComponent; + +public final class ResourcePacks { + + // up until 20w45a (1.17 snapshot) Resource Packs + // and Data Packs used the same format number! + private static int supportedFormat = 1; + + public static void setSupportedFormat(int format) { + supportedFormat = format; + } + + public static int getSupportedFormat() { + return supportedFormat; + } + + public static List getRootPaths(Path path, String directory) { + return getRootPaths(Collections.singleton(path), directory); + } + + public static List getRootPaths(Iterable paths, String directory) { + List rootPaths = new ArrayList<>(); + + for (Path root : paths) { + root = root.toAbsolutePath().normalize(); + + String separator = root.getFileSystem().getSeparator(); + String dir = directory.replace("/", separator); + Path path = root.resolve(dir).normalize(); + + if (path.startsWith(root) && Files.isDirectory(path)) { + rootPaths.add(path); + } + } + + return rootPaths; + } + + public static void findNamespaces(ResourcePack pack, Iterable roots, BiConsumer consumer) { + for (Path root : roots) { + findNamespaces(pack, root, consumer); + } + } + + public static void findNamespaces(ResourcePack pack, Path root, BiConsumer consumer) { + String separator = root.getFileSystem().getSeparator(); + + for (ResourceType type : ResourceType.values()) { + Path dir = root.resolve(type.directory()); + + if (!Files.isDirectory(dir)) { + continue; + } + + try (DirectoryStream ds = Files.newDirectoryStream(dir)) { + for (Path p : ds) { + if (!Files.isDirectory(p)) { + continue; + } + + String s = p.getFileName().toString(); + String namespace = s.replace(separator, ""); + + try { + consumer.accept(type, NamespacedIdentifiers.validateNamespace(namespace)); + } catch (NamespacedIdentifierException e) { + } + } + } catch (IOException e) { + ResourceLoader.LOGGER.warn("failed to parse namespaces for resource pack " + pack.getId(), e); + } + } + } + + public static void findResources(ResourcePack pack, Iterable roots, ResourceType type, String namespace, String directory, ResourceConsumer consumer) { + for (Path root : roots) { + findResources(pack, root, type, namespace, directory, consumer); + } + } + + public static void findResources(ResourcePack pack, Path root, ResourceType type, String namespace, String directory, ResourceConsumer consumer) { + String separator = root.getFileSystem().getSeparator(); + + Path dir = root.resolve(type.directory()).resolve(namespace); + Path start = dir.resolve(directory.replace("/", separator)); + + if (!Files.isDirectory(start)) { + return; + } + + try (Stream paths = Files.find( + start, + Integer.MAX_VALUE, + (p, attributes) -> attributes.isRegularFile() + && (ResourceLoader.DEBUG || !p.toString().endsWith(".ds_store")) + )) { + Iterator it = paths.iterator(); + + while (it.hasNext()) { + Path p = it.next(); + + String path = dir.relativize(p).toString().replace(separator, "/"); + NamespacedIdentifier location = NamespacedIdentifiers.from(namespace, path); + IOSupplier resource = pack.getResource(type, location); + + consumer.accept(location, resource); + } + } catch (IOException e) { + ResourceLoader.LOGGER.debug("error while listing resources from resource pack " + pack.getId(), e); + } + } + + public static boolean isMetadataLocation(NamespacedIdentifier location) { + return location.identifier().endsWith(ResourceMetadata.FILE_EXTENSION); + } + + public static NamespacedIdentifier getMetadataLocation(NamespacedIdentifier location) { + return NamespacedIdentifiers.from(location.namespace(), location.identifier() + ResourceMetadata.FILE_EXTENSION); + } + + public static NamespacedIdentifier getResourceLocation(NamespacedIdentifier metadata) { + return NamespacedIdentifiers.from(metadata.namespace(), metadata.identifier().substring(0, metadata.identifier().length() - ResourceMetadata.FILE_EXTENSION.length())); + } + + public static IOSupplier generateMetadataFile(TextComponent description) { + return JsonResourceMetadata.asInputStream(new SimpleResourcePackMetadata(supportedFormat, description)); + } +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/pack/SimpleResourcePackMetadata.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/pack/SimpleResourcePackMetadata.java new file mode 100644 index 00000000..22ffc893 --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/pack/SimpleResourcePackMetadata.java @@ -0,0 +1,66 @@ +package net.ornithemc.osl.resource.loader.impl.resource.pack; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSyntaxException; + +import net.ornithemc.osl.resource.loader.api.resource.ResourceMetadata; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePackMetadata; +import net.ornithemc.osl.text.api.TextComponent; +import net.ornithemc.osl.text.api.TextComponents; + +public class SimpleResourcePackMetadata implements ResourcePackMetadata { + + public static final Serializer SERIALIZER = new Serializer(); + + private final int format; + private final TextComponent description; + + public SimpleResourcePackMetadata(int format, TextComponent description) { + this.format = format; + this.description = description; + } + + @Override + public int format() { + return this.format; + } + + @Override + public TextComponent description() { + return this.description; + } + + public static class Serializer implements ResourceMetadata.Section.Serializer { + + private static final String PACK_FORMAT = "pack_format"; + private static final String DESCRIPTION = "description"; + + @Override + public ResourcePackMetadata deserialize(JsonObject json) { + JsonElement packFormat; + JsonElement description; + + if (!json.has(PACK_FORMAT) || !(packFormat = json.get(PACK_FORMAT)).isJsonPrimitive()) { + throw new JsonSyntaxException(PACK_FORMAT + " missing or not an integer!"); + } + if (!json.has(DESCRIPTION) || (description = json.get(DESCRIPTION)).isJsonNull()) { + throw new JsonSyntaxException(DESCRIPTION + " missing or null!"); + } + + return new SimpleResourcePackMetadata( + packFormat.getAsInt(), + TextComponents.fromJsonTree(description) + ); + } + + public JsonObject serialize(ResourcePackMetadata metadata) { + JsonObject json = new JsonObject(); + + json.addProperty(PACK_FORMAT, metadata.format()); + json.add(DESCRIPTION, TextComponents.toJsonTree(metadata.description())); + + return json; + } + } +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/pack/ZippedResourcePack.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/pack/ZippedResourcePack.java new file mode 100644 index 00000000..bf98d50c --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/pack/ZippedResourcePack.java @@ -0,0 +1,59 @@ +package net.ornithemc.osl.resource.loader.impl.resource.pack; + +import java.io.IOException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.util.Collections; +import java.util.List; + +public class ZippedResourcePack extends PathResourcePack { + + private final Path file; + + private FileSystem zipFs; + private boolean zipFailed; + + public ZippedResourcePack(Path file) { + this.file = file; + } + + @Override + public String getId() { + return "file/" + this.file.getFileName(); + } + + @Override + protected List findRootPaths() { + if (this.zipFs == null && !this.zipFailed) { + try { + this.zipFs = FileSystems.newFileSystem(this.file, (ClassLoader) null); + this.zipFailed = false; + } catch (IOException e) { + this.zipFs = null; + this.zipFailed = true; + } + } + + if (this.zipFs == null) { + return Collections.emptyList(); + } else { + return ResourcePacks.getRootPaths(this.zipFs.getRootDirectories(), "."); + } + } + + @Override + public void close() { + super.close(); + + if (this.zipFs != null) { + try { + this.zipFs.close(); + } catch (IOException e) { + } + } + + this.zipFs = null; + this.zipFailed = false; + } +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/reload/SharedReloaderState.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/reload/SharedReloaderState.java new file mode 100644 index 00000000..773810a7 --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/reload/SharedReloaderState.java @@ -0,0 +1,34 @@ +package net.ornithemc.osl.resource.loader.impl.resource.reload; + +import java.util.IdentityHashMap; +import java.util.Map; +import java.util.Objects; + +import net.ornithemc.osl.resource.loader.api.resource.manager.ResourceManager; +import net.ornithemc.osl.resource.loader.api.resource.reload.ResourceReloader.SharedState; + +public class SharedReloaderState implements SharedState { + + private final ResourceManager resourceManager; + private final Map, Object> state; + + public SharedReloaderState(ResourceManager resourceManager) { + this.resourceManager = resourceManager; + this.state = new IdentityHashMap<>(); + } + + @Override + public ResourceManager resourceManager() { + return this.resourceManager; + } + + @Override + public void set(Key key, T value) { + this.state.put(key, value); + } + + @Override + public T get(Key key) { + return (T) Objects.requireNonNull(this.state.get(key)); + } +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/reload/SimpleResourceReload.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/reload/SimpleResourceReload.java new file mode 100644 index 00000000..6ce74b75 --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/reload/SimpleResourceReload.java @@ -0,0 +1,136 @@ +package net.ornithemc.osl.resource.loader.impl.resource.reload; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicInteger; + +import net.ornithemc.osl.core.api.util.Unit; +import net.ornithemc.osl.core.impl.util.Util; +import net.ornithemc.osl.resource.loader.api.resource.manager.ResourceManager; +import net.ornithemc.osl.resource.loader.api.resource.reload.ReloadStep; +import net.ornithemc.osl.resource.loader.api.resource.reload.ResourceReload; +import net.ornithemc.osl.resource.loader.api.resource.reload.ResourceReloader; +import net.ornithemc.osl.resource.loader.api.resource.reload.ResourceReloader.SharedState; + +public class SimpleResourceReload implements ResourceReload { + + public static ResourceReload of(ResourceManager manager, List reloaders, Executor backgroundExecutor, Executor mainThreadExecutor, CompletableFuture initialTask) { + SimpleResourceReload reload = new SimpleResourceReload<>(); + reload.startTasks(manager, reloaders, backgroundExecutor, mainThreadExecutor, TaskFactory.SIMPLE, initialTask); + return reload; + } + + private static final int RELOAD_PROGRESS_WEIGHT = 2; + private static final int APPLICATION_PROGRESS_WEIGHT = 2; + private static final int RELOADER_PROGRESS_WEIGHT = 1; + + private final Set runningReloaders = new HashSet<>(); + private final CompletableFuture reloads = new CompletableFuture<>(); + + private final AtomicInteger startedReloads = new AtomicInteger(); + private final AtomicInteger finishedReloads = new AtomicInteger(); + private final AtomicInteger startedApplications = new AtomicInteger(); + private final AtomicInteger finishedApplications = new AtomicInteger(); + + private int reloaderCount; + private CompletableFuture> result; + + private void startTasks(ResourceManager manager, List reloaders, Executor backgroundExecutor, Executor mainThreadExecutor, TaskFactory taskFactory, CompletableFuture initialTask) { + this.runningReloaders.addAll(reloaders); + this.reloaderCount = reloaders.size(); + + this.result = this.prepareTasks(manager, reloaders, backgroundExecutor, mainThreadExecutor, taskFactory, initialTask); + } + + private CompletableFuture> prepareTasks(ResourceManager manager, List reloaders, Executor backgroundExecutor, Executor mainThreadExecutor, TaskFactory taskFactory, CompletableFuture initialTask) { + Executor reloadExecutor = r -> { + this.startedReloads.incrementAndGet(); + backgroundExecutor.execute(() -> { + r.run(); + this.finishedReloads.incrementAndGet(); + }); + }; + Executor applyExecutor = r -> { + this.startedApplications.incrementAndGet(); + mainThreadExecutor.execute(() -> { + r.run(); + this.finishedApplications.incrementAndGet(); + }); + }; + + this.startedReloads.incrementAndGet(); + initialTask.thenRun(this.finishedReloads::incrementAndGet); + + SharedState state = new SharedReloaderState(manager); + + for (ResourceReloader reloader : reloaders) { + reloader.prepareSharedState(state); + } + + List> tasks = new ArrayList<>(); + CompletableFuture prevTask = initialTask; + + for (ResourceReloader reloader : reloaders) { + ReloadStep previousStep = this.createReloadStep(reloader, prevTask, mainThreadExecutor); + CompletableFuture task = taskFactory.createTask(state, previousStep, reloader, reloadExecutor, applyExecutor); + + tasks.add(task); + prevTask = task; + } + + return Util.sequence(tasks); + } + + private ReloadStep createReloadStep(ResourceReloader reloader, CompletableFuture task, Executor mainThreadExecutor) { + return new ReloadStep() { + + @Override + public CompletableFuture await(T t) { + mainThreadExecutor.execute(() -> { + SimpleResourceReload.this.runningReloaders.remove(reloader); + if (SimpleResourceReload.this.runningReloaders.isEmpty()) { + SimpleResourceReload.this.reloads.complete(Unit.INSTANCE); + } + }); + + return SimpleResourceReload.this.reloads.thenCombine(task, (p, b) -> t); + } + }; + } + + @Override + public CompletableFuture result() { + return Objects.requireNonNull(this.result, "Resource reload has not started!").thenApply(s -> Unit.INSTANCE); + } + + @Override + public float getProgress() { + float weightedFinished = weightProgress(this.finishedReloads.get(), this.finishedApplications.get(), this.reloaderCount - this.runningReloaders.size()); + float weightedTotal = weightProgress(this.startedReloads.get(), this.startedApplications.get(), this.reloaderCount); + + return weightedFinished / weightedTotal; + } + + @Override + public boolean isApplying() { + return this.reloads.isDone(); + } + + private static int weightProgress(int reloads, int applications, int reloaders) { + return reloads * RELOAD_PROGRESS_WEIGHT + applications * APPLICATION_PROGRESS_WEIGHT + reloaders * RELOADER_PROGRESS_WEIGHT; + } + + protected interface TaskFactory { + + TaskFactory SIMPLE = (state, previousStep, reloader, reloadExecutor, applyExecutor) + -> reloader.reloadResources(state, previousStep, reloadExecutor, applyExecutor); + + CompletableFuture createTask(SharedState state, ReloadStep previousStep, ResourceReloader reloader, Executor reloadExecutor, Executor applyExecutor); + + } +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/repository/BundledModResourcePacks.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/repository/BundledModResourcePacks.java new file mode 100644 index 00000000..5391296d --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/repository/BundledModResourcePacks.java @@ -0,0 +1,78 @@ +package net.ornithemc.osl.resource.loader.impl.resource.repository; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.api.ModContainer; + +import net.ornithemc.osl.resource.loader.api.resource.pack.PackPosition; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePack; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackRepository; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackSummary; +import net.ornithemc.osl.resource.loader.impl.resource.pack.BuiltInModResourcesPack; +import net.ornithemc.osl.resource.loader.impl.resource.pack.ModResourcePack; + +public class BundledModResourcePacks implements ResourcePackRepository.Source { + + private static final Map CUSTOM_MOD_RESOURCES = new LinkedHashMap<>(); + + public static void registerBundledModResourcePack(String id, ModContainer mod, String directory) { + if (CUSTOM_MOD_RESOURCES.containsKey(id)) { + throw new IllegalStateException("Duplicate bundled mod resources '" + id + "'"); + } + + CUSTOM_MOD_RESOURCES.put(id, new CustomModResources(mod, directory)); + } + + @Override + public void loadResourcePacks(Consumer consumer) { + List packs = new ArrayList<>(); + + for (ModContainer mod : FabricLoader.getInstance().getAllMods()) { + if ("builtin".equals(mod.getMetadata().getType())) { + continue; + } + + packs.add(new ModResourcePack(mod)); + } + + ResourcePack compositePack = new BuiltInModResourcesPack(packs); + ResourcePackSummary compositeSummary = ResourcePackSummary.create( + compositePack, + true, + false, + PackPosition.BOTTOM + ); + + consumer.accept(compositeSummary); + + for (CustomModResources customResources : CUSTOM_MOD_RESOURCES.values()) { + ResourcePack pack = new ModResourcePack(customResources.mod, customResources.directory); + ResourcePackSummary summary = ResourcePackSummary.create( + pack, + true, + false, + PackPosition.BOTTOM + ); + + if (summary != null) { + consumer.accept(summary); + } + } + } + + private static class CustomModResources { + + final ModContainer mod; + final String directory; + + CustomModResources(ModContainer mod, String directory) { + this.mod = mod; + this.directory = directory; + } + } +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/repository/SimpleResourcePackRepository.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/repository/SimpleResourcePackRepository.java new file mode 100644 index 00000000..0fe4907f --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/repository/SimpleResourcePackRepository.java @@ -0,0 +1,163 @@ +package net.ornithemc.osl.resource.loader.impl.resource.repository; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.EnumMap; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import net.ornithemc.osl.resource.loader.api.client.ClientResourceLoaderEvents; +import net.ornithemc.osl.resource.loader.api.resource.ResourceType; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackRepository; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackSummary; +import net.ornithemc.osl.resource.loader.api.server.ServerResourceLoaderEvents; +import net.ornithemc.osl.resource.loader.impl.ResourceLoader; + +public class SimpleResourcePackRepository implements ResourcePackRepository { + + private static final Map INSTANCES = new EnumMap<>(ResourceType.class); + + private static SimpleResourcePackRepository forType(ResourceType type) { + return INSTANCES.computeIfAbsent(type, SimpleResourcePackRepository::new); + } + + public static SimpleResourcePackRepository client() { + return forType(ResourceType.CLIENT_ASSETS); + } + + public static SimpleResourcePackRepository server() { + return forType(ResourceType.SERVER_DATA); + } + + private final ResourceType type; + private final Set sources; + private final Map packs; + private final List available; + private final List selected; + + // these callbacks are used to sync vanilla pack lists + private Runnable discoveryCallback; + private Runnable selectionCallback; + + public SimpleResourcePackRepository(ResourceType type) { + this.type = type; + this.sources = new LinkedHashSet<>(); + this.packs = new LinkedHashMap<>(); + this.available = new ArrayList<>(); + this.selected = new ArrayList<>(); + } + + public void setCallbacks(Runnable discovery, Runnable selection) { + this.discoveryCallback = discovery; + this.selectionCallback = selection; + } + + public void init() { + if (this.type == ResourceType.CLIENT_ASSETS) { + ClientResourceLoaderEvents.INIT_RESOURCE_PACK_REPOSITORY.invoker().accept(this); + } else if (this.type == ResourceType.SERVER_DATA) { + ServerResourceLoaderEvents.INIT_RESOURCE_PACK_REPOSITORY.invoker().accept(this); + } + } + + @Override + public void addSource(Source source) { + this.sources.add(source); + } + + @Override + public void reload() { + this.close(); + + if (this.type == ResourceType.CLIENT_ASSETS) { + ClientResourceLoaderEvents.START_RESOURCE_PACKS_RELOAD.invoker().run(); + } else if (this.type == ResourceType.SERVER_DATA) { + ServerResourceLoaderEvents.START_RESOURCE_PACKS_RELOAD.invoker().run(); + } + + List selection = this.selected.stream().map(ResourcePackSummary::getId).collect(Collectors.toList()); + + this.discoverAvailablePacks(); + this.rebuildSelectedPacks(selection); + + if (this.type == ResourceType.CLIENT_ASSETS) { + ClientResourceLoaderEvents.END_RESOURCE_PACKS_RELOAD.invoker().run(); + } else if (this.type == ResourceType.SERVER_DATA) { + ServerResourceLoaderEvents.END_RESOURCE_PACKS_RELOAD.invoker().run(); + } + } + + private void discoverAvailablePacks() { + this.packs.clear(); + this.available.clear(); + + for (Source source : this.sources) { + source.loadResourcePacks(pack -> { + if (this.packs.containsKey(pack.getId())) { + ResourceLoader.LOGGER.info("Duplicate ResourcePack '{}'", pack.getId()); + } else { + this.packs.put(pack.getId(), pack); + this.available.add(0, pack); + } + }); + } + + if (this.discoveryCallback != null) { + this.discoveryCallback.run(); + } + } + + private void rebuildSelectedPacks(Collection selection) { + this.selected.clear(); + this.selected.addAll(this.getAvailablePacks(selection)); + + for (ResourcePackSummary pack : this.available) { + if (pack.isRequired() && !this.selected.contains(pack)) { + pack.getDefaultPosition().insert(this.selected, pack, false); + } + } + + if (this.selectionCallback != null) { + this.selectionCallback.run(); + } + } + + @Override + public Collection getAvailablePacks() { + return this.available; + } + + private List getAvailablePacks(Collection selection) { + return selection.stream().map(this.packs::get).filter(Objects::nonNull).collect(Collectors.toList()); + } + + @Override + public Collection getSelectedPacks() { + return this.selected; + } + + @Override + public void setSelectedPacks(Collection packs) { + this.rebuildSelectedPacks(packs); + } + + @Override + public Collection getUnselectedPacks() { + return this.available.stream().filter(p -> !this.selected.contains(p)).collect(Collectors.toList()); + } + + @Override + public ResourcePackSummary getPack(String id) { + return this.packs.get(id); + } + + @Override + public void close() { + this.available.forEach(ResourcePackSummary::close); + } +} diff --git a/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/repository/SimpleResourcePackSummary.java b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/repository/SimpleResourcePackSummary.java new file mode 100644 index 00000000..39d92b19 --- /dev/null +++ b/libraries/resource-loader/src/main/java/net/ornithemc/osl/resource/loader/impl/resource/repository/SimpleResourcePackSummary.java @@ -0,0 +1,114 @@ +package net.ornithemc.osl.resource.loader.impl.resource.repository; + +import java.io.IOException; +import java.util.function.Supplier; + +import net.ornithemc.osl.resource.loader.api.resource.pack.PackCompatibility; +import net.ornithemc.osl.resource.loader.api.resource.pack.PackPosition; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePack; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePackMetadata; +import net.ornithemc.osl.resource.loader.api.resource.repository.ResourcePackSummary; +import net.ornithemc.osl.resource.loader.impl.ResourceLoader; +import net.ornithemc.osl.text.api.TextComponent; +import net.ornithemc.osl.text.api.TextComponents; + +public class SimpleResourcePackSummary implements ResourcePackSummary { + + public static ResourcePackSummary create(ResourcePack pack, boolean required, boolean fixedPosition, PackPosition defaultPosition) { + return create(pack.getId(), required, fixedPosition, defaultPosition, () -> pack); + } + + public static ResourcePackSummary create(String id, boolean required, boolean fixedPosition, PackPosition defaultPosition, Supplier opener) { + try { + ResourcePack pack = opener.get(); + ResourcePackMetadata metadata = pack.getMetadata(ResourcePackMetadata.SECTION); + + if (metadata != null) { + return new SimpleResourcePackSummary(metadata, id, required, fixedPosition, defaultPosition, opener); + } else { + ResourceLoader.LOGGER.warn("Could not find pack metadata for pack {}", id); + } + } catch (IOException e) { + ResourceLoader.LOGGER.warn("Could not load pack metadata for pack {}: {}", id, e); + } + + return null; + }; + + private final TextComponent title; + private final TextComponent description; + private final String id; + private final boolean required; + private final boolean fixedPosition; + private final PackPosition defaultPosition; + private final PackCompatibility compatibility; + private final Supplier opener; + + public SimpleResourcePackSummary(ResourcePackMetadata metadata, String id, boolean required, boolean fixedPosition, PackPosition defaultPosition, Supplier opener) { + this( + TextComponents.literal(id), + metadata.description(), + id, + required, + fixedPosition, + defaultPosition, + PackCompatibility.forFormat(metadata.format()), + opener + ); + } + + public SimpleResourcePackSummary(TextComponent title, TextComponent description, String id, boolean required, boolean fixedPosition, PackPosition defaultPosition, PackCompatibility compatibility, Supplier opener) { + this.title = title; + this.description = description; + this.id = id; + this.required = required; + this.fixedPosition = fixedPosition; + this.defaultPosition = defaultPosition; + this.compatibility = compatibility; + this.opener = opener; + } + + @Override + public TextComponent getTitle() { + return this.title; + } + + @Override + public TextComponent getDescription() { + return this.description; + } + + @Override + public String getId() { + return this.id; + } + + @Override + public boolean isRequired() { + return this.required; + } + + @Override + public boolean isFixedPosition() { + return this.fixedPosition; + } + + @Override + public PackPosition getDefaultPosition() { + return this.defaultPosition; + } + + @Override + public PackCompatibility getCompatibility() { + return this.compatibility; + } + + @Override + public ResourcePack open() { + return this.opener.get(); + } + + @Override + public void close() { + } +} diff --git a/libraries/text-components/build.gradle b/libraries/text-components/build.gradle new file mode 100644 index 00000000..7bb43400 --- /dev/null +++ b/libraries/text-components/build.gradle @@ -0,0 +1,5 @@ +setUpLibrary(project) + +dependencies { + implementation 'com.google.code.gson:gson:2.8.0' +} diff --git a/libraries/text-components/gradle.properties b/libraries/text-components/gradle.properties new file mode 100644 index 00000000..1d71ad08 --- /dev/null +++ b/libraries/text-components/gradle.properties @@ -0,0 +1,6 @@ +library_id = text-components +library_name = Text Components +library_description = Versatile text components. +library_version = 0.1.0-alpha.1 + +osl_dependencies = core:>=0.7.0 diff --git a/libraries/text-components/src/main/java/net/ornithemc/osl/text/api/ClickEvent.java b/libraries/text-components/src/main/java/net/ornithemc/osl/text/api/ClickEvent.java new file mode 100644 index 00000000..65e722df --- /dev/null +++ b/libraries/text-components/src/main/java/net/ornithemc/osl/text/api/ClickEvent.java @@ -0,0 +1,64 @@ +package net.ornithemc.osl.text.api; + +import java.util.Locale; +import java.util.Objects; + +public class ClickEvent { + + private final Action action; + private final String value; + + public ClickEvent(Action action, String value) { + this.action = action; + this.value = value; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof ClickEvent)) { + return false; + } + ClickEvent event = (ClickEvent) o; + return this.action == event.action && Objects.equals(this.value, event.value); + } + + public Action getAction() { + return this.action; + } + + public String getValue() { + return this.value; + } + + public static ClickEvent openUrl(String url) { + return new ClickEvent(Action.OPEN_URL, url); + } + + public static ClickEvent runCommand(String command) { + return new ClickEvent(Action.RUN_COMMAND, command); + } + + public static ClickEvent suggestCommand(String command) { + return new ClickEvent(Action.SUGGEST_COMMAND, command); + } + + public static ClickEvent copyToClipboard(String text) { + return new ClickEvent(Action.COPY_TO_CLIPBOARD, text); + } + + public enum Action { + + OPEN_URL, RUN_COMMAND, SUGGEST_COMMAND, COPY_TO_CLIPBOARD; + + public String getName() { + return this.name().toLowerCase(Locale.ROOT); + } + + public static Action byName(String name) { + return Action.valueOf(name.toUpperCase()); + } + } +} diff --git a/libraries/text-components/src/main/java/net/ornithemc/osl/text/api/Formatting.java b/libraries/text-components/src/main/java/net/ornithemc/osl/text/api/Formatting.java new file mode 100644 index 00000000..1a577845 --- /dev/null +++ b/libraries/text-components/src/main/java/net/ornithemc/osl/text/api/Formatting.java @@ -0,0 +1,68 @@ +package net.ornithemc.osl.text.api; + +public enum Formatting { + + BLACK ('0', 0x000000), + DARK_BLUE ('1', 0x0000AA), + DARK_GREEN ('2', 0x00AA00), + DARK_AQUA ('3', 0x00AAAA), + DARK_RED ('4', 0xAA0000), + DARK_PURPLE ('5', 0xAA00AA), + GOLD ('6', 0xFFAA00), + GRAY ('7', 0xAAAAAA), + DARK_GRAY ('8', 0x555555), + BLUE ('9', 0x5555FF), + GREEN ('a', 0x55FF55), + AQUA ('b', 0x55FFFF), + RED ('c', 0xFF5555), + LIGHT_PURPLE ('d', 0xFF55FF), + YELLOW ('e', 0xFFFF55), + WHITE ('f', 0xFFFFFF), + OBFUSCATED ('k'), + BOLD ('l'), + STRIKETHROUGH('m'), + UNDERLINED ('n'), + ITALIC ('o'), + RESET ('r'); + + public static final char PREFIX = 'ยง'; + + final char code; + final Integer color; + + private Formatting(char code) { + this(code, null); + } + + private Formatting(char code, Integer color) { + this.code = code; + this.color = color; + } + + @Override + public String toString() { + return "" + PREFIX + this.code; + } + + public char getCode() { + return this.code; + } + + public boolean isColor() { + return this.color != null; + } + + public Integer getColor() { + return this.color; + } + + public static Formatting byCode(char code) { + for (Formatting f : Formatting.values()) { + if (f.code == code) { + return f; + } + } + + throw new IllegalStateException("unknown text formatting code " + code); + } +} diff --git a/libraries/text-components/src/main/java/net/ornithemc/osl/text/api/HoverEvent.java b/libraries/text-components/src/main/java/net/ornithemc/osl/text/api/HoverEvent.java new file mode 100644 index 00000000..332d3a32 --- /dev/null +++ b/libraries/text-components/src/main/java/net/ornithemc/osl/text/api/HoverEvent.java @@ -0,0 +1,52 @@ +package net.ornithemc.osl.text.api; + +import java.util.Locale; +import java.util.Objects; + +public class HoverEvent { + + private final Action action; + private final Object value; + + public HoverEvent(Action action, Object value) { + this.action = action; + this.value = value; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof HoverEvent)) { + return false; + } + HoverEvent event = (HoverEvent) o; + return this.action == event.action && Objects.equals(this.value, event.value); + } + + public Action getAction() { + return this.action; + } + + public T getValue() { + return (T) this.value; + } + + public static HoverEvent showText(TextComponent text) { + return new HoverEvent(Action.SHOW_TEXT, text); + } + + public enum Action { + + SHOW_TEXT; + + public String getName() { + return this.name().toLowerCase(Locale.ROOT); + } + + public static Action byName(String name) { + return Action.valueOf(name.toUpperCase()); + } + } +} diff --git a/libraries/text-components/src/main/java/net/ornithemc/osl/text/api/Style.java b/libraries/text-components/src/main/java/net/ornithemc/osl/text/api/Style.java new file mode 100644 index 00000000..48af6253 --- /dev/null +++ b/libraries/text-components/src/main/java/net/ornithemc/osl/text/api/Style.java @@ -0,0 +1,539 @@ +package net.ornithemc.osl.text.api; + +import java.lang.reflect.Type; +import java.util.Objects; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; + +public final class Style { + + public static final Style EMPTY = new Style(null, null, null, null, null, null, null, null, null); + + private final TextColor color; + private final Boolean bold; + private final Boolean italic; + private final Boolean underlined; + private final Boolean strikethrough; + private final Boolean obfuscated; + private final String insertion; + private final ClickEvent clickEvent; + private final HoverEvent hoverEvent; + + private Style( + TextColor color, + Boolean bold, + Boolean italic, + Boolean underlined, + Boolean strikethrough, + Boolean obfuscated, + String insertion, + ClickEvent clickEvent, + HoverEvent hoverEvent + ) { + this.color = color; + this.bold = bold; + this.italic = italic; + this.underlined = underlined; + this.strikethrough = strikethrough; + this.obfuscated = obfuscated; + this.insertion = insertion; + this.clickEvent = clickEvent; + this.hoverEvent = hoverEvent; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof Style)) { + return false; + } + Style style = (Style) o; + return this.color == style.color + && this.bold == style.bold + && this.italic == style.italic + && this.obfuscated == style.obfuscated + && this.strikethrough == style.strikethrough + && this.underlined == style.underlined + && Objects.equals(this.insertion, style.insertion) + && Objects.equals(this.clickEvent, style.clickEvent) + && Objects.equals(this.hoverEvent, style.hoverEvent); + } + + public TextColor getColor() { + return this.color; + } + + public boolean isBold() { + return this.bold == Boolean.TRUE; + } + + public boolean isItalic() { + return this.italic == Boolean.TRUE; + } + + public boolean isStrikethrough() { + return this.strikethrough == Boolean.TRUE; + } + + public boolean isUnderlined() { + return this.underlined == Boolean.TRUE; + } + + public boolean isObfuscated() { + return this.obfuscated == Boolean.TRUE; + } + + public String getInsertion() { + return this.insertion; + } + + public ClickEvent getClickEvent() { + return this.clickEvent; + } + + public HoverEvent getHoverEvent() { + return this.hoverEvent; + } + + public boolean isEmpty() { + return this == EMPTY; + } + + private static Style checkEmptyAfterChange(Style style, T oldValue, T newValue) { + return oldValue != null && newValue == null && style.equals(EMPTY) ? EMPTY : style; + } + + public Style withColor(int color) { + return this.withColor(TextColor.of(color)); + } + + public Style withColor(Formatting formatting) { + return this.withColor(TextColor.fromFormatting(formatting)); + } + + public Style withColor(TextColor color) { + return Objects.equals(this.color, color) + ? this + : checkEmptyAfterChange( + new Style( + color, + this.bold, + this.italic, + this.underlined, + this.strikethrough, + this.obfuscated, + this.insertion, + this.clickEvent, + this.hoverEvent + ), + this.color, + color + ); + } + + public Style withBold(Boolean bold) { + return Objects.equals(this.bold, bold) + ? this + : checkEmptyAfterChange( + new Style( + this.color, + bold, + this.italic, + this.underlined, + this.strikethrough, + this.obfuscated, + this.insertion, + this.clickEvent, + this.hoverEvent + ), + this.bold, + bold + ); + } + + public Style withItalic(Boolean italic) { + return Objects.equals(this.italic, italic) + ? this + : checkEmptyAfterChange( + new Style( + this.color, + this.bold, + italic, + this.underlined, + this.strikethrough, + this.obfuscated, + this.insertion, + this.clickEvent, + this.hoverEvent + ), + this.italic, + italic + ); + } + + public Style withUnderlined(Boolean underlined) { + return Objects.equals(this.underlined, underlined) + ? this + : checkEmptyAfterChange( + new Style( + this.color, + this.bold, + this.italic, + underlined, + this.strikethrough, + this.obfuscated, + this.insertion, + this.clickEvent, + this.hoverEvent + ), + this.underlined, + underlined + ); + } + + public Style withStrikethrough(Boolean strikethrough) { + return Objects.equals(this.strikethrough, strikethrough) + ? this + : checkEmptyAfterChange( + new Style( + this.color, + this.bold, + this.italic, + this.underlined, + strikethrough, + this.obfuscated, + this.insertion, + this.clickEvent, + this.hoverEvent + ), + this.strikethrough, + strikethrough + ); + } + + public Style withObfuscated(Boolean obfuscated) { + return Objects.equals(this.obfuscated, obfuscated) + ? this + : checkEmptyAfterChange( + new Style( + this.color, + this.bold, + this.italic, + this.underlined, + this.strikethrough, + obfuscated, + this.insertion, + this.clickEvent, + this.hoverEvent + ), + this.obfuscated, + obfuscated + ); + } + + public Style withInsertion(String insertion) { + return Objects.equals(this.insertion, insertion) + ? this + : checkEmptyAfterChange( + new Style( + this.color, + this.bold, + this.italic, + this.underlined, + this.strikethrough, + this.obfuscated, + insertion, + this.clickEvent, + this.hoverEvent + ), + this.insertion, + insertion + ); + } + + public Style withClickEvent(ClickEvent clickEvent) { + return Objects.equals(this.clickEvent, clickEvent) + ? this + : checkEmptyAfterChange( + new Style( + this.color, + this.bold, + this.italic, + this.underlined, + this.strikethrough, + this.obfuscated, + this.insertion, + clickEvent, + this.hoverEvent + ), + this.clickEvent, + clickEvent + ); + } + + public Style withHoverEvent(HoverEvent hoverEvent) { + return Objects.equals(this.hoverEvent, hoverEvent) + ? this + : checkEmptyAfterChange( + new Style( + this.color, + this.bold, + this.italic, + this.underlined, + this.strikethrough, + this.obfuscated, + this.insertion, + this.clickEvent, + hoverEvent + ), + this.hoverEvent, + hoverEvent + ); + } + + public Style withFormatting(Formatting... formattings) { + TextColor color = this.color; + Boolean bold = this.bold; + Boolean italic = this.italic; + Boolean strikethrough = this.strikethrough; + Boolean underlined = this.underlined; + Boolean obfuscated = this.obfuscated; + + for (Formatting formatting : formattings) { + switch (formatting) { + case RESET: + return EMPTY; + case OBFUSCATED: + obfuscated = true; + break; + case BOLD: + bold = true; + break; + case STRIKETHROUGH: + strikethrough = true; + break; + case UNDERLINED: + underlined = true; + break; + case ITALIC: + italic = true; + break; + default: + if (formatting.isColor()) { + color = TextColor.fromFormatting(formatting); + } + } + } + + return new Style( + color, + bold, + italic, + underlined, + strikethrough, + obfuscated, + this.insertion, + this.clickEvent, + this.hoverEvent + ); + } + + public Style withStyle(Style style) { + if (this == EMPTY) { + return style; + } + if (style == EMPTY) { + return this; + } + return new Style( + this.color != null ? this.color : style.color, + this.bold != null ? this.bold : style.bold, + this.italic != null ? this.italic : style.italic, + this.underlined != null ? this.underlined : style.underlined, + this.strikethrough != null ? this.strikethrough : style.strikethrough, + this.obfuscated != null ? this.obfuscated : style.obfuscated, + this.insertion != null ? this.insertion : style.insertion, + this.clickEvent != null ? this.clickEvent : style.clickEvent, + this.hoverEvent != null ? this.hoverEvent : style.hoverEvent + ); + } + + public void apply(StringBuilder sb) { + if (this.color != null) { + Formatting formatting = this.color.getFormatting(); + + if (formatting != null) { + sb.append(formatting); + } + } + if (this.bold != null) { + sb.append(Formatting.BOLD); + } + if (this.italic != null) { + sb.append(Formatting.ITALIC); + } + if (this.underlined != null) { + sb.append(Formatting.UNDERLINED); + } + if (this.strikethrough != null) { + sb.append(Formatting.STRIKETHROUGH); + } + if (this.obfuscated != null) { + sb.append(Formatting.OBFUSCATED); + } + } + + public static class Serializer implements JsonDeserializer