mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-12-15 21:03:41 +01:00
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:
parent
8bfc4445b0
commit
c4513020df
23 changed files with 696 additions and 242 deletions
|
@ -127,17 +127,27 @@ public class ItemHelper {
|
|||
return false;
|
||||
}
|
||||
|
||||
public static enum ExtractionCountMode {
|
||||
EXACTLY, UPTO
|
||||
}
|
||||
|
||||
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) {
|
||||
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;
|
||||
boolean amountRequired = exactAmount != -1;
|
||||
boolean amountRequired = mode == ExtractionCountMode.EXACTLY;
|
||||
boolean checkHasEnoughItems = amountRequired;
|
||||
boolean hasEnoughItems = !checkHasEnoughItems;
|
||||
int maxExtractionCount = hasEnoughItems ? AllConfigs.SERVER.logistics.extractorAmount.get() : exactAmount;
|
||||
boolean potentialOtherMatch = false;
|
||||
int maxExtractionCount = amount;
|
||||
|
||||
Extraction: do {
|
||||
extracting = ItemStack.EMPTY;
|
||||
|
@ -186,7 +196,7 @@ public class ItemHelper {
|
|||
|
||||
} while (true);
|
||||
|
||||
if (amountRequired && extracting.getCount() < exactAmount)
|
||||
if (amountRequired && extracting.getCount() < amount)
|
||||
return ItemStack.EMPTY;
|
||||
|
||||
return extracting;
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
package com.simibubi.create.modules.contraptions.components.actors;
|
||||
|
||||
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.MovementBehaviour;
|
||||
import com.simibubi.create.modules.contraptions.components.contraptions.MovementContext;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.FallingBlock;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.item.ItemEntity;
|
||||
import net.minecraft.entity.item.minecart.AbstractMinecartEntity;
|
||||
|
|
|
@ -9,6 +9,7 @@ import net.minecraft.network.PacketBuffer;
|
|||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.fml.DistExecutor;
|
||||
import net.minecraftforge.fml.network.NetworkEvent.Context;
|
||||
|
||||
|
@ -36,6 +37,7 @@ public class GlueEffectPacket extends SimplePacketBase {
|
|||
buffer.writeBoolean(fullBlock);
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public void handle(Supplier<Context> context) {
|
||||
context.get().enqueueWork(() -> DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
|
|
|
@ -8,6 +8,9 @@ import com.simibubi.create.AllEntities;
|
|||
import com.simibubi.create.AllItems;
|
||||
import com.simibubi.create.AllPackets;
|
||||
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.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.PacketDistributor;
|
||||
|
||||
public class SuperGlueEntity extends Entity implements IEntityAdditionalSpawnData {
|
||||
public class SuperGlueEntity extends Entity implements IEntityAdditionalSpawnData, ISpecialEntityItemRequirement {
|
||||
|
||||
private int validationTimer;
|
||||
protected BlockPos hangingPosition;
|
||||
|
@ -64,7 +67,8 @@ public class SuperGlueEntity extends Entity implements IEntityAdditionalSpawnDat
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void registerData() {}
|
||||
protected void registerData() {
|
||||
}
|
||||
|
||||
public int getWidthPixels() {
|
||||
return 12;
|
||||
|
@ -104,34 +108,32 @@ public class SuperGlueEntity extends Entity implements IEntityAdditionalSpawnDat
|
|||
|
||||
protected void updateBoundingBox() {
|
||||
if (this.getFacingDirection() != null) {
|
||||
this.posX =
|
||||
(double) this.hangingPosition.getX() + 0.5 - (double) this.getFacingDirection().getXOffset() * 0.5;
|
||||
this.posY =
|
||||
(double) this.hangingPosition.getY() + 0.5 - (double) this.getFacingDirection().getYOffset() * 0.5;
|
||||
this.posZ =
|
||||
(double) this.hangingPosition.getZ() + 0.5 - (double) this.getFacingDirection().getZOffset() * 0.5;
|
||||
double d1 = (double) this.getWidthPixels();
|
||||
double d2 = (double) this.getHeightPixels();
|
||||
double d3 = (double) this.getWidthPixels();
|
||||
double offset = 0.5 - 1 / 256d;
|
||||
this.posX = hangingPosition.getX() + 0.5 - facingDirection.getXOffset() * offset;
|
||||
this.posY = hangingPosition.getY() + 0.5 - facingDirection.getYOffset() * offset;
|
||||
this.posZ = hangingPosition.getZ() + 0.5 - facingDirection.getZOffset() * offset;
|
||||
double w = getWidthPixels();
|
||||
double h = getHeightPixels();
|
||||
double l = getWidthPixels();
|
||||
Axis axis = this.getFacingDirection().getAxis();
|
||||
double depth = 2 - 1 / 128f;
|
||||
|
||||
switch (axis) {
|
||||
case X:
|
||||
d1 = depth;
|
||||
w = depth;
|
||||
break;
|
||||
case Y:
|
||||
d2 = depth;
|
||||
h = depth;
|
||||
break;
|
||||
case Z:
|
||||
d3 = depth;
|
||||
l = depth;
|
||||
}
|
||||
|
||||
d1 = d1 / 32.0D;
|
||||
d2 = d2 / 32.0D;
|
||||
d3 = d3 / 32.0D;
|
||||
this.setBoundingBox(new AxisAlignedBB(this.posX - d1, this.posY - d2, this.posZ - d3, this.posX + d1,
|
||||
this.posY + d2, this.posZ + d3));
|
||||
w = w / 32.0D;
|
||||
h = h / 32.0D;
|
||||
l = l / 32.0D;
|
||||
this.setBoundingBox(new AxisAlignedBB(this.posX - w, this.posY - h, this.posZ - l, this.posX + w,
|
||||
this.posY + h, this.posZ + l));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -317,13 +319,13 @@ public class SuperGlueEntity extends Entity implements IEntityAdditionalSpawnDat
|
|||
if (this.getFacingDirection().getAxis() != Direction.Axis.Y) {
|
||||
switch (transformRotation) {
|
||||
case CLOCKWISE_180:
|
||||
this.facingDirection = this.getFacingDirection().getOpposite();
|
||||
facingDirection = facingDirection.getOpposite();
|
||||
break;
|
||||
case COUNTERCLOCKWISE_90:
|
||||
this.facingDirection = this.getFacingDirection().rotateYCCW();
|
||||
facingDirection = facingDirection.rotateYCCW();
|
||||
break;
|
||||
case CLOCKWISE_90:
|
||||
this.facingDirection = this.getFacingDirection().rotateY();
|
||||
facingDirection = facingDirection.rotateY();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -356,10 +358,12 @@ public class SuperGlueEntity extends Entity implements IEntityAdditionalSpawnDat
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onStruckByLightning(LightningBoltEntity lightningBolt) {}
|
||||
public void onStruckByLightning(LightningBoltEntity lightningBolt) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recalculateSize() {}
|
||||
public void recalculateSize() {
|
||||
}
|
||||
|
||||
public static EntityType.Builder<?> build(EntityType.Builder<?> builder) {
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -387,4 +391,10 @@ public class SuperGlueEntity extends Entity implements IEntityAdditionalSpawnDat
|
|||
public Direction getFacingDirection() {
|
||||
return facingDirection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemRequirement getRequiredItems() {
|
||||
return new ItemRequirement(ItemUseType.DAMAGE, AllItems.SUPER_GLUE.get());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.simibubi.create.modules.contraptions.relays.belt;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
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.relays.belt.transport.BeltMovementHandler.TransportedEntityInfo;
|
||||
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.BlockRenderType;
|
||||
|
@ -63,7 +67,7 @@ import net.minecraftforge.items.CapabilityItemHandler;
|
|||
import net.minecraftforge.items.IItemHandler;
|
||||
|
||||
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<Part> PART = EnumProperty.create("part", Part.class);
|
||||
|
@ -603,5 +607,19 @@ public class BeltBlock extends HorizontalKineticBlock
|
|||
public Class<BeltTileEntity> getTileEntityClass() {
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package com.simibubi.create.modules.schematics;
|
||||
|
||||
public interface ISpecialEntityItemRequirement {
|
||||
|
||||
default ItemRequirement getRequiredItems() {
|
||||
return ItemRequirement.INVALID;
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -7,6 +7,9 @@ import java.util.List;
|
|||
import java.util.Locale;
|
||||
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.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
|
@ -21,10 +24,12 @@ public class MaterialChecklist {
|
|||
|
||||
public Map<Item, Integer> gathered;
|
||||
public Map<Item, Integer> required;
|
||||
public Map<Item, Integer> damageRequired;
|
||||
public boolean blocksNotLoaded;
|
||||
|
||||
public MaterialChecklist() {
|
||||
required = new HashMap<>();
|
||||
damageRequired = new HashMap<>();
|
||||
gathered = new HashMap<>();
|
||||
}
|
||||
|
||||
|
@ -32,16 +37,33 @@ public class MaterialChecklist {
|
|||
blocksNotLoaded = true;
|
||||
}
|
||||
|
||||
public void require(Item item) {
|
||||
if (required.containsKey(item))
|
||||
required.put(item, required.get(item) + 1);
|
||||
public void require(ItemRequirement requirement) {
|
||||
if (requirement.isEmpty())
|
||||
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
|
||||
required.put(item, 1);
|
||||
map.put(item, stack.getCount());
|
||||
}
|
||||
|
||||
public void collect(ItemStack stack) {
|
||||
Item item = stack.getItem();
|
||||
if (required.containsKey(item))
|
||||
if (required.containsKey(item) || damageRequired.containsKey(item))
|
||||
if (gathered.containsKey(item))
|
||||
gathered.put(item, gathered.get(item) + stack.getCount());
|
||||
else
|
||||
|
@ -65,19 +87,19 @@ public class MaterialChecklist {
|
|||
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) -> {
|
||||
Locale locale = Locale.ENGLISH;
|
||||
String name1 = new TranslationTextComponent(((Item) item1).getTranslationKey()).getFormattedText()
|
||||
.toLowerCase(locale);
|
||||
String name2 = new TranslationTextComponent(((Item) item2).getTranslationKey()).getFormattedText()
|
||||
.toLowerCase(locale);
|
||||
String name1 =
|
||||
new TranslationTextComponent(((Item) item1).getTranslationKey()).getFormattedText().toLowerCase(locale);
|
||||
String name2 =
|
||||
new TranslationTextComponent(((Item) item2).getTranslationKey()).getFormattedText().toLowerCase(locale);
|
||||
return name1.compareTo(name2);
|
||||
});
|
||||
|
||||
List<Item> completed = new ArrayList<>();
|
||||
for (Item item : keys) {
|
||||
int amount = required.get(item);
|
||||
int amount = getRequiredAmount(item);
|
||||
if (gathered.containsKey(item))
|
||||
amount -= gathered.get(item);
|
||||
|
||||
|
@ -106,7 +128,7 @@ public class MaterialChecklist {
|
|||
}
|
||||
|
||||
itemsWritten++;
|
||||
string.append(gatheredEntry(new ItemStack(item), required.get(item)));
|
||||
string.append(gatheredEntry(new ItemStack(item), getRequiredAmount(item)));
|
||||
}
|
||||
|
||||
string.append("\"}");
|
||||
|
@ -120,6 +142,13 @@ public class MaterialChecklist {
|
|||
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) {
|
||||
int stacks = amount / 64;
|
||||
int remainder = amount % 64;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.simibubi.create.modules.schematics;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
@ -14,6 +15,8 @@ import net.minecraft.block.Block;
|
|||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
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.fluid.Fluid;
|
||||
import net.minecraft.fluid.IFluidState;
|
||||
|
@ -31,6 +34,7 @@ public class SchematicWorld extends WrappedWorld {
|
|||
|
||||
private Map<BlockPos, BlockState> blocks;
|
||||
private Map<BlockPos, TileEntity> tileEntities;
|
||||
private List<Entity> entities;
|
||||
private Cuboid bounds;
|
||||
public BlockPos anchor;
|
||||
public boolean renderMode;
|
||||
|
@ -41,11 +45,28 @@ public class SchematicWorld extends WrappedWorld {
|
|||
this.tileEntities = new HashMap<>();
|
||||
this.bounds = new Cuboid();
|
||||
this.anchor = anchor;
|
||||
this.entities = new ArrayList<>();
|
||||
}
|
||||
|
||||
public Set<BlockPos> getAllPositions() {
|
||||
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
|
||||
public TileEntity getTileEntity(BlockPos pos) {
|
||||
|
|
|
@ -25,7 +25,6 @@ import com.simibubi.create.modules.schematics.item.SchematicItem;
|
|||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.entity.player.ServerPlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.text.StringTextComponent;
|
||||
import net.minecraft.util.text.TranslationTextComponent;
|
||||
|
@ -234,7 +233,6 @@ public class ServerSchematicLoader {
|
|||
if (table == null)
|
||||
return;
|
||||
table.finishUpload();
|
||||
table.inventory.setStackInSlot(0, ItemStack.EMPTY);
|
||||
table.inventory.setStackInSlot(1, SchematicItem.create(schematic, player.getName().getFormattedText()));
|
||||
|
||||
} catch (IOException e) {
|
||||
|
|
|
@ -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--;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -7,6 +7,7 @@ import net.minecraft.entity.player.PlayerEntity;
|
|||
import net.minecraft.entity.player.PlayerInventory;
|
||||
import net.minecraft.inventory.container.Container;
|
||||
import net.minecraft.inventory.container.INamedContainerProvider;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.network.PacketBuffer;
|
||||
import net.minecraft.tileentity.ITickableTileEntity;
|
||||
|
@ -102,6 +103,7 @@ public class SchematicTableTileEntity extends SyncedTileEntity implements ITicka
|
|||
uploadingProgress = 0;
|
||||
uploadingSchematic = schematic;
|
||||
sendUpdate = true;
|
||||
inventory.setStackInSlot(0, ItemStack.EMPTY);
|
||||
}
|
||||
|
||||
public void finishUpload() {
|
||||
|
|
|
@ -17,7 +17,6 @@ import net.minecraft.util.math.BlockRayTraceResult;
|
|||
import net.minecraft.util.math.shapes.ISelectionContext;
|
||||
import net.minecraft.util.math.shapes.VoxelShape;
|
||||
import net.minecraft.world.IBlockReader;
|
||||
import net.minecraft.world.IWorldReader;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fml.network.NetworkHooks;
|
||||
|
||||
|
@ -52,11 +51,6 @@ public class SchematicannonBlock extends Block implements ITE<SchematicannonTile
|
|||
return AllShapes.SCHEMATICANNON_SHAPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNeighborChange(BlockState state, IWorldReader world, BlockPos pos, BlockPos neighbor) {
|
||||
withTileEntityDo(world, pos, SchematicannonTileEntity::findInventories);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onBlockActivated(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand handIn,
|
||||
BlockRayTraceResult hit) {
|
||||
|
|
|
@ -7,11 +7,14 @@ import com.simibubi.create.AllBlockPartials;
|
|||
import com.simibubi.create.foundation.block.SafeTileEntityRenderer;
|
||||
import com.simibubi.create.foundation.utility.SuperByteBuffer;
|
||||
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.client.Minecraft;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
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.vertex.DefaultVertexFormats;
|
||||
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.Vec3d;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public class SchematicannonRenderer extends SafeTileEntityRenderer<SchematicannonTileEntity> {
|
||||
|
||||
@Override
|
||||
|
@ -56,14 +60,14 @@ public class SchematicannonRenderer extends SafeTileEntityRenderer<Schematicanno
|
|||
}
|
||||
|
||||
if (!tileEntityIn.flyingBlocks.isEmpty()) {
|
||||
for (LaunchedBlock block : tileEntityIn.flyingBlocks) {
|
||||
for (LaunchedItem launched : tileEntityIn.flyingBlocks) {
|
||||
|
||||
if (block.ticksRemaining == 0)
|
||||
if (launched.ticksRemaining == 0)
|
||||
continue;
|
||||
|
||||
// Calculate position of flying block
|
||||
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);
|
||||
|
||||
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);
|
||||
start = start.add(cannonOffset);
|
||||
|
||||
double progress = ((double) block.totalTicks - (block.ticksRemaining + 1 - partialTicks))
|
||||
/ block.totalTicks;
|
||||
Vec3d blockLocationXZ = new Vec3d(x + .5, y + .5, z + .5)
|
||||
.add(target.subtract(start).scale(progress).mul(1, 0, 1));
|
||||
double progress =
|
||||
((double) launched.totalTicks - (launched.ticksRemaining + 1 - partialTicks)) / launched.totalTicks;
|
||||
Vec3d blockLocationXZ =
|
||||
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
|
||||
double t = progress;
|
||||
|
@ -86,21 +90,32 @@ public class SchematicannonRenderer extends SafeTileEntityRenderer<Schematicanno
|
|||
GlStateManager.translated(blockLocation.x, blockLocation.y, blockLocation.z);
|
||||
|
||||
// Rotation and Scaling effects
|
||||
double scale = .3f;
|
||||
GlStateManager.rotated(360 * t * 2, 1, 1, 0);
|
||||
GlStateManager.scaled(scale, scale, scale);
|
||||
|
||||
// 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();
|
||||
|
||||
// Apply Recoil if block was just launched
|
||||
if ((block.ticksRemaining + 1 - partialTicks) > block.totalTicks - 10) {
|
||||
recoil = Math.max(recoil, (block.ticksRemaining + 1 - partialTicks) - block.totalTicks + 10);
|
||||
if ((launched.ticksRemaining + 1 - partialTicks) > launched.totalTicks - 10) {
|
||||
recoil = Math.max(recoil, (launched.ticksRemaining + 1 - partialTicks) - launched.totalTicks + 10);
|
||||
}
|
||||
|
||||
// Render particles for launch
|
||||
if (block.ticksRemaining == block.totalTicks && tileEntityIn.firstRenderTick) {
|
||||
if (launched.ticksRemaining == launched.totalTicks && tileEntityIn.firstRenderTick) {
|
||||
tileEntityIn.firstRenderTick = false;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Random r = tileEntityIn.getWorld().getRandom();
|
||||
|
|
|
@ -26,7 +26,6 @@ import net.minecraft.client.gui.widget.Widget;
|
|||
import net.minecraft.client.renderer.Rectangle2d;
|
||||
import net.minecraft.client.renderer.RenderHelper;
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
import net.minecraft.item.BlockItem;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
import net.minecraft.util.text.TextFormatting;
|
||||
|
@ -89,9 +88,8 @@ public class SchematicannonScreen extends AbstractSimiContainerScreen<Schematica
|
|||
// Replace settings
|
||||
replaceLevelButtons = new Vector<>(4);
|
||||
replaceLevelIndicators = new Vector<>(4);
|
||||
List<ScreenResources> icons = ImmutableList.of(ScreenResources.I_DONT_REPLACE,
|
||||
ScreenResources.I_REPLACE_SOLID, ScreenResources.I_REPLACE_ANY,
|
||||
ScreenResources.I_REPLACE_EMPTY);
|
||||
List<ScreenResources> icons = ImmutableList.of(ScreenResources.I_DONT_REPLACE, ScreenResources.I_REPLACE_SOLID,
|
||||
ScreenResources.I_REPLACE_ANY, ScreenResources.I_REPLACE_EMPTY);
|
||||
List<String> toolTips = ImmutableList.of(Lang.translate("gui.schematicannon.option.dontReplaceSolid"),
|
||||
Lang.translate("gui.schematicannon.option.replaceWithSolid"),
|
||||
Lang.translate("gui.schematicannon.option.replaceWithAny"),
|
||||
|
@ -215,10 +213,9 @@ public class SchematicannonScreen extends AbstractSimiContainerScreen<Schematica
|
|||
String msg = Lang.translate("schematicannon.status." + te.statusMsg);
|
||||
int stringWidth = font.getStringWidth(msg);
|
||||
|
||||
if (te.missingBlock != null) {
|
||||
if (te.missingItem != null) {
|
||||
stringWidth += 15;
|
||||
itemRenderer.renderItemIntoGUI(new ItemStack(BlockItem.BLOCK_TO_ITEM.get(te.missingBlock.getBlock())),
|
||||
guiLeft + 145, guiTop + 25);
|
||||
itemRenderer.renderItemIntoGUI(te.missingItem, guiLeft + 145, guiTop + 25);
|
||||
}
|
||||
|
||||
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,
|
||||
0x666666);
|
||||
|
||||
//to see or debug the bounds of the extra area uncomment the following lines
|
||||
//Rectangle2d r = extraAreas.get(0);
|
||||
//fill(r.getX() + r.getWidth(), r.getY() + r.getHeight(), r.getX(), r.getY(), 0xd3d3d3d3);
|
||||
// to see or debug the bounds of the extra area uncomment the following lines
|
||||
// Rectangle2d r = extraAreas.get(0);
|
||||
// fill(r.getX() + r.getWidth(), r.getY() + r.getHeight(), r.getX(), r.getY(),
|
||||
// 0xd3d3d3d3);
|
||||
}
|
||||
|
||||
protected void renderCannon() {
|
||||
|
@ -282,21 +280,27 @@ public class SchematicannonScreen extends AbstractSimiContainerScreen<Schematica
|
|||
if (mouseX >= fuelX && mouseY >= fuelY && mouseX <= fuelX + ScreenResources.SCHEMATICANNON_FUEL.width
|
||||
&& mouseY <= fuelY + ScreenResources.SCHEMATICANNON_FUEL.height) {
|
||||
container.getTileEntity();
|
||||
|
||||
double fuelUsageRate = te.getFuelUsageRate();
|
||||
int shotsLeft = (int) (te.fuelLevel / fuelUsageRate);
|
||||
int shotsLeftWithItems = (int) (shotsLeft
|
||||
+ 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),
|
||||
GRAY + Lang.translate(_shotsRemainingWithBackup, "" + TextFormatting.BLUE + shotsLeftWithItems)),
|
||||
mouseX, mouseY);
|
||||
|
||||
List<String> tooltip = new ArrayList<>();
|
||||
tooltip.add(Lang.translate(_gunpowderLevel, "" + (int) (te.fuelLevel * 100)));
|
||||
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;
|
||||
if (mouseX >= missingBlockX && mouseY >= missingBlockY && mouseX <= missingBlockX + 16
|
||||
&& mouseY <= missingBlockY + 16) {
|
||||
renderTooltip(new ItemStack(BlockItem.BLOCK_TO_ITEM.get(te.missingBlock.getBlock())), mouseX, mouseY);
|
||||
renderTooltip(te.missingItem, mouseX, mouseY);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,10 @@ import com.simibubi.create.config.AllConfigs;
|
|||
import com.simibubi.create.config.CSchematics;
|
||||
import com.simibubi.create.foundation.behaviour.base.SmartTileEntity;
|
||||
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.SchematicWorld;
|
||||
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.Blocks;
|
||||
import net.minecraft.block.PistonHeadBlock;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
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.BlockStateProperties;
|
||||
import net.minecraft.state.properties.DoubleBlockHalf;
|
||||
import net.minecraft.state.properties.SlabType;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.tileentity.TileEntityType;
|
||||
import net.minecraft.util.Direction;
|
||||
|
@ -48,6 +52,7 @@ import net.minecraftforge.api.distmarker.OnlyIn;
|
|||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.items.CapabilityItemHandler;
|
||||
import net.minecraftforge.items.IItemHandler;
|
||||
import net.minecraftforge.items.ItemHandlerHelper;
|
||||
|
||||
public class SchematicannonTileEntity extends SmartTileEntity implements INamedContainerProvider {
|
||||
|
||||
|
@ -71,17 +76,18 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
|
|||
public BlockPos currentPos;
|
||||
public BlockPos schematicAnchor;
|
||||
public boolean schematicLoaded;
|
||||
public BlockState missingBlock;
|
||||
public boolean blockNotLoaded;
|
||||
public ItemStack missingItem;
|
||||
public boolean positionNotLoaded;
|
||||
public boolean hasCreativeCrate;
|
||||
private int printerCooldown;
|
||||
private int skipsLeft;
|
||||
private boolean blockSkipped;
|
||||
private int printingEntityIndex;
|
||||
|
||||
public BlockPos target;
|
||||
public BlockPos previousTarget;
|
||||
public List<IItemHandler> attachedInventories;
|
||||
public List<LaunchedBlock> flyingBlocks;
|
||||
public List<LaunchedItem> flyingBlocks;
|
||||
public MaterialChecklist checklist;
|
||||
|
||||
// Gui information
|
||||
|
@ -124,6 +130,7 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
|
|||
inventory = new SchematicannonInventory(this);
|
||||
statusMsg = "idle";
|
||||
state = State.STOPPED;
|
||||
printingEntityIndex = -1;
|
||||
replaceMode = 2;
|
||||
neighbourCheckCooldown = NEIGHBOUR_CHECKING;
|
||||
checklist = new MaterialChecklist();
|
||||
|
@ -143,8 +150,8 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
|
|||
|
||||
TileEntity tileEntity = world.getTileEntity(pos.offset(facing));
|
||||
if (tileEntity != null) {
|
||||
LazyOptional<IItemHandler> capability = tileEntity
|
||||
.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, facing.getOpposite());
|
||||
LazyOptional<IItemHandler> capability =
|
||||
tileEntity.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, facing.getOpposite());
|
||||
if (capability.isPresent()) {
|
||||
attachedInventories.add(capability.orElse(null));
|
||||
}
|
||||
|
@ -174,11 +181,11 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
|
|||
state = State.valueOf(compound.getString("State"));
|
||||
blocksPlaced = compound.getInt("AmountPlaced");
|
||||
blocksToPlace = compound.getInt("AmountToPlace");
|
||||
printingEntityIndex = compound.getInt("EntityProgress");
|
||||
|
||||
if (compound.contains("MissingBlock"))
|
||||
missingBlock = NBTUtil.readBlockState(compound.getCompound("MissingBlock"));
|
||||
else
|
||||
missingBlock = null;
|
||||
missingItem = null;
|
||||
if (compound.contains("MissingItem"))
|
||||
missingItem = ItemStack.read(compound.getCompound("MissingItem"));
|
||||
|
||||
// Settings
|
||||
CompoundNBT options = compound.getCompound("Options");
|
||||
|
@ -203,15 +210,12 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
|
|||
|
||||
for (int i = 0; i < tagBlocks.size(); i++) {
|
||||
CompoundNBT c = tagBlocks.getCompound(i);
|
||||
|
||||
BlockPos readBlockPos = NBTUtil.readBlockPos(c.getCompound("Target"));
|
||||
BlockState readBlockState = NBTUtil.readBlockState(c.getCompound("Block"));
|
||||
int int1 = c.getInt("TicksLeft");
|
||||
int int2 = c.getInt("TotalTicks");
|
||||
LaunchedItem launched = LaunchedItem.fromNBT(c);
|
||||
BlockPos readBlockPos = launched.target;
|
||||
|
||||
// Always write to Server tile
|
||||
if (world == null || !world.isRemote) {
|
||||
flyingBlocks.add(new LaunchedBlock(this, readBlockPos, readBlockState, int1, int2));
|
||||
flyingBlocks.add(launched);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -224,7 +228,7 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
|
|||
|
||||
// Add new server side blocks
|
||||
if (i >= flyingBlocks.size()) {
|
||||
flyingBlocks.add(new LaunchedBlock(this, readBlockPos, readBlockState, int1, int2));
|
||||
flyingBlocks.add(launched);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -256,9 +260,10 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
|
|||
compound.putString("State", state.name());
|
||||
compound.putInt("AmountPlaced", blocksPlaced);
|
||||
compound.putInt("AmountToPlace", blocksToPlace);
|
||||
compound.putInt("EntityProgress", printingEntityIndex);
|
||||
|
||||
if (missingBlock != null)
|
||||
compound.put("MissingBlock", NBTUtil.writeBlockState(missingBlock));
|
||||
if (missingItem != null)
|
||||
compound.put("MissingItem", missingItem.serializeNBT());
|
||||
|
||||
// Settings
|
||||
CompoundNBT options = new CompoundNBT();
|
||||
|
@ -271,14 +276,8 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
|
|||
if (target != null)
|
||||
compound.put("Target", NBTUtil.writeBlockPos(target));
|
||||
ListNBT tagBlocks = new ListNBT();
|
||||
for (LaunchedBlock b : flyingBlocks) {
|
||||
CompoundNBT c = new CompoundNBT();
|
||||
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);
|
||||
}
|
||||
for (LaunchedItem b : flyingBlocks)
|
||||
tagBlocks.add(b.serializeNBT());
|
||||
compound.put("FlyingBlocks", tagBlocks);
|
||||
|
||||
return compound;
|
||||
|
@ -287,7 +286,7 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
|
|||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
|
||||
if (neighbourCheckCooldown-- <= 0) {
|
||||
neighbourCheckCooldown = NEIGHBOUR_CHECKING;
|
||||
findInventories();
|
||||
|
@ -344,7 +343,7 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
|
|||
return;
|
||||
}
|
||||
|
||||
if (state == State.PAUSED && !blockNotLoaded && missingBlock == null && fuelLevel > getFuelUsageRate())
|
||||
if (state == State.PAUSED && !positionNotLoaded && missingItem == null && fuelLevel > getFuelUsageRate())
|
||||
return;
|
||||
|
||||
// Initialize Printer
|
||||
|
@ -370,13 +369,13 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
|
|||
|
||||
// Update Target
|
||||
if (hasCreativeCrate) {
|
||||
if (missingBlock != null) {
|
||||
missingBlock = null;
|
||||
if (missingItem != null) {
|
||||
missingItem = null;
|
||||
state = State.RUNNING;
|
||||
}
|
||||
}
|
||||
|
||||
if (missingBlock == null && !blockNotLoaded) {
|
||||
if (missingItem == null && !positionNotLoaded) {
|
||||
advanceCurrentPos();
|
||||
|
||||
// End reached
|
||||
|
@ -387,61 +386,83 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
|
|||
target = schematicAnchor.add(currentPos);
|
||||
}
|
||||
|
||||
boolean entityMode = printingEntityIndex >= 0;
|
||||
|
||||
// Check block
|
||||
if (!getWorld().isAreaLoaded(target, 0)) {
|
||||
blockNotLoaded = true;
|
||||
positionNotLoaded = true;
|
||||
statusMsg = "targetNotLoaded";
|
||||
state = State.PAUSED;
|
||||
return;
|
||||
} else {
|
||||
if (blockNotLoaded) {
|
||||
blockNotLoaded = false;
|
||||
if (positionNotLoaded) {
|
||||
positionNotLoaded = false;
|
||||
state = State.RUNNING;
|
||||
}
|
||||
}
|
||||
|
||||
BlockState blockState = blockReader.getBlockState(target);
|
||||
ItemStack requiredItem = getItemForBlock(blockState);
|
||||
boolean shouldSkip = false;
|
||||
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";
|
||||
blockSkipped = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Find item
|
||||
if (blockState.has(BlockStateProperties.SLAB_TYPE)
|
||||
&& blockState.get(BlockStateProperties.SLAB_TYPE) == SlabType.DOUBLE)
|
||||
requiredItem.setCount(2);
|
||||
List<ItemStack> requiredItems = requirement.getRequiredItems();
|
||||
if (!requirement.isEmpty()) {
|
||||
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)) {
|
||||
if (skipMissing) {
|
||||
statusMsg = "skipping";
|
||||
blockSkipped = true;
|
||||
if (missingBlock != null) {
|
||||
missingBlock = null;
|
||||
state = State.RUNNING;
|
||||
missingItem = required;
|
||||
state = State.PAUSED;
|
||||
statusMsg = "missingBlock";
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
missingBlock = blockState;
|
||||
state = State.PAUSED;
|
||||
statusMsg = "missingBlock";
|
||||
return;
|
||||
for (ItemStack required : requiredItems)
|
||||
grabItemsFromAttachedInventories(required, requirement.getUsage(), false);
|
||||
}
|
||||
|
||||
// Success
|
||||
state = State.RUNNING;
|
||||
if (blockState.getBlock() != Blocks.AIR)
|
||||
if (blockState.getBlock() != Blocks.AIR || entityMode)
|
||||
statusMsg = "placing";
|
||||
else
|
||||
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();
|
||||
fuelLevel -= getFuelUsageRate();
|
||||
sendUpdate = true;
|
||||
missingBlock = null;
|
||||
missingItem = null;
|
||||
}
|
||||
|
||||
public double getFuelUsageRate() {
|
||||
|
@ -487,6 +508,7 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
|
|||
schematicLoaded = true;
|
||||
state = State.PAUSED;
|
||||
statusMsg = "ready";
|
||||
printingEntityIndex = -1;
|
||||
updateChecklist();
|
||||
sendUpdate = true;
|
||||
blocksToPlace += blocksPlaced;
|
||||
|
@ -498,44 +520,82 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
|
|||
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)
|
||||
return true;
|
||||
|
||||
boolean two = requiredItem.getCount() == 2;
|
||||
int lastSlot = -1;
|
||||
// Find and apply damage
|
||||
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) {
|
||||
for (int slot = 0; slot < iItemHandler.getSlots(); slot++) {
|
||||
ItemStack stackInSlot = iItemHandler.getStackInSlot(slot);
|
||||
if (!stackInSlot.isItemEqual(requiredItem))
|
||||
continue;
|
||||
if (!two && !iItemHandler.extractItem(slot, 1, false).isEmpty())
|
||||
return true;
|
||||
|
||||
// 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;
|
||||
if (!simulate) {
|
||||
ItemStack stack = iItemHandler.extractItem(slot, 1, false);
|
||||
stack.setDamage(stack.getDamage() + 1);
|
||||
if (stack.getDamage() <= stack.getMaxDamage()) {
|
||||
if (iItemHandler.getStackInSlot(slot).isEmpty())
|
||||
iItemHandler.insertItem(slot, stack, false);
|
||||
else
|
||||
ItemHandlerHelper.insertItem(iItemHandler, stack, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
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();
|
||||
currentPos = currentPos.offset(Direction.EAST);
|
||||
BlockPos posInBounds = currentPos.subtract(blockReader.getBounds().getOrigin());
|
||||
|
@ -545,29 +605,38 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
|
|||
if (posInBounds.getZ() > size.getZ())
|
||||
currentPos = new BlockPos(currentPos.getX(), currentPos.getY() + 1, blockReader.getBounds().z).west();
|
||||
|
||||
// End reached
|
||||
// End of blocks reached
|
||||
if (currentPos.getY() > size.getY()) {
|
||||
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;
|
||||
return;
|
||||
printingEntityIndex = 0;
|
||||
if (entities.isEmpty()) {
|
||||
finishedPrinting();
|
||||
return;
|
||||
}
|
||||
currentPos = entities.get(0).getPosition().subtract(schematicAnchor);
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
schematicLoaded = false;
|
||||
schematicAnchor = null;
|
||||
currentPos = null;
|
||||
blockReader = null;
|
||||
missingBlock = null;
|
||||
missingItem = null;
|
||||
sendUpdate = true;
|
||||
printingEntityIndex = -1;
|
||||
schematicProgress = 0;
|
||||
blocksPlaced = 0;
|
||||
blocksToPlace = 0;
|
||||
|
@ -577,6 +646,10 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
|
|||
BlockState toReplace = world.getBlockState(pos);
|
||||
boolean placingAir = state.getBlock() == Blocks.AIR;
|
||||
|
||||
if (!world.isBlockPresent(pos))
|
||||
return false;
|
||||
if (!world.getWorldBorder().contains(pos))
|
||||
return false;
|
||||
if (toReplace == state)
|
||||
return false;
|
||||
if (toReplace.getBlockHardness(world, pos) == -1)
|
||||
|
@ -622,21 +695,10 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
|
|||
}
|
||||
|
||||
protected void tickFlyingBlocks() {
|
||||
List<LaunchedBlock> toRemove = new LinkedList<>();
|
||||
for (LaunchedBlock b : flyingBlocks) {
|
||||
b.update();
|
||||
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));
|
||||
List<LaunchedItem> toRemove = new LinkedList<>();
|
||||
for (LaunchedItem b : flyingBlocks)
|
||||
if (b.update(world))
|
||||
toRemove.add(b);
|
||||
}
|
||||
}
|
||||
flyingBlocks.removeAll(toRemove);
|
||||
}
|
||||
|
||||
|
@ -696,10 +758,20 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
|
|||
sendUpdate = true;
|
||||
}
|
||||
|
||||
protected void launchBlock(BlockPos target, BlockState state) {
|
||||
protected void launchBlock(BlockPos target, ItemStack stack, BlockState state) {
|
||||
if (state.getBlock() != Blocks.AIR)
|
||||
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(),
|
||||
SoundCategory.BLOCKS, .1f, 1.1f);
|
||||
}
|
||||
|
@ -721,6 +793,7 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
|
|||
|
||||
public void updateChecklist() {
|
||||
checklist.required.clear();
|
||||
checklist.damageRequired.clear();
|
||||
checklist.blocksNotLoaded = false;
|
||||
|
||||
if (schematicLoaded) {
|
||||
|
@ -734,18 +807,22 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
|
|||
}
|
||||
if (!shouldPlace(pos.add(schematicAnchor), required))
|
||||
continue;
|
||||
ItemStack requiredItem = getItemForBlock(required);
|
||||
if (requiredItem.isEmpty())
|
||||
ItemRequirement requirement = ItemRequirement.of(required);
|
||||
if (requirement.isEmpty())
|
||||
continue;
|
||||
|
||||
// Two items for double slabs
|
||||
if (required.has(BlockStateProperties.SLAB_TYPE)
|
||||
&& required.get(BlockStateProperties.SLAB_TYPE) == SlabType.DOUBLE)
|
||||
checklist.require(requiredItem.getItem());
|
||||
|
||||
checklist.require(requiredItem.getItem());
|
||||
if (requirement.isInvalid())
|
||||
continue;
|
||||
checklist.require(requirement);
|
||||
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();
|
||||
for (IItemHandler inventory : attachedInventories) {
|
||||
|
@ -762,7 +839,7 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC
|
|||
@Override
|
||||
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void lazyTick() {
|
||||
super.lazyTick();
|
||||
|
|
|
@ -225,7 +225,7 @@ public class SchematicAndQuillHandler {
|
|||
Template t = new Template();
|
||||
MutableBoundingBox bb = new MutableBoundingBox(firstPos, secondPos);
|
||||
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())
|
||||
string = Lang.translate("schematicAndQuill.fallbackName");
|
||||
|
|
|
@ -9,6 +9,7 @@ import net.minecraft.entity.player.ServerPlayerEntity;
|
|||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTUtil;
|
||||
import net.minecraft.network.PacketBuffer;
|
||||
import net.minecraft.world.gen.feature.template.PlacementSettings;
|
||||
import net.minecraft.world.gen.feature.template.Template;
|
||||
import net.minecraftforge.fml.network.NetworkEvent.Context;
|
||||
|
||||
|
@ -32,8 +33,10 @@ public class SchematicPlacePacket extends SimplePacketBase {
|
|||
context.get().enqueueWork(() -> {
|
||||
ServerPlayerEntity player = context.get().getSender();
|
||||
Template t = SchematicItem.loadSchematic(stack);
|
||||
PlacementSettings settings = SchematicItem.getSettings(stack);
|
||||
settings.setIgnoreEntities(false);
|
||||
t.addBlocksToWorld(player.getServerWorld(), NBTUtil.readBlockPos(stack.getTag().getCompound("Anchor")),
|
||||
SchematicItem.getSettings(stack));
|
||||
settings);
|
||||
});
|
||||
context.get().setPacketHandled(true);
|
||||
}
|
||||
|
|
|
@ -534,11 +534,11 @@
|
|||
"create.schematicannon.status.paused": "Paused",
|
||||
"create.schematicannon.status.stopped": "Stopped",
|
||||
"create.schematicannon.status.noGunpowder": "Out of Gunpowder",
|
||||
"create.schematicannon.status.targetNotLoaded": "Block is Not Loaded",
|
||||
"create.schematicannon.status.targetOutsideRange": "Target too Far Away",
|
||||
"create.schematicannon.status.targetNotLoaded": "Target is not loaded",
|
||||
"create.schematicannon.status.targetOutsideRange": "Target too far away",
|
||||
"create.schematicannon.status.searching": "Searching",
|
||||
"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.clearing": "Clearing Blocks",
|
||||
"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 |
Loading…
Reference in a new issue