Schematics and Entities

- Fixed sidedness issue with glue effect packets
- Fixed duplication issue with Schematic tables
- Schematics can now include entities
- Schematicannons can now print:
    - superglue
    - (filled) item frames
    - (equipped) armor stands
    - end crystals
    - boats and minecarts
    - paintings
- Special blocks/entities placed by a schematicannon can now specify custom item requirements (used currently for belts & superglue)
- Fixed superglue not being rotated/mirrored correctly
This commit is contained in:
simibubi 2020-05-05 20:21:22 +02:00
parent 8bfc4445b0
commit c4513020df
23 changed files with 696 additions and 242 deletions

View File

@ -127,17 +127,27 @@ public class ItemHelper {
return false; return false;
} }
public static enum ExtractionCountMode {
EXACTLY, UPTO
}
public static ItemStack extract(IItemHandler inv, Predicate<ItemStack> test, boolean simulate) { public static ItemStack extract(IItemHandler inv, Predicate<ItemStack> test, boolean simulate) {
return extract(inv, test, -1, simulate); return extract(inv, test, ExtractionCountMode.UPTO, AllConfigs.SERVER.logistics.extractorAmount.get(),
simulate);
} }
public static ItemStack extract(IItemHandler inv, Predicate<ItemStack> test, int exactAmount, boolean simulate) { public static ItemStack extract(IItemHandler inv, Predicate<ItemStack> test, int exactAmount, boolean simulate) {
return extract(inv, test, ExtractionCountMode.EXACTLY, exactAmount, simulate);
}
public static ItemStack extract(IItemHandler inv, Predicate<ItemStack> test, ExtractionCountMode mode, int amount,
boolean simulate) {
ItemStack extracting = ItemStack.EMPTY; ItemStack extracting = ItemStack.EMPTY;
boolean amountRequired = exactAmount != -1; boolean amountRequired = mode == ExtractionCountMode.EXACTLY;
boolean checkHasEnoughItems = amountRequired; boolean checkHasEnoughItems = amountRequired;
boolean hasEnoughItems = !checkHasEnoughItems; boolean hasEnoughItems = !checkHasEnoughItems;
int maxExtractionCount = hasEnoughItems ? AllConfigs.SERVER.logistics.extractorAmount.get() : exactAmount;
boolean potentialOtherMatch = false; boolean potentialOtherMatch = false;
int maxExtractionCount = amount;
Extraction: do { Extraction: do {
extracting = ItemStack.EMPTY; extracting = ItemStack.EMPTY;
@ -186,7 +196,7 @@ public class ItemHelper {
} while (true); } while (true);
if (amountRequired && extracting.getCount() < exactAmount) if (amountRequired && extracting.getCount() < amount)
return ItemStack.EMPTY; return ItemStack.EMPTY;
return extracting; return extracting;

View File

@ -1,14 +1,12 @@
package com.simibubi.create.modules.contraptions.components.actors; package com.simibubi.create.modules.contraptions.components.actors;
import com.simibubi.create.foundation.utility.BlockHelper; import com.simibubi.create.foundation.utility.BlockHelper;
import com.simibubi.create.foundation.utility.Debug;
import com.simibubi.create.modules.contraptions.components.contraptions.ContraptionEntity; import com.simibubi.create.modules.contraptions.components.contraptions.ContraptionEntity;
import com.simibubi.create.modules.contraptions.components.contraptions.MovementBehaviour; import com.simibubi.create.modules.contraptions.components.contraptions.MovementBehaviour;
import com.simibubi.create.modules.contraptions.components.contraptions.MovementContext; import com.simibubi.create.modules.contraptions.components.contraptions.MovementContext;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.block.FallingBlock; import net.minecraft.block.FallingBlock;
import net.minecraft.block.material.Material;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.item.ItemEntity; import net.minecraft.entity.item.ItemEntity;
import net.minecraft.entity.item.minecart.AbstractMinecartEntity; import net.minecraft.entity.item.minecart.AbstractMinecartEntity;

View File

@ -9,6 +9,7 @@ import net.minecraft.network.PacketBuffer;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fml.network.NetworkEvent.Context; import net.minecraftforge.fml.network.NetworkEvent.Context;
@ -36,6 +37,7 @@ public class GlueEffectPacket extends SimplePacketBase {
buffer.writeBoolean(fullBlock); buffer.writeBoolean(fullBlock);
} }
@OnlyIn(Dist.CLIENT)
public void handle(Supplier<Context> context) { public void handle(Supplier<Context> context) {
context.get().enqueueWork(() -> DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> { context.get().enqueueWork(() -> DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> {
Minecraft mc = Minecraft.getInstance(); Minecraft mc = Minecraft.getInstance();

View File

@ -8,6 +8,9 @@ import com.simibubi.create.AllEntities;
import com.simibubi.create.AllItems; import com.simibubi.create.AllItems;
import com.simibubi.create.AllPackets; import com.simibubi.create.AllPackets;
import com.simibubi.create.AllSoundEvents; import com.simibubi.create.AllSoundEvents;
import com.simibubi.create.modules.schematics.ISpecialEntityItemRequirement;
import com.simibubi.create.modules.schematics.ItemRequirement;
import com.simibubi.create.modules.schematics.ItemRequirement.ItemUseType;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.player.ClientPlayerEntity; import net.minecraft.client.entity.player.ClientPlayerEntity;
@ -46,7 +49,7 @@ import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData;
import net.minecraftforge.fml.network.NetworkHooks; import net.minecraftforge.fml.network.NetworkHooks;
import net.minecraftforge.fml.network.PacketDistributor; import net.minecraftforge.fml.network.PacketDistributor;
public class SuperGlueEntity extends Entity implements IEntityAdditionalSpawnData { public class SuperGlueEntity extends Entity implements IEntityAdditionalSpawnData, ISpecialEntityItemRequirement {
private int validationTimer; private int validationTimer;
protected BlockPos hangingPosition; protected BlockPos hangingPosition;
@ -64,7 +67,8 @@ public class SuperGlueEntity extends Entity implements IEntityAdditionalSpawnDat
} }
@Override @Override
protected void registerData() {} protected void registerData() {
}
public int getWidthPixels() { public int getWidthPixels() {
return 12; return 12;
@ -104,34 +108,32 @@ public class SuperGlueEntity extends Entity implements IEntityAdditionalSpawnDat
protected void updateBoundingBox() { protected void updateBoundingBox() {
if (this.getFacingDirection() != null) { if (this.getFacingDirection() != null) {
this.posX = double offset = 0.5 - 1 / 256d;
(double) this.hangingPosition.getX() + 0.5 - (double) this.getFacingDirection().getXOffset() * 0.5; this.posX = hangingPosition.getX() + 0.5 - facingDirection.getXOffset() * offset;
this.posY = this.posY = hangingPosition.getY() + 0.5 - facingDirection.getYOffset() * offset;
(double) this.hangingPosition.getY() + 0.5 - (double) this.getFacingDirection().getYOffset() * 0.5; this.posZ = hangingPosition.getZ() + 0.5 - facingDirection.getZOffset() * offset;
this.posZ = double w = getWidthPixels();
(double) this.hangingPosition.getZ() + 0.5 - (double) this.getFacingDirection().getZOffset() * 0.5; double h = getHeightPixels();
double d1 = (double) this.getWidthPixels(); double l = getWidthPixels();
double d2 = (double) this.getHeightPixels();
double d3 = (double) this.getWidthPixels();
Axis axis = this.getFacingDirection().getAxis(); Axis axis = this.getFacingDirection().getAxis();
double depth = 2 - 1 / 128f; double depth = 2 - 1 / 128f;
switch (axis) { switch (axis) {
case X: case X:
d1 = depth; w = depth;
break; break;
case Y: case Y:
d2 = depth; h = depth;
break; break;
case Z: case Z:
d3 = depth; l = depth;
} }
d1 = d1 / 32.0D; w = w / 32.0D;
d2 = d2 / 32.0D; h = h / 32.0D;
d3 = d3 / 32.0D; l = l / 32.0D;
this.setBoundingBox(new AxisAlignedBB(this.posX - d1, this.posY - d2, this.posZ - d3, this.posX + d1, this.setBoundingBox(new AxisAlignedBB(this.posX - w, this.posY - h, this.posZ - l, this.posX + w,
this.posY + d2, this.posZ + d3)); this.posY + h, this.posZ + l));
} }
} }
@ -317,13 +319,13 @@ public class SuperGlueEntity extends Entity implements IEntityAdditionalSpawnDat
if (this.getFacingDirection().getAxis() != Direction.Axis.Y) { if (this.getFacingDirection().getAxis() != Direction.Axis.Y) {
switch (transformRotation) { switch (transformRotation) {
case CLOCKWISE_180: case CLOCKWISE_180:
this.facingDirection = this.getFacingDirection().getOpposite(); facingDirection = facingDirection.getOpposite();
break; break;
case COUNTERCLOCKWISE_90: case COUNTERCLOCKWISE_90:
this.facingDirection = this.getFacingDirection().rotateYCCW(); facingDirection = facingDirection.rotateYCCW();
break; break;
case CLOCKWISE_90: case CLOCKWISE_90:
this.facingDirection = this.getFacingDirection().rotateY(); facingDirection = facingDirection.rotateY();
default: default:
break; break;
} }
@ -356,10 +358,12 @@ public class SuperGlueEntity extends Entity implements IEntityAdditionalSpawnDat
} }
@Override @Override
public void onStruckByLightning(LightningBoltEntity lightningBolt) {} public void onStruckByLightning(LightningBoltEntity lightningBolt) {
}
@Override @Override
public void recalculateSize() {} public void recalculateSize() {
}
public static EntityType.Builder<?> build(EntityType.Builder<?> builder) { public static EntityType.Builder<?> build(EntityType.Builder<?> builder) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -387,4 +391,10 @@ public class SuperGlueEntity extends Entity implements IEntityAdditionalSpawnDat
public Direction getFacingDirection() { public Direction getFacingDirection() {
return facingDirection; return facingDirection;
} }
@Override
public ItemRequirement getRequiredItems() {
return new ItemRequirement(ItemUseType.DAMAGE, AllItems.SUPER_GLUE.get());
}
} }

View File

@ -1,5 +1,6 @@
package com.simibubi.create.modules.contraptions.relays.belt; package com.simibubi.create.modules.contraptions.relays.belt;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@ -16,6 +17,9 @@ import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.modules.contraptions.base.HorizontalKineticBlock; import com.simibubi.create.modules.contraptions.base.HorizontalKineticBlock;
import com.simibubi.create.modules.contraptions.relays.belt.transport.BeltMovementHandler.TransportedEntityInfo; import com.simibubi.create.modules.contraptions.relays.belt.transport.BeltMovementHandler.TransportedEntityInfo;
import com.simibubi.create.modules.logistics.block.belts.tunnel.BeltTunnelBlock; import com.simibubi.create.modules.logistics.block.belts.tunnel.BeltTunnelBlock;
import com.simibubi.create.modules.schematics.ISpecialBlockItemRequirement;
import com.simibubi.create.modules.schematics.ItemRequirement;
import com.simibubi.create.modules.schematics.ItemRequirement.ItemUseType;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockRenderType; import net.minecraft.block.BlockRenderType;
@ -63,7 +67,7 @@ import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandler;
public class BeltBlock extends HorizontalKineticBlock public class BeltBlock extends HorizontalKineticBlock
implements IHaveNoBlockItem, ITE<BeltTileEntity>, IHaveColorHandler { implements IHaveNoBlockItem, ITE<BeltTileEntity>, IHaveColorHandler, ISpecialBlockItemRequirement {
public static final IProperty<Slope> SLOPE = EnumProperty.create("slope", Slope.class); public static final IProperty<Slope> SLOPE = EnumProperty.create("slope", Slope.class);
public static final IProperty<Part> PART = EnumProperty.create("part", Part.class); public static final IProperty<Part> PART = EnumProperty.create("part", Part.class);
@ -603,5 +607,19 @@ public class BeltBlock extends HorizontalKineticBlock
public Class<BeltTileEntity> getTileEntityClass() { public Class<BeltTileEntity> getTileEntityClass() {
return BeltTileEntity.class; return BeltTileEntity.class;
} }
@Override
public ItemRequirement getRequiredItems(BlockState state) {
List<ItemStack> required = new ArrayList<>();
if (state.get(PART) != Part.MIDDLE)
required.add(new ItemStack(AllBlocks.SHAFT.get()));
if (state.get(CASING))
required.add(new ItemStack(AllBlocks.BRASS_CASING.get()));
if (state.get(PART) == Part.START)
required.add(AllItems.BELT_CONNECTOR.asStack());
if (required.isEmpty())
return ItemRequirement.NONE;
return new ItemRequirement(ItemUseType.CONSUME, required);
}
} }

View File

@ -0,0 +1,11 @@
package com.simibubi.create.modules.schematics;
import net.minecraft.block.BlockState;
public interface ISpecialBlockItemRequirement {
default ItemRequirement getRequiredItems(BlockState state) {
return ItemRequirement.INVALID;
}
}

View File

@ -0,0 +1,9 @@
package com.simibubi.create.modules.schematics;
public interface ISpecialEntityItemRequirement {
default ItemRequirement getRequiredItems() {
return ItemRequirement.INVALID;
}
}

View File

@ -0,0 +1,125 @@
package com.simibubi.create.modules.schematics;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.item.ArmorStandEntity;
import net.minecraft.entity.item.BoatEntity;
import net.minecraft.entity.item.ItemFrameEntity;
import net.minecraft.entity.item.minecart.AbstractMinecartEntity;
import net.minecraft.item.BlockItem;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.state.properties.SlabType;
public class ItemRequirement {
public enum ItemUseType {
CONSUME, DAMAGE
}
ItemUseType usage;
List<ItemStack> requiredItems;
public static ItemRequirement INVALID = new ItemRequirement();
public static ItemRequirement NONE = new ItemRequirement();
private ItemRequirement() {
}
public ItemRequirement(ItemUseType usage, Item item) {
this(usage, Arrays.asList(new ItemStack(item)));
}
public ItemRequirement(ItemUseType usage, List<ItemStack> requiredItems) {
this.usage = usage;
this.requiredItems = requiredItems;
}
public static ItemRequirement of(BlockState state) {
Block block = state.getBlock();
if (block == Blocks.AIR)
return NONE;
if (block instanceof ISpecialBlockItemRequirement)
return ((ISpecialBlockItemRequirement) block).getRequiredItems(state);
Item item = BlockItem.BLOCK_TO_ITEM.getOrDefault(state.getBlock(), Items.AIR);
// double slab needs two items
if (state.has(BlockStateProperties.SLAB_TYPE) && state.get(BlockStateProperties.SLAB_TYPE) == SlabType.DOUBLE)
return new ItemRequirement(ItemUseType.CONSUME, Arrays.asList(new ItemStack(item, 2)));
return item == Items.AIR ? INVALID : new ItemRequirement(ItemUseType.CONSUME, item);
}
public static ItemRequirement of(Entity entity) {
EntityType<?> type = entity.getType();
if (entity instanceof ISpecialEntityItemRequirement)
return ((ISpecialEntityItemRequirement) entity).getRequiredItems();
if (type == EntityType.ITEM_FRAME) {
ItemFrameEntity ife = (ItemFrameEntity) entity;
ItemStack frame = new ItemStack(Items.ITEM_FRAME);
ItemStack displayedItem = ife.getDisplayedItem();
if (displayedItem.isEmpty())
return new ItemRequirement(ItemUseType.CONSUME, Items.ITEM_FRAME);
return new ItemRequirement(ItemUseType.CONSUME, Arrays.asList(frame, displayedItem));
}
if (type == EntityType.PAINTING)
return new ItemRequirement(ItemUseType.CONSUME, Items.PAINTING);
if (type == EntityType.ARMOR_STAND) {
List<ItemStack> requirements = new ArrayList<>();
ArmorStandEntity armorStandEntity = (ArmorStandEntity) entity;
armorStandEntity.getEquipmentAndArmor().forEach(requirements::add);
requirements.add(new ItemStack(Items.ARMOR_STAND));
return new ItemRequirement(ItemUseType.CONSUME, requirements);
}
if (entity instanceof AbstractMinecartEntity) {
AbstractMinecartEntity minecartEntity = (AbstractMinecartEntity) entity;
return new ItemRequirement(ItemUseType.CONSUME, minecartEntity.getCartItem().getItem());
}
if (entity instanceof BoatEntity) {
BoatEntity boatEntity = (BoatEntity) entity;
return new ItemRequirement(ItemUseType.CONSUME, boatEntity.getItemBoat().getItem());
}
if (type == EntityType.END_CRYSTAL)
return new ItemRequirement(ItemUseType.CONSUME, Items.END_CRYSTAL);
return INVALID;
}
public boolean isEmpty() {
return NONE == this;
}
public boolean isInvalid() {
return INVALID == this;
}
public List<ItemStack> getRequiredItems() {
return requiredItems;
}
public ItemUseType getUsage() {
return usage;
}
public static boolean validate(ItemStack required, ItemStack present) {
return required.isEmpty() || required.getItem() == present.getItem();
}
}

View File

@ -7,6 +7,9 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import com.google.common.collect.Sets;
import com.simibubi.create.modules.schematics.ItemRequirement.ItemUseType;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.item.Items; import net.minecraft.item.Items;
@ -21,10 +24,12 @@ public class MaterialChecklist {
public Map<Item, Integer> gathered; public Map<Item, Integer> gathered;
public Map<Item, Integer> required; public Map<Item, Integer> required;
public Map<Item, Integer> damageRequired;
public boolean blocksNotLoaded; public boolean blocksNotLoaded;
public MaterialChecklist() { public MaterialChecklist() {
required = new HashMap<>(); required = new HashMap<>();
damageRequired = new HashMap<>();
gathered = new HashMap<>(); gathered = new HashMap<>();
} }
@ -32,16 +37,33 @@ public class MaterialChecklist {
blocksNotLoaded = true; blocksNotLoaded = true;
} }
public void require(Item item) { public void require(ItemRequirement requirement) {
if (required.containsKey(item)) if (requirement.isEmpty())
required.put(item, required.get(item) + 1); return;
if (requirement.isInvalid())
return;
for (ItemStack stack : requirement.requiredItems) {
if (requirement.getUsage() == ItemUseType.DAMAGE)
putOrIncrement(damageRequired, stack);
if (requirement.getUsage() == ItemUseType.CONSUME)
putOrIncrement(required, stack);
}
}
private void putOrIncrement(Map<Item, Integer> map, ItemStack stack) {
Item item = stack.getItem();
if (item == Items.AIR)
return;
if (map.containsKey(item))
map.put(item, map.get(item) + stack.getCount());
else else
required.put(item, 1); map.put(item, stack.getCount());
} }
public void collect(ItemStack stack) { public void collect(ItemStack stack) {
Item item = stack.getItem(); Item item = stack.getItem();
if (required.containsKey(item)) if (required.containsKey(item) || damageRequired.containsKey(item))
if (gathered.containsKey(item)) if (gathered.containsKey(item))
gathered.put(item, gathered.get(item) + stack.getCount()); gathered.put(item, gathered.get(item) + stack.getCount());
else else
@ -65,19 +87,19 @@ public class MaterialChecklist {
string = new StringBuilder("{\"text\":\""); string = new StringBuilder("{\"text\":\"");
} }
List<Item> keys = new ArrayList<>(required.keySet()); List<Item> keys = new ArrayList<>(Sets.union(required.keySet(), damageRequired.keySet()));
Collections.sort(keys, (item1, item2) -> { Collections.sort(keys, (item1, item2) -> {
Locale locale = Locale.ENGLISH; Locale locale = Locale.ENGLISH;
String name1 = new TranslationTextComponent(((Item) item1).getTranslationKey()).getFormattedText() String name1 =
.toLowerCase(locale); new TranslationTextComponent(((Item) item1).getTranslationKey()).getFormattedText().toLowerCase(locale);
String name2 = new TranslationTextComponent(((Item) item2).getTranslationKey()).getFormattedText() String name2 =
.toLowerCase(locale); new TranslationTextComponent(((Item) item2).getTranslationKey()).getFormattedText().toLowerCase(locale);
return name1.compareTo(name2); return name1.compareTo(name2);
}); });
List<Item> completed = new ArrayList<>(); List<Item> completed = new ArrayList<>();
for (Item item : keys) { for (Item item : keys) {
int amount = required.get(item); int amount = getRequiredAmount(item);
if (gathered.containsKey(item)) if (gathered.containsKey(item))
amount -= gathered.get(item); amount -= gathered.get(item);
@ -106,7 +128,7 @@ public class MaterialChecklist {
} }
itemsWritten++; itemsWritten++;
string.append(gatheredEntry(new ItemStack(item), required.get(item))); string.append(gatheredEntry(new ItemStack(item), getRequiredAmount(item)));
} }
string.append("\"}"); string.append("\"}");
@ -120,6 +142,13 @@ public class MaterialChecklist {
return book; return book;
} }
public Integer getRequiredAmount(Item item) {
int amount = required.getOrDefault(item, 0);
if (damageRequired.containsKey(item))
amount += Math.ceil(damageRequired.get(item) / (float) new ItemStack(item).getMaxDamage());
return amount;
}
private String gatheredEntry(ItemStack item, int amount) { private String gatheredEntry(ItemStack item, int amount) {
int stacks = amount / 64; int stacks = amount / 64;
int remainder = amount % 64; int remainder = amount % 64;

View File

@ -1,5 +1,6 @@
package com.simibubi.create.modules.schematics; package com.simibubi.create.modules.schematics;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -14,6 +15,8 @@ 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.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.item.ArmorStandEntity;
import net.minecraft.entity.item.ItemFrameEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.fluid.Fluid; import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.IFluidState; import net.minecraft.fluid.IFluidState;
@ -31,6 +34,7 @@ public class SchematicWorld extends WrappedWorld {
private Map<BlockPos, BlockState> blocks; private Map<BlockPos, BlockState> blocks;
private Map<BlockPos, TileEntity> tileEntities; private Map<BlockPos, TileEntity> tileEntities;
private List<Entity> entities;
private Cuboid bounds; private Cuboid bounds;
public BlockPos anchor; public BlockPos anchor;
public boolean renderMode; public boolean renderMode;
@ -41,11 +45,28 @@ public class SchematicWorld extends WrappedWorld {
this.tileEntities = new HashMap<>(); this.tileEntities = new HashMap<>();
this.bounds = new Cuboid(); this.bounds = new Cuboid();
this.anchor = anchor; this.anchor = anchor;
this.entities = new ArrayList<>();
} }
public Set<BlockPos> getAllPositions() { public Set<BlockPos> getAllPositions() {
return blocks.keySet(); return blocks.keySet();
} }
@Override
public boolean addEntity(Entity entityIn) {
if (entityIn instanceof ItemFrameEntity)
((ItemFrameEntity) entityIn).getDisplayedItem().setTag(null);
if (entityIn instanceof ArmorStandEntity) {
ArmorStandEntity armorStandEntity = (ArmorStandEntity) entityIn;
armorStandEntity.getEquipmentAndArmor().forEach(stack -> stack.setTag(null));
}
return entities.add(entityIn);
}
public List<Entity> getEntities() {
return entities;
}
@Override @Override
public TileEntity getTileEntity(BlockPos pos) { public TileEntity getTileEntity(BlockPos pos) {

View File

@ -25,7 +25,6 @@ import com.simibubi.create.modules.schematics.item.SchematicItem;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.text.StringTextComponent; import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.text.TranslationTextComponent; import net.minecraft.util.text.TranslationTextComponent;
@ -234,7 +233,6 @@ public class ServerSchematicLoader {
if (table == null) if (table == null)
return; return;
table.finishUpload(); table.finishUpload();
table.inventory.setStackInSlot(0, ItemStack.EMPTY);
table.inventory.setStackInSlot(1, SchematicItem.create(schematic, player.getName().getFormattedText())); table.inventory.setStackInSlot(1, SchematicItem.create(schematic, player.getName().getFormattedText()));
} catch (IOException e) { } catch (IOException e) {

View File

@ -1,36 +0,0 @@
package com.simibubi.create.modules.schematics.block;
import net.minecraft.block.BlockState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
public class LaunchedBlock {
private final SchematicannonTileEntity te;
public int totalTicks;
public int ticksRemaining;
public BlockPos target;
public BlockState state;
public LaunchedBlock(SchematicannonTileEntity schematicannonTileEntity, BlockPos target, BlockState state) {
te = schematicannonTileEntity;
this.target = target;
this.state = state;
totalTicks = (int) (Math.max(10, MathHelper.sqrt(MathHelper.sqrt(target.distanceSq(te.getPos()))) * 4f));
ticksRemaining = totalTicks;
}
public LaunchedBlock(SchematicannonTileEntity schematicannonTileEntity, BlockPos target, BlockState state,
int ticksLeft, int total) {
te = schematicannonTileEntity;
this.target = target;
this.state = state;
this.totalTicks = total;
this.ticksRemaining = ticksLeft;
}
public void update() {
if (ticksRemaining > 0)
ticksRemaining--;
}
}

View File

@ -0,0 +1,164 @@
package com.simibubi.create.modules.schematics.block;
import java.util.Optional;
import net.minecraft.block.BlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.NBTUtil;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World;
public abstract class LaunchedItem {
public int totalTicks;
public int ticksRemaining;
public BlockPos target;
public ItemStack stack;
private LaunchedItem(BlockPos start, BlockPos target, ItemStack stack) {
this(target, stack, ticksForDistance(start, target), ticksForDistance(start, target));
}
private static int ticksForDistance(BlockPos start, BlockPos target) {
return (int) (Math.max(10, MathHelper.sqrt(MathHelper.sqrt(target.distanceSq(start))) * 4f));
}
LaunchedItem() {
}
private LaunchedItem(BlockPos target, ItemStack stack, int ticksLeft, int total) {
this.target = target;
this.stack = stack;
this.totalTicks = total;
this.ticksRemaining = ticksLeft;
}
public boolean update(World world) {
if (ticksRemaining > 0) {
ticksRemaining--;
return false;
}
if (world.isRemote)
return false;
place(world);
return true;
}
public CompoundNBT serializeNBT() {
CompoundNBT c = new CompoundNBT();
c.putInt("TotalTicks", totalTicks);
c.putInt("TicksLeft", ticksRemaining);
c.put("Stack", stack.serializeNBT());
c.put("Target", NBTUtil.writeBlockPos(target));
return c;
}
public static LaunchedItem fromNBT(CompoundNBT c) {
LaunchedItem launched =
c.contains("BlockState") ? new LaunchedItem.ForBlockState() : new LaunchedItem.ForEntity();
launched.readNBT(c);
return launched;
}
abstract void place(World world);
void readNBT(CompoundNBT c) {
target = NBTUtil.readBlockPos(c.getCompound("Target"));
ticksRemaining = c.getInt("TicksLeft");
totalTicks = c.getInt("TotalTicks");
stack = ItemStack.read(c.getCompound("Stack"));
}
public static class ForBlockState extends LaunchedItem {
public BlockState state;
ForBlockState() {
}
public ForBlockState(BlockPos start, BlockPos target, ItemStack stack, BlockState state) {
super(start, target, stack);
this.state = state;
}
@Override
public CompoundNBT serializeNBT() {
CompoundNBT serializeNBT = super.serializeNBT();
serializeNBT.put("BlockState", NBTUtil.writeBlockState(state));
return serializeNBT;
}
@Override
void readNBT(CompoundNBT nbt) {
super.readNBT(nbt);
state = NBTUtil.readBlockState(nbt.getCompound("BlockState"));
}
@Override
void place(World world) {
// Piston
if (state.has(BlockStateProperties.EXTENDED))
state = state.with(BlockStateProperties.EXTENDED, false);
world.setBlockState(target, state, 18);
state.getBlock().onBlockPlacedBy(world, target, state, null, stack);
}
}
public static class ForEntity extends LaunchedItem {
public Entity entity;
private CompoundNBT deferredTag;
ForEntity() {
}
public ForEntity(BlockPos start, BlockPos target, ItemStack stack, Entity entity) {
super(start, target, stack);
this.entity = entity;
}
@Override
public boolean update(World world) {
if (deferredTag != null && entity == null) {
try {
Optional<Entity> loadEntityUnchecked = EntityType.loadEntityUnchecked(deferredTag, world);
if (!loadEntityUnchecked.isPresent())
return true;
entity = loadEntityUnchecked.get();
} catch (Exception var3) {
return true;
}
deferredTag = null;
}
return super.update(world);
}
@Override
public CompoundNBT serializeNBT() {
CompoundNBT serializeNBT = super.serializeNBT();
if (entity != null)
serializeNBT.put("Entity", entity.serializeNBT());
return serializeNBT;
}
@Override
void readNBT(CompoundNBT nbt) {
super.readNBT(nbt);
if (nbt.contains("Entity"))
deferredTag = nbt.getCompound("Entity");
}
@Override
void place(World world) {
world.addEntity(entity);
}
}
}

View File

@ -7,6 +7,7 @@ import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory; import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.inventory.container.Container; import net.minecraft.inventory.container.Container;
import net.minecraft.inventory.container.INamedContainerProvider; import net.minecraft.inventory.container.INamedContainerProvider;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.network.PacketBuffer; import net.minecraft.network.PacketBuffer;
import net.minecraft.tileentity.ITickableTileEntity; import net.minecraft.tileentity.ITickableTileEntity;
@ -102,6 +103,7 @@ public class SchematicTableTileEntity extends SyncedTileEntity implements ITicka
uploadingProgress = 0; uploadingProgress = 0;
uploadingSchematic = schematic; uploadingSchematic = schematic;
sendUpdate = true; sendUpdate = true;
inventory.setStackInSlot(0, ItemStack.EMPTY);
} }
public void finishUpload() { public void finishUpload() {

View File

@ -17,7 +17,6 @@ import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.shapes.ISelectionContext; import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.world.IBlockReader; import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorldReader;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.fml.network.NetworkHooks; import net.minecraftforge.fml.network.NetworkHooks;
@ -52,11 +51,6 @@ public class SchematicannonBlock extends Block implements ITE<SchematicannonTile
return AllShapes.SCHEMATICANNON_SHAPE; return AllShapes.SCHEMATICANNON_SHAPE;
} }
@Override
public void onNeighborChange(BlockState state, IWorldReader world, BlockPos pos, BlockPos neighbor) {
withTileEntityDo(world, pos, SchematicannonTileEntity::findInventories);
}
@Override @Override
public boolean onBlockActivated(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand handIn, public boolean onBlockActivated(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand handIn,
BlockRayTraceResult hit) { BlockRayTraceResult hit) {

View File

@ -7,11 +7,14 @@ import com.simibubi.create.AllBlockPartials;
import com.simibubi.create.foundation.block.SafeTileEntityRenderer; import com.simibubi.create.foundation.block.SafeTileEntityRenderer;
import com.simibubi.create.foundation.utility.SuperByteBuffer; import com.simibubi.create.foundation.utility.SuperByteBuffer;
import com.simibubi.create.foundation.utility.TessellatorHelper; import com.simibubi.create.foundation.utility.TessellatorHelper;
import com.simibubi.create.modules.schematics.block.LaunchedItem.ForBlockState;
import com.simibubi.create.modules.schematics.block.LaunchedItem.ForEntity;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType;
import net.minecraft.client.renderer.texture.AtlasTexture; import net.minecraft.client.renderer.texture.AtlasTexture;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.particles.ParticleTypes; import net.minecraft.particles.ParticleTypes;
@ -20,6 +23,7 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
@SuppressWarnings("deprecation")
public class SchematicannonRenderer extends SafeTileEntityRenderer<SchematicannonTileEntity> { public class SchematicannonRenderer extends SafeTileEntityRenderer<SchematicannonTileEntity> {
@Override @Override
@ -56,14 +60,14 @@ public class SchematicannonRenderer extends SafeTileEntityRenderer<Schematicanno
} }
if (!tileEntityIn.flyingBlocks.isEmpty()) { if (!tileEntityIn.flyingBlocks.isEmpty()) {
for (LaunchedBlock block : tileEntityIn.flyingBlocks) { for (LaunchedItem launched : tileEntityIn.flyingBlocks) {
if (block.ticksRemaining == 0) if (launched.ticksRemaining == 0)
continue; continue;
// Calculate position of flying block // Calculate position of flying block
Vec3d start = new Vec3d(tileEntityIn.getPos().add(.5f, 1, .5f)); Vec3d start = new Vec3d(tileEntityIn.getPos().add(.5f, 1, .5f));
Vec3d target = new Vec3d(block.target).add(-.5, 0, 1); Vec3d target = new Vec3d(launched.target).add(-.5, 0, 1);
Vec3d distance = target.subtract(start); Vec3d distance = target.subtract(start);
double targetY = target.y - start.y; double targetY = target.y - start.y;
@ -71,10 +75,10 @@ public class SchematicannonRenderer extends SafeTileEntityRenderer<Schematicanno
Vec3d cannonOffset = distance.add(0, throwHeight, 0).normalize().scale(2); Vec3d cannonOffset = distance.add(0, throwHeight, 0).normalize().scale(2);
start = start.add(cannonOffset); start = start.add(cannonOffset);
double progress = ((double) block.totalTicks - (block.ticksRemaining + 1 - partialTicks)) double progress =
/ block.totalTicks; ((double) launched.totalTicks - (launched.ticksRemaining + 1 - partialTicks)) / launched.totalTicks;
Vec3d blockLocationXZ = new Vec3d(x + .5, y + .5, z + .5) Vec3d blockLocationXZ =
.add(target.subtract(start).scale(progress).mul(1, 0, 1)); new Vec3d(x + .5, y + .5, z + .5).add(target.subtract(start).scale(progress).mul(1, 0, 1));
// Height is determined through a bezier curve // Height is determined through a bezier curve
double t = progress; double t = progress;
@ -86,21 +90,32 @@ public class SchematicannonRenderer extends SafeTileEntityRenderer<Schematicanno
GlStateManager.translated(blockLocation.x, blockLocation.y, blockLocation.z); GlStateManager.translated(blockLocation.x, blockLocation.y, blockLocation.z);
// Rotation and Scaling effects // Rotation and Scaling effects
double scale = .3f;
GlStateManager.rotated(360 * t * 2, 1, 1, 0); GlStateManager.rotated(360 * t * 2, 1, 1, 0);
GlStateManager.scaled(scale, scale, scale);
// Render the Block // Render the Block
Minecraft.getInstance().getBlockRendererDispatcher().renderBlockBrightness(block.state, 1); if (launched instanceof ForBlockState) {
double scale = .3f;
GlStateManager.scaled(scale, scale, scale);
Minecraft.getInstance().getBlockRendererDispatcher()
.renderBlockBrightness(((ForBlockState) launched).state, 1);
}
// Render the item
if (launched instanceof ForEntity) {
double scale = 1.2f;
GlStateManager.scaled(scale, scale, scale);
Minecraft.getInstance().getItemRenderer().renderItem(launched.stack, TransformType.GROUND);
}
GlStateManager.popMatrix(); GlStateManager.popMatrix();
// Apply Recoil if block was just launched // Apply Recoil if block was just launched
if ((block.ticksRemaining + 1 - partialTicks) > block.totalTicks - 10) { if ((launched.ticksRemaining + 1 - partialTicks) > launched.totalTicks - 10) {
recoil = Math.max(recoil, (block.ticksRemaining + 1 - partialTicks) - block.totalTicks + 10); recoil = Math.max(recoil, (launched.ticksRemaining + 1 - partialTicks) - launched.totalTicks + 10);
} }
// Render particles for launch // Render particles for launch
if (block.ticksRemaining == block.totalTicks && tileEntityIn.firstRenderTick) { if (launched.ticksRemaining == launched.totalTicks && tileEntityIn.firstRenderTick) {
tileEntityIn.firstRenderTick = false; tileEntityIn.firstRenderTick = false;
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
Random r = tileEntityIn.getWorld().getRandom(); Random r = tileEntityIn.getWorld().getRandom();

View File

@ -26,7 +26,6 @@ import net.minecraft.client.gui.widget.Widget;
import net.minecraft.client.renderer.Rectangle2d; import net.minecraft.client.renderer.Rectangle2d;
import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.entity.player.PlayerInventory; import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextFormatting; import net.minecraft.util.text.TextFormatting;
@ -89,9 +88,8 @@ public class SchematicannonScreen extends AbstractSimiContainerScreen<Schematica
// Replace settings // Replace settings
replaceLevelButtons = new Vector<>(4); replaceLevelButtons = new Vector<>(4);
replaceLevelIndicators = new Vector<>(4); replaceLevelIndicators = new Vector<>(4);
List<ScreenResources> icons = ImmutableList.of(ScreenResources.I_DONT_REPLACE, List<ScreenResources> icons = ImmutableList.of(ScreenResources.I_DONT_REPLACE, ScreenResources.I_REPLACE_SOLID,
ScreenResources.I_REPLACE_SOLID, ScreenResources.I_REPLACE_ANY, ScreenResources.I_REPLACE_ANY, ScreenResources.I_REPLACE_EMPTY);
ScreenResources.I_REPLACE_EMPTY);
List<String> toolTips = ImmutableList.of(Lang.translate("gui.schematicannon.option.dontReplaceSolid"), List<String> toolTips = ImmutableList.of(Lang.translate("gui.schematicannon.option.dontReplaceSolid"),
Lang.translate("gui.schematicannon.option.replaceWithSolid"), Lang.translate("gui.schematicannon.option.replaceWithSolid"),
Lang.translate("gui.schematicannon.option.replaceWithAny"), Lang.translate("gui.schematicannon.option.replaceWithAny"),
@ -215,10 +213,9 @@ public class SchematicannonScreen extends AbstractSimiContainerScreen<Schematica
String msg = Lang.translate("schematicannon.status." + te.statusMsg); String msg = Lang.translate("schematicannon.status." + te.statusMsg);
int stringWidth = font.getStringWidth(msg); int stringWidth = font.getStringWidth(msg);
if (te.missingBlock != null) { if (te.missingItem != null) {
stringWidth += 15; stringWidth += 15;
itemRenderer.renderItemIntoGUI(new ItemStack(BlockItem.BLOCK_TO_ITEM.get(te.missingBlock.getBlock())), itemRenderer.renderItemIntoGUI(te.missingItem, guiLeft + 145, guiTop + 25);
guiLeft + 145, guiTop + 25);
} }
font.drawStringWithShadow(msg, guiLeft + 20 + 96 - stringWidth / 2, guiTop + 30, 0xCCDDFF); font.drawStringWithShadow(msg, guiLeft + 20 + 96 - stringWidth / 2, guiTop + 30, 0xCCDDFF);
@ -227,9 +224,10 @@ public class SchematicannonScreen extends AbstractSimiContainerScreen<Schematica
font.drawString(playerInventory.getDisplayName().getFormattedText(), guiLeft - 10 + 7, guiTop + 145 + 6, font.drawString(playerInventory.getDisplayName().getFormattedText(), guiLeft - 10 + 7, guiTop + 145 + 6,
0x666666); 0x666666);
//to see or debug the bounds of the extra area uncomment the following lines // to see or debug the bounds of the extra area uncomment the following lines
//Rectangle2d r = extraAreas.get(0); // Rectangle2d r = extraAreas.get(0);
//fill(r.getX() + r.getWidth(), r.getY() + r.getHeight(), r.getX(), r.getY(), 0xd3d3d3d3); // fill(r.getX() + r.getWidth(), r.getY() + r.getHeight(), r.getX(), r.getY(),
// 0xd3d3d3d3);
} }
protected void renderCannon() { protected void renderCannon() {
@ -282,21 +280,27 @@ public class SchematicannonScreen extends AbstractSimiContainerScreen<Schematica
if (mouseX >= fuelX && mouseY >= fuelY && mouseX <= fuelX + ScreenResources.SCHEMATICANNON_FUEL.width if (mouseX >= fuelX && mouseY >= fuelY && mouseX <= fuelX + ScreenResources.SCHEMATICANNON_FUEL.width
&& mouseY <= fuelY + ScreenResources.SCHEMATICANNON_FUEL.height) { && mouseY <= fuelY + ScreenResources.SCHEMATICANNON_FUEL.height) {
container.getTileEntity(); container.getTileEntity();
double fuelUsageRate = te.getFuelUsageRate(); double fuelUsageRate = te.getFuelUsageRate();
int shotsLeft = (int) (te.fuelLevel / fuelUsageRate); int shotsLeft = (int) (te.fuelLevel / fuelUsageRate);
int shotsLeftWithItems = (int) (shotsLeft int shotsLeftWithItems = (int) (shotsLeft
+ te.inventory.getStackInSlot(4).getCount() * (te.getFuelAddedByGunPowder() / fuelUsageRate)); + te.inventory.getStackInSlot(4).getCount() * (te.getFuelAddedByGunPowder() / fuelUsageRate));
renderTooltip(ImmutableList.of(Lang.translate(_gunpowderLevel, "" + (int) (te.fuelLevel * 100)),
GRAY + Lang.translate(_shotsRemaining, "" + TextFormatting.BLUE + shotsLeft), List<String> tooltip = new ArrayList<>();
GRAY + Lang.translate(_shotsRemainingWithBackup, "" + TextFormatting.BLUE + shotsLeftWithItems)), tooltip.add(Lang.translate(_gunpowderLevel, "" + (int) (te.fuelLevel * 100)));
mouseX, mouseY); tooltip.add(GRAY + Lang.translate(_shotsRemaining, "" + TextFormatting.BLUE + shotsLeft));
if (shotsLeftWithItems != shotsLeft)
tooltip.add(GRAY
+ Lang.translate(_shotsRemainingWithBackup, "" + TextFormatting.BLUE + shotsLeftWithItems));
renderTooltip(tooltip, mouseX, mouseY);
} }
if (te.missingBlock != null) { if (te.missingItem != null) {
int missingBlockX = guiLeft + 145, missingBlockY = guiTop + 25; int missingBlockX = guiLeft + 145, missingBlockY = guiTop + 25;
if (mouseX >= missingBlockX && mouseY >= missingBlockY && mouseX <= missingBlockX + 16 if (mouseX >= missingBlockX && mouseY >= missingBlockY && mouseX <= missingBlockX + 16
&& mouseY <= missingBlockY + 16) { && mouseY <= missingBlockY + 16) {
renderTooltip(new ItemStack(BlockItem.BLOCK_TO_ITEM.get(te.missingBlock.getBlock())), mouseX, mouseY); renderTooltip(te.missingItem, mouseX, mouseY);
} }
} }

View File

@ -11,6 +11,10 @@ import com.simibubi.create.config.AllConfigs;
import com.simibubi.create.config.CSchematics; import com.simibubi.create.config.CSchematics;
import com.simibubi.create.foundation.behaviour.base.SmartTileEntity; import com.simibubi.create.foundation.behaviour.base.SmartTileEntity;
import com.simibubi.create.foundation.behaviour.base.TileEntityBehaviour; import com.simibubi.create.foundation.behaviour.base.TileEntityBehaviour;
import com.simibubi.create.foundation.item.ItemHelper;
import com.simibubi.create.foundation.item.ItemHelper.ExtractionCountMode;
import com.simibubi.create.modules.schematics.ItemRequirement;
import com.simibubi.create.modules.schematics.ItemRequirement.ItemUseType;
import com.simibubi.create.modules.schematics.MaterialChecklist; import com.simibubi.create.modules.schematics.MaterialChecklist;
import com.simibubi.create.modules.schematics.SchematicWorld; import com.simibubi.create.modules.schematics.SchematicWorld;
import com.simibubi.create.modules.schematics.item.SchematicItem; import com.simibubi.create.modules.schematics.item.SchematicItem;
@ -18,6 +22,7 @@ import com.simibubi.create.modules.schematics.item.SchematicItem;
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;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory; import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.inventory.container.Container; import net.minecraft.inventory.container.Container;
@ -33,7 +38,6 @@ import net.minecraft.network.PacketBuffer;
import net.minecraft.state.properties.BedPart; import net.minecraft.state.properties.BedPart;
import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.state.properties.DoubleBlockHalf; import net.minecraft.state.properties.DoubleBlockHalf;
import net.minecraft.state.properties.SlabType;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType; import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
@ -48,6 +52,7 @@ import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemHandlerHelper;
public class SchematicannonTileEntity extends SmartTileEntity implements INamedContainerProvider { public class SchematicannonTileEntity extends SmartTileEntity implements INamedContainerProvider {
@ -71,17 +76,18 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
public BlockPos currentPos; public BlockPos currentPos;
public BlockPos schematicAnchor; public BlockPos schematicAnchor;
public boolean schematicLoaded; public boolean schematicLoaded;
public BlockState missingBlock; public ItemStack missingItem;
public boolean blockNotLoaded; public boolean positionNotLoaded;
public boolean hasCreativeCrate; public boolean hasCreativeCrate;
private int printerCooldown; private int printerCooldown;
private int skipsLeft; private int skipsLeft;
private boolean blockSkipped; private boolean blockSkipped;
private int printingEntityIndex;
public BlockPos target; public BlockPos target;
public BlockPos previousTarget; public BlockPos previousTarget;
public List<IItemHandler> attachedInventories; public List<IItemHandler> attachedInventories;
public List<LaunchedBlock> flyingBlocks; public List<LaunchedItem> flyingBlocks;
public MaterialChecklist checklist; public MaterialChecklist checklist;
// Gui information // Gui information
@ -124,6 +130,7 @@ 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;
replaceMode = 2; replaceMode = 2;
neighbourCheckCooldown = NEIGHBOUR_CHECKING; neighbourCheckCooldown = NEIGHBOUR_CHECKING;
checklist = new MaterialChecklist(); checklist = new MaterialChecklist();
@ -143,8 +150,8 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
TileEntity tileEntity = world.getTileEntity(pos.offset(facing)); TileEntity tileEntity = world.getTileEntity(pos.offset(facing));
if (tileEntity != null) { if (tileEntity != null) {
LazyOptional<IItemHandler> capability = tileEntity LazyOptional<IItemHandler> capability =
.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, facing.getOpposite()); tileEntity.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, facing.getOpposite());
if (capability.isPresent()) { if (capability.isPresent()) {
attachedInventories.add(capability.orElse(null)); attachedInventories.add(capability.orElse(null));
} }
@ -174,11 +181,11 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
state = State.valueOf(compound.getString("State")); state = State.valueOf(compound.getString("State"));
blocksPlaced = compound.getInt("AmountPlaced"); blocksPlaced = compound.getInt("AmountPlaced");
blocksToPlace = compound.getInt("AmountToPlace"); blocksToPlace = compound.getInt("AmountToPlace");
printingEntityIndex = compound.getInt("EntityProgress");
if (compound.contains("MissingBlock")) missingItem = null;
missingBlock = NBTUtil.readBlockState(compound.getCompound("MissingBlock")); if (compound.contains("MissingItem"))
else missingItem = ItemStack.read(compound.getCompound("MissingItem"));
missingBlock = null;
// Settings // Settings
CompoundNBT options = compound.getCompound("Options"); CompoundNBT options = compound.getCompound("Options");
@ -203,15 +210,12 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
for (int i = 0; i < tagBlocks.size(); i++) { for (int i = 0; i < tagBlocks.size(); i++) {
CompoundNBT c = tagBlocks.getCompound(i); CompoundNBT c = tagBlocks.getCompound(i);
LaunchedItem launched = LaunchedItem.fromNBT(c);
BlockPos readBlockPos = NBTUtil.readBlockPos(c.getCompound("Target")); BlockPos readBlockPos = launched.target;
BlockState readBlockState = NBTUtil.readBlockState(c.getCompound("Block"));
int int1 = c.getInt("TicksLeft");
int int2 = c.getInt("TotalTicks");
// Always write to Server tile // Always write to Server tile
if (world == null || !world.isRemote) { if (world == null || !world.isRemote) {
flyingBlocks.add(new LaunchedBlock(this, readBlockPos, readBlockState, int1, int2)); flyingBlocks.add(launched);
continue; continue;
} }
@ -224,7 +228,7 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
// Add new server side blocks // Add new server side blocks
if (i >= flyingBlocks.size()) { if (i >= flyingBlocks.size()) {
flyingBlocks.add(new LaunchedBlock(this, readBlockPos, readBlockState, int1, int2)); flyingBlocks.add(launched);
continue; continue;
} }
@ -256,9 +260,10 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
compound.putString("State", state.name()); compound.putString("State", state.name());
compound.putInt("AmountPlaced", blocksPlaced); compound.putInt("AmountPlaced", blocksPlaced);
compound.putInt("AmountToPlace", blocksToPlace); compound.putInt("AmountToPlace", blocksToPlace);
compound.putInt("EntityProgress", printingEntityIndex);
if (missingBlock != null) if (missingItem != null)
compound.put("MissingBlock", NBTUtil.writeBlockState(missingBlock)); compound.put("MissingItem", missingItem.serializeNBT());
// Settings // Settings
CompoundNBT options = new CompoundNBT(); CompoundNBT options = new CompoundNBT();
@ -271,14 +276,8 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
if (target != null) if (target != null)
compound.put("Target", NBTUtil.writeBlockPos(target)); compound.put("Target", NBTUtil.writeBlockPos(target));
ListNBT tagBlocks = new ListNBT(); ListNBT tagBlocks = new ListNBT();
for (LaunchedBlock b : flyingBlocks) { for (LaunchedItem b : flyingBlocks)
CompoundNBT c = new CompoundNBT(); tagBlocks.add(b.serializeNBT());
c.putInt("TotalTicks", b.totalTicks);
c.putInt("TicksLeft", b.ticksRemaining);
c.put("Target", NBTUtil.writeBlockPos(b.target));
c.put("Block", NBTUtil.writeBlockState(b.state));
tagBlocks.add(c);
}
compound.put("FlyingBlocks", tagBlocks); compound.put("FlyingBlocks", tagBlocks);
return compound; return compound;
@ -287,7 +286,7 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
@Override @Override
public void tick() { public void tick() {
super.tick(); super.tick();
if (neighbourCheckCooldown-- <= 0) { if (neighbourCheckCooldown-- <= 0) {
neighbourCheckCooldown = NEIGHBOUR_CHECKING; neighbourCheckCooldown = NEIGHBOUR_CHECKING;
findInventories(); findInventories();
@ -344,7 +343,7 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
return; return;
} }
if (state == State.PAUSED && !blockNotLoaded && missingBlock == null && fuelLevel > getFuelUsageRate()) if (state == State.PAUSED && !positionNotLoaded && missingItem == null && fuelLevel > getFuelUsageRate())
return; return;
// Initialize Printer // Initialize Printer
@ -370,13 +369,13 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
// Update Target // Update Target
if (hasCreativeCrate) { if (hasCreativeCrate) {
if (missingBlock != null) { if (missingItem != null) {
missingBlock = null; missingItem = null;
state = State.RUNNING; state = State.RUNNING;
} }
} }
if (missingBlock == null && !blockNotLoaded) { if (missingItem == null && !positionNotLoaded) {
advanceCurrentPos(); advanceCurrentPos();
// End reached // End reached
@ -387,61 +386,83 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
target = schematicAnchor.add(currentPos); target = schematicAnchor.add(currentPos);
} }
boolean entityMode = printingEntityIndex >= 0;
// Check block // Check block
if (!getWorld().isAreaLoaded(target, 0)) { if (!getWorld().isAreaLoaded(target, 0)) {
blockNotLoaded = true; positionNotLoaded = true;
statusMsg = "targetNotLoaded"; statusMsg = "targetNotLoaded";
state = State.PAUSED; state = State.PAUSED;
return; return;
} else { } else {
if (blockNotLoaded) { if (positionNotLoaded) {
blockNotLoaded = false; positionNotLoaded = false;
state = State.RUNNING; state = State.RUNNING;
} }
} }
BlockState blockState = blockReader.getBlockState(target); boolean shouldSkip = false;
ItemStack requiredItem = getItemForBlock(blockState); BlockState blockState = Blocks.AIR.getDefaultState();
ItemRequirement requirement;
if (!shouldPlace(target, blockState) || requiredItem.isEmpty()) { if (entityMode) {
requirement = ItemRequirement.of(blockReader.getEntities().get(printingEntityIndex));
} else {
blockState = blockReader.getBlockState(target);
requirement = ItemRequirement.of(blockState);
shouldSkip = !shouldPlace(target, blockState);
}
if (shouldSkip || requirement.isInvalid()) {
statusMsg = "searching"; statusMsg = "searching";
blockSkipped = true; blockSkipped = true;
return; return;
} }
// Find item // Find item
if (blockState.has(BlockStateProperties.SLAB_TYPE) List<ItemStack> requiredItems = requirement.getRequiredItems();
&& blockState.get(BlockStateProperties.SLAB_TYPE) == SlabType.DOUBLE) if (!requirement.isEmpty()) {
requiredItem.setCount(2); for (ItemStack required : requiredItems) {
if (!grabItemsFromAttachedInventories(required, requirement.getUsage(), true)) {
if (skipMissing) {
statusMsg = "skipping";
blockSkipped = true;
if (missingItem != null) {
missingItem = null;
state = State.RUNNING;
}
return;
}
if (!findItemInAttachedInventories(requiredItem)) { missingItem = required;
if (skipMissing) { state = State.PAUSED;
statusMsg = "skipping"; statusMsg = "missingBlock";
blockSkipped = true; return;
if (missingBlock != null) {
missingBlock = null;
state = State.RUNNING;
} }
return;
} }
missingBlock = blockState; for (ItemStack required : requiredItems)
state = State.PAUSED; grabItemsFromAttachedInventories(required, requirement.getUsage(), false);
statusMsg = "missingBlock";
return;
} }
// Success // Success
state = State.RUNNING; state = State.RUNNING;
if (blockState.getBlock() != Blocks.AIR) if (blockState.getBlock() != Blocks.AIR || entityMode)
statusMsg = "placing"; statusMsg = "placing";
else else
statusMsg = "clearing"; statusMsg = "clearing";
launchBlock(target, blockState);
ItemStack icon = requirement.isEmpty() || requiredItems.isEmpty() ? ItemStack.EMPTY : requiredItems.get(0);
if (entityMode)
launchEntity(target, icon, blockReader.getEntities().get(printingEntityIndex));
else
launchBlock(target, icon, blockState);
printerCooldown = config().schematicannonDelay.get(); printerCooldown = config().schematicannonDelay.get();
fuelLevel -= getFuelUsageRate(); fuelLevel -= getFuelUsageRate();
sendUpdate = true; sendUpdate = true;
missingBlock = null; missingItem = null;
} }
public double getFuelUsageRate() { public double getFuelUsageRate() {
@ -487,6 +508,7 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
schematicLoaded = true; schematicLoaded = true;
state = State.PAUSED; state = State.PAUSED;
statusMsg = "ready"; statusMsg = "ready";
printingEntityIndex = -1;
updateChecklist(); updateChecklist();
sendUpdate = true; sendUpdate = true;
blocksToPlace += blocksPlaced; blocksToPlace += blocksPlaced;
@ -498,44 +520,82 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
return item == Items.AIR ? ItemStack.EMPTY : new ItemStack(item); return item == Items.AIR ? ItemStack.EMPTY : new ItemStack(item);
} }
protected boolean findItemInAttachedInventories(ItemStack requiredItem) { protected boolean grabItemsFromAttachedInventories(ItemStack required, ItemUseType usage, boolean simulate) {
if (hasCreativeCrate) if (hasCreativeCrate)
return true; return true;
boolean two = requiredItem.getCount() == 2; // Find and apply damage
int lastSlot = -1; if (usage == ItemUseType.DAMAGE) {
for (IItemHandler iItemHandler : attachedInventories) {
for (int slot = 0; slot < iItemHandler.getSlots(); slot++) {
ItemStack extractItem = iItemHandler.extractItem(slot, 1, true);
if (!ItemRequirement.validate(required, extractItem))
continue;
if (!extractItem.isDamageable())
continue;
for (IItemHandler iItemHandler : attachedInventories) { if (!simulate) {
for (int slot = 0; slot < iItemHandler.getSlots(); slot++) { ItemStack stack = iItemHandler.extractItem(slot, 1, false);
ItemStack stackInSlot = iItemHandler.getStackInSlot(slot); stack.setDamage(stack.getDamage() + 1);
if (!stackInSlot.isItemEqual(requiredItem)) if (stack.getDamage() <= stack.getMaxDamage()) {
continue; if (iItemHandler.getStackInSlot(slot).isEmpty())
if (!two && !iItemHandler.extractItem(slot, 1, false).isEmpty()) iItemHandler.insertItem(slot, stack, false);
return true; else
ItemHandlerHelper.insertItem(iItemHandler, stack, false);
// Two Items required (Double slabs)
if (two) {
int count = iItemHandler.extractItem(slot, 2, true).getCount();
if (count == 2) {
iItemHandler.extractItem(slot, 2, false);
return true;
} else if (count == 1) {
if (lastSlot == -1)
lastSlot = slot;
else {
iItemHandler.extractItem(lastSlot, 1, false);
iItemHandler.extractItem(slot, 1, false);
return true;
} }
} }
}
return true;
}
} }
} }
return false;
// Find and remove
boolean success = false;
if (usage == ItemUseType.CONSUME) {
int amountFound = 0;
for (IItemHandler iItemHandler : attachedInventories) {
amountFound += ItemHelper.extract(iItemHandler, s -> ItemRequirement.validate(required, s),
ExtractionCountMode.UPTO, required.getCount(), true).getCount();
if (amountFound < required.getCount())
continue;
success = true;
break;
}
}
if (!simulate && success) {
int amountFound = 0;
for (IItemHandler iItemHandler : attachedInventories) {
amountFound += ItemHelper.extract(iItemHandler, s -> ItemRequirement.validate(required, s),
ExtractionCountMode.UPTO, required.getCount(), false).getCount();
if (amountFound < required.getCount())
continue;
break;
}
}
return success;
} }
protected void advanceCurrentPos() { protected void advanceCurrentPos() {
List<Entity> entities = blockReader.getEntities();
if (printingEntityIndex != -1) {
printingEntityIndex++;
// End of entities reached
if (printingEntityIndex >= entities.size()) {
finishedPrinting();
return;
}
currentPos = entities.get(printingEntityIndex).getPosition().subtract(schematicAnchor);
return;
}
BlockPos size = blockReader.getBounds().getSize(); BlockPos size = blockReader.getBounds().getSize();
currentPos = currentPos.offset(Direction.EAST); currentPos = currentPos.offset(Direction.EAST);
BlockPos posInBounds = currentPos.subtract(blockReader.getBounds().getOrigin()); BlockPos posInBounds = currentPos.subtract(blockReader.getBounds().getOrigin());
@ -545,29 +605,38 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
if (posInBounds.getZ() > size.getZ()) if (posInBounds.getZ() > size.getZ())
currentPos = new BlockPos(currentPos.getX(), currentPos.getY() + 1, blockReader.getBounds().z).west(); currentPos = new BlockPos(currentPos.getX(), currentPos.getY() + 1, blockReader.getBounds().z).west();
// End reached // End of blocks reached
if (currentPos.getY() > size.getY()) { if (currentPos.getY() > size.getY()) {
inventory.setStackInSlot(0, ItemStack.EMPTY); printingEntityIndex = 0;
inventory.setStackInSlot(1, if (entities.isEmpty()) {
new ItemStack(AllItems.EMPTY_BLUEPRINT.get(), inventory.getStackInSlot(1).getCount() + 1)); finishedPrinting();
state = State.STOPPED; return;
statusMsg = "finished"; }
resetPrinter(); currentPos = entities.get(0).getPosition().subtract(schematicAnchor);
target = getPos().add(1, 0, 0);
world.playSound(null, pos.getX(), pos.getY(), pos.getZ(), AllSoundEvents.SCHEMATICANNON_FINISH.get(),
SoundCategory.BLOCKS, 1, .7f);
sendUpdate = true;
return;
} }
} }
public void finishedPrinting() {
inventory.setStackInSlot(0, ItemStack.EMPTY);
inventory.setStackInSlot(1,
new ItemStack(AllItems.EMPTY_BLUEPRINT.get(), inventory.getStackInSlot(1).getCount() + 1));
state = State.STOPPED;
statusMsg = "finished";
resetPrinter();
target = getPos().add(1, 0, 0);
world.playSound(null, pos.getX(), pos.getY(), pos.getZ(), AllSoundEvents.SCHEMATICANNON_FINISH.get(),
SoundCategory.BLOCKS, 1, .7f);
sendUpdate = true;
}
protected void resetPrinter() { protected void resetPrinter() {
schematicLoaded = false; schematicLoaded = false;
schematicAnchor = null; schematicAnchor = null;
currentPos = null; currentPos = null;
blockReader = null; blockReader = null;
missingBlock = null; missingItem = null;
sendUpdate = true; sendUpdate = true;
printingEntityIndex = -1;
schematicProgress = 0; schematicProgress = 0;
blocksPlaced = 0; blocksPlaced = 0;
blocksToPlace = 0; blocksToPlace = 0;
@ -577,6 +646,10 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
BlockState toReplace = world.getBlockState(pos); BlockState toReplace = world.getBlockState(pos);
boolean placingAir = state.getBlock() == Blocks.AIR; boolean placingAir = state.getBlock() == Blocks.AIR;
if (!world.isBlockPresent(pos))
return false;
if (!world.getWorldBorder().contains(pos))
return false;
if (toReplace == state) if (toReplace == state)
return false; return false;
if (toReplace.getBlockHardness(world, pos) == -1) if (toReplace.getBlockHardness(world, pos) == -1)
@ -622,21 +695,10 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
} }
protected void tickFlyingBlocks() { protected void tickFlyingBlocks() {
List<LaunchedBlock> toRemove = new LinkedList<>(); List<LaunchedItem> toRemove = new LinkedList<>();
for (LaunchedBlock b : flyingBlocks) { for (LaunchedItem b : flyingBlocks)
b.update(); if (b.update(world))
if (b.ticksRemaining <= 0 && !world.isRemote) {
// Piston
if (b.state.has(BlockStateProperties.EXTENDED)) {
b.state = b.state.with(BlockStateProperties.EXTENDED, false);
}
world.setBlockState(b.target, b.state, 18);
b.state.getBlock().onBlockPlacedBy(world, b.target, b.state, null, getItemForBlock(b.state));
toRemove.add(b); toRemove.add(b);
}
}
flyingBlocks.removeAll(toRemove); flyingBlocks.removeAll(toRemove);
} }
@ -696,10 +758,20 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
sendUpdate = true; sendUpdate = true;
} }
protected void launchBlock(BlockPos target, BlockState state) { protected void launchBlock(BlockPos target, ItemStack stack, BlockState state) {
if (state.getBlock() != Blocks.AIR) if (state.getBlock() != Blocks.AIR)
blocksPlaced++; blocksPlaced++;
flyingBlocks.add(new LaunchedBlock(this, target, state)); flyingBlocks.add(new LaunchedItem.ForBlockState(this.getPos(), target, stack, state));
playFiringSound();
}
protected void launchEntity(BlockPos target, ItemStack stack, Entity entity) {
blocksPlaced++;
flyingBlocks.add(new LaunchedItem.ForEntity(this.getPos(), target, stack, entity));
playFiringSound();
}
public void playFiringSound() {
world.playSound(null, pos.getX(), pos.getY(), pos.getZ(), AllSoundEvents.SCHEMATICANNON_LAUNCH_BLOCK.get(), world.playSound(null, pos.getX(), pos.getY(), pos.getZ(), AllSoundEvents.SCHEMATICANNON_LAUNCH_BLOCK.get(),
SoundCategory.BLOCKS, .1f, 1.1f); SoundCategory.BLOCKS, .1f, 1.1f);
} }
@ -721,6 +793,7 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
public void updateChecklist() { public void updateChecklist() {
checklist.required.clear(); checklist.required.clear();
checklist.damageRequired.clear();
checklist.blocksNotLoaded = false; checklist.blocksNotLoaded = false;
if (schematicLoaded) { if (schematicLoaded) {
@ -734,18 +807,22 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
} }
if (!shouldPlace(pos.add(schematicAnchor), required)) if (!shouldPlace(pos.add(schematicAnchor), required))
continue; continue;
ItemStack requiredItem = getItemForBlock(required); ItemRequirement requirement = ItemRequirement.of(required);
if (requiredItem.isEmpty()) if (requirement.isEmpty())
continue; continue;
if (requirement.isInvalid())
// Two items for double slabs continue;
if (required.has(BlockStateProperties.SLAB_TYPE) checklist.require(requirement);
&& required.get(BlockStateProperties.SLAB_TYPE) == SlabType.DOUBLE)
checklist.require(requiredItem.getItem());
checklist.require(requiredItem.getItem());
blocksToPlace++; blocksToPlace++;
} }
for (Entity entity : blockReader.getEntities()) {
ItemRequirement requirement = ItemRequirement.of(entity);
if (requirement.isEmpty())
continue;
if (requirement.isInvalid())
continue;
checklist.require(requirement);
}
} }
checklist.gathered.clear(); checklist.gathered.clear();
for (IItemHandler inventory : attachedInventories) { for (IItemHandler inventory : attachedInventories) {
@ -762,7 +839,7 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
@Override @Override
public void addBehaviours(List<TileEntityBehaviour> behaviours) { public void addBehaviours(List<TileEntityBehaviour> behaviours) {
} }
@Override @Override
public void lazyTick() { public void lazyTick() {
super.lazyTick(); super.lazyTick();

View File

@ -225,7 +225,7 @@ public class SchematicAndQuillHandler {
Template t = new Template(); Template t = new Template();
MutableBoundingBox bb = new MutableBoundingBox(firstPos, secondPos); MutableBoundingBox bb = new MutableBoundingBox(firstPos, secondPos);
t.takeBlocksFromWorld(Minecraft.getInstance().world, new BlockPos(bb.minX, bb.minY, bb.minZ), t.takeBlocksFromWorld(Minecraft.getInstance().world, new BlockPos(bb.minX, bb.minY, bb.minZ),
new BlockPos(bb.getXSize(), bb.getYSize(), bb.getZSize()), false, Blocks.AIR); new BlockPos(bb.getXSize(), bb.getYSize(), bb.getZSize()), true, Blocks.AIR);
if (string.isEmpty()) if (string.isEmpty())
string = Lang.translate("schematicAndQuill.fallbackName"); string = Lang.translate("schematicAndQuill.fallbackName");

View File

@ -9,6 +9,7 @@ import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTUtil; import net.minecraft.nbt.NBTUtil;
import net.minecraft.network.PacketBuffer; import net.minecraft.network.PacketBuffer;
import net.minecraft.world.gen.feature.template.PlacementSettings;
import net.minecraft.world.gen.feature.template.Template; import net.minecraft.world.gen.feature.template.Template;
import net.minecraftforge.fml.network.NetworkEvent.Context; import net.minecraftforge.fml.network.NetworkEvent.Context;
@ -32,8 +33,10 @@ public class SchematicPlacePacket extends SimplePacketBase {
context.get().enqueueWork(() -> { context.get().enqueueWork(() -> {
ServerPlayerEntity player = context.get().getSender(); ServerPlayerEntity player = context.get().getSender();
Template t = SchematicItem.loadSchematic(stack); Template t = SchematicItem.loadSchematic(stack);
PlacementSettings settings = SchematicItem.getSettings(stack);
settings.setIgnoreEntities(false);
t.addBlocksToWorld(player.getServerWorld(), NBTUtil.readBlockPos(stack.getTag().getCompound("Anchor")), t.addBlocksToWorld(player.getServerWorld(), NBTUtil.readBlockPos(stack.getTag().getCompound("Anchor")),
SchematicItem.getSettings(stack)); settings);
}); });
context.get().setPacketHandled(true); context.get().setPacketHandled(true);
} }

View File

@ -534,11 +534,11 @@
"create.schematicannon.status.paused": "Paused", "create.schematicannon.status.paused": "Paused",
"create.schematicannon.status.stopped": "Stopped", "create.schematicannon.status.stopped": "Stopped",
"create.schematicannon.status.noGunpowder": "Out of Gunpowder", "create.schematicannon.status.noGunpowder": "Out of Gunpowder",
"create.schematicannon.status.targetNotLoaded": "Block is Not Loaded", "create.schematicannon.status.targetNotLoaded": "Target is not loaded",
"create.schematicannon.status.targetOutsideRange": "Target too Far Away", "create.schematicannon.status.targetOutsideRange": "Target too far away",
"create.schematicannon.status.searching": "Searching", "create.schematicannon.status.searching": "Searching",
"create.schematicannon.status.skipping": "Skipping", "create.schematicannon.status.skipping": "Skipping",
"create.schematicannon.status.missingBlock": "Missing Block:", "create.schematicannon.status.missingBlock": "Missing Item:",
"create.schematicannon.status.placing": "Placing", "create.schematicannon.status.placing": "Placing",
"create.schematicannon.status.clearing": "Clearing Blocks", "create.schematicannon.status.clearing": "Clearing Blocks",
"create.schematicannon.status.schematicInvalid": "Schematic Invalid", "create.schematicannon.status.schematicInvalid": "Schematic Invalid",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 258 B

After

Width:  |  Height:  |  Size: 401 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 508 B

After

Width:  |  Height:  |  Size: 444 B