mirror of
https://github.com/FabricMC/fabric.git
synced 2025-04-21 03:10:54 -04:00
Resource loader changes and built-in mod resource/data packs API (#1011)
* WIP built-in resource packs API. * Add built-in resource pack register API and fix old injection methods. * Fix code style. * Fix code style. * Add documentation. * Drop useless else. * Fix resource packs and data packs isolation issues, and more. * Move ResourcePackManagerAccessor to its own accessor mixin. * Make the built-in mod pack test mod work on server too because data pack part. * Add new argument to built-in pack method and make mod data packs always active. * Add documentation. * Complete documentation in GameOptions mixin. * Remove register built-in pack overload as Player requested.
This commit is contained in:
parent
0ba3dd89ec
commit
8072a3a990
22 changed files with 453 additions and 183 deletions
fabric-resource-loader-v0/src
main
java/net/fabricmc/fabric
api/resource
impl/resource/loader
ModNioResourcePack.javaModResourcePackCreator.javaModResourcePackUtil.javaResourceManagerHelperImpl.java
mixin/resource/loader
resources
testmod
|
@ -18,8 +18,10 @@ package net.fabricmc.fabric.api.resource;
|
|||
|
||||
import net.minecraft.resource.ResourceManager;
|
||||
import net.minecraft.resource.ResourceType;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.fabric.impl.resource.loader.ResourceManagerHelperImpl;
|
||||
import net.fabricmc.loader.api.ModContainer;
|
||||
|
||||
/**
|
||||
* Helper for working with {@link ResourceManager} instances.
|
||||
|
@ -52,4 +54,27 @@ public interface ResourceManagerHelper {
|
|||
static ResourceManagerHelper get(ResourceType type) {
|
||||
return ResourceManagerHelperImpl.get(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a built-in resource pack.
|
||||
*
|
||||
* <p>A built-in resource pack is an extra resource pack provided by your mod which is not always active, it's similar to the "Programmer Art" resource pack.
|
||||
*
|
||||
* <p>Why and when to use it? A built-in resource pack should be used to provide extra assets/data that should be optional with your mod but still directly provided by it.
|
||||
* For example it could provide textures of your mod in another resolution, or could allow to provide different styles of your assets.
|
||||
*
|
||||
* <p>The {@code subPath} corresponds to a path in the JAR file which points to the resource pack folder. For example the subPath can be {@code "resourcepacks/extra"}.
|
||||
*
|
||||
* <p>Note about the enabled by default parameter: a resource pack cannot be enabled by default, only data packs can.
|
||||
* Making this work for resource packs is near impossible without touching how Vanilla handles disabled resource packs.
|
||||
*
|
||||
* @param id The identifier of the resource pack.
|
||||
* @param subPath The sub path in the mod resources.
|
||||
* @param container The mod container.
|
||||
* @param enabledByDefault True if enabled by default, else false.
|
||||
* @return True if successfully registered the resource pack, else false.
|
||||
*/
|
||||
static boolean registerBuiltinResourcePack(Identifier id, String subPath, ModContainer container, boolean enabledByDefault) {
|
||||
return ResourceManagerHelperImpl.registerBuiltinResourcePack(id, subPath, container, enabledByDefault);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,14 +50,19 @@ public class ModNioResourcePack extends AbstractFileResourcePack implements ModR
|
|||
private final boolean cacheable;
|
||||
private final AutoCloseable closer;
|
||||
private final String separator;
|
||||
private final String name;
|
||||
private final boolean defaultEnabled;
|
||||
|
||||
public ModNioResourcePack(ModMetadata modInfo, Path path, AutoCloseable closer) {
|
||||
public ModNioResourcePack(ModMetadata modInfo, Path path, AutoCloseable closer, String name, boolean defaultEnabled) {
|
||||
super(null);
|
||||
this.modInfo = modInfo;
|
||||
this.basePath = path.toAbsolutePath().normalize();
|
||||
this.cacheable = false; /* TODO */
|
||||
this.closer = closer;
|
||||
this.separator = basePath.getFileSystem().getSeparator();
|
||||
// Specific to registered built-in resource packs.
|
||||
this.name = name;
|
||||
this.defaultEnabled = defaultEnabled;
|
||||
}
|
||||
|
||||
private Path getPath(String filename) {
|
||||
|
@ -225,8 +230,16 @@ public class ModNioResourcePack extends AbstractFileResourcePack implements ModR
|
|||
return modInfo;
|
||||
}
|
||||
|
||||
public boolean shouldBeEnabledByDefault() {
|
||||
return this.defaultEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
if (this.name != null) {
|
||||
return this.name; // Built-in resource pack provided by a mod, the name is overriden.
|
||||
}
|
||||
|
||||
return ModResourcePackUtil.getName(modInfo);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,8 +29,12 @@ import net.minecraft.text.TranslatableText;
|
|||
|
||||
import net.fabricmc.fabric.api.resource.ModResourcePack;
|
||||
|
||||
/**
|
||||
* Represents a resource pack provider for mods and built-in mods resource packs.
|
||||
*/
|
||||
public class ModResourcePackCreator implements ResourcePackProvider {
|
||||
public static final ResourcePackSource RESOURCE_PACK_SOURCE = text -> new TranslatableText("pack.nameAndSource", text, new TranslatableText("pack.source.fabricmod"));
|
||||
public static final ModResourcePackCreator CLIENT_RESOURCE_PACK_PROVIDER = new ModResourcePackCreator(ResourceType.CLIENT_RESOURCES);
|
||||
private final ResourceType type;
|
||||
|
||||
public ModResourcePackCreator(ResourceType type) {
|
||||
|
@ -39,7 +43,19 @@ public class ModResourcePackCreator implements ResourcePackProvider {
|
|||
|
||||
@Override
|
||||
public void register(Consumer<ResourcePackProfile> consumer, ResourcePackProfile.Factory factory) {
|
||||
// TODO: "vanilla" does not emit a message; neither should a modded datapack
|
||||
/*
|
||||
Register order rule in this provider:
|
||||
1. Mod resource packs
|
||||
2. Mod built-in resource packs
|
||||
|
||||
Register order rule globally:
|
||||
1. Default and Vanilla built-in resource packs
|
||||
2. Mod resource packs
|
||||
3. Mod built-in resource packs
|
||||
4. User resource packs
|
||||
*/
|
||||
|
||||
// Build a list of mod resource packs.
|
||||
List<ResourcePack> packs = new ArrayList<>();
|
||||
ModResourcePackUtil.appendModResourcePacks(packs, type);
|
||||
|
||||
|
@ -48,13 +64,19 @@ public class ModResourcePackCreator implements ResourcePackProvider {
|
|||
throw new RuntimeException("Not a ModResourcePack!");
|
||||
}
|
||||
|
||||
// Make the resource pack profile for mod resource packs.
|
||||
// Mod resource packs must always be enabled to avoid issues
|
||||
// and inserted on top to ensure that they are applied before user resource packs and after default/programmer art resource pack.
|
||||
ResourcePackProfile resourcePackProfile = ResourcePackProfile.of("fabric/" + ((ModResourcePack) pack).getFabricModMetadata().getId(),
|
||||
false, () -> pack, factory, ResourcePackProfile.InsertionPosition.TOP,
|
||||
true, () -> pack, factory, ResourcePackProfile.InsertionPosition.TOP,
|
||||
RESOURCE_PACK_SOURCE);
|
||||
|
||||
if (resourcePackProfile != null) {
|
||||
consumer.accept(resourcePackProfile);
|
||||
}
|
||||
}
|
||||
|
||||
// Register all built-in resource packs provided by mods.
|
||||
ResourceManagerHelperImpl.registerBuiltinResourcePacks(this.type, consumer, factory);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,16 +21,12 @@ import java.nio.file.Path;
|
|||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.client.resource.Format4ResourcePack;
|
||||
import net.minecraft.resource.ResourcePack;
|
||||
import net.minecraft.resource.ResourceType;
|
||||
import net.minecraft.resource.DefaultResourcePack;
|
||||
|
||||
import net.fabricmc.fabric.mixin.resource.loader.MixinFormat4ResourcePack;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.fabricmc.loader.api.ModContainer;
|
||||
import net.fabricmc.loader.api.metadata.ModMetadata;
|
||||
|
@ -50,7 +46,7 @@ public final class ModResourcePackUtil {
|
|||
}
|
||||
|
||||
Path path = container.getRootPath();
|
||||
ResourcePack pack = new ModNioResourcePack(container.getMetadata(), path, null);
|
||||
ResourcePack pack = new ModNioResourcePack(container.getMetadata(), path, null, null, true);
|
||||
|
||||
if (!pack.getNamespaces(type).isEmpty()) {
|
||||
packList.add(pack);
|
||||
|
@ -87,38 +83,4 @@ public final class ModResourcePackUtil {
|
|||
return "Fabric Mod \"" + info.getId() + "\"";
|
||||
}
|
||||
}
|
||||
|
||||
public static void modifyResourcePackList(List<ResourcePack> list) {
|
||||
List<ResourcePack> oldList = Lists.newArrayList(list);
|
||||
list.clear();
|
||||
|
||||
boolean appended = false;
|
||||
|
||||
for (int i = 0; i < oldList.size(); i++) {
|
||||
ResourcePack pack = oldList.get(i);
|
||||
list.add(pack);
|
||||
|
||||
boolean isDefaultResources = pack instanceof DefaultResourcePack;
|
||||
|
||||
if (!isDefaultResources && pack instanceof Format4ResourcePack) {
|
||||
MixinFormat4ResourcePack fixer = (MixinFormat4ResourcePack) pack;
|
||||
isDefaultResources = fixer.getParent() instanceof DefaultResourcePack;
|
||||
}
|
||||
|
||||
if (isDefaultResources) {
|
||||
ModResourcePackUtil.appendModResourcePacks(list, ResourceType.CLIENT_RESOURCES);
|
||||
appended = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!appended) {
|
||||
StringBuilder builder = new StringBuilder("Fabric could not find resource pack injection location!");
|
||||
|
||||
for (ResourcePack rp : oldList) {
|
||||
builder.append("\n - ").append(rp.getName()).append(" (").append(rp.getClass().getName()).append(")");
|
||||
}
|
||||
|
||||
throw new RuntimeException(builder.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
package net.fabricmc.fabric.impl.resource.loader;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
|
@ -23,20 +25,26 @@ import java.util.LinkedHashSet;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import net.minecraft.resource.ResourcePackProfile;
|
||||
import net.minecraft.resource.ResourcePackSource;
|
||||
import net.minecraft.resource.ResourceReloadListener;
|
||||
import net.minecraft.resource.ResourceType;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.Pair;
|
||||
|
||||
import net.fabricmc.loader.api.ModContainer;
|
||||
import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener;
|
||||
import net.fabricmc.fabric.api.resource.ResourceManagerHelper;
|
||||
|
||||
public class ResourceManagerHelperImpl implements ResourceManagerHelper {
|
||||
private static final Map<ResourceType, ResourceManagerHelperImpl> registryMap = new HashMap<>();
|
||||
private static final Set<Pair<String, ModNioResourcePack>> builtinResourcePacks = new HashSet<>();
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
|
||||
private final Set<Identifier> addedListenerIds = new HashSet<>();
|
||||
|
@ -46,6 +54,48 @@ public class ResourceManagerHelperImpl implements ResourceManagerHelper {
|
|||
return registryMap.computeIfAbsent(type, (t) -> new ResourceManagerHelperImpl());
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a built-in resource pack. Internal implementation.
|
||||
*
|
||||
* @param id The identifier of the resource pack.
|
||||
* @param subPath The sub path in the mod resources.
|
||||
* @param container The mod container.
|
||||
* @param enabledByDefault True if enabled by default, else false.
|
||||
* @return True if successfully registered the resource pack, else false.
|
||||
*
|
||||
* @see ResourceManagerHelper#registerBuiltinResourcePack(Identifier, String, ModContainer, boolean)
|
||||
*/
|
||||
public static boolean registerBuiltinResourcePack(Identifier id, String subPath, ModContainer container, boolean enabledByDefault) {
|
||||
String separator = container.getRootPath().getFileSystem().getSeparator();
|
||||
subPath = subPath.replace("/", separator);
|
||||
|
||||
Path resourcePackPath = container.getRootPath().resolve(subPath).toAbsolutePath().normalize();
|
||||
|
||||
if (!Files.exists(resourcePackPath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String name = id.getNamespace() + "/" + id.getPath();
|
||||
builtinResourcePacks.add(new Pair<>(name, new ModNioResourcePack(container.getMetadata(), resourcePackPath, null, name, enabledByDefault)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void registerBuiltinResourcePacks(ResourceType resourceType, Consumer<ResourcePackProfile> consumer, ResourcePackProfile.Factory factory) {
|
||||
// Loop through each registered built-in resource packs and add them if valid.
|
||||
for (Pair<String, ModNioResourcePack> entry : builtinResourcePacks) {
|
||||
// Add the built-in pack only if namespaces for the specified resource type are present.
|
||||
if (!entry.getRight().getNamespaces(resourceType).isEmpty()) {
|
||||
// Make the resource pack profile for built-in pack, should never be always enabled.
|
||||
ResourcePackProfile profile = ResourcePackProfile.of(entry.getLeft(), false,
|
||||
entry::getRight, factory, ResourcePackProfile.InsertionPosition.TOP, ResourcePackSource.PACK_SOURCE_BUILTIN);
|
||||
if (profile != null) {
|
||||
consumer.accept(profile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void sort(ResourceType type, List<ResourceReloadListener> listeners) {
|
||||
ResourceManagerHelperImpl instance = registryMap.get(type);
|
||||
|
||||
|
|
|
@ -19,11 +19,11 @@ package net.fabricmc.fabric.mixin.resource.loader;
|
|||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
import net.minecraft.client.resource.Format4ResourcePack;
|
||||
import net.minecraft.resource.ResourcePack;
|
||||
import net.minecraft.resource.FileResourcePackProvider;
|
||||
import net.minecraft.resource.ResourcePackSource;
|
||||
|
||||
@Mixin(Format4ResourcePack.class)
|
||||
public interface MixinFormat4ResourcePack {
|
||||
@Accessor
|
||||
ResourcePack getParent();
|
||||
@Mixin(FileResourcePackProvider.class)
|
||||
public interface FileResourcePackProviderAccessor {
|
||||
@Accessor("field_25345")
|
||||
ResourcePackSource getResourcePackSource();
|
||||
}
|
|
@ -16,25 +16,23 @@
|
|||
|
||||
package net.fabricmc.fabric.mixin.resource.loader;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
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 org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import net.minecraft.resource.ResourcePack;
|
||||
import net.minecraft.resource.ResourcePackManager;
|
||||
import net.minecraft.resource.ResourcePackProfile;
|
||||
import net.minecraft.client.resource.ClientBuiltinResourcePackProvider;
|
||||
|
||||
import net.fabricmc.fabric.impl.resource.loader.ModResourcePackUtil;
|
||||
import net.fabricmc.fabric.impl.resource.loader.ModResourcePackCreator;
|
||||
|
||||
@Mixin(ResourcePackManager.class)
|
||||
public class MixinResourcePackManagerClient {
|
||||
@Inject(method = "createResourcePacks", at = @At("RETURN"), cancellable = true)
|
||||
public void createResourcePacks(CallbackInfoReturnable<List<ResourcePack>> infoReturnable) {
|
||||
List<ResourcePack> list = new ArrayList<>(infoReturnable.getReturnValue());
|
||||
ModResourcePackUtil.modifyResourcePackList(list);
|
||||
infoReturnable.setReturnValue(list);
|
||||
@Mixin(ClientBuiltinResourcePackProvider.class)
|
||||
public class MixinClientBuiltinResourcePackProvider {
|
||||
@Inject(method = "register", at = @At("RETURN"))
|
||||
private void addBuiltinResourcePacks(Consumer<ResourcePackProfile> consumer, ResourcePackProfile.Factory factory, CallbackInfo ci) {
|
||||
// Register mod and built-in resource packs after the vanilla built-in resource packs are registered.
|
||||
ModResourcePackCreator.CLIENT_RESOURCE_PACK_PROVIDER.register(consumer, factory);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.resource.loader;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
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.ModifyArg;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import net.minecraft.client.gui.screen.world.CreateWorldScreen;
|
||||
import net.minecraft.resource.DataPackSettings;
|
||||
import net.minecraft.resource.ResourcePack;
|
||||
import net.minecraft.resource.ResourcePackManager;
|
||||
import net.minecraft.resource.ResourcePackProfile;
|
||||
import net.minecraft.resource.ResourceType;
|
||||
|
||||
import net.fabricmc.fabric.impl.resource.loader.ModNioResourcePack;
|
||||
import net.fabricmc.fabric.impl.resource.loader.ModResourcePackCreator;
|
||||
|
||||
@Mixin(CreateWorldScreen.class)
|
||||
public class MixinCreateWorldScreen {
|
||||
@Shadow
|
||||
private ResourcePackManager field_25792;
|
||||
|
||||
@Inject(method = "method_30296", at = @At(value = "INVOKE", target = "Lnet/minecraft/resource/ResourcePackManager;scanPacks()V", shift = At.Shift.BEFORE))
|
||||
private void onScanPacks(CallbackInfoReturnable<Pair<File, ResourcePackManager>> cir) {
|
||||
// Allow to display built-in data packs in the data pack selection screen at world creation.
|
||||
((ResourcePackManagerAccessor) this.field_25792).getProviders().add(new ModResourcePackCreator(ResourceType.SERVER_DATA));
|
||||
}
|
||||
|
||||
@ModifyArg(method = "method_31130", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/world/CreateWorldScreen;<init>(Lnet/minecraft/client/gui/screen/Screen;Lnet/minecraft/resource/DataPackSettings;Lnet/minecraft/client/gui/screen/world/MoreOptionsDialog;)V"), index = 1)
|
||||
private static DataPackSettings onNew(DataPackSettings settings) {
|
||||
ModResourcePackCreator modResourcePackCreator = new ModResourcePackCreator(ResourceType.SERVER_DATA);
|
||||
List<ResourcePackProfile> moddedResourcePacks = new ArrayList<>();
|
||||
modResourcePackCreator.register(moddedResourcePacks::add, ResourcePackProfile::new);
|
||||
|
||||
List<String> enabled = new ArrayList<>(settings.getEnabled());
|
||||
List<String> disabled = new ArrayList<>(settings.getDisabled());
|
||||
|
||||
// This ensure that any built-in registered data packs by mods which needs to be enabled by default are
|
||||
// as the data pack screen automatically put any data pack as disabled except the Default data pack.
|
||||
for (ResourcePackProfile profile : moddedResourcePacks) {
|
||||
ResourcePack pack = profile.createResourcePack();
|
||||
|
||||
if (pack instanceof ModNioResourcePack && ((ModNioResourcePack) pack).shouldBeEnabledByDefault()) {
|
||||
enabled.add(profile.getName());
|
||||
} else {
|
||||
disabled.add(profile.getName());
|
||||
}
|
||||
}
|
||||
|
||||
return new DataPackSettings(enabled, disabled);
|
||||
}
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.resource.loader;
|
||||
|
||||
import java.nio.file.Path;
|
||||
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.Mutable;
|
||||
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.DataPackSettings;
|
||||
import net.minecraft.resource.ResourcePack;
|
||||
import net.minecraft.resource.ResourceType;
|
||||
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.fabricmc.loader.api.ModContainer;
|
||||
import net.fabricmc.fabric.impl.resource.loader.ModNioResourcePack;
|
||||
|
||||
@Mixin(DataPackSettings.class)
|
||||
public class MixinDataPackSettings {
|
||||
@Shadow
|
||||
@Final
|
||||
@Mutable
|
||||
private List<String> enabled;
|
||||
|
||||
/*
|
||||
This injection takes all instances of this class with an enabled list that only have the vanilla pack enabled,
|
||||
and forcibly enables all mod resource packs. This is probably not the best option, but it's the only one that I can
|
||||
think of that will work on both existing and new worlds. Is there a better option?
|
||||
*/
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void init(List<String> enabled, List<String> disabled, CallbackInfo info) {
|
||||
if (enabled.size() == 1 && enabled.get(0).equals("vanilla")) {
|
||||
List<String> newEnabled = new ArrayList<>(enabled);
|
||||
|
||||
for (ModContainer container : FabricLoader.getInstance().getAllMods()) {
|
||||
if (container.getMetadata().getType().equals("builtin")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Path path = container.getRootPath();
|
||||
|
||||
try (ResourcePack pack = new ModNioResourcePack(container.getMetadata(), path, null)) {
|
||||
if (!pack.getNamespaces(ResourceType.SERVER_DATA).isEmpty()) {
|
||||
newEnabled.add("fabric/" + container.getMetadata().getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.enabled = newEnabled;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.resource.loader;
|
||||
|
||||
import java.util.ArrayList;
|
||||
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.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import net.minecraft.client.options.GameOptions;
|
||||
import net.minecraft.resource.ResourcePack;
|
||||
import net.minecraft.resource.ResourcePackProfile;
|
||||
|
||||
import net.fabricmc.fabric.impl.resource.loader.ModNioResourcePack;
|
||||
import net.fabricmc.fabric.impl.resource.loader.ModResourcePackCreator;
|
||||
|
||||
@Mixin(GameOptions.class)
|
||||
public class MixinGameOptions {
|
||||
@Shadow
|
||||
public List<String> resourcePacks;
|
||||
|
||||
@Inject(method = "load", at = @At("RETURN"))
|
||||
private void onLoad(CallbackInfo ci) {
|
||||
// Add built-in resource packs if they are enabled by default only if the options file is blank.
|
||||
if (this.resourcePacks.isEmpty()) {
|
||||
List<ResourcePackProfile> profiles = new ArrayList<>();
|
||||
ModResourcePackCreator.CLIENT_RESOURCE_PACK_PROVIDER.register(profiles::add, ResourcePackProfile::new);
|
||||
this.resourcePacks = new ArrayList<>();
|
||||
|
||||
for (ResourcePackProfile profile : profiles) {
|
||||
ResourcePack pack = profile.createResourcePack();
|
||||
if (profile.getSource() == ModResourcePackCreator.RESOURCE_PACK_SOURCE
|
||||
|| (pack instanceof ModNioResourcePack && ((ModNioResourcePack) pack).shouldBeEnabledByDefault())) {
|
||||
this.resourcePacks.add(profile.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.resource.loader;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
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 org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.resource.ResourcePack;
|
||||
|
||||
import net.fabricmc.fabric.impl.resource.loader.ModResourcePackUtil;
|
||||
|
||||
@Mixin(MinecraftClient.class)
|
||||
public class MixinMinecraftGame {
|
||||
@Inject(method = "reloadResources", at = @At(value = "INVOKE", target = "Lnet/minecraft/resource/ReloadableResourceManager;beginMonitoredReload(Ljava/util/concurrent/Executor;Ljava/util/concurrent/Executor;Ljava/util/concurrent/CompletableFuture;Ljava/util/List;)Lnet/minecraft/resource/ResourceReloadMonitor;", ordinal = 0), locals = LocalCapture.CAPTURE_FAILHARD)
|
||||
public void reloadResources(CallbackInfoReturnable<CompletableFuture> info, CompletableFuture<java.lang.Void> cf, List<ResourcePack> list) {
|
||||
ModResourcePackUtil.modifyResourcePackList(list);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.resource.loader;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
|
||||
import net.minecraft.resource.ResourcePack;
|
||||
import net.minecraft.resource.ResourcePackManager;
|
||||
import net.minecraft.resource.ResourcePackProfile;
|
||||
import net.minecraft.resource.ResourcePackSource;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
|
||||
import net.fabricmc.fabric.impl.resource.loader.ModNioResourcePack;
|
||||
|
||||
@Mixin(MinecraftServer.class)
|
||||
public class MixinMinecraftServer {
|
||||
@Redirect(method = "loadDataPacks", at = @At(value = "INVOKE", target = "Ljava/util/List;contains(Ljava/lang/Object;)Z"))
|
||||
private static boolean onCheckDisabled(List<String> list, Object o, ResourcePackManager resourcePackManager) {
|
||||
String profileName = (String) o;
|
||||
boolean contains = list.contains(profileName);
|
||||
|
||||
if (contains) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ResourcePackProfile profile = resourcePackManager.getProfile(profileName);
|
||||
|
||||
if (profile.getSource() == ResourcePackSource.PACK_SOURCE_BUILTIN && !profileName.equals("vanilla")) {
|
||||
ResourcePack pack = profile.createResourcePack();
|
||||
// Prevents automatic load for built-in data packs provided by mods.
|
||||
return pack instanceof ModNioResourcePack && !((ModNioResourcePack) pack).shouldBeEnabledByDefault();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -21,16 +21,18 @@ 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.gui.screen.pack.PackScreen;
|
||||
import net.minecraft.client.gui.screen.pack.PackListWidget;
|
||||
import net.minecraft.client.gui.screen.pack.PackScreen;
|
||||
import net.minecraft.client.gui.screen.pack.ResourcePackOrganizer;
|
||||
|
||||
import net.fabricmc.fabric.impl.resource.loader.ModResourcePackCreator;
|
||||
|
||||
@Mixin(PackScreen.class)
|
||||
public class MixinAbstractPackScreen {
|
||||
public class MixinPackScreen {
|
||||
@Inject(method = "method_29672", at = @At("HEAD"), cancellable = true)
|
||||
private void addPackEntry(PackListWidget packListWidget, ResourcePackOrganizer.Pack pack, CallbackInfo info) {
|
||||
// Every mod resource packs should be hidden from the user.
|
||||
// Registered built-in resource packs should not be hidden as they are optional for the user.
|
||||
if (pack.getSource() == ModResourcePackCreator.RESOURCE_PACK_SOURCE) {
|
||||
info.cancel();
|
||||
}
|
|
@ -27,15 +27,17 @@ 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.FileResourcePackProvider;
|
||||
import net.minecraft.resource.ResourcePackManager;
|
||||
import net.minecraft.resource.ResourcePackProfile;
|
||||
import net.minecraft.resource.ResourcePackProvider;
|
||||
import net.minecraft.resource.ResourcePackSource;
|
||||
import net.minecraft.resource.ResourceType;
|
||||
|
||||
import net.fabricmc.fabric.impl.resource.loader.ModResourcePackCreator;
|
||||
|
||||
@Mixin(ResourcePackManager.class)
|
||||
public class MixinResourcePackManager<T extends ResourcePackProfile> {
|
||||
public abstract class MixinResourcePackManager<T extends ResourcePackProfile> {
|
||||
@Shadow
|
||||
@Final
|
||||
@Mutable
|
||||
|
@ -44,6 +46,22 @@ public class MixinResourcePackManager<T extends ResourcePackProfile> {
|
|||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
public void construct(ResourcePackProfile.Factory arg, ResourcePackProvider[] resourcePackProviders, CallbackInfo info) {
|
||||
providers = new HashSet<>(providers);
|
||||
providers.add(new ModResourcePackCreator(ResourceType.SERVER_DATA));
|
||||
|
||||
// Search resource pack providers to find any server-related pack provider.
|
||||
boolean shouldAddServerProvider = false;
|
||||
|
||||
for (ResourcePackProvider provider : this.providers) {
|
||||
if (provider instanceof FileResourcePackProvider
|
||||
&& (((FileResourcePackProviderAccessor) provider).getResourcePackSource() == ResourcePackSource.PACK_SOURCE_WORLD
|
||||
|| ((FileResourcePackProviderAccessor) provider).getResourcePackSource() == ResourcePackSource.PACK_SOURCE_SERVER)) {
|
||||
shouldAddServerProvider = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// On server, add the mod resource pack provider.
|
||||
if (shouldAddServerProvider) {
|
||||
providers.add(new ModResourcePackCreator(ResourceType.SERVER_DATA));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.resource.loader;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
import net.minecraft.resource.ResourcePackManager;
|
||||
import net.minecraft.resource.ResourcePackProvider;
|
||||
|
||||
@Mixin(ResourcePackManager.class)
|
||||
public interface ResourcePackManagerAccessor {
|
||||
/**
|
||||
* Returns the resource pack providers of this resource pack manager.
|
||||
*
|
||||
* @return The resource pack providers.
|
||||
*/
|
||||
@Accessor("providers")
|
||||
Set<ResourcePackProvider> getProviders();
|
||||
}
|
|
@ -3,18 +3,20 @@
|
|||
"package": "net.fabricmc.fabric.mixin.resource.loader",
|
||||
"compatibilityLevel": "JAVA_8",
|
||||
"mixins": [
|
||||
"MixinDataPackSettings",
|
||||
"FileResourcePackProviderAccessor",
|
||||
"MixinDefaultResourcePack",
|
||||
"MixinKeyedResourceReloadListener$Server",
|
||||
"MixinMinecraftServer",
|
||||
"MixinReloadableResourceManagerImpl",
|
||||
"MixinResourcePackManager"
|
||||
"MixinResourcePackManager",
|
||||
"ResourcePackManagerAccessor"
|
||||
],
|
||||
"client": [
|
||||
"MixinAbstractPackScreen",
|
||||
"MixinFormat4ResourcePack",
|
||||
"MixinClientBuiltinResourcePackProvider",
|
||||
"MixinCreateWorldScreen",
|
||||
"MixinGameOptions",
|
||||
"MixinKeyedResourceReloadListener$Client",
|
||||
"MixinMinecraftGame",
|
||||
"MixinResourcePackManagerClient"
|
||||
"MixinPackScreen"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.test.resource.loader;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.resource.ResourceManagerHelper;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
|
||||
public class BuiltinResourcePackTestMod implements ModInitializer {
|
||||
public static final String MODID = "fabric-resource-loader-v0-testmod";
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
// Should always be present as it's **this** mod.
|
||||
FabricLoader.getInstance().getModContainer(MODID)
|
||||
.map(container -> ResourceManagerHelper.registerBuiltinResourcePack(new Identifier(MODID, "test"), "resourcepacks/test", container, false))
|
||||
.filter(success -> !success).ifPresent(success -> LOGGER.warn("Could not register built-in resource pack."));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "fabric-resource-loader-v0-testmod",
|
||||
"name": "Fabric Resource Loader (v0) Test Mod",
|
||||
"version": "1.0.0",
|
||||
"environment": "*",
|
||||
"license": "Apache-2.0",
|
||||
"depends": {
|
||||
"fabric-resource-loader-v0": "*"
|
||||
},
|
||||
"entrypoints": {
|
||||
"main": [
|
||||
"net.fabricmc.fabric.test.resource.loader.BuiltinResourcePackTestMod"
|
||||
]
|
||||
}
|
||||
}
|
Binary file not shown.
After ![]() (image error) Size: 114 B |
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"minecraft:bamboo"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"pack": {
|
||||
"pack_format": 6,
|
||||
"description": "Fabric Resource Loader Test Builtin Pack."
|
||||
}
|
||||
}
|
Binary file not shown.
After ![]() (image error) Size: 1.5 KiB |
Loading…
Add table
Add a link
Reference in a new issue