added movableTE's with help from @2No2Name

This commit is contained in:
DeadlyMC committed 2019-06-05 10:02:22 +05:30
1 parent 78eafdcedd
commit e409ae4108
12 files changed
+698 -3

No files matched your search

+1 -1
View File
@@ -114,7 +114,7 @@ public class CarpetSettings
"Items counted are destroyed, count up to one stack per tick per hopper")
.isACommand().boolAccelerate().defaultFalse(),
rule("renewableSponges", "experimental feature", "Guardians turn into Elder Guardian when struck by lightning").wip(),
rule("movableTileEntities", "experimental", "Pistons can push tile entities, like hoppers, chests etc.").boolAccelerate().wip(),
rule("movableTileEntities", "experimental", "Pistons can push tile entities, like hoppers, chests etc.").boolAccelerate(),
rule("desertShrubs", "feature", "Saplings turn into dead shrubs in hot climates and no water access when it attempts to grow into a tree").wip(),
rule("silverFishDropGravel", "experimental", "Silverfish drop a gravel item when breaking out of a block"),
rule("summonNaturalLightning","creative", "summoning a lightning bolt has all the side effects of natural lightning"),
@@ -0,0 +1,8 @@
package carpet.fakes;
import net.minecraft.block.entity.BlockEntity;
public interface BlockEntityRenderDispatcherInterface
{
void renderBlockEntityOffset(BlockEntity blockEntity, float partialTicks, int destroyStage, double xOffset, double yOffset, double zOffset);
}
@@ -0,0 +1,12 @@
package carpet.fakes;
import net.minecraft.block.entity.BlockEntity;
public interface PistonBlockEntityInterface
{
void setCarriedBlockEntity(BlockEntity blockEntity);
BlockEntity getCarriedBlockEntity();
void setRenderCarriedBlockEntity(boolean b);
boolean getRenderCarriedBlockEntity();
boolean isRenderModeSet();
}
@@ -0,0 +1,10 @@
package carpet.fakes;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.util.math.BlockPos;
public interface WorldChunkInterface
{
BlockState setBlockStateWithBlockEntity(BlockPos blockPos, BlockState newBlockState, BlockEntity newBlockEntity, boolean boolean1);
}
@@ -1,11 +1,16 @@
package carpet.fakes;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.util.math.BlockPos;
import java.util.Map;
public interface WorldInterface
{
Map<EntityType, Entity> getPrecookedMobs();
boolean setBlockStateWithBlockEntity(BlockPos blockPos, BlockState blockState, BlockEntity newBlockEntity, int int1);
}
@@ -0,0 +1,53 @@
package carpet.mixins;
import carpet.fakes.BlockEntityRenderDispatcherInterface;
import com.mojang.blaze3d.platform.GLX;
import com.mojang.blaze3d.platform.GlStateManager;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.client.render.Camera;
import net.minecraft.client.render.GuiLighting;
import net.minecraft.client.render.block.entity.BlockEntityRenderDispatcher;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@Mixin(BlockEntityRenderDispatcher.class)
public abstract class BlockEntityRenderDispatcher_movableTEMixin implements BlockEntityRenderDispatcherInterface
{
@Shadow
public static double renderOffsetX;
@Shadow
public static double renderOffsetY;
@Shadow
public static double renderOffsetZ;
@Shadow
public Camera cameraEntity;
@Shadow
public World world;
@Shadow
public abstract void renderEntity(BlockEntity blockEntity_1, double double_1, double double_2, double double_3,
float float_1, int int_1, boolean boolean_1);
/**
* @author 2No2Name
*/
//Renders the BlockEntity offset by the amount specified in the arguments xOffset yOffset zOffset (the moving block moved in the animation by this)
public void renderBlockEntityOffset(BlockEntity blockEntity_1, float partialTicks, int destroyStage, double xOffset,
double yOffset, double zOffset)
{
if (blockEntity_1.getSquaredDistance(this.cameraEntity.getPos().x - xOffset, this.cameraEntity.getPos().y - yOffset,
this.cameraEntity.getPos().z - zOffset) < blockEntity_1.getSquaredRenderDistance())
{
GuiLighting.enable();
int i = this.world.getLightmapIndex(blockEntity_1.getPos(), 0);
int j = i % 65536;
int k = i / 65536;
GLX.glMultiTexCoord2f(GLX.GL_TEXTURE1, (float) j, (float) k);
GlStateManager.color4f(1.0F, 1.0F, 1.0F, 1.0F);
BlockPos blockpos = blockEntity_1.getPos();
this.renderEntity(blockEntity_1, (double) blockpos.getX() - renderOffsetX + xOffset, (double) blockpos.getY() - renderOffsetY + yOffset, (double) blockpos.getZ() - renderOffsetZ + zOffset, partialTicks, destroyStage, false);
}
}
}
@@ -0,0 +1,42 @@
package carpet.mixins;
import carpet.CarpetSettings;
import carpet.fakes.BlockEntityRenderDispatcherInterface;
import carpet.fakes.PistonBlockEntityInterface;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.PistonBlockEntity;
import net.minecraft.client.render.block.entity.BlockEntityRenderDispatcher;
import net.minecraft.client.render.block.entity.BlockEntityRenderer;
import net.minecraft.client.render.block.entity.PistonBlockEntityRenderer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(PistonBlockEntityRenderer.class)
public abstract class PistonBlockEntityRenderer_movableTEMixin extends BlockEntityRenderer<PistonBlockEntity>
{
@Inject(method = "method_3576", at = @At(value = "INVOKE",
target = "Lnet/minecraft/client/render/block/entity/PistonBlockEntityRenderer;method_3575(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;Lnet/minecraft/client/render/BufferBuilder;Lnet/minecraft/world/World;Z)Z", ordinal = 3))
private void updateRenderBool(PistonBlockEntity pistonBlockEntity_1, double double_1, double double_2,
double double_3, float float_1, int int_1, CallbackInfo ci)
{
if (!((PistonBlockEntityInterface) pistonBlockEntity_1).isRenderModeSet())
((PistonBlockEntityInterface) pistonBlockEntity_1).setRenderCarriedBlockEntity(CarpetSettings.b_movableTileEntities && ((PistonBlockEntityInterface) pistonBlockEntity_1).getCarriedBlockEntity() != null);
}
@Inject(method = "method_3576", at = @At("RETURN"))
private void endMethod3576(PistonBlockEntity pistonBlockEntity_1, double double_1, double double_2, double double_3,
float float_1, int int_1, CallbackInfo ci)
{
if (((PistonBlockEntityInterface) pistonBlockEntity_1).getRenderCarriedBlockEntity())
{
BlockEntity carriedBlockEntity = ((PistonBlockEntityInterface) pistonBlockEntity_1).getCarriedBlockEntity();
if (carriedBlockEntity != null)
{
carriedBlockEntity.setPos(pistonBlockEntity_1.getPos());
((BlockEntityRenderDispatcherInterface) BlockEntityRenderDispatcher.INSTANCE).renderBlockEntityOffset(carriedBlockEntity, float_1, int_1, pistonBlockEntity_1.getRenderOffsetX(float_1), pistonBlockEntity_1.getRenderOffsetY(float_1), pistonBlockEntity_1.getRenderOffsetZ(float_1));
}
}
}
}
@@ -0,0 +1,139 @@
package carpet.mixins;
import carpet.CarpetSettings;
import carpet.fakes.PistonBlockEntityInterface;
import carpet.fakes.WorldInterface;
import net.minecraft.block.Block;
import net.minecraft.block.BlockEntityProvider;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.block.entity.PistonBlockEntity;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(PistonBlockEntity.class)
public abstract class PistonBlockEntity_movableTEMixin extends BlockEntity implements PistonBlockEntityInterface
{
@Shadow
private boolean source;
@Shadow
private BlockState pushedBlock;
private BlockEntity carriedBlockEntity;
private boolean renderCarriedBlockEntity = false;
private boolean renderSet = false;
public PistonBlockEntity_movableTEMixin(BlockEntityType<?> blockEntityType_1)
{
super(blockEntityType_1);
}
/**
* @author 2No2Name
*/
public BlockEntity getCarriedBlockEntity()
{
return carriedBlockEntity;
}
public void setCarriedBlockEntity(BlockEntity blockEntity)
{
this.carriedBlockEntity = blockEntity;
if (this.carriedBlockEntity != null)
this.carriedBlockEntity.setPos(this.pos);
}
public boolean isRenderModeSet()
{
return renderSet;
}
public boolean getRenderCarriedBlockEntity()
{
return renderCarriedBlockEntity;
}
public void setRenderCarriedBlockEntity(boolean b)
{
renderCarriedBlockEntity = b;
renderSet = true;
}
/**
* @author 2No2Name
*/
@Redirect(method = "tick", at = @At(value = "INVOKE",
target = "Lnet/minecraft/world/World;setBlockState(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;I)Z"))
private boolean movableTEsetBlockState0(World world, BlockPos blockPos_1, BlockState blockAState_2, int int_1)
{
if (!CarpetSettings.b_movableTileEntities)
return world.setBlockState(blockPos_1, blockAState_2, int_1);
else
return ((WorldInterface) (world)).setBlockStateWithBlockEntity(blockPos_1, blockAState_2, this.carriedBlockEntity, int_1);
}
@Redirect(method = "finish", at = @At(value = "INVOKE",
target = "Lnet/minecraft/world/World;setBlockState(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;I)Z"))
private boolean movableTEsetBlockState1(World world, BlockPos blockPos_1, BlockState blockState_2, int int_1)
{
if (!CarpetSettings.b_movableTileEntities)
return world.setBlockState(blockPos_1, blockState_2, int_1);
else
{
boolean ret = ((WorldInterface) (world)).setBlockStateWithBlockEntity(blockPos_1, blockState_2, this.carriedBlockEntity, int_1);
this.carriedBlockEntity = null; //this will cancel the finishHandleBroken
return ret;
}
}
@Inject(method = "finish", at = @At(value = "RETURN"))
private void finishHandleBroken(CallbackInfo cir)
{
//Handle TNT Explosions or other ways the moving Block is broken
//Also /setblock will cause this to be called, and drop e.g. a moving chest's contents.
// This is MC-40380 (BlockEntities that aren't Inventories drop stuff when setblock is called )
if (CarpetSettings.b_movableTileEntities && this.carriedBlockEntity != null && !this.world.isClient && this.world.getBlockState(this.pos).getBlock() == Blocks.AIR)
{
BlockState blockState_2;
if (this.source)
blockState_2 = Blocks.AIR.getDefaultState();
else
blockState_2 = Block.getRenderingState(this.pushedBlock, this.world, this.pos);
((WorldInterface) (this.world)).setBlockStateWithBlockEntity(this.pos, blockState_2, this.carriedBlockEntity, 3);
this.world.breakBlock(this.pos, true);
}
}
@Inject(method = "fromTag", at = @At(value = "TAIL"))
private void onFromTag(CompoundTag compoundTag_1, CallbackInfo ci)
{
if (CarpetSettings.b_movableTileEntities && compoundTag_1.containsKey("carriedTileEntity", 10))
{
if (this.pushedBlock.getBlock() instanceof BlockEntityProvider)
this.carriedBlockEntity = ((BlockEntityProvider) (this.pushedBlock.getBlock())).createBlockEntity(this.world);
if (carriedBlockEntity != null) //Can actually be null, as BlockPistonMoving.createNewTileEntity(...) returns null
this.carriedBlockEntity.fromTag(compoundTag_1.getCompound("carriedTileEntity"));
}
}
@Inject(method = "toTag", at = @At(value = "RETURN", shift = At.Shift.BEFORE))
private void onToTag(CompoundTag compoundTag_1, CallbackInfoReturnable<CompoundTag> cir)
{
if (CarpetSettings.b_movableTileEntities && this.carriedBlockEntity != null)
{
//Leave name "carriedTileEntity" instead of "carriedBlockEntity" for upgrade compatibility with 1.12 movable TE
compoundTag_1.put("carriedTileEntity", this.carriedBlockEntity.toTag(new CompoundTag()));
}
}
}
@@ -0,0 +1,123 @@
package carpet.mixins;
import carpet.CarpetSettings;
import carpet.fakes.PistonBlockEntityInterface;
import com.google.common.collect.Lists;
import net.minecraft.block.*;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.piston.PistonHandler;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
import java.util.List;
import java.util.Set;
@Mixin(PistonBlock.class)
public abstract class PistonBlock_movableTEMixin extends FacingBlock
{
protected PistonBlock_movableTEMixin(Settings block$Settings_1)
{
super(block$Settings_1);
}
private ThreadLocal<List<BlockEntity>> list1_BlockEntities = new ThreadLocal<>(); //Unneccessary ThreadLocal if client and server use different PistonBlock instances
@Inject(method = "isMovable", at = @At(value = "RETURN", ordinal = 3, shift = At.Shift.BEFORE))
private static void movableCMD(BlockState blockState_1, World world_1, BlockPos blockPos_1,
Direction direction_1, boolean boolean_1, Direction direction_2, CallbackInfoReturnable<Boolean> cir)
{
Block block_1 = blockState_1.getBlock();
//Make CommandBlocks movable, either use instanceof CommandBlock or the 3 cmd block objects,
if (CarpetSettings.b_movableTileEntities && block_1 instanceof CommandBlock)
{
cir.setReturnValue(true);
}
}
private static boolean isPushableTileEntityBlock(Block block)
{
//Making PISTON_EXTENSION (BlockPistonMoving) pushable would not work as its createNewTileEntity()-method returns null
return block != Blocks.ENDER_CHEST && block != Blocks.ENCHANTING_TABLE &&
block != Blocks.END_GATEWAY && block != Blocks.END_PORTAL && block != Blocks.MOVING_PISTON &&
block != Blocks.SPAWNER;
}
@Redirect(method = "isMovable", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/Block;hasBlockEntity()Z"))
private static boolean ifHasBlockEntity(Block block)
{
if (!block.hasBlockEntity())
{
return !true;
}
else
{
return !(CarpetSettings.b_movableTileEntities && isPushableTileEntityBlock(block));
}
}
@Inject(method = "move", at = @At(value = "INVOKE", shift = At.Shift.BEFORE,
target = "Ljava/util/List;size()I", ordinal = 4),locals = LocalCapture.CAPTURE_FAILHARD)
private void onMove(World world_1, BlockPos blockPos_1, Direction direction_1, boolean boolean_1,
CallbackInfoReturnable<Boolean> cir, BlockPos blockPos_2, PistonHandler pistonHandler_1,
List<BlockPos> list_1, List<BlockState> list_2, List list_3, int int_2, BlockState blockStates_1[],
Direction direction_2, Set set_1)
{
//Get the blockEntities and remove them from the world before any magic starts to happen
if (CarpetSettings.b_movableTileEntities)
{
list1_BlockEntities.set(Lists.<BlockEntity>newArrayList());
for (int i = 0; i < list_1.size(); ++i)
{
BlockPos blockpos = list_1.get(i);
BlockEntity blockEntity = (list_2.get(i).getBlock().hasBlockEntity()) ? world_1.getBlockEntity(blockpos) : null;
list1_BlockEntities.get().add(blockEntity);
if (blockEntity != null)
{
//hopefully this call won't have any side effects in the future, such as dropping all the BlockEntity's items
//we want to place this same(!) BlockEntity object into the world later when the movement stops again
world_1.removeBlockEntity(blockpos);
blockEntity.markDirty();
}
}
}
}
@Inject(method = "move", at = @At(value = "INVOKE", shift = At.Shift.BEFORE,
target = "Lnet/minecraft/world/World;setBlockEntity(Lnet/minecraft/util/math/BlockPos;" +
"Lnet/minecraft/block/entity/BlockEntity;)V", ordinal = 0),
locals = LocalCapture.CAPTURE_FAILHARD)
private void setBlockEntityWithCarried(World world_1, BlockPos blockPos_1, Direction direction_1, boolean boolean_1,
CallbackInfoReturnable<Boolean> cir, BlockPos blockPos_2, PistonHandler pistonHandler_1, List list_1,
List list_2, List list_3, int int_2, BlockState blockStates_1[], Direction direction_2, Set set_1,
int int_3, BlockPos blockPos_4, BlockState blockState_1)
{
BlockEntity blockEntityPiston = PistonExtensionBlock.createBlockEntityPiston((BlockState) list_2.get(int_3),
direction_1, boolean_1, false);
if (CarpetSettings.b_movableTileEntities)
((PistonBlockEntityInterface) blockEntityPiston).setCarriedBlockEntity(list1_BlockEntities.get().get(int_3));
world_1.setBlockEntity(blockPos_4, blockEntityPiston);
}
@Redirect(method = "move", at = @At(value = "INVOKE",
target = "Lnet/minecraft/world/World;setBlockEntity(Lnet/minecraft/util/math/BlockPos;" +
"Lnet/minecraft/block/entity/BlockEntity;)V",
ordinal = 0))
private void dontDoAnything(World world, BlockPos blockPos_6, BlockEntity blockEntityPiston)
{
}
@Redirect(method = "move", at = @At(value = "INVOKE",
target = "Lnet/minecraft/block/PistonExtensionBlock;createBlockEntityPiston(Lnet/minecraft/block/BlockState;" +
"Lnet/minecraft/util/math/Direction;ZZ)Lnet/minecraft/block/entity/BlockEntity;",
ordinal = 0))
private BlockEntity returnNull(BlockState blockState_1, Direction direction_1, boolean boolean_1, boolean boolean_2)
{
return null;
}
}
@@ -0,0 +1,158 @@
package carpet.mixins;
import carpet.CarpetSettings;
import carpet.fakes.WorldChunkInterface;
import com.sun.istack.internal.Nullable;
import net.minecraft.block.Block;
import net.minecraft.block.BlockEntityProvider;
import net.minecraft.block.BlockState;
import net.minecraft.block.PistonExtensionBlock;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.Heightmap;
import net.minecraft.world.World;
import net.minecraft.world.chunk.ChunkSection;
import net.minecraft.world.chunk.WorldChunk;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import java.util.Map;
import static net.minecraft.world.chunk.WorldChunk.EMPTY_SECTION;
@Mixin(WorldChunk.class)
public abstract class WorldChunk_movableTEMixin implements WorldChunkInterface
{
@Shadow
@Final
private ChunkSection[] sections;
@Shadow
@Final
private Map<Heightmap.Type, Heightmap> heightmaps;
@Shadow
private boolean shouldSave;
@Shadow
@Final
private World world;
@Shadow
@Nullable
public abstract BlockEntity getBlockEntity(BlockPos blockPos_1, WorldChunk.CreationType worldChunk$CreationType_1);
// Fix Failure: If a moving BlockEntity is placed while BlockEntities are ticking, this will not find it and then replace it with a new TileEntity!
// blockEntity_2 = this.getBlockEntity(blockPos_1, WorldChunk.CreationType.CHECK);
@Redirect(method = "setBlockState", at = @At(value = "INVOKE", ordinal = 1,
target = "Lnet/minecraft/world/chunk/WorldChunk;getBlockEntity(Lnet/minecraft/util/math/BlockPos;" + "Lnet/minecraft/world/chunk/WorldChunk$CreationType;)" + "Lnet/minecraft/block/entity/BlockEntity;"))
private BlockEntity ifGetBlockEntity(WorldChunk worldChunk, BlockPos blockPos_1,
WorldChunk.CreationType worldChunk$CreationType_1)
{
if (!CarpetSettings.b_movableTileEntities)
{
return this.getBlockEntity(blockPos_1, WorldChunk.CreationType.CHECK);
}
else
{
return this.world.getBlockEntity(blockPos_1);
}
}
/**
* Sets the Blockstate and the BlockEntity.
* Only sets BlockEntity if Block is BlockEntityProvider, but doesn't check if it actually matches (e.g. can assign beacon to chest entity).
*
* @author 2No2Name
*/
@Nullable
public BlockState setBlockStateWithBlockEntity(BlockPos blockPos_1, BlockState newBlockState, BlockEntity newBlockEntity,
boolean boolean_1)
{
int x = blockPos_1.getX() & 15;
int y = blockPos_1.getY();
int z = blockPos_1.getZ() & 15;
ChunkSection chunkSection = this.sections[y >> 4];
if (chunkSection == EMPTY_SECTION)
{
if (newBlockState.isAir())
{
return null;
}
chunkSection = new ChunkSection(y >> 4 << 4);
this.sections[y >> 4] = chunkSection;
}
boolean boolean_2 = chunkSection.isEmpty();
BlockState oldBlockState = chunkSection.setBlockState(x, y & 15, z, newBlockState);
if (oldBlockState == newBlockState)
{
return null;
}
else
{
Block newBlock = newBlockState.getBlock();
Block oldBlock = oldBlockState.getBlock();
((Heightmap) this.heightmaps.get(Heightmap.Type.MOTION_BLOCKING)).trackUpdate(x, y, z, newBlockState);
((Heightmap) this.heightmaps.get(Heightmap.Type.MOTION_BLOCKING_NO_LEAVES)).trackUpdate(x, y, z, newBlockState);
((Heightmap) this.heightmaps.get(Heightmap.Type.OCEAN_FLOOR)).trackUpdate(x, y, z, newBlockState);
((Heightmap) this.heightmaps.get(Heightmap.Type.WORLD_SURFACE)).trackUpdate(x, y, z, newBlockState);
boolean boolean_3 = chunkSection.isEmpty();
if (boolean_2 != boolean_3)
{
this.world.getChunkManager().getLightingProvider().updateSectionStatus(blockPos_1, boolean_3);
}
if (!this.world.isClient)
{
if (!(oldBlock instanceof PistonExtensionBlock))//this is a movableTE special case, if condition wasn't there it would remove the blockentity that was carried for some reason
oldBlockState.onBlockRemoved(this.world, blockPos_1, newBlockState, boolean_1);//this kills it
}
else if (oldBlock != newBlock && oldBlock instanceof BlockEntityProvider)
{
this.world.removeBlockEntity(blockPos_1);
}
if (chunkSection.getBlockState(x, y & 15, z).getBlock() != newBlock)
{
return null;
}
else
{
BlockEntity oldBlockEntity = null;
if (oldBlock instanceof BlockEntityProvider)
{
oldBlockEntity = this.getBlockEntity(blockPos_1, WorldChunk.CreationType.CHECK);
if (oldBlockEntity != null)
{
oldBlockEntity.resetBlock();
}
}
if (newBlock instanceof BlockEntityProvider)
{
if (newBlockEntity == null)
{
newBlockEntity = ((BlockEntityProvider) newBlock).createBlockEntity(this.world);
}
if (newBlockEntity != oldBlockEntity && newBlockEntity != null)
{
newBlockEntity.validate();
this.world.setBlockEntity(blockPos_1, newBlockEntity);
newBlockEntity.resetBlock();
}
}
if (!this.world.isClient)
{
newBlockState.onBlockAdded(this.world, blockPos_1, oldBlockState, boolean_1); //This can call setblockstate! (e.g. hopper does)
}
this.shouldSave = true;
return oldBlockState;
}
}
}
}
@@ -0,0 +1,137 @@
package carpet.mixins;
import carpet.fakes.WorldChunkInterface;
import carpet.fakes.WorldInterface;
import net.minecraft.block.Block;
import net.minecraft.block.BlockEntityProvider;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.server.world.ChunkHolder;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.profiler.Profiler;
import net.minecraft.world.BlockView;
import net.minecraft.world.World;
import net.minecraft.world.chunk.ChunkManager;
import net.minecraft.world.chunk.EmptyChunk;
import net.minecraft.world.chunk.WorldChunk;
import net.minecraft.world.level.LevelGeneratorType;
import net.minecraft.world.level.LevelProperties;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@Mixin(World.class)
public abstract class World_movableTEMixin implements WorldInterface
{
@Shadow
@Final
public boolean isClient;
@Shadow
@Final
protected LevelProperties properties;
@Shadow
@Final
private Profiler profiler;
@Shadow
protected abstract WorldChunk getWorldChunk(BlockPos blockPos_1);
@Shadow
public abstract BlockState getBlockState(BlockPos blockPos_1);
@Shadow
public abstract ChunkManager getChunkManager();
@Shadow
public abstract void scheduleBlockRender(BlockPos blockPos_1);
@Shadow
public abstract void updateListeners(BlockPos var1, BlockState var2, BlockState var3, int var4);
@Shadow
public abstract void updateNeighbors(BlockPos blockPos_1, Block block_1);
@Shadow
public abstract void updateHorizontalAdjacent(BlockPos blockPos_1, Block block_1);
@Shadow
public abstract void onBlockChanged(BlockPos blockPos_1, BlockState blockState_1, BlockState blockState_2);
/**
* @author 2No2Name
*/
public boolean setBlockStateWithBlockEntity(BlockPos blockPos_1, BlockState blockState_1, BlockEntity newBlockEntity, int int_1)
{
if ((Object) this instanceof EmptyChunk)
return false;
if (World.isHeightInvalid(blockPos_1))
{
return false;
}
else if (!this.isClient && this.properties.getGeneratorType() == LevelGeneratorType.DEBUG_ALL_BLOCK_STATES)
{
return false;
}
else
{
WorldChunk worldChunk_1 = this.getWorldChunk(blockPos_1);
Block block_1 = blockState_1.getBlock();
BlockState blockState_2;
if (newBlockEntity != null && block_1 instanceof BlockEntityProvider)
blockState_2 = ((WorldChunkInterface) worldChunk_1).setBlockStateWithBlockEntity(blockPos_1, blockState_1, newBlockEntity, (int_1 & 64) != 0);
else
blockState_2 = worldChunk_1.setBlockState(blockPos_1, blockState_1, (int_1 & 64) != 0);
if (blockState_2 == null)
{
return false;
}
else
{
BlockState blockState_3 = this.getBlockState(blockPos_1);
if (blockState_3 != blockState_2 && (blockState_3.getLightSubtracted((BlockView) this, blockPos_1) != blockState_2.getLightSubtracted((BlockView) this, blockPos_1) || blockState_3.getLuminance() != blockState_2.getLuminance() || blockState_3.hasSidedTransparency() || blockState_2.hasSidedTransparency()))
{
this.profiler.push("queueCheckLight");
this.getChunkManager().getLightingProvider().enqueueLightUpdate(blockPos_1);
this.profiler.pop();
}
if (blockState_3 == blockState_1)
{
if (blockState_2 != blockState_3)
{
this.scheduleBlockRender(blockPos_1);
}
if ((int_1 & 2) != 0 && (!this.isClient || (int_1 & 4) == 0) && (this.isClient || worldChunk_1.getLevelType() != null && worldChunk_1.getLevelType().isAfter(ChunkHolder.LevelType.TICKING)))
{
this.updateListeners(blockPos_1, blockState_2, blockState_1, int_1);
}
if (!this.isClient && (int_1 & 1) != 0)
{
this.updateNeighbors(blockPos_1, blockState_2.getBlock());
if (blockState_1.hasComparatorOutput())
{
this.updateHorizontalAdjacent(blockPos_1, block_1);
}
}
if ((int_1 & 16) == 0)
{
int int_2 = int_1 & -2;
blockState_2.method_11637((net.minecraft.world.IWorld) this, blockPos_1, int_2);
blockState_1.updateNeighborStates((net.minecraft.world.IWorld) this, blockPos_1, int_2);
blockState_1.method_11637((net.minecraft.world.IWorld) this, blockPos_1, int_2);
}
this.onBlockChanged(blockPos_1, blockState_2, blockState_3);
}
return true;
}
}
}
}