Skip to content

Commit 7db5d6a

Browse files
committed
Make CTM work on 1.21
1 parent 631ad05 commit 7db5d6a

File tree

8 files changed

+162
-2
lines changed

8 files changed

+162
-2
lines changed

common/src/main/java/org/embeddedt/modernfix/api/entrypoint/ModernFixClientIntegration.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
package org.embeddedt.modernfix.api.entrypoint;
22

3+
import net.minecraft.client.resources.model.BakedModel;
4+
import net.minecraft.client.resources.model.ModelBakery;
5+
import net.minecraft.client.resources.model.ModelResourceLocation;
6+
import net.minecraft.client.resources.model.ModelState;
7+
import net.minecraft.client.resources.model.UnbakedModel;
8+
39
/**
410
* Implement this interface in a mod class and add it to "modernfix:integration_v1" in your mod metadata file
511
* to integrate with ModernFix's features.
@@ -13,4 +19,19 @@ public interface ModernFixClientIntegration {
1319
*/
1420
default void onDynamicResourcesStatusChange(boolean enabled) {
1521
}
22+
23+
/**
24+
* Called to allow mods to observe the loading of a baked model and either make changes to it or wrap it with their
25+
* own instance.
26+
*
27+
* @param location the ResourceLocation of the model (this may be a ModelResourceLocation)
28+
* @param originalModel the original model
29+
* @param bakery the model bakery - do not touch internal fields as they probably don't behave the way you expect
30+
* with dynamic resources on
31+
* @param textureGetter function to retrieve textures for this model
32+
* @return the model which should actually be loaded for this resource location
33+
*/
34+
default BakedModel onBakedModelLoad(ModelResourceLocation location, UnbakedModel baseModel, BakedModel originalModel, ModelState state, ModelBakery bakery, ModelBakery.TextureGetter textureGetter) {
35+
return originalModel;
36+
}
1637
}

common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/ModelBakeryMixin.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
77
import net.minecraft.client.color.block.BlockColors;
88
import net.minecraft.client.resources.model.BakedModel;
9+
import net.minecraft.client.resources.model.BlockModelRotation;
910
import net.minecraft.client.resources.model.BlockStateModelLoader;
1011
import net.minecraft.client.resources.model.ModelBakery;
1112
import net.minecraft.client.resources.model.ModelResourceLocation;
@@ -14,7 +15,9 @@
1415
import net.minecraft.resources.ResourceLocation;
1516
import net.minecraft.util.profiling.ProfilerFiller;
1617
import org.embeddedt.modernfix.ModernFix;
18+
import org.embeddedt.modernfix.ModernFixClient;
1719
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
20+
import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration;
1821
import org.embeddedt.modernfix.duck.IBlockStateModelLoader;
1922
import org.embeddedt.modernfix.duck.IExtendedModelBakery;
2023
import org.embeddedt.modernfix.util.DynamicOverridableMap;
@@ -129,6 +132,9 @@ private BakedModel loadBakedModelDynamic(ModelResourceLocation location) {
129132
ModernFix.LOGGER.error("Failed to load model " + location);
130133
model = bakedMissingModel;
131134
}
135+
for(ModernFixClientIntegration integration : ModernFixClient.CLIENT_INTEGRATIONS) {
136+
model = integration.onBakedModelLoad(location, prototype, model, BlockModelRotation.X0_Y0, (ModelBakery)(Object)this, this.textureGetter);
137+
}
132138
}
133139
}
134140
} finally {

common/src/main/resources/modernfix.accesswidener

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ accessible field net/minecraft/client/renderer/block/model/BlockModel GSON Lcom/
4141
accessible class net/minecraft/server/level/ChunkMap$DistanceManager
4242
accessible class net/minecraft/client/resources/model/ModelBakery$BakedCacheKey
4343
accessible method net/minecraft/client/resources/model/ModelBakery$BakedCacheKey <init> (Lnet/minecraft/resources/ResourceLocation;Lcom/mojang/math/Transformation;Z)V
44+
accessible class net/minecraft/client/resources/model/ModelBakery$ModelBakerImpl
45+
accessible method net/minecraft/client/resources/model/ModelBakery$ModelBakerImpl <init> (Lnet/minecraft/client/resources/model/ModelBakery;Lnet/minecraft/client/resources/model/ModelBakery$TextureGetter;Lnet/minecraft/client/resources/model/ModelResourceLocation;)V
46+
accessible method net/minecraft/client/resources/model/ModelBakery getModel (Lnet/minecraft/resources/ResourceLocation;)Lnet/minecraft/client/resources/model/UnbakedModel;
4447
accessible class net/minecraft/world/level/chunk/PalettedContainer$Data
4548
accessible field net/minecraft/server/MinecraftServer resources Lnet/minecraft/server/MinecraftServer$ReloadableResources;
4649
accessible class net/minecraft/server/MinecraftServer$ReloadableResources

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ parchment_version=2024.07.07
1212
refined_storage_version=4392788
1313
jei_version=19.0.0.9
1414
rei_version=13.0.678
15-
ctm_version=1.20.1-1.1.8+4
15+
ctm_version=1.21-1.2.0+2
1616
kubejs_version=1902.6.0-build.142
1717
rhino_version=1902.2.2-build.268
1818
supported_minecraft_versions=1.21

neoforge/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ dependencies {
5454
modCompileOnly("me.shedaniel:RoughlyEnoughItems-forge:${rei_version}") { transitive false }
5555
modCompileOnly("dev.latvian.mods:kubejs-forge:${kubejs_version}")
5656
//modRuntimeOnly("curse.maven:ferritecore-429235:4441949")
57-
modCompileOnly files("deps/ctm.jar")
57+
modCompileOnly("team.chisel.ctm:CTM:${ctm_version}")
5858

5959
modCompileOnly("curse.maven:supermartijncore-454372:4455391")
6060
modCompileOnly("vazkii.patchouli:Patchouli:1.19.2-77")

neoforge/deps/ctm.jar

-239 KB
Binary file not shown.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package org.embeddedt.modernfix.neoforge.mixin.perf.dynamic_resources.ctm;
2+
3+
import net.minecraft.client.resources.model.BakedModel;
4+
import net.minecraft.client.resources.model.ModelBakery;
5+
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
6+
import org.spongepowered.asm.mixin.Mixin;
7+
import org.spongepowered.asm.mixin.gen.Accessor;
8+
9+
import java.util.Map;
10+
11+
@Mixin(ModelBakery.class)
12+
@ClientOnlyMixin
13+
public interface CTMModelBakeryAccessor {
14+
@Accessor("bakedCache")
15+
Map<ModelBakery.BakedCacheKey, BakedModel> mfix$getBakedCache();
16+
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package org.embeddedt.modernfix.neoforge.mixin.perf.dynamic_resources.ctm;
2+
3+
import com.google.common.collect.Multimap;
4+
import com.google.common.collect.Sets;
5+
import com.mojang.datafixers.util.Pair;
6+
import net.minecraft.client.resources.model.*;
7+
import net.minecraft.resources.ResourceLocation;
8+
import org.embeddedt.modernfix.ModernFixClient;
9+
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
10+
import org.embeddedt.modernfix.annotation.RequiresMod;
11+
import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration;
12+
import org.spongepowered.asm.mixin.Final;
13+
import org.spongepowered.asm.mixin.Mixin;
14+
import org.spongepowered.asm.mixin.Shadow;
15+
import org.spongepowered.asm.mixin.injection.At;
16+
import org.spongepowered.asm.mixin.injection.Inject;
17+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
18+
import team.chisel.ctm.CTM;
19+
import team.chisel.ctm.api.model.IModelCTM;
20+
import team.chisel.ctm.client.model.AbstractCTMBakedModel;
21+
import team.chisel.ctm.client.model.ModelCTM;
22+
import team.chisel.ctm.client.texture.IMetadataSectionCTM;
23+
import team.chisel.ctm.client.util.ResourceUtil;
24+
import team.chisel.ctm.client.util.TextureMetadataHandler;
25+
26+
import javax.annotation.Nonnull;
27+
import java.io.IOException;
28+
import java.util.*;
29+
30+
@Mixin(TextureMetadataHandler.class)
31+
@RequiresMod("ctm")
32+
@ClientOnlyMixin
33+
public abstract class TextureMetadataHandlerMixin implements ModernFixClientIntegration {
34+
35+
@Shadow(remap = false) @Nonnull protected abstract BakedModel wrap(UnbakedModel model, BakedModel object) throws IOException;
36+
37+
@Shadow(remap = false) @Final private Multimap<ResourceLocation, Material> scrapedTextures;
38+
39+
@Inject(method = "<init>", at = @At("RETURN"))
40+
private void subscribeDynamic(CallbackInfo ci) {
41+
ModernFixClient.CLIENT_INTEGRATIONS.add(this);
42+
}
43+
44+
@Inject(method = { "onModelBake(Lnet/neoforged/neoforge/client/event/ModelEvent$BakingCompleted;)V", "onModelBake(Lnet/neoforged/neoforge/client/event/ModelEvent$ModifyBakingResult;)V" }, at = @At("HEAD"), cancellable = true, remap = false)
45+
private void noIteration(CallbackInfo ci) {
46+
ci.cancel();
47+
}
48+
49+
@Override
50+
public BakedModel onBakedModelLoad(ModelResourceLocation mrl, UnbakedModel rootModel, BakedModel baked, ModelState state, ModelBakery bakery, ModelBakery.TextureGetter getter) {
51+
if (!(baked instanceof AbstractCTMBakedModel) && !baked.isCustomRenderer()) {
52+
Deque<ResourceLocation> dependencies = new ArrayDeque<>();
53+
Set<ResourceLocation> seenModels = new HashSet<>();
54+
dependencies.push(mrl.id());
55+
seenModels.add(mrl.id());
56+
boolean shouldWrap = false;
57+
Set<Pair<String, String>> errors = new HashSet<>();
58+
// Breadth-first loop through dependencies, exiting as soon as a CTM texture is found, and skipping duplicates/cycles
59+
while (!shouldWrap && !dependencies.isEmpty()) {
60+
ResourceLocation dep = dependencies.pop();
61+
UnbakedModel model;
62+
try {
63+
model = dep == mrl.id() ? rootModel : bakery.getModel(dep);
64+
} catch (Exception e) {
65+
continue;
66+
}
67+
68+
Collection<Material> textures = Sets.newHashSet(scrapedTextures.get(dep));
69+
Collection<ResourceLocation> newDependencies = model.getDependencies();
70+
for (Material tex : textures) {
71+
IMetadataSectionCTM meta = null;
72+
// Cache all dependent texture metadata
73+
try {
74+
meta = ResourceUtil.getMetadata(ResourceUtil.spriteToAbsolute(tex.texture())).orElse(null); // TODO, lazy
75+
} catch (IOException e) {} // Fallthrough
76+
if (meta != null) {
77+
// At least one texture has CTM metadata, so we should wrap this model
78+
shouldWrap = true;
79+
}
80+
}
81+
82+
for (ResourceLocation newDep : newDependencies) {
83+
if (seenModels.add(newDep)) {
84+
dependencies.push(newDep);
85+
}
86+
}
87+
}
88+
if (shouldWrap) {
89+
try {
90+
baked = wrap(rootModel, baked);
91+
handleInit(mrl, baked, bakery, getter);
92+
dependencies.clear();
93+
} catch (IOException e) {
94+
CTM.logger.error("Could not wrap model " + mrl + ". Aborting...", e);
95+
}
96+
}
97+
}
98+
return baked;
99+
}
100+
101+
private void handleInit(ModelResourceLocation key, BakedModel wrappedModel, ModelBakery bakery, ModelBakery.TextureGetter spriteGetter) {
102+
if(wrappedModel instanceof AbstractCTMBakedModel baked) {
103+
IModelCTM var10 = baked.getModel();
104+
if (var10 instanceof ModelCTM ctmModel) {
105+
if (!ctmModel.isInitialized()) {
106+
// Clear the baked cache as upstream CTM does
107+
((CTMModelBakeryAccessor)bakery).mfix$getBakedCache().clear();
108+
ModelBakery.ModelBakerImpl baker = bakery.new ModelBakerImpl(spriteGetter, key);
109+
ctmModel.bake(baker, Material::sprite, BlockModelRotation.X0_Y0);
110+
}
111+
}
112+
}
113+
}
114+
}

0 commit comments

Comments
 (0)