Resource loader changes and built-in mod resource/data packs API ()

* 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:
LambdAurora 2020-09-03 20:49:40 +02:00 committed by GitHub
parent 0ba3dd89ec
commit 8072a3a990
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 453 additions and 183 deletions

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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());
}
}
}

View file

@ -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);

View file

@ -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();
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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;
}
}
}

View file

@ -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());
}
}
}
}
}

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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();
}

View file

@ -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));
}
}
}

View file

@ -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();
}

View file

@ -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

View file

@ -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."));
}
}

View file

@ -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"
]
}
}

View file

@ -0,0 +1,6 @@
{
"replace": false,
"values": [
"minecraft:bamboo"
]
}

View file

@ -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