11package org .embeddedt .modernfix .forge .dynresources ;
22
33import com .google .common .collect .ForwardingMap ;
4- import com .google .common .collect .ImmutableSet ;
5- import com .google .common .collect .Iterators ;
4+ import com .google .common .collect .ImmutableMap ;
65import com .google .common .collect .Sets ;
76import com .google .common .graph .GraphBuilder ;
87import com .google .common .graph .MutableGraph ;
1110import net .minecraft .client .resources .model .BakedModel ;
1211import net .minecraft .client .resources .model .ModelBakery ;
1312import net .minecraft .client .resources .model .ModelResourceLocation ;
13+ import net .minecraft .core .registries .BuiltInRegistries ;
1414import net .minecraft .resources .ResourceLocation ;
1515import net .minecraft .world .level .block .state .BlockState ;
1616import net .minecraftforge .fml .ModContainer ;
1717import net .minecraftforge .fml .ModList ;
1818import net .minecraftforge .forgespi .language .IModInfo ;
19- import net .minecraftforge .registries .ForgeRegistries ;
2019import org .embeddedt .modernfix .ModernFix ;
2120import org .embeddedt .modernfix .util .ForwardingInclDefaultsMap ;
2221import org .jetbrains .annotations .Nullable ;
2322
2423import java .util .AbstractSet ;
2524import java .util .ArrayList ;
2625import java .util .Collection ;
26+ import java .util .Collections ;
2727import java .util .HashSet ;
2828import java .util .Iterator ;
2929import java .util .List ;
3838 * of the model registry that emulates vanilla keySet behavior.
3939 */
4040public class ModelBakeEventHelper {
41- // TODO: make into config option
42- private static final Set <String > INCOMPATIBLE_MODS = ImmutableSet .of (
43- "industrialforegoing" ,
44- "mekanism" ,
45- "vampirism" ,
46- "elevatorid" ,
47- "cfm" ,
48- "refinedstorage" ,
49- "embers" ,
50- "buildcraftsilicon" ,
51- "buildcrafttransport" ,
52- "buildcraftfactory" );
41+ private enum UniverseVisibility {
42+ /**
43+ * Mod cannot see any view of the universe of model locations.
44+ */
45+ NONE ,
46+ /**
47+ * Mod can see its own model locations and those of dependencies/dependents.
48+ */
49+ SELF_AND_DEPS ,
50+ /**
51+ * Mod can see every model location.
52+ */
53+ EVERYTHING
54+ }
55+ private static final Map <String , UniverseVisibility > MOD_VISIBILITY_CONFIGURATION = ImmutableMap .<String , UniverseVisibility >builder ()
56+ .build ();
5357 private final Map <ResourceLocation , BakedModel > modelRegistry ;
5458 private final Set <ResourceLocation > topLevelModelLocations ;
5559 private final MutableGraph <String > dependencyGraph ;
5660 public ModelBakeEventHelper (Map <ResourceLocation , BakedModel > modelRegistry ) {
5761 this .modelRegistry = modelRegistry ;
5862 this .topLevelModelLocations = new ObjectLinkedOpenHashSet <>();
5963 // Skip going through ModelLocationCache because most of the accesses will be misses
60- ForgeRegistries . BLOCKS . getEntries ().forEach (entry -> {
64+ BuiltInRegistries . BLOCK . entrySet ().forEach (entry -> {
6165 var location = entry .getKey ().location ();
6266 for (BlockState state : entry .getValue ().getStateDefinition ().getPossibleStates ()) {
6367 topLevelModelLocations .add (BlockModelShaper .stateToModelLocation (location , state ));
6468 }
6569 });
66- ForgeRegistries . ITEMS . getKeys ().forEach (key -> topLevelModelLocations .add (new ModelResourceLocation (key , "inventory" )));
70+ BuiltInRegistries . ITEM . keySet ().forEach (key -> topLevelModelLocations .add (new ModelResourceLocation (key , "inventory" )));
6771 this .topLevelModelLocations .addAll (modelRegistry .keySet ());
68- this .dependencyGraph = GraphBuilder .undirected ().build ();
72+ this .dependencyGraph = buildDependencyGraph ();
73+ }
74+
75+ private static MutableGraph <String > buildDependencyGraph () {
76+ MutableGraph <String > dependencyGraph = GraphBuilder .undirected ().build ();
6977 ModList .get ().forEachModContainer ((id , mc ) -> {
70- this . dependencyGraph .addNode (id );
78+ dependencyGraph .addNode (id );
7179 for (IModInfo .ModVersion version : mc .getModInfo ().getDependencies ()) {
72- this . dependencyGraph .addNode (version .getModId ());
80+ dependencyGraph .addNode (version .getModId ());
7381 }
7482 });
75- for (String id : this . dependencyGraph .nodes ()) {
83+ for (String id : dependencyGraph .nodes ()) {
7684 Optional <? extends ModContainer > mContainer = ModList .get ().getModContainerById (id );
7785 if (mContainer .isPresent ()) {
7886 for (IModInfo .ModVersion version : mContainer .get ().getModInfo ().getDependencies ()) {
7987 // avoid self-loops
8088 if (!Objects .equals (id , version .getModId ()))
81- this . dependencyGraph .putEdge (id , version .getModId ());
89+ dependencyGraph .putEdge (id , version .getModId ());
8290 }
8391 }
8492 }
93+ return dependencyGraph ;
8594 }
8695
8796 private static final Set <String > WARNED_MOD_IDS = new HashSet <>();
@@ -132,73 +141,94 @@ public void replaceAll(BiFunction<? super ResourceLocation, ? super BakedModel,
132141 }
133142
134143 public Map <ResourceLocation , BakedModel > wrapRegistry (String modId ) {
144+ var config = MOD_VISIBILITY_CONFIGURATION .getOrDefault (modId , UniverseVisibility .EVERYTHING );
145+ if (config == UniverseVisibility .NONE ) {
146+ return createWarningRegistry (modId );
147+ }
135148 final Set <String > modIdsToInclude = new HashSet <>();
136149 modIdsToInclude .add (modId );
137150 try {
138151 modIdsToInclude .addAll (this .dependencyGraph .adjacentNodes (modId ));
139152 } catch (IllegalArgumentException ignored ) { /* sanity check */ }
140153 modIdsToInclude .remove ("minecraft" );
141- if (modIdsToInclude .stream ().noneMatch (INCOMPATIBLE_MODS ::contains ))
142- return createWarningRegistry (modId );
143- Set <ResourceLocation > ourModelLocations = Sets .filter (this .topLevelModelLocations , loc -> modIdsToInclude .contains (loc .getNamespace ()));
154+ Set <ResourceLocation > ourModelLocations ;
155+ if (config == UniverseVisibility .SELF_AND_DEPS ) {
156+ ourModelLocations = Sets .filter (this .topLevelModelLocations , loc -> modIdsToInclude .contains (loc .getNamespace ()));
157+ } else {
158+ ourModelLocations = this .topLevelModelLocations ;
159+ }
144160 BakedModel missingModel = modelRegistry .get (ModelBakery .MISSING_MODEL_LOCATION );
145- return new ForwardingMap <ResourceLocation , BakedModel >() {
146- @ Override
147- protected Map <ResourceLocation , BakedModel > delegate () {
148- return modelRegistry ;
149- }
161+ return new EmulatedModelRegistry (modId , modIdsToInclude , missingModel , ourModelLocations );
162+ }
150163
151- @ Override
152- public BakedModel get (@ Nullable Object key ) {
153- BakedModel model = super .get (key );
154- if (model == null && key != null && modIdsToInclude .contains (((ResourceLocation )key ).getNamespace ())) {
155- ModernFix .LOGGER .warn ("Model {} is missing, but was requested in model bake event. Returning missing model" , key );
156- return missingModel ;
157- }
158- return model ;
159- }
164+ public class EmulatedModelRegistry extends ForwardingMap <ResourceLocation , BakedModel > {
165+ private final Set <String > modIdsToInclude ;
166+ private final BakedModel missingModel ;
167+ private final Set <ResourceLocation > ourModelLocations ;
168+ private final String modId ;
160169
161- @ Override
162- public Set <ResourceLocation > keySet () {
163- return ourModelLocations ;
164- }
170+ private EmulatedModelRegistry (String modId , Set <String > modIdsToInclude , BakedModel missingModel , Set <ResourceLocation > ourModelLocations ) {
171+ this .modId = modId ;
172+ this .modIdsToInclude = modIdsToInclude ;
173+ this .missingModel = missingModel ;
174+ this .ourModelLocations = ourModelLocations ;
175+ }
165176
166- @ Override
167- public boolean containsKey ( @ Nullable Object key ) {
168- return ourModelLocations . contains ( key ) || super . containsKey ( key ) ;
169- }
177+ @ Override
178+ protected Map < ResourceLocation , BakedModel > delegate ( ) {
179+ return modelRegistry ;
180+ }
170181
171- @ Override
172- public Set <Entry <ResourceLocation , BakedModel >> entrySet () {
173- return new DynamicModelEntrySet (this , ourModelLocations );
182+ @ Override
183+ public BakedModel get (@ Nullable Object key ) {
184+ BakedModel model = super .get (key );
185+ if (model == null && key != null && modIdsToInclude .contains (((ResourceLocation )key ).getNamespace ())) {
186+ ModernFix .LOGGER .warn ("Model {} is missing, but was requested in model bake event. Returning missing model" , key );
187+ return missingModel ;
174188 }
189+ return model ;
190+ }
175191
176- @ Override
177- public void replaceAll (BiFunction <? super ResourceLocation , ? super BakedModel , ? extends BakedModel > function ) {
178- ModernFix .LOGGER .warn ("Mod '{}' is calling replaceAll on the model registry. Some hacks will be used to keep this fast, but they may not be 100% compatible." , modId );
179- List <ResourceLocation > locations = new ArrayList <>(keySet ());
180- for (ResourceLocation location : locations ) {
181- /*
182- * Fetching every model is insanely slow. So we call the function with a null object first, since it
183- * probably isn't expecting that. If we get an exception thrown, or it returns nonnull, then we know
184- * it actually cares about the given model.
185- */
186- boolean needsReplacement ;
187- try {
188- needsReplacement = function .apply (location , null ) != null ;
189- } catch (Throwable e ) {
190- needsReplacement = true ;
191- }
192- if (needsReplacement ) {
193- BakedModel existing = get (location );
194- BakedModel replacement = function .apply (location , existing );
195- if (replacement != existing ) {
196- put (location , replacement );
197- }
192+ @ Override
193+ public Set <ResourceLocation > keySet () {
194+ return Collections .unmodifiableSet (ourModelLocations );
195+ }
196+
197+ @ Override
198+ public boolean containsKey (@ Nullable Object key ) {
199+ return ourModelLocations .contains (key ) || super .containsKey (key );
200+ }
201+
202+ @ Override
203+ public Set <Entry <ResourceLocation , BakedModel >> entrySet () {
204+ return new DynamicModelEntrySet (this , ourModelLocations );
205+ }
206+
207+ @ Override
208+ public void replaceAll (BiFunction <? super ResourceLocation , ? super BakedModel , ? extends BakedModel > function ) {
209+ ModernFix .LOGGER .warn ("Mod '{}' is calling replaceAll on the model registry. Some hacks will be used to keep this fast, but they may not be 100% compatible." , modId );
210+ List <ResourceLocation > locations = new ArrayList <>(ourModelLocations );
211+ for (ResourceLocation location : locations ) {
212+ /*
213+ * Fetching every model is insanely slow. So we call the function with a null object first, since it
214+ * probably isn't expecting that. If we get an exception thrown, or it returns nonnull, then we know
215+ * it actually cares about the given model.
216+ */
217+ boolean needsReplacement ;
218+ try {
219+ needsReplacement = function .apply (location , null ) != null ;
220+ } catch (Throwable e ) {
221+ needsReplacement = true ;
222+ }
223+ if (needsReplacement ) {
224+ BakedModel existing = get (location );
225+ BakedModel replacement = function .apply (location , existing );
226+ if (replacement != existing ) {
227+ put (location , replacement );
198228 }
199229 }
200230 }
201- };
231+ }
202232 }
203233
204234 private static class DynamicModelEntrySet extends AbstractSet <Map .Entry <ResourceLocation , BakedModel >> {
@@ -212,7 +242,18 @@ private DynamicModelEntrySet(Map<ResourceLocation, BakedModel> modelRegistry, Se
212242
213243 @ Override
214244 public Iterator <Map .Entry <ResourceLocation , BakedModel >> iterator () {
215- return Iterators .transform (Iterators .unmodifiableIterator (this .modelLocations .iterator ()), DynamicModelEntry ::new );
245+ var iter = this .modelLocations .iterator ();
246+ return new Iterator <>() {
247+ @ Override
248+ public boolean hasNext () {
249+ return iter .hasNext ();
250+ }
251+
252+ @ Override
253+ public Map .Entry <ResourceLocation , BakedModel > next () {
254+ return new DynamicModelEntry (iter .next ());
255+ }
256+ };
216257 }
217258
218259 @ Override
0 commit comments