mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-08-30 00:57:55 +00:00
fix: turtle upgrades item render
This commit is contained in:
@@ -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();
|
||||
}
|
||||
|
@@ -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<TileTurtle>
|
||||
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<TileTurtle>
|
||||
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<TileTurtle>
|
||||
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 );
|
||||
|
@@ -30,7 +30,7 @@ public class TurtleMultiModel implements BakedModel
|
||||
private final TransformedModel leftUpgradeModel;
|
||||
private final TransformedModel rightUpgradeModel;
|
||||
private List<BakedQuad> generalQuads = null;
|
||||
private Map<Direction, List<BakedQuad>> faceQuads = new EnumMap<>( Direction.class );
|
||||
private final Map<Direction, List<BakedQuad>> 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
|
||||
|
@@ -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<TurtleModelCombination, BakedModel> 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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();
|
||||
}
|
@@ -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];
|
||||
}
|
||||
}
|
@@ -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 );
|
||||
}
|
@@ -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 );
|
||||
}
|
||||
}
|
||||
|
@@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -14,11 +14,11 @@
|
||||
"WorldSavePathAccess",
|
||||
"MixinServerPlayerInteractionManager",
|
||||
"MusicDiscItemAccessor",
|
||||
"GameRendererMixin"
|
||||
"GameRendererMixin",
|
||||
"MixinMatrix4f"
|
||||
],
|
||||
"client": [
|
||||
"AffineTransformationAccess",
|
||||
"BakedQuadAccess",
|
||||
"ChatHudAccess",
|
||||
"HeldItemRendererAccess",
|
||||
"MixinHeldItemRenderer",
|
||||
|
Reference in New Issue
Block a user