Skip to content

Instantly share code, notes, and snippets.

@Lanse505
Created July 31, 2022 17:34
Show Gist options
  • Save Lanse505/4e077a688e8781ea5df90f4b775f26b0 to your computer and use it in GitHub Desktop.
Save Lanse505/4e077a688e8781ea5df90f4b775f26b0 to your computer and use it in GitHub Desktop.
package matteroverdrive.core.block;
import com.hrznstudio.titanium.block.BasicTileBlock;
import com.hrznstudio.titanium.block.tile.BasicTile;
import net.minecraft.world.level.block.RenderShape;
import net.minecraft.world.level.block.state.BlockState;
public abstract class GenericEntityBlock<T extends BasicTile<T>> extends BasicTileBlock<T> {
/**
* Default Constructor for GenericEntityBlock.
*
* @param properties The blocks BlockBehaviour Properties.
* @param name The "name" of the block (IE. "charger_block")
* @param tileClass The BlockEntity Class for the block.
*/
protected GenericEntityBlock(Properties properties, String name, Class<T> tileClass) {
super(name, properties, tileClass);
}
/**
* Override this to change the RenderShape if we need a TESR.
* INVISIBLE: {@link RenderShape#INVISIBLE} = No Rendering
* MODEL: {@link RenderShape#MODEL} = Model-based Rendering
* ENTITYBLOCK_ANIMATED: {@link RenderShape#ENTITYBLOCK_ANIMATED} = Model + TESR
*
* We are provided the {@link BlockState} of the block for use to decide if the blocks RenderShape needs to change.
* Potential optimisation would be if we add animations to the blocks that only if a "running" state is active.
* To use {@link RenderShape#ENTITYBLOCK_ANIMATED} otherwise use {@link RenderShape#MODEL}
* @param state The state of the block.
* @return returns the {@link RenderShape} of the block, using the state as a variable for the shape.
*/
@Override
@SuppressWarnings({"deprecation"})
public RenderShape getRenderShape(BlockState state) {
return RenderShape.MODEL;
}
}
package matteroverdrive.core.block;
import com.hrznstudio.titanium.block.RotatableBlock.RotationType;
import com.hrznstudio.titanium.block.RotationHandler;
import com.hrznstudio.titanium.block.tile.BasicTile;
import matteroverdrive.core.block.state.StateVariables;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Mirror;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.level.material.Fluids;
import org.jetbrains.annotations.Nullable;
public abstract class GenericStateVariableBlock<T extends BasicTile<T>> extends GenericEntityBlock<T> {
/**
* Value set for if the block should be waterloggable, defaults to false.
*/
private final boolean isWaterloggable;
/**
* Value set for if the block has a {@link RotationType}, defaults to {@link RotationType#NONE}
*/
private final RotationType rotationType;
/**
* Default Constructor for GenericStateVariableBlock.
*
* @param properties The blocks BlockBehaviour Properties.
* @param stateVariables The state variables for the block.
* @param name The "name" of the block (IE. "charger_block")
* @param tileClass The BlockEntity Class for the block.
*/
protected GenericStateVariableBlock(Properties properties, StateVariables stateVariables, String name, Class<T> tileClass) {
super(properties, name, tileClass);
this.isWaterloggable = stateVariables.getIsWaterloggable();
this.rotationType = stateVariables.getRotationType() != null ? stateVariables.getRotationType() : RotationType.NONE;
BlockState defaultState = getStateDefinition().any();
if (isWaterloggable) {
defaultState.setValue(BlockStateProperties.WATERLOGGED, false);
}
}
/**
* Getter for RotationType.
*
* @return returns the blocks {@link RotationType}.
*/
public RotationType getRotationType() {
return rotationType;
}
/**
* Logic goes:
* 1. Get the Default {@link BlockState} + Modifications by the {@link RotationHandler}.
* 2. Get the {@link FluidState} -> If the fluidstate is of type {@link Fluids#WATER} then set the value of {@link BlockStateProperties#WATERLOGGED} to true.
*
* @param context The context for the block placement.
* @return Returns the BlockState of the placed block to use.
*/
@Nullable
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
BlockState stateWithRotation = this.getRotationType().getHandler().getStateForPlacement(this, context);
FluidState fluidState = context.getLevel().getFluidState(context.getClickedPos());
return fluidState.getType() == Fluids.WATER ? stateWithRotation.setValue(BlockStateProperties.WATERLOGGED, true) : stateWithRotation;
}
/**
* Used to update the fluid if need be, by scheduling a fluid tick with a delayed value.
*
* @param state The {@link BlockState} of the {@link Block} whose shape needs updating.
* @param direction The direction of the {@link Block}.
* @param neighborState The neighbouring {@link BlockState}.
* @param level The {@link Level} of the {@link Block}.
* @param currentPos The current {@link BlockPos} of the {@link Block}.
* @param neighborPos The neighbouring {@link Block}'s {@link BlockPos}.
* @return Returns the blocks state unless modifications occur.
*/
@SuppressWarnings("deprecation")
@Override
public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor level, BlockPos currentPos, BlockPos neighborPos) {
if (state.getValue(BlockStateProperties.WATERLOGGED)) {
level.scheduleTick(currentPos, Fluids.WATER, Fluids.WATER.getTickDelay(level));
}
return super.updateShape(state, direction, neighborState, level, currentPos, neighborPos);
}
/**
* Override the default getFluidState method to be able to return the Water fluid if the block is waterlogged.
*
* @param state The {@link BlockState} of the {@link Block}.
* @return Returns the {@link FluidState} of the {@link Block}.
*/
@SuppressWarnings("deprecation")
@Override
public FluidState getFluidState(BlockState state) {
return state.getValue(BlockStateProperties.WATERLOGGED) ? Fluids.WATER.getSource(false) : super.getFluidState(state);
}
/**
* Creates our default {@link StateDefinition}.
* In our case:
* - If {@link #isWaterloggable} is true then it adds the {@link BlockStateProperties#WATERLOGGED} property.
* - If our {@link #rotationType)'s "property" list isn't null then we can add the associated properties of our {@link RotationType}.
*
* @param builder The passed in {@link net.minecraft.world.level.block.state.StateDefinition.Builder} for adding the properties to.
*/
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder);
if (isWaterloggable) {
builder.add(BlockStateProperties.WATERLOGGED);
}
if (this.rotationType.getProperties().length > 0) {
builder.add(this.rotationType.getProperties());
}
}
/**
* Rotates our {@link Block} using our blocks provided {@link RotationType} handler.
*
* @param state The current {@link BlockState} of the {@link Block}.
* @param rotation The current {@link Rotation} of the {@link Block}.
* @return Returns the new state of the block.
*/
@SuppressWarnings("deprecation")
@Override
public BlockState rotate(BlockState state, Rotation rotation) {
if (getRotationType().getProperties().length > 0){
return state.setValue(getRotationType().getProperties()[0], rotation.rotate(state.getValue(getRotationType().getProperties()[0])));
}
return super.rotate(state, rotation);
}
/**
* Mirrors our {@link Block} using our blocks provided {@link RotationType} handler.
*
* @param state The current {@link BlockState} of the {@link Block}.
* @param mirror The current {@link Mirror} state of the {@link Block}.
* @return Returns the new state of the block.
*/
@SuppressWarnings("deprecation")
@Override
public BlockState mirror(BlockState state, Mirror mirror) {
if (getRotationType().getProperties().length > 0){
return state.rotate(mirror.getRotation(state.getValue(getRotationType().getProperties()[0])));
}
return super.mirror(state, mirror);
}
}
}
package matteroverdrive.core.block.state;
import com.hrznstudio.titanium.block.RotatableBlock;
import javax.annotation.Nullable;
public class StateVariables {
/**
*
*/
boolean isWaterloggable;
/**
*
*/
@Nullable
RotatableBlock.RotationType rotationType;
/**
* Empty Private Constructor to make it so people don't instantiate new objects directly.
*/
private StateVariables() {}
/**
* @return Returns a new {@link StateVariables} object.
*/
public static StateVariables getBuilder() {
return new StateVariables();
}
/**
* Copies another StateVariables object into a new builder object.
*
* @param variables
* @return
*/
public static StateVariables copy(StateVariables variables) {
StateVariables copy = new StateVariables();
copy.isWaterloggable = variables.isWaterloggable;
copy.rotationType = variables.rotationType;
return copy;
}
/**
* @return
*/
public StateVariables isWaterloggable() {
this.isWaterloggable = true;
return this;
}
/**
* @param rotationType
* @return
*/
public StateVariables rotationType(@Nullable RotatableBlock.RotationType rotationType) {
this.rotationType = rotationType;
return this;
}
/**
* @return
*/
public boolean getIsWaterloggable() {
return isWaterloggable;
}
/**
* @return
*/
@Nullable
public RotatableBlock.RotationType getRotationType() {
return rotationType;
}
}
package matteroverdrive.core.block;
import com.hrznstudio.titanium.block.BasicTileBlock;
import com.hrznstudio.titanium.block.tile.BasicTile;
import matteroverdrive.core.block.state.StateVariables;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.SoundType;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.Material;
import net.minecraft.world.phys.BlockHitResult;
import org.jetbrains.annotations.Nullable;
public abstract class GenericMachineBlock<T extends BasicTile<T>> extends GenericStateVariableEntityBlock<T> {
// Defaults
/**
* Default Machine Block Properties
*/
private static final Properties defaultMachineProperties = Properties.of(Material.METAL)
.strength(3.5F).sound(SoundType.METAL).noOcclusion().requiresCorrectToolForDrops();
/**
* Default Waterloggable StateVariables
*/
private static final StateVariables defaultWaterloggableVariables = StateVariables.getBuilder().isWaterloggable();
/**
* Constructor that doesn't use the "Default Machine Properties"
* Note: This also does not provide a default StateVariable config!
*
* @param properties The blocks BlockBehaviour Properties.
* @param stateVariables The state variables for the block.
* @param name The "name" of the block (IE. "charger_block")
* @param tileClass The BlockEntity Class for the block.
*/
protected GenericMachineBlock(Properties properties, StateVariables stateVariables, String name, Class<T> tileClass) {
super(properties, stateVariables, name, tileClass);
}
/**
* Constructor that uses the "Default Machine Properties"
* Note: This does not provide a default StateVariable config!
*
* @param stateVariables The state variables for the block.
* @param name The "name" of the block (IE. "charger_block")
* @param tileClass The BlockEntity Class for the block.
*/
protected GenericMachineBlock(StateVariables stateVariables, String name, Class<T> tileClass) {
super(defaultMachineProperties, stateVariables, name, tileClass);
}
/**
* So you might be looking at this in the future asking where the old handling code went?
* Well I'll tell you! to consolidate behaviour and handling, this code now exists **ON** the BlockEntity itself.
* See the BlockEntity's implementation of {@link BasicTile#onActivated(Player, InteractionHand, Direction, double, double, double)}
* Also see {@link BasicTileBlock#use(BlockState, Level, BlockPos, Player, InteractionHand, BlockHitResult)}
* For where it's calling the #onActivated on the Tile!
*/
@Override
public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult ray) {
if (level.isClientSide()) return InteractionResult.SUCCESS;
return super.use(state, level, pos, player, hand, ray);
}
/**
* So this method gets overriden in {@link BasicTileBlock#newBlockEntity(BlockPos, BlockState)}
* Which defaults to a new method called {@link BasicTileBlock#getTileEntityFactory()}
* This method is what gets overriden on new blocks and where we provide the BlockEntity creation!
*
* @param pos The position of the block where the BlockEntity is created.
* @param state The state of the block which is creating the BlockEntity.
* @return Returns the new BlockEntity instance.
*/
@Nullable
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
return super.newBlockEntity(pos, state);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment