From d7bcc1ea28c8a7b412b22ab526adc1d899aa15db Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Wed, 17 Jul 2019 17:13:09 +0200 Subject: [PATCH] Schematic and Quill - Added Schematic and Quill for recording schematics in game - Schematicannon no longer attempts to place liquids --- .../java/com/simibubi/create/AllItems.java | 2 + src/main/java/com/simibubi/create/Create.java | 2 + .../create/block/SchematicTableContainer.java | 10 +- .../block/SchematicannonTileEntity.java | 8 +- .../simibubi/create/gui/GuiTextPrompt.java | 101 +++++++++ .../create/item/ItemBlueprintAndQuill.java | 11 + .../schematic/BlueprintAndQuillHandler.java | 196 ++++++++++++++++++ .../resources/assets/create/lang/en_us.json | 5 +- .../models/item/blueprint_and_quill.json | 6 + .../textures/item/blueprint_and_quill.png | Bin 0 -> 368 bytes 10 files changed, 333 insertions(+), 8 deletions(-) create mode 100644 src/main/java/com/simibubi/create/gui/GuiTextPrompt.java create mode 100644 src/main/java/com/simibubi/create/item/ItemBlueprintAndQuill.java create mode 100644 src/main/java/com/simibubi/create/schematic/BlueprintAndQuillHandler.java create mode 100644 src/main/resources/assets/create/models/item/blueprint_and_quill.json create mode 100644 src/main/resources/assets/create/textures/item/blueprint_and_quill.png diff --git a/src/main/java/com/simibubi/create/AllItems.java b/src/main/java/com/simibubi/create/AllItems.java index 1c1fef701..db186bf53 100644 --- a/src/main/java/com/simibubi/create/AllItems.java +++ b/src/main/java/com/simibubi/create/AllItems.java @@ -1,6 +1,7 @@ package com.simibubi.create; import com.simibubi.create.item.ItemBlueprint; +import com.simibubi.create.item.ItemBlueprintAndQuill; import com.simibubi.create.item.ItemWandSymmetry; import net.minecraft.item.Item; @@ -14,6 +15,7 @@ public enum AllItems { SYMMETRY_WAND(new ItemWandSymmetry(standardProperties())), EMPTY_BLUEPRINT(new Item(standardProperties().maxStackSize(1))), + BLUEPRINT_AND_QUILL(new ItemBlueprintAndQuill(standardProperties().maxStackSize(1))), BLUEPRINT(new ItemBlueprint(standardProperties())); public Item item; diff --git a/src/main/java/com/simibubi/create/Create.java b/src/main/java/com/simibubi/create/Create.java index 5e985d8d5..df42b7308 100644 --- a/src/main/java/com/simibubi/create/Create.java +++ b/src/main/java/com/simibubi/create/Create.java @@ -5,6 +5,7 @@ import org.apache.logging.log4j.Logger; import com.simibubi.create.gui.Keyboard; import com.simibubi.create.networking.Packets; +import com.simibubi.create.schematic.BlueprintAndQuillHandler; import com.simibubi.create.schematic.BlueprintHandler; import com.simibubi.create.schematic.SchematicHologram; @@ -63,6 +64,7 @@ public class Create { new BlueprintHandler(); ScrollFixer.init(); ScrollFixer.addMouseWheelListener(BlueprintHandler.instance::onScroll); + ScrollFixer.addMouseWheelListener(BlueprintAndQuillHandler::onScroll); TOOL_MENU = new KeyBinding("Tool Menu (Hold)", Keyboard.LALT, NAME); ClientRegistry.registerKeyBinding(TOOL_MENU); diff --git a/src/main/java/com/simibubi/create/block/SchematicTableContainer.java b/src/main/java/com/simibubi/create/block/SchematicTableContainer.java index 23b004a84..c95cc48d3 100644 --- a/src/main/java/com/simibubi/create/block/SchematicTableContainer.java +++ b/src/main/java/com/simibubi/create/block/SchematicTableContainer.java @@ -40,7 +40,7 @@ public class SchematicTableContainer extends Container { inputSlot = new SlotItemHandler(te.inventory, 0, -9, 40) { @Override public boolean isItemValid(ItemStack stack) { - return AllItems.EMPTY_BLUEPRINT.typeOf(stack); + return AllItems.EMPTY_BLUEPRINT.typeOf(stack) || AllItems.BLUEPRINT_AND_QUILL.typeOf(stack); } }; @@ -53,7 +53,7 @@ public class SchematicTableContainer extends Container { addSlot(inputSlot); addSlot(outputSlot); - + // player Slots for (int row = 0; row < 3; ++row) { for (int col = 0; col < 9; ++col) { @@ -64,7 +64,7 @@ public class SchematicTableContainer extends Container { for (int hotbarSlot = 0; hotbarSlot < 9; ++hotbarSlot) { this.addSlot(new Slot(player.inventory, hotbarSlot, 12 + hotbarSlot * 18, 160)); } - + detectAndSendChanges(); } @@ -86,9 +86,9 @@ public class SchematicTableContainer extends Container { ItemStack stack = clickedSlot.getStack(); if (index < 2) mergeItemStack(stack, 2, inventorySlots.size(), false); - else + else mergeItemStack(stack, 0, 1, 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 25c753371..876a4ff31 100644 --- a/src/main/java/com/simibubi/create/block/SchematicannonTileEntity.java +++ b/src/main/java/com/simibubi/create/block/SchematicannonTileEntity.java @@ -592,6 +592,10 @@ public class SchematicannonTileEntity extends TileEntitySynced implements ITicka return false; if (!replaceTileEntities && toReplace.hasTileEntity()) return false; + + // Block doesnt have a mapping (Water, lava, etc) + if (getItemForBlock(state).getItem() == Items.AIR && state.getBlock() != Blocks.AIR) + return false; if (replaceMode == 3) return true; @@ -611,7 +615,7 @@ public class SchematicannonTileEntity extends TileEntitySynced implements ITicka for (LaunchedBlock b : flyingBlocks) { b.update(); if (b.ticksRemaining <= 0 && !world.isRemote) { - world.setBlockState(b.target, b.state); + world.setBlockState(b.target, b.state, 18); toRemove.add(b); } } @@ -709,6 +713,8 @@ public class SchematicannonTileEntity extends TileEntitySynced implements ITicka if (!shouldPlace(pos.add(schematicAnchor), required)) continue; ItemStack requiredItem = getItemForBlock(required); + if (requiredItem.isEmpty()) + continue; checklist.require(requiredItem.getItem()); blocksToPlace++; } diff --git a/src/main/java/com/simibubi/create/gui/GuiTextPrompt.java b/src/main/java/com/simibubi/create/gui/GuiTextPrompt.java new file mode 100644 index 000000000..e2548901b --- /dev/null +++ b/src/main/java/com/simibubi/create/gui/GuiTextPrompt.java @@ -0,0 +1,101 @@ +package com.simibubi.create.gui; + +import java.util.function.Consumer; + +import org.lwjgl.glfw.GLFW; + +import net.minecraft.client.gui.widget.TextFieldWidget; +import net.minecraft.client.gui.widget.button.Button; + +public class GuiTextPrompt extends AbstractSimiScreen { + + private Consumer callback; + private Consumer abortCallback; + + private TextFieldWidget nameField; + private Button confirm; + private Button abort; + + private String buttonTextConfirm; + private String buttonTextAbort; + private String title; + + private boolean confirmed; + + public GuiTextPrompt(Consumer callBack, Consumer abortCallback) { + super(); + this.callback = callBack; + this.abortCallback = abortCallback; + + buttonTextConfirm = "Confirm"; + buttonTextAbort = "Abort"; + confirmed = false; + } + + @Override + public void init() { + super.init(); + setWindowSize(GuiResources.TEXT_INPUT.width, GuiResources.TEXT_INPUT.height + 30); + + this.nameField = new TextFieldWidget(font, topLeftX + 33, topLeftY + 26, 128, 8, ""); + this.nameField.setTextColor(-1); + this.nameField.setDisabledTextColour(-1); + this.nameField.setEnableBackgroundDrawing(false); + this.nameField.setMaxStringLength(35); + this.nameField.changeFocus(true); + + confirm = new Button(topLeftX - 5, topLeftY + 50, 100, 20, buttonTextConfirm, button -> { + callback.accept(nameField.getText()); + confirmed = true; + minecraft.displayGuiScreen(null); + }); + + abort = new Button(topLeftX + 100, topLeftY + 50, 100, 20, buttonTextAbort, button -> { + minecraft.displayGuiScreen(null); + }); + + widgets.add(confirm); + widgets.add(abort); + widgets.add(nameField); + } + + @Override + public void renderWindow(int mouseX, int mouseY, float partialTicks) { + GuiResources.TEXT_INPUT.draw(this, topLeftX, topLeftY); + font.drawString(title, topLeftX + (sWidth / 2) - (font.getStringWidth(title) / 2), topLeftY + 11, + GuiResources.FONT_COLOR); + } + + @Override + public void removed() { + if (!confirmed) + abortCallback.accept(nameField.getText()); + super.removed(); + } + + public void setButtonTextConfirm(String buttonTextConfirm) { + this.buttonTextConfirm = buttonTextConfirm; + } + + public void setButtonTextAbort(String buttonTextAbort) { + this.buttonTextAbort = buttonTextAbort; + } + + public void setTitle(String title) { + this.title = title; + } + + @Override + public boolean keyPressed(int keyCode, int p_keyPressed_2_, int p_keyPressed_3_) { + if (keyCode == GLFW.GLFW_KEY_ENTER) { + confirm.onPress(); + return true; + } + if (keyCode == 256 && this.shouldCloseOnEsc()) { + this.onClose(); + return true; + } + return nameField.keyPressed(keyCode, p_keyPressed_2_, p_keyPressed_3_); + } + +} diff --git a/src/main/java/com/simibubi/create/item/ItemBlueprintAndQuill.java b/src/main/java/com/simibubi/create/item/ItemBlueprintAndQuill.java new file mode 100644 index 000000000..be1217d56 --- /dev/null +++ b/src/main/java/com/simibubi/create/item/ItemBlueprintAndQuill.java @@ -0,0 +1,11 @@ +package com.simibubi.create.item; + +import net.minecraft.item.Item; + +public class ItemBlueprintAndQuill extends Item { + + public ItemBlueprintAndQuill(Properties properties) { + super(properties); + } + +} diff --git a/src/main/java/com/simibubi/create/schematic/BlueprintAndQuillHandler.java b/src/main/java/com/simibubi/create/schematic/BlueprintAndQuillHandler.java new file mode 100644 index 000000000..6dfb49f5a --- /dev/null +++ b/src/main/java/com/simibubi/create/schematic/BlueprintAndQuillHandler.java @@ -0,0 +1,196 @@ +package com.simibubi.create.schematic; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; + +import org.apache.commons.io.IOUtils; +import org.lwjgl.glfw.GLFW; + +import com.mojang.blaze3d.platform.GlStateManager; +import com.simibubi.create.AllItems; +import com.simibubi.create.gui.GuiOpener; +import com.simibubi.create.gui.GuiTextPrompt; +import com.simibubi.create.gui.Keyboard; +import com.simibubi.create.utility.FilesHelper; +import com.simibubi.create.utility.RaycastHelper; +import com.simibubi.create.utility.TessellatorHelper; + +import net.minecraft.block.Blocks; +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.player.ClientPlayerEntity; +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.item.BlockItemUseContext; +import net.minecraft.item.ItemUseContext; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.CompressedStreamTools; +import net.minecraft.util.Hand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.MutableBoundingBox; +import net.minecraft.util.math.RayTraceResult.Type; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.world.gen.feature.template.Template; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.InputEvent.MouseInputEvent; +import net.minecraftforge.client.event.RenderWorldLastEvent; +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.common.gameevent.TickEvent.ClientTickEvent; + +@EventBusSubscriber(value = Dist.CLIENT, bus = Bus.FORGE) +public class BlueprintAndQuillHandler { + + static BlockPos firstPos; + static BlockPos selectedPos; + static int range = 10; + + private static boolean active() { + return present() && AllItems.BLUEPRINT_AND_QUILL.typeOf(Minecraft.getInstance().player.getHeldItemMainhand()); + } + + private static boolean present() { + return Minecraft.getInstance() != null && Minecraft.getInstance().world != null + && Minecraft.getInstance().currentScreen == null && !Minecraft.getInstance().player.isSneaking(); + } + + public static boolean onScroll(double delta) { + if (!active()) + return false; + if (!Keyboard.isKeyDown(GLFW.GLFW_KEY_LEFT_CONTROL)) + return false; + range = (int) MathHelper.clamp(range + delta, 1, 100); + return true; + } + + @SubscribeEvent + public static void onClick(MouseInputEvent event) { + if (event.getAction() != Keyboard.PRESS) + return; + if (event.getButton() != 1) + return; + if (!active() && !Minecraft.getInstance().player.isSneaking()) + return; + if (selectedPos == null) + return; + if (Minecraft.getInstance().player.isSneaking()) { + firstPos = null; + return; + } + + if (firstPos != null) { + GuiTextPrompt guiScreenIn = new GuiTextPrompt(BlueprintAndQuillHandler::saveSchematic, s -> { + firstPos = null; + }); + guiScreenIn.setTitle("Enter a name for the Schematic:"); + guiScreenIn.setButtonTextConfirm("Save"); + guiScreenIn.setButtonTextAbort("Cancel"); + GuiOpener.open(guiScreenIn); + return; + } + + firstPos = selectedPos; + } + + public static void saveSchematic(String string) { + Template t = new Template(); + MutableBoundingBox bb = new MutableBoundingBox(firstPos, selectedPos); + t.takeBlocksFromWorld(Minecraft.getInstance().world, new BlockPos(bb.minX, bb.minY, bb.minZ), + new BlockPos(bb.getXSize(), bb.getYSize(), bb.getZSize()), false, Blocks.AIR); + + if (string.isEmpty()) + string = "My Schematic"; + + String folderPath = "schematics"; + FilesHelper.createFolderIfMissing(folderPath); + String filename = FilesHelper.findFirstValidFilename(string, folderPath, "nbt"); + String filepath = folderPath + "/" + filename; + + OutputStream outputStream = null; + try { + outputStream = Files.newOutputStream(Paths.get(filepath), StandardOpenOption.CREATE); + CompoundNBT nbttagcompound = t.writeToNBT(new CompoundNBT()); + CompressedStreamTools.writeCompressed(nbttagcompound, outputStream); + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (outputStream != null) + IOUtils.closeQuietly(outputStream); + } + firstPos = null; + Minecraft.getInstance().player.sendStatusMessage(new StringTextComponent("Saved as " + filepath), true); + } + + @SubscribeEvent + public static void onRenderWorld(RenderWorldLastEvent event) { + if (!active()) + return; + + TessellatorHelper.prepareForDrawing(); + GlStateManager.lineWidth(3); + GlStateManager.color4f(1, 1, 1, 1); + GlStateManager.disableTexture(); + + if (firstPos != null) { + MutableBoundingBox bb = new MutableBoundingBox(firstPos, firstPos.add(1, 1, 1)); + BlockPos min = new BlockPos(bb.minX, bb.minY, bb.minZ); + BlockPos max = new BlockPos(bb.maxX, bb.maxY, bb.maxZ); + drawBox(min, max); + } + + if (selectedPos != null) { + MutableBoundingBox bb = new MutableBoundingBox(selectedPos, selectedPos.add(1, 1, 1)); + BlockPos min = new BlockPos(bb.minX, bb.minY, bb.minZ); + BlockPos max = new BlockPos(bb.maxX, bb.maxY, bb.maxZ); + drawBox(min, max); + + if (firstPos != null) { + bb = new MutableBoundingBox(firstPos, selectedPos); + min = new BlockPos(bb.minX, bb.minY, bb.minZ); + max = new BlockPos(bb.maxX + 1, bb.maxY + 1, bb.maxZ + 1); + drawBox(min, max); + } + } + + GlStateManager.lineWidth(1); + GlStateManager.enableTexture(); + TessellatorHelper.cleanUpAfterDrawing(); + } + + protected static void drawBox(BlockPos min, BlockPos max) { + WorldRenderer.drawBoundingBox(min.getX() - 1 / 16d, min.getY() - 1 / 16d, min.getZ() - 1 / 16d, + max.getX() + 1 / 16d, max.getY() + 1 / 16d, max.getZ() + 1 / 16d, .3f, .4f, 1, 1); + } + + @SubscribeEvent + public static void onClientTick(ClientTickEvent event) { + if (!active()) + return; + ClientPlayerEntity player = Minecraft.getInstance().player; + + selectedPos = null; + if (Keyboard.isKeyDown(GLFW.GLFW_KEY_LEFT_CONTROL)) { + selectedPos = new BlockPos(player.getEyePosition(Minecraft.getInstance().getRenderPartialTicks()) + .add(player.getLookVec().scale(range))); + } else { + BlockRayTraceResult trace = RaycastHelper.rayTraceRange(player.world, player, 75); + if (trace != null && trace.getType() == Type.BLOCK) { + + BlockPos hit = new BlockPos(trace.getHitVec()); + boolean replaceable = player.world.getBlockState(hit) + .isReplaceable(new BlockItemUseContext(new ItemUseContext(player, Hand.MAIN_HAND, trace))); + if (trace.getFace().getAxis().isVertical() && !replaceable) + hit = hit.offset(trace.getFace()); + + selectedPos = hit; + } else { + selectedPos = null; + } + } + + } +} \ No newline at end of file diff --git a/src/main/resources/assets/create/lang/en_us.json b/src/main/resources/assets/create/lang/en_us.json index eeb8ac86b..8df216de6 100644 --- a/src/main/resources/assets/create/lang/en_us.json +++ b/src/main/resources/assets/create/lang/en_us.json @@ -1,9 +1,10 @@ { "item.create.symmetry_wand": "Staff of Symmetry", "item.create.empty_blueprint": "Empty Schematic", + "item.create.blueprint_and_quill": "Schematic and Quill", "item.create.blueprint": "Schematic", - "block.create.schematicannon": "SchematiCannon 9000", + "block.create.schematicannon": "Schematicannon", "block.create.schematic_table": "Schematic Table", - "block.create.creative_crate": "SchematiCannon Creatifier", + "block.create.creative_crate": "Schematicannon Creatifier", "itemGroup.create": "Create" } diff --git a/src/main/resources/assets/create/models/item/blueprint_and_quill.json b/src/main/resources/assets/create/models/item/blueprint_and_quill.json new file mode 100644 index 000000000..1266c975f --- /dev/null +++ b/src/main/resources/assets/create/models/item/blueprint_and_quill.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "create:item/blueprint_and_quill" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/create/textures/item/blueprint_and_quill.png b/src/main/resources/assets/create/textures/item/blueprint_and_quill.png new file mode 100644 index 0000000000000000000000000000000000000000..dd13e81665dc9b5c48a9b8ff019af80018acebc2 GIT binary patch literal 368 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6;>1s;*b z3=DjSK$uZf!>a)(C{f}XQ4*Y=R#Ki=l*&+$n3-3imzP?iV4`QJXZF{R^94}NJ5LwK z5DWjc6KwgK90XcDdu*pp|G;vuVR1yjC1Hyu*o_DoLtO%1q@wb}mO