-
Notifications
You must be signed in to change notification settings - Fork 18
/
ConfigurableResourcePack.java
217 lines (191 loc) · 8.06 KB
/
ConfigurableResourcePack.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
package knightminer.inspirations.library.client;
import knightminer.inspirations.Inspirations;
import net.minecraft.block.Block;
import net.minecraft.resources.IPackFinder;
import net.minecraft.resources.ResourcePack;
import net.minecraft.resources.ResourcePackFileNotFoundException;
import net.minecraft.resources.ResourcePackInfo;
import net.minecraft.resources.ResourcePackInfo.IFactory;
import net.minecraft.resources.ResourcePackType;
import net.minecraft.util.IItemProvider;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.text.TranslationTextComponent;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.Supplier;
/**
* Resource pack that overrides resources based on config
*/
public class ConfigurableResourcePack extends ResourcePack implements IPackFinder {
/** Class within the mod jar to serve as a root for getting resources */
private final Class<?> resourceLoader;
/** Namespaced pack name, used to pass to resource pack loaders and for the translation key */
private final String packId;
/** Display name of the pack */
private final String displayName;
/** Prefix for where to find pack resources */
private final String pathPrefix;
/** Set of namespaces relevant to this pack */
private final Set<String> namespaces;
/** Map of replaced resource name to condition for replacing */
private final Map<String,Replacement> replacements = new HashMap<>();
/**
* Creates a new pack instance
* @param resourceLoader Class context for resource loading
* @param packId ID for the pack
* @param displayName Display name of the pack for UIs
* @param namespaces List of namespaces that have resources replaced
*/
public ConfigurableResourcePack(Class<?> resourceLoader, ResourceLocation packId, String displayName, Set<String> namespaces) {
this(resourceLoader, packId.toString(), String.format("/%s/%s/%s/", ResourcePackType.CLIENT_RESOURCES.getDirectoryName(), packId.getNamespace(), packId.getPath()), displayName, namespaces);
}
/**
* Internal method for constructing
* @param resourceLoader Class context for resource loading
* @param packId Pack ID resource location
* @param pathPrefix Path resource prefix
* @param namespaces List of namepsaces that have resources replaced
*/
private ConfigurableResourcePack(Class<?> resourceLoader, String packId, String pathPrefix, String displayName, Set<String> namespaces) {
super(new File(pathPrefix));
this.resourceLoader = resourceLoader;
this.packId = packId.toString();
this.displayName = displayName;
this.pathPrefix = pathPrefix;
this.namespaces = namespaces;
}
@Override
public String getName() {
return displayName;
}
@Override
public Set<String> getResourceNamespaces(ResourcePackType type) {
return type == ResourcePackType.CLIENT_RESOURCES ? namespaces : Collections.emptySet();
}
/**
* Gets the resource in the pack for the given name
* @param name Default resource path
* @return Resource from the path, or null if missing
*/
private InputStream getPackResource(String name) {
return resourceLoader.getResourceAsStream(pathPrefix + name);
}
@Override
protected InputStream getInputStream(String name) throws IOException {
// pack.mcmeta and pack.png are requested without prefix, and requird directly
if (name.equals("pack.mcmeta") || name.equals("pack.png")) {
return getPackResource(name);
}
// if its a replacement, treat as such
Replacement replacement = replacements.get(name);
if (replacement != null && replacement.isEnabled()) {
return getPackResource(replacement.getName());
}
// not a replacement or replacement is disabled, error
throw new ResourcePackFileNotFoundException(this.file, name);
}
@Override
protected boolean resourceExists(String name) {
Replacement replacement = replacements.get(name);
return replacement != null && replacement.isEnabled();
}
@Override
public Collection<ResourceLocation> getAllResourceLocations(ResourcePackType type, String domain, String path, int maxDepth, Predicate<String> filter) {
// this method appears to only be called for fonts and GUIs, so just return an empty list as neither is used here
return Collections.emptyList();
}
@Override
public void close() {}
@Override
public <T extends ResourcePackInfo> void func_230230_a_(Consumer<T> consumer, IFactory<T> factory) {
// add a new always enabled pack. Config is how you disable the replacements
consumer.accept(ResourcePackInfo.createResourcePack(
packId, true, () -> this, factory, ResourcePackInfo.Priority.TOP,
name -> new TranslationTextComponent("pack.nameAndSource", name, Inspirations.modID)));
}
/* Replacement additions */
/**
* Generic method to add a replacement
* @param condition Condition for replacement
* @param originalPath Original resource path
* @param resource Path to the replacement resource relative to the pack root
*/
protected void addReplacement(BooleanSupplier condition, String originalPath, Supplier<String> resource) {
if (replacements.containsKey(originalPath)) {
throw new IllegalArgumentException("Duplicate replacement '" + originalPath + "' for configurable pack " + packId);
}
this.replacements.put(originalPath, new Replacement(condition, resource));
}
/**
* Makes a path for the given resource
* @param id Resource ID
* @param folder Resource folder
* @return Full resource path
*/
private static String makePath(ResourceLocation id, String folder, String extension) {
return String.format("%s/%s/%s/%s.%s", ResourcePackType.CLIENT_RESOURCES.getDirectoryName(), id.getNamespace(), folder, id.getPath(), extension);
}
/**
* Adds a replacement for a blockstate JSON
* @param condition Condition for replacement
* @param block Block to replace the model
* @param resource Name of blockstate replacement
*/
public void addBlockstateReplacement(BooleanSupplier condition, Block block, String resource) {
addReplacement(condition, makePath(Objects.requireNonNull(block.getRegistryName()), "blockstates", "json"), () -> "blockstates/" + resource + ".json");
}
/**
* Adds a replacement for a item model replacement
* @param condition Condition for replacement
* @param item Item to replace the model
* @param resource New name supplier
*/
public void addItemModelReplacement(BooleanSupplier condition, IItemProvider item, Supplier<String> resource) {
addReplacement(condition, makePath(Objects.requireNonNull(item.asItem().getRegistryName()), "models/item", "json"), () -> "item_models/" + resource.get() + ".json");
}
/**
* Adds a replacement for a blockstate JSON
* @param condition Condition for replacement
* @param item Item to replace the model
* @param resource New name supplier
*/
public void addItemModelReplacement(BooleanSupplier condition, IItemProvider item, String resource) {
addItemModelReplacement(condition, item, () -> resource);
}
/**
* Data class holding a single replacement pair
*/
private static class Replacement {
private final BooleanSupplier condition;
private final Supplier<String> name;
/**
* Creates a new replacement
* @param condition Condition for the replacement
* @param name New file name, relative to pack root
*/
public Replacement(BooleanSupplier condition, Supplier<String> name) {
this.name = name;
this.condition = condition;
}
public String getName() {
return name.get();
}
/**
* If true, this replacement is enabled
* @return True if enabled
*/
public boolean isEnabled() {
return condition.getAsBoolean();
}
}
}