Schematic and Quill
- Added Schematic and Quill for recording schematics in game - Schematicannon no longer attempts to place liquids
This commit is contained in:
parent
a34034379f
commit
d7bcc1ea28
10 changed files with 333 additions and 8 deletions
|
@ -1,6 +1,7 @@
|
||||||
package com.simibubi.create;
|
package com.simibubi.create;
|
||||||
|
|
||||||
import com.simibubi.create.item.ItemBlueprint;
|
import com.simibubi.create.item.ItemBlueprint;
|
||||||
|
import com.simibubi.create.item.ItemBlueprintAndQuill;
|
||||||
import com.simibubi.create.item.ItemWandSymmetry;
|
import com.simibubi.create.item.ItemWandSymmetry;
|
||||||
|
|
||||||
import net.minecraft.item.Item;
|
import net.minecraft.item.Item;
|
||||||
|
@ -14,6 +15,7 @@ public enum AllItems {
|
||||||
|
|
||||||
SYMMETRY_WAND(new ItemWandSymmetry(standardProperties())),
|
SYMMETRY_WAND(new ItemWandSymmetry(standardProperties())),
|
||||||
EMPTY_BLUEPRINT(new Item(standardProperties().maxStackSize(1))),
|
EMPTY_BLUEPRINT(new Item(standardProperties().maxStackSize(1))),
|
||||||
|
BLUEPRINT_AND_QUILL(new ItemBlueprintAndQuill(standardProperties().maxStackSize(1))),
|
||||||
BLUEPRINT(new ItemBlueprint(standardProperties()));
|
BLUEPRINT(new ItemBlueprint(standardProperties()));
|
||||||
|
|
||||||
public Item item;
|
public Item item;
|
||||||
|
|
|
@ -5,6 +5,7 @@ import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
import com.simibubi.create.gui.Keyboard;
|
import com.simibubi.create.gui.Keyboard;
|
||||||
import com.simibubi.create.networking.Packets;
|
import com.simibubi.create.networking.Packets;
|
||||||
|
import com.simibubi.create.schematic.BlueprintAndQuillHandler;
|
||||||
import com.simibubi.create.schematic.BlueprintHandler;
|
import com.simibubi.create.schematic.BlueprintHandler;
|
||||||
import com.simibubi.create.schematic.SchematicHologram;
|
import com.simibubi.create.schematic.SchematicHologram;
|
||||||
|
|
||||||
|
@ -63,6 +64,7 @@ public class Create {
|
||||||
new BlueprintHandler();
|
new BlueprintHandler();
|
||||||
ScrollFixer.init();
|
ScrollFixer.init();
|
||||||
ScrollFixer.addMouseWheelListener(BlueprintHandler.instance::onScroll);
|
ScrollFixer.addMouseWheelListener(BlueprintHandler.instance::onScroll);
|
||||||
|
ScrollFixer.addMouseWheelListener(BlueprintAndQuillHandler::onScroll);
|
||||||
|
|
||||||
TOOL_MENU = new KeyBinding("Tool Menu (Hold)", Keyboard.LALT, NAME);
|
TOOL_MENU = new KeyBinding("Tool Menu (Hold)", Keyboard.LALT, NAME);
|
||||||
ClientRegistry.registerKeyBinding(TOOL_MENU);
|
ClientRegistry.registerKeyBinding(TOOL_MENU);
|
||||||
|
|
|
@ -40,7 +40,7 @@ public class SchematicTableContainer extends Container {
|
||||||
inputSlot = new SlotItemHandler(te.inventory, 0, -9, 40) {
|
inputSlot = new SlotItemHandler(te.inventory, 0, -9, 40) {
|
||||||
@Override
|
@Override
|
||||||
public boolean isItemValid(ItemStack stack) {
|
public boolean isItemValid(ItemStack stack) {
|
||||||
return AllItems.EMPTY_BLUEPRINT.typeOf(stack);
|
return AllItems.EMPTY_BLUEPRINT.typeOf(stack) || AllItems.BLUEPRINT_AND_QUILL.typeOf(stack);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -593,6 +593,10 @@ public class SchematicannonTileEntity extends TileEntitySynced implements ITicka
|
||||||
if (!replaceTileEntities && toReplace.hasTileEntity())
|
if (!replaceTileEntities && toReplace.hasTileEntity())
|
||||||
return false;
|
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)
|
if (replaceMode == 3)
|
||||||
return true;
|
return true;
|
||||||
if (replaceMode == 2 && !placingAir)
|
if (replaceMode == 2 && !placingAir)
|
||||||
|
@ -611,7 +615,7 @@ public class SchematicannonTileEntity extends TileEntitySynced implements ITicka
|
||||||
for (LaunchedBlock b : flyingBlocks) {
|
for (LaunchedBlock b : flyingBlocks) {
|
||||||
b.update();
|
b.update();
|
||||||
if (b.ticksRemaining <= 0 && !world.isRemote) {
|
if (b.ticksRemaining <= 0 && !world.isRemote) {
|
||||||
world.setBlockState(b.target, b.state);
|
world.setBlockState(b.target, b.state, 18);
|
||||||
toRemove.add(b);
|
toRemove.add(b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -709,6 +713,8 @@ public class SchematicannonTileEntity extends TileEntitySynced implements ITicka
|
||||||
if (!shouldPlace(pos.add(schematicAnchor), required))
|
if (!shouldPlace(pos.add(schematicAnchor), required))
|
||||||
continue;
|
continue;
|
||||||
ItemStack requiredItem = getItemForBlock(required);
|
ItemStack requiredItem = getItemForBlock(required);
|
||||||
|
if (requiredItem.isEmpty())
|
||||||
|
continue;
|
||||||
checklist.require(requiredItem.getItem());
|
checklist.require(requiredItem.getItem());
|
||||||
blocksToPlace++;
|
blocksToPlace++;
|
||||||
}
|
}
|
||||||
|
|
101
src/main/java/com/simibubi/create/gui/GuiTextPrompt.java
Normal file
101
src/main/java/com/simibubi/create/gui/GuiTextPrompt.java
Normal file
|
@ -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<String> callback;
|
||||||
|
private Consumer<String> 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<String> callBack, Consumer<String> 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_);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,10 @@
|
||||||
{
|
{
|
||||||
"item.create.symmetry_wand": "Staff of Symmetry",
|
"item.create.symmetry_wand": "Staff of Symmetry",
|
||||||
"item.create.empty_blueprint": "Empty Schematic",
|
"item.create.empty_blueprint": "Empty Schematic",
|
||||||
|
"item.create.blueprint_and_quill": "Schematic and Quill",
|
||||||
"item.create.blueprint": "Schematic",
|
"item.create.blueprint": "Schematic",
|
||||||
"block.create.schematicannon": "SchematiCannon 9000",
|
"block.create.schematicannon": "Schematicannon",
|
||||||
"block.create.schematic_table": "Schematic Table",
|
"block.create.schematic_table": "Schematic Table",
|
||||||
"block.create.creative_crate": "SchematiCannon Creatifier",
|
"block.create.creative_crate": "Schematicannon Creatifier",
|
||||||
"itemGroup.create": "Create"
|
"itemGroup.create": "Create"
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"parent": "item/generated",
|
||||||
|
"textures": {
|
||||||
|
"layer0": "create:item/blueprint_and_quill"
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 368 B |
Loading…
Reference in a new issue