Clean up and optimize copycat models

- Rename ITransformableTE -> ITransformableBlockEntity
This commit is contained in:
PepperCode1 2023-02-24 12:37:41 -08:00
parent 783cd126f7
commit 42675f9511
25 changed files with 296 additions and 301 deletions

View file

@ -831,8 +831,8 @@ public class AllBlockEntityTypes {
.validBlocks(AllBlocks.TRAIN_DOOR, AllBlocks.FRAMED_GLASS_DOOR) .validBlocks(AllBlocks.TRAIN_DOOR, AllBlocks.FRAMED_GLASS_DOOR)
.register(); .register();
public static final BlockEntityEntry<CopycatBlockEntity> UNIVERSAL_FRAME = REGISTRATE public static final BlockEntityEntry<CopycatBlockEntity> COPYCAT = REGISTRATE
.blockEntity("universal_frame", CopycatBlockEntity::new) .blockEntity("copycat", CopycatBlockEntity::new)
.validBlocks(AllBlocks.COPYCAT_PANEL, AllBlocks.COPYCAT_STEP) .validBlocks(AllBlocks.COPYCAT_PANEL, AllBlocks.COPYCAT_STEP)
.register(); .register();

View file

@ -1,6 +1,6 @@
package com.simibubi.create.content.contraptions.components.structureMovement; package com.simibubi.create.content.contraptions.components.structureMovement;
public interface ITransformableTE { public interface ITransformableBlockEntity {
void transform(StructureTransform transform); void transform(StructureTransform transform);

View file

@ -111,8 +111,8 @@ public class StructureTransform {
} }
public void apply(BlockEntity be) { public void apply(BlockEntity be) {
if (be instanceof ITransformableTE) if (be instanceof ITransformableBlockEntity)
((ITransformableTE) be).transform(this); ((ITransformableBlockEntity) be).transform(this);
} }
/** /**

View file

@ -10,8 +10,8 @@ import com.simibubi.create.content.contraptions.fluids.FluidTransportBehaviour.A
import com.simibubi.create.content.contraptions.fluids.FluidTransportBehaviour.AttachmentTypes.ComponentPartials; import com.simibubi.create.content.contraptions.fluids.FluidTransportBehaviour.AttachmentTypes.ComponentPartials;
import com.simibubi.create.content.contraptions.fluids.pipes.FluidPipeBlock; import com.simibubi.create.content.contraptions.fluids.pipes.FluidPipeBlock;
import com.simibubi.create.content.contraptions.relays.elementary.BracketedBlockEntityBehaviour; import com.simibubi.create.content.contraptions.relays.elementary.BracketedBlockEntityBehaviour;
import com.simibubi.create.foundation.block.connected.BakedModelWrapperWithData;
import com.simibubi.create.foundation.blockEntity.BlockEntityBehaviour; import com.simibubi.create.foundation.blockEntity.BlockEntityBehaviour;
import com.simibubi.create.foundation.model.BakedModelWrapperWithData;
import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
@ -34,7 +34,7 @@ public class PipeAttachmentModel extends BakedModelWrapperWithData {
} }
@Override @Override
protected Builder gatherModelData(Builder builder, BlockAndTintGetter world, BlockPos pos, BlockState state, protected void gatherModelData(Builder builder, BlockAndTintGetter world, BlockPos pos, BlockState state,
IModelData blockEntityData) { IModelData blockEntityData) {
PipeModelData data = new PipeModelData(); PipeModelData data = new PipeModelData();
FluidTransportBehaviour transport = BlockEntityBehaviour.get(world, pos, FluidTransportBehaviour.TYPE); FluidTransportBehaviour transport = BlockEntityBehaviour.get(world, pos, FluidTransportBehaviour.TYPE);
@ -47,7 +47,7 @@ public class PipeAttachmentModel extends BakedModelWrapperWithData {
data.putBracket(bracket.getBracket()); data.putBracket(bracket.getBracket());
data.setEncased(FluidPipeBlock.shouldDrawCasing(world, pos, state)); data.setEncased(FluidPipeBlock.shouldDrawCasing(world, pos, state));
return builder.withInitial(PIPE_PROPERTY, data); builder.withInitial(PIPE_PROPERTY, data);
} }
@Override @Override

View file

@ -3,7 +3,7 @@ package com.simibubi.create.content.contraptions.fluids.pipes;
import java.util.List; import java.util.List;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableTE; import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableBlockEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform;
import com.simibubi.create.content.contraptions.fluids.FluidPropagator; import com.simibubi.create.content.contraptions.fluids.FluidPropagator;
import com.simibubi.create.content.contraptions.fluids.FluidTransportBehaviour; import com.simibubi.create.content.contraptions.fluids.FluidTransportBehaviour;
@ -17,7 +17,7 @@ import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
public class FluidPipeBlockEntity extends SmartBlockEntity implements ITransformableTE { public class FluidPipeBlockEntity extends SmartBlockEntity implements ITransformableBlockEntity {
public FluidPipeBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) { public FluidPipeBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
super(type, pos, state); super(type, pos, state);

View file

@ -42,12 +42,13 @@ public class FluidTankModel extends CTModel {
} }
@Override @Override
protected Builder gatherModelData(Builder builder, BlockAndTintGetter world, BlockPos pos, BlockState state, protected void gatherModelData(Builder builder, BlockAndTintGetter world, BlockPos pos, BlockState state,
IModelData blockEntityData) { IModelData blockEntityData) {
super.gatherModelData(builder, world, pos, state, blockEntityData);
CullData cullData = new CullData(); CullData cullData = new CullData();
for (Direction d : Iterate.horizontalDirections) for (Direction d : Iterate.horizontalDirections)
cullData.setCulled(d, ConnectivityHandler.isConnected(world, pos, pos.relative(d))); cullData.setCulled(d, ConnectivityHandler.isConnected(world, pos, pos.relative(d)));
return super.gatherModelData(builder, world, pos, state, blockEntityData).withInitial(CULL_PROPERTY, cullData); builder.withInitial(CULL_PROPERTY, cullData);
} }
@Override @Override
@ -66,7 +67,7 @@ public class FluidTankModel extends CTModel {
return quads; return quads;
} }
private class CullData { private static class CullData {
boolean[] culledFaces; boolean[] culledFaces;
public CullData() { public CullData() {

View file

@ -56,7 +56,6 @@ import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.client.model.data.IModelData; import net.minecraftforge.client.model.data.IModelData;
import net.minecraftforge.client.model.data.ModelDataMap; import net.minecraftforge.client.model.data.ModelDataMap;
import net.minecraftforge.client.model.data.ModelProperty;
import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.DistExecutor;
@ -517,11 +516,9 @@ public class BeltBlockEntity extends KineticBlockEntity {
return empty; return empty;
} }
public static final ModelProperty<CasingType> CASING_PROPERTY = new ModelProperty<>();
@Override @Override
public IModelData getModelData() { public IModelData getModelData() {
return new ModelDataMap.Builder().withInitial(CASING_PROPERTY, casing) return new ModelDataMap.Builder().withInitial(BeltModel.CASING_PROPERTY, casing)
.build(); .build();
} }

View file

@ -1,15 +1,13 @@
package com.simibubi.create.content.contraptions.relays.belt; package com.simibubi.create.content.contraptions.relays.belt;
import static com.simibubi.create.content.contraptions.relays.belt.BeltBlockEntity.CASING_PROPERTY;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
import com.simibubi.create.AllSpriteShifts; import com.simibubi.create.AllSpriteShifts;
import com.simibubi.create.content.contraptions.relays.belt.BeltBlockEntity.CasingType; import com.simibubi.create.content.contraptions.relays.belt.BeltBlockEntity.CasingType;
import com.simibubi.create.foundation.block.render.QuadHelper;
import com.simibubi.create.foundation.block.render.SpriteShiftEntry; import com.simibubi.create.foundation.block.render.SpriteShiftEntry;
import com.simibubi.create.foundation.model.BakedQuadHelper;
import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureAtlasSprite;
@ -18,9 +16,12 @@ import net.minecraft.core.Direction;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.client.model.BakedModelWrapper; import net.minecraftforge.client.model.BakedModelWrapper;
import net.minecraftforge.client.model.data.IModelData; import net.minecraftforge.client.model.data.IModelData;
import net.minecraftforge.client.model.data.ModelProperty;
public class BeltModel extends BakedModelWrapper<BakedModel> { public class BeltModel extends BakedModelWrapper<BakedModel> {
public static final ModelProperty<CasingType> CASING_PROPERTY = new ModelProperty<>();
private static final SpriteShiftEntry SPRITE_SHIFT = AllSpriteShifts.ANDESIDE_BELT_CASING; private static final SpriteShiftEntry SPRITE_SHIFT = AllSpriteShifts.ANDESIDE_BELT_CASING;
public BeltModel(BakedModel template) { public BeltModel(BakedModel template) {
@ -44,14 +45,14 @@ public class BeltModel extends BakedModelWrapper<BakedModel> {
if (original != SPRITE_SHIFT.getOriginal()) if (original != SPRITE_SHIFT.getOriginal())
continue; continue;
BakedQuad newQuad = QuadHelper.clone(quad); BakedQuad newQuad = BakedQuadHelper.clone(quad);
int[] vertexData = newQuad.getVertices(); int[] vertexData = newQuad.getVertices();
for (int vertex = 0; vertex < 4; vertex++) { for (int vertex = 0; vertex < 4; vertex++) {
float u = QuadHelper.getU(vertexData, vertex); float u = BakedQuadHelper.getU(vertexData, vertex);
float v = QuadHelper.getV(vertexData, vertex); float v = BakedQuadHelper.getV(vertexData, vertex);
QuadHelper.setU(vertexData, vertex, SPRITE_SHIFT.getTargetU(u)); BakedQuadHelper.setU(vertexData, vertex, SPRITE_SHIFT.getTargetU(u));
QuadHelper.setV(vertexData, vertex, SPRITE_SHIFT.getTargetV(v)); BakedQuadHelper.setV(vertexData, vertex, SPRITE_SHIFT.getTargetV(v));
} }
quads.set(i, newQuad); quads.set(i, newQuad);

View file

@ -2,7 +2,7 @@ package com.simibubi.create.content.contraptions.relays.elementary;
import java.util.List; import java.util.List;
import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableTE; import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableBlockEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform;
import com.simibubi.create.foundation.blockEntity.BlockEntityBehaviour; import com.simibubi.create.foundation.blockEntity.BlockEntityBehaviour;
@ -10,7 +10,7 @@ import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
public class BracketedKineticBlockEntity extends SimpleKineticBlockEntity implements ITransformableTE { public class BracketedKineticBlockEntity extends SimpleKineticBlockEntity implements ITransformableBlockEntity {
public BracketedKineticBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) { public BracketedKineticBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
super(type, pos, state); super(type, pos, state);

View file

@ -81,7 +81,7 @@ public abstract class CopycatBlock extends Block implements IBE<CopycatBlockEnti
context.getLevel() context.getLevel()
.levelEvent(2001, context.getClickedPos(), Block.getId(ufte.getBlockState())); .levelEvent(2001, context.getClickedPos(), Block.getId(ufte.getBlockState()));
ufte.setMaterial(AllBlocks.COPYCAT_BASE.getDefaultState()); ufte.setMaterial(AllBlocks.COPYCAT_BASE.getDefaultState());
ufte.setItem(ItemStack.EMPTY); ufte.setConsumedItem(ItemStack.EMPTY);
return InteractionResult.SUCCESS; return InteractionResult.SUCCESS;
}); });
} }
@ -116,7 +116,7 @@ public abstract class CopycatBlock extends Block implements IBE<CopycatBlockEnti
return InteractionResult.SUCCESS; return InteractionResult.SUCCESS;
ufte.setMaterial(material); ufte.setMaterial(material);
ufte.setItem(itemInHand); ufte.setConsumedItem(itemInHand);
ufte.getLevel() ufte.getLevel()
.playSound(null, ufte.getBlockPos(), material.getSoundType() .playSound(null, ufte.getBlockPos(), material.getSoundType()
.getPlaceSound(), SoundSource.BLOCKS, 1, .75f); .getPlaceSound(), SoundSource.BLOCKS, 1, .75f);
@ -146,7 +146,7 @@ public abstract class CopycatBlock extends Block implements IBE<CopycatBlockEnti
return; return;
ufte.setMaterial(appliedState); ufte.setMaterial(appliedState);
ufte.setItem(offhandItem); ufte.setConsumedItem(offhandItem);
if (pPlacer instanceof Player player && player.isCreative()) if (pPlacer instanceof Player player && player.isCreative())
return; return;
@ -215,7 +215,7 @@ public abstract class CopycatBlock extends Block implements IBE<CopycatBlockEnti
public void playerWillDestroy(Level pLevel, BlockPos pPos, BlockState pState, Player pPlayer) { public void playerWillDestroy(Level pLevel, BlockPos pPos, BlockState pState, Player pPlayer) {
super.playerWillDestroy(pLevel, pPos, pState, pPlayer); super.playerWillDestroy(pLevel, pPos, pState, pPlayer);
if (pPlayer.isCreative()) if (pPlayer.isCreative())
withBlockEntityDo(pLevel, pPos, ufte -> ufte.setItem(ItemStack.EMPTY)); withBlockEntityDo(pLevel, pPos, ufte -> ufte.setConsumedItem(ItemStack.EMPTY));
} }
@Override @Override
@ -225,7 +225,7 @@ public abstract class CopycatBlock extends Block implements IBE<CopycatBlockEnti
@Override @Override
public BlockEntityType<? extends CopycatBlockEntity> getBlockEntityType() { public BlockEntityType<? extends CopycatBlockEntity> getBlockEntityType() {
return AllBlockEntityTypes.UNIVERSAL_FRAME.get(); return AllBlockEntityTypes.COPYCAT.get();
} }
// Connected Textures // Connected Textures

View file

@ -5,7 +5,7 @@ import java.util.List;
import com.google.gson.JsonParser; import com.google.gson.JsonParser;
import com.mojang.serialization.JsonOps; import com.mojang.serialization.JsonOps;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableTE; import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableBlockEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform;
import com.simibubi.create.content.logistics.block.redstone.RoseQuartzLampBlock; import com.simibubi.create.content.logistics.block.redstone.RoseQuartzLampBlock;
import com.simibubi.create.content.schematics.ISpecialBlockEntityItemRequirement; import com.simibubi.create.content.schematics.ISpecialBlockEntityItemRequirement;
@ -24,55 +24,46 @@ import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraftforge.client.model.data.IModelData; import net.minecraftforge.client.model.data.IModelData;
import net.minecraftforge.client.model.data.ModelDataMap; import net.minecraftforge.client.model.data.ModelDataMap;
import net.minecraftforge.client.model.data.ModelProperty;
import net.minecraftforge.items.ItemHandlerHelper; import net.minecraftforge.items.ItemHandlerHelper;
public class CopycatBlockEntity extends SmartBlockEntity implements ISpecialBlockEntityItemRequirement, ITransformableTE { public class CopycatBlockEntity extends SmartBlockEntity implements ISpecialBlockEntityItemRequirement, ITransformableBlockEntity {
ItemStack consumedItem; private BlockState material;
BlockState baseBlock; private ItemStack consumedItem;
public CopycatBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) { public CopycatBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
super(type, pos, state); super(type, pos, state);
baseBlock = AllBlocks.COPYCAT_BASE.getDefaultState(); material = AllBlocks.COPYCAT_BASE.getDefaultState();
consumedItem = ItemStack.EMPTY; consumedItem = ItemStack.EMPTY;
} }
public void setItem(ItemStack item) { public BlockState getMaterial() {
consumedItem = ItemHandlerHelper.copyStackWithSize(item, 1); return material;
setChanged();
} }
public ItemStack getConsumedItem() { public boolean hasCustomMaterial() {
return consumedItem; return !AllBlocks.COPYCAT_BASE.has(getMaterial());
}
@Override
public ItemRequirement getRequiredItems(BlockState state) {
if (consumedItem.isEmpty())
return ItemRequirement.NONE;
return new ItemRequirement(ItemUseType.CONSUME, consumedItem);
} }
public void setMaterial(BlockState blockState) { public void setMaterial(BlockState blockState) {
BlockState wrapperState = getBlockState(); BlockState wrapperState = getBlockState();
if (!baseBlock.is(blockState.getBlock())) if (!material.is(blockState.getBlock()))
for (Direction side : Iterate.directions) { for (Direction side : Iterate.directions) {
BlockPos neighbour = worldPosition.relative(side); BlockPos neighbour = worldPosition.relative(side);
BlockState neighbourState = level.getBlockState(neighbour); BlockState neighbourState = level.getBlockState(neighbour);
if (neighbourState != wrapperState) if (neighbourState != wrapperState)
continue; continue;
if (!(level.getBlockEntity(neighbour)instanceof CopycatBlockEntity ufte)) if (!(level.getBlockEntity(neighbour) instanceof CopycatBlockEntity cbe))
continue; continue;
BlockState otherMaterial = ufte.getMaterial(); BlockState otherMaterial = cbe.getMaterial();
if (!otherMaterial.is(blockState.getBlock())) if (!otherMaterial.is(blockState.getBlock()))
continue; continue;
blockState = otherMaterial; blockState = otherMaterial;
break; break;
} }
baseBlock = blockState; material = blockState;
if (!level.isClientSide()) { if (!level.isClientSide()) {
notifyUpdate(); notifyUpdate();
return; return;
@ -80,50 +71,32 @@ public class CopycatBlockEntity extends SmartBlockEntity implements ISpecialBloc
redraw(); redraw();
} }
public boolean hasCustomMaterial() {
return !AllBlocks.COPYCAT_BASE.has(getMaterial());
}
public BlockState getMaterial() {
return baseBlock;
}
public boolean cycleMaterial() { public boolean cycleMaterial() {
if (baseBlock.hasProperty(BlockStateProperties.FACING)) if (material.hasProperty(BlockStateProperties.FACING))
setMaterial(baseBlock.cycle(BlockStateProperties.FACING)); setMaterial(material.cycle(BlockStateProperties.FACING));
else if (baseBlock.hasProperty(BlockStateProperties.HORIZONTAL_FACING)) else if (material.hasProperty(BlockStateProperties.HORIZONTAL_FACING))
setMaterial(baseBlock.cycle(BlockStateProperties.HORIZONTAL_FACING)); setMaterial(material.cycle(BlockStateProperties.HORIZONTAL_FACING));
else if (baseBlock.hasProperty(BlockStateProperties.AXIS)) else if (material.hasProperty(BlockStateProperties.AXIS))
setMaterial(baseBlock.cycle(BlockStateProperties.AXIS)); setMaterial(material.cycle(BlockStateProperties.AXIS));
else if (baseBlock.hasProperty(BlockStateProperties.HORIZONTAL_AXIS)) else if (material.hasProperty(BlockStateProperties.HORIZONTAL_AXIS))
setMaterial(baseBlock.cycle(BlockStateProperties.HORIZONTAL_AXIS)); setMaterial(material.cycle(BlockStateProperties.HORIZONTAL_AXIS));
else if (baseBlock.hasProperty(BlockStateProperties.LIT)) else if (material.hasProperty(BlockStateProperties.LIT))
setMaterial(baseBlock.cycle(BlockStateProperties.LIT)); setMaterial(material.cycle(BlockStateProperties.LIT));
else if (baseBlock.hasProperty(RoseQuartzLampBlock.POWERING)) else if (material.hasProperty(RoseQuartzLampBlock.POWERING))
setMaterial(baseBlock.cycle(RoseQuartzLampBlock.POWERING)); setMaterial(material.cycle(RoseQuartzLampBlock.POWERING));
else else
return false; return false;
return true; return true;
} }
@Override public ItemStack getConsumedItem() {
protected void read(CompoundTag tag, boolean clientPacket) { return consumedItem;
super.read(tag, clientPacket); }
consumedItem = ItemStack.of(tag.getCompound("Item")); public void setConsumedItem(ItemStack stack) {
consumedItem = ItemHandlerHelper.copyStackWithSize(stack, 1);
BlockState prevMaterial = baseBlock; setChanged();
if (!tag.contains("Material"))
return;
JsonOps ops = JsonOps.INSTANCE;
BlockState.CODEC.decode(ops, JsonParser.parseString(tag.getString("Material")))
.result()
.ifPresent(p -> baseBlock = p.getFirst());
if (clientPacket && prevMaterial != baseBlock)
redraw();
} }
private void redraw() { private void redraw() {
@ -137,6 +110,41 @@ public class CopycatBlockEntity extends SmartBlockEntity implements ISpecialBloc
} }
} }
@Override
public void addBehaviours(List<BlockEntityBehaviour> behaviours) {}
@Override
public ItemRequirement getRequiredItems(BlockState state) {
if (consumedItem.isEmpty())
return ItemRequirement.NONE;
return new ItemRequirement(ItemUseType.CONSUME, consumedItem);
}
@Override
public void transform(StructureTransform transform) {
material = transform.apply(material);
notifyUpdate();
}
@Override
protected void read(CompoundTag tag, boolean clientPacket) {
super.read(tag, clientPacket);
consumedItem = ItemStack.of(tag.getCompound("Item"));
BlockState prevMaterial = material;
if (!tag.contains("Material"))
return;
JsonOps ops = JsonOps.INSTANCE;
BlockState.CODEC.decode(ops, JsonParser.parseString(tag.getString("Material")))
.result()
.ifPresent(p -> material = p.getFirst());
if (clientPacket && prevMaterial != material)
redraw();
}
@Override @Override
protected void write(CompoundTag tag, boolean clientPacket) { protected void write(CompoundTag tag, boolean clientPacket) {
super.write(tag, clientPacket); super.write(tag, clientPacket);
@ -144,27 +152,16 @@ public class CopycatBlockEntity extends SmartBlockEntity implements ISpecialBloc
tag.put("Item", consumedItem.serializeNBT()); tag.put("Item", consumedItem.serializeNBT());
JsonOps ops = JsonOps.INSTANCE; JsonOps ops = JsonOps.INSTANCE;
BlockState.CODEC.encode(baseBlock, ops, ops.empty()) BlockState.CODEC.encode(material, ops, ops.empty())
.result() .result()
.map(je -> je.toString()) .map(je -> je.toString())
.ifPresent(s -> tag.putString("Material", s)); .ifPresent(s -> tag.putString("Material", s));
} }
public static final ModelProperty<BlockState> MATERIAL_PROPERTY = new ModelProperty<>();
@Override @Override
public IModelData getModelData() { public IModelData getModelData() {
return new ModelDataMap.Builder().withInitial(MATERIAL_PROPERTY, baseBlock) return new ModelDataMap.Builder().withInitial(CopycatModel.MATERIAL_PROPERTY, material)
.build(); .build();
} }
@Override
public void addBehaviours(List<BlockEntityBehaviour> behaviours) {}
@Override
public void transform(StructureTransform transform) {
baseBlock = transform.apply(baseBlock);
notifyUpdate();
}
} }

View file

@ -1,20 +1,13 @@
package com.simibubi.create.content.curiosities.frames; package com.simibubi.create.content.curiosities.frames;
import static com.simibubi.create.content.curiosities.frames.CopycatBlockEntity.MATERIAL_PROPERTY;
import static com.simibubi.create.foundation.block.render.SpriteShiftEntry.getUnInterpolatedU;
import static com.simibubi.create.foundation.block.render.SpriteShiftEntry.getUnInterpolatedV;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.foundation.block.connected.BakedModelWrapperWithData; import com.simibubi.create.foundation.model.BakedModelWrapperWithData;
import com.simibubi.create.foundation.block.render.QuadHelper;
import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.ItemBlockRenderTypes; import net.minecraft.client.renderer.ItemBlockRenderTypes;
@ -28,177 +21,94 @@ import net.minecraft.core.Direction;
import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.client.MinecraftForgeClient; import net.minecraftforge.client.MinecraftForgeClient;
import net.minecraftforge.client.model.data.EmptyModelData; import net.minecraftforge.client.model.data.EmptyModelData;
import net.minecraftforge.client.model.data.IModelData; import net.minecraftforge.client.model.data.IModelData;
import net.minecraftforge.client.model.data.ModelDataMap;
import net.minecraftforge.client.model.data.ModelDataMap.Builder; import net.minecraftforge.client.model.data.ModelDataMap.Builder;
import net.minecraftforge.client.model.data.ModelProperty; import net.minecraftforge.client.model.data.ModelProperty;
public abstract class CopycatModel extends BakedModelWrapperWithData { public abstract class CopycatModel extends BakedModelWrapperWithData {
private static final ModelProperty<IModelData> WRAPPED_DATA_PROPERTY = new ModelProperty<>(); public static final ModelProperty<BlockState> MATERIAL_PROPERTY = new ModelProperty<>();
private static final ModelProperty<OcclusionData> OCCLUSION_PROPERTY = new ModelProperty<>(); private static final ModelProperty<OcclusionData> OCCLUSION_PROPERTY = new ModelProperty<>();
private static final ModelProperty<IModelData> WRAPPED_DATA_PROPERTY = new ModelProperty<>();
public CopycatModel(BakedModel originalModel) { public CopycatModel(BakedModel originalModel) {
super(originalModel); super(originalModel);
} }
@Override @Override
protected Builder gatherModelData(Builder builder, BlockAndTintGetter world, BlockPos pos, BlockState state, protected void gatherModelData(Builder builder, BlockAndTintGetter world, BlockPos pos, BlockState state,
IModelData blockEntityData) { IModelData blockEntityData) {
BlockState wrappedState = getMaterial(world, pos, state); BlockState material = getMaterial(blockEntityData);
if (material == null)
return;
if (wrappedState == null) builder.withInitial(MATERIAL_PROPERTY, material);
return builder;
if (blockEntityData instanceof ModelDataMap mdm && mdm.hasProperty(MATERIAL_PROPERTY))
builder.withInitial(MATERIAL_PROPERTY, mdm.getData(MATERIAL_PROPERTY));
OcclusionData occlusionData = new OcclusionData(); OcclusionData occlusionData = new OcclusionData();
if (state.getBlock()instanceof CopycatBlock ufb) { if (state.getBlock() instanceof CopycatBlock copycatBlock) {
MutableBlockPos mutablePos = new MutableBlockPos(); MutableBlockPos mutablePos = new MutableBlockPos();
for (Direction face : Iterate.directions) for (Direction face : Iterate.directions)
if (ufb.canFaceBeOccluded(state, face)) if (copycatBlock.canFaceBeOccluded(state, face))
if (!Block.shouldRenderFace(wrappedState, world, pos, face, mutablePos.setWithOffset(pos, face))) if (!Block.shouldRenderFace(material, world, pos, face, mutablePos.setWithOffset(pos, face)))
occlusionData.occlude(face); occlusionData.occlude(face);
builder.withInitial(OCCLUSION_PROPERTY, occlusionData); builder.withInitial(OCCLUSION_PROPERTY, occlusionData);
} }
IModelData modelData = getModelOf(wrappedState).getModelData(world, pos, wrappedState, EmptyModelData.INSTANCE); IModelData wrappedData = getModelOf(material).getModelData(world, pos, material, EmptyModelData.INSTANCE);
return builder.withInitial(WRAPPED_DATA_PROPERTY, modelData); builder.withInitial(WRAPPED_DATA_PROPERTY, wrappedData);
} }
@Override @Override
public List<BakedQuad> getQuads(BlockState state, Direction side, Random rand, IModelData extraData) { public List<BakedQuad> getQuads(BlockState state, Direction side, Random rand, IModelData data) {
List<BakedQuad> quads = super.getQuads(state, side, rand, extraData); BlockState material = getMaterial(data);
BlockState material = getMaterial(extraData);
IModelData wrappedData = extraData.getData(WRAPPED_DATA_PROPERTY);
if (material == null) if (material == null)
return quads; return super.getQuads(state, side, rand, data);
OcclusionData occlusionData = data.getData(OCCLUSION_PROPERTY);
if (occlusionData != null && occlusionData.isOccluded(side))
return super.getQuads(state, side, rand, data);
RenderType renderType = MinecraftForgeClient.getRenderType(); RenderType renderType = MinecraftForgeClient.getRenderType();
if (renderType != null && !ItemBlockRenderTypes.canRenderInLayer(material, renderType)) if (renderType != null && !ItemBlockRenderTypes.canRenderInLayer(material, renderType))
return quads; return super.getQuads(state, side, rand, data);
IModelData wrappedData = data.getData(WRAPPED_DATA_PROPERTY);
if (wrappedData == null) if (wrappedData == null)
wrappedData = EmptyModelData.INSTANCE; wrappedData = EmptyModelData.INSTANCE;
OcclusionData occlusionData = extraData.getData(OCCLUSION_PROPERTY);
if (occlusionData != null && occlusionData.isOccluded(side))
return quads;
return getCroppedQuads(state, side, rand, material, wrappedData); return getCroppedQuads(state, side, rand, material, wrappedData);
} }
protected abstract List<BakedQuad> getCroppedQuads(BlockState state, Direction side, Random rand, protected abstract List<BakedQuad> getCroppedQuads(BlockState state, Direction side, Random rand,
BlockState material, IModelData wrappedData); BlockState material, IModelData wrappedData);
public static boolean cropAndMove(BakedQuad quad, AABB crop, Vec3 move) {
int[] vertexData = quad.getVertices();
Vec3 xyz0 = QuadHelper.getXYZ(vertexData, 0);
Vec3 xyz1 = QuadHelper.getXYZ(vertexData, 1);
Vec3 xyz2 = QuadHelper.getXYZ(vertexData, 2);
Vec3 xyz3 = QuadHelper.getXYZ(vertexData, 3);
Vec3 uAxis = xyz3.add(xyz2)
.scale(.5);
Vec3 vAxis = xyz1.add(xyz2)
.scale(.5);
Vec3 center = xyz3.add(xyz2)
.add(xyz0)
.add(xyz1)
.scale(.25);
float u0 = QuadHelper.getU(vertexData, 0);
float u3 = QuadHelper.getU(vertexData, 3);
float v0 = QuadHelper.getV(vertexData, 0);
float v1 = QuadHelper.getV(vertexData, 1);
TextureAtlasSprite sprite = quad.getSprite();
float uScale = (float) Math
.round((getUnInterpolatedU(sprite, u3) - getUnInterpolatedU(sprite, u0)) / xyz3.distanceTo(xyz0));
float vScale = (float) Math
.round((getUnInterpolatedV(sprite, v1) - getUnInterpolatedV(sprite, v0)) / xyz1.distanceTo(xyz0));
if (uScale == 0) {
float v3 = QuadHelper.getV(vertexData, 3);
float u1 = QuadHelper.getU(vertexData, 1);
uAxis = xyz1.add(xyz2)
.scale(.5);
vAxis = xyz3.add(xyz2)
.scale(.5);
uScale = (float) Math
.round((getUnInterpolatedU(sprite, u1) - getUnInterpolatedU(sprite, u0)) / xyz1.distanceTo(xyz0));
vScale = (float) Math
.round((getUnInterpolatedV(sprite, v3) - getUnInterpolatedV(sprite, v0)) / xyz3.distanceTo(xyz0));
}
uAxis = uAxis.subtract(center)
.normalize();
vAxis = vAxis.subtract(center)
.normalize();
Vec3 min = new Vec3(crop.minX, crop.minY, crop.minZ);
Vec3 max = new Vec3(crop.maxX, crop.maxY, crop.maxZ);
for (int vertex = 0; vertex < 4; vertex++) {
Vec3 xyz = QuadHelper.getXYZ(vertexData, vertex);
Vec3 newXyz = VecHelper.componentMin(max, VecHelper.componentMax(xyz, min));
Vec3 diff = newXyz.subtract(xyz);
if (diff.lengthSqr() > 0) {
float u = QuadHelper.getU(vertexData, vertex);
float v = QuadHelper.getV(vertexData, vertex);
float uDiff = (float) uAxis.dot(diff) * uScale;
float vDiff = (float) vAxis.dot(diff) * vScale;
QuadHelper.setU(vertexData, vertex, sprite.getU(getUnInterpolatedU(sprite, u) + uDiff));
QuadHelper.setV(vertexData, vertex, sprite.getV(getUnInterpolatedV(sprite, v) + vDiff));
}
QuadHelper.setXYZ(vertexData, vertex, newXyz.add(move));
}
return true;
}
@Override @Override
public TextureAtlasSprite getParticleIcon(IModelData data) { public TextureAtlasSprite getParticleIcon(IModelData data) {
BlockState material = getMaterial(data); BlockState material = getMaterial(data);
IModelData wrappedData = data.getData(WRAPPED_DATA_PROPERTY);
if (material == null)
return super.getParticleIcon(data);
IModelData wrappedData = data.getData(WRAPPED_DATA_PROPERTY);
if (wrappedData == null) if (wrappedData == null)
wrappedData = EmptyModelData.INSTANCE; wrappedData = EmptyModelData.INSTANCE;
if (material != null)
return getModelOf(material).getParticleIcon(wrappedData);
return super.getParticleIcon(data); return getModelOf(material).getParticleIcon(wrappedData);
} }
@Nullable @Nullable
public BlockState getMaterial(IModelData extraData) { public static BlockState getMaterial(IModelData data) {
BlockState material = extraData.getData(MATERIAL_PROPERTY); BlockState material = data.getData(MATERIAL_PROPERTY);
return material == null ? AllBlocks.COPYCAT_BASE.getDefaultState() : material; return material == null ? AllBlocks.COPYCAT_BASE.getDefaultState() : material;
} }
@Nullable public static BakedModel getModelOf(BlockState state) {
public BlockState getMaterial(BlockAndTintGetter world, BlockPos pos, BlockState state) {
if (!(state.getBlock()instanceof CopycatBlock ufb))
return null;
return ufb.getBlockEntityOptional(world, pos)
.map(CopycatBlockEntity::getMaterial)
.orElse(null);
}
public BakedModel getModelOf(BlockState wrappedState) {
return Minecraft.getInstance() return Minecraft.getInstance()
.getBlockRenderer() .getBlockRenderer()
.getBlockModel(wrappedState); .getBlockModel(state);
} }
private static class OcclusionData { private static class OcclusionData {
@ -206,7 +116,6 @@ public abstract class CopycatModel extends BakedModelWrapperWithData {
public OcclusionData() { public OcclusionData() {
occluded = new boolean[6]; occluded = new boolean[6];
Arrays.fill(occluded, false);
} }
public void occlude(Direction face) { public void occlude(Direction face) {

View file

@ -4,7 +4,8 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
import com.simibubi.create.foundation.block.render.QuadHelper; import com.simibubi.create.foundation.model.BakedModelHelper;
import com.simibubi.create.foundation.model.BakedQuadHelper;
import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.block.model.BakedQuad;
@ -18,6 +19,8 @@ import net.minecraftforge.client.model.data.IModelData;
public class CopycatPanelModel extends CopycatModel { public class CopycatPanelModel extends CopycatModel {
protected static final AABB CUBE_AABB = new AABB(BlockPos.ZERO);
public CopycatPanelModel(BakedModel originalModel) { public CopycatPanelModel(BakedModel originalModel) {
super(originalModel); super(originalModel);
} }
@ -28,17 +31,22 @@ public class CopycatPanelModel extends CopycatModel {
Direction facing = state.getOptionalValue(CopycatPanelBlock.FACING) Direction facing = state.getOptionalValue(CopycatPanelBlock.FACING)
.orElse(Direction.UP); .orElse(Direction.UP);
Vec3 normal = Vec3.atLowerCornerOf(facing.getNormal());
AABB cube = new AABB(BlockPos.ZERO);
BakedModel model = getModelOf(material); BakedModel model = getModelOf(material);
List<BakedQuad> templateQuads = model.getQuads(material, side, rand, wrappedData); List<BakedQuad> templateQuads = model.getQuads(material, side, rand, wrappedData);
int size = templateQuads.size(); int size = templateQuads.size();
List<BakedQuad> quads = new ArrayList<>(); List<BakedQuad> quads = new ArrayList<>();
Vec3 normal = Vec3.atLowerCornerOf(facing.getNormal());
Vec3 normalScaled14 = normal.scale(14 / 16f);
// 2 Pieces // 2 Pieces
for (boolean front : Iterate.trueAndFalse) { for (boolean front : Iterate.trueAndFalse) {
Vec3 normalScaledN13 = normal.scale(front ? 0 : -13 / 16f);
float contract = 16 - (front ? 1 : 2);
AABB bb = CUBE_AABB.contract(normal.x * contract / 16, normal.y * contract / 16, normal.z * contract / 16);
if (!front)
bb = bb.move(normalScaled14);
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
BakedQuad quad = templateQuads.get(i); BakedQuad quad = templateQuads.get(i);
@ -49,15 +57,9 @@ public class CopycatPanelModel extends CopycatModel {
if (!front && direction == facing.getOpposite()) if (!front && direction == facing.getOpposite())
continue; continue;
float contract = 16 - (front ? 1 : 2); BakedQuad newQuad = BakedQuadHelper.clone(quad);
AABB bb = cube.contract(normal.x * contract / 16, normal.y * contract / 16, normal.z * contract / 16); BakedModelHelper.cropAndMove(newQuad, bb, normalScaledN13);
quads.add(newQuad);
if (!front)
bb = bb.move(normal.scale(14 / 16f));
BakedQuad newQuad = QuadHelper.clone(quad);
if (cropAndMove(newQuad, bb, normal.scale(front ? 0 : -13 / 16f)));
quads.add(newQuad);
} }
} }

View file

@ -42,8 +42,8 @@ import net.minecraftforge.common.ForgeMod;
public class CopycatStepBlock extends WaterloggedCopycatBlock { public class CopycatStepBlock extends WaterloggedCopycatBlock {
public static EnumProperty<Half> HALF = BlockStateProperties.HALF; public static final EnumProperty<Half> HALF = BlockStateProperties.HALF;
public static DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING; public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
private static final int placementHelperId = PlacementHelpers.register(new PlacementHelper()); private static final int placementHelperId = PlacementHelpers.register(new PlacementHelper());

View file

@ -4,7 +4,8 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
import com.simibubi.create.foundation.block.render.QuadHelper; import com.simibubi.create.foundation.model.BakedModelHelper;
import com.simibubi.create.foundation.model.BakedQuadHelper;
import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.block.model.BakedQuad;
@ -19,6 +20,11 @@ import net.minecraftforge.client.model.data.IModelData;
public class CopycatStepModel extends CopycatModel { public class CopycatStepModel extends CopycatModel {
protected static final Vec3 VEC_Y_3 = new Vec3(0, .75, 0);
protected static final Vec3 VEC_Y_2 = new Vec3(0, .5, 0);
protected static final Vec3 VEC_Y_N2 = new Vec3(0, -.5, 0);
protected static final AABB CUBE_AABB = new AABB(BlockPos.ZERO);
public CopycatStepModel(BakedModel originalModel) { public CopycatStepModel(BakedModel originalModel) {
super(originalModel); super(originalModel);
} }
@ -31,21 +37,33 @@ public class CopycatStepModel extends CopycatModel {
boolean upperHalf = state.getOptionalValue(CopycatStepBlock.HALF) boolean upperHalf = state.getOptionalValue(CopycatStepBlock.HALF)
.orElse(Half.BOTTOM) == Half.TOP; .orElse(Half.BOTTOM) == Half.TOP;
Vec3 zero = Vec3.ZERO;
Vec3 up = new Vec3(0, 1, 0);
Vec3 normal = Vec3.atLowerCornerOf(facing.getNormal());
BakedModel model = getModelOf(material); BakedModel model = getModelOf(material);
List<BakedQuad> templateQuads = model.getQuads(material, side, rand, wrappedData); List<BakedQuad> templateQuads = model.getQuads(material, side, rand, wrappedData);
int size = templateQuads.size(); int size = templateQuads.size();
AABB cube = new AABB(BlockPos.ZERO);
List<BakedQuad> quads = new ArrayList<>(); List<BakedQuad> quads = new ArrayList<>();
Vec3 normal = Vec3.atLowerCornerOf(facing.getNormal());
Vec3 normalScaled2 = normal.scale(.5);
Vec3 normalScaledN3 = normal.scale(-.75);
AABB bb = CUBE_AABB.contract(-normal.x * .75, .75, -normal.z * .75);
// 4 Pieces // 4 Pieces
for (boolean top : Iterate.trueAndFalse) { for (boolean top : Iterate.trueAndFalse) {
for (boolean front : Iterate.trueAndFalse) { for (boolean front : Iterate.trueAndFalse) {
AABB bb1 = bb;
if (front)
bb1 = bb1.move(normalScaledN3);
if (top)
bb1 = bb1.move(VEC_Y_3);
Vec3 offset = Vec3.ZERO;
if (front)
offset = offset.add(normalScaled2);
if (top != upperHalf)
offset = offset.add(upperHalf ? VEC_Y_2 : VEC_Y_N2);
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
BakedQuad quad = templateQuads.get(i); BakedQuad quad = templateQuads.get(i);
Direction direction = quad.getDirection(); Direction direction = quad.getDirection();
@ -59,23 +77,9 @@ public class CopycatStepModel extends CopycatModel {
if (top && direction == Direction.DOWN) if (top && direction == Direction.DOWN)
continue; continue;
AABB bb = cube.contract(-normal.x * .75, .75, -normal.z * .75); BakedQuad newQuad = BakedQuadHelper.clone(quad);
BakedModelHelper.cropAndMove(newQuad, bb1, offset);
if (front) quads.add(newQuad);
bb = bb.move(normal.scale(-.75));
if (top)
bb = bb.move(up.scale(.75));
Vec3 offset = zero;
if (front)
offset = offset.add(normal.scale(.5));
if (top != upperHalf)
offset = offset.add(up.scale(upperHalf ? .5 : -.5));
BakedQuad newQuad = QuadHelper.clone(quad);
if (cropAndMove(newQuad, bb, offset))
quads.add(newQuad);
} }
} }

View file

@ -21,20 +21,20 @@ import net.minecraftforge.client.model.data.ModelProperty;
public class ConnectedGirderModel extends CTModel { public class ConnectedGirderModel extends CTModel {
protected static ModelProperty<ConnectionData> CONNECTION_PROPERTY = new ModelProperty<>(); protected static final ModelProperty<ConnectionData> CONNECTION_PROPERTY = new ModelProperty<>();
public ConnectedGirderModel(BakedModel originalModel) { public ConnectedGirderModel(BakedModel originalModel) {
super(originalModel, new GirderCTBehaviour()); super(originalModel, new GirderCTBehaviour());
} }
@Override @Override
protected Builder gatherModelData(Builder builder, BlockAndTintGetter world, BlockPos pos, BlockState state, protected void gatherModelData(Builder builder, BlockAndTintGetter world, BlockPos pos, BlockState state,
IModelData blockEntityData) { IModelData blockEntityData) {
super.gatherModelData(builder, world, pos, state, blockEntityData);
ConnectionData connectionData = new ConnectionData(); ConnectionData connectionData = new ConnectionData();
for (Direction d : Iterate.horizontalDirections) for (Direction d : Iterate.horizontalDirections)
connectionData.setConnected(d, GirderBlock.isConnected(world, pos, state, d)); connectionData.setConnected(d, GirderBlock.isConnected(world, pos, state, d));
return super.gatherModelData(builder, world, pos, state, blockEntityData).withInitial(CONNECTION_PROPERTY, builder.withInitial(CONNECTION_PROPERTY, connectionData);
connectionData);
} }
@Override @Override
@ -52,7 +52,7 @@ public class ConnectedGirderModel extends CTModel {
return quads; return quads;
} }
private class ConnectionData { private static class ConnectionData {
boolean[] connectedFaces; boolean[] connectedFaces;
public ConnectionData() { public ConnectionData() {

View file

@ -7,7 +7,7 @@ import javax.annotation.Nullable;
import com.simibubi.create.Create; import com.simibubi.create.Create;
import com.simibubi.create.content.contraptions.base.KineticBlockEntity; import com.simibubi.create.content.contraptions.base.KineticBlockEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableTE; import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableBlockEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform;
import com.simibubi.create.content.logistics.block.mechanicalArm.AllArmInteractionPointTypes.JukeboxPoint; import com.simibubi.create.content.logistics.block.mechanicalArm.AllArmInteractionPointTypes.JukeboxPoint;
import com.simibubi.create.content.logistics.block.mechanicalArm.ArmInteractionPoint.Mode; import com.simibubi.create.content.logistics.block.mechanicalArm.ArmInteractionPoint.Mode;
@ -45,7 +45,7 @@ import net.minecraft.world.level.chunk.ChunkSource;
import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
public class ArmBlockEntity extends KineticBlockEntity implements ITransformableTE { public class ArmBlockEntity extends KineticBlockEntity implements ITransformableBlockEntity {
// Server // Server
List<ArmInteractionPoint> inputs; List<ArmInteractionPoint> inputs;

View file

@ -6,7 +6,7 @@ import javax.annotation.Nullable;
import com.jozufozu.flywheel.util.transform.TransformStack; import com.jozufozu.flywheel.util.transform.TransformStack;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableTE; import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableBlockEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform;
import com.simibubi.create.content.logistics.block.display.DisplayLinkBlock; import com.simibubi.create.content.logistics.block.display.DisplayLinkBlock;
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType; import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType;
@ -23,7 +23,7 @@ import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
public class TrackObserverBlockEntity extends SmartBlockEntity implements ITransformableTE { public class TrackObserverBlockEntity extends SmartBlockEntity implements ITransformableBlockEntity {
public TrackTargetingBehaviour<TrackObserver> edgePoint; public TrackTargetingBehaviour<TrackObserver> edgePoint;

View file

@ -4,7 +4,7 @@ import java.util.List;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableTE; import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableBlockEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform;
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType; import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType;
import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBehaviour; import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBehaviour;
@ -19,7 +19,7 @@ import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.AABB;
public class SignalBlockEntity extends SmartBlockEntity implements ITransformableTE { public class SignalBlockEntity extends SmartBlockEntity implements ITransformableBlockEntity {
public static enum OverlayState { public static enum OverlayState {
RENDER, SKIP, DUAL RENDER, SKIP, DUAL

View file

@ -17,7 +17,7 @@ import com.simibubi.create.AllItems;
import com.simibubi.create.AllSoundEvents; import com.simibubi.create.AllSoundEvents;
import com.simibubi.create.Create; import com.simibubi.create.Create;
import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException;
import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableTE; import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableBlockEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform;
import com.simibubi.create.content.logistics.block.depot.DepotBehaviour; import com.simibubi.create.content.logistics.block.depot.DepotBehaviour;
import com.simibubi.create.content.logistics.block.display.DisplayLinkBlock; import com.simibubi.create.content.logistics.block.display.DisplayLinkBlock;
@ -77,7 +77,7 @@ import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.network.PacketDistributor; import net.minecraftforge.network.PacketDistributor;
public class StationBlockEntity extends SmartBlockEntity implements ITransformableTE { public class StationBlockEntity extends SmartBlockEntity implements ITransformableBlockEntity {
public TrackTargetingBehaviour<GlobalStation> edgePoint; public TrackTargetingBehaviour<GlobalStation> edgePoint;
public LerpedFloat flag; public LerpedFloat flag;

View file

@ -9,7 +9,7 @@ import java.util.Set;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableTE; import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableBlockEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform;
import com.simibubi.create.content.logistics.trains.BezierConnection; import com.simibubi.create.content.logistics.trains.BezierConnection;
import com.simibubi.create.content.logistics.trains.ITrackBlock; import com.simibubi.create.content.logistics.trains.ITrackBlock;
@ -46,7 +46,7 @@ import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.DistExecutor;
public class TrackBlockEntity extends SmartBlockEntity implements ITransformableTE, IMergeableBE { public class TrackBlockEntity extends SmartBlockEntity implements ITransformableBlockEntity, IMergeableBE {
Map<BlockPos, BezierConnection> connections; Map<BlockPos, BezierConnection> connections;
boolean cancelDrops; boolean cancelDrops;

View file

@ -7,7 +7,8 @@ import java.util.Random;
import com.simibubi.create.content.curiosities.frames.CopycatBlock; import com.simibubi.create.content.curiosities.frames.CopycatBlock;
import com.simibubi.create.foundation.block.connected.ConnectedTextureBehaviour.CTContext; import com.simibubi.create.foundation.block.connected.ConnectedTextureBehaviour.CTContext;
import com.simibubi.create.foundation.block.render.QuadHelper; import com.simibubi.create.foundation.model.BakedModelWrapperWithData;
import com.simibubi.create.foundation.model.BakedQuadHelper;
import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.block.model.BakedQuad;
@ -34,9 +35,9 @@ public class CTModel extends BakedModelWrapperWithData {
} }
@Override @Override
protected Builder gatherModelData(Builder builder, BlockAndTintGetter world, BlockPos pos, BlockState state, protected void gatherModelData(Builder builder, BlockAndTintGetter world, BlockPos pos, BlockState state,
IModelData blockEntityData) { IModelData blockEntityData) {
return builder.withInitial(CT_PROPERTY, createCTData(world, pos, state)); builder.withInitial(CT_PROPERTY, createCTData(world, pos, state));
} }
protected CTData createCTData(BlockAndTintGetter world, BlockPos pos, BlockState state) { protected CTData createCTData(BlockAndTintGetter world, BlockPos pos, BlockState state) {
@ -80,14 +81,14 @@ public class CTModel extends BakedModelWrapperWithData {
if (quad.getSprite() != spriteShift.getOriginal()) if (quad.getSprite() != spriteShift.getOriginal())
continue; continue;
BakedQuad newQuad = QuadHelper.clone(quad); BakedQuad newQuad = BakedQuadHelper.clone(quad);
int[] vertexData = newQuad.getVertices(); int[] vertexData = newQuad.getVertices();
for (int vertex = 0; vertex < 4; vertex++) { for (int vertex = 0; vertex < 4; vertex++) {
float u = QuadHelper.getU(vertexData, vertex); float u = BakedQuadHelper.getU(vertexData, vertex);
float v = QuadHelper.getV(vertexData, vertex); float v = BakedQuadHelper.getV(vertexData, vertex);
QuadHelper.setU(vertexData, vertex, spriteShift.getTargetU(u, index)); BakedQuadHelper.setU(vertexData, vertex, spriteShift.getTargetU(u, index));
QuadHelper.setV(vertexData, vertex, spriteShift.getTargetV(v, index)); BakedQuadHelper.setV(vertexData, vertex, spriteShift.getTargetV(v, index));
} }
quads.set(i, newQuad); quads.set(i, newQuad);

View file

@ -0,0 +1,82 @@
package com.simibubi.create.foundation.model;
import static com.simibubi.create.foundation.block.render.SpriteShiftEntry.getUnInterpolatedU;
import static com.simibubi.create.foundation.block.render.SpriteShiftEntry.getUnInterpolatedV;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
public class BakedModelHelper {
public static void cropAndMove(BakedQuad quad, AABB crop, Vec3 move) {
int[] vertexData = quad.getVertices();
Vec3 xyz0 = BakedQuadHelper.getXYZ(vertexData, 0);
Vec3 xyz1 = BakedQuadHelper.getXYZ(vertexData, 1);
Vec3 xyz2 = BakedQuadHelper.getXYZ(vertexData, 2);
Vec3 xyz3 = BakedQuadHelper.getXYZ(vertexData, 3);
Vec3 uAxis = xyz3.add(xyz2)
.scale(.5);
Vec3 vAxis = xyz1.add(xyz2)
.scale(.5);
Vec3 center = xyz3.add(xyz2)
.add(xyz0)
.add(xyz1)
.scale(.25);
float u0 = BakedQuadHelper.getU(vertexData, 0);
float u3 = BakedQuadHelper.getU(vertexData, 3);
float v0 = BakedQuadHelper.getV(vertexData, 0);
float v1 = BakedQuadHelper.getV(vertexData, 1);
TextureAtlasSprite sprite = quad.getSprite();
float uScale = (float) Math
.round((getUnInterpolatedU(sprite, u3) - getUnInterpolatedU(sprite, u0)) / xyz3.distanceTo(xyz0));
float vScale = (float) Math
.round((getUnInterpolatedV(sprite, v1) - getUnInterpolatedV(sprite, v0)) / xyz1.distanceTo(xyz0));
if (uScale == 0) {
float v3 = BakedQuadHelper.getV(vertexData, 3);
float u1 = BakedQuadHelper.getU(vertexData, 1);
uAxis = xyz1.add(xyz2)
.scale(.5);
vAxis = xyz3.add(xyz2)
.scale(.5);
uScale = (float) Math
.round((getUnInterpolatedU(sprite, u1) - getUnInterpolatedU(sprite, u0)) / xyz1.distanceTo(xyz0));
vScale = (float) Math
.round((getUnInterpolatedV(sprite, v3) - getUnInterpolatedV(sprite, v0)) / xyz3.distanceTo(xyz0));
}
uAxis = uAxis.subtract(center)
.normalize();
vAxis = vAxis.subtract(center)
.normalize();
Vec3 min = new Vec3(crop.minX, crop.minY, crop.minZ);
Vec3 max = new Vec3(crop.maxX, crop.maxY, crop.maxZ);
for (int vertex = 0; vertex < 4; vertex++) {
Vec3 xyz = BakedQuadHelper.getXYZ(vertexData, vertex);
Vec3 newXyz = VecHelper.componentMin(max, VecHelper.componentMax(xyz, min));
Vec3 diff = newXyz.subtract(xyz);
if (diff.lengthSqr() > 0) {
float u = BakedQuadHelper.getU(vertexData, vertex);
float v = BakedQuadHelper.getV(vertexData, vertex);
float uDiff = (float) uAxis.dot(diff) * uScale;
float vDiff = (float) vAxis.dot(diff) * vScale;
BakedQuadHelper.setU(vertexData, vertex, sprite.getU(getUnInterpolatedU(sprite, u) + uDiff));
BakedQuadHelper.setV(vertexData, vertex, sprite.getV(getUnInterpolatedV(sprite, v) + vDiff));
}
BakedQuadHelper.setXYZ(vertexData, vertex, newXyz.add(move));
}
}
}

View file

@ -1,4 +1,4 @@
package com.simibubi.create.foundation.block.connected; package com.simibubi.create.foundation.model;
import net.minecraft.client.resources.model.BakedModel; import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
@ -21,10 +21,11 @@ public abstract class BakedModelWrapperWithData extends BakedModelWrapper<BakedM
Builder builder = new ModelDataMap.Builder(); Builder builder = new ModelDataMap.Builder();
if (originalModel instanceof BakedModelWrapperWithData) if (originalModel instanceof BakedModelWrapperWithData)
((BakedModelWrapperWithData) originalModel).gatherModelData(builder, world, pos, state, blockEntityData); ((BakedModelWrapperWithData) originalModel).gatherModelData(builder, world, pos, state, blockEntityData);
return gatherModelData(builder, world, pos, state, blockEntityData).build(); gatherModelData(builder, world, pos, state, blockEntityData);
return builder.build();
} }
protected abstract ModelDataMap.Builder gatherModelData(ModelDataMap.Builder builder, BlockAndTintGetter world, protected abstract void gatherModelData(ModelDataMap.Builder builder, BlockAndTintGetter world,
BlockPos pos, BlockState state, IModelData blockEntityData); BlockPos pos, BlockState state, IModelData blockEntityData);
} }

View file

@ -1,4 +1,4 @@
package com.simibubi.create.foundation.block.render; package com.simibubi.create.foundation.model;
import java.util.Arrays; import java.util.Arrays;
@ -8,7 +8,7 @@ import com.mojang.blaze3d.vertex.VertexFormat;
import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
public final class QuadHelper { public final class BakedQuadHelper {
public static final VertexFormat FORMAT = DefaultVertexFormat.BLOCK; public static final VertexFormat FORMAT = DefaultVertexFormat.BLOCK;
public static final int VERTEX_STRIDE = FORMAT.getIntegerSize(); public static final int VERTEX_STRIDE = FORMAT.getIntegerSize();
@ -22,7 +22,7 @@ public final class QuadHelper {
public static final int LIGHT_OFFSET = 6; public static final int LIGHT_OFFSET = 6;
public static final int NORMAL_OFFSET = 7; public static final int NORMAL_OFFSET = 7;
private QuadHelper() {} private BakedQuadHelper() {}
public static BakedQuad clone(BakedQuad quad) { public static BakedQuad clone(BakedQuad quad) {
return new BakedQuad(Arrays.copyOf(quad.getVertices(), quad.getVertices().length), return new BakedQuad(Arrays.copyOf(quad.getVertices(), quad.getVertices().length),
@ -36,6 +36,12 @@ public final class QuadHelper {
return new Vec3(x, y, z); return new Vec3(x, y, z);
} }
public static void setXYZ(int[] vertexData, int vertex, Vec3 xyz) {
vertexData[vertex * VERTEX_STRIDE + X_OFFSET] = Float.floatToRawIntBits((float) xyz.x);
vertexData[vertex * VERTEX_STRIDE + Y_OFFSET] = Float.floatToRawIntBits((float) xyz.y);
vertexData[vertex * VERTEX_STRIDE + Z_OFFSET] = Float.floatToRawIntBits((float) xyz.z);
}
public static float getU(int[] vertexData, int vertex) { public static float getU(int[] vertexData, int vertex) {
return Float.intBitsToFloat(vertexData[vertex * VERTEX_STRIDE + U_OFFSET]); return Float.intBitsToFloat(vertexData[vertex * VERTEX_STRIDE + U_OFFSET]);
} }
@ -44,12 +50,6 @@ public final class QuadHelper {
return Float.intBitsToFloat(vertexData[vertex * VERTEX_STRIDE + V_OFFSET]); return Float.intBitsToFloat(vertexData[vertex * VERTEX_STRIDE + V_OFFSET]);
} }
public static void setXYZ(int[] vertexData, int vertex, Vec3 xyz) {
vertexData[vertex * VERTEX_STRIDE + X_OFFSET] = Float.floatToRawIntBits((float) xyz.x);
vertexData[vertex * VERTEX_STRIDE + Y_OFFSET] = Float.floatToRawIntBits((float) xyz.y);
vertexData[vertex * VERTEX_STRIDE + Z_OFFSET] = Float.floatToRawIntBits((float) xyz.z);
}
public static void setU(int[] vertexData, int vertex, float u) { public static void setU(int[] vertexData, int vertex, float u) {
vertexData[vertex * VERTEX_STRIDE + U_OFFSET] = Float.floatToRawIntBits(u); vertexData[vertex * VERTEX_STRIDE + U_OFFSET] = Float.floatToRawIntBits(u);
} }