Additional ISBRH compat + JSONModel Compat from GTNHLib (#54)

This commit is contained in:
Ryan Nasers authored and GitHub committed 2026-09-06 23:45:06 +02:00
1 parent f10595d062
commit 2d050bdd08
15 files changed
+307 -28

No files matched your search

+1 -1
View File
@@ -25,6 +25,6 @@ whitelist.json
*.iml *.iml
*.ipr *.ipr
*.iws *.iws
src/main/resources/mixins.*.json src/main/resources/mixins.*.refmap.json
*.bat *.bat
layout.json layout.json
+4 -1
View File
@@ -1,10 +1,13 @@
// Add your dependencies here // Add your dependencies here
dependencies { dependencies {
implementation("com.github.GTNewHorizons:CodeChickenCore:1.4.12:dev") implementation("com.github.GTNewHorizons:CodeChickenCore:1.4.19:dev")
compileOnly("com.github.GTNewHorizons:Angelica:2.1.19:dev") compileOnly("com.github.GTNewHorizons:Angelica:2.1.19:dev")
compileOnly("com.github.GTNewHorizons:Postea:1.2.5:dev") {transitive = false} compileOnly("com.github.GTNewHorizons:Postea:1.2.5:dev") {transitive = false}
devOnlyNonPublishable("com.github.GTNewHorizons:NotEnoughItems:2.8.93-GTNH:dev") { devOnlyNonPublishable("com.github.GTNewHorizons:NotEnoughItems:2.8.93-GTNH:dev") {
exclude group: 'com.github.GTNewHorizons', module: 'CodeChickenCore' exclude group: 'com.github.GTNewHorizons', module: 'CodeChickenCore'
} }
compileOnly("com.github.GTNewHorizons:GTNHLib:0.11.44:dev")
// devOnlyNonPublishable("com.github.GTNewHorizons:Angelica:2.2.10:dev")
devOnlyNonPublishable("io.github.legacymoddingmc:unimixins:0.1.23:dev")
} }
+5 -5
View File
@@ -107,15 +107,15 @@ apiPackage =
accessTransformersFile = multipart_at.cfg accessTransformersFile = multipart_at.cfg
# Provides setup for Mixins if enabled. If you don't know what mixins are: Keep it disabled! # Provides setup for Mixins if enabled. If you don't know what mixins are: Keep it disabled!
usesMixins = false usesMixins = true
# Set to a non-empty string to configure mixins in a separate source set under src/VALUE, instead of src/main. # Set to a non-empty string to configure mixins in a separate source set under src/VALUE, instead of src/main.
# This can speed up compile times thanks to not running the mixin annotation processor on all input sources. # This can speed up compile times thanks to not running the mixin annotation processor on all input sources.
# Mixin classes will have access to "main" classes, but not the other way around. # Mixin classes will have access to "main" classes, but not the other way around.
separateMixinSourceSet = separateMixinSourceSet = mixin
# Adds some debug arguments like verbose output and class export. # Adds some debug arguments like verbose output and class export.
usesMixinDebug = false usesMixinDebug = true
# Specify the location of your implementation of IMixinConfigPlugin. Leave it empty otherwise. # Specify the location of your implementation of IMixinConfigPlugin. Leave it empty otherwise.
mixinPlugin = mixinPlugin =
@@ -123,12 +123,12 @@ mixinPlugin =
# Specify the package that contains all of your Mixins. The package must exist or # Specify the package that contains all of your Mixins. The package must exist or
# the build will fail. If you have a package property defined in your mixins.<modid>.json, # the build will fail. If you have a package property defined in your mixins.<modid>.json,
# it must match with this or the build will fail. # it must match with this or the build will fail.
mixinsPackage = mixinsPackage = multipart.mixin
# Specify the core mod entry class if you use a core mod. This class must implement IFMLLoadingPlugin! # Specify the core mod entry class if you use a core mod. This class must implement IFMLLoadingPlugin!
# This parameter is for legacy compatibility only # This parameter is for legacy compatibility only
# Example value: (coreModClass = asm.FMLPlugin) + (modGroup = com.myname.mymodid) -> com.myname.mymodid.asm.FMLPlugin # Example value: (coreModClass = asm.FMLPlugin) + (modGroup = com.myname.mymodid) -> com.myname.mymodid.asm.FMLPlugin
coreModClass = coreModClass = multipart.mixin.FMPMixinLoader
# If your project is only a consolidation of mixins or a core mod and does NOT contain a 'normal' mod ( = some class # If your project is only a consolidation of mixins or a core mod and does NOT contain a 'normal' mod ( = some class
# that is annotated with @Mod) you want this to be true. When in doubt: leave it on false! # that is annotated with @Mod) you want this to be true. When in doubt: leave it on false!
+1
View File
@@ -1,4 +1,5 @@
// Add any additional repositiroes for your dependencies here // Add any additional repositiroes for your dependencies here
repositories { repositories {
mavenLocal()
} }
@@ -0,0 +1,47 @@
package codechicken.multipart.mixin;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.gtnewhorizon.gtnhmixins.IEarlyMixinLoader;
import com.gtnewhorizon.gtnhmixins.builders.IMixins;
import cpw.mods.fml.relauncher.IFMLLoadingPlugin;
@IFMLLoadingPlugin.MCVersion("1.7.10")
public class FMPMixinLoader implements IFMLLoadingPlugin, IEarlyMixinLoader {
@Override
public String[] getASMTransformerClass() {
return null;
}
@Override
public String getModContainerClass() {
return null;
}
@Override
public String getSetupClass() {
return null;
}
@Override
public void injectData(Map<String, Object> data) {}
@Override
public String getAccessTransformerClass() {
return null;
}
@Override
public String getMixinConfig() {
return "mixins.ForgeMultipart.early.json";
}
@Override
public List<String> getMixins(Set<String> loadedCoreMods) {
return IMixins.getEarlyMixins(Mixins.class, loadedCoreMods);
}
}
@@ -0,0 +1,24 @@
package codechicken.multipart.mixin;
import javax.annotation.Nonnull;
import com.gtnewhorizon.gtnhmixins.builders.IMixins;
import com.gtnewhorizon.gtnhmixins.builders.MixinBuilder;
public enum Mixins implements IMixins {
RENDER_GLOBAL_MIXIN(new MixinBuilder("Redirects part block break renders to ISBRHModel")
.addClientMixins("MixinRenderGlobal").addRequiredMod(TargetedMod.GTNHLIB).setPhase(Phase.EARLY));
private final MixinBuilder builder;
Mixins(MixinBuilder builder) {
this.builder = builder;
}
@Nonnull
@Override
public MixinBuilder getBuilder() {
return this.builder;
}
}
@@ -0,0 +1,31 @@
package codechicken.multipart.mixin;
import javax.annotation.Nonnull;
import com.gtnewhorizon.gtnhmixins.builders.ITargetMod;
import com.gtnewhorizon.gtnhmixins.builders.TargetModBuilder;
public enum TargetedMod implements ITargetMod {
GTNHLIB("GTNHLib Core", "gtnhlib");
private final TargetModBuilder builder;
TargetedMod(String modId) {
this(null, modId, null);
}
TargetedMod(String coreModClass, String modId) {
this(coreModClass, modId, null);
}
TargetedMod(String coreModClass, String modId, String targetClass) {
this.builder = new TargetModBuilder().setCoreModClass(coreModClass).setModId(modId).setTargetClass(targetClass);
}
@Nonnull
@Override
public TargetModBuilder getBuilder() {
return builder;
}
}
@@ -0,0 +1,11 @@
{
"required": true,
"minVersion": "0.8.5-GTNH",
"package": "codechicken.multipart.mixin.early",
"refmap": "mixins.ForgeMultipart.refmap.json",
"target": "@env(DEFAULT)",
"mixinextras": {
"minVersion": "0.5.0"
},
"compatibilityLevel": "JAVA_8"
}
@@ -0,0 +1,7 @@
{
"required": true,
"minVersion": "0.8.5-GTNH",
"refmap": "mixins.ForgeMultipart.refmap.json",
"target": "@env(DEFAULT)",
"compatibilityLevel": "JAVA_8"
}
@@ -0,0 +1,18 @@
package codechicken.multipart;
import net.minecraft.block.Block;
import net.minecraft.world.IBlockAccess;
public interface JsonModeledPart {
Block getBlock();
/**
* Use to give your part a world that can be used to define properties for rendering. For example having your world
* returning your block with some specific state such as meta you can override the getMeta for the input location to
* be the meta you desire
*
* @return The world to use
*/
IBlockAccess getRenderWorld();
}
@@ -5,18 +5,14 @@ import codechicken.lib.vec.Vector3
import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler
import cpw.mods.fml.client.registry.RenderingRegistry import cpw.mods.fml.client.registry.RenderingRegistry
import net.minecraft.block.Block import net.minecraft.block.Block
import net.minecraft.client.renderer.{Tessellator, RenderBlocks} import net.minecraft.client.renderer.{RenderBlocks, Tessellator}
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer
import net.minecraft.tileentity.TileEntity import net.minecraft.tileentity.TileEntity
import net.minecraft.world.IBlockAccess import net.minecraft.world.IBlockAccess
import net.minecraft.client.Minecraft
import net.minecraftforge.client.ForgeHooksClient
import net.minecraftforge.client.MinecraftForgeClient import net.minecraftforge.client.MinecraftForgeClient
import cpw.mods.fml.relauncher.SideOnly import cpw.mods.fml.relauncher.SideOnly
import cpw.mods.fml.relauncher.Side import cpw.mods.fml.relauncher.Side
import codechicken.lib.raytracer.ExtendedMOP import codechicken.multipart.RenderPartResolver
import codechicken.lib.lighting.LightMatrix
import com.gtnewhorizons.angelica.api.ThreadSafeISBRH
/** Internal class for rendering callbacks. Should be moved to the handler /** Internal class for rendering callbacks. Should be moved to the handler
* package * package
@@ -67,19 +63,15 @@ object MultipartRenderer
return false return false
if (renderer.hasOverrideBlockTexture) { if (renderer.hasOverrideBlockTexture) {
val hit = Minecraft.getMinecraft.objectMouseOver val part =
if ( RenderPartResolver.resolve(world, x, y, z)
hit != null && hit.blockX == x && hit.blockY == y && hit.blockZ == z && ExtendedMOP if (part != null) {
.getData(hit) part match {
.isInstanceOf[(_, _)] case isbrh: ISBRHPart =>
) { isbrh.renderWorldBlock(world, x, y, z, renderer)
val hitInfo: (Int, _) = ExtendedMOP.getData(hit) case _ =>
if ( part.drawBreaking(renderer)
hitInfo._1.isInstanceOf[ }
Int
] && hitInfo._1 >= 0 && hitInfo._1 < tmpart.partList.size
)
tmpart.partList(hitInfo._1).drawBreaking(renderer)
} }
return false return false
} }
@@ -0,0 +1,59 @@
package codechicken.multipart;
import net.minecraft.client.Minecraft;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.world.IBlockAccess;
import codechicken.lib.raytracer.ExtendedMOP;
import scala.Tuple2;
/**
* A helper class for resolving parts so we don't do a double look up
*/
public final class RenderPartResolver {
public static TMultiPart resolve(IBlockAccess world, int x, int y, int z) {
if (world == null) {
return null;
}
// Make sure the hit is actually this block.
MovingObjectPosition hit = Minecraft.getMinecraft().objectMouseOver;
if (hit == null || hit.blockX != x || hit.blockY != y || hit.blockZ != z) {
return null;
}
Object data = ExtendedMOP.getData(hit);
if (!(data instanceof Tuple2)) {
return null;
}
Tuple2<?, ?> hitInfo = (Tuple2<?, ?>) data;
Object indexObject = hitInfo._1();
if (!(indexObject instanceof Integer)) {
return null;
}
int index = (Integer) indexObject;
TileMultipartClient tile = getMultipartTile(world, x, y, z);
if (tile == null) {
return null;
}
// Needed because scala is stupid and the client tile doesn't expose what we need.
TileMultipart multipart = (TileMultipart) tile;
if (index < 0 || index >= multipart.jPartList().size()) {
return null;
}
return multipart.jPartList().get(index);
}
private static TileMultipartClient getMultipartTile(IBlockAccess world, int x, int y, int z) {
if (world.getTileEntity(x, y, z) instanceof TileMultipartClient) {
return (TileMultipartClient) world.getTileEntity(x, y, z);
}
return null;
}
}
@@ -30,7 +30,7 @@ import net.minecraft.util.{AxisAlignedBB, Vec3}
import java.lang.Iterable import java.lang.Iterable
import codechicken.lib.world.IChunkLoadTile import codechicken.lib.world.IChunkLoadTile
import net.minecraft.block.Block import com.gtnewhorizon.gtnhlib.client.model.ModelISBRH
import net.minecraft.client.renderer.RenderBlocks import net.minecraft.client.renderer.RenderBlocks
import net.minecraftforge.client.ForgeHooksClient import net.minecraftforge.client.ForgeHooksClient
@@ -534,6 +534,22 @@ trait TileMultipartClient extends TileMultipart {
return return
part match { part match {
case jsonModeledPart: JsonModeledPart =>
if (
ModelISBRH.INSTANCE
.get()
.renderWorldBlock(
jsonModeledPart.getRenderWorld,
vec.x.toInt,
vec.y.toInt,
vec.z.toInt,
jsonModeledPart.getBlock,
ModelISBRH.JSON_ISBRH_ID,
renderer
)
) {
rendered = true
}
case isbrh: ISBRHPart => case isbrh: ISBRHPart =>
if ( if (
isbrh.renderWorldBlock( isbrh.renderWorldBlock(
@@ -29,7 +29,7 @@ class MultipartProxy_serverImpl {
.setComment("Multipart API config file") .setComment("Multipart API config file")
GameRegistry.registerBlock( GameRegistry.registerBlock(
new BlockMultipart().setBlockName("multipart"), new BlockMultipart().setBlockName("codechicken/multipart"),
null, null,
"block" "block"
) )
@@ -0,0 +1,70 @@
package codechicken.multipart.mixin.early;
import net.minecraft.block.Block;
import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.client.renderer.RenderBlocks;
import net.minecraft.client.renderer.RenderGlobal;
import net.minecraft.util.IIcon;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import com.gtnewhorizon.gtnhlib.client.model.ModelISBRH;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import codechicken.multipart.JsonModeledPart;
import codechicken.multipart.RenderPartResolver;
import codechicken.multipart.TMultiPart;
@Mixin(RenderGlobal.class)
public class MixinRenderGlobal {
@Shadow
private WorldClient theWorld;
@Redirect(
method = "drawBlockDamageTexture(Lnet/minecraft/client/renderer/Tessellator;Lnet/minecraft/entity/EntityLivingBase;F)V",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/client/multiplayer/WorldClient;getBlock(III)Lnet/minecraft/block/Block;"))
private Block forgemultipart$redirectDamageBlock(WorldClient world, int x, int y, int z) {
Block block = world.getBlock(x, y, z);
TMultiPart part = RenderPartResolver.resolve(world, x, y, z);
if (part instanceof JsonModeledPart) {
return ((JsonModeledPart) part).getBlock();
}
return block;
}
@WrapOperation(
method = "drawBlockDamageTexture(Lnet/minecraft/client/renderer/Tessellator;Lnet/minecraft/entity/EntityLivingBase;F)V",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/client/renderer/RenderBlocks;renderBlockUsingTexture(Lnet/minecraft/block/Block;IIILnet/minecraft/util/IIcon;)V"))
private void forgemultipart$redirectBreakingModeledPartDraw(RenderBlocks instance, Block block, int x, int y, int z,
IIcon overrideTexture, Operation<Void> original) {
TMultiPart candidatePart = RenderPartResolver.resolve(theWorld, x, y, z);
if (candidatePart instanceof JsonModeledPart) {
JsonModeledPart part = (JsonModeledPart) candidatePart;
instance.setOverrideBlockTexture(overrideTexture);
try {
ModelISBRH.INSTANCE.get().renderWorldBlock(
part.getRenderWorld(),
x,
y,
z,
part.getBlock(),
ModelISBRH.JSON_ISBRH_ID,
instance);
} finally {
instance.clearOverrideBlockTexture();
}
} else {
original.call(instance, block, x, y, z, overrideTexture);
}
}
}