Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ public record MaterialIconType(String name) {
public static final MaterialIconType molten = new MaterialIconType("molten");
public static final MaterialIconType block = new MaterialIconType("block");
public static final MaterialIconType ore = new MaterialIconType("ore");
public static final MaterialIconType oreEmissive = new MaterialIconType("oreEmissive");
public static final MaterialIconType oreSmall = new MaterialIconType("oreSmall");
public static final MaterialIconType frameGt = new MaterialIconType("frameGt");
public static final MaterialIconType wire = new MaterialIconType("wire");
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/com/gregtechceu/gtceu/api/data/tag/TagPrefix.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.gregtechceu.gtceu.api.data.chemical.material.Material;
import com.gregtechceu.gtceu.api.data.chemical.material.info.MaterialFlags;
import com.gregtechceu.gtceu.api.data.chemical.material.info.MaterialIconType;
import com.gregtechceu.gtceu.api.data.chemical.material.properties.OreProperty;
import com.gregtechceu.gtceu.api.data.chemical.material.properties.PropertyKey;
import com.gregtechceu.gtceu.api.data.chemical.material.stack.MaterialStack;
import com.gregtechceu.gtceu.api.item.MaterialBlockItem;
Expand Down Expand Up @@ -1232,6 +1233,17 @@ public boolean doGenerateBlock(Material material) {
hasItemTable() && this.itemTable.get() != null && getItemFromTable(material) != null;
}

public MaterialIconType getMaterialIconType(Material material) {
// special case emissive ores
if (materialIconType == MaterialIconType.ore && material.hasProperty(PropertyKey.ORE)) {
OreProperty oreProp = material.getProperty(PropertyKey.ORE);
if (oreProp.isEmissive()) {
return MaterialIconType.oreEmissive;
}
}
return materialIconType;
}

public String getLowerCaseName() {
return FormattingUtil.toLowerCaseUnderscore(this.name);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@

public class MaterialBlockRenderer {

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

public static void create(Block block, MaterialIconType type, MaterialIconSet iconSet) {
Expand All @@ -25,12 +24,11 @@ public static void create(Block block, MaterialIconType type, MaterialIconSet ic
public static void reinitModels() {
for (MaterialBlockRenderer model : MODELS) {
ResourceLocation blockId = BuiltInRegistries.BLOCK.getKey(model.block);
ResourceLocation modelId = blockId.withPrefix("block/");
GTDynamicResourcePack.addBlockModel(blockId,
new DelegatedModel(model.type.getBlockModelPath(model.iconSet, true)));
ResourceLocation modelId = model.type.getBlockModelPath(model.iconSet, true);

GTDynamicResourcePack.addBlockState(blockId, BlockModelGenerators.createSimpleBlock(model.block, modelId));
GTDynamicResourcePack.addItemModel(BuiltInRegistries.ITEM.getKey(model.block.asItem()),
new DelegatedModel(ModelLocationUtils.getModelLocation(model.block)));
new DelegatedModel(modelId));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,45 @@
import com.gregtechceu.gtceu.GTCEu;
import com.gregtechceu.gtceu.api.block.MaterialBlock;
import com.gregtechceu.gtceu.api.data.chemical.material.Material;
import com.gregtechceu.gtceu.api.data.chemical.material.properties.OreProperty;
import com.gregtechceu.gtceu.api.data.chemical.material.properties.PropertyKey;
import com.gregtechceu.gtceu.api.data.chemical.material.info.MaterialIconSet;
import com.gregtechceu.gtceu.api.data.chemical.material.info.MaterialIconType;
import com.gregtechceu.gtceu.api.data.tag.TagPrefix;
import com.gregtechceu.gtceu.data.pack.GTDynamicResourcePack;
import com.gregtechceu.gtceu.utils.memoization.GTMemoizer;
import com.gregtechceu.gtceu.utils.memoization.function.MemoizedBiFunction;

import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.client.Minecraft;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.data.models.BlockModelGenerators;
import net.minecraft.data.models.model.*;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.Resource;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.util.GsonHelper;

import com.google.common.base.Preconditions;
import com.google.gson.JsonObject;
import org.jetbrains.annotations.ApiStatus;

import java.io.BufferedReader;
import java.io.IOException;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;

@MethodsReturnNonnullByDefault
public class OreBlockRenderer {

private static final Set<OreBlockRenderer> MODELS = new HashSet<>();
protected static final Set<OreBlockRenderer> MODELS = new HashSet<>();

private final MaterialBlock block;
protected static final JsonObject NULL_ELEMENT_MARKER = new JsonObject();
protected static final MemoizedBiFunction<MaterialIconType, MaterialIconSet, JsonObject> TEMPLATE_MODEL_CACHE = GTMemoizer
.memoizeFunctionWeakIdent(OreBlockRenderer::loadTemplateOreModel);

// First format key is material set name, 2nd is stone type prefix's name, 3rd is icon type's name
public static final String ORE_MODEL_NAME_FORMAT = "block/material_sets/%s/ores/%s/%s";

protected final MaterialBlock block;

public static void create(MaterialBlock block) {
MODELS.add(new OreBlockRenderer(block));
Expand All @@ -39,56 +51,81 @@ public OreBlockRenderer(MaterialBlock block) {
this.block = block;
}

@ApiStatus.Internal
public static void reinitModels() {
// first set up all the stone types for all tag prefixes
for (MaterialIconSet iconSet : MaterialIconSet.ICON_SETS.values()) {
for (var entry : TagPrefix.ORES.entrySet()) {
copyOreModelWithBaseStone(entry.getKey(), entry.getValue(), MaterialIconType.ore, iconSet);
copyOreModelWithBaseStone(entry.getKey(), entry.getValue(), MaterialIconType.oreEmissive, iconSet);
// TODO uncomment if/when small ores are added
// copyOreModelWithBaseStone(entry.getKey(), entry.getValue(), MaterialIconType.oreSmall, iconSet);
}
}

// then create block state JSONs for all ore blocks with those models
for (OreBlockRenderer model : MODELS) {
Material material = model.block.material;
TagPrefix tagPrefix = model.block.tagPrefix;
MaterialIconSet iconSet = material.getMaterialIconSet();
MaterialIconType iconType = tagPrefix.getMaterialIconType(material);

ResourceLocation blockId = BuiltInRegistries.BLOCK.getKey(model.block);
ResourceLocation modelId = blockId.withPrefix("block/");
OreBlockRenderer.cloneBlockModel(blockId, model.block.tagPrefix, model.block.material);
ResourceLocation modelId = GTCEu.id(ORE_MODEL_NAME_FORMAT
.formatted(iconSet.name, tagPrefix.name, iconType.name()));

GTDynamicResourcePack.addBlockState(blockId, BlockModelGenerators.createSimpleBlock(model.block, modelId));
GTDynamicResourcePack.addItemModel(BuiltInRegistries.ITEM.getKey(model.block.asItem()),
new DelegatedModel(ModelLocationUtils.getModelLocation(model.block)));
new DelegatedModel(modelId));
}
}

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

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

// clone it
// copy it
JsonObject newJson = original.deepCopy();
JsonObject children = newJson.getAsJsonObject("children");
// add the base stone texture.
children.getAsJsonObject("base_stone")
.addProperty("parent", TagPrefix.ORES.get(prefix).baseModelLocation().toString());
// add the base stone model.
newJson.getAsJsonObject("children")
.getAsJsonObject("base_stone")
.addProperty("parent", oreType.baseModelLocation().toString());

ResourceLocation layer0 = prefix.materialIconType()
.getBlockTexturePath(material.getMaterialIconSet(), true);
ResourceLocation layer1 = prefix.materialIconType()
.getBlockTexturePath(material.getMaterialIconSet(), "layer2", true);
GTDynamicResourcePack.addBlockModel(
GTCEu.id(ORE_MODEL_NAME_FORMAT.formatted(iconSet.name, tagPrefix.name, iconType.name())), newJson);
}

JsonObject oresTextures = children.getAsJsonObject("ore_texture").getAsJsonObject("textures");
oresTextures.addProperty("layer0", layer0.toString());
oresTextures.addProperty("layer1", layer1.toString());
private static JsonObject loadTemplateOreModel(MaterialIconType iconType, MaterialIconSet iconSet) {
ResourceLocation baseModelPath = iconType.getBlockModelPath(iconSet, true);
baseModelPath = GTDynamicResourcePack.MODEL_ID_CONVERTER.idToFile(baseModelPath);

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

GTDynamicResourcePack.addBlockModel(modelId, newJson);
if (modelResource.isEmpty()) {
// if the icon set doesn't have an ore model (somehow...), skip it gracefully
return NULL_ELEMENT_MARKER;
}
// read & cache the base ore model JSON
try (BufferedReader reader = modelResource.get().openAsReader()) {
return GsonHelper.parse(reader, true);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -862,13 +862,18 @@ public static class RendererConfigs {
@Configurable.Comment({ "Render growing plants in multiblocks that support them?", "Default: true" })
public boolean renderGrowingPlants = true;

@Configurable
@Configurable.Comment({ "Whether or not to color material/ore block highlights in the material color",
"Default: true" })
public boolean coloredMaterialBlockOutline = true;

@Configurable
@Configurable.Comment({ "Whether or not to color tiered machine highlights in the tier color",
"Default: true" })
public boolean coloredTieredMachineOutline = true;

@Configurable
@Configurable.Comment({ "Whether or not to color wire/cable highlights based on voltage tier",
@Configurable.Comment({ "Whether or not to color wire/cable highlights based on voltage tier or material color",
"Default: true" })
public boolean coloredWireOutline = true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.*;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.client.resources.model.ModelBakery;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.BlockDestructionProgress;
Expand All @@ -44,7 +43,6 @@
import com.mojang.blaze3d.vertex.SheetedDecalTextureGenerator;
import com.mojang.blaze3d.vertex.VertexConsumer;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.joml.Matrix4f;
import org.spongepowered.asm.mixin.Final;
Expand Down Expand Up @@ -177,26 +175,25 @@ private static void renderShape(PoseStack poseStack, VertexConsumer consumer, Vo
assert level != null;
var rendererCfg = ConfigHolder.INSTANCE.client.renderer;
int rgb = 0;
boolean doRenderColoredOutline = false;
boolean renderColoredOutline = false;

// spotless:off
// if it's translucent and a material block, always do the colored outline
MaterialEntry materialEntry = gtceu$getTranslucentBlockMaterial(state, pos);
if (!materialEntry.isEmpty()) {
doRenderColoredOutline = true;
MaterialEntry materialEntry = ChemicalHelper.getMaterialEntry(state.getBlock());
if (rendererCfg.coloredMaterialBlockOutline && !materialEntry.isEmpty()) {
renderColoredOutline = true;
rgb = materialEntry.material().getMaterialRGB();
Comment thread
screret marked this conversation as resolved.
} else if (level.getBlockEntity(pos) instanceof IMachineBlockEntity mbe) {
if (rendererCfg.coloredTieredMachineOutline) {
if (mbe.getMetaMachine() instanceof SteamMachine steam) {
doRenderColoredOutline = true;
renderColoredOutline = true;
rgb = steam.isHighPressure() ? GTValues.VC_HP_STEAM : GTValues.VC_LP_STEAM;
} else if (mbe.getMetaMachine() instanceof ITieredMachine tiered) {
doRenderColoredOutline = true;
renderColoredOutline = true;
rgb = GTValues.VCM[tiered.getTier()];
}
}
} else if (rendererCfg.coloredWireOutline && level.getBlockEntity(pos) instanceof IPipeNode<?, ?> pipe) {
doRenderColoredOutline = true;
renderColoredOutline = true;
if (!pipe.getFrameMaterial().isNull()) {
rgb = pipe.getFrameMaterial().getMaterialRGB();
} else if (pipe instanceof CableBlockEntity cable) {
Expand All @@ -205,48 +202,18 @@ private static void renderShape(PoseStack poseStack, VertexConsumer consumer, Vo
rgb = materialPipe.material.getMaterialRGB();
}
}

VoxelShape blockShape = state.getShape(level, pos, CollisionContext.of(entity));
// spotless:on
if (doRenderColoredOutline) {
VoxelShape blockShape = state.getShape(level, pos, CollisionContext.of(entity));

if (renderColoredOutline) {
float red = FastColor.ARGB32.red(rgb) / 255f;
float green = FastColor.ARGB32.green(rgb) / 255f;
float blue = FastColor.ARGB32.blue(rgb) / 255f;
renderShape(poseStack, consumer, blockShape,
pos.getX() - camX, pos.getY() - camY, pos.getZ() - camZ,
red, green, blue, 1f);
red, green, blue, 0.4f);
return;
}
BlockPos.MutableBlockPos mutable = pos.mutable();
for (BlockPos o : GTUtil.NON_CORNER_NEIGHBOURS) {
BlockPos offset = mutable.setWithOffset(pos, o);
if (!gtceu$getTranslucentBlockMaterial(level.getBlockState(offset), offset).isEmpty()) {
renderShape(poseStack, consumer, blockShape,
pos.getX() - camX, pos.getY() - camY, pos.getZ() - camZ,
0, 0, 0, 1f);
return;
}
}
original.call(instance, poseStack, consumer, entity, camX, camY, camZ, pos, state);
}

@Unique
private @NotNull MaterialEntry gtceu$getTranslucentBlockMaterial(BlockState state, BlockPos pos) {
assert level != null;
// skip non-solid blocks from other mods (like vanilla ice blocks)
if (!state.isSolidRender(level, pos) && !(state.getBlock() instanceof MaterialBlock)) {
return MaterialEntry.NULL_ENTRY;
}

BakedModel blockModel = minecraft.getBlockRenderer().getBlockModel(state);
ModelData modelData = level.getModelDataManager().getAt(pos);
if (modelData == null) modelData = ModelData.EMPTY;
modelData = blockModel.getModelData(level, pos, state, modelData);

gtceu$modelRandom.setSeed(state.getSeed(pos));
if (blockModel.getRenderTypes(state, gtceu$modelRandom, modelData).contains(RenderType.translucent())) {
return ChemicalHelper.getMaterialEntry(state.getBlock());
}
return MaterialEntry.NULL_ENTRY;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ public class GTDynamicResourcePack implements PackResources {
protected static final GTDynamicPackContents CONTENTS = new GTDynamicPackContents();

private static final FileToIdConverter ATLAS_ID_CONVERTER = FileToIdConverter.json("atlases");
private static final FileToIdConverter TEXTURE_ID_CONVERTER = SpriteSource.TEXTURE_ID_CONVERTER;
public static final FileToIdConverter TEXTURE_ID_CONVERTER = SpriteSource.TEXTURE_ID_CONVERTER;
public static final FileToIdConverter BLOCKSTATE_ID_CONVERTER = FileToIdConverter.json("blockstates");
private static final FileToIdConverter MODEL_ID_CONVERTER = FileToIdConverter.json("models");
public static final FileToIdConverter MODEL_ID_CONVERTER = FileToIdConverter.json("models");

private final String name;

Expand Down
Loading
Loading