CTM integration improvements (#1931)

Co-authored-by: Jason Mitchell <mitchej@gmail.com>
This commit is contained in:
SuperSouprandJason Mitchell authored and GitHub committed 2026-07-12 10:45:16 -05:00
1 parent 1c49649685
commit 7017786a7c
7 files changed
+87 -20

No files matched your search

@@ -40,6 +40,7 @@ final class BlockOrientation extends RenderBlockState {
private int altMetadata;
private int metadataBits;
private int renderType;
private boolean iCtmBlock;
private int blockFace;
private int textureFace;
@@ -76,6 +77,11 @@ final class BlockOrientation extends RenderBlockState {
return z;
}
@Override
public int getMetadata() {
return metadata;
}
@Override
public int getBlockFace() {
return blockFace;
@@ -156,8 +162,8 @@ final class BlockOrientation extends RenderBlockState {
@Override
public boolean shouldConnectByBlock(Block neighbor, int neighborX, int neighborY, int neighborZ) {
return block == neighbor
&& (metadataBits & (1 << blockAccess.getBlockMetadata(neighborX, neighborY, neighborZ))) != 0;
return iCtmBlock ? ((ICTMBlock) block).shouldConnectByBlock(this, neighbor, neighborX, neighborY, neighborZ)
: block == neighbor && (metadataBits & (1 << blockAccess.getBlockMetadata(neighborX, neighborY, neighborZ))) != 0;
}
@Override
@@ -175,6 +181,7 @@ final class BlockOrientation extends RenderBlockState {
copy.altMetadata = altMetadata;
copy.metadataBits = metadataBits;
copy.renderType = renderType;
copy.iCtmBlock = iCtmBlock;
copy.blockFace = blockFace;
copy.textureFace = textureFace;
copy.textureFaceOrig = textureFaceOrig;
@@ -203,6 +210,7 @@ final class BlockOrientation extends RenderBlockState {
this.z = z;
renderType = block.getRenderType();
metadata = altMetadata = blockAccess.getBlockMetadata(x, y, z);
iCtmBlock = block instanceof ICTMBlock;
offsetsComputed = false;
}
@@ -223,6 +231,7 @@ final class BlockOrientation extends RenderBlockState {
renderType = block.getRenderType();
blockFace = textureFace = textureFaceOrig = face;
this.metadata = metadata;
iCtmBlock = block instanceof ICTMBlock;
metadataBits = 1 << metadata;
dx = dy = dz = 0;
rotateUV = 0;
@@ -9,6 +9,7 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.StampedLock;
import java.util.function.Consumer;
import com.github.bsideup.jabel.Desugar;
import net.minecraft.block.Block;
@@ -34,10 +35,22 @@ public class CTMUtils {
public static final MCLogger logger = MCLogger.getLogger(MCLogger.Category.CONNECTED_TEXTURES, "CTM");
private static class Overrides {
public static class Overrides {
private final List<TileOverride> all = new ArrayList<>();
private final Map<Block, List<BlockStateMatcher>> block = new IdentityHashMap<>();
private final Map<String, List<TileOverride>> tile = new HashMap<>();
public List<TileOverride> getAll() {
return all;
}
public Map<Block, List<BlockStateMatcher>> getBlock() {
return block;
}
public Map<String, List<TileOverride>> getTile() {
return tile;
}
}
private static Overrides overrides = new Overrides();
@@ -82,6 +95,8 @@ public class CTMUtils {
private static final AtomicInteger texturePackChangeCounter = new AtomicInteger(0);
private static final ArrayList<Consumer<Overrides>> ctmRegistrationCallbacks = new ArrayList<>();
static {
try {
Class.forName(MCPatcherUtils.RENDER_PASS_CLASS)
@@ -117,6 +132,9 @@ public class CTMUtils {
.listResources(TexturePackAPI.MCPATCHER_SUBDIR + "ctm", ".properties", true)) {
registerOverrideWithoutLock(newOverrides, TileOverride.create(resource, tileLoader));
}
for (Consumer<Overrides> callback : ctmRegistrationCallbacks) {
callback.accept(newOverrides);
}
}
for (ResourceLocation resource : BlendMethod.getAllBlankResources()) {
tileLoader.preloadTile(resource, false);
@@ -257,7 +275,7 @@ public class CTMUtils {
return RenderPassAPI.instance.skipDefaultRendering(block);
}
private static void registerOverrideWithoutLock(Overrides overrides, TileOverride override) {
public static void registerOverrideWithoutLock(Overrides overrides, TileOverride override) {
if (override != null && !override.isDisabled()) {
boolean registered = false;
List<BlockStateMatcher> matchingBlocks = override.getMatchingBlocks();
@@ -308,4 +326,8 @@ public class CTMUtils {
private static TileOverrideIterator.Metadata newMetadataIterator() {
return new TileOverrideIterator.Metadata(overrides.block, overrides.tile);
}
public static void addCtmRegistrationCallback(Consumer<Overrides> consumer) {
ctmRegistrationCallbacks.add(consumer);
}
}
@@ -0,0 +1,10 @@
package com.prupe.mcpatcher.ctm;
import net.minecraft.block.Block;
/**
* Implement this interface on blocks that support connected textures to allow them to control if they connect to neighbors or not
*/
public interface ICTMBlock {
boolean shouldConnectByBlock(RenderBlockState renderBlockState, Block neighbor, int neighborX, int neighborY, int neighborZ);
}
@@ -109,6 +109,8 @@ abstract public class RenderBlockState {
abstract public int getZ();
abstract public int getMetadata();
abstract public int getBlockFace();
abstract public int getTextureFace();
@@ -33,7 +33,7 @@ public abstract class TileOverride implements Comparable<TileOverride> {
private static final MCLogger logger = MCLogger.getLogger(MCLogger.Category.CONNECTED_TEXTURES, "CTM");
protected final PropertiesFile properties;
public final PropertiesFile properties;
private final String baseFilename;
protected final TileLoader tileLoader;
protected final int renderPass;
@@ -79,7 +79,10 @@ public abstract class TileOverride implements Comparable<TileOverride> {
if (properties == null) {
return null;
}
return create(properties, tileLoader);
}
public static TileOverride create(PropertiesFile properties, TileLoader tileLoader) {
String method = properties.getString("method", "default")
.toLowerCase();
TileOverride override = null;
@@ -211,7 +214,7 @@ public abstract class TileOverride implements Comparable<TileOverride> {
for (int i = 0;; i++) {
ResourceLocation resource = TileLoader
.parseTileAddress(properties.getResource(), String.valueOf(i), blankResource);
if (!TexturePackAPI.hasResource(resource)) {
if (!TexturePackAPI.hasResource(resource) && !tileLoader.ignoreMissingTextures()) {
break;
}
if (!addIcon(resource)) {
@@ -237,7 +240,7 @@ public abstract class TileOverride implements Comparable<TileOverride> {
.parseTileAddress(properties.getResource(), token, blankResource);
if (resource == null) {
tileNames.add(null);
} else if (TexturePackAPI.hasResource(resource)) {
} else if (TexturePackAPI.hasResource(resource) || tileLoader.ignoreMissingTextures()) {
addIcon(resource);
} else {
properties.warning("could not find image %s", resource);
@@ -252,7 +255,7 @@ public abstract class TileOverride implements Comparable<TileOverride> {
for (int i = from; i <= to; i++) {
ResourceLocation resource = TileLoader
.parseTileAddress(properties.getResource(), String.valueOf(i), blankResource);
if (TexturePackAPI.hasResource(resource)) {
if (TexturePackAPI.hasResource(resource) || tileLoader.ignoreMissingTextures()) {
addIcon(resource);
} else {
properties.warning("could not find image %s", resource);
@@ -9,12 +9,12 @@ import net.minecraft.util.ResourceLocation;
import com.prupe.mcpatcher.MCLogger;
import com.prupe.mcpatcher.MCPatcherUtils;
final public class PropertiesFile {
public class PropertiesFile {
private final MCLogger logger;
private final ResourceLocation resource;
private final String prefix;
private final Properties properties;
protected final MCLogger logger;
protected final ResourceLocation resource;
protected final String prefix;
protected final Properties properties;
private int errorCount;
public static PropertiesFile get(MCLogger logger, ResourceLocation resource) {
@@ -147,4 +147,16 @@ final public class PropertiesFile {
return resource.equals(((PropertiesFile) that).resource);
}
}
public MCLogger getLogger() {
return logger;
}
public String getPrefix() {
return prefix;
}
public Properties getProperties() {
return properties;
}
}
@@ -275,7 +275,7 @@ public class TileLoader {
return false;
}
private boolean registerOneIcon(TextureMap textureMap, String mapName, Map<String, TextureAtlasSprite> map) {
protected boolean registerOneIcon(TextureMap textureMap, String mapName, Map<String, TextureAtlasSprite> map) {
ResourceLocation resource = tilesToRegister.iterator()
.next();
String name = resource.toString();
@@ -304,6 +304,16 @@ public class TileLoader {
return false;
}
}
TextureAtlasSprite icon = registerIconToMap(textureMap, resource, name);
map.put(name, icon);
iconMap.put(name, icon);
String extra = (width == height ? "" : ", " + (height / width) + " frames");
subLogger.finer("%s -> %s icon %dx%d%s", name, mapName, width, width, extra);
tilesToRegister.remove(resource);
return true;
}
protected TextureAtlasSprite registerIconToMap(TextureMap textureMap, ResourceLocation resource, String name) {
TextureAtlasSprite icon;
if(generatedTiles.contains(resource)){
icon = new GeneratedCTMAtlasSprite(this, textureMap.anisotropicFiltering > 1, name);
@@ -311,12 +321,7 @@ public class TileLoader {
}else{
icon = (TextureAtlasSprite)textureMap.registerIcon(name);
}
map.put(name, icon);
iconMap.put(name, icon);
String extra = (width == height ? "" : ", " + (height / width) + " frames");
subLogger.finer("%s -> %s icon %dx%d%s", name, mapName, width, width, extra);
tilesToRegister.remove(resource);
return true;
return icon;
}
public void finish() {
@@ -339,4 +344,8 @@ public class TileLoader {
public IIcon getIcon(ResourceLocation resource) {
return resource == null ? null : getIcon(resource.toString());
}
public boolean ignoreMissingTextures() {
return false;
}
}