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
*.ipr
*.iws
src/main/resources/mixins.*.json
src/main/resources/mixins.*.refmap.json
*.bat
layout.json
+4 -1
View File
@@ -1,10 +1,13 @@
// Add your dependencies here
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:Postea:1.2.5:dev") {transitive = false}
devOnlyNonPublishable("com.github.GTNewHorizons:NotEnoughItems:2.8.93-GTNH:dev") {
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
# 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.
# 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.
separateMixinSourceSet =
separateMixinSourceSet = mixin
# 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.
mixinPlugin =
@@ -123,12 +123,12 @@ mixinPlugin =
# 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,
# 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!
# This parameter is for legacy compatibility only
# 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
# 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
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.RenderingRegistry
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.tileentity.TileEntity
import net.minecraft.world.IBlockAccess
import net.minecraft.client.Minecraft
import net.minecraftforge.client.ForgeHooksClient
import net.minecraftforge.client.MinecraftForgeClient
import cpw.mods.fml.relauncher.SideOnly
import cpw.mods.fml.relauncher.Side
import codechicken.lib.raytracer.ExtendedMOP
import codechicken.lib.lighting.LightMatrix
import com.gtnewhorizons.angelica.api.ThreadSafeISBRH
import codechicken.multipart.RenderPartResolver
/** Internal class for rendering callbacks. Should be moved to the handler
* package
@@ -67,19 +63,15 @@ object MultipartRenderer
return false
if (renderer.hasOverrideBlockTexture) {
val hit = Minecraft.getMinecraft.objectMouseOver
if (
hit != null && hit.blockX == x && hit.blockY == y && hit.blockZ == z && ExtendedMOP
.getData(hit)
.isInstanceOf[(_, _)]
) {
val hitInfo: (Int, _) = ExtendedMOP.getData(hit)
if (
hitInfo._1.isInstanceOf[
Int
] && hitInfo._1 >= 0 && hitInfo._1 < tmpart.partList.size
)
tmpart.partList(hitInfo._1).drawBreaking(renderer)
val part =
RenderPartResolver.resolve(world, x, y, z)
if (part != null) {
part match {
case isbrh: ISBRHPart =>
isbrh.renderWorldBlock(world, x, y, z, renderer)
case _ =>
part.drawBreaking(renderer)
}
}
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 codechicken.lib.world.IChunkLoadTile
import net.minecraft.block.Block
import com.gtnewhorizon.gtnhlib.client.model.ModelISBRH
import net.minecraft.client.renderer.RenderBlocks
import net.minecraftforge.client.ForgeHooksClient
@@ -534,6 +534,22 @@ trait TileMultipartClient extends TileMultipart {
return
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 =>
if (
isbrh.renderWorldBlock(
@@ -29,7 +29,7 @@ class MultipartProxy_serverImpl {
.setComment("Multipart API config file")
GameRegistry.registerBlock(
new BlockMultipart().setBlockName("multipart"),
new BlockMultipart().setBlockName("codechicken/multipart"),
null,
"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);
}
}
}