From 8372a1eb439abf0aef34ee6907368344d9448e38 Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Tue, 16 Jul 2019 16:01:51 +0200 Subject: [PATCH] Schematicannon Container - Made the Schematicannon a proper container - Added Gui Screen for Schematicannon - Added a few new Icons - Fixed Make-Shift registering of Containers --- .../com/simibubi/create/AllContainers.java | 36 +- .../create/ClientSchematicLoader.java | 10 +- .../create/ServerSchematicLoader.java | 43 +- .../create/block/SchematicTableBlock.java | 29 +- .../create/block/SchematicTableContainer.java | 75 +-- .../block/SchematicTableTileEntity.java | 79 ++- .../create/block/SchematicannonBlock.java | 46 +- .../create/block/SchematicannonContainer.java | 92 +++ .../block/SchematicannonTileEntity.java | 604 +++++++++++++----- .../gui/AbstractSimiContainerScreen.java | 131 ++++ .../com/simibubi/create/gui/GuiResources.java | 36 +- .../create/gui/SchematicTableScreen.java | 11 +- .../create/gui/SchematicannonScreen.java | 319 +++++++++ .../create/gui/widgets/SimiButton.java | 2 +- .../simibubi/create/item/ItemBlueprint.java | 46 +- .../PacketConfigureSchematicannon.java | 94 +++ .../simibubi/create/networking/Packets.java | 2 + .../create/schematic/BlueprintHandler.java | 14 +- .../com/simibubi/create/schematic/Tools.java | 10 +- .../create/utility/TileEntitySynced.java | 19 +- .../create/models/item/symmetry_wand.json | 2 +- .../assets/create/textures/gui/icons.png | Bin 2194 -> 2154 bytes .../create/textures/gui/schematicannon.png | Bin 0 -> 4327 bytes .../create/textures/item/blueprint_filled.png | Bin 351 -> 340 bytes 24 files changed, 1327 insertions(+), 373 deletions(-) create mode 100644 src/main/java/com/simibubi/create/block/SchematicannonContainer.java create mode 100644 src/main/java/com/simibubi/create/gui/AbstractSimiContainerScreen.java create mode 100644 src/main/java/com/simibubi/create/gui/SchematicannonScreen.java create mode 100644 src/main/java/com/simibubi/create/networking/PacketConfigureSchematicannon.java create mode 100644 src/main/resources/assets/create/textures/gui/schematicannon.png diff --git a/src/main/java/com/simibubi/create/AllContainers.java b/src/main/java/com/simibubi/create/AllContainers.java index 8cbffd161..22463f18e 100644 --- a/src/main/java/com/simibubi/create/AllContainers.java +++ b/src/main/java/com/simibubi/create/AllContainers.java @@ -1,41 +1,59 @@ package com.simibubi.create; import com.simibubi.create.block.SchematicTableContainer; +import com.simibubi.create.block.SchematicannonContainer; import com.simibubi.create.gui.SchematicTableScreen; +import com.simibubi.create.gui.SchematicannonScreen; +import net.minecraft.client.gui.IHasContainer; import net.minecraft.client.gui.ScreenManager; +import net.minecraft.client.gui.ScreenManager.IScreenFactory; +import net.minecraft.client.gui.screen.Screen; import net.minecraft.inventory.container.Container; import net.minecraft.inventory.container.ContainerType; +import net.minecraft.inventory.container.ContainerType.IFactory; +import net.minecraft.util.ResourceLocation; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod.EventBusSubscriber; import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus; +import net.minecraftforge.fml.network.IContainerFactory; @EventBusSubscriber(bus = Bus.MOD) public enum AllContainers { - SchematicTable(); + SchematicTable(SchematicTableContainer::new), + Schematicannon(SchematicannonContainer::new); public ContainerType type; + private IFactory factory; - private AllContainers() { + private AllContainers(IContainerFactory factory) { + this.factory = factory; } @SubscribeEvent public static void onContainerTypeRegistry(final RegistryEvent.Register> e) { - SchematicTable.type = new ContainerType<>(SchematicTableContainer::new) - .setRegistryName(SchematicTable.name().toLowerCase()); - - e.getRegistry().register(SchematicTable.type); + + for (AllContainers container : values()) { + container.type = new ContainerType<>(container.factory) + .setRegistryName(new ResourceLocation(Create.ID, container.name().toLowerCase())); + e.getRegistry().register(container.type); + } } - @SuppressWarnings("unchecked") @OnlyIn(Dist.CLIENT) public static void registerScreenFactories() { - ScreenManager.registerFactory( - (ContainerType) SchematicTable.type, SchematicTableScreen::new); + bind(SchematicTable, SchematicTableScreen::new); + bind(Schematicannon, SchematicannonScreen::new); + } + + @OnlyIn(Dist.CLIENT) + @SuppressWarnings("unchecked") + private static > void bind(AllContainers c, IScreenFactory factory) { + ScreenManager.registerFactory((ContainerType) c.type, factory); } } diff --git a/src/main/java/com/simibubi/create/ClientSchematicLoader.java b/src/main/java/com/simibubi/create/ClientSchematicLoader.java index 541427e3a..eb12aa3aa 100644 --- a/src/main/java/com/simibubi/create/ClientSchematicLoader.java +++ b/src/main/java/com/simibubi/create/ClientSchematicLoader.java @@ -18,6 +18,7 @@ import com.simibubi.create.networking.PacketSchematicUpload; import com.simibubi.create.networking.Packets; import com.simibubi.create.utility.FilesHelper; +import net.minecraft.client.Minecraft; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; @@ -25,7 +26,7 @@ import net.minecraftforge.api.distmarker.OnlyIn; public class ClientSchematicLoader { public static final int PACKET_DELAY = 10; - public static final int PACKET_SIZE = 500; + public static final int PACKET_SIZE = 2048; private List availableSchematics; private Map activeUploads; @@ -92,7 +93,12 @@ public class ClientSchematicLoader { data = Arrays.copyOf(data, status); } - Packets.channel.sendToServer(PacketSchematicUpload.write(schematic, data)); + if (Minecraft.getInstance().world != null) + Packets.channel.sendToServer(PacketSchematicUpload.write(schematic, data)); + else { + activeUploads.remove(schematic); + return; + } if (status < PACKET_SIZE) finishUpload(schematic); diff --git a/src/main/java/com/simibubi/create/ServerSchematicLoader.java b/src/main/java/com/simibubi/create/ServerSchematicLoader.java index e8c614573..b83d93a5e 100644 --- a/src/main/java/com/simibubi/create/ServerSchematicLoader.java +++ b/src/main/java/com/simibubi/create/ServerSchematicLoader.java @@ -31,7 +31,7 @@ public class ServerSchematicLoader { FilesHelper.createFolderIfMissing(PATH); } - public void handleNewUpload(ServerPlayerEntity player, String schematic, DimensionPos dimensionPos) { + public void handleNewUpload(ServerPlayerEntity player, String schematic, DimensionPos dimPos) { String playerPath = PATH + "/" + player.getName().getFormattedText(); String playerSchematicId = player.getName().getFormattedText() + "/" + schematic; @@ -46,14 +46,19 @@ public class ServerSchematicLoader { StandardOpenOption.CREATE_NEW); Create.logger.info("Receiving New Schematic: " + playerSchematicId); activeDownloads.put(playerSchematicId, writer); - activeTables.put(playerSchematicId, dimensionPos); + activeTables.put(playerSchematicId, dimPos); + + SchematicTableTileEntity tileEntity = (SchematicTableTileEntity) dimPos.world + .getTileEntity(dimPos.pos); + tileEntity.uploadingSchematic = schematic; + tileEntity.uploadingProgress = 0; + BlockState blockState = dimPos.world.getBlockState(dimPos.pos); + dimPos.world.notifyBlockUpdate(dimPos.pos, blockState, blockState, 6); if (player.openContainer instanceof SchematicTableContainer) { SchematicTableContainer c = (SchematicTableContainer) player.openContainer; - c.schematicUploading = schematic; - c.isUploading = true; c.sendSchematicUpdate = true; - player.openContainer.detectAndSendChanges(); + c.detectAndSendChanges(); } } catch (IOException e) { @@ -94,31 +99,21 @@ public class ServerSchematicLoader { if (!AllBlocks.SCHEMATIC_TABLE.typeOf(blockState)) return; + SchematicTableTileEntity tileEntity = (SchematicTableTileEntity) dimpos.world.getTileEntity(dimpos.pos); + + tileEntity.inventory.setStackInSlot(0, ItemStack.EMPTY); + tileEntity.inventory.setStackInSlot(1, + ItemBlueprint.create(schematic, player.getName().getFormattedText())); + tileEntity.uploadingSchematic = null; + tileEntity.uploadingProgress = 0; + dimpos.world.notifyBlockUpdate(dimpos.pos, blockState, blockState, 3); + if (player.openContainer instanceof SchematicTableContainer) { SchematicTableContainer c = (SchematicTableContainer) player.openContainer; - c.isUploading = false; - c.schematicUploading = null; - c.progress = 0; c.sendSchematicUpdate = true; c.detectAndSendChanges(); } - SchematicTableTileEntity tileEntity = (SchematicTableTileEntity) dimpos.world.getTileEntity(dimpos.pos); - if (tileEntity.inputStack.isEmpty()) - return; - if (!tileEntity.outputStack.isEmpty()) - return; - - tileEntity.inputStack = ItemStack.EMPTY; - tileEntity.outputStack = ItemBlueprint.create(schematic, player.getName().getFormattedText()); - - dimpos.world.notifyBlockUpdate(dimpos.pos, blockState, blockState, 3); - - if (player.openContainer instanceof SchematicTableContainer) { - SchematicTableContainer c = (SchematicTableContainer) player.openContainer; - c.updateContent(); - } - } catch (IOException e) { e.printStackTrace(); } diff --git a/src/main/java/com/simibubi/create/block/SchematicTableBlock.java b/src/main/java/com/simibubi/create/block/SchematicTableBlock.java index dc030606d..298d0cb1e 100644 --- a/src/main/java/com/simibubi/create/block/SchematicTableBlock.java +++ b/src/main/java/com/simibubi/create/block/SchematicTableBlock.java @@ -5,8 +5,8 @@ import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.block.HorizontalBlock; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.inventory.InventoryHelper; -import net.minecraft.inventory.container.INamedContainerProvider; import net.minecraft.item.BlockItemUseContext; import net.minecraft.state.StateContainer.Builder; import net.minecraft.tileentity.TileEntity; @@ -15,6 +15,7 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.world.IBlockReader; import net.minecraft.world.World; +import net.minecraftforge.fml.network.NetworkHooks; public class SchematicTableBlock extends HorizontalBlock { @@ -27,7 +28,7 @@ public class SchematicTableBlock extends HorizontalBlock { builder.add(HORIZONTAL_FACING); super.fillStateContainer(builder); } - + @Override public boolean isSolid(BlockState state) { return false; @@ -46,19 +47,17 @@ public class SchematicTableBlock extends HorizontalBlock { @Override public boolean onBlockActivated(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand handIn, BlockRayTraceResult hit) { - + if (worldIn.isRemote) { return true; } else { - INamedContainerProvider inamedcontainerprovider = (INamedContainerProvider) worldIn.getTileEntity(pos); - if (inamedcontainerprovider != null) { - player.openContainer(inamedcontainerprovider); - } - + SchematicTableTileEntity te = (SchematicTableTileEntity) worldIn.getTileEntity(pos); + if (te != null) + NetworkHooks.openGui((ServerPlayerEntity) player, te, te::sendToContainer); return true; } } - + @Override public TileEntity createTileEntity(BlockState state, IBlockReader world) { return new SchematicTableTileEntity(); @@ -70,10 +69,14 @@ public class SchematicTableBlock extends HorizontalBlock { return; SchematicTableTileEntity te = (SchematicTableTileEntity) worldIn.getTileEntity(pos); - if (!te.inputStack.isEmpty()) - InventoryHelper.spawnItemStack(worldIn, pos.getX(), pos.getY(), pos.getZ(), te.inputStack); - if (!te.outputStack.isEmpty()) - InventoryHelper.spawnItemStack(worldIn, pos.getX(), pos.getY(), pos.getZ(), te.outputStack); + for (int slot = 0; slot < te.inventory.getSlots(); slot++) { + InventoryHelper.spawnItemStack(worldIn, pos.getX(), pos.getY(), pos.getZ(), + te.inventory.getStackInSlot(slot)); + } + + if (state.hasTileEntity() && state.getBlock() != newState.getBlock()) { + worldIn.removeTileEntity(pos); + } } diff --git a/src/main/java/com/simibubi/create/block/SchematicTableContainer.java b/src/main/java/com/simibubi/create/block/SchematicTableContainer.java index 71cf7d17f..75eb6d45a 100644 --- a/src/main/java/com/simibubi/create/block/SchematicTableContainer.java +++ b/src/main/java/com/simibubi/create/block/SchematicTableContainer.java @@ -5,27 +5,22 @@ import com.simibubi.create.AllItems; import com.simibubi.create.networking.PacketSchematicTableContainer; import com.simibubi.create.networking.Packets; +import net.minecraft.client.Minecraft; +import net.minecraft.client.world.ClientWorld; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.entity.player.ServerPlayerEntity; -import net.minecraft.inventory.IInventory; -import net.minecraft.inventory.Inventory; import net.minecraft.inventory.container.Container; import net.minecraft.inventory.container.Slot; import net.minecraft.item.ItemStack; +import net.minecraft.network.PacketBuffer; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.fml.network.PacketDistributor; +import net.minecraftforge.items.SlotItemHandler; public class SchematicTableContainer extends Container { - private final IInventory tableInventory = new Inventory(2) { - public void markDirty() { - super.markDirty(); - onCraftMatrixChanged(this); - } - }; - private SchematicTableTileEntity te; private Slot inputSlot; private Slot outputSlot; @@ -36,23 +31,31 @@ public class SchematicTableContainer extends Container { public float progress; public boolean sendSchematicUpdate; - public SchematicTableContainer(int id, PlayerInventory inv) { - this(id, inv, null); + public SchematicTableContainer(int id, PlayerInventory inv, PacketBuffer extraData) { + super(AllContainers.SchematicTable.type, id); + player = inv.player; + ClientWorld world = Minecraft.getInstance().world; + this.te = (SchematicTableTileEntity) world.getTileEntity(extraData.readBlockPos()); + this.te.handleUpdateTag(extraData.readCompoundTag()); + init(); } public SchematicTableContainer(int id, PlayerInventory inv, SchematicTableTileEntity te) { super(AllContainers.SchematicTable.type, id); this.player = inv.player; this.te = te; + init(); + } - inputSlot = new Slot(tableInventory, 0, -9, 40) { + protected void init() { + inputSlot = new SlotItemHandler(te.inventory, 0, -9, 40) { @Override public boolean isItemValid(ItemStack stack) { return AllItems.EMPTY_BLUEPRINT.typeOf(stack); } }; - outputSlot = new Slot(tableInventory, 1, 75, 40) { + outputSlot = new SlotItemHandler(te.inventory, 1, 75, 40) { @Override public boolean isItemValid(ItemStack stack) { return false; @@ -61,28 +64,32 @@ public class SchematicTableContainer extends Container { addSlot(inputSlot); addSlot(outputSlot); - - updateContent(); - if (te != null) { - this.addListener(te); - } - // player Slots - tableInventory.openInventory(inv.player); - for (int l = 0; l < 3; ++l) { - for (int j1 = 0; j1 < 9; ++j1) { - this.addSlot(new Slot(inv, j1 + l * 9 + 9, -8 + j1 * 18, 102 + l * 18)); + for (int row = 0; row < 3; ++row) { + for (int col = 0; col < 9; ++col) { + this.addSlot(new Slot(player.inventory, col + row * 9 + 9, -8 + col * 18, 102 + row * 18)); } } - for (int i1 = 0; i1 < 9; ++i1) { - this.addSlot(new Slot(inv, i1, -8 + i1 * 18, 160)); + for (int hotbarSlot = 0; hotbarSlot < 9; ++hotbarSlot) { + this.addSlot(new Slot(player.inventory, hotbarSlot, -8 + hotbarSlot * 18, 160)); } + + detectAndSendChanges(); } - + @Override public void detectAndSendChanges() { + if (te.uploadingSchematic != null) { + schematicUploading = te.uploadingSchematic; + progress = te.uploadingProgress; + isUploading = true; + } else { + schematicUploading = null; + progress = 0; + isUploading = false; + } super.detectAndSendChanges(); sendSchematicInfo(); } @@ -122,16 +129,6 @@ public class SchematicTableContainer extends Container { return ItemStack.EMPTY; } - public void updateContent() { - if (te != null) { - inputSlot.putStack(te.inputStack); - outputSlot.putStack(te.outputStack); - schematicUploading = te.uploadingSchematic; - progress = te.uploadingProgress; - sendSchematicUpdate = true; - } - } - public void sendSchematicInfo() { if (player instanceof ServerPlayerEntity) { if (sendSchematicUpdate) { @@ -158,12 +155,6 @@ public class SchematicTableContainer extends Container { @Override public void onContainerClosed(PlayerEntity playerIn) { - if (te != null) { - te.inputStack = inputSlot.getStack(); - te.outputStack = outputSlot.getStack(); - te.markDirty(); - } - super.onContainerClosed(playerIn); } diff --git a/src/main/java/com/simibubi/create/block/SchematicTableTileEntity.java b/src/main/java/com/simibubi/create/block/SchematicTableTileEntity.java index fd7efde91..d2726a1df 100644 --- a/src/main/java/com/simibubi/create/block/SchematicTableTileEntity.java +++ b/src/main/java/com/simibubi/create/block/SchematicTableTileEntity.java @@ -5,57 +5,70 @@ import com.simibubi.create.utility.TileEntitySynced; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.inventory.ItemStackHelper; import net.minecraft.inventory.container.Container; -import net.minecraft.inventory.container.IContainerListener; 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; import net.minecraft.tileentity.TileEntityType; -import net.minecraft.util.NonNullList; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.StringTextComponent; +import net.minecraftforge.items.ItemStackHandler; -public class SchematicTableTileEntity extends TileEntitySynced implements ITickableTileEntity, INamedContainerProvider, IContainerListener { +public class SchematicTableTileEntity extends TileEntitySynced implements ITickableTileEntity, INamedContainerProvider { - public ItemStack inputStack; - public ItemStack outputStack; - + public SchematicTableInventory inventory; public String uploadingSchematic; public float uploadingProgress; + public class SchematicTableInventory extends ItemStackHandler { + public SchematicTableInventory() { + super(2); + } + + @Override + protected void onContentsChanged(int slot) { + super.onContentsChanged(slot); + markDirty(); + } + } + public SchematicTableTileEntity() { this(AllTileEntities.SchematicTable.type); } public SchematicTableTileEntity(TileEntityType tileEntityTypeIn) { super(tileEntityTypeIn); - inputStack = ItemStack.EMPTY; - outputStack = ItemStack.EMPTY; + inventory = new SchematicTableInventory(); + uploadingSchematic = null; + uploadingProgress = 0; + } + + public void sendToContainer(PacketBuffer buffer) { + buffer.writeBlockPos(getPos()); + buffer.writeCompoundTag(getUpdateTag()); } @Override public void read(CompoundNBT compound) { - NonNullList stacks = NonNullList.create(); - ItemStackHelper.loadAllItems(compound, stacks); - - if (!stacks.isEmpty()) { - inputStack = stacks.get(0); - outputStack = stacks.get(1); + inventory.deserializeNBT(compound.getCompound("Inventory")); + if (compound.contains("Schematic")) { + uploadingSchematic = compound.getString("Schematic"); + uploadingProgress = compound.getFloat("Progress"); + } else { + uploadingSchematic = null; + uploadingProgress = 0; } - super.read(compound); } @Override public CompoundNBT write(CompoundNBT compound) { - NonNullList stacks = NonNullList.create(); - - stacks.add(inputStack); - stacks.add(outputStack); - - ItemStackHelper.saveAllItems(compound, stacks); + compound.put("Inventory", inventory.serializeNBT()); + if (uploadingSchematic != null) { + compound.putString("Schematic", uploadingSchematic); + compound.putFloat("Progress", uploadingProgress); + } return super.write(compound); } @@ -74,24 +87,4 @@ public class SchematicTableTileEntity extends TileEntitySynced implements ITicka return new StringTextComponent(getType().getRegistryName().toString()); } - @Override - public void sendAllContents(Container containerToSend, NonNullList itemsList) { - inputStack = itemsList.get(0); - outputStack = itemsList.get(1); - } - - @Override - public void sendSlotContents(Container containerToSend, int slotInd, ItemStack stack) { - if (slotInd == 0) { - inputStack = stack; - } - if (slotInd == 1) { - outputStack = stack; - } - } - - @Override - public void sendWindowProperty(Container containerIn, int varToUpdate, int newValue) { - } - } diff --git a/src/main/java/com/simibubi/create/block/SchematicannonBlock.java b/src/main/java/com/simibubi/create/block/SchematicannonBlock.java index a42ffeb42..9dc7c67bf 100644 --- a/src/main/java/com/simibubi/create/block/SchematicannonBlock.java +++ b/src/main/java/com/simibubi/create/block/SchematicannonBlock.java @@ -1,14 +1,24 @@ package com.simibubi.create.block; +import com.simibubi.create.AllItems; + import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.inventory.InventoryHelper; +import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Direction; +import net.minecraft.util.Hand; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.world.IBlockReader; import net.minecraft.world.IWorld; import net.minecraft.world.IWorldReader; +import net.minecraft.world.World; +import net.minecraftforge.fml.network.NetworkHooks; public class SchematicannonBlock extends Block { @@ -38,11 +48,45 @@ public class SchematicannonBlock extends Block { return false; } - @Override public void onNeighborChange(BlockState state, IWorldReader world, BlockPos pos, BlockPos neighbor) { ((SchematicannonTileEntity) world.getTileEntity(pos)).findInventories(); super.onNeighborChange(state, world, pos, neighbor); } + + @Override + public boolean onBlockActivated(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand handIn, + BlockRayTraceResult hit) { + + if (worldIn.isRemote) { + return true; + } else { + SchematicannonTileEntity te = (SchematicannonTileEntity) worldIn.getTileEntity(pos); + if (te != null) + if (AllItems.BLUEPRINT.typeOf(player.getHeldItemMainhand()) && te.inventory.getStackInSlot(0).isEmpty()) { + te.inventory.setStackInSlot(0, player.getHeldItemMainhand()); + player.inventory.setInventorySlotContents(player.inventory.currentItem, ItemStack.EMPTY); + } + NetworkHooks.openGui((ServerPlayerEntity) player, te, te::sendToContainer); + return true; + } + } + + @Override + public void onReplaced(BlockState state, World worldIn, BlockPos pos, BlockState newState, boolean isMoving) { + if (worldIn.getTileEntity(pos) == null) + return; + SchematicannonTileEntity te = (SchematicannonTileEntity) worldIn.getTileEntity(pos); + for (int slot = 0; slot < te.inventory.getSlots(); slot++) { + InventoryHelper.spawnItemStack(worldIn, pos.getX(), pos.getY(), pos.getZ(), + te.inventory.getStackInSlot(slot)); + } + + if (state.hasTileEntity() && state.getBlock() != newState.getBlock()) { + worldIn.removeTileEntity(pos); + } + + } + } diff --git a/src/main/java/com/simibubi/create/block/SchematicannonContainer.java b/src/main/java/com/simibubi/create/block/SchematicannonContainer.java new file mode 100644 index 000000000..d51139b5f --- /dev/null +++ b/src/main/java/com/simibubi/create/block/SchematicannonContainer.java @@ -0,0 +1,92 @@ +package com.simibubi.create.block; + +import com.simibubi.create.AllContainers; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.container.Container; +import net.minecraft.inventory.container.Slot; +import net.minecraft.item.ItemStack; +import net.minecraft.network.PacketBuffer; +import net.minecraftforge.items.SlotItemHandler; + +public class SchematicannonContainer extends Container { + + private SchematicannonTileEntity te; + private PlayerEntity player; + + public SchematicannonContainer(int id, PlayerInventory inv, PacketBuffer buffer) { + super(AllContainers.Schematicannon.type, id); + player = inv.player; + ClientWorld world = Minecraft.getInstance().world; + this.te = (SchematicannonTileEntity) world.getTileEntity(buffer.readBlockPos()); + this.te.handleUpdateTag(buffer.readCompoundTag()); + init(); + } + + public SchematicannonContainer(int id, PlayerInventory inv, SchematicannonTileEntity te) { + super(AllContainers.Schematicannon.type, id); + player = inv.player; + this.te = te; + init(); + } + + protected void init() { + + int x = 20; + int y = 0; + + addSlot(new SlotItemHandler(te.inventory, 0, x + 14, y + 37)); + addSlot(new SlotItemHandler(te.inventory, 1, x + 170, y + 37)); + addSlot(new SlotItemHandler(te.inventory, 2, x + 222, y + 21)); + addSlot(new SlotItemHandler(te.inventory, 3, x + 222, y + 60)); + addSlot(new SlotItemHandler(te.inventory, 4, x + 51, y + 135)); + + // player Slots + for (int row = 0; row < 3; ++row) { + for (int col = 0; col < 9; ++col) { + addSlot(new Slot(player.inventory, col + row * 9 + 9, -2 + col * 18, 163 + row * 18)); + } + } + for (int hotbarSlot = 0; hotbarSlot < 9; ++hotbarSlot) { + addSlot(new Slot(player.inventory, hotbarSlot, -2 + hotbarSlot * 18, 221)); + } + + detectAndSendChanges(); + } + + @Override + public boolean canInteractWith(PlayerEntity playerIn) { + return true; + } + + @Override + public void onContainerClosed(PlayerEntity playerIn) { + super.onContainerClosed(playerIn); + } + + public SchematicannonTileEntity getTileEntity() { + return te; + } + + @Override + public ItemStack transferStackInSlot(PlayerEntity playerIn, int index) { + Slot clickedSlot = getSlot(index); + if (!clickedSlot.getHasStack()) + return ItemStack.EMPTY; + ItemStack stack = clickedSlot.getStack(); + + if (index < 5) { + mergeItemStack(stack, 5, inventorySlots.size(), false); + } else { + if (mergeItemStack(stack, 0, 1, false) || mergeItemStack(stack, 2, 3, false) + || mergeItemStack(stack, 4, 5, false)) + ; + } + + return ItemStack.EMPTY; + } + +} diff --git a/src/main/java/com/simibubi/create/block/SchematicannonTileEntity.java b/src/main/java/com/simibubi/create/block/SchematicannonTileEntity.java index 3192cc005..6b358c201 100644 --- a/src/main/java/com/simibubi/create/block/SchematicannonTileEntity.java +++ b/src/main/java/com/simibubi/create/block/SchematicannonTileEntity.java @@ -1,19 +1,13 @@ package com.simibubi.create.block; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.nio.file.StandardOpenOption; import java.util.HashMap; import java.util.LinkedList; import java.util.List; -import org.apache.commons.io.IOUtils; - import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllItems; import com.simibubi.create.AllTileEntities; -import com.simibubi.create.ServerSchematicLoader; +import com.simibubi.create.item.ItemBlueprint; import com.simibubi.create.schematic.Cuboid; import com.simibubi.create.schematic.SchematicWorld; import com.simibubi.create.utility.TileEntitySynced; @@ -21,13 +15,17 @@ import com.simibubi.create.utility.TileEntitySynced; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.entity.Entity; +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.BlockItem; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.nbt.CompoundNBT; -import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.nbt.ListNBT; import net.minecraft.nbt.NBTUtil; +import net.minecraft.network.PacketBuffer; import net.minecraft.tileentity.ITickableTileEntity; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityType; @@ -38,33 +36,88 @@ import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.StringTextComponent; import net.minecraft.world.Explosion; -import net.minecraft.world.gen.feature.template.PlacementSettings; import net.minecraft.world.gen.feature.template.Template; import net.minecraftforge.api.distmarker.Dist; 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.ItemStackHandler; -public class SchematicannonTileEntity extends TileEntitySynced implements ITickableTileEntity { +public class SchematicannonTileEntity extends TileEntitySynced implements ITickableTileEntity, INamedContainerProvider { public static final int PLACEMENT_DELAY = 10; + public static final float FUEL_PER_GUNPOWDER = .2f; + public static final float FUEL_USAGE_RATE = .0001f; - private SchematicWorld reader; + public enum State { + STOPPED, PAUSED, RUNNING; + } + + // Inventory + public SchematicannonInventory inventory; + + // Sync + public boolean sendUpdate; + + // Printer + private SchematicWorld blockReader; public BlockPos currentPos; - public BlockPos anchor; - public String schematicToPrint; + public BlockPos schematicAnchor; + public boolean schematicLoaded; public boolean missingBlock; - public boolean creative; + public boolean hasCreativeCrate; + private int printerCooldown; public BlockPos target; public BlockPos previousTarget; - public List attachedInventories; public List flyingBlocks; - private int cooldown; + // Gui information + public float fuelLevel; + public float paperPrintingProgress; + public float schematicProgress; + public String statusMsg; + public State state; + + // Settings + public int replaceMode; + public boolean skipMissing; + public boolean replaceTileEntities; + + public class SchematicannonInventory extends ItemStackHandler { + public SchematicannonInventory() { + super(5); + } + + @Override + protected void onContentsChanged(int slot) { + super.onContentsChanged(slot); + markDirty(); + } + + @Override + public boolean isItemValid(int slot, ItemStack stack) { + switch (slot) { + case 0: // Blueprint Slot + return AllItems.BLUEPRINT.typeOf(stack); + case 1: // Blueprint output + return false; + case 2: // Paper input + return stack.getItem() == Items.PAPER; + case 3: // Material List output + return false; + case 4: // Gunpowder + return stack.getItem() == Items.GUNPOWDER; + default: + return super.isItemValid(slot, stack); + } + } + } public class LaunchedBlock { public int totalTicks; @@ -111,14 +164,18 @@ public class SchematicannonTileEntity extends TileEntitySynced implements ITicka super(tileEntityTypeIn); attachedInventories = new LinkedList<>(); flyingBlocks = new LinkedList<>(); + inventory = new SchematicannonInventory(); + statusMsg = "Idle"; + state = State.STOPPED; + replaceMode = 2; } public void findInventories() { - creative = false; + hasCreativeCrate = false; for (Direction facing : Direction.values()) { if (AllBlocks.CREATIVE_CRATE.typeOf(world.getBlockState(pos.offset(facing)))) { - creative = true; + hasCreativeCrate = true; } TileEntity tileEntity = world.getTileEntity(pos.offset(facing)); @@ -134,58 +191,116 @@ public class SchematicannonTileEntity extends TileEntitySynced implements ITicka @Override public void read(CompoundNBT compound) { - if (compound.contains("Target")) { - target = NBTUtil.readBlockPos(compound.getCompound("Target")); - } - - if (compound.contains("FlyingBlocks")) { - - ListNBT tagBlocks = compound.getList("FlyingBlocks", 10); - if (tagBlocks.isEmpty()) - flyingBlocks.clear(); - - boolean pastDead = false; - - 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"); - - // Always write to Server tile - if (!world.isRemote) { - flyingBlocks.add(new LaunchedBlock(readBlockPos, readBlockState, int1, int2)); - continue; - } - - // Delete all Client side blocks that are now missing on the server - while (!pastDead && !flyingBlocks.isEmpty() && !flyingBlocks.get(0).target.equals(readBlockPos)) { - flyingBlocks.remove(0); - } - - pastDead = true; - - // Add new server side blocks - if (i >= flyingBlocks.size()) { - flyingBlocks.add(new LaunchedBlock(readBlockPos, readBlockState, int1, int2)); - continue; - } - - // Don't do anything with existing - } - } - + inventory.deserializeNBT(compound.getCompound("Inventory")); + + if (compound.contains("Running")) + currentPos = NBTUtil.readBlockPos(compound.getCompound("CurrentPos")); + + readClientUpdate(compound); super.read(compound); } + + @Override + public void onLoad() { + findInventories(); + super.onLoad(); + } + + @Override + public void readClientUpdate(CompoundNBT compound) { + + // Gui information + statusMsg = compound.getString("Status"); + schematicProgress = compound.getFloat("Progress"); + paperPrintingProgress = compound.getFloat("PaperProgress"); + fuelLevel = compound.getFloat("Fuel"); + state = State.valueOf(compound.getString("State")); + + // Settings + CompoundNBT options = compound.getCompound("Options"); + replaceMode = options.getInt("ReplaceMode"); + skipMissing = options.getBoolean("SkipMissing"); + replaceTileEntities = options.getBoolean("ReplaceTileEntities"); + + // Printer & Flying Blocks + if (compound.contains("Target")) + target = NBTUtil.readBlockPos(compound.getCompound("Target")); + if (compound.contains("FlyingBlocks")) + readFlyingBlocks(compound); + + } + + protected void readFlyingBlocks(CompoundNBT compound) { + ListNBT tagBlocks = compound.getList("FlyingBlocks", 10); + if (tagBlocks.isEmpty()) + flyingBlocks.clear(); + + boolean pastDead = false; + + 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"); + + // Always write to Server tile + if (world == null || !world.isRemote) { + flyingBlocks.add(new LaunchedBlock(readBlockPos, readBlockState, int1, int2)); + continue; + } + + // Delete all Client side blocks that are now missing on the server + while (!pastDead && !flyingBlocks.isEmpty() && !flyingBlocks.get(0).target.equals(readBlockPos)) { + flyingBlocks.remove(0); + } + + pastDead = true; + + // Add new server side blocks + if (i >= flyingBlocks.size()) { + flyingBlocks.add(new LaunchedBlock(readBlockPos, readBlockState, int1, int2)); + continue; + } + + // Don't do anything with existing + } + } @Override public CompoundNBT write(CompoundNBT compound) { - if (target != null) { - compound.put("Target", NBTUtil.writeBlockPos(target)); + compound.put("Inventory", inventory.serializeNBT()); + + if (state == State.RUNNING) { + compound.putBoolean("Running", true); + compound.put("CurrentPos", NBTUtil.writeBlockPos(currentPos)); } + + writeToClient(compound); + return super.write(compound); + } + @Override + public CompoundNBT writeToClient(CompoundNBT compound) { + + // Gui information + compound.putFloat("Progress", schematicProgress); + compound.putFloat("PaperProgress", paperPrintingProgress); + compound.putFloat("Fuel", fuelLevel); + compound.putString("Status", statusMsg); + compound.putString("State", state.name()); + + // Settings + CompoundNBT options = new CompoundNBT(); + options.putInt("ReplaceMode", replaceMode); + options.putBoolean("SkipMissing", skipMissing); + options.putBoolean("ReplaceTileEntities", replaceTileEntities); + compound.put("Options", options); + + // Printer & Flying Blocks + if (target != null) + compound.put("Target", NBTUtil.writeBlockPos(target)); ListNBT tagBlocks = new ListNBT(); for (LaunchedBlock b : flyingBlocks) { CompoundNBT c = new CompoundNBT(); @@ -197,13 +312,219 @@ public class SchematicannonTileEntity extends TileEntitySynced implements ITicka } compound.put("FlyingBlocks", tagBlocks); - return super.write(compound); + return compound; } @Override public void tick() { previousTarget = target; + tickFlyingBlocks(); + if (world.isRemote) + return; + + // Update Fuel and Paper + tickPaperPrinter(); + refillFuelIfPossible(); + + // Update Printer + tickPrinter(); + + // Update Client Tile + if (sendUpdate) { + sendUpdate = false; + world.notifyBlockUpdate(pos, getBlockState(), getBlockState(), 6); + } + } + + protected void tickPrinter() { + ItemStack blueprint = inventory.getStackInSlot(0); + + // Skip if not Active + if (state == State.STOPPED) { + if (schematicLoaded) + resetPrinter(); + return; + } + if (state == State.PAUSED && !missingBlock && fuelLevel > FUEL_USAGE_RATE) + return; + + if (blueprint.isEmpty()) { + state = State.STOPPED; + statusMsg = "Idle"; + sendUpdate = true; + return; + } + + // Initialize Printer + if (!schematicLoaded) { + if (!blueprint.hasTag()) { + state = State.STOPPED; + statusMsg = "Invalid Blueprint"; + sendUpdate = true; + return; + } + + if (!blueprint.getTag().getBoolean("Deployed")) { + state = State.STOPPED; + statusMsg = "Blueprint not Deployed"; + sendUpdate = true; + return; + } + + currentPos = currentPos != null ? currentPos.west() : BlockPos.ZERO.west(); + schematicAnchor = NBTUtil.readBlockPos(blueprint.getTag().getCompound("Anchor")); + + // Load blocks into reader + Template activeTemplate = ItemBlueprint.getSchematic(blueprint); + blockReader = new SchematicWorld(new HashMap<>(), new Cuboid(), schematicAnchor); + activeTemplate.addBlocksToWorld(blockReader, schematicAnchor, ItemBlueprint.getSettings(blueprint)); + schematicLoaded = true; + sendUpdate = true; + return; + } + + // Cooldown from last shot + if (printerCooldown > 0) { + printerCooldown--; + return; + } + + // Check Fuel + if (fuelLevel <= 0) { + fuelLevel = 0; + state = State.PAUSED; + statusMsg = "Out of Gunpowder"; + sendUpdate = true; + return; + } + + // Update Target + if (!missingBlock) { + advanceCurrentPos(); + + // End reached + if (state == State.STOPPED) + return; + + sendUpdate = true; + target = schematicAnchor.add(currentPos); + } + + // Check block + BlockState blockState = blockReader.getBlockState(target); + if (!shouldPlace(target, blockState)) + return; + + // Find Item + ItemStack requiredItem = getItemForBlock(blockState); + if (!findItemInAttachedInventories(requiredItem)) { + if (skipMissing) { + statusMsg = "Skipping"; + if (missingBlock) { + missingBlock = false; + state = State.RUNNING; + } + return; + } + + missingBlock = true; + state = State.PAUSED; + statusMsg = "Missing " + blockState.getBlock().getNameTextComponent().getFormattedText(); + return; + } + + // Success + state = State.RUNNING; + statusMsg = "Running..."; + launchBlock(target, blockState); + printerCooldown = PLACEMENT_DELAY; + fuelLevel -= FUEL_USAGE_RATE; + sendUpdate = true; + missingBlock = false; + } + + protected ItemStack getItemForBlock(BlockState blockState) { + return new ItemStack(BlockItem.BLOCK_TO_ITEM.getOrDefault(blockState.getBlock(), Items.AIR)); + } + + protected boolean findItemInAttachedInventories(ItemStack requiredItem) { + if (hasCreativeCrate) + return true; + + for (IItemHandler iItemHandler : attachedInventories) { + for (int slot = 0; slot < iItemHandler.getSlots(); slot++) { + ItemStack stackInSlot = iItemHandler.getStackInSlot(slot); + if (!stackInSlot.isItemEqual(requiredItem)) + continue; + if (!iItemHandler.extractItem(slot, 1, false).isEmpty()) + return true; + } + } + return false; + } + + protected void advanceCurrentPos() { + BlockPos size = blockReader.getBounds().getSize(); + currentPos = currentPos.offset(Direction.EAST); + + schematicProgress += 1d / (size.getX() * size.getY() * size.getZ()); + + if (currentPos.getX() > size.getX()) + currentPos = new BlockPos(0, currentPos.getY(), currentPos.getZ() + 1); + if (currentPos.getZ() > size.getZ()) + currentPos = new BlockPos(currentPos.getX(), currentPos.getY() + 1, 0); + + // End reached + if (currentPos.getY() > size.getY()) { + inventory.setStackInSlot(0, ItemStack.EMPTY); + inventory.setStackInSlot(1, new ItemStack(AllItems.EMPTY_BLUEPRINT.get())); + state = State.STOPPED; + statusMsg = "Finished"; + resetPrinter(); + target = getPos().add(1, 0, 0); + world.playSound(null, pos.getX(), pos.getY(), pos.getZ(), SoundEvents.BLOCK_NOTE_BLOCK_BELL, + SoundCategory.BLOCKS, 1, .7f); + sendUpdate = true; + return; + } + } + + protected void resetPrinter() { + schematicLoaded = false; + schematicAnchor = null; + currentPos = null; + blockReader = null; + missingBlock = false; + sendUpdate = true; + schematicProgress = 0; + } + + protected boolean shouldPlace(BlockPos pos, BlockState state) { + BlockState toReplace = world.getBlockState(pos); + boolean placingAir = state.getBlock() == Blocks.AIR; + + if (toReplace.getBlockState() == state) + return false; + if (pos.withinDistance(getPos(), 2f)) + return false; + if (!replaceTileEntities && toReplace.hasTileEntity()) + return false; + + if (replaceMode == 3) + return true; + if (replaceMode == 2 && !placingAir) + return true; + if (replaceMode == 1 && (state.isNormalCube(blockReader, pos.subtract(schematicAnchor)) + || !toReplace.isNormalCube(world, pos)) && !placingAir) + return true; + if (replaceMode == 0 && !toReplace.isNormalCube(world, pos) && !placingAir) + return true; + + return false; + } + + protected void tickFlyingBlocks() { List toRemove = new LinkedList<>(); for (LaunchedBlock b : flyingBlocks) { b.update(); @@ -213,111 +534,66 @@ public class SchematicannonTileEntity extends TileEntitySynced implements ITicka } } flyingBlocks.removeAll(toRemove); - - if (world.isRemote) - return; - if (schematicToPrint == null) - return; - if (cooldown-- > 0) - return; - cooldown = PLACEMENT_DELAY; - - if (reader == null) { - currentPos = BlockPos.ZERO; - currentPos = currentPos.offset(Direction.WEST); - - String filepath = ServerSchematicLoader.PATH + "/" + schematicToPrint; - Template activeTemplate = new Template(); - - InputStream stream = null; - try { - stream = Files.newInputStream(Paths.get(filepath), StandardOpenOption.READ); - CompoundNBT nbt = CompressedStreamTools.readCompressed(stream); - activeTemplate.read(nbt); - reader = new SchematicWorld(new HashMap<>(), new Cuboid(BlockPos.ZERO, 0, 0, 0), anchor); - activeTemplate.addBlocksToWorld(reader, anchor, new PlacementSettings()); - - } catch (IOException e) { - e.printStackTrace(); - } finally { - if (stream != null) - IOUtils.closeQuietly(stream); - } - return; - } - - BlockPos size = reader.getBounds().getSize(); - BlockState state; - do { - // Find next block to place - if (!missingBlock || creative) - currentPos = currentPos.offset(Direction.EAST); - if (currentPos.getX() > size.getX()) { - currentPos = new BlockPos(0, currentPos.getY(), currentPos.getZ() + 1); - } - if (currentPos.getZ() > size.getZ()) { - currentPos = new BlockPos(currentPos.getX(), currentPos.getY() + 1, 0); - } - if (currentPos.getY() > size.getY()) { - schematicToPrint = null; - currentPos = null; - anchor = null; - reader = null; - missingBlock = false; - target = getPos().add(1, 0, 0); - world.playSound(null, pos.getX(), pos.getY(), pos.getZ(), SoundEvents.BLOCK_NOTE_BLOCK_BELL, - SoundCategory.BLOCKS, 1, .7f); - world.notifyBlockUpdate(getPos(), getBlockState(), getBlockState(), 2); - return; - } - state = reader.getBlockState(anchor.add(currentPos)); - } while (state.getBlock() == Blocks.AIR); - - target = anchor.add(currentPos); - missingBlock = false; - - // Update orientation - world.notifyBlockUpdate(getPos(), getBlockState(), getBlockState(), 2); - - if (target.withinDistance(getPos(), 2f)) { - return; - } - - if (creative) { - launchBlock(currentPos.add(anchor), state); - return; - } - - if (world.getBlockState(target).getBlock() == state.getBlock()) { - // Don't overwrite tiles - if (world.getTileEntity(target) != null) - return; - - // Overwrite in case its rotated - launchBlock(target, state); - } - - // Search for required item - missingBlock = true; - ItemStack requiredItem = new ItemStack(BlockItem.BLOCK_TO_ITEM.getOrDefault(state.getBlock(), Items.AIR)); - for (IItemHandler iItemHandler : attachedInventories) { - for (int slot = 0; slot < iItemHandler.getSlots(); slot++) { - ItemStack stackInSlot = iItemHandler.getStackInSlot(slot); - if (!stackInSlot.isItemEqual(requiredItem)) - continue; - iItemHandler.extractItem(slot, 1, false); - launchBlock(target, state); - missingBlock = false; - return; - } - } } - private void launchBlock(BlockPos target, BlockState state) { + protected void refillFuelIfPossible() { + if (1 - fuelLevel + 1 / 128f < FUEL_PER_GUNPOWDER) + return; + if (inventory.getStackInSlot(4).isEmpty()) + return; + + inventory.getStackInSlot(4).shrink(1); + fuelLevel += FUEL_PER_GUNPOWDER; + sendUpdate = true; + } + + protected void tickPaperPrinter() { + int PaperInput = 2; + int PaperOutput = 3; + + ItemStack paper = inventory.extractItem(PaperInput, 1, true); + boolean outputFull = inventory.getStackInSlot(PaperOutput).getCount() == inventory.getSlotLimit(PaperOutput); + + if (paper.isEmpty() || outputFull) { + if (paperPrintingProgress != 0) + sendUpdate = true; + paperPrintingProgress = 0; + return; + } + + if (paperPrintingProgress >= 1) { + paperPrintingProgress = 0; + inventory.extractItem(PaperInput, 1, false); + inventory.setStackInSlot(PaperOutput, + new ItemStack(Items.PAPER, inventory.getStackInSlot(PaperOutput).getCount() + 1)); + sendUpdate = true; + return; + } + + paperPrintingProgress += 0.05f; + sendUpdate = true; + } + + protected void launchBlock(BlockPos target, BlockState state) { flyingBlocks.add(new LaunchedBlock(target, state)); Vec3d explosionPos = new Vec3d(pos).add(new Vec3d(target.subtract(pos)).normalize()); this.world.createExplosion((Entity) null, explosionPos.x, explosionPos.y + 1.5f, explosionPos.z, 0, Explosion.Mode.NONE); } + public void sendToContainer(PacketBuffer buffer) { + buffer.writeBlockPos(getPos()); + buffer.writeCompoundTag(getUpdateTag()); + } + + @Override + public Container createMenu(int id, PlayerInventory inv, PlayerEntity player) { + return new SchematicannonContainer(id, inv, this); + } + + @Override + public ITextComponent getDisplayName() { + return new StringTextComponent(getType().getRegistryName().toString()); + } + } diff --git a/src/main/java/com/simibubi/create/gui/AbstractSimiContainerScreen.java b/src/main/java/com/simibubi/create/gui/AbstractSimiContainerScreen.java new file mode 100644 index 000000000..373eb9564 --- /dev/null +++ b/src/main/java/com/simibubi/create/gui/AbstractSimiContainerScreen.java @@ -0,0 +1,131 @@ +package com.simibubi.create.gui; + +import java.util.ArrayList; +import java.util.List; + +import com.mojang.blaze3d.platform.GlStateManager; +import com.simibubi.create.gui.widgets.AbstractSimiWidget; + +import net.minecraft.client.gui.screen.inventory.ContainerScreen; +import net.minecraft.client.gui.widget.Widget; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.container.Container; +import net.minecraft.util.text.ITextComponent; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +@OnlyIn(Dist.CLIENT) +public abstract class AbstractSimiContainerScreen extends ContainerScreen { + + protected List widgets; + + protected AbstractSimiContainerScreen(T container, PlayerInventory inv, ITextComponent title) { + super(container, inv, title); + widgets = new ArrayList<>(); + } + + protected void setWindowSize(int width, int height) { + this.xSize = width; + this.ySize = height; + } + + @Override + public void render(int mouseX, int mouseY, float partialTicks) { + renderBackground(); + renderWindow(mouseX, mouseY, partialTicks); + + super.render(mouseX, mouseY, partialTicks); + + GlStateManager.enableAlphaTest(); + GlStateManager.enableBlend(); + GlStateManager.disableRescaleNormal(); + RenderHelper.disableStandardItemLighting(); + GlStateManager.disableLighting(); + GlStateManager.disableDepthTest(); + + for (Widget widget : widgets) + widget.render(mouseX, mouseY, partialTicks); + renderWindowForeground(mouseX, mouseY, partialTicks); + for (Widget widget : widgets) + widget.renderToolTip(mouseX, mouseY); + } + + @Override + public boolean mouseClicked(double x, double y, int button) { + boolean result = false; + for (Widget widget : widgets) { + if (widget.mouseClicked(x, y, button)) + result = true; + } + return result || super.mouseClicked(x, y, button); + } + + @Override + public boolean keyPressed(int code, int p_keyPressed_2_, int p_keyPressed_3_) { + for (Widget widget : widgets) { + if (widget.keyPressed(code, p_keyPressed_2_, p_keyPressed_3_)) + return true; + } + return super.keyPressed(code, p_keyPressed_2_, p_keyPressed_3_); + } + + @Override + public boolean charTyped(char character, int code) { + for (Widget widget : widgets) { + if (widget.charTyped(character, code)) + return true; + } + if (character == 'e') + onClose(); + return super.charTyped(character, code); + } + + @Override + public boolean mouseScrolled(double mouseX, double mouseY, double delta) { + for (Widget widget : widgets) { + if (widget.mouseScrolled(mouseX, mouseY, delta)) + return true; + } + return super.mouseScrolled(mouseX, mouseY, delta); + } + + @Override + public boolean mouseReleased(double x, double y, int button) { + boolean result = false; + for (Widget widget : widgets) { + if (widget.mouseReleased(x, y, button)) + result = true; + } + return result | super.mouseReleased(x, y, button); + } + + @Override + public boolean shouldCloseOnEsc() { + return true; + } + + @Override + public boolean isPauseScreen() { + return false; + } + + protected abstract void renderWindow(int mouseX, int mouseY, float partialTicks); + + @Override + protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY) { + } + + protected void renderWindowForeground(int mouseX, int mouseY, float partialTicks) { + super.renderHoveredToolTip(mouseX, mouseY); + for (Widget widget : widgets) { + if (!widget.isHovered()) + continue; + + if (widget instanceof AbstractSimiWidget && !((AbstractSimiWidget) widget).getToolTip().isEmpty()) { + renderTooltip(((AbstractSimiWidget) widget).getToolTip(), mouseX, mouseY); + } + } + } + +} diff --git a/src/main/java/com/simibubi/create/gui/GuiResources.java b/src/main/java/com/simibubi/create/gui/GuiResources.java index 42ee6f7a3..f78670bb3 100644 --- a/src/main/java/com/simibubi/create/gui/GuiResources.java +++ b/src/main/java/com/simibubi/create/gui/GuiResources.java @@ -11,9 +11,16 @@ public enum GuiResources { // Inventories PLAYER_INVENTORY("player_inventory.png", 176, 108), WAND_SYMMETRY("wand_symmetry.png", 207, 58), + SCHEMATIC_TABLE("schematic_table.png", 207, 89), SCHEMATIC_TABLE_PROGRESS("schematic_table.png", 209, 0, 24, 17), SCHEMATIC("schematic.png", 207, 95), + + SCHEMATICANNON("schematicannon.png", 247, 161), + SCHEMATICANNON_PROGRESS("schematicannon.png", 0, 161, 121, 16), + SCHEMATICANNON_PROGRESS_2("schematicannon.png", 122, 161, 16, 15), + SCHEMATICANNON_HIGHLIGHT("schematicannon.png", 0, 182, 28, 28), + SCHEMATICANNON_FUEL("schematicannon.png", 0, 215, 82, 4), // Widgets PALETTE_BUTTON("palette_picker.png", 0, 236, 20, 20), @@ -40,26 +47,23 @@ public enum GuiResources { ICON_NORMAL_ROOF("icons.png", 32, 16, 16, 16), ICON_FLAT_ROOF("icons.png", 48, 16, 16, 16), - ICON_NO_ROOF("icons.png", 0, 32, 16, 16), - ICON_TOWER_NO_ROOF("icons.png", 16, 32, 16, 16), - ICON_TOWER_ROOF("icons.png", 32, 32, 16, 16), - ICON_TOWER_FLAT_ROOF("icons.png", 48, 32, 16, 16), + ICON_DONT_REPLACE("icons.png", 0, 32, 16, 16), + ICON_REPLACE_SOLID("icons.png", 16, 32, 16, 16), + ICON_REPLACE_ANY("icons.png", 32, 32, 16, 16), + ICON_REPLACE_EMPTY("icons.png", 48, 32, 16, 16), - ICON_LAYER_REGULAR("icons.png", 0, 48, 16, 16), - ICON_LAYER_OPEN("icons.png", 16, 48, 16, 16), - ICON_LAYER_FOUNDATION("icons.png", 32, 48, 16, 16), - ICON_LAYER_SPECIAL("icons.png", 48, 48, 16, 16), + ICON_TOOL_DEPLOY("icons.png", 0, 48, 16, 16), + ICON_SKIP_MISSING("icons.png", 16, 48, 16, 16), - ICON_TOOL_RESHAPE("icons.png", 0, 64, 16, 16), - ICON_TOOL_ROOM("icons.png", 16, 64, 16, 16), - ICON_TOOL_TOWER("icons.png", 32, 64, 16, 16), - ICON_TOOL_STACK("icons.png", 48, 64, 16, 16), + ICON_TOOL_MOVE_XZ("icons.png", 0, 64, 16, 16), + ICON_TOOL_MOVE_Y("icons.png", 16, 64, 16, 16), + ICON_TOOL_ROTATE("icons.png", 32, 64, 16, 16), + ICON_TOOL_MIRROR("icons.png", 48, 64, 16, 16), - ICON_TOOL_HEIGHT("icons.png", 0, 80, 16, 16), - ICON_TOOL_REROLL("icons.png", 16, 80, 16, 16), - ICON_TOOL_REROLL_TARGET("icons.png", 32, 80, 16, 16), - ICON_TOOL_PALETTE("icons.png", 48, 80, 16, 16); + ICON_PLAY("icons.png", 0, 80, 16, 16), + ICON_PAUSE("icons.png", 16, 80, 16, 16), + ICON_STOP("icons.png", 32, 80, 16, 16); public static final int FONT_COLOR = 0x575F7A; diff --git a/src/main/java/com/simibubi/create/gui/SchematicTableScreen.java b/src/main/java/com/simibubi/create/gui/SchematicTableScreen.java index 8e8a0d5ab..c5c472b2d 100644 --- a/src/main/java/com/simibubi/create/gui/SchematicTableScreen.java +++ b/src/main/java/com/simibubi/create/gui/SchematicTableScreen.java @@ -147,24 +147,23 @@ public class SchematicTableScreen extends ContainerScreen availableSchematics = Create.cSchematicLoader.getAvailableSchematics(); + if (button.active && button.isHovered() && ((SchematicTableContainer) container).canWrite() && schematics != null) { + lastProgress = progress = 0; + List availableSchematics = Create.cSchematicLoader.getAvailableSchematics(); String schematic = availableSchematics.get(schematics.getState()); Create.cSchematicLoader.startNewUpload(schematic); } diff --git a/src/main/java/com/simibubi/create/gui/SchematicannonScreen.java b/src/main/java/com/simibubi/create/gui/SchematicannonScreen.java new file mode 100644 index 000000000..c7cd9c686 --- /dev/null +++ b/src/main/java/com/simibubi/create/gui/SchematicannonScreen.java @@ -0,0 +1,319 @@ +package com.simibubi.create.gui; + +import java.util.Collections; +import java.util.List; +import java.util.Vector; + +import com.google.common.collect.ImmutableList; +import com.mojang.blaze3d.platform.GlStateManager; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.block.SchematicannonContainer; +import com.simibubi.create.block.SchematicannonTileEntity; +import com.simibubi.create.gui.widgets.GuiIndicator; +import com.simibubi.create.gui.widgets.GuiIndicator.State; +import com.simibubi.create.gui.widgets.SimiButton; +import com.simibubi.create.networking.PacketConfigureSchematicannon; +import com.simibubi.create.networking.PacketConfigureSchematicannon.Option; +import com.simibubi.create.networking.Packets; + +import net.minecraft.client.gui.widget.Widget; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextFormatting; + +public class SchematicannonScreen extends AbstractSimiContainerScreen { + + protected Vector replaceLevelIndicators; + protected Vector replaceLevelButtons; + + protected SimiButton skipMissingButton; + protected GuiIndicator skipMissingIndicator; + + protected SimiButton playButton; + protected GuiIndicator playIndicator; + protected SimiButton pauseButton; + protected GuiIndicator pauseIndicator; + protected SimiButton resetButton; + protected GuiIndicator resetIndicator; + + public SchematicannonScreen(SchematicannonContainer container, PlayerInventory inventory, + ITextComponent p_i51105_3_) { + super(container, inventory, p_i51105_3_); + } + + @Override + protected void init() { + setWindowSize(GuiResources.SCHEMATICANNON.width + 50, GuiResources.SCHEMATICANNON.height + 80); + super.init(); + + int x = guiLeft + 20; + int y = guiTop; + + widgets.clear(); + + // Play Pause Stop + playButton = new SimiButton(x + 69, y + 55, GuiResources.ICON_PLAY); + playIndicator = new GuiIndicator(x + 69, y + 50, ""); + pauseButton = new SimiButton(x + 88, y + 55, GuiResources.ICON_PAUSE); + pauseIndicator = new GuiIndicator(x + 88, y + 50, ""); + resetButton = new SimiButton(x + 107, y + 55, GuiResources.ICON_STOP); + resetIndicator = new GuiIndicator(x + 107, y + 50, "Not Running"); + resetIndicator.state = State.RED; + Collections.addAll(widgets, playButton, playIndicator, pauseButton, pauseIndicator, resetButton, + resetIndicator); + + // Replace settings + replaceLevelButtons = new Vector<>(4); + replaceLevelIndicators = new Vector<>(4); + List icons = ImmutableList.of(GuiResources.ICON_DONT_REPLACE, GuiResources.ICON_REPLACE_SOLID, + GuiResources.ICON_REPLACE_ANY, GuiResources.ICON_REPLACE_EMPTY); + List toolTips = ImmutableList.of("Don't Replace Solid Blocks", "Replace Solid with Solid", + "Replace Solid with Any", "Replace Solid with Empty"); + + for (int i = 0; i < 4; i++) { + replaceLevelIndicators.add(new GuiIndicator(x + 12 + i * 18, y + 96, "")); + replaceLevelButtons.add(new SimiButton(x + 12 + i * 18, y + 101, icons.get(i))); + replaceLevelButtons.get(i).setToolTip(toolTips.get(i)); + } + widgets.addAll(replaceLevelButtons); + widgets.addAll(replaceLevelIndicators); + + // Other Settings + skipMissingButton = new SimiButton(x + 107, y + 101, GuiResources.ICON_SKIP_MISSING); + skipMissingButton.setToolTip("Skip missing Blocks"); + skipMissingIndicator = new GuiIndicator(x + 107, y + 96, ""); + Collections.addAll(widgets, skipMissingButton, skipMissingIndicator); + + tick(); + } + + @Override + public void tick() { + + SchematicannonTileEntity te = container.getTileEntity(); + for (int replaceMode = 0; replaceMode < replaceLevelButtons.size(); replaceMode++) + replaceLevelIndicators.get(replaceMode).state = replaceMode <= te.replaceMode ? State.ON : State.OFF; + + skipMissingIndicator.state = te.skipMissing ? State.ON : State.OFF; + + playIndicator.state = State.OFF; + pauseIndicator.state = State.OFF; + resetIndicator.state = State.OFF; + + switch (te.state) { + case PAUSED: + pauseIndicator.state = State.YELLOW; + playButton.active = true; + pauseButton.active = false; + resetButton.active = true; + break; + case RUNNING: + playIndicator.state = State.GREEN; + playButton.active = false; + pauseButton.active = true; + resetButton.active = true; + break; + case STOPPED: + resetIndicator.state = State.RED; + playButton.active = true; + pauseButton.active = false; + resetButton.active = false; + break; + default: + break; + } + + handleTooltips(); + + super.tick(); + } + + protected void handleTooltips() { + for (Widget w : widgets) + if (w instanceof SimiButton) + if (!((SimiButton) w).getToolTip().isEmpty()) { + ((SimiButton) w).setToolTip(((SimiButton) w).getToolTip().get(0)); + ((SimiButton) w).getToolTip() + .add(TextFormatting.DARK_GRAY + "" + TextFormatting.ITALIC + "[Ctrl] for more Info"); + } + + if (hasControlDown()) { + if (skipMissingButton.isHovered()) { + List tip = skipMissingButton.getToolTip(); + tip.remove(1); + tip.add(TextFormatting.BLUE + + (skipMissingIndicator.state == State.ON ? "Currently Enabled" : "Currently Disabled")); + tip.add(TextFormatting.GRAY + "If the Schematicannon cannot find"); + tip.add(TextFormatting.GRAY + "a required Block for placement, it"); + tip.add(TextFormatting.GRAY + "will continue at the next Location."); + } + if (replaceLevelButtons.get(0).isHovered()) { + List tip = replaceLevelButtons.get(0).getToolTip(); + tip.remove(1); + tip.add(TextFormatting.BLUE + (replaceLevelIndicators.get(0).state == State.ON ? "Currently Enabled" + : "Currently Disabled")); + tip.add(TextFormatting.GRAY + "The cannon will never replace"); + tip.add(TextFormatting.GRAY + "any Solid blocks in its working area,"); + tip.add(TextFormatting.GRAY + "only non-Solid and Air."); + } + if (replaceLevelButtons.get(1).isHovered()) { + List tip = replaceLevelButtons.get(1).getToolTip(); + tip.remove(1); + tip.add(TextFormatting.BLUE + (replaceLevelIndicators.get(1).state == State.ON ? "Currently Enabled" + : "Currently Disabled")); + tip.add(TextFormatting.GRAY + "The cannon will only replace"); + tip.add(TextFormatting.GRAY + "Solid blocks in its working area,"); + tip.add(TextFormatting.GRAY + "if the Schematic contains a solid"); + tip.add(TextFormatting.GRAY + "Block at their location."); + } + if (replaceLevelButtons.get(2).isHovered()) { + List tip = replaceLevelButtons.get(2).getToolTip(); + tip.remove(1); + tip.add(TextFormatting.BLUE + (replaceLevelIndicators.get(2).state == State.ON ? "Currently Enabled" + : "Currently Disabled")); + tip.add(TextFormatting.GRAY + "The cannon will replace"); + tip.add(TextFormatting.GRAY + "Solid blocks in its working area,"); + tip.add(TextFormatting.GRAY + "if the Schematic contains any"); + tip.add(TextFormatting.GRAY + "Block at their location."); + } + if (replaceLevelButtons.get(3).isHovered()) { + List tip = replaceLevelButtons.get(3).getToolTip(); + tip.remove(1); + tip.add(TextFormatting.BLUE + (replaceLevelIndicators.get(3).state == State.ON ? "Currently Enabled" + : "Currently Disabled")); + tip.add(TextFormatting.GRAY + "The cannon will clear out all"); + tip.add(TextFormatting.GRAY + "blocks in its working area,"); + tip.add(TextFormatting.GRAY + "including those replaced by Air."); + } + + } + } + + @Override + protected void renderWindow(int mouseX, int mouseY, float partialTicks) { + GuiResources.PLAYER_INVENTORY.draw(this, guiLeft - 10, guiTop + 145); + GuiResources.SCHEMATICANNON.draw(this, guiLeft + 20, guiTop); + + SchematicannonTileEntity te = container.getTileEntity(); + renderPrintingProgress(te.schematicProgress); + renderFuelBar(te.fuelLevel); + renderChecklistPrinterProgress(te.paperPrintingProgress); + + if (!te.inventory.getStackInSlot(0).isEmpty()) + renderBlueprintHighlight(); + + renderCannon(); + + font.drawString("Schematicannon", guiLeft + 80, guiTop + 10, GuiResources.FONT_COLOR); + + String msg = te.statusMsg; + int stringWidth = font.getStringWidth(msg); + if (stringWidth < 120) + font.drawStringWithShadow(msg, guiLeft + 20 + 96 - stringWidth / 2, guiTop + 30, 0xCCDDFF); + else + font.drawSplitString(msg, guiLeft + 20 + 45, guiTop + 24, 120, 0xCCDDFF); + + font.drawString("Placement Settings", guiLeft + 20 + 13, guiTop + 84, GuiResources.FONT_COLOR); + font.drawString("Inventory", guiLeft - 10 + 7, guiTop + 145 + 6, 0x666666); + } + + protected void renderCannon() { + GlStateManager.pushMatrix(); + + GlStateManager.enableBlend(); + GlStateManager.enableRescaleNormal(); + GlStateManager.enableAlphaTest(); + RenderHelper.enableGUIStandardItemLighting(); + GlStateManager.color4f(1.0F, 1.0F, 1.0F, 1.0F); + + GlStateManager.translated(guiLeft + 240, guiTop + 120, 200); + GlStateManager.scaled(5, 5, 5); + + itemRenderer.renderItemIntoGUI(new ItemStack(AllBlocks.SCHEMATICANNON.block), 0, 0); + + GlStateManager.popMatrix(); + } + + protected void renderBlueprintHighlight() { + GuiResources.SCHEMATICANNON_HIGHLIGHT.draw(this, guiLeft + 20 + 8, guiTop + 31); + } + + protected void renderPrintingProgress(float progress) { + GuiResources sprite = GuiResources.SCHEMATICANNON_PROGRESS; + minecraft.getTextureManager().bindTexture(sprite.location); + blit(guiLeft + 20 + 39, guiTop + 36, sprite.startX, sprite.startY, (int) (sprite.width * progress), + sprite.height); + } + + protected void renderChecklistPrinterProgress(float progress) { + GuiResources sprite = GuiResources.SCHEMATICANNON_PROGRESS_2; + minecraft.getTextureManager().bindTexture(sprite.location); + blit(guiLeft + 20 + 222, guiTop + 42, sprite.startX, sprite.startY, sprite.width, + (int) (sprite.height * progress)); + } + + protected void renderFuelBar(float amount) { + GuiResources sprite = GuiResources.SCHEMATICANNON_FUEL; + minecraft.getTextureManager().bindTexture(sprite.location); + blit(guiLeft + 20 + 73, guiTop + 135, sprite.startX, sprite.startY, (int) (sprite.width * amount), + sprite.height); + } + + @Override + protected void renderWindowForeground(int mouseX, int mouseY, float partialTicks) { + int fuelX = guiLeft + 20 + 73, fuelY = guiTop + 135; + if (mouseX >= fuelX && mouseY >= fuelY && mouseX <= fuelX + GuiResources.SCHEMATICANNON_FUEL.width + && mouseY <= fuelY + GuiResources.SCHEMATICANNON_FUEL.height) { + container.getTileEntity(); + SchematicannonTileEntity te = container.getTileEntity(); + int shotsLeft = (int) (te.fuelLevel / SchematicannonTileEntity.FUEL_USAGE_RATE); + int shotsLeftWithItems = (int) (shotsLeft + te.inventory.getStackInSlot(4).getCount() + * (SchematicannonTileEntity.FUEL_PER_GUNPOWDER / SchematicannonTileEntity.FUEL_USAGE_RATE)); + renderTooltip( + ImmutableList.of("Gunpowder at " + (int) (te.fuelLevel * 100) + "%", + TextFormatting.GRAY + "Shots left: " + TextFormatting.BLUE + shotsLeft, + TextFormatting.GRAY + "With backup: " + TextFormatting.BLUE + shotsLeftWithItems), + mouseX, mouseY); + } + + int paperX = guiLeft + 20 + 202, paperY = guiTop + 20; + if (mouseX >= paperX && mouseY >= paperY && mouseX <= paperX + 16 && mouseY <= paperY + 16) { + renderTooltip("Material List Printer", mouseX, mouseY); + } + + super.renderWindowForeground(mouseX, mouseY, partialTicks); + } + + @Override + public boolean mouseClicked(double x, double y, int button) { + + for (int replaceMode = 0; replaceMode < replaceLevelButtons.size(); replaceMode++) { + if (!replaceLevelButtons.get(replaceMode).isHovered()) + continue; + if (container.getTileEntity().replaceMode == replaceMode) + continue; + sendOptionUpdate(Option.values()[replaceMode], true); + } + + if (skipMissingButton.isHovered()) + sendOptionUpdate(Option.SKIP_MISSING, !container.getTileEntity().skipMissing); + + if (playButton.isHovered() && playButton.active) + sendOptionUpdate(Option.PLAY, true); + if (pauseButton.isHovered() && pauseButton.active) + sendOptionUpdate(Option.PAUSE, true); + if (resetButton.isHovered() && resetButton.active) + sendOptionUpdate(Option.STOP, true); + + + return super.mouseClicked(x, y, button); + } + + protected void sendOptionUpdate(Option option, boolean set) { + Packets.channel + .sendToServer(PacketConfigureSchematicannon.setOption(container.getTileEntity().getPos(), option, set)); + } + +} diff --git a/src/main/java/com/simibubi/create/gui/widgets/SimiButton.java b/src/main/java/com/simibubi/create/gui/widgets/SimiButton.java index bdca7aea9..58b60ab79 100644 --- a/src/main/java/com/simibubi/create/gui/widgets/SimiButton.java +++ b/src/main/java/com/simibubi/create/gui/widgets/SimiButton.java @@ -12,7 +12,7 @@ public class SimiButton extends AbstractSimiWidget { protected boolean pressed; public SimiButton(int x, int y, GuiResources icon) { - super(x, y, 16, 16); + super(x, y, 18, 18); this.icon = icon; } diff --git a/src/main/java/com/simibubi/create/item/ItemBlueprint.java b/src/main/java/com/simibubi/create/item/ItemBlueprint.java index c5fcd2aab..3ddfbb120 100644 --- a/src/main/java/com/simibubi/create/item/ItemBlueprint.java +++ b/src/main/java/com/simibubi/create/item/ItemBlueprint.java @@ -8,16 +8,11 @@ import java.nio.file.StandardOpenOption; import org.apache.commons.io.IOUtils; -import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; -import com.simibubi.create.block.SchematicannonTileEntity; import com.simibubi.create.gui.BlueprintEditScreen; import com.simibubi.create.gui.GuiOpener; -import com.simibubi.create.schematic.SchematicHologram; -import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.inventory.EquipmentSlotType; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.ItemUseContext; @@ -56,7 +51,7 @@ public class ItemBlueprint extends Item { tag.putString("Rotation", Rotation.NONE.name()); tag.putString("Mirror", Mirror.NONE.name()); blueprint.setTag(tag); - + writeSize(blueprint); blueprint.setDisplayName(new StringTextComponent(TextFormatting.RESET + "" + TextFormatting.WHITE + "Blueprint (" + TextFormatting.GOLD + schematic + TextFormatting.WHITE + ")")); @@ -70,10 +65,10 @@ public class ItemBlueprint extends Item { tag.put("Bounds", NBTUtil.writeBlockPos(t.getSize())); blueprint.setTag(tag); } - + public static PlacementSettings getSettings(ItemStack blueprint) { CompoundNBT tag = blueprint.getTag(); - + PlacementSettings settings = new PlacementSettings(); settings.setRotation(Rotation.valueOf(tag.getString("Rotation"))); settings.setMirror(Mirror.valueOf(tag.getString("Mirror"))); @@ -85,10 +80,10 @@ public class ItemBlueprint extends Item { Template t = new Template(); String owner = blueprint.getTag().getString("Owner"); String schematic = blueprint.getTag().getString("File"); - + String filepath = ""; - - if (Thread.currentThread().getThreadGroup() == SidedThreadGroups.SERVER) + + if (Thread.currentThread().getThreadGroup() == SidedThreadGroups.SERVER) filepath = "schematics/uploaded/" + owner + "/" + schematic; else filepath = "schematics/" + schematic; @@ -111,38 +106,14 @@ public class ItemBlueprint extends Item { @Override public ActionResultType onItemUse(ItemUseContext context) { - if (context.isPlacerSneaking() && context.getHand() == Hand.MAIN_HAND) { DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> { GuiOpener.open(new BlueprintEditScreen()); }); return ActionResultType.SUCCESS; } - - World world = context.getWorld(); - CompoundNBT tag = context.getItem().getTag(); - if (tag.contains("File")) { - BlockPos pos = context.getPos(); - BlockState blockState = world.getBlockState(pos); - if (AllBlocks.SCHEMATICANNON.typeOf(blockState)) { - if (world.isRemote) { - SchematicHologram.reset(); - return ActionResultType.SUCCESS; - } - if (!tag.contains("Anchor")) - return ActionResultType.FAIL; - - SchematicannonTileEntity te = (SchematicannonTileEntity) world.getTileEntity(pos); - te.schematicToPrint = tag.getString("Owner") + "/" + tag.getString("File"); - te.anchor = NBTUtil.readBlockPos(tag.getCompound("Anchor")); - context.getPlayer().setItemStackToSlot(EquipmentSlotType.MAINHAND, ItemStack.EMPTY); - return ActionResultType.SUCCESS; - } - } - - context.getPlayer().getCooldownTracker().setCooldown(this, 10); - return ActionResultType.SUCCESS; + return super.onItemUse(context); } @Override @@ -153,8 +124,7 @@ public class ItemBlueprint extends Item { }); return new ActionResult(ActionResultType.SUCCESS, playerIn.getHeldItem(handIn)); } - - + return super.onItemRightClick(worldIn, playerIn, handIn); } diff --git a/src/main/java/com/simibubi/create/networking/PacketConfigureSchematicannon.java b/src/main/java/com/simibubi/create/networking/PacketConfigureSchematicannon.java new file mode 100644 index 000000000..1388ab1ab --- /dev/null +++ b/src/main/java/com/simibubi/create/networking/PacketConfigureSchematicannon.java @@ -0,0 +1,94 @@ +package com.simibubi.create.networking; + +import java.util.function.Supplier; + +import com.simibubi.create.block.SchematicannonTileEntity; +import com.simibubi.create.block.SchematicannonTileEntity.State; + +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.network.PacketBuffer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.fml.network.NetworkEvent.Context; + +public class PacketConfigureSchematicannon { + + public static enum Option { + DONT_REPLACE, REPLACE_SOLID, REPLACE_ANY, REPLACE_EMPTY, SKIP_MISSING, PLAY, PAUSE, STOP; + } + + private Option option; + private boolean set; + private BlockPos pos; + + public static PacketConfigureSchematicannon setOption(BlockPos pos, Option option, boolean set) { + PacketConfigureSchematicannon packet = new PacketConfigureSchematicannon(pos); + packet.option = option; + packet.set = set; + return packet; + } + + public PacketConfigureSchematicannon(BlockPos pos) { + this.pos = pos; + } + + public PacketConfigureSchematicannon(PacketBuffer buffer) { + pos = buffer.readBlockPos(); + option = Option.values()[buffer.readInt()]; + set = buffer.readBoolean(); + } + + public void toBytes(PacketBuffer buffer) { + buffer.writeBlockPos(pos); + buffer.writeInt(option.ordinal()); + buffer.writeBoolean(set); + } + + public void handle(Supplier context) { + context.get().enqueueWork(() -> { + ServerPlayerEntity player = context.get().getSender(); + World world = player.world; + + if (world == null || world.getTileEntity(pos) == null) + return; + TileEntity tileEntity = world.getTileEntity(pos); + if (tileEntity instanceof SchematicannonTileEntity) { + + SchematicannonTileEntity te = (SchematicannonTileEntity) tileEntity; + switch (option) { + case DONT_REPLACE: + case REPLACE_ANY: + case REPLACE_EMPTY: + case REPLACE_SOLID: + te.replaceMode = option.ordinal(); + break; + case SKIP_MISSING: + te.skipMissing = set; + break; + + case PLAY: + te.state = State.RUNNING; + te.statusMsg = "Running"; + break; + case PAUSE: + te.state = State.PAUSED; + te.statusMsg = "Paused"; + break; + case STOP: + te.state = State.STOPPED; + te.statusMsg = "Stopped"; + break; + default: + break; + } + + te.sendUpdate = true; + + } + + return; + }); + } + +} diff --git a/src/main/java/com/simibubi/create/networking/Packets.java b/src/main/java/com/simibubi/create/networking/Packets.java index 0bae86f3a..8bae2a1bb 100644 --- a/src/main/java/com/simibubi/create/networking/Packets.java +++ b/src/main/java/com/simibubi/create/networking/Packets.java @@ -19,6 +19,8 @@ public class Packets { PROTOCOL_VERSION::equals, PROTOCOL_VERSION::equals); channel.registerMessage(i++, PacketNbt.class, PacketNbt::toBytes, PacketNbt::new, PacketNbt::handle); + channel.registerMessage(i++, PacketConfigureSchematicannon.class, PacketConfigureSchematicannon::toBytes, + PacketConfigureSchematicannon::new, PacketConfigureSchematicannon::handle); channel.registerMessage(i++, PacketSchematicTableContainer.class, PacketSchematicTableContainer::toBytes, PacketSchematicTableContainer::new, PacketSchematicTableContainer::handle); channel.registerMessage(i++, PacketSchematicUpload.class, PacketSchematicUpload::toBytes, diff --git a/src/main/java/com/simibubi/create/schematic/BlueprintHandler.java b/src/main/java/com/simibubi/create/schematic/BlueprintHandler.java index fcc381289..c1c6508d8 100644 --- a/src/main/java/com/simibubi/create/schematic/BlueprintHandler.java +++ b/src/main/java/com/simibubi/create/schematic/BlueprintHandler.java @@ -226,12 +226,14 @@ public class BlueprintHandler { Minecraft.getInstance().player.sendStatusMessage(new StringTextComponent("Syncing..."), true); Packets.channel.sendToServer(new PacketNbt(item, slot)); - SchematicWorld w = new SchematicWorld(new HashMap<>(), new Cuboid(), anchor); - PlacementSettings settings = cachedSettings.copy(); - settings.setBoundingBox(null); - ItemBlueprint.getSchematic(item).addBlocksToWorld(w, anchor, settings); - - new SchematicHologram().startHologram(w); + if (deployed) { + SchematicWorld w = new SchematicWorld(new HashMap<>(), new Cuboid(), anchor); + PlacementSettings settings = cachedSettings.copy(); + settings.setBoundingBox(null); + ItemBlueprint.getSchematic(item).addBlocksToWorld(w, anchor, settings); + + new SchematicHologram().startHologram(w); + } } public void equip(Tools tool) { diff --git a/src/main/java/com/simibubi/create/schematic/Tools.java b/src/main/java/com/simibubi/create/schematic/Tools.java index a8c59530f..3defdc6e7 100644 --- a/src/main/java/com/simibubi/create/schematic/Tools.java +++ b/src/main/java/com/simibubi/create/schematic/Tools.java @@ -8,12 +8,12 @@ import com.simibubi.create.gui.GuiResources; public enum Tools { - Deploy(new SchematicDeployTool(), "Deploy", GuiResources.ICON_3x3), + Deploy(new SchematicDeployTool(), "Deploy", GuiResources.ICON_TOOL_DEPLOY), - Move(new SchematicMoveTool(), "Move XZ", GuiResources.ICON_3x3), - MoveY(new SchematicMoveVerticalTool(), "Move Y", GuiResources.ICON_3x3), - Rotate(new SchematicRotateTool(), "Rotate", GuiResources.ICON_3x3), - Flip(new SchematicFlipTool(), "Flip", GuiResources.ICON_3x3); + Move(new SchematicMoveTool(), "Move XZ", GuiResources.ICON_TOOL_MOVE_XZ), + MoveY(new SchematicMoveVerticalTool(), "Move Y", GuiResources.ICON_TOOL_MOVE_Y), + Rotate(new SchematicRotateTool(), "Rotate", GuiResources.ICON_TOOL_ROTATE), + Flip(new SchematicFlipTool(), "Flip", GuiResources.ICON_TOOL_MIRROR); private ISchematicTool tool; private String displayName; diff --git a/src/main/java/com/simibubi/create/utility/TileEntitySynced.java b/src/main/java/com/simibubi/create/utility/TileEntitySynced.java index 7386b0734..659df09d7 100644 --- a/src/main/java/com/simibubi/create/utility/TileEntitySynced.java +++ b/src/main/java/com/simibubi/create/utility/TileEntitySynced.java @@ -12,6 +12,11 @@ public abstract class TileEntitySynced extends TileEntity { super(tileEntityTypeIn); } + @Override + public CompoundNBT getTileData() { + return super.getTileData(); + } + @Override public CompoundNBT getUpdateTag() { return write(new CompoundNBT()); @@ -24,12 +29,22 @@ public abstract class TileEntitySynced extends TileEntity { @Override public SUpdateTileEntityPacket getUpdatePacket(){ - return new SUpdateTileEntityPacket(getPos(), 1, write(new CompoundNBT())); + return new SUpdateTileEntityPacket(getPos(), 1, writeToClient(new CompoundNBT())); } @Override public void onDataPacket(NetworkManager net, SUpdateTileEntityPacket pkt){ - read(pkt.getNbtCompound()); + readClientUpdate(pkt.getNbtCompound()); + } + + // Special handling for client update packets + public void readClientUpdate(CompoundNBT tag) { + read(tag); + } + + // Special handling for client update packets + public CompoundNBT writeToClient(CompoundNBT tag) { + return write(tag); } } diff --git a/src/main/resources/assets/create/models/item/symmetry_wand.json b/src/main/resources/assets/create/models/item/symmetry_wand.json index 24cb1cb33..29b7719ff 100644 --- a/src/main/resources/assets/create/models/item/symmetry_wand.json +++ b/src/main/resources/assets/create/models/item/symmetry_wand.json @@ -46,7 +46,7 @@ "east": { "texture": "#0", "uv": [ 2.0, 3.0, 5.0, 14.0 ] }, "south": { "texture": "#0", "uv": [ 10.0, 1.0, 13.0, 12.0 ] }, "west": { "texture": "#0", "uv": [ 7.0, 1.0, 10.0, 12.0 ] }, - "up": { "texture": "#-1", "uv": [ 0.0, 0.0, 3.0, 3.0 ] }, + "up": { "texture": "#0", "uv": [ 0.0, 0.0, 3.0, 3.0 ] }, "down": { "texture": "#0", "uv": [ 5.0, 6.0, 8.0, 9.0 ] } } }, diff --git a/src/main/resources/assets/create/textures/gui/icons.png b/src/main/resources/assets/create/textures/gui/icons.png index fd368353ec8f1e421344e5e6ea86de6351cb0138..9072b95f40be0120cc8007e4d55e8270f3b6ad09 100644 GIT binary patch literal 2154 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K58911MRQ8&P5Fo{p?&#~tz_78O`%fY(0|PTd zfKP}kQ2f!OM?i8EjE2An41q<`Z~lTZN=cAk@c)qw7=pjEs{)e%XMsm#F#`kNE)ZrE z-EVdYC@4|l8c`CQpH@_3q0(1$?ngkN^DXN@jf0SeI4@_VhzXc$o6MpE(!$GVg7; z-M8_cWXIvA)|oF^?uf1Wy0}0_)YSj1;)8Ae_jmV&E#h1eHGj)$`-o@z53c#Q>Hp3T zmGfrqV10C}Zs-5i+#bx9cQ@>5NK<&+x5r7UXL@CtSAzl2nk1lYyBmIZ$lF~zKmYUd zO2Izu2VY{&@4M?YXWto_^FHO=J*7#z-u&R|^)j?!#gpF%-wsw^Cz8;Kf8I;U8dxliB~mmNQQV9Z}Zquvc zkJ*f?Iet1E_-Lyc;pI@vedm`U4{!VWw#qzR#;@Ie$G7NT`KYGaTzvVn*MX%U%#H`N zf4!>mmjs(?kN=du`r{eOhxs zcf(}o?Lz6-#RJ$q{q6=`;g^`6Bp$GmovCCaLy#D^Lh2}m83a@A-~Ych`~$=5MWuT| O^@69XpUXO@geCxVBE<>- literal 2194 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K58911MRQ8&P5Fo{p?&#~tz_78O`%fY(0|PTd zfKP}kQ2f!OM?i8EjE2An41q<`Z~lTZN=cAk@c)qw7=pjEs{)e%XMsm#F#`kNZV+ZX z{^N=nP*9@8HKHUqKdq!Zu_%?HATcwqL@zJ3M8QPQP|xhIALk2Tf%3!C#WAEJ?(Ov3 zWlIcrSjzwZU%Yu*Xv`T^gU$X$<#Riujh;BNGM}6;U#Qby^I^MV<=Mjzt#p{|WHYiD z3x7^7ZRVHxeX2%1q2pG~Z_ycT0tcSvJ-PR@i@(-hzy6x>t0cxJ2Hx49ln-b#F0TWs zQGakD{MqgG2V^dri!n0)ZM?ByZ&DtkR|JD*H|vB=dqh5b@Y6V>@SyC(zo0pn55ygK z+p}@Mu|Vn}x70GGJoZz6b04gj^u~KL=Z?AQ_T^#57g?S}%=ekT-{5S0bM2S-=k|Ox zZ?uKu8+UB4-}`Sf_Y1bF^21-4W;M!{f3aTTSp7V&h9EI+h15#zgg*CwtmaI9 z`a6TIyC-@xTHdKUQuyEn)2&M}+!BilXPDpaWHC5z6%dwv{vw<7PS?meA`?zq1!*TA zh-Q3JRhOE_@<#cF?|lpT^{2HN{cBTo6sFmojC07_^A2dug7+oI-tAoPExw=!=rO4O zN*F(e@&EE`{#F_sU8j(tmqN|LLV^&%zF@ zi@!BB>{&XK-h4*M=7!kY=8v8{{c`Ef9mc@5e;4)|#jcfZm1NOL*(yBYb=9FyEHUO> z#kvU(H|@Ql;UmtlQ`wDU0@Ni(Ar2a)rXYeKu&(YOBlBL*0NbfkJwf${r>mdKI;Vst E04SH~Hvj+t diff --git a/src/main/resources/assets/create/textures/gui/schematicannon.png b/src/main/resources/assets/create/textures/gui/schematicannon.png new file mode 100644 index 0000000000000000000000000000000000000000..3ec65b3d02b2f247a0ca4dcadcbe9bc52833734e GIT binary patch literal 4327 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 Xugqy^U9->;00000NkvXXu0mjfQQdK`