mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-12-24 14:06:42 +01:00
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;
|
||||
|
||||
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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -593,6 +593,10 @@ public class SchematicannonTileEntity extends TileEntitySynced implements ITicka
|
|||
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;
|
||||
if (replaceMode == 2 && !placingAir)
|
||||
|
@ -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++;
|
||||
}
|
||||
|
|
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.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"
|
||||
}
|
||||
|
|
|
@ -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