Merge remote-tracking branch 'upstream/master' into renewableSponges
This commit is contained in:
commit
9e5981a3b9
12 files changed
+702
-2
No files matched your search
@@ -113,8 +113,13 @@ public class CarpetSettings
|
||||
"Counters are global and shared between players, 16 channels available",
|
||||
"Items counted are destroyed, count up to one stack per tick per hopper")
|
||||
.isACommand().boolAccelerate().defaultFalse(),
|
||||
<<<<<<< HEAD
|
||||
rule("renewableSponges", "experimental feature", "Guardians turn into Elder Guardian when struck by lightning"),
|
||||
rule("movableTileEntities", "experimental", "Pistons can push tile entities, like hoppers, chests etc.").boolAccelerate().wip(),
|
||||
=======
|
||||
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(),
|
||||
>>>>>>> master
|
||||
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("carriedTileEntityCM", 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("carriedTileEntityCM"));
|
||||
}
|
||||
}
|
||||
|
||||
@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 "carriedTileEntityCM" instead of "carriedBlockEntityCM" for upgrade compatibility with 1.13.2 movable TE
|
||||
compoundTag_1.put("carriedTileEntityCM", 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 false;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -73,13 +73,21 @@
|
||||
"EndCityFeatureMixin",
|
||||
|
||||
"InfestedBlockMixin",
|
||||
"PlayerEntityMixin"
|
||||
"PlayerEntityMixin",
|
||||
|
||||
"PistonBlock_movableTEMixin",
|
||||
"PistonBlockEntity_movableTEMixin",
|
||||
"World_movableTEMixin",
|
||||
"WorldChunk_movableTEMixin"
|
||||
],
|
||||
"client": [
|
||||
"MinecraftClientMixin",
|
||||
"IntegratedServerMixin",
|
||||
"InGameHudMixin",
|
||||
"PlayerListHudMixin"
|
||||
"PlayerListHudMixin",
|
||||
|
||||
"BlockEntityRenderDispatcher_movableTEMixin",
|
||||
"PistonBlockEntityRenderer_movableTEMixin"
|
||||
],
|
||||
"server": [
|
||||
"MinecraftDedicatedServerMixin"
|
||||
|
||||
Reference in new issue
Block a user