diff --git a/build.gradle b/build.gradle index 485198b..9a66d76 100644 --- a/build.gradle +++ b/build.gradle @@ -18,17 +18,6 @@ repositories { // for more information about repositories. } -loom { - splitEnvironmentSourceSets() - - mods { - "env_json" { - sourceSet sourceSets.main - } - } - -} - dependencies { // To change the versions see the gradle.properties file minecraft "com.mojang:minecraft:${project.minecraft_version}" @@ -44,6 +33,10 @@ dependencies { // modImplementation "net.fabricmc.fabric-api:fabric-api-deprecated:${project.fabric_version}" } +loom { + accessWidenerPath = file("src/main/resources/env_json.accesswidener") +} + processResources { inputs.property "version", project.version diff --git a/src/main/java/fr/firstmegagame4/env/json/api/resource/ExtendedResource.java b/src/main/java/fr/firstmegagame4/env/json/api/resource/ExtendedResource.java new file mode 100644 index 0000000..dd21ee1 --- /dev/null +++ b/src/main/java/fr/firstmegagame4/env/json/api/resource/ExtendedResource.java @@ -0,0 +1,34 @@ +package fr.firstmegagame4.env.json.api.resource; + +import fr.firstmegagame4.env.json.api.EnvJson; +import fr.firstmegagame4.env.json.impl.resource.ExtendedResourceImpl; +import net.minecraft.resource.Resource; +import net.minecraft.resource.ResourcePack; +import net.minecraft.resource.metadata.ResourceMetadata; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; + +public interface ExtendedResource { + + static ExtendedResource of(Resource resource) { + return ExtendedResourceImpl.of(resource); + } + + ResourcePack getPack(); + + String getResourcePackName(); + + boolean isAlwaysStable(); + + InputStream getInputStream() throws IOException; + + BufferedReader getReader() throws IOException; + + ResourceMetadata getMetadata() throws IOException; + + EnvJson getEnvJson() throws IOException; + + Resource asResource(); +} diff --git a/src/main/java/fr/firstmegagame4/env/json/impl/resource/ExtendedResourceImpl.java b/src/main/java/fr/firstmegagame4/env/json/impl/resource/ExtendedResourceImpl.java new file mode 100644 index 0000000..0496e50 --- /dev/null +++ b/src/main/java/fr/firstmegagame4/env/json/impl/resource/ExtendedResourceImpl.java @@ -0,0 +1,41 @@ +package fr.firstmegagame4.env.json.impl.resource; + +import fr.firstmegagame4.env.json.api.EnvJson; +import fr.firstmegagame4.env.json.api.resource.ExtendedResource; +import fr.firstmegagame4.env.json.mixin.ResourceAccessor; +import net.minecraft.resource.InputSupplier; +import net.minecraft.resource.Resource; +import net.minecraft.resource.ResourcePack; +import net.minecraft.resource.metadata.ResourceMetadata; +import org.jetbrains.annotations.ApiStatus; + +import java.io.IOException; +import java.io.InputStream; + +@ApiStatus.Internal +public class ExtendedResourceImpl extends Resource implements ExtendedResource { + + public static ExtendedResource of(Resource resource) { + ResourceAccessor accessor = (ResourceAccessor) resource; + ResourceDuckInterface ducked = (ResourceDuckInterface) resource; + return new ExtendedResourceImpl(accessor.getPack(), accessor.getInputSupplier(), accessor.getMetadataSupplier(), ducked.env_json$getEnvJsonSupplier(), accessor.getMetadata(), ducked.env_json$getEnvJson()); + } + + private ExtendedResourceImpl(ResourcePack pack, InputSupplier inputSupplier, InputSupplier metadataSupplier, InputSupplier envJsonSupplier, ResourceMetadata resourceMetadata, EnvJson envJson) { + super(pack, inputSupplier, metadataSupplier); + ResourceDuckInterface ducked = (ResourceDuckInterface) this; + ducked.env_json$initEnvJsonSupplier(envJsonSupplier); + ducked.env_json$initEnvJson(envJson); + } + + @Override + public EnvJson getEnvJson() throws IOException { + ResourceDuckInterface ducked = (ResourceDuckInterface) this; + return ducked.env_json$getEnvJson() == null ? ducked.en_json$applyEnvJson() : ducked.env_json$getEnvJson(); + } + + @Override + public Resource asResource() { + return this; + } +} diff --git a/src/main/java/fr/firstmegagame4/env/json/impl/resource/ResourceDuckInterface.java b/src/main/java/fr/firstmegagame4/env/json/impl/resource/ResourceDuckInterface.java new file mode 100644 index 0000000..eb5c5b1 --- /dev/null +++ b/src/main/java/fr/firstmegagame4/env/json/impl/resource/ResourceDuckInterface.java @@ -0,0 +1,21 @@ +package fr.firstmegagame4.env.json.impl.resource; + +import fr.firstmegagame4.env.json.api.EnvJson; +import net.minecraft.resource.InputSupplier; +import org.jetbrains.annotations.ApiStatus; + +import java.io.IOException; + +@ApiStatus.Internal +public interface ResourceDuckInterface { + + void env_json$initEnvJsonSupplier(InputSupplier envJsonSupplier); + + void env_json$initEnvJson(EnvJson envJson); + + EnvJson en_json$applyEnvJson() throws IOException; + + InputSupplier env_json$getEnvJsonSupplier(); + + EnvJson env_json$getEnvJson(); +} diff --git a/src/main/java/fr/firstmegagame4/env/json/mixin/NamespaceResourceManagerMixin.java b/src/main/java/fr/firstmegagame4/env/json/mixin/NamespaceResourceManagerMixin.java new file mode 100644 index 0000000..2996131 --- /dev/null +++ b/src/main/java/fr/firstmegagame4/env/json/mixin/NamespaceResourceManagerMixin.java @@ -0,0 +1,104 @@ +package fr.firstmegagame4.env.json.mixin; + +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.llamalad7.mixinextras.sugar.Local; +import com.llamalad7.mixinextras.sugar.Share; +import com.llamalad7.mixinextras.sugar.ref.LocalRef; +import fr.firstmegagame4.env.json.api.EnvJson; +import fr.firstmegagame4.env.json.impl.resource.ResourceDuckInterface; +import net.minecraft.resource.*; +import net.minecraft.util.Identifier; +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 java.io.IOException; +import java.io.InputStream; +import java.util.List; + +@Mixin(NamespaceResourceManager.class) +public class NamespaceResourceManagerMixin { + + @Unique + private static final EnvJson ENV_JSON_NONE = null; + + @Shadow + @Final + protected List packList; + + @Shadow + @Final + private ResourceType type; + + @ModifyExpressionValue(method = "getResource", at = @At(value = "INVOKE", target = "Lnet/minecraft/resource/NamespaceResourceManager;createResource(Lnet/minecraft/resource/ResourcePack;Lnet/minecraft/util/Identifier;Lnet/minecraft/resource/InputSupplier;Lnet/minecraft/resource/InputSupplier;)Lnet/minecraft/resource/Resource;")) + private Resource onResourceCreated(Resource original, Identifier identifier, @Local(ordinal = 0) int i) { + ((ResourceDuckInterface) original).env_json$initEnvJsonSupplier(this.createEnvJsonSupplier(identifier, i)); + return original; + } + + @WrapOperation(method = "getAllResources", at = @At(value = "INVOKE", target = "Lnet/minecraft/resource/ResourcePack;open(Lnet/minecraft/resource/ResourceType;Lnet/minecraft/util/Identifier;)Lnet/minecraft/resource/InputSupplier;")) + private InputSupplier onResourceAdd(ResourcePack instance, ResourceType resourceType, Identifier identifier, Operation> original, @Local(ordinal = 0) boolean bl, @Share("envJsonInputSupplier") LocalRef> ref) { + InputSupplier inputSupplier = original.call(instance, resourceType, identifier); + Identifier envJsonPath = this.getEnvJsonPath(identifier); + if (inputSupplier != null) { + InputSupplier envJsonInputSupplier; + if (bl) { + envJsonInputSupplier = () -> null; + } + else { + envJsonInputSupplier = () -> { + InputSupplier supplier = instance.open(resourceType, envJsonPath); + return supplier != null ? this.loadEnvJson(supplier) : NamespaceResourceManagerMixin.ENV_JSON_NONE; + }; + } + ref.set(envJsonInputSupplier); + } + return inputSupplier; + } + + @WrapOperation(method = "getAllResources", at = @At(value = "INVOKE", target = "Ljava/util/List;add(Ljava/lang/Object;)Z")) + private boolean onResourceCreated(List instance, E e, Operation original, @Share("envJsonInputSupplier") LocalRef> ref) { + ((ResourceDuckInterface) e).env_json$initEnvJsonSupplier(ref.get()); + // noinspection MixinExtrasOperationParameters + return original.call(instance, e); + } + + @Unique + private Identifier getEnvJsonPath(Identifier identifier) { + return identifier.withPath(identifier.getPath() + ".env.json"); + } + + @Unique + private InputSupplier createEnvJsonSupplier(Identifier identifier, int index) { + return () -> { + Identifier envJsonPath = this.getEnvJsonPath(identifier); + // noinspection OverflowingLoopIndex + for (int i = this.packList.size() - 1; i >= index; i++) { + NamespaceResourceManager.FilterablePack filterablePack = this.packList.get(i); + ResourcePack resourcePack = filterablePack.underlying(); + if (resourcePack != null) { + InputSupplier inputSupplier = resourcePack.open(this.type, envJsonPath); + if (inputSupplier != null) { + return this.loadEnvJson(inputSupplier); + } + } + if (filterablePack.isFiltered(envJsonPath)) { + break; + } + } + return null; + }; + } + + @Unique + private EnvJson loadEnvJson(InputSupplier supplier) throws IOException { + InputStream inputStream = supplier.get(); + EnvJson envJson = EnvJson.parse(inputStream); + inputStream.close(); + return envJson; + } +} diff --git a/src/main/java/fr/firstmegagame4/env/json/mixin/ResourceAccessor.java b/src/main/java/fr/firstmegagame4/env/json/mixin/ResourceAccessor.java new file mode 100644 index 0000000..5cb610c --- /dev/null +++ b/src/main/java/fr/firstmegagame4/env/json/mixin/ResourceAccessor.java @@ -0,0 +1,28 @@ +package fr.firstmegagame4.env.json.mixin; + +import net.minecraft.resource.InputSupplier; +import net.minecraft.resource.Resource; +import net.minecraft.resource.ResourcePack; +import net.minecraft.resource.metadata.ResourceMetadata; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.io.InputStream; + +@Mixin(Resource.class) +public interface ResourceAccessor { + + @Accessor + ResourcePack getPack(); + + @Accessor + InputSupplier getInputSupplier(); + + @Accessor + InputSupplier getMetadataSupplier(); + + @Nullable + @Accessor + ResourceMetadata getMetadata(); +} diff --git a/src/main/java/fr/firstmegagame4/env/json/mixin/ResourceMixin.java b/src/main/java/fr/firstmegagame4/env/json/mixin/ResourceMixin.java new file mode 100644 index 0000000..3e434fa --- /dev/null +++ b/src/main/java/fr/firstmegagame4/env/json/mixin/ResourceMixin.java @@ -0,0 +1,45 @@ +package fr.firstmegagame4.env.json.mixin; + +import fr.firstmegagame4.env.json.api.EnvJson; +import fr.firstmegagame4.env.json.impl.resource.ResourceDuckInterface; +import net.minecraft.resource.InputSupplier; +import net.minecraft.resource.Resource; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; + +import java.io.IOException; + +@Mixin(Resource.class) +public class ResourceMixin implements ResourceDuckInterface { + + @Unique + private InputSupplier envJsonSupplier = null; + + @Unique + private EnvJson envJson = null; + + @Override + public void env_json$initEnvJsonSupplier(InputSupplier envJsonSupplier) { + this.envJsonSupplier = envJsonSupplier; + } + + @Override + public void env_json$initEnvJson(EnvJson envJson) { + this.envJson = envJson; + } + + @Override + public EnvJson en_json$applyEnvJson() throws IOException { + return this.envJson = this.envJsonSupplier.get(); + } + + @Override + public InputSupplier env_json$getEnvJsonSupplier() { + return this.envJsonSupplier; + } + + @Override + public EnvJson env_json$getEnvJson() { + return this.envJson; + } +} diff --git a/src/main/resources/env_json.accesswidener b/src/main/resources/env_json.accesswidener new file mode 100644 index 0000000..07a0b76 --- /dev/null +++ b/src/main/resources/env_json.accesswidener @@ -0,0 +1,3 @@ +accessWidener v1 named + +accessible class net/minecraft/resource/NamespaceResourceManager$FilterablePack \ No newline at end of file diff --git a/src/main/resources/env_json.mixins.json b/src/main/resources/env_json.mixins.json new file mode 100644 index 0000000..8800771 --- /dev/null +++ b/src/main/resources/env_json.mixins.json @@ -0,0 +1,14 @@ +{ + "required": true, + "package": "fr.firstmegagame4.env.json.mixin", + "compatibilityLevel": "JAVA_17", + "mixins": [ + "NamespaceResourceManagerMixin", + "ResourceAccessor", + "ResourceMixin" + ], + "client": [], + "injectors": { + "defaultRequire": 1 + } +}