Merge pull request #1613 from reidbhuntley/schematics-crash

Various bugfixes regarding schematics
This commit is contained in:
simibubi 2021-05-22 17:50:45 +02:00 committed by GitHub
commit aea44aa3fb
Failed to generate hash of commit
19 changed files with 323 additions and 95 deletions

View file

@ -409,19 +409,19 @@ a3a11524cd3515fc01d905767b4b7ea782adaf03 assets/create/blockstates/yellow_seat.j
b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json
a6d814f94926d88764c38862cc4ece9c367e023b assets/create/lang/en_ud.json a6d814f94926d88764c38862cc4ece9c367e023b assets/create/lang/en_ud.json
d1838140c8383ee4537db90eb8f657d0c268fe91 assets/create/lang/en_us.json d1838140c8383ee4537db90eb8f657d0c268fe91 assets/create/lang/en_us.json
9d6f26ca7b59d3707ce996e513358cc9b873cad1 assets/create/lang/unfinished/de_de.json 4fcda300efe5a2ad8695b5ae3f24a54ea109a954 assets/create/lang/unfinished/de_de.json
7fafb7565349aa52f4ccb829d4886a179eb547dc assets/create/lang/unfinished/es_es.json 6a1dde57b2224d4b0287ebc705d6a75d329b5e1f assets/create/lang/unfinished/es_es.json
822b912d290d40c5f02011393af44bf37684f9b4 assets/create/lang/unfinished/es_mx.json 93ee0e30a56b405a9e766d353c36276e36a84b5c assets/create/lang/unfinished/es_mx.json
502d761465a0de7aeb15acec4147b8ec8bee92cf assets/create/lang/unfinished/fr_fr.json 49a691320c73e09f921cd0ea97398126231e99fa assets/create/lang/unfinished/fr_fr.json
dac15c17578fb37bbdb874cee5a0a078110b7481 assets/create/lang/unfinished/it_it.json cf14b3828b6c11013f606f277d88fb63245bb2a8 assets/create/lang/unfinished/it_it.json
fd270c9c8bc46d4df21aa04ecc7bf059011e4b3e assets/create/lang/unfinished/ja_jp.json 73c1c1489833cbcb28bb1ce90541c8c8bdf329c0 assets/create/lang/unfinished/ja_jp.json
a5b002e047a2f509a8d35b9e638627f970b4810e assets/create/lang/unfinished/ko_kr.json 924303b9bcf56aedbbfc46108655f71324308e12 assets/create/lang/unfinished/ko_kr.json
50f65aaba8c4fec5404ab1fc40f74b4970a55edd assets/create/lang/unfinished/nl_nl.json 079aea6843e756efbfca0976983be1957863717c assets/create/lang/unfinished/nl_nl.json
ff61e567f15ded6ba127522af03860232069cdd2 assets/create/lang/unfinished/pl_pl.json b7bab15167400ee48a9728f81446e572c494fd8d assets/create/lang/unfinished/pl_pl.json
a7a28fb3896bc38e00f746e650433160f5b53c90 assets/create/lang/unfinished/pt_br.json 07e84cc3eee3faa1ab3d26e0c85c7f09c8573368 assets/create/lang/unfinished/pt_br.json
ffa1901b392719634403048419d29b268704bd10 assets/create/lang/unfinished/ru_ru.json 6ffb0cf20d712aee23a42a9ec440dd7dc92293d6 assets/create/lang/unfinished/ru_ru.json
38b843c5232167876b3678328b47ec95f30cf69f assets/create/lang/unfinished/zh_cn.json 0ae98a18e59f478da41d8c5d832737b65f6a8c8a assets/create/lang/unfinished/zh_cn.json
b806d1e6fe9ebee27f417a3c4d6c818124ee4cde assets/create/lang/unfinished/zh_tw.json 4c96e5a76e72368a59190b7588d389fdd2cc75e1 assets/create/lang/unfinished/zh_tw.json
487a511a01b2a4531fb672f917922312db78f958 assets/create/models/block/acacia_window.json 487a511a01b2a4531fb672f917922312db78f958 assets/create/models/block/acacia_window.json
b48060cba1a382f373a05bf0039054053eccf076 assets/create/models/block/acacia_window_pane_noside.json b48060cba1a382f373a05bf0039054053eccf076 assets/create/models/block/acacia_window_pane_noside.json
3066db1bf03cffa1a9c7fbacf47ae586632f4eb3 assets/create/models/block/acacia_window_pane_noside_alt.json 3066db1bf03cffa1a9c7fbacf47ae586632f4eb3 assets/create/models/block/acacia_window_pane_noside_alt.json
@ -2726,7 +2726,7 @@ cecaac07bd275bb1ae9e302f0bf44b581e74105d data/create/loot_tables/blocks/rope_pul
aa6af37356d65105efab2503ffe75f778cfe873b data/create/loot_tables/blocks/rotation_speed_controller.json aa6af37356d65105efab2503ffe75f778cfe873b data/create/loot_tables/blocks/rotation_speed_controller.json
30de11bec82606fead9d6bff7bba0232e97f1039 data/create/loot_tables/blocks/sail_frame.json 30de11bec82606fead9d6bff7bba0232e97f1039 data/create/loot_tables/blocks/sail_frame.json
069701cb804b6522c18624a0d4f3f949ff8b0281 data/create/loot_tables/blocks/schematic_table.json 069701cb804b6522c18624a0d4f3f949ff8b0281 data/create/loot_tables/blocks/schematic_table.json
c4a89145334addfd0dd1fedf7fa75ba07a7d3490 data/create/loot_tables/blocks/schematicannon.json a2b172dc749176d4df34729007019605fc6dd150 data/create/loot_tables/blocks/schematicannon.json
af1bbbb8236b4ab05a6a8edc6db960bc758cbdf3 data/create/loot_tables/blocks/scoria.json af1bbbb8236b4ab05a6a8edc6db960bc758cbdf3 data/create/loot_tables/blocks/scoria.json
bb670ac5dd2fa4c743bc268cd0547926eb6cdb68 data/create/loot_tables/blocks/scoria_bricks.json bb670ac5dd2fa4c743bc268cd0547926eb6cdb68 data/create/loot_tables/blocks/scoria_bricks.json
a7217ea301a282d0ef52f2d8c06dd8683398408d data/create/loot_tables/blocks/scoria_bricks_slab.json a7217ea301a282d0ef52f2d8c06dd8683398408d data/create/loot_tables/blocks/scoria_bricks_slab.json

View file

@ -6,6 +6,19 @@
"entries": [ "entries": [
{ {
"type": "minecraft:item", "type": "minecraft:item",
"functions": [
{
"function": "minecraft:copy_nbt",
"source": "block_entity",
"ops": [
{
"source": "Options",
"target": "BlockEntityTag.Options",
"op": "replace"
}
]
}
],
"name": "create:schematicannon" "name": "create:schematicannon"
} }
], ],

View file

@ -215,6 +215,16 @@ public class AllBlocks {
REGISTRATE.block("schematicannon", SchematicannonBlock::new) REGISTRATE.block("schematicannon", SchematicannonBlock::new)
.initialProperties(() -> Blocks.DISPENSER) .initialProperties(() -> Blocks.DISPENSER)
.blockstate((ctx, prov) -> prov.simpleBlock(ctx.getEntry(), AssetLookup.partialBaseModel(ctx, prov))) .blockstate((ctx, prov) -> prov.simpleBlock(ctx.getEntry(), AssetLookup.partialBaseModel(ctx, prov)))
.loot((lt, block) -> {
Builder builder = LootTable.builder();
IBuilder survivesExplosion = SurvivesExplosion.builder();
lt.registerLootTable(block, builder.addLootPool(LootPool.builder()
.acceptCondition(survivesExplosion)
.rolls(ConstantRange.of(1))
.addEntry(ItemLootEntry.builder(AllBlocks.SCHEMATICANNON.get().asItem())
.acceptFunction(CopyNbt.func_215881_a(CopyNbt.Source.BLOCK_ENTITY)
.func_216056_a("Options", "BlockEntityTag.Options")))));
})
.item() .item()
.transform(customItemModel()) .transform(customItemModel())
.register(); .register();

View file

@ -54,6 +54,7 @@ import net.minecraft.util.ActionResultType;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis; import net.minecraft.util.Direction.Axis;
import net.minecraft.util.Hand; import net.minecraft.util.Hand;
import net.minecraft.util.Mirror;
import net.minecraft.util.Rotation; import net.minecraft.util.Rotation;
import net.minecraft.util.SoundCategory; import net.minecraft.util.SoundCategory;
import net.minecraft.util.SoundEvents; import net.minecraft.util.SoundEvents;
@ -492,29 +493,55 @@ public class CartAssemblerBlock extends AbstractRailBlock
public boolean allowsMovement(BlockState state, IBlockReader reader, BlockPos pos, PathType type) { public boolean allowsMovement(BlockState state, IBlockReader reader, BlockPos pos, PathType type) {
return false; return false;
} }
@Override @Override
public ActionResultType onWrenched(BlockState state, ItemUseContext context) { public ActionResultType onWrenched(BlockState state, ItemUseContext context) {
World world = context.getWorld(); World world = context.getWorld();
if (world.isRemote) if (world.isRemote)
return ActionResultType.SUCCESS; return ActionResultType.SUCCESS;
BlockPos pos = context.getPos(); BlockPos pos = context.getPos();
BlockState newState = state.with(RAIL_SHAPE, world.setBlockState(pos, rotate(state, Rotation.CLOCKWISE_90), 3);
state.get(RAIL_SHAPE) == RailShape.NORTH_SOUTH ? RailShape.EAST_WEST : RailShape.NORTH_SOUTH);
if (state.get(RAIL_TYPE) == CartAssembleRailType.CONTROLLER_RAIL
|| state.get(RAIL_TYPE) == CartAssembleRailType.CONTROLLER_RAIL_BACKWARDS) {
newState = newState.with(RAIL_TYPE, AllBlocks.CONTROLLER_RAIL.get()
.rotate(AllBlocks.CONTROLLER_RAIL.getDefaultState()
.with(ControllerRailBlock.SHAPE, state.get(RAIL_SHAPE))
.with(ControllerRailBlock.BACKWARDS,
state.get(RAIL_TYPE) == CartAssembleRailType.CONTROLLER_RAIL_BACKWARDS),
Rotation.CLOCKWISE_90)
.get(ControllerRailBlock.BACKWARDS) ? CartAssembleRailType.CONTROLLER_RAIL_BACKWARDS
: CartAssembleRailType.CONTROLLER_RAIL);
}
context.getWorld()
.setBlockState(pos, newState, 3);
world.notifyNeighborsOfStateChange(pos.down(), this); world.notifyNeighborsOfStateChange(pos.down(), this);
return ActionResultType.SUCCESS; return ActionResultType.SUCCESS;
} }
@Override
public BlockState rotate(BlockState state, Rotation rotation) {
if (rotation == Rotation.NONE)
return state;
boolean is_controller_rail_backwards = state.get(RAIL_TYPE) == CartAssembleRailType.CONTROLLER_RAIL_BACKWARDS;
boolean is_controller_rail = state.get(RAIL_TYPE) == CartAssembleRailType.CONTROLLER_RAIL || is_controller_rail_backwards;
BlockState base = AllBlocks.CONTROLLER_RAIL.getDefaultState()
.with(ControllerRailBlock.SHAPE, state.get(RAIL_SHAPE))
.with(ControllerRailBlock.BACKWARDS, is_controller_rail_backwards)
.rotate(rotation);
if (is_controller_rail) {
state = state.with(RAIL_TYPE,
base.get(ControllerRailBlock.BACKWARDS) ? CartAssembleRailType.CONTROLLER_RAIL_BACKWARDS :
CartAssembleRailType.CONTROLLER_RAIL
);
}
return state.with(RAIL_SHAPE, base.get(ControllerRailBlock.SHAPE));
}
@Override
public BlockState mirror(BlockState state, Mirror mirror) {
if (mirror == Mirror.NONE)
return state;
boolean is_controller_rail_backwards = state.get(RAIL_TYPE) == CartAssembleRailType.CONTROLLER_RAIL_BACKWARDS;
boolean is_controller_rail = state.get(RAIL_TYPE) == CartAssembleRailType.CONTROLLER_RAIL || is_controller_rail_backwards;
BlockState base = AllBlocks.CONTROLLER_RAIL.getDefaultState()
.with(ControllerRailBlock.SHAPE, state.get(RAIL_SHAPE))
.with(ControllerRailBlock.BACKWARDS, is_controller_rail_backwards)
.mirror(mirror);
if (is_controller_rail) {
state = state.with(RAIL_TYPE,
base.get(ControllerRailBlock.BACKWARDS) ? CartAssembleRailType.CONTROLLER_RAIL_BACKWARDS :
CartAssembleRailType.CONTROLLER_RAIL
);
}
return state.with(RAIL_SHAPE, base.get(ControllerRailBlock.SHAPE));
}
} }

View file

@ -169,6 +169,20 @@ public class GantryShaftBlock extends DirectionalKineticBlock {
return onWrenched; return onWrenched;
} }
@Override
public void onBlockAdded(BlockState state, World worldIn, BlockPos pos, BlockState oldState, boolean isMoving) {
super.onBlockAdded(state, worldIn, pos, oldState, isMoving);
if (!worldIn.isRemote() && oldState.getBlock().is(AllBlocks.GANTRY_SHAFT.get())) {
Part oldPart = oldState.get(PART), part = state.get(PART);
if ((oldPart != Part.MIDDLE && part == Part.MIDDLE) || (oldPart == Part.SINGLE && part != Part.SINGLE)) {
TileEntity te = worldIn.getTileEntity(pos);
if (te instanceof GantryShaftTileEntity)
((GantryShaftTileEntity) te).checkAttachedCarriageBlocks();
}
}
}
@Override @Override
public void neighborChanged(BlockState state, World worldIn, BlockPos pos, Block p_220069_4_, BlockPos p_220069_5_, public void neighborChanged(BlockState state, World worldIn, BlockPos pos, Block p_220069_4_, BlockPos p_220069_5_,
boolean p_220069_6_) { boolean p_220069_6_) {
@ -260,7 +274,7 @@ public class GantryShaftBlock extends DirectionalKineticBlock {
return super.areStatesKineticallyEquivalent(oldState, newState) return super.areStatesKineticallyEquivalent(oldState, newState)
&& oldState.get(POWERED) == newState.get(POWERED); && oldState.get(POWERED) == newState.get(POWERED);
} }
@Override @Override
public float getParticleTargetRadius() { public float getParticleTargetRadius() {
return .35f; return .35f;
@ -270,7 +284,7 @@ public class GantryShaftBlock extends DirectionalKineticBlock {
public float getParticleInitialRadius() { public float getParticleInitialRadius() {
return .25f; return .25f;
} }
@Override @Override
public boolean allowsMovement(BlockState state, IBlockReader reader, BlockPos pos, PathType type) { public boolean allowsMovement(BlockState state, IBlockReader reader, BlockPos pos, PathType type) {
return false; return false;

View file

@ -19,15 +19,12 @@ public class GantryShaftTileEntity extends KineticTileEntity {
super(typeIn); super(typeIn);
} }
@Override public void checkAttachedCarriageBlocks() {
public void onSpeedChanged(float previousSpeed) {
super.onSpeedChanged(previousSpeed);
if (!canAssembleOn()) if (!canAssembleOn())
return; return;
for (Direction d : Iterate.directions) { for (Direction d : Iterate.directions) {
if (d.getAxis() == getBlockState().get(GantryShaftBlock.FACING) if (d.getAxis() == getBlockState().get(GantryShaftBlock.FACING)
.getAxis()) .getAxis())
continue; continue;
BlockPos offset = pos.offset(d); BlockPos offset = pos.offset(d);
BlockState pinionState = world.getBlockState(offset); BlockState pinionState = world.getBlockState(offset);
@ -39,7 +36,12 @@ public class GantryShaftTileEntity extends KineticTileEntity {
if (tileEntity instanceof GantryCarriageTileEntity) if (tileEntity instanceof GantryCarriageTileEntity)
((GantryCarriageTileEntity) tileEntity).queueAssembly(); ((GantryCarriageTileEntity) tileEntity).queueAssembly();
} }
}
@Override
public void onSpeedChanged(float previousSpeed) {
super.onSpeedChanged(previousSpeed);
checkAttachedCarriageBlocks();
} }
@Override @Override
@ -99,7 +101,7 @@ public class GantryShaftTileEntity extends KineticTileEntity {
return 0; return 0;
return MathHelper.clamp(-getSpeed() / 512f, -.49f, .49f); return MathHelper.clamp(-getSpeed() / 512f, -.49f, .49f);
} }
@Override @Override
protected boolean isNoisy() { protected boolean isNoisy() {
return false; return false;

View file

@ -122,14 +122,14 @@ public class ArmTileEntity extends KineticTileEntity {
} }
if (world.isRemote) if (world.isRemote)
return; return;
if (phase == Phase.MOVE_TO_INPUT) if (phase == Phase.MOVE_TO_INPUT)
collectItem(); collectItem();
else if (phase == Phase.MOVE_TO_OUTPUT) else if (phase == Phase.MOVE_TO_OUTPUT)
depositItem(); depositItem();
else if (phase == Phase.SEARCH_INPUTS || phase == Phase.DANCING) else if (phase == Phase.SEARCH_INPUTS || phase == Phase.DANCING)
searchForItem(); searchForItem();
if (targetReached) if (targetReached)
lazyTick(); lazyTick();
} }
@ -142,7 +142,7 @@ public class ArmTileEntity extends KineticTileEntity {
return; return;
if (chasedPointProgress < .5f) if (chasedPointProgress < .5f)
return; return;
if (phase == Phase.SEARCH_INPUTS || phase == Phase.DANCING) if (phase == Phase.SEARCH_INPUTS || phase == Phase.DANCING)
checkForMusic(); checkForMusic();
if (phase == Phase.SEARCH_OUTPUTS) if (phase == Phase.SEARCH_OUTPUTS)
searchForDestination(); searchForDestination();
@ -175,7 +175,7 @@ public class ArmTileEntity extends KineticTileEntity {
} }
private boolean tickMovementProgress() { private boolean tickMovementProgress() {
boolean targetReachedPreviously = chasedPointProgress >= 1; boolean targetReachedPreviously = chasedPointProgress >= 1;
chasedPointProgress += Math.min(256, Math.abs(getSpeed())) / 1024f; chasedPointProgress += Math.min(256, Math.abs(getSpeed())) / 1024f;
if (chasedPointProgress > 1) if (chasedPointProgress > 1)
chasedPointProgress = 1; chasedPointProgress = 1;
@ -349,7 +349,7 @@ public class ArmTileEntity extends KineticTileEntity {
chasedPointIndex = -1; chasedPointIndex = -1;
sendData(); sendData();
markDirty(); markDirty();
if (!prevHeld.isItemEqual(heldItem)) if (!prevHeld.isItemEqual(heldItem))
world.playSound(null, pos, SoundEvents.ENTITY_ITEM_PICKUP, SoundCategory.BLOCKS, .125f, world.playSound(null, pos, SoundEvents.ENTITY_ITEM_PICKUP, SoundCategory.BLOCKS, .125f,
.5f + Create.random.nextFloat() * .25f); .5f + Create.random.nextFloat() * .25f);
@ -416,23 +416,26 @@ public class ArmTileEntity extends KineticTileEntity {
markDirty(); markDirty();
} }
public void writeInteractionPoints(CompoundNBT compound) {
if (updateInteractionPoints) {
compound.put("InteractionPoints", interactionPointTag);
} else {
ListNBT pointsNBT = new ListNBT();
inputs.stream()
.map(aip -> aip.serialize(pos))
.forEach(pointsNBT::add);
outputs.stream()
.map(aip -> aip.serialize(pos))
.forEach(pointsNBT::add);
compound.put("InteractionPoints", pointsNBT);
}
}
@Override @Override
public void write(CompoundNBT compound, boolean clientPacket) { public void write(CompoundNBT compound, boolean clientPacket) {
super.write(compound, clientPacket); super.write(compound, clientPacket);
if (updateInteractionPoints) { writeInteractionPoints(compound);
compound.put("InteractionPoints", interactionPointTag);
} else {
ListNBT pointsNBT = new ListNBT();
inputs.stream()
.map(aip -> aip.serialize(pos))
.forEach(pointsNBT::add);
outputs.stream()
.map(aip -> aip.serialize(pos))
.forEach(pointsNBT::add);
compound.put("InteractionPoints", pointsNBT);
}
NBTHelper.writeEnum(compound, "Phase", phase); NBTHelper.writeEnum(compound, "Phase", phase);
compound.putBoolean("Powered", redstoneLocked); compound.putBoolean("Powered", redstoneLocked);
@ -441,6 +444,13 @@ public class ArmTileEntity extends KineticTileEntity {
compound.putFloat("MovementProgress", chasedPointProgress); compound.putFloat("MovementProgress", chasedPointProgress);
} }
@Override
public void writeSafe(CompoundNBT compound, boolean clientPacket) {
super.writeSafe(compound, clientPacket);
writeInteractionPoints(compound);
}
@Override @Override
protected void fromTag(BlockState state, CompoundNBT compound, boolean clientPacket) { protected void fromTag(BlockState state, CompoundNBT compound, boolean clientPacket) {
int previousIndex = chasedPointIndex; int previousIndex = chasedPointIndex;

View file

@ -28,10 +28,15 @@ import com.simibubi.create.foundation.item.ItemHelper.ExtractionCountMode;
import com.simibubi.create.foundation.render.backend.instancing.IInstanceRendered; import com.simibubi.create.foundation.render.backend.instancing.IInstanceRendered;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity; import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType;
import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour;
import com.simibubi.create.foundation.utility.BlockHelper; import com.simibubi.create.foundation.utility.BlockHelper;
import com.simibubi.create.foundation.utility.IPartialSafeNBT;
import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.NBTProcessors; import com.simibubi.create.foundation.utility.NBTProcessors;
import net.minecraft.block.AbstractRailBlock;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks; import net.minecraft.block.Blocks;
import net.minecraft.block.PistonHeadBlock; import net.minecraft.block.PistonHeadBlock;
@ -79,6 +84,10 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
STOPPED, PAUSED, RUNNING; STOPPED, PAUSED, RUNNING;
} }
public enum PrintStage {
BLOCKS, DEFERRED_BLOCKS, ENTITIES
}
// Inventory // Inventory
public SchematicannonInventory inventory; public SchematicannonInventory inventory;
@ -99,12 +108,14 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
private int skipsLeft; private int skipsLeft;
private boolean blockSkipped; private boolean blockSkipped;
private int printingEntityIndex; private int printingEntityIndex;
private PrintStage printStage;
public BlockPos target; public BlockPos target;
public BlockPos previousTarget; public BlockPos previousTarget;
public LinkedHashSet<LazyOptional<IItemHandler>> attachedInventories; public LinkedHashSet<LazyOptional<IItemHandler>> attachedInventories;
public List<LaunchedItem> flyingBlocks; public List<LaunchedItem> flyingBlocks;
public MaterialChecklist checklist; public MaterialChecklist checklist;
public List<BlockPos> deferredBlocks;
// Gui information // Gui information
public float fuelLevel; public float fuelLevel;
@ -142,7 +153,9 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
inventory = new SchematicannonInventory(this); inventory = new SchematicannonInventory(this);
statusMsg = "idle"; statusMsg = "idle";
state = State.STOPPED; state = State.STOPPED;
printingEntityIndex = -1; printingEntityIndex = 0;
printStage = PrintStage.BLOCKS;
deferredBlocks = new LinkedList<>();
replaceMode = 2; replaceMode = 2;
checklist = new MaterialChecklist(); checklist = new MaterialChecklist();
} }
@ -198,8 +211,14 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
replaceTileEntities = options.getBoolean("ReplaceTileEntities"); replaceTileEntities = options.getBoolean("ReplaceTileEntities");
// Printer & Flying Blocks // Printer & Flying Blocks
if (compound.contains("PrintStage"))
printStage = PrintStage.valueOf(compound.getString("PrintStage"));
if (compound.contains("Target")) if (compound.contains("Target"))
target = NBTUtil.readBlockPos(compound.getCompound("Target")); target = NBTUtil.readBlockPos(compound.getCompound("Target"));
if (compound.contains("DeferredBlocks"))
compound.getList("DeferredBlocks", 10).stream()
.map(p -> NBTUtil.readBlockPos((CompoundNBT) p))
.collect(Collectors.toCollection(() -> deferredBlocks));
if (compound.contains("FlyingBlocks")) if (compound.contains("FlyingBlocks"))
readFlyingBlocks(compound); readFlyingBlocks(compound);
@ -273,12 +292,20 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
compound.put("Options", options); compound.put("Options", options);
// Printer & Flying Blocks // Printer & Flying Blocks
compound.putString("PrintStage", printStage.name());
if (target != null) if (target != null)
compound.put("Target", NBTUtil.writeBlockPos(target)); compound.put("Target", NBTUtil.writeBlockPos(target));
ListNBT tagBlocks = new ListNBT();
ListNBT tagDeferredBlocks = new ListNBT();
for (BlockPos p : deferredBlocks)
tagDeferredBlocks.add(NBTUtil.writeBlockPos(p));
compound.put("DeferredBlocks", tagDeferredBlocks);
ListNBT tagFlyingBlocks = new ListNBT();
for (LaunchedItem b : flyingBlocks) for (LaunchedItem b : flyingBlocks)
tagBlocks.add(b.serializeNBT()); tagFlyingBlocks.add(b.serializeNBT());
compound.put("FlyingBlocks", tagBlocks); compound.put("FlyingBlocks", tagFlyingBlocks);
super.write(compound, clientPacket); super.write(compound, clientPacket);
} }
@ -388,7 +415,7 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
target = schematicAnchor.add(currentPos); target = schematicAnchor.add(currentPos);
} }
boolean entityMode = printingEntityIndex >= 0; boolean entityMode = printStage == PrintStage.ENTITIES;
// Check block // Check block
if (!getWorld().isAreaLoaded(target, 0)) { if (!getWorld().isAreaLoaded(target, 0)) {
@ -471,13 +498,18 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
launchBlock(target, icon, blockState, null); launchBlock(target, icon, blockState, null);
} else { } else {
CompoundNBT data = null; CompoundNBT data = null;
if (AllBlockTags.SAFE_NBT.matches(blockState)) { TileEntity tile = blockReader.getTileEntity(target);
TileEntity tile = blockReader.getTileEntity(target); if (tile != null) {
if (tile != null) { if (AllBlockTags.SAFE_NBT.matches(blockState)) {
data = tile.write(new CompoundNBT()); data = tile.write(new CompoundNBT());
data = NBTProcessors.process(tile, data, true); data = NBTProcessors.process(tile, data, true);
} else if (tile instanceof IPartialSafeNBT) {
data = new CompoundNBT();
((IPartialSafeNBT) tile).writeSafe(data, false);
data = NBTProcessors.process(tile, data, true);
} }
} }
launchBlock(target, icon, blockState, data); launchBlock(target, icon, blockState, data);
} }
@ -563,7 +595,9 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
schematicLoaded = true; schematicLoaded = true;
state = State.PAUSED; state = State.PAUSED;
statusMsg = "ready"; statusMsg = "ready";
printingEntityIndex = -1; printingEntityIndex = 0;
printStage = PrintStage.BLOCKS;
deferredBlocks.clear();
updateChecklist(); updateChecklist();
sendUpdate = true; sendUpdate = true;
blocksToPlace += blocksPlaced; blocksToPlace += blocksPlaced;
@ -649,22 +683,33 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
protected void advanceCurrentPos() { protected void advanceCurrentPos() {
List<Entity> entities = blockReader.getEntities() List<Entity> entities = blockReader.getEntities()
.collect(Collectors.toList()); .collect(Collectors.toList());
if (printingEntityIndex != -1) {
printingEntityIndex++;
// End of entities reached if (printStage == PrintStage.BLOCKS) {
if (printingEntityIndex >= entities.size()) { MutableBoundingBox bounds = blockReader.getBounds();
finishedPrinting(); while (tryAdvanceCurrentPos(bounds, entities)) {
return; deferredBlocks.add(currentPos);
} }
currentPos = entities.get(printingEntityIndex)
.getBlockPos()
.subtract(schematicAnchor);
return;
} }
MutableBoundingBox bounds = blockReader.getBounds(); if (printStage == PrintStage.DEFERRED_BLOCKS) {
if (deferredBlocks.isEmpty()) {
printStage = PrintStage.ENTITIES;
} else {
currentPos = deferredBlocks.remove(0);
}
}
if (printStage == PrintStage.ENTITIES) {
if (printingEntityIndex < entities.size()) {
currentPos = entities.get(printingEntityIndex).getBlockPos().subtract(schematicAnchor);
printingEntityIndex++;
} else {
finishedPrinting();
}
}
}
protected boolean tryAdvanceCurrentPos(MutableBoundingBox bounds, List<Entity> entities) {
currentPos = currentPos.offset(Direction.EAST); currentPos = currentPos.offset(Direction.EAST);
BlockPos posInBounds = currentPos.add(-bounds.minX, -bounds.minY, -bounds.minZ); BlockPos posInBounds = currentPos.add(-bounds.minX, -bounds.minY, -bounds.minZ);
@ -675,15 +720,16 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
// End of blocks reached // End of blocks reached
if (currentPos.getY() > bounds.getYSize()) { if (currentPos.getY() > bounds.getYSize()) {
printingEntityIndex = 0; printStage = PrintStage.DEFERRED_BLOCKS;
if (entities.isEmpty()) { return false;
finishedPrinting();
return;
}
currentPos = entities.get(0)
.getBlockPos()
.subtract(schematicAnchor);
} }
return shouldDeferBlock(blockReader.getBlockState(schematicAnchor.add(currentPos)));
}
public static boolean shouldDeferBlock(BlockState state) {
Block block = state.getBlock();
return block instanceof AbstractRailBlock || block.is(AllBlocks.GANTRY_CARRIAGE.get());
} }
public void finishedPrinting() { public void finishedPrinting() {
@ -705,10 +751,12 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
blockReader = null; blockReader = null;
missingItem = null; missingItem = null;
sendUpdate = true; sendUpdate = true;
printingEntityIndex = -1; printingEntityIndex = 0;
printStage = PrintStage.BLOCKS;
schematicProgress = 0; schematicProgress = 0;
blocksPlaced = 0; blocksPlaced = 0;
blocksToPlace = 0; blocksToPlace = 0;
deferredBlocks.clear();
} }
protected boolean shouldPlace(BlockPos pos, BlockState state) { protected boolean shouldPlace(BlockPos pos, BlockState state) {

View file

@ -0,0 +1,37 @@
package com.simibubi.create.foundation.mixin;
import com.simibubi.create.content.schematics.SchematicWorld;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import net.minecraftforge.client.model.ModelDataManager;
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;
import net.minecraft.client.Minecraft;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
@Mixin(ModelDataManager.class)
public class ModelDataRefreshMixin {
/**
* Normally ModelDataManager will throw an exception if a tile entity tries
* to refresh its model data from a world the client isn't currently in,
* but we need that to not happen for tile entities in fake schematic
* worlds, so in those cases just do nothing instead.
*/
@Inject(at = @At("HEAD"), method = "requestModelDataRefresh", cancellable = true, remap = false)
private static void requestModelDataRefresh(TileEntity te, CallbackInfo ci) {
if (te != null) {
World world = te.getWorld();
if (world != Minecraft.getInstance().world && world instanceof SchematicWorld)
ci.cancel();
}
}
}

View file

@ -8,6 +8,8 @@ import java.util.function.Consumer;
import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType; import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType;
import com.simibubi.create.foundation.utility.IPartialSafeNBT;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.tileentity.ITickableTileEntity; import net.minecraft.tileentity.ITickableTileEntity;
@ -16,7 +18,7 @@ import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler; import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.CapabilityItemHandler;
public abstract class SmartTileEntity extends SyncedTileEntity implements ITickableTileEntity { public abstract class SmartTileEntity extends SyncedTileEntity implements ITickableTileEntity, IPartialSafeNBT {
private final Map<BehaviourType<?>, TileEntityBehaviour> behaviours; private final Map<BehaviourType<?>, TileEntityBehaviour> behaviours;
// Internally maintained to be identical to behaviorMap.values() in order to improve iteration performance. // Internally maintained to be identical to behaviorMap.values() in order to improve iteration performance.
@ -118,6 +120,14 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka
behaviourList.forEach(tb -> tb.write(compound, clientPacket)); behaviourList.forEach(tb -> tb.write(compound, clientPacket));
} }
public void writeSafe(CompoundNBT compound, boolean clientPacket) {
super.write(compound);
behaviourList.forEach(tb -> {
if (tb.isSafeNBT())
tb.write(compound, clientPacket);
});
}
@Override @Override
public void remove() { public void remove() {
forEachBehaviour(TileEntityBehaviour::remove); forEachBehaviour(TileEntityBehaviour::remove);

View file

@ -42,6 +42,8 @@ public abstract class TileEntityBehaviour {
} }
public boolean isSafeNBT() { return false; }
public void onBlockChanged(BlockState oldState) { public void onBlockChanged(BlockState oldState) {
} }
@ -94,5 +96,4 @@ public abstract class TileEntityBehaviour {
SmartTileEntity ste = (SmartTileEntity) te; SmartTileEntity ste = (SmartTileEntity) te;
return ste.getBehaviour(type); return ste.getBehaviour(type);
} }
} }

View file

@ -57,6 +57,9 @@ public class FilteringBehaviour extends TileEntityBehaviour {
fluidFilter = false; fluidFilter = false;
} }
@Override
public boolean isSafeNBT() { return true; }
@Override @Override
public void write(CompoundNBT nbt, boolean clientPacket) { public void write(CompoundNBT nbt, boolean clientPacket) {
nbt.put("Filter", getFilter().serializeNBT()); nbt.put("Filter", getFilter().serializeNBT());

View file

@ -58,6 +58,9 @@ public class SidedFilteringBehaviour extends FilteringBehaviour {
removeFilter(d); removeFilter(d);
} }
@Override
public boolean isSafeNBT() { return true; }
@Override @Override
public void write(CompoundNBT nbt, boolean clientPacket) { public void write(CompoundNBT nbt, boolean clientPacket) {
nbt.put("Filters", NBTHelper.writeCompoundList(sidedFilters.entrySet(), entry -> { nbt.put("Filters", NBTHelper.writeCompoundList(sidedFilters.entrySet(), entry -> {

View file

@ -115,6 +115,9 @@ public class LinkBehaviour extends TileEntityBehaviour {
getHandler().removeFromNetwork(this); getHandler().removeFromNetwork(this);
} }
@Override
public boolean isSafeNBT() { return true; }
@Override @Override
public void write(CompoundNBT nbt, boolean clientPacket) { public void write(CompoundNBT nbt, boolean clientPacket) {
super.write(nbt, clientPacket); super.write(nbt, clientPacket);

View file

@ -54,6 +54,9 @@ public class ScrollValueBehaviour extends TileEntityBehaviour {
ticksUntilScrollPacket = -1; ticksUntilScrollPacket = -1;
} }
@Override
public boolean isSafeNBT() { return true; }
@Override @Override
public void write(CompoundNBT nbt, boolean clientPacket) { public void write(CompoundNBT nbt, boolean clientPacket) {
nbt.putInt("ScrollValue", value); nbt.putInt("ScrollValue", value);
@ -95,7 +98,7 @@ public class ScrollValueBehaviour extends TileEntityBehaviour {
clientCallback = valueCallback; clientCallback = valueCallback;
return this; return this;
} }
public ScrollValueBehaviour withCallback(Consumer<Integer> valueCallback) { public ScrollValueBehaviour withCallback(Consumer<Integer> valueCallback) {
callback = valueCallback; callback = valueCallback;
return this; return this;
@ -126,7 +129,7 @@ public class ScrollValueBehaviour extends TileEntityBehaviour {
this.unit = unit; this.unit = unit;
return this; return this;
} }
public ScrollValueBehaviour onlyActiveWhen(Supplier<Boolean> condition) { public ScrollValueBehaviour onlyActiveWhen(Supplier<Boolean> condition) {
isActive = condition; isActive = condition;
return this; return this;
@ -168,7 +171,7 @@ public class ScrollValueBehaviour extends TileEntityBehaviour {
public BehaviourType<?> getType() { public BehaviourType<?> getType() {
return TYPE; return TYPE;
} }
public boolean isActive() { public boolean isActive() {
return isActive.get(); return isActive.get();
} }
@ -182,7 +185,7 @@ public class ScrollValueBehaviour extends TileEntityBehaviour {
public void setLabel(ITextComponent label) { public void setLabel(ITextComponent label) {
this.label = label; this.label = label;
} }
public static class StepContext { public static class StepContext {
public int currentValue; public int currentValue;
public boolean forward; public boolean forward;

View file

@ -20,6 +20,9 @@ public class DeferralBehaviour extends TileEntityBehaviour {
this.callback = callback; this.callback = callback;
} }
@Override
public boolean isSafeNBT() { return true; }
@Override @Override
public void write(CompoundNBT nbt, boolean clientPacket) { public void write(CompoundNBT nbt, boolean clientPacket) {
nbt.putBoolean("NeedsUpdate", needsUpdate); nbt.putBoolean("NeedsUpdate", needsUpdate);
@ -38,7 +41,7 @@ public class DeferralBehaviour extends TileEntityBehaviour {
if (needsUpdate && callback.get()) if (needsUpdate && callback.get())
needsUpdate = false; needsUpdate = false;
} }
public void scheduleUpdate() { public void scheduleUpdate() {
needsUpdate = true; needsUpdate = true;
} }

View file

@ -1,9 +1,18 @@
package com.simibubi.create.foundation.utility; package com.simibubi.create.foundation.utility;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import net.minecraft.block.AbstractRailBlock;
import net.minecraft.block.RailBlock;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.ChunkSection;
import net.minecraftforge.common.util.BlockSnapshot;
import org.apache.commons.lang3.mutable.MutableInt; import org.apache.commons.lang3.mutable.MutableInt;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
@ -234,6 +243,24 @@ public class BlockHelper {
.isEmpty(); .isEmpty();
} }
private static void placeRailWithoutUpdate(World world, BlockState state, BlockPos target) {
int i = target.getX() & 15;
int j = target.getY();
int k = target.getZ() & 15;
Chunk chunk = world.getChunkAt(target);
ChunkSection chunksection = chunk.getSections()[j >> 4];
if (chunksection == Chunk.EMPTY_SECTION) {
chunksection = new ChunkSection(j >> 4 << 4);
chunk.getSections()[j >> 4] = chunksection;
}
BlockState old = chunksection.setBlockState(i, j & 15, k, state);
chunk.markDirty();
world.markAndNotifyBlock(target, chunk, old, state, 82, 512);
world.setBlockState(target, state, 82);
world.neighborChanged(target, world.getBlockState(target.down()).getBlock(), target.down());
}
public static void placeSchematicBlock(World world, BlockState state, BlockPos target, ItemStack stack, public static void placeSchematicBlock(World world, BlockState state, BlockPos target, ItemStack stack,
@Nullable CompoundNBT data) { @Nullable CompoundNBT data) {
// Piston // Piston
@ -268,7 +295,13 @@ public class BlockHelper {
Block.spawnDrops(state, world, target); Block.spawnDrops(state, world, target);
return; return;
} }
world.setBlockState(target, state, 18);
if (state.getBlock() instanceof AbstractRailBlock) {
placeRailWithoutUpdate(world, state, target);
} else {
world.setBlockState(target, state, 18);
}
if (data != null) { if (data != null) {
TileEntity tile = world.getTileEntity(target); TileEntity tile = world.getTileEntity(target);
if (tile != null) { if (tile != null) {

View file

@ -0,0 +1,7 @@
package com.simibubi.create.foundation.utility;
import net.minecraft.nbt.CompoundNBT;
public interface IPartialSafeNBT {
public void writeSafe(CompoundNBT compound, boolean clientPacket);
}

View file

@ -19,7 +19,8 @@
"StoreProjectionMatrixMixin", "StoreProjectionMatrixMixin",
"TileRemoveMixin", "TileRemoveMixin",
"TileWorldHookMixin", "TileWorldHookMixin",
"WindowResizeMixin" "WindowResizeMixin",
"ModelDataRefreshMixin"
], ],
"injectors": { "injectors": {
"defaultRequire": 1 "defaultRequire": 1