Skip to content

Commit 2c5fe8a

Browse files
screretGhostipedia
andauthored
Simplify material block models and fix issues they had with shaders (#4532)
Co-authored-by: Ghostipedia / Caitlynn <46772882+Ghostipedia@users.noreply.github.com>
1 parent 2f3a6a1 commit 2c5fe8a

44 files changed

Lines changed: 1505 additions & 149 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/info/MaterialIconType.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ public record MaterialIconType(String name) {
9797
public static final MaterialIconType molten = new MaterialIconType("molten");
9898
public static final MaterialIconType block = new MaterialIconType("block");
9999
public static final MaterialIconType ore = new MaterialIconType("ore");
100+
public static final MaterialIconType oreEmissive = new MaterialIconType("oreEmissive");
100101
public static final MaterialIconType oreSmall = new MaterialIconType("oreSmall");
101102
public static final MaterialIconType frameGt = new MaterialIconType("frameGt");
102103
public static final MaterialIconType wire = new MaterialIconType("wire");

src/main/java/com/gregtechceu/gtceu/api/data/tag/TagPrefix.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import com.gregtechceu.gtceu.api.data.chemical.material.Material;
1111
import com.gregtechceu.gtceu.api.data.chemical.material.info.MaterialFlags;
1212
import com.gregtechceu.gtceu.api.data.chemical.material.info.MaterialIconType;
13+
import com.gregtechceu.gtceu.api.data.chemical.material.properties.OreProperty;
1314
import com.gregtechceu.gtceu.api.data.chemical.material.properties.PropertyKey;
1415
import com.gregtechceu.gtceu.api.data.chemical.material.stack.MaterialStack;
1516
import com.gregtechceu.gtceu.api.item.MaterialBlockItem;
@@ -1232,6 +1233,17 @@ public boolean doGenerateBlock(Material material) {
12321233
hasItemTable() && this.itemTable.get() != null && getItemFromTable(material) != null;
12331234
}
12341235

1236+
public MaterialIconType getMaterialIconType(Material material) {
1237+
// special case emissive ores
1238+
if (materialIconType == MaterialIconType.ore && material.hasProperty(PropertyKey.ORE)) {
1239+
OreProperty oreProp = material.getProperty(PropertyKey.ORE);
1240+
if (oreProp.isEmissive()) {
1241+
return MaterialIconType.oreEmissive;
1242+
}
1243+
}
1244+
return materialIconType;
1245+
}
1246+
12351247
public String getLowerCaseName() {
12361248
return FormattingUtil.toLowerCaseUnderscore(this.name);
12371249
}

src/main/java/com/gregtechceu/gtceu/client/renderer/block/MaterialBlockRenderer.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515

1616
public class MaterialBlockRenderer {
1717

18-
public static final String LAYER_2_SUFFIX = "_layer2";
1918
private static final Set<MaterialBlockRenderer> MODELS = new HashSet<>();
2019

2120
public static void create(Block block, MaterialIconType type, MaterialIconSet iconSet) {
@@ -25,12 +24,11 @@ public static void create(Block block, MaterialIconType type, MaterialIconSet ic
2524
public static void reinitModels() {
2625
for (MaterialBlockRenderer model : MODELS) {
2726
ResourceLocation blockId = BuiltInRegistries.BLOCK.getKey(model.block);
28-
ResourceLocation modelId = blockId.withPrefix("block/");
29-
GTDynamicResourcePack.addBlockModel(blockId,
30-
new DelegatedModel(model.type.getBlockModelPath(model.iconSet, true)));
27+
ResourceLocation modelId = model.type.getBlockModelPath(model.iconSet, true);
28+
3129
GTDynamicResourcePack.addBlockState(blockId, BlockModelGenerators.createSimpleBlock(model.block, modelId));
3230
GTDynamicResourcePack.addItemModel(BuiltInRegistries.ITEM.getKey(model.block.asItem()),
33-
new DelegatedModel(ModelLocationUtils.getModelLocation(model.block)));
31+
new DelegatedModel(modelId));
3432
}
3533
}
3634

src/main/java/com/gregtechceu/gtceu/client/renderer/block/OreBlockRenderer.java

Lines changed: 76 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,45 @@
33
import com.gregtechceu.gtceu.GTCEu;
44
import com.gregtechceu.gtceu.api.block.MaterialBlock;
55
import com.gregtechceu.gtceu.api.data.chemical.material.Material;
6-
import com.gregtechceu.gtceu.api.data.chemical.material.properties.OreProperty;
7-
import com.gregtechceu.gtceu.api.data.chemical.material.properties.PropertyKey;
6+
import com.gregtechceu.gtceu.api.data.chemical.material.info.MaterialIconSet;
7+
import com.gregtechceu.gtceu.api.data.chemical.material.info.MaterialIconType;
88
import com.gregtechceu.gtceu.api.data.tag.TagPrefix;
99
import com.gregtechceu.gtceu.data.pack.GTDynamicResourcePack;
10+
import com.gregtechceu.gtceu.utils.memoization.GTMemoizer;
11+
import com.gregtechceu.gtceu.utils.memoization.function.MemoizedBiFunction;
1012

1113
import net.minecraft.MethodsReturnNonnullByDefault;
1214
import net.minecraft.client.Minecraft;
1315
import net.minecraft.core.registries.BuiltInRegistries;
1416
import net.minecraft.data.models.BlockModelGenerators;
1517
import net.minecraft.data.models.model.*;
1618
import net.minecraft.resources.ResourceLocation;
19+
import net.minecraft.server.packs.resources.Resource;
20+
import net.minecraft.server.packs.resources.ResourceManager;
1721
import net.minecraft.util.GsonHelper;
1822

19-
import com.google.common.base.Preconditions;
2023
import com.google.gson.JsonObject;
24+
import org.jetbrains.annotations.ApiStatus;
2125

2226
import java.io.BufferedReader;
2327
import java.io.IOException;
2428
import java.util.HashSet;
29+
import java.util.Optional;
2530
import java.util.Set;
2631

2732
@MethodsReturnNonnullByDefault
2833
public class OreBlockRenderer {
2934

30-
private static final Set<OreBlockRenderer> MODELS = new HashSet<>();
35+
protected static final Set<OreBlockRenderer> MODELS = new HashSet<>();
3136

32-
private final MaterialBlock block;
37+
protected static final JsonObject NULL_ELEMENT_MARKER = new JsonObject();
38+
protected static final MemoizedBiFunction<MaterialIconType, MaterialIconSet, JsonObject> TEMPLATE_MODEL_CACHE = GTMemoizer
39+
.memoizeFunctionWeakIdent(OreBlockRenderer::loadTemplateOreModel);
40+
41+
// First format key is material set name, 2nd is stone type prefix's name, 3rd is icon type's name
42+
public static final String ORE_MODEL_NAME_FORMAT = "block/material_sets/%s/ores/%s/%s";
43+
44+
protected final MaterialBlock block;
3345

3446
public static void create(MaterialBlock block) {
3547
MODELS.add(new OreBlockRenderer(block));
@@ -39,56 +51,81 @@ public OreBlockRenderer(MaterialBlock block) {
3951
this.block = block;
4052
}
4153

54+
@ApiStatus.Internal
4255
public static void reinitModels() {
56+
// first set up all the stone types for all tag prefixes
57+
for (MaterialIconSet iconSet : MaterialIconSet.ICON_SETS.values()) {
58+
for (var entry : TagPrefix.ORES.entrySet()) {
59+
copyOreModelWithBaseStone(entry.getKey(), entry.getValue(), MaterialIconType.ore, iconSet);
60+
copyOreModelWithBaseStone(entry.getKey(), entry.getValue(), MaterialIconType.oreEmissive, iconSet);
61+
// TODO uncomment if/when small ores are added
62+
// copyOreModelWithBaseStone(entry.getKey(), entry.getValue(), MaterialIconType.oreSmall, iconSet);
63+
}
64+
}
65+
66+
// then create block state JSONs for all ore blocks with those models
4367
for (OreBlockRenderer model : MODELS) {
68+
Material material = model.block.material;
69+
TagPrefix tagPrefix = model.block.tagPrefix;
70+
MaterialIconSet iconSet = material.getMaterialIconSet();
71+
MaterialIconType iconType = tagPrefix.getMaterialIconType(material);
72+
4473
ResourceLocation blockId = BuiltInRegistries.BLOCK.getKey(model.block);
45-
ResourceLocation modelId = blockId.withPrefix("block/");
46-
OreBlockRenderer.cloneBlockModel(blockId, model.block.tagPrefix, model.block.material);
74+
ResourceLocation modelId = GTCEu.id(ORE_MODEL_NAME_FORMAT
75+
.formatted(iconSet.name, tagPrefix.name, iconType.name()));
76+
4777
GTDynamicResourcePack.addBlockState(blockId, BlockModelGenerators.createSimpleBlock(model.block, modelId));
4878
GTDynamicResourcePack.addItemModel(BuiltInRegistries.ITEM.getKey(model.block.asItem()),
49-
new DelegatedModel(ModelLocationUtils.getModelLocation(model.block)));
79+
new DelegatedModel(modelId));
5080
}
51-
}
5281

53-
/**
54-
* Clones & modifies the base JSON for a single ore block.
55-
*
56-
* @param modelId the model id (usually {@code gtceu:block/<block id path>})
57-
* @param prefix the TagPrefix of the block being added.
58-
* @param material the material of the block being added. must have an ore property.
59-
*/
60-
public static void cloneBlockModel(ResourceLocation modelId, TagPrefix prefix, Material material) {
61-
OreProperty prop = material.getProperty(PropertyKey.ORE);
62-
Preconditions.checkNotNull(prop,
63-
"material %s has no ore property, but needs one for an ore model!".formatted(material.getName()));
82+
TEMPLATE_MODEL_CACHE.getCache().clear();
83+
}
6484

85+
/// This is called for every combination of tag prefix + icon type + icon set
86+
protected static void copyOreModelWithBaseStone(TagPrefix tagPrefix, TagPrefix.OreType oreType,
87+
MaterialIconType iconType, MaterialIconSet iconSet) {
6588
// read the base ore model JSON
6689
JsonObject original;
67-
try (BufferedReader reader = Minecraft.getInstance().getResourceManager()
68-
.openAsReader(GTCEu.id("models/block/ore%s.json".formatted(prop.isEmissive() ? "_emissive" : "")))) {
69-
original = GsonHelper.parse(reader, true);
70-
} catch (IOException e) {
71-
throw new RuntimeException(e);
90+
try {
91+
original = TEMPLATE_MODEL_CACHE.apply(iconType, iconSet);
92+
} catch (RuntimeException e) {
93+
GTCEu.LOGGER.error("Could not load template block model for ore type {}, icon type '{}', icon set '{}'",
94+
tagPrefix.name, iconType.name(), iconSet.name, e);
95+
return;
96+
}
97+
if (original == NULL_ELEMENT_MARKER) {
98+
// if the icon set doesn't have an ore model (somehow...), skip it
99+
return;
72100
}
73101

74-
// clone it
102+
// copy it
75103
JsonObject newJson = original.deepCopy();
76-
JsonObject children = newJson.getAsJsonObject("children");
77-
// add the base stone texture.
78-
children.getAsJsonObject("base_stone")
79-
.addProperty("parent", TagPrefix.ORES.get(prefix).baseModelLocation().toString());
104+
// add the base stone model.
105+
newJson.getAsJsonObject("children")
106+
.getAsJsonObject("base_stone")
107+
.addProperty("parent", oreType.baseModelLocation().toString());
80108

81-
ResourceLocation layer0 = prefix.materialIconType()
82-
.getBlockTexturePath(material.getMaterialIconSet(), true);
83-
ResourceLocation layer1 = prefix.materialIconType()
84-
.getBlockTexturePath(material.getMaterialIconSet(), "layer2", true);
109+
GTDynamicResourcePack.addBlockModel(
110+
GTCEu.id(ORE_MODEL_NAME_FORMAT.formatted(iconSet.name, tagPrefix.name, iconType.name())), newJson);
111+
}
85112

86-
JsonObject oresTextures = children.getAsJsonObject("ore_texture").getAsJsonObject("textures");
87-
oresTextures.addProperty("layer0", layer0.toString());
88-
oresTextures.addProperty("layer1", layer1.toString());
113+
private static JsonObject loadTemplateOreModel(MaterialIconType iconType, MaterialIconSet iconSet) {
114+
ResourceLocation baseModelPath = iconType.getBlockModelPath(iconSet, true);
115+
baseModelPath = GTDynamicResourcePack.MODEL_ID_CONVERTER.idToFile(baseModelPath);
89116

90-
newJson.getAsJsonObject("textures").addProperty("particle", layer0.toString());
117+
ResourceManager resourceManager = Minecraft.getInstance().getResourceManager();
118+
Optional<Resource> modelResource = resourceManager.getResource(baseModelPath);
91119

92-
GTDynamicResourcePack.addBlockModel(modelId, newJson);
120+
if (modelResource.isEmpty()) {
121+
// if the icon set doesn't have an ore model (somehow...), skip it gracefully
122+
return NULL_ELEMENT_MARKER;
123+
}
124+
// read & cache the base ore model JSON
125+
try (BufferedReader reader = modelResource.get().openAsReader()) {
126+
return GsonHelper.parse(reader, true);
127+
} catch (IOException e) {
128+
throw new RuntimeException(e);
129+
}
93130
}
94131
}

src/main/java/com/gregtechceu/gtceu/config/ConfigHolder.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -862,13 +862,18 @@ public static class RendererConfigs {
862862
@Configurable.Comment({ "Render growing plants in multiblocks that support them?", "Default: true" })
863863
public boolean renderGrowingPlants = true;
864864

865+
@Configurable
866+
@Configurable.Comment({ "Whether or not to color material/ore block highlights in the material color",
867+
"Default: true" })
868+
public boolean coloredMaterialBlockOutline = true;
869+
865870
@Configurable
866871
@Configurable.Comment({ "Whether or not to color tiered machine highlights in the tier color",
867872
"Default: true" })
868873
public boolean coloredTieredMachineOutline = true;
869874

870875
@Configurable
871-
@Configurable.Comment({ "Whether or not to color wire/cable highlights based on voltage tier",
876+
@Configurable.Comment({ "Whether or not to color wire/cable highlights based on voltage tier or material color",
872877
"Default: true" })
873878
public boolean coloredWireOutline = true;
874879
}

src/main/java/com/gregtechceu/gtceu/core/mixins/client/LevelRendererMixin.java

Lines changed: 11 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import net.minecraft.client.Minecraft;
2020
import net.minecraft.client.multiplayer.ClientLevel;
2121
import net.minecraft.client.renderer.*;
22-
import net.minecraft.client.resources.model.BakedModel;
2322
import net.minecraft.client.resources.model.ModelBakery;
2423
import net.minecraft.core.BlockPos;
2524
import net.minecraft.server.level.BlockDestructionProgress;
@@ -44,7 +43,6 @@
4443
import com.mojang.blaze3d.vertex.SheetedDecalTextureGenerator;
4544
import com.mojang.blaze3d.vertex.VertexConsumer;
4645
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
47-
import org.jetbrains.annotations.NotNull;
4846
import org.jetbrains.annotations.Nullable;
4947
import org.joml.Matrix4f;
5048
import org.spongepowered.asm.mixin.Final;
@@ -177,26 +175,25 @@ private static void renderShape(PoseStack poseStack, VertexConsumer consumer, Vo
177175
assert level != null;
178176
var rendererCfg = ConfigHolder.INSTANCE.client.renderer;
179177
int rgb = 0;
180-
boolean doRenderColoredOutline = false;
178+
boolean renderColoredOutline = false;
181179

182180
// spotless:off
183-
// if it's translucent and a material block, always do the colored outline
184-
MaterialEntry materialEntry = gtceu$getTranslucentBlockMaterial(state, pos);
185-
if (!materialEntry.isEmpty()) {
186-
doRenderColoredOutline = true;
181+
MaterialEntry materialEntry = ChemicalHelper.getMaterialEntry(state.getBlock());
182+
if (rendererCfg.coloredMaterialBlockOutline && !materialEntry.isEmpty()) {
183+
renderColoredOutline = true;
187184
rgb = materialEntry.material().getMaterialRGB();
188185
} else if (level.getBlockEntity(pos) instanceof IMachineBlockEntity mbe) {
189186
if (rendererCfg.coloredTieredMachineOutline) {
190187
if (mbe.getMetaMachine() instanceof SteamMachine steam) {
191-
doRenderColoredOutline = true;
188+
renderColoredOutline = true;
192189
rgb = steam.isHighPressure() ? GTValues.VC_HP_STEAM : GTValues.VC_LP_STEAM;
193190
} else if (mbe.getMetaMachine() instanceof ITieredMachine tiered) {
194-
doRenderColoredOutline = true;
191+
renderColoredOutline = true;
195192
rgb = GTValues.VCM[tiered.getTier()];
196193
}
197194
}
198195
} else if (rendererCfg.coloredWireOutline && level.getBlockEntity(pos) instanceof IPipeNode<?, ?> pipe) {
199-
doRenderColoredOutline = true;
196+
renderColoredOutline = true;
200197
if (!pipe.getFrameMaterial().isNull()) {
201198
rgb = pipe.getFrameMaterial().getMaterialRGB();
202199
} else if (pipe instanceof CableBlockEntity cable) {
@@ -205,48 +202,18 @@ private static void renderShape(PoseStack poseStack, VertexConsumer consumer, Vo
205202
rgb = materialPipe.material.getMaterialRGB();
206203
}
207204
}
208-
209-
VoxelShape blockShape = state.getShape(level, pos, CollisionContext.of(entity));
210205
// spotless:on
211-
if (doRenderColoredOutline) {
206+
VoxelShape blockShape = state.getShape(level, pos, CollisionContext.of(entity));
207+
208+
if (renderColoredOutline) {
212209
float red = FastColor.ARGB32.red(rgb) / 255f;
213210
float green = FastColor.ARGB32.green(rgb) / 255f;
214211
float blue = FastColor.ARGB32.blue(rgb) / 255f;
215212
renderShape(poseStack, consumer, blockShape,
216213
pos.getX() - camX, pos.getY() - camY, pos.getZ() - camZ,
217-
red, green, blue, 1f);
214+
red, green, blue, 0.4f);
218215
return;
219216
}
220-
BlockPos.MutableBlockPos mutable = pos.mutable();
221-
for (BlockPos o : GTUtil.NON_CORNER_NEIGHBOURS) {
222-
BlockPos offset = mutable.setWithOffset(pos, o);
223-
if (!gtceu$getTranslucentBlockMaterial(level.getBlockState(offset), offset).isEmpty()) {
224-
renderShape(poseStack, consumer, blockShape,
225-
pos.getX() - camX, pos.getY() - camY, pos.getZ() - camZ,
226-
0, 0, 0, 1f);
227-
return;
228-
}
229-
}
230217
original.call(instance, poseStack, consumer, entity, camX, camY, camZ, pos, state);
231218
}
232-
233-
@Unique
234-
private @NotNull MaterialEntry gtceu$getTranslucentBlockMaterial(BlockState state, BlockPos pos) {
235-
assert level != null;
236-
// skip non-solid blocks from other mods (like vanilla ice blocks)
237-
if (!state.isSolidRender(level, pos) && !(state.getBlock() instanceof MaterialBlock)) {
238-
return MaterialEntry.NULL_ENTRY;
239-
}
240-
241-
BakedModel blockModel = minecraft.getBlockRenderer().getBlockModel(state);
242-
ModelData modelData = level.getModelDataManager().getAt(pos);
243-
if (modelData == null) modelData = ModelData.EMPTY;
244-
modelData = blockModel.getModelData(level, pos, state, modelData);
245-
246-
gtceu$modelRandom.setSeed(state.getSeed(pos));
247-
if (blockModel.getRenderTypes(state, gtceu$modelRandom, modelData).contains(RenderType.translucent())) {
248-
return ChemicalHelper.getMaterialEntry(state.getBlock());
249-
}
250-
return MaterialEntry.NULL_ENTRY;
251-
}
252219
}

src/main/java/com/gregtechceu/gtceu/data/pack/GTDynamicResourcePack.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,9 @@ public class GTDynamicResourcePack implements PackResources {
5656
protected static final GTDynamicPackContents CONTENTS = new GTDynamicPackContents();
5757

5858
private static final FileToIdConverter ATLAS_ID_CONVERTER = FileToIdConverter.json("atlases");
59-
private static final FileToIdConverter TEXTURE_ID_CONVERTER = SpriteSource.TEXTURE_ID_CONVERTER;
59+
public static final FileToIdConverter TEXTURE_ID_CONVERTER = SpriteSource.TEXTURE_ID_CONVERTER;
6060
public static final FileToIdConverter BLOCKSTATE_ID_CONVERTER = FileToIdConverter.json("blockstates");
61-
private static final FileToIdConverter MODEL_ID_CONVERTER = FileToIdConverter.json("models");
61+
public static final FileToIdConverter MODEL_ID_CONVERTER = FileToIdConverter.json("models");
6262

6363
private final String name;
6464

0 commit comments

Comments
 (0)