diff --git a/src/main/java/dan200/computercraft/client/render/ModelTransformer.java b/src/main/java/dan200/computercraft/client/render/ModelTransformer.java index 1ae9c35a1..1556246a1 100644 --- a/src/main/java/dan200/computercraft/client/render/ModelTransformer.java +++ b/src/main/java/dan200/computercraft/client/render/ModelTransformer.java @@ -5,15 +5,14 @@ */ package dan200.computercraft.client.render; -import dan200.computercraft.fabric.mixin.BakedQuadAccess; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.render.VertexFormat; import net.minecraft.client.render.VertexFormatElement; import net.minecraft.client.render.VertexFormats; import net.minecraft.client.render.model.BakedQuad; -import net.minecraft.util.math.Vector4f; import net.minecraft.util.math.Matrix4f; +import net.minecraft.util.math.Vector4f; import java.util.List; @@ -58,28 +57,41 @@ public final class ModelTransformer private static BakedQuad doTransformQuad( VertexFormat format, BakedQuad quad, Matrix4f transform ) { int[] vertexData = quad.getVertexData().clone(); - BakedQuad copy = new BakedQuad( vertexData, -1, quad.getFace(), ((BakedQuadAccess) quad).getSprite(), true ); + BakedQuad copy = new BakedQuad( vertexData, -1, quad.getFace(), quad.getSprite(), true ); int offsetBytes = 0; for( int v = 0; v < 4; ++v ) { for( VertexFormatElement element : format.getElements() ) // For each vertex element { - int start = offsetBytes / Integer.BYTES; - if( element.getType() == VertexFormatElement.Type.POSITION && element.getDataType() == VertexFormatElement.DataType.FLOAT ) // When we find a position element + if( element.isPosition() && + element.getDataType() == VertexFormatElement.DataType.FLOAT && + element.getLength() == 3 ) // When we find a position element { - Vector4f pos = new Vector4f( Float.intBitsToFloat( vertexData[start] ), - Float.intBitsToFloat( vertexData[start + 1] ), - Float.intBitsToFloat( vertexData[start + 2] ), - 1 ); + for ( int j = 0; j < 4; ++j ) // For each corner of the quad + { + int start = offsetBytes + j * format.getVertexSize(); + if ( (start % 4) == 0 ) + { + start = start / 4; - // Transform the position - pos.transform( transform ); + // Extract the position + Vector4f pos = new Vector4f( + Float.intBitsToFloat( vertexData[start] ), + Float.intBitsToFloat( vertexData[start + 1] ), + Float.intBitsToFloat( vertexData[start + 2] ), + 1 + ); - // Insert the position - vertexData[start] = Float.floatToRawIntBits( pos.getX() ); - vertexData[start + 1] = Float.floatToRawIntBits( pos.getY() ); - vertexData[start + 2] = Float.floatToRawIntBits( pos.getZ() ); + // Transform the position + pos.transform( transform ); + + // Insert the position + vertexData[start] = Float.floatToRawIntBits( pos.getX() ); + vertexData[start + 1] = Float.floatToRawIntBits( pos.getY() ); + vertexData[start + 2] = Float.floatToRawIntBits( pos.getZ() ); + } + } } offsetBytes += element.getLength(); } diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java index 2e4e0fa86..a5ef4bb7c 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.client.render; import dan200.computercraft.api.client.TransformedModel; @@ -148,7 +147,7 @@ public class TileEntityTurtleRenderer implements BlockEntityRenderer transform.pop(); } - public void renderUpgrade( @Nonnull MatrixStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, TileTurtle turtle, + private void renderUpgrade( @Nonnull MatrixStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, TileTurtle turtle, TurtleSide side, float f ) { ITurtleUpgrade upgrade = turtle.getUpgrade( side ); @@ -171,7 +170,7 @@ public class TileEntityTurtleRenderer implements BlockEntityRenderer transform.pop(); } - public void renderModel( @Nonnull MatrixStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, + private void renderModel( @Nonnull MatrixStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, ModelIdentifier modelLocation, int[] tints ) { BakedModelManager modelManager = MinecraftClient.getInstance() @@ -181,7 +180,7 @@ public class TileEntityTurtleRenderer implements BlockEntityRenderer renderModel( transform, renderer, lightmapCoord, overlayLight, modelManager.getModel( modelLocation ), tints ); } - public void renderModel( @Nonnull MatrixStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, BakedModel model, + private void renderModel( @Nonnull MatrixStack transform, @Nonnull VertexConsumer renderer, int lightmapCoord, int overlayLight, BakedModel model, int[] tints ) { random.setSeed( 0 ); diff --git a/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java b/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java index 6bccfd62e..bc7a6e46b 100644 --- a/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java +++ b/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java @@ -30,7 +30,7 @@ public class TurtleMultiModel implements BakedModel private final TransformedModel leftUpgradeModel; private final TransformedModel rightUpgradeModel; private List generalQuads = null; - private Map> faceQuads = new EnumMap<>( Direction.class ); + private final Map> faceQuads = new EnumMap<>( Direction.class ); public TurtleMultiModel( BakedModel baseModel, BakedModel overlayModel, AffineTransformation generalTransform, TransformedModel leftUpgradeModel, TransformedModel rightUpgradeModel ) @@ -117,6 +117,7 @@ public class TurtleMultiModel implements BakedModel return baseModel.isBuiltin(); } + @Nonnull @Override @Deprecated public Sprite getParticleSprite() @@ -124,14 +125,6 @@ public class TurtleMultiModel implements BakedModel return baseModel.getParticleSprite(); } - // @Nonnull - // @Override - // @Deprecated - // public Sprite getSprite() - // { - // return baseModel.getSprite(); - // } - @Nonnull @Override @Deprecated diff --git a/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java b/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java index d9274fc7c..c23a0be48 100644 --- a/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java +++ b/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.client.render; import com.google.common.base.Objects; @@ -55,8 +54,60 @@ public class TurtleSmartItemModel implements BakedModel .getModel() ); } + private static class TurtleModelCombination + { + final boolean colour; + final ITurtleUpgrade leftUpgrade; + final ITurtleUpgrade rightUpgrade; + final Identifier overlay; + final boolean christmas; + final boolean flip; + + TurtleModelCombination( boolean colour, ITurtleUpgrade leftUpgrade, ITurtleUpgrade rightUpgrade, Identifier overlay, boolean christmas, + boolean flip ) + { + this.colour = colour; + this.leftUpgrade = leftUpgrade; + this.rightUpgrade = rightUpgrade; + this.overlay = overlay; + this.christmas = christmas; + this.flip = flip; + } + + @Override + public boolean equals( Object other ) + { + if( other == this ) + { + return true; + } + if( !(other instanceof TurtleModelCombination otherCombo) ) + { + return false; + } + + return otherCombo.colour == colour && otherCombo.leftUpgrade == leftUpgrade && otherCombo.rightUpgrade == rightUpgrade && Objects.equal( + otherCombo.overlay, overlay ) && otherCombo.christmas == christmas && otherCombo.flip == flip; + } + + @Override + public int hashCode() + { + final int prime = 31; + int result = 0; + result = prime * result + (colour ? 1 : 0); + result = prime * result + (leftUpgrade != null ? leftUpgrade.hashCode() : 0); + result = prime * result + (rightUpgrade != null ? rightUpgrade.hashCode() : 0); + result = prime * result + (overlay != null ? overlay.hashCode() : 0); + result = prime * result + (christmas ? 1 : 0); + result = prime * result + (flip ? 1 : 0); + return result; + } + } + private final BakedModel familyModel; private final BakedModel colourModel; + private final HashMap cachedModels = new HashMap<>(); private final ModelOverrideList overrides; @@ -79,9 +130,7 @@ public class TurtleSmartItemModel implements BakedModel Identifier overlay = turtle.getOverlay( stack ); boolean christmas = HolidayUtil.getCurrentHoliday() == Holiday.CHRISTMAS; String label = turtle.getLabel( stack ); - // TODO make upside down turtle items render properly (currently inivisible) - //boolean flip = label != null && (label.equals("Dinnerbone") || label.equals("Grumm")); - boolean flip = false; + boolean flip = label != null && (label.equals( "Dinnerbone" ) || label.equals( "Grumm" )); TurtleModelCombination combo = new TurtleModelCombination( colour != -1, leftUpgrade, rightUpgrade, overlay, christmas, flip ); BakedModel model = cachedModels.get( combo ); @@ -149,13 +198,12 @@ public class TurtleSmartItemModel implements BakedModel return familyModel.getParticleSprite(); } - // @Nonnull - // @Override - // @Deprecated - // public Sprite getSprite() - // { - // return familyModel.getSprite(); - // } + @Nonnull + @Override + public ModelOverrideList getOverrides() + { + return overrides; + } @Nonnull @Override @@ -165,63 +213,4 @@ public class TurtleSmartItemModel implements BakedModel return familyModel.getTransformation(); } - @Nonnull - @Override - public ModelOverrideList getOverrides() - { - return overrides; - } - - private static class TurtleModelCombination - { - final boolean colour; - final ITurtleUpgrade leftUpgrade; - final ITurtleUpgrade rightUpgrade; - final Identifier overlay; - final boolean christmas; - final boolean flip; - - TurtleModelCombination( boolean colour, ITurtleUpgrade leftUpgrade, ITurtleUpgrade rightUpgrade, Identifier overlay, boolean christmas, - boolean flip ) - { - this.colour = colour; - this.leftUpgrade = leftUpgrade; - this.rightUpgrade = rightUpgrade; - this.overlay = overlay; - this.christmas = christmas; - this.flip = flip; - } - - @Override - public int hashCode() - { - final int prime = 31; - int result = 0; - result = prime * result + (colour ? 1 : 0); - result = prime * result + (leftUpgrade != null ? leftUpgrade.hashCode() : 0); - result = prime * result + (rightUpgrade != null ? rightUpgrade.hashCode() : 0); - result = prime * result + (overlay != null ? overlay.hashCode() : 0); - result = prime * result + (christmas ? 1 : 0); - result = prime * result + (flip ? 1 : 0); - return result; - } - - @Override - public boolean equals( Object other ) - { - if( other == this ) - { - return true; - } - if( !(other instanceof TurtleModelCombination) ) - { - return false; - } - - TurtleModelCombination otherCombo = (TurtleModelCombination) other; - return otherCombo.colour == colour && otherCombo.leftUpgrade == leftUpgrade && otherCombo.rightUpgrade == rightUpgrade && Objects.equal( - otherCombo.overlay, overlay ) && otherCombo.christmas == christmas && otherCombo.flip == flip; - } - } - } diff --git a/src/main/java/dan200/computercraft/fabric/mixin/BakedQuadAccess.java b/src/main/java/dan200/computercraft/fabric/mixin/BakedQuadAccess.java deleted file mode 100644 index fa7541eca..000000000 --- a/src/main/java/dan200/computercraft/fabric/mixin/BakedQuadAccess.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.fabric.mixin; - -import net.minecraft.client.render.model.BakedQuad; -import net.minecraft.client.texture.Sprite; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -@Mixin( BakedQuad.class ) -public interface BakedQuadAccess -{ - @Accessor - Sprite getSprite(); -} diff --git a/src/main/java/dan200/computercraft/fabric/mixin/MixinMatrix4f.java b/src/main/java/dan200/computercraft/fabric/mixin/MixinMatrix4f.java new file mode 100644 index 000000000..247151863 --- /dev/null +++ b/src/main/java/dan200/computercraft/fabric/mixin/MixinMatrix4f.java @@ -0,0 +1,52 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.fabric.mixin; + +import dan200.computercraft.fabric.mixininterface.IMatrix4f; +import net.minecraft.util.math.Matrix4f; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin( Matrix4f.class ) +public class MixinMatrix4f implements IMatrix4f +{ + @Shadow protected float a00; + @Shadow protected float a01; + @Shadow protected float a02; + @Shadow protected float a03; + @Shadow protected float a10; + @Shadow protected float a11; + @Shadow protected float a12; + @Shadow protected float a13; + @Shadow protected float a20; + @Shadow protected float a21; + @Shadow protected float a22; + @Shadow protected float a23; + @Shadow protected float a30; + @Shadow protected float a31; + @Shadow protected float a32; + @Shadow protected float a33; + + public void setFloatArray( float[] values ) + { + a00 = values[0]; + a01 = values[1]; + a02 = values[2]; + a03 = values[3]; + a10 = values[4]; + a11 = values[5]; + a12 = values[6]; + a13 = values[7]; + a20 = values[8]; + a21 = values[9]; + a22 = values[10]; + a23 = values[11]; + a30 = values[12]; + a31 = values[13]; + a32 = values[14]; + a33 = values[15]; + } +} diff --git a/src/main/java/dan200/computercraft/fabric/mixininterface/IMatrix4f.java b/src/main/java/dan200/computercraft/fabric/mixininterface/IMatrix4f.java new file mode 100644 index 000000000..ca5b862ea --- /dev/null +++ b/src/main/java/dan200/computercraft/fabric/mixininterface/IMatrix4f.java @@ -0,0 +1,11 @@ +/* + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ +package dan200.computercraft.fabric.mixininterface; + +public interface IMatrix4f +{ + void setFloatArray( float[] values ); +} diff --git a/src/main/java/dan200/computercraft/shared/TurtlePermissions.java b/src/main/java/dan200/computercraft/shared/TurtlePermissions.java index 59419fc41..19d336d06 100644 --- a/src/main/java/dan200/computercraft/shared/TurtlePermissions.java +++ b/src/main/java/dan200/computercraft/shared/TurtlePermissions.java @@ -3,12 +3,8 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared; -import com.google.common.eventbus.Subscribe; -import dan200.computercraft.ComputerCraft; -import dan200.computercraft.api.turtle.event.TurtleActionEvent; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.server.MinecraftServer; import net.minecraft.server.world.ServerWorld; @@ -17,23 +13,14 @@ import net.minecraft.world.World; public final class TurtlePermissions { - public static boolean isBlockEditable( World world, BlockPos pos, PlayerEntity player ) - { - return isBlockEnterable( world, pos, player ); - } - public static boolean isBlockEnterable( World world, BlockPos pos, PlayerEntity player ) { MinecraftServer server = world.getServer(); return server == null || world.isClient || world instanceof ServerWorld && !server.isSpawnProtected( (ServerWorld) world, pos, player ); } - @Subscribe - public void onTurtleAction( TurtleActionEvent event ) + public static boolean isBlockEditable( World world, BlockPos pos, PlayerEntity player ) { - if( ComputerCraft.turtleDisabledActions.contains( event.getAction() ) ) - { - event.setCanceled( true, "Action has been disabled" ); - } + return isBlockEnterable( world, pos, player ); } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java index 113ea0f3b..dc51b1fae 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java @@ -12,6 +12,8 @@ import dan200.computercraft.api.turtle.*; import dan200.computercraft.api.turtle.event.TurtleAttackEvent; import dan200.computercraft.api.turtle.event.TurtleBlockEvent; import dan200.computercraft.api.turtle.event.TurtleEvent; +import dan200.computercraft.fabric.mixin.MixinMatrix4f; +import dan200.computercraft.fabric.mixininterface.IMatrix4f; import dan200.computercraft.shared.TurtlePermissions; import dan200.computercraft.shared.turtle.core.TurtleBrain; import dan200.computercraft.shared.turtle.core.TurtlePlaceCommand; @@ -26,8 +28,8 @@ import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.block.entity.BlockEntity; -import net.minecraft.util.math.AffineTransformation; -import net.minecraft.util.math.Vec3f; +import net.minecraft.client.render.model.json.Transformation; +import net.minecraft.util.math.*; import net.minecraft.entity.Entity; import net.minecraft.entity.attribute.EntityAttributes; import net.minecraft.entity.damage.DamageSource; @@ -38,9 +40,6 @@ import net.minecraft.nbt.NbtCompound; import net.minecraft.util.ActionResult; import net.minecraft.util.Hand; import net.minecraft.util.Identifier; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import org.apache.commons.lang3.tuple.Pair; @@ -106,8 +105,7 @@ public class TurtleTool extends AbstractTurtleUpgrade @Environment( EnvType.CLIENT ) public TransformedModel getModel( ITurtleAccess turtle, @Nonnull TurtleSide side ) { - float xOffset = side == TurtleSide.LEFT ? -0.40625f : 0.40625f; - return TransformedModel.of( getCraftingItem(), new AffineTransformation( new Vec3f( xOffset + 1, 0, 1 ), Vec3f.POSITIVE_Y.getDegreesQuaternion( 270 ), new Vec3f( 1, 1, 1 ), Vec3f.POSITIVE_Z.getDegreesQuaternion( 90 ) ) ); + return TransformedModel.of( getCraftingItem(), side == TurtleSide.LEFT ? Transforms.leftTransform : Transforms.rightTransform ); } private TurtleCommandResult attack( ITurtleAccess turtle, Direction direction, TurtleSide side ) @@ -296,4 +294,22 @@ public class TurtleTool extends AbstractTurtleUpgrade Block block = state.getBlock(); return !state.isAir() && block != Blocks.BEDROCK && state.calcBlockBreakingDelta( player, world, pos ) > 0; } + + private static class Transforms + { + static final AffineTransformation leftTransform = getMatrixFor( -0.40625f ); + static final AffineTransformation rightTransform = getMatrixFor( 0.40625f ); + + private static AffineTransformation getMatrixFor( float offset ) + { + Matrix4f matrix = new Matrix4f(); + ((IMatrix4f) (Object) matrix).setFloatArray( new float[] { + 0.0f, 0.0f, -1.0f, 1.0f + offset, + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 0.0f, 1.0f, + } ); + return new AffineTransformation( matrix ); + } + } } diff --git a/src/main/resources/computercraft.mixins.json b/src/main/resources/computercraft.mixins.json index c3da4edb3..219edc8ac 100644 --- a/src/main/resources/computercraft.mixins.json +++ b/src/main/resources/computercraft.mixins.json @@ -14,11 +14,11 @@ "WorldSavePathAccess", "MixinServerPlayerInteractionManager", "MusicDiscItemAccessor", - "GameRendererMixin" + "GameRendererMixin", + "MixinMatrix4f" ], "client": [ "AffineTransformationAccess", - "BakedQuadAccess", "ChatHudAccess", "HeldItemRendererAccess", "MixinHeldItemRenderer",