From 56139aab20399e1f62fcb32072ceab1e9f0fbaba Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Mon, 15 Jul 2019 12:10:57 +0200 Subject: [PATCH] Blueprint Placement Tools - New tools for modifying the blueprints location and orientation - Fixed client classes loading on physical servers --- .../java/com/simibubi/create/AllItems.java | 3 + .../com/simibubi/create/AllTileEntities.java | 4 + src/main/java/com/simibubi/create/Create.java | 25 +- .../create/ServerSchematicLoader.java | 11 +- .../create/block/SchematicTableBlock.java | 27 +- .../create/block/SchematicTableContainer.java | 8 +- .../block/SchematicannonTileEntity.java | 15 +- .../create/gui/AbstractSimiScreen.java | 3 + .../create/gui/BlueprintHotbarOverlay.java | 20 + .../com/simibubi/create/gui/GuiHandler.java | 5 - .../com/simibubi/create/gui/GuiOpener.java | 5 +- .../com/simibubi/create/gui/GuiResources.java | 2 + .../create/{utility => gui}/Keyboard.java | 7 +- .../create/gui/SchematicTableScreen.java | 20 +- .../create/gui/ToolSelectionScreen.java | 103 +++++ .../create/gui/widgets/ScrollArea.java | 2 +- .../simibubi/create/item/ItemBlueprint.java | 92 +++-- .../create/item/ItemWandSymmetry.java | 51 ++- .../simibubi/create/networking/PacketNbt.java | 24 +- .../PacketSchematicTableContainer.java | 4 - .../networking/PacketSchematicUpload.java | 2 +- .../simibubi/create/networking/Packets.java | 7 +- .../create/schematic/BlueprintHandler.java | 355 ++++++++++++++++++ .../com/simibubi/create/schematic/Cuboid.java | 4 + .../create/schematic/ISchematicTool.java | 15 + .../create/schematic/SchematicDeployTool.java | 84 +++++ .../create/schematic/SchematicFlipTool.java | 39 ++ .../create/schematic/SchematicHologram.java | 9 + .../create/schematic/SchematicMoveTool.java | 23 ++ .../schematic/SchematicMoveVerticalTool.java | 16 + .../schematic/SchematicPlacementToolBase.java | 35 ++ .../create/schematic/SchematicRotateTool.java | 13 + .../create/schematic/SchematicToolBase.java | 122 ++++++ .../create/schematic/SchematicWorld.java | 2 +- .../com/simibubi/create/schematic/Tools.java | 46 +++ .../create/utility/RaycastHelper.java | 195 ++++++++++ .../create/utility/TessellatorTextures.java | 29 ++ .../resources/assets/create/lang/en_us.json | 7 +- .../assets/create/textures/gui/widgets.png | Bin 4289 -> 4492 bytes 39 files changed, 1309 insertions(+), 125 deletions(-) create mode 100644 src/main/java/com/simibubi/create/gui/BlueprintHotbarOverlay.java delete mode 100644 src/main/java/com/simibubi/create/gui/GuiHandler.java rename src/main/java/com/simibubi/create/{utility => gui}/Keyboard.java (78%) create mode 100644 src/main/java/com/simibubi/create/gui/ToolSelectionScreen.java create mode 100644 src/main/java/com/simibubi/create/schematic/BlueprintHandler.java create mode 100644 src/main/java/com/simibubi/create/schematic/ISchematicTool.java create mode 100644 src/main/java/com/simibubi/create/schematic/SchematicDeployTool.java create mode 100644 src/main/java/com/simibubi/create/schematic/SchematicFlipTool.java create mode 100644 src/main/java/com/simibubi/create/schematic/SchematicMoveTool.java create mode 100644 src/main/java/com/simibubi/create/schematic/SchematicMoveVerticalTool.java create mode 100644 src/main/java/com/simibubi/create/schematic/SchematicPlacementToolBase.java create mode 100644 src/main/java/com/simibubi/create/schematic/SchematicRotateTool.java create mode 100644 src/main/java/com/simibubi/create/schematic/SchematicToolBase.java create mode 100644 src/main/java/com/simibubi/create/schematic/Tools.java create mode 100644 src/main/java/com/simibubi/create/utility/RaycastHelper.java create mode 100644 src/main/java/com/simibubi/create/utility/TessellatorTextures.java diff --git a/src/main/java/com/simibubi/create/AllItems.java b/src/main/java/com/simibubi/create/AllItems.java index f8412edc1..1c1fef701 100644 --- a/src/main/java/com/simibubi/create/AllItems.java +++ b/src/main/java/com/simibubi/create/AllItems.java @@ -6,6 +6,8 @@ import com.simibubi.create.item.ItemWandSymmetry; import net.minecraft.item.Item; import net.minecraft.item.Item.Properties; import net.minecraft.item.ItemStack; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.registries.IForgeRegistry; public enum AllItems { @@ -39,6 +41,7 @@ public enum AllItems { return stack.getItem() == item; } + @OnlyIn(Dist.CLIENT) public static void initColorHandlers() { } diff --git a/src/main/java/com/simibubi/create/AllTileEntities.java b/src/main/java/com/simibubi/create/AllTileEntities.java index 45fb8105a..177b04e0b 100644 --- a/src/main/java/com/simibubi/create/AllTileEntities.java +++ b/src/main/java/com/simibubi/create/AllTileEntities.java @@ -10,6 +10,8 @@ import net.minecraft.client.renderer.tileentity.TileEntityRenderer; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityType; 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.client.registry.ClientRegistry; @@ -42,10 +44,12 @@ public enum AllTileEntities { } } + @OnlyIn(Dist.CLIENT) public static void registerRenderers() { bind(SchematicannonTileEntity.class, new SchematicannonRenderer()); } + @OnlyIn(Dist.CLIENT) private static void bind(Class clazz, TileEntityRenderer renderer) { ClientRegistry.bindTileEntitySpecialRenderer(clazz, renderer); } diff --git a/src/main/java/com/simibubi/create/Create.java b/src/main/java/com/simibubi/create/Create.java index 6d43e6173..b6b08b98c 100644 --- a/src/main/java/com/simibubi/create/Create.java +++ b/src/main/java/com/simibubi/create/Create.java @@ -3,10 +3,13 @@ package com.simibubi.create; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import com.simibubi.create.gui.Keyboard; import com.simibubi.create.networking.Packets; +import com.simibubi.create.schematic.BlueprintHandler; import com.simibubi.create.schematic.SchematicHologram; import net.minecraft.block.Block; +import net.minecraft.client.settings.KeyBinding; import net.minecraft.item.Item; import net.minecraft.item.ItemGroup; import net.minecraftforge.api.distmarker.Dist; @@ -15,6 +18,7 @@ import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.DistExecutor; +import net.minecraftforge.fml.client.registry.ClientRegistry; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod.EventBusSubscriber; import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus; @@ -37,6 +41,8 @@ public class Create { @OnlyIn(Dist.CLIENT) public static ClientSchematicLoader cSchematicLoader; + @OnlyIn(Dist.CLIENT) + public static KeyBinding TOOL_MENU; public static ServerSchematicLoader sSchematicLoader; @@ -47,17 +53,24 @@ public class Create { } private void clientInit(FMLClientSetupEvent event) { - AllItems.initColorHandlers(); - AllTileEntities.registerRenderers(); - cSchematicLoader = new ClientSchematicLoader(); - sSchematicLoader = new ServerSchematicLoader(); - new SchematicHologram(); -// ScrollFixer.init(); + DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> { + AllItems.initColorHandlers(); + AllTileEntities.registerRenderers(); + cSchematicLoader = new ClientSchematicLoader(); + new SchematicHologram(); + new BlueprintHandler(); + ScrollFixer.init(); + ScrollFixer.addMouseWheelListener(BlueprintHandler.instance::onScroll); + + TOOL_MENU = new KeyBinding("Tool Menu (Hold)", Keyboard.LALT, NAME); + ClientRegistry.registerKeyBinding(TOOL_MENU); + }); } private void init(final FMLCommonSetupEvent event) { Packets.registerPackets(); DistExecutor.runWhenOn(Dist.CLIENT, () -> AllContainers::registerScreenFactories); + sSchematicLoader = new ServerSchematicLoader(); } @OnlyIn(Dist.CLIENT) diff --git a/src/main/java/com/simibubi/create/ServerSchematicLoader.java b/src/main/java/com/simibubi/create/ServerSchematicLoader.java index 28930408c..e8c614573 100644 --- a/src/main/java/com/simibubi/create/ServerSchematicLoader.java +++ b/src/main/java/com/simibubi/create/ServerSchematicLoader.java @@ -10,14 +10,13 @@ import java.util.Map; import com.simibubi.create.block.SchematicTableContainer; import com.simibubi.create.block.SchematicTableTileEntity; +import com.simibubi.create.item.ItemBlueprint; import com.simibubi.create.networking.PacketSchematicUpload.DimensionPos; import com.simibubi.create.utility.FilesHelper; import net.minecraft.block.BlockState; import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.item.ItemStack; -import net.minecraft.util.text.StringTextComponent; -import net.minecraft.util.text.TextFormatting; public class ServerSchematicLoader { @@ -111,13 +110,7 @@ public class ServerSchematicLoader { return; tileEntity.inputStack = ItemStack.EMPTY; - ItemStack blueprint = new ItemStack(AllItems.BLUEPRINT.get()); - blueprint.setDisplayName(new StringTextComponent(TextFormatting.RESET + "" + TextFormatting.WHITE - + "Blueprint (" + TextFormatting.GOLD + schematic + TextFormatting.WHITE + ")")); - blueprint.getTag().putString("Owner", player.getName().getFormattedText()); - blueprint.getTag().putString("File", schematic); - - tileEntity.outputStack = blueprint; + tileEntity.outputStack = ItemBlueprint.create(schematic, player.getName().getFormattedText()); dimpos.world.notifyBlockUpdate(dimpos.pos, blockState, blockState, 3); diff --git a/src/main/java/com/simibubi/create/block/SchematicTableBlock.java b/src/main/java/com/simibubi/create/block/SchematicTableBlock.java index 39904510d..dc030606d 100644 --- a/src/main/java/com/simibubi/create/block/SchematicTableBlock.java +++ b/src/main/java/com/simibubi/create/block/SchematicTableBlock.java @@ -1,12 +1,9 @@ package com.simibubi.create.block; -import javax.annotation.Nullable; - import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.block.HorizontalBlock; -import net.minecraft.block.ITileEntityProvider; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.inventory.InventoryHelper; import net.minecraft.inventory.container.INamedContainerProvider; @@ -19,8 +16,7 @@ import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.world.IBlockReader; import net.minecraft.world.World; -@SuppressWarnings("deprecation") -public class SchematicTableBlock extends HorizontalBlock implements ITileEntityProvider { +public class SchematicTableBlock extends HorizontalBlock { public SchematicTableBlock() { super(Properties.from(Blocks.OAK_PLANKS)); @@ -43,17 +39,18 @@ public class SchematicTableBlock extends HorizontalBlock implements ITileEntityP } @Override - public boolean hasTileEntity() { + public boolean hasTileEntity(BlockState state) { return true; } @Override public boolean onBlockActivated(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand handIn, BlockRayTraceResult hit) { + if (worldIn.isRemote) { return true; } else { - INamedContainerProvider inamedcontainerprovider = this.getContainer(state, worldIn, pos); + INamedContainerProvider inamedcontainerprovider = (INamedContainerProvider) worldIn.getTileEntity(pos); if (inamedcontainerprovider != null) { player.openContainer(inamedcontainerprovider); } @@ -61,9 +58,9 @@ public class SchematicTableBlock extends HorizontalBlock implements ITileEntityP return true; } } - + @Override - public TileEntity createNewTileEntity(IBlockReader worldIn) { + public TileEntity createTileEntity(BlockState state, IBlockReader world) { return new SchematicTableTileEntity(); } @@ -80,16 +77,4 @@ public class SchematicTableBlock extends HorizontalBlock implements ITileEntityP } - public boolean eventReceived(BlockState state, World worldIn, BlockPos pos, int id, int param) { - super.eventReceived(state, worldIn, pos, id, param); - TileEntity tileentity = worldIn.getTileEntity(pos); - return tileentity == null ? false : tileentity.receiveClientEvent(id, param); - } - - @Nullable - public INamedContainerProvider getContainer(BlockState state, World worldIn, BlockPos pos) { - TileEntity tileentity = worldIn.getTileEntity(pos); - return tileentity instanceof INamedContainerProvider ? (INamedContainerProvider) tileentity : null; - } - } diff --git a/src/main/java/com/simibubi/create/block/SchematicTableContainer.java b/src/main/java/com/simibubi/create/block/SchematicTableContainer.java index e614a8f5e..71cf7d17f 100644 --- a/src/main/java/com/simibubi/create/block/SchematicTableContainer.java +++ b/src/main/java/com/simibubi/create/block/SchematicTableContainer.java @@ -45,14 +45,14 @@ public class SchematicTableContainer extends Container { this.player = inv.player; this.te = te; - inputSlot = new Slot(tableInventory, 0, -9, 15) { + inputSlot = new Slot(tableInventory, 0, -9, 40) { @Override public boolean isItemValid(ItemStack stack) { return AllItems.EMPTY_BLUEPRINT.typeOf(stack); } }; - outputSlot = new Slot(tableInventory, 1, 75, 15) { + outputSlot = new Slot(tableInventory, 1, 75, 40) { @Override public boolean isItemValid(ItemStack stack) { return false; @@ -72,12 +72,12 @@ public class SchematicTableContainer extends Container { 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, 77 + l * 18)); + this.addSlot(new Slot(inv, j1 + l * 9 + 9, -8 + j1 * 18, 102 + l * 18)); } } for (int i1 = 0; i1 < 9; ++i1) { - this.addSlot(new Slot(inv, i1, -8 + i1 * 18, 135)); + this.addSlot(new Slot(inv, i1, -8 + i1 * 18, 160)); } } diff --git a/src/main/java/com/simibubi/create/block/SchematicannonTileEntity.java b/src/main/java/com/simibubi/create/block/SchematicannonTileEntity.java index d556ad35b..3192cc005 100644 --- a/src/main/java/com/simibubi/create/block/SchematicannonTileEntity.java +++ b/src/main/java/com/simibubi/create/block/SchematicannonTileEntity.java @@ -32,6 +32,8 @@ import net.minecraft.tileentity.ITickableTileEntity; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; +import net.minecraft.util.SoundCategory; +import net.minecraft.util.SoundEvents; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; @@ -262,19 +264,27 @@ public class SchematicannonTileEntity extends TileEntitySynced implements ITicka 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(), 3); + world.notifyBlockUpdate(getPos(), getBlockState(), getBlockState(), 2); + + if (target.withinDistance(getPos(), 2f)) { + return; + } if (creative) { launchBlock(currentPos.add(anchor), state); - missingBlock = false; return; } @@ -285,7 +295,6 @@ public class SchematicannonTileEntity extends TileEntitySynced implements ITicka // Overwrite in case its rotated launchBlock(target, state); - missingBlock = false; } // Search for required item diff --git a/src/main/java/com/simibubi/create/gui/AbstractSimiScreen.java b/src/main/java/com/simibubi/create/gui/AbstractSimiScreen.java index 5f01b4b92..31ea5eb2b 100644 --- a/src/main/java/com/simibubi/create/gui/AbstractSimiScreen.java +++ b/src/main/java/com/simibubi/create/gui/AbstractSimiScreen.java @@ -8,7 +8,10 @@ import com.simibubi.create.gui.widgets.AbstractSimiWidget; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.widget.Widget; import net.minecraft.util.text.StringTextComponent; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +@OnlyIn(Dist.CLIENT) public abstract class AbstractSimiScreen extends Screen { protected int sWidth, sHeight; diff --git a/src/main/java/com/simibubi/create/gui/BlueprintHotbarOverlay.java b/src/main/java/com/simibubi/create/gui/BlueprintHotbarOverlay.java new file mode 100644 index 000000000..a5712f38e --- /dev/null +++ b/src/main/java/com/simibubi/create/gui/BlueprintHotbarOverlay.java @@ -0,0 +1,20 @@ +package com.simibubi.create.gui; + +import com.mojang.blaze3d.platform.GlStateManager; + +import net.minecraft.client.MainWindow; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.AbstractGui; + +public class BlueprintHotbarOverlay extends AbstractGui { + + public void renderOn(int slot) { + MainWindow mainWindow = Minecraft.getInstance().mainWindow; + int x = mainWindow.getScaledWidth() / 2 - 92; + int y = mainWindow.getScaledHeight() - 23; + GlStateManager.enableBlend(); + GlStateManager.enableAlphaTest(); + GuiResources.BLUEPRINT_SLOT.draw(this, x + 20 * slot, y); + } + +} diff --git a/src/main/java/com/simibubi/create/gui/GuiHandler.java b/src/main/java/com/simibubi/create/gui/GuiHandler.java deleted file mode 100644 index f7fa187ab..000000000 --- a/src/main/java/com/simibubi/create/gui/GuiHandler.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.simibubi.create.gui; - -public class GuiHandler { - -} diff --git a/src/main/java/com/simibubi/create/gui/GuiOpener.java b/src/main/java/com/simibubi/create/gui/GuiOpener.java index 74112956f..d24a45826 100644 --- a/src/main/java/com/simibubi/create/gui/GuiOpener.java +++ b/src/main/java/com/simibubi/create/gui/GuiOpener.java @@ -2,11 +2,14 @@ package com.simibubi.create.gui; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screen.Screen; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod.EventBusSubscriber; import net.minecraftforge.fml.common.gameevent.TickEvent.ClientTickEvent; -@EventBusSubscriber +@OnlyIn(Dist.CLIENT) +@EventBusSubscriber(value = Dist.CLIENT) public class GuiOpener { private static Screen openedGuiNextTick; diff --git a/src/main/java/com/simibubi/create/gui/GuiResources.java b/src/main/java/com/simibubi/create/gui/GuiResources.java index 599dbfa38..4025376a1 100644 --- a/src/main/java/com/simibubi/create/gui/GuiResources.java +++ b/src/main/java/com/simibubi/create/gui/GuiResources.java @@ -27,6 +27,8 @@ public enum GuiResources { INDICATOR_RED("widgets.png", 36, 23, 18, 5), GRAY("background.png", 0, 0, 16, 16), + BLUEPRINT_SLOT("widgets.png", 90, 0, 24, 24), + // Icons ICON_NONE("icons.png", 16, 16, 16, 16), ICON_ADD("icons.png", 16, 16), diff --git a/src/main/java/com/simibubi/create/utility/Keyboard.java b/src/main/java/com/simibubi/create/gui/Keyboard.java similarity index 78% rename from src/main/java/com/simibubi/create/utility/Keyboard.java rename to src/main/java/com/simibubi/create/gui/Keyboard.java index 088e26633..ada30d0a7 100644 --- a/src/main/java/com/simibubi/create/utility/Keyboard.java +++ b/src/main/java/com/simibubi/create/gui/Keyboard.java @@ -1,7 +1,8 @@ -package com.simibubi.create.utility; +package com.simibubi.create.gui; + +import org.lwjgl.glfw.GLFW; import net.minecraft.client.Minecraft; -import net.minecraft.client.util.InputMappings; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; @@ -24,7 +25,7 @@ public class Keyboard { public static final int G = 71; public static boolean isKeyDown(int key) { - return InputMappings.isKeyDown(Minecraft.getInstance().mainWindow.getHandle(), key); + return GLFW.glfwGetKey(Minecraft.getInstance().mainWindow.getHandle(), key) != 0; } } diff --git a/src/main/java/com/simibubi/create/gui/SchematicTableScreen.java b/src/main/java/com/simibubi/create/gui/SchematicTableScreen.java index 4fb5b7406..8e8a0d5ab 100644 --- a/src/main/java/com/simibubi/create/gui/SchematicTableScreen.java +++ b/src/main/java/com/simibubi/create/gui/SchematicTableScreen.java @@ -2,8 +2,6 @@ package com.simibubi.create.gui; import java.util.List; -import org.lwjgl.opengl.GL11; - import com.mojang.blaze3d.platform.GlStateManager; import com.simibubi.create.AllBlocks; import com.simibubi.create.Create; @@ -18,15 +16,11 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.gui.IHasContainer; import net.minecraft.client.gui.screen.inventory.ContainerScreen; import net.minecraft.client.gui.widget.Widget; -import net.minecraft.client.renderer.BufferBuilder; -import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.texture.AtlasTexture; -import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.text.ITextComponent; -import net.minecraftforge.client.model.data.EmptyModelData; public class SchematicTableScreen extends ContainerScreen implements IHasContainer { @@ -53,7 +47,7 @@ public class SchematicTableScreen extends ContainerScreen tools; + protected Consumer callback; + public boolean focused; + private float yOffset; + protected int selection; + + protected int w; + protected int h; + + public ToolSelectionScreen(List tools, Consumer callback) { + super(new StringTextComponent("Tool Selection")); + this.minecraft = Minecraft.getInstance(); + this.tools = tools; + this.callback = callback; + focused = false; + yOffset = 0; + selection = 0; + + callback.accept(tools.get(selection)); + + w = tools.size() * 50 + 30; + h = 30; + } + + public void setSelectedElement(Tools tool) { + if (!tools.contains(tool)) + return; + selection = tools.indexOf(tool); + } + + public void cycle(int direction) { + selection += (direction < 0)? 1 : -1; + selection = (selection + tools.size()) % tools.size(); + } + + private void draw(float partialTicks) { + MainWindow mainWindow = Minecraft.getInstance().mainWindow; + + int x = (mainWindow.getScaledWidth() - w) / 2 + 15; + int y = mainWindow.getScaledHeight() - h - 75; + + GlStateManager.pushMatrix(); + GlStateManager.translatef(0, -yOffset, 0); + + GuiResources gray = GuiResources.GRAY; + GlStateManager.enableBlend(); + GlStateManager.enableAlphaTest(); + GlStateManager.color4f(1, 1, 1, focused? 7 / 8f : 1 / 2f); + + Minecraft.getInstance().getTextureManager().bindTexture(gray.location); + blit(x - 15, y, gray.startX, gray.startY, w, h, gray.width, gray.height); + GlStateManager.color4f(1, 1, 1, 1); + + for (int i = 0; i < tools.size(); i++) { + GlStateManager.pushMatrix(); + + float alpha = focused? 1 : .2f; + if (i == selection) { + GlStateManager.translatef(0, -10, 0); + drawCenteredString(minecraft.fontRenderer, tools.get(i).getDisplayName(), x + i * 50 + 24, y + 28, 0xCCDDFF); + alpha = 1; + } + GlStateManager.color4f(0, 0, 0, alpha); + tools.get(i).getIcon().draw(this, x + i * 50 + 16, y + 12); + GlStateManager.color4f(1, 1, 1, alpha); + tools.get(i).getIcon().draw(this, x + i * 50 + 16, y + 11); + + GlStateManager.popMatrix(); + } + + GlStateManager.popMatrix(); + } + + public void update() { + if (focused) yOffset += (10 - yOffset) * .1f; + else yOffset *= .9f; + } + + public void renderPassive(float partialTicks) { + draw(partialTicks); + } + + @Override + public void onClose() { + callback.accept(tools.get(selection)); + } + +} diff --git a/src/main/java/com/simibubi/create/gui/widgets/ScrollArea.java b/src/main/java/com/simibubi/create/gui/widgets/ScrollArea.java index fed9acd9c..fbf0f6ed9 100644 --- a/src/main/java/com/simibubi/create/gui/widgets/ScrollArea.java +++ b/src/main/java/com/simibubi/create/gui/widgets/ScrollArea.java @@ -2,7 +2,7 @@ package com.simibubi.create.gui.widgets; import java.util.function.Consumer; -import com.simibubi.create.utility.Keyboard; +import com.simibubi.create.gui.Keyboard; import net.minecraft.util.text.TextFormatting; diff --git a/src/main/java/com/simibubi/create/item/ItemBlueprint.java b/src/main/java/com/simibubi/create/item/ItemBlueprint.java index 947104667..7698a1d86 100644 --- a/src/main/java/com/simibubi/create/item/ItemBlueprint.java +++ b/src/main/java/com/simibubi/create/item/ItemBlueprint.java @@ -9,6 +9,7 @@ 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.schematic.SchematicHologram; @@ -24,10 +25,15 @@ import net.minecraft.nbt.NBTUtil; import net.minecraft.util.ActionResult; import net.minecraft.util.ActionResultType; import net.minecraft.util.Hand; +import net.minecraft.util.Mirror; +import net.minecraft.util.Rotation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.StringTextComponent; +import net.minecraft.util.text.TextFormatting; import net.minecraft.world.World; +import net.minecraft.world.gen.feature.template.PlacementSettings; import net.minecraft.world.gen.feature.template.Template; +import net.minecraftforge.fml.common.thread.SidedThreadGroups; public class ItemBlueprint extends Item { @@ -35,6 +41,70 @@ public class ItemBlueprint extends Item { super(properties.maxStackSize(1)); } + public static ItemStack create(String schematic, String owner) { + ItemStack blueprint = new ItemStack(AllItems.BLUEPRINT.item); + + CompoundNBT tag = new CompoundNBT(); + tag.putBoolean("Deployed", false); + tag.putString("Owner", owner); + tag.putString("File", schematic); + tag.put("Anchor", NBTUtil.writeBlockPos(BlockPos.ZERO)); + 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 + ")")); + + return blueprint; + } + + public static void writeSize(ItemStack blueprint) { + CompoundNBT tag = blueprint.getTag(); + Template t = getSchematic(blueprint); + 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"))); + + return settings; + } + + public static Template getSchematic(ItemStack blueprint) { + Template t = new Template(); + String owner = blueprint.getTag().getString("Owner"); + String schematic = blueprint.getTag().getString("File"); + + String filepath = ""; + + if (Thread.currentThread().getThreadGroup() == SidedThreadGroups.SERVER) + filepath = "schematics/uploaded/" + owner + "/" + schematic; + else + filepath = "schematics/" + schematic; + + InputStream stream = null; + try { + stream = Files.newInputStream(Paths.get(filepath), StandardOpenOption.READ); + CompoundNBT nbt = CompressedStreamTools.readCompressed(stream); + t.read(nbt); + + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (stream != null) + IOUtils.closeQuietly(stream); + } + + return t; + } + @Override public ActionResultType onItemUse(ItemUseContext context) { @@ -66,28 +136,6 @@ public class ItemBlueprint extends Item { return ActionResultType.SUCCESS; } - if (!(context.getPlayer().getName().getFormattedText().equals(tag.getString("Owner")))) { - context.getPlayer() - .sendStatusMessage(new StringTextComponent("You are not the Owner of this Schematic."), true); - } - - String filepath = "schematics/" + tag.getString("File"); - Template t = new Template(); - - InputStream stream = null; - try { - stream = Files.newInputStream(Paths.get(filepath), StandardOpenOption.READ); - CompoundNBT nbt = CompressedStreamTools.readCompressed(stream); - t.read(nbt); - new SchematicHologram().startHologram(t, pos.offset(context.getFace())); - - } catch (IOException e) { - e.printStackTrace(); - } finally { - if (stream != null) - IOUtils.closeQuietly(stream); - } - } context.getPlayer().getCooldownTracker().setCooldown(this, 10); diff --git a/src/main/java/com/simibubi/create/item/ItemWandSymmetry.java b/src/main/java/com/simibubi/create/item/ItemWandSymmetry.java index 70332bc05..0c2608c62 100644 --- a/src/main/java/com/simibubi/create/item/ItemWandSymmetry.java +++ b/src/main/java/com/simibubi/create/item/ItemWandSymmetry.java @@ -31,6 +31,9 @@ import net.minecraft.util.math.shapes.ISelectionContext; import net.minecraft.util.text.StringTextComponent; import net.minecraft.util.text.TextFormatting; import net.minecraft.world.World; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.network.PacketDistributor; public class ItemWandSymmetry extends Item { @@ -41,16 +44,16 @@ public class ItemWandSymmetry extends Item { public ItemWandSymmetry(Properties properties) { super(properties.maxStackSize(1)); } - + @Override public ActionResultType onItemUse(ItemUseContext context) { PlayerEntity player = context.getPlayer(); BlockPos pos = context.getPos(); player.getCooldownTracker().setCooldown(this, 5); - - if (context.getWorld().isRemote || context.getHand() != Hand.MAIN_HAND) + + if (context.getWorld().isRemote || context.getHand() != Hand.MAIN_HAND) return ActionResultType.SUCCESS; - + ItemStack wand = player.getHeldItem(context.getHand()); checkNBT(wand); CompoundNBT compound = wand.getTag().getCompound($SYMMETRY); @@ -68,8 +71,9 @@ public class ItemWandSymmetry extends Item { SymmetryElement newElement = new SymmetryPlane(pos3d); if (previousElement instanceof SymmetryEmptySlot) { - newElement.setOrientation((player.getHorizontalFacing() == Direction.NORTH - || player.getHorizontalFacing() == Direction.SOUTH) ? SymmetryPlane.Align.XY.ordinal() + newElement.setOrientation( + (player.getHorizontalFacing() == Direction.NORTH || player.getHorizontalFacing() == Direction.SOUTH) + ? SymmetryPlane.Align.XY.ordinal() : SymmetryPlane.Align.YZ.ordinal()); newElement.enable = true; player.sendStatusMessage(new StringTextComponent(TextFormatting.GREEN + "New Plane created"), true); @@ -105,12 +109,19 @@ public class ItemWandSymmetry extends Item { @Override public ActionResult onItemRightClick(World worldIn, PlayerEntity playerIn, Hand handIn) { if (worldIn.isRemote) { - GuiOpener.open(new GuiWandSymmetry(playerIn.getHeldItem(handIn))); - playerIn.getCooldownTracker().setCooldown(this, 5); + DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> { + openWandGUI(playerIn.getHeldItem(handIn)); + }); + playerIn.getCooldownTracker().setCooldown(this, 5); } return super.onItemRightClick(worldIn, playerIn, handIn); } + @OnlyIn(Dist.CLIENT) + private void openWandGUI(ItemStack wand) { + GuiOpener.open(new GuiWandSymmetry(wand)); + } + private static void checkNBT(ItemStack wand) { if (!wand.hasTag() || !wand.getTag().contains($SYMMETRY)) { wand.setTag(new CompoundNBT()); @@ -136,15 +147,14 @@ public class ItemWandSymmetry extends Item { Map blockSet = new HashMap<>(); blockSet.put(pos, block); - SymmetryElement symmetry = SymmetryElement - .fromNBT((CompoundNBT) wand.getTag().getCompound($SYMMETRY)); + SymmetryElement symmetry = SymmetryElement.fromNBT((CompoundNBT) wand.getTag().getCompound($SYMMETRY)); Vec3d mirrorPos = symmetry.getPosition(); if (mirrorPos.distanceTo(new Vec3d(pos)) > 50) return; symmetry.process(blockSet); - + BlockPos to = new BlockPos(mirrorPos); List targets = new ArrayList<>(); @@ -152,11 +162,12 @@ public class ItemWandSymmetry extends Item { for (BlockPos position : blockSet.keySet()) { if (world.func_217350_a(block, position, ISelectionContext.forEntity(player))) { world.setBlockState(position, blockSet.get(position)); - targets.add(position); + targets.add(position); } } - - Packets.channel.send(PacketDistributor.TRACKING_ENTITY_AND_SELF.with(() -> player), new PacketSymmetryEffect(to, targets)); + + Packets.channel.send(PacketDistributor.TRACKING_ENTITY_AND_SELF.with(() -> player), + new PacketSymmetryEffect(to, targets)); } public static void remove(World world, ItemStack wand, PlayerEntity player, BlockPos pos) { @@ -167,8 +178,7 @@ public class ItemWandSymmetry extends Item { Map blockSet = new HashMap<>(); blockSet.put(pos, air); - SymmetryElement symmetry = SymmetryElement - .fromNBT((CompoundNBT) wand.getTag().getCompound($SYMMETRY)); + SymmetryElement symmetry = SymmetryElement.fromNBT((CompoundNBT) wand.getTag().getCompound($SYMMETRY)); Vec3d mirrorPos = symmetry.getPosition(); if (mirrorPos.distanceTo(new Vec3d(pos)) > 50) @@ -178,14 +188,15 @@ public class ItemWandSymmetry extends Item { BlockPos to = new BlockPos(mirrorPos); List targets = new ArrayList<>(); - + targets.add(pos); for (BlockPos position : blockSet.keySet()) { targets.add(position); world.setBlockState(position, air); } - - Packets.channel.send(PacketDistributor.TRACKING_ENTITY_AND_SELF.with(() -> player), new PacketSymmetryEffect(to, targets)); + + Packets.channel.send(PacketDistributor.TRACKING_ENTITY_AND_SELF.with(() -> player), + new PacketSymmetryEffect(to, targets)); } - + } diff --git a/src/main/java/com/simibubi/create/networking/PacketNbt.java b/src/main/java/com/simibubi/create/networking/PacketNbt.java index 1b90cc077..acd64d186 100644 --- a/src/main/java/com/simibubi/create/networking/PacketNbt.java +++ b/src/main/java/com/simibubi/create/networking/PacketNbt.java @@ -10,26 +10,44 @@ import net.minecraftforge.fml.network.NetworkEvent.Context; public class PacketNbt { public ItemStack stack; + public int slot; public PacketNbt(ItemStack stack) { + this(stack, -1); + } + + public PacketNbt(ItemStack stack, int slot) { this.stack = stack; + this.slot = slot; } public PacketNbt(PacketBuffer buffer) { stack = buffer.readItemStack(); + slot = buffer.readInt(); } public void toBytes(PacketBuffer buffer) { buffer.writeItemStack(stack); + buffer.writeInt(slot); } public void handle(Supplier context) { context.get().enqueueWork(() -> { ServerPlayerEntity player = context.get().getSender(); - ItemStack heldItem = player.getHeldItemMainhand(); - if (heldItem.getItem() == stack.getItem()) { - heldItem.setTag(stack.getTag()); + + if (slot == -1) { + ItemStack heldItem = player.getHeldItemMainhand(); + if (heldItem.getItem() == stack.getItem()) { + heldItem.setTag(stack.getTag()); + } + return; } + + ItemStack heldInSlot = player.inventory.getStackInSlot(slot); + if (heldInSlot.getItem() == stack.getItem()) { + heldInSlot.setTag(stack.getTag()); + } + }); } diff --git a/src/main/java/com/simibubi/create/networking/PacketSchematicTableContainer.java b/src/main/java/com/simibubi/create/networking/PacketSchematicTableContainer.java index bee33fe95..5a5605be4 100644 --- a/src/main/java/com/simibubi/create/networking/PacketSchematicTableContainer.java +++ b/src/main/java/com/simibubi/create/networking/PacketSchematicTableContainer.java @@ -7,8 +7,6 @@ import com.simibubi.create.block.SchematicTableContainer; import net.minecraft.client.Minecraft; import net.minecraft.inventory.container.Container; import net.minecraft.network.PacketBuffer; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.fml.network.NetworkEvent.Context; public class PacketSchematicTableContainer { @@ -33,14 +31,12 @@ public class PacketSchematicTableContainer { buffer.writeFloat(progress); } - @OnlyIn(Dist.CLIENT) public void handle(Supplier context) { context.get().enqueueWork(() -> { Container c = Minecraft.getInstance().player.openContainer; if (c != null && c instanceof SchematicTableContainer) { ((SchematicTableContainer) c).receiveSchematicInfo(schematic, progress); } - }); } diff --git a/src/main/java/com/simibubi/create/networking/PacketSchematicUpload.java b/src/main/java/com/simibubi/create/networking/PacketSchematicUpload.java index 60c9bc7ce..71c8a1f10 100644 --- a/src/main/java/com/simibubi/create/networking/PacketSchematicUpload.java +++ b/src/main/java/com/simibubi/create/networking/PacketSchematicUpload.java @@ -43,7 +43,7 @@ public class PacketSchematicUpload { public PacketSchematicUpload(PacketBuffer buffer) { code = buffer.readInt(); - schematic = buffer.readString(); + schematic = buffer.readString(256); if (code == WRITE) data = buffer.readByteArray(); diff --git a/src/main/java/com/simibubi/create/networking/Packets.java b/src/main/java/com/simibubi/create/networking/Packets.java index 1993307c3..0bae86f3a 100644 --- a/src/main/java/com/simibubi/create/networking/Packets.java +++ b/src/main/java/com/simibubi/create/networking/Packets.java @@ -10,13 +10,14 @@ public class Packets { private static final String PROTOCOL_VERSION = "1"; - public static final SimpleChannel channel = NetworkRegistry.newSimpleChannel( - new ResourceLocation(Create.ID, "main"), () -> PROTOCOL_VERSION, PROTOCOL_VERSION::equals, - PROTOCOL_VERSION::equals); + public static SimpleChannel channel; public static void registerPackets() { int i = 0; + channel = NetworkRegistry.newSimpleChannel(new ResourceLocation(Create.ID, "main"), () -> PROTOCOL_VERSION, + PROTOCOL_VERSION::equals, PROTOCOL_VERSION::equals); + channel.registerMessage(i++, PacketNbt.class, PacketNbt::toBytes, PacketNbt::new, PacketNbt::handle); channel.registerMessage(i++, PacketSchematicTableContainer.class, PacketSchematicTableContainer::toBytes, PacketSchematicTableContainer::new, PacketSchematicTableContainer::handle); diff --git a/src/main/java/com/simibubi/create/schematic/BlueprintHandler.java b/src/main/java/com/simibubi/create/schematic/BlueprintHandler.java new file mode 100644 index 000000000..d591bf545 --- /dev/null +++ b/src/main/java/com/simibubi/create/schematic/BlueprintHandler.java @@ -0,0 +1,355 @@ +package com.simibubi.create.schematic; + +import java.util.HashMap; + +import org.lwjgl.glfw.GLFW; + +import com.google.common.collect.ImmutableList; +import com.simibubi.create.AllItems; +import com.simibubi.create.Create; +import com.simibubi.create.gui.BlueprintHotbarOverlay; +import com.simibubi.create.gui.Keyboard; +import com.simibubi.create.gui.ToolSelectionScreen; +import com.simibubi.create.item.ItemBlueprint; +import com.simibubi.create.networking.PacketNbt; +import com.simibubi.create.networking.Packets; +import com.simibubi.create.utility.TessellatorHelper; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.player.ClientPlayerEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.NBTUtil; +import net.minecraft.util.Direction.Axis; +import net.minecraft.util.Mirror; +import net.minecraft.util.Rotation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.world.gen.feature.template.PlacementSettings; +import net.minecraft.world.gen.feature.template.Template; +import net.minecraftforge.client.event.InputEvent.KeyInputEvent; +import net.minecraftforge.client.event.InputEvent.MouseInputEvent; +import net.minecraftforge.client.event.RenderGameOverlayEvent; +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(bus = Bus.FORGE) +public class BlueprintHandler { + + public static BlueprintHandler instance; + + public Template cachedSchematic; + public String cachedSchematicName; + public PlacementSettings cachedSettings; + + public BlockPos anchor; + public BlockPos size; + public boolean active; + public boolean deployed; + public int slot; + public ItemStack item; + + public Tools currentTool; + public ToolSelectionScreen selectionScreen; + + public static final int SYNC_DELAY = 20; + public int syncCooldown; + + private BlueprintHotbarOverlay overlay; + + public BlueprintHandler() { + instance = this; + currentTool = Tools.Deploy; + overlay = new BlueprintHotbarOverlay(); + selectionScreen = new ToolSelectionScreen(ImmutableList.of(Tools.Deploy), this::equip); + } + + @SubscribeEvent + public static void onClientTick(ClientTickEvent event) { + ClientPlayerEntity player = Minecraft.getInstance().player; + + if (player == null) + return; + + ItemStack stack = findBlueprintInHand(player); + if (stack == null) { + instance.active = false; + instance.syncCooldown = 0; + instance.slot = 0; + if (instance.item != null && itemLost(player)) { + instance.item = null; + SchematicHologram.reset(); + } + return; + } + + // Newly equipped + if (!instance.active || !stack.getTag().getString("File").equals(instance.cachedSchematicName)) { + instance.loadSettings(stack); + instance.cachedSchematicName = stack.getTag().getString("File"); + instance.active = true; + if (instance.deployed) { + Tools toolBefore = instance.currentTool; + instance.selectionScreen = new ToolSelectionScreen(Tools.getTools(), instance::equip); + if (toolBefore != null) { + instance.selectionScreen.setSelectedElement(toolBefore); + instance.equip(toolBefore); + } + } + else + instance.selectionScreen = new ToolSelectionScreen(ImmutableList.of(Tools.Deploy), instance::equip); + instance.sync(); + } + + if (!instance.active) + return; + + if (instance.syncCooldown > 0) + instance.syncCooldown--; + if (instance.syncCooldown == 1) + instance.sync(); + + instance.selectionScreen.update(); + instance.currentTool.getTool().updateSelection(); + } + + @SubscribeEvent + public static void onRenderWorld(RenderWorldLastEvent event) { + if (!instance.active) + return; + + TessellatorHelper.prepareForDrawing(); + instance.currentTool.getTool().renderTool(); + TessellatorHelper.cleanUpAfterDrawing(); + } + + @SubscribeEvent + public static void onRenderOverlay(RenderGameOverlayEvent event) { + if (!instance.active) + return; + + instance.overlay.renderOn(instance.slot); + instance.currentTool.getTool().renderOverlay(); + instance.selectionScreen.renderPassive(event.getPartialTicks()); + } + + @SubscribeEvent + public static void onClick(MouseInputEvent event) { + if (Minecraft.getInstance().currentScreen != null) + return; + if (event.getAction() != Keyboard.PRESS) + return; + if (event.getButton() != 1) + return; + if (!instance.active) + return; + + instance.currentTool.getTool().handleRightClick(); + } + + @SubscribeEvent + public static void onKeyTyped(KeyInputEvent event) { + if (Minecraft.getInstance().currentScreen != null) + return; + if (event.getKey() != Create.TOOL_MENU.getKey().getKeyCode()) + return; + if (!instance.active) + return; + + boolean released = event.getAction() == Keyboard.RELEASE; + + ToolSelectionScreen toolSelection = instance.selectionScreen; + if (released && toolSelection.focused) { + toolSelection.focused = false; + toolSelection.onClose(); + } + + if (!released && !toolSelection.focused) + toolSelection.focused = true; + } + + public boolean onScroll(double delta) { + if (!active) + return false; + if (selectionScreen.focused) { + selectionScreen.cycle((int) delta); + return true; + } + if (Keyboard.isKeyDown(GLFW.GLFW_KEY_LEFT_CONTROL)) { + return currentTool.getTool().handleMouseWheel(delta); + } + + return false; + } + + private static ItemStack findBlueprintInHand(PlayerEntity player) { + ItemStack stack = player.getHeldItemMainhand(); + if (!AllItems.BLUEPRINT.typeOf(stack)) + return null; + if (!stack.hasTag()) + return null; + + instance.item = stack; + instance.slot = player.inventory.currentItem; + return stack; + } + + private static boolean itemLost(PlayerEntity player) { + for (int i = 0; i < PlayerInventory.getHotbarSize(); i++) { + if (!player.inventory.getStackInSlot(i).isItemEqual(instance.item)) + continue; + if (!ItemStack.areItemStackTagsEqual(player.inventory.getStackInSlot(i), instance.item)) + continue; + return false; + } + return true; + } + + public void markDirty() { + syncCooldown = SYNC_DELAY; + SchematicHologram.reset(); + } + + public void sync() { + 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); + } + + public void equip(Tools tool) { + this.currentTool = tool; + currentTool.getTool().init(); + } + + public void loadSettings(ItemStack blueprint) { + CompoundNBT tag = blueprint.getTag(); + cachedSettings = new PlacementSettings(); + cachedSettings.setRotation(Rotation.valueOf(tag.getString("Rotation"))); + cachedSettings.setMirror(Mirror.valueOf(tag.getString("Mirror"))); + + deployed = tag.getBoolean("Deployed"); + if (deployed) + anchor = NBTUtil.readBlockPos(tag.getCompound("Anchor")); + + size = NBTUtil.readBlockPos(tag.getCompound("Bounds")); + } + + public void flip(Axis axis) { + + Rotation r = cachedSettings.getRotation(); + boolean rotationAt90s = r == Rotation.CLOCKWISE_90 || r == Rotation.COUNTERCLOCKWISE_90; + Mirror mirror = axis == Axis.Z ^ rotationAt90s ? Mirror.FRONT_BACK : Mirror.LEFT_RIGHT; + + BlockPos coordModifier = new BlockPos((r == Rotation.NONE || r == Rotation.COUNTERCLOCKWISE_90) ? 1 : -1, 0, + (r == Rotation.NONE || r == Rotation.CLOCKWISE_90) ? 1 : -1); + BlockPos anchorOffset = axis == Axis.Z + ? new BlockPos(((rotationAt90s ? size.getZ() : size.getX()) - 1) * coordModifier.getX(), 0, 0) + : new BlockPos(0, 0, ((!rotationAt90s ? size.getZ() : size.getX()) - 1) * coordModifier.getZ()); + + Mirror m = cachedSettings.getMirror(); + + if (m == Mirror.NONE) { + cachedSettings.setMirror(mirror); + anchor = anchor.add(anchorOffset); + Minecraft.getInstance().player.sendStatusMessage( + new StringTextComponent("Mirror: " + cachedSettings.getMirror().toString()), true); + + } else if (m == mirror) { + cachedSettings.setMirror(Mirror.NONE); + anchor = anchor.subtract(anchorOffset); + Minecraft.getInstance().player.sendStatusMessage( + new StringTextComponent("Mirror: " + cachedSettings.getMirror().toString()), true); + + } else if (m != mirror) { + cachedSettings.setMirror(Mirror.NONE); + anchor = anchor.add(anchorOffset); + cachedSettings.setRotation(r.add(Rotation.CLOCKWISE_180)); + Minecraft.getInstance().player.sendStatusMessage( + new StringTextComponent("Mirror: None, Rotation: " + cachedSettings.getRotation().toString()), + true); + } + + item.getTag().put("Anchor", NBTUtil.writeBlockPos(anchor)); + item.getTag().putString("Mirror", cachedSettings.getMirror().name()); + item.getTag().putString("Rotation", r.name()); + + markDirty(); + } + + public void rotate(Rotation rotation) { + Rotation r = cachedSettings.getRotation(); + BlockPos center = centerOfSchematic(); + cachedSettings.setRotation(r.add(rotation)); + BlockPos diff = center.subtract(anchor); + BlockPos move = diff.subtract(diff.rotate(rotation)); + anchor = anchor.add(move); + + item.getTag().put("Anchor", NBTUtil.writeBlockPos(anchor)); + item.getTag().putString("Rotation", cachedSettings.getRotation().name()); + + Minecraft.getInstance().player.sendStatusMessage( + new StringTextComponent("Rotation: " + cachedSettings.getRotation().toString()), true); + + markDirty(); + } + + public void moveTo(BlockPos anchor) { + if (!deployed) + instance.selectionScreen = new ToolSelectionScreen(Tools.getTools(), instance::equip); + + deployed = true; + this.anchor = anchor; + item.getTag().putBoolean("Deployed", true); + item.getTag().put("Anchor", NBTUtil.writeBlockPos(anchor)); + markDirty(); + } + + public BlockPos getTransformedSize() { + BlockPos flipped = size; + if (cachedSettings.getMirror() == Mirror.FRONT_BACK) + flipped = new BlockPos(-flipped.getX(), flipped.getY(), flipped.getZ()); + if (cachedSettings.getMirror() == Mirror.LEFT_RIGHT) + flipped = new BlockPos(flipped.getX(), flipped.getY(), -flipped.getZ()); + + BlockPos rotate = flipped.rotate(cachedSettings.getRotation()); + return rotate; + } + + public BlockPos getTransformedAnchor() { + BlockPos anchor = this.anchor; + Rotation r = cachedSettings.getRotation(); + + BlockPos flipOffset = BlockPos.ZERO; + if (cachedSettings.getMirror() == Mirror.FRONT_BACK) + flipOffset = new BlockPos(1, 0, 0); + if (cachedSettings.getMirror() == Mirror.LEFT_RIGHT) + flipOffset = new BlockPos(0, 0, 1); + + flipOffset = flipOffset.rotate(r); + anchor = anchor.add(flipOffset); + + if (r == Rotation.CLOCKWISE_90 || r == Rotation.CLOCKWISE_180) + anchor = anchor.add(1, 0, 0); + if (r == Rotation.COUNTERCLOCKWISE_90 || r == Rotation.CLOCKWISE_180) + anchor = anchor.add(0, 0, 1); + return anchor; + } + + public BlockPos centerOfSchematic() { + BlockPos size = getTransformedSize(); + BlockPos center = new BlockPos(size.getX() / 2, 0, size.getZ() / 2); + return anchor.add(center); + } + +} diff --git a/src/main/java/com/simibubi/create/schematic/Cuboid.java b/src/main/java/com/simibubi/create/schematic/Cuboid.java index 7530aa0f5..de28c2d52 100644 --- a/src/main/java/com/simibubi/create/schematic/Cuboid.java +++ b/src/main/java/com/simibubi/create/schematic/Cuboid.java @@ -11,6 +11,10 @@ public class Cuboid { public int height; public int length; + public Cuboid() { + this(BlockPos.ZERO, 0, 0, 0); + } + public Cuboid(BlockPos origin, BlockPos size) { this(origin, size.getX(), size.getY(), size.getZ()); } diff --git a/src/main/java/com/simibubi/create/schematic/ISchematicTool.java b/src/main/java/com/simibubi/create/schematic/ISchematicTool.java new file mode 100644 index 000000000..b3b1ed19e --- /dev/null +++ b/src/main/java/com/simibubi/create/schematic/ISchematicTool.java @@ -0,0 +1,15 @@ +package com.simibubi.create.schematic; + +public interface ISchematicTool { + + public void init(); + public void updateSelection(); + + public boolean handleRightClick(); + public boolean handleMouseWheel(double delta); + + public void renderTool(); + public void renderOverlay(); + + +} diff --git a/src/main/java/com/simibubi/create/schematic/SchematicDeployTool.java b/src/main/java/com/simibubi/create/schematic/SchematicDeployTool.java new file mode 100644 index 000000000..cbc6d524c --- /dev/null +++ b/src/main/java/com/simibubi/create/schematic/SchematicDeployTool.java @@ -0,0 +1,84 @@ +package com.simibubi.create.schematic; + +import org.lwjgl.glfw.GLFW; + +import com.mojang.blaze3d.platform.GlStateManager; +import com.simibubi.create.gui.Keyboard; + +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.MutableBoundingBox; + +public class SchematicDeployTool extends SchematicPlacementToolBase { + + @Override + public void init() { + super.init(); + selectionRange = -1; + } + + @Override + public void updateSelection() { + if (blueprint.active && selectionRange == -1) { + selectionRange = (int) blueprint.size.manhattanDistance(BlockPos.ZERO) / 2; + selectionRange = MathHelper.clamp(selectionRange, 1, 100); + } + selectIgnoreBlocks = Keyboard.isKeyDown(GLFW.GLFW_KEY_LEFT_CONTROL); + + super.updateSelection(); + } + + @Override + public void renderTool() { + super.renderTool(); + + if (selectedPos == null) + return; + + BlockPos size = blueprint.getTransformedSize(); + BlockPos min = selectedPos.add(Math.round(size.getX() * -.5f), 0, Math.round(size.getZ() * -.5f)); + BlockPos max = min.add(size.getX(), size.getY(), size.getZ()); + + if (blueprint.deployed) { + MutableBoundingBox bb = new MutableBoundingBox(min, min.add(blueprint.getTransformedSize())); + min = new BlockPos(bb.minX, bb.minY, bb.minZ); + max = new BlockPos(bb.maxX, bb.maxY, bb.maxZ); + } + + GlStateManager.lineWidth(3); + GlStateManager.color4f(.5f, .8f, 1, 1); + GlStateManager.disableTexture(); + + WorldRenderer.drawBoundingBox(min.getX() - 1 / 8d, min.getY() + 1 / 16d, min.getZ() - 1 / 8d, + max.getX() + 1 / 8d, max.getY() + 1 / 8d, max.getZ() + 1 / 8d, 1, 1, 1, 1); + + GlStateManager.lineWidth(1); + GlStateManager.enableTexture(); + + } + + @Override + public boolean handleMouseWheel(double delta) { + + if (selectIgnoreBlocks) { + selectionRange += delta; + selectionRange = MathHelper.clamp(selectionRange, 1, 100); + return true; + } + + return super.handleMouseWheel(delta); + } + + @Override + public boolean handleRightClick() { + if (selectedPos == null) + return super.handleRightClick(); + + BlockPos size = blueprint.getTransformedSize(); + blueprint.moveTo(selectedPos.add(Math.round(size.getX() * -.5f), 0, Math.round(size.getZ() * -.5f))); + + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/schematic/SchematicFlipTool.java b/src/main/java/com/simibubi/create/schematic/SchematicFlipTool.java new file mode 100644 index 000000000..9efda8a8d --- /dev/null +++ b/src/main/java/com/simibubi/create/schematic/SchematicFlipTool.java @@ -0,0 +1,39 @@ +package com.simibubi.create.schematic; + +public class SchematicFlipTool extends SchematicPlacementToolBase { + + @Override + public void init() { + super.init(); + renderSelectedFace = true; + } + + @Override + public boolean handleRightClick() { + mirror(); + return true; + } + + @Override + public boolean handleMouseWheel(double delta) { + mirror(); + return true; + } + + @Override + public void updateSelection() { + super.updateSelection(); + + if (!schematicSelected) + return; + + renderSelectedFace = selectedFace.getAxis().isHorizontal(); + } + + private void mirror() { + if (schematicSelected && selectedFace.getAxis().isHorizontal()) { + blueprint.flip(selectedFace.getAxis()); + } + } + +} diff --git a/src/main/java/com/simibubi/create/schematic/SchematicHologram.java b/src/main/java/com/simibubi/create/schematic/SchematicHologram.java index 8a5d7fb3d..1d69826e5 100644 --- a/src/main/java/com/simibubi/create/schematic/SchematicHologram.java +++ b/src/main/java/com/simibubi/create/schematic/SchematicHologram.java @@ -28,6 +28,7 @@ import net.minecraft.util.math.Vec3d; 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.client.ForgeHooksClient; import net.minecraftforge.client.event.RenderWorldLastEvent; import net.minecraftforge.client.model.data.EmptyModelData; @@ -36,6 +37,7 @@ import net.minecraftforge.fml.common.Mod.EventBusSubscriber; import net.minecraftforge.fml.common.gameevent.TickEvent; import net.minecraftforge.fml.common.gameevent.TickEvent.ClientTickEvent; +@OnlyIn(Dist.CLIENT) @EventBusSubscriber(Dist.CLIENT) public class SchematicHologram { @@ -63,6 +65,13 @@ public class SchematicHologram { active = true; changed = true; } + + public void startHologram(SchematicWorld world) { + this.anchor = world.anchor; + this.schematic = world; + this.active = true; + this.changed = true; + } public static SchematicHologram getInstance() { return instance; diff --git a/src/main/java/com/simibubi/create/schematic/SchematicMoveTool.java b/src/main/java/com/simibubi/create/schematic/SchematicMoveTool.java new file mode 100644 index 000000000..916f8fedb --- /dev/null +++ b/src/main/java/com/simibubi/create/schematic/SchematicMoveTool.java @@ -0,0 +1,23 @@ +package com.simibubi.create.schematic; + +public class SchematicMoveTool extends SchematicPlacementToolBase { + + @Override + public void init() { + super.init(); + renderSelectedFace = true; + } + + @Override + public boolean handleMouseWheel(double delta) { + + if (schematicSelected && selectedFace.getAxis().isHorizontal()) { + blueprint.moveTo(delta < 0 ? blueprint.anchor.add(selectedFace.getDirectionVec()) + : blueprint.anchor.subtract(selectedFace.getDirectionVec())); + return true; + } + + return super.handleMouseWheel(delta); + } + +} diff --git a/src/main/java/com/simibubi/create/schematic/SchematicMoveVerticalTool.java b/src/main/java/com/simibubi/create/schematic/SchematicMoveVerticalTool.java new file mode 100644 index 000000000..2d130df42 --- /dev/null +++ b/src/main/java/com/simibubi/create/schematic/SchematicMoveVerticalTool.java @@ -0,0 +1,16 @@ +package com.simibubi.create.schematic; + +public class SchematicMoveVerticalTool extends SchematicPlacementToolBase { + + @Override + public boolean handleMouseWheel(double delta) { + + if (blueprint.deployed) { + blueprint.moveTo(blueprint.anchor.add(0, delta, 0)); + return true; + } + + return super.handleMouseWheel(delta); + } + +} diff --git a/src/main/java/com/simibubi/create/schematic/SchematicPlacementToolBase.java b/src/main/java/com/simibubi/create/schematic/SchematicPlacementToolBase.java new file mode 100644 index 000000000..0d94227de --- /dev/null +++ b/src/main/java/com/simibubi/create/schematic/SchematicPlacementToolBase.java @@ -0,0 +1,35 @@ +package com.simibubi.create.schematic; + +public abstract class SchematicPlacementToolBase extends SchematicToolBase { + + @Override + public void init() { + super.init(); + } + + @Override + public void updateSelection() { + super.updateSelection(); + } + + @Override + public void renderTool() { + super.renderTool(); + } + + @Override + public void renderOverlay() { + super.renderOverlay(); + } + + @Override + public boolean handleMouseWheel(double delta) { + return false; + } + + @Override + public boolean handleRightClick() { + return false; + } + +} diff --git a/src/main/java/com/simibubi/create/schematic/SchematicRotateTool.java b/src/main/java/com/simibubi/create/schematic/SchematicRotateTool.java new file mode 100644 index 000000000..6f0f53cf3 --- /dev/null +++ b/src/main/java/com/simibubi/create/schematic/SchematicRotateTool.java @@ -0,0 +1,13 @@ +package com.simibubi.create.schematic; + +import net.minecraft.util.Rotation; + +public class SchematicRotateTool extends SchematicPlacementToolBase { + + @Override + public boolean handleMouseWheel(double delta) { + blueprint.rotate(delta > 0 ? Rotation.CLOCKWISE_90 : Rotation.COUNTERCLOCKWISE_90); + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/schematic/SchematicToolBase.java b/src/main/java/com/simibubi/create/schematic/SchematicToolBase.java new file mode 100644 index 000000000..74cbc5648 --- /dev/null +++ b/src/main/java/com/simibubi/create/schematic/SchematicToolBase.java @@ -0,0 +1,122 @@ +package com.simibubi.create.schematic; + +import com.mojang.blaze3d.platform.GlStateManager; +import com.simibubi.create.utility.RaycastHelper; +import com.simibubi.create.utility.RaycastHelper.PredicateTraceResult; + +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.util.Direction; +import net.minecraft.util.Hand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.util.math.MutableBoundingBox; +import net.minecraft.util.math.RayTraceResult.Type; +import net.minecraft.util.math.Vec3d; + +public abstract class SchematicToolBase implements ISchematicTool { + + protected BlueprintHandler blueprint; + + public BlockPos selectedPos; + public boolean selectIgnoreBlocks; + public int selectionRange; + + public boolean schematicSelected; + public boolean renderSelectedFace; + public Direction selectedFace; + + public SchematicToolBase() { + blueprint = BlueprintHandler.instance; + } + + @Override + public void init() { + selectedPos = null; + selectedFace = null; + schematicSelected = false; + } + + @Override + public void updateSelection() { + ClientPlayerEntity player = Minecraft.getInstance().player; + + // Select Blueprint + if (blueprint.deployed) { + PredicateTraceResult result = RaycastHelper.rayTraceUntil(player, 70, + pos -> new MutableBoundingBox(BlockPos.ZERO, blueprint.getTransformedSize()) + .isVecInside(pos.subtract(blueprint.anchor))); + schematicSelected = !result.missed(); + selectedFace = schematicSelected ? result.getFacing() : null; + } + + // Select location at distance + if (selectIgnoreBlocks) { + selectedPos = new BlockPos(player.getEyePosition(Minecraft.getInstance().getRenderPartialTicks()) + .add(player.getLookVec().scale(selectionRange))); + return; + } + + // Select targeted Block + 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; + } + } + + @Override + public void renderTool() { + + if (blueprint.deployed) { + GlStateManager.lineWidth(5); + GlStateManager.color4f(1, 1, 1, 1); + GlStateManager.disableTexture(); + + BlockPos min = blueprint.getTransformedAnchor(); + MutableBoundingBox bb = new MutableBoundingBox(min, min.add(blueprint.getTransformedSize())); + min = new BlockPos(bb.minX, bb.minY, bb.minZ); + BlockPos max = new BlockPos(bb.maxX, bb.maxY, bb.maxZ); + + WorldRenderer.drawBoundingBox(min.getX() - 1 / 8d, min.getY() + 1 / 16d, min.getZ() - 1 / 8d, + max.getX() + 1 / 8d, max.getY() + 1 / 8d, max.getZ() + 1 / 8d, .3f, .4f, 1, 1); + + if (schematicSelected && renderSelectedFace) { + Vec3d vec = new Vec3d(selectedFace.getDirectionVec()); + Vec3d center = new Vec3d(min.add(max)).scale(1 / 2f); + Vec3d radii = new Vec3d(max.subtract(min)).scale(1 / 2f); + + Vec3d onFaceOffset = new Vec3d(1 - Math.abs(vec.x), 1 - Math.abs(vec.y), 1 - Math.abs(vec.z)) + .mul(radii); + Vec3d faceMin = center.add(vec.mul(radii).add(onFaceOffset)); + Vec3d faceMax = center.add(vec.mul(radii).subtract(onFaceOffset)); + + GlStateManager.lineWidth(4); + WorldRenderer.drawBoundingBox(faceMin.getX(), faceMin.getY() + 1 / 16d, faceMin.getZ(), faceMax.getX(), + faceMax.getY() + 1 / 8d, faceMax.getZ(), 1, 1, 1, 1); + } + + GlStateManager.lineWidth(1); + GlStateManager.enableTexture(); + + } + + } + + @Override + public void renderOverlay() { + + } + +} diff --git a/src/main/java/com/simibubi/create/schematic/SchematicWorld.java b/src/main/java/com/simibubi/create/schematic/SchematicWorld.java index 2f08fdef4..be0b71e01 100644 --- a/src/main/java/com/simibubi/create/schematic/SchematicWorld.java +++ b/src/main/java/com/simibubi/create/schematic/SchematicWorld.java @@ -45,7 +45,7 @@ public class SchematicWorld implements IWorld { private Map blocks; private Cuboid bounds; - private BlockPos anchor; + public BlockPos anchor; public SchematicWorld(Map blocks, Cuboid bounds, BlockPos anchor) { this.blocks = blocks; diff --git a/src/main/java/com/simibubi/create/schematic/Tools.java b/src/main/java/com/simibubi/create/schematic/Tools.java new file mode 100644 index 000000000..a8c59530f --- /dev/null +++ b/src/main/java/com/simibubi/create/schematic/Tools.java @@ -0,0 +1,46 @@ +package com.simibubi.create.schematic; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import com.simibubi.create.gui.GuiResources; + +public enum Tools { + + Deploy(new SchematicDeployTool(), "Deploy", GuiResources.ICON_3x3), + + 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); + + private ISchematicTool tool; + private String displayName; + private GuiResources icon; + + private Tools(ISchematicTool tool, String name, GuiResources icon) { + this.tool = tool; + this.displayName = name; + this.icon = icon; + } + + public ISchematicTool getTool() { + return tool; + } + + public String getDisplayName() { + return displayName; + } + + public GuiResources getIcon() { + return icon; + } + + public static List getTools() { + List tools = new ArrayList<>(); + Collections.addAll(tools, Move, MoveY, Deploy, Rotate, Flip); + return tools; + } + +} diff --git a/src/main/java/com/simibubi/create/utility/RaycastHelper.java b/src/main/java/com/simibubi/create/utility/RaycastHelper.java new file mode 100644 index 000000000..a58b0591d --- /dev/null +++ b/src/main/java/com/simibubi/create/utility/RaycastHelper.java @@ -0,0 +1,195 @@ +package com.simibubi.create.utility; + +import java.util.function.Predicate; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.RayTraceContext; +import net.minecraft.util.math.RayTraceContext.BlockMode; +import net.minecraft.util.math.RayTraceContext.FluidMode; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +public class RaycastHelper { + + public static BlockRayTraceResult rayTraceRange(World worldIn, PlayerEntity playerIn, double range) { + Vec3d origin = getTraceOrigin(playerIn); + Vec3d target = getTraceTarget(playerIn, range, origin); + RayTraceContext context = new RayTraceContext(origin, target, BlockMode.COLLIDER, FluidMode.NONE, playerIn); + return worldIn.rayTraceBlocks(context); + } + + public static PredicateTraceResult rayTraceUntil(PlayerEntity playerIn, double range, Predicate predicate) { + Vec3d origin = getTraceOrigin(playerIn); + Vec3d target = getTraceTarget(playerIn, range, origin); + return rayTraceUntil(origin, target, predicate); + } + + private static Vec3d getTraceTarget(PlayerEntity playerIn, double range, Vec3d origin) { + float f = playerIn.rotationPitch; + float f1 = playerIn.rotationYaw; + float f2 = MathHelper.cos(-f1 * 0.017453292F - (float) Math.PI); + float f3 = MathHelper.sin(-f1 * 0.017453292F - (float) Math.PI); + float f4 = -MathHelper.cos(-f * 0.017453292F); + float f5 = MathHelper.sin(-f * 0.017453292F); + float f6 = f3 * f4; + float f7 = f2 * f4; + double d3 = range; + Vec3d vec3d1 = origin.add((double) f6 * d3, (double) f5 * d3, (double) f7 * d3); + return vec3d1; + } + + private static Vec3d getTraceOrigin(PlayerEntity playerIn) { + double d0 = playerIn.posX; + double d1 = playerIn.posY + (double) playerIn.getEyeHeight(); + double d2 = playerIn.posZ; + Vec3d vec3d = new Vec3d(d0, d1, d2); + return vec3d; + } + + private static PredicateTraceResult rayTraceUntil(Vec3d start, Vec3d end, Predicate predicate) { + if (Double.isNaN(start.x) || Double.isNaN(start.y) || Double.isNaN(start.z)) + return null; + if (Double.isNaN(end.x) || Double.isNaN(end.y) || Double.isNaN(end.z)) + return null; + + int dx = MathHelper.floor(end.x); + int dy = MathHelper.floor(end.y); + int dz = MathHelper.floor(end.z); + int x = MathHelper.floor(start.x); + int y = MathHelper.floor(start.y); + int z = MathHelper.floor(start.z); + + BlockPos currentPos = new BlockPos(x, y, z); + + if (predicate.test(currentPos)) + return new PredicateTraceResult(currentPos, Direction.getFacingFromVector(dx - x, dy - y, dz - z)); + + int remainingDistance = 200; + + while (remainingDistance-- >= 0) { + if (Double.isNaN(start.x) || Double.isNaN(start.y) || Double.isNaN(start.z)) { + return null; + } + + if (x == dx && y == dy && z == dz) { + return new PredicateTraceResult(); + } + + boolean flag2 = true; + boolean flag = true; + boolean flag1 = true; + double d0 = 999.0D; + double d1 = 999.0D; + double d2 = 999.0D; + + if (dx > x) { + d0 = (double) x + 1.0D; + } else if (dx < x) { + d0 = (double) x + 0.0D; + } else { + flag2 = false; + } + + if (dy > y) { + d1 = (double) y + 1.0D; + } else if (dy < y) { + d1 = (double) y + 0.0D; + } else { + flag = false; + } + + if (dz > z) { + d2 = (double) z + 1.0D; + } else if (dz < z) { + d2 = (double) z + 0.0D; + } else { + flag1 = false; + } + + double d3 = 999.0D; + double d4 = 999.0D; + double d5 = 999.0D; + double d6 = end.x - start.x; + double d7 = end.y - start.y; + double d8 = end.z - start.z; + + if (flag2) { + d3 = (d0 - start.x) / d6; + } + + if (flag) { + d4 = (d1 - start.y) / d7; + } + + if (flag1) { + d5 = (d2 - start.z) / d8; + } + + if (d3 == -0.0D) { + d3 = -1.0E-4D; + } + + if (d4 == -0.0D) { + d4 = -1.0E-4D; + } + + if (d5 == -0.0D) { + d5 = -1.0E-4D; + } + + Direction enumfacing; + + if (d3 < d4 && d3 < d5) { + enumfacing = dx > x ? Direction.WEST : Direction.EAST; + start = new Vec3d(d0, start.y + d7 * d3, start.z + d8 * d3); + } else if (d4 < d5) { + enumfacing = dy > y ? Direction.DOWN : Direction.UP; + start = new Vec3d(start.x + d6 * d4, d1, start.z + d8 * d4); + } else { + enumfacing = dz > z ? Direction.NORTH : Direction.SOUTH; + start = new Vec3d(start.x + d6 * d5, start.y + d7 * d5, d2); + } + + x = MathHelper.floor(start.x) - (enumfacing == Direction.EAST ? 1 : 0); + y = MathHelper.floor(start.y) - (enumfacing == Direction.UP ? 1 : 0); + z = MathHelper.floor(start.z) - (enumfacing == Direction.SOUTH ? 1 : 0); + currentPos = new BlockPos(x, y, z); + + if (predicate.test(currentPos)) + return new PredicateTraceResult(currentPos, enumfacing); + } + + return new PredicateTraceResult(); + } + + public static class PredicateTraceResult { + private BlockPos pos; + private Direction facing; + + public PredicateTraceResult(BlockPos pos, Direction facing) { + this.pos = pos; + this.facing = facing; + } + + public PredicateTraceResult() { + // missed, no result + } + + public Direction getFacing() { + return facing; + } + + public BlockPos getPos() { + return pos; + } + + public boolean missed() { + return this.pos == null; + } + } + +} diff --git a/src/main/java/com/simibubi/create/utility/TessellatorTextures.java b/src/main/java/com/simibubi/create/utility/TessellatorTextures.java new file mode 100644 index 000000000..e7a431a91 --- /dev/null +++ b/src/main/java/com/simibubi/create/utility/TessellatorTextures.java @@ -0,0 +1,29 @@ +package com.simibubi.create.utility; + +import com.simibubi.create.Create; + +import net.minecraft.client.Minecraft; +import net.minecraft.util.ResourceLocation; + +public enum TessellatorTextures { + + Room("inner.png"), + RoomTransparent("inner_transparent.png"), + SelectedRoom("inner_selected.png"), + SuperSelectedRoom("inner_super_selected.png"), + Selection("select.png"), + Exporter("exporter.png"), + Trim("trim.png"); + + private ResourceLocation location; + + private TessellatorTextures(String filename) { + location = new ResourceLocation(Create.ID, + "textures/block/marker/" + filename); + } + + public void bind() { + Minecraft.getInstance().getTextureManager().bindTexture(location); + } + +} \ 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 92c0fbb5e..eeb8ac86b 100644 --- a/src/main/resources/assets/create/lang/en_us.json +++ b/src/main/resources/assets/create/lang/en_us.json @@ -1,8 +1,9 @@ { "item.create.symmetry_wand": "Staff of Symmetry", - "item.create.empty_blueprint": "Empty Blueprint", - "item.create.blueprint": "Blueprint", + "item.create.empty_blueprint": "Empty Schematic", + "item.create.blueprint": "Schematic", "block.create.schematicannon": "SchematiCannon 9000", - "block.create.schematic_table": "Schematic Planner", + "block.create.schematic_table": "Schematic Table", + "block.create.creative_crate": "SchematiCannon Creatifier", "itemGroup.create": "Create" } diff --git a/src/main/resources/assets/create/textures/gui/widgets.png b/src/main/resources/assets/create/textures/gui/widgets.png index 0c7695db7fbf460ec1cd63f9ad92eb236c768376..1c4f897f6c53dfd82de096e71e8bab35ff3977b7 100644 GIT binary patch literal 4492 zcmeHLYdDnY8-L!}CSl9wa@b8Fk)%wmHY0J2HOpGitS~`09Y+&W4Zg_X^)BAguBCj z?rrqfeZdtGMQVfVdwxnv?y-J)(t9raxsugei!S9$UTZbar*+)Evv23@*)wY#f9-mV zo>LxHG(7Khf&2(_4$)~BpyQi4c-0{DTKV`1_TPtb1J^as^m>+iGllNTrBK9i1*{>~ zm;Fo=@enf>kMHkq#nowRURKL zRL%L^(}5NGSjm*gC=-7yh~%;KtLfI=M`B&r`#d zjv%St0<{y?m{oB*v~l`fbKLX=bABLqCPfrtYlHUSktYI%j@1I~QpFf2 z;QdjK^7>K%&ZFVplo<$vF=a~?sh z4u&Xq*I9K?cX11`-iH22092x;b!d_A6mjyH@XhH)$S%W0fy7f=fNWE5ZW$|`hP{k- zJ{0NuAr_3z%cYak1xbiHc1cc9S^ZSI{zO;d9^DT~y7^V_+EPUYoleud9tTFXcN^!^ zn@3Snu>i$DKa;qbt)BPf_&RwE0;R)FBJpx|2Cwm*{@7Vd5JfR4u@Be%9!9&OZgzrh zF1jl<&eKtTl)k|#XoO0r4eU2y)CM!g-c2@)SK#El){_eU{uZ$J2er6eh}ZXgQ_Mcm zeyEM+dYGL4G&&YKW8h%+rFTr+L+8G(_U1{pD$^L~DO4pEQA%!p=A;rkov`9pIF!$$ zp`hW0S5cEg#zHl7JCSyiHCB@lla_ppo^Muk%Q~g77;$lht?K+KD%q@wDcCe07;@!E z22D@EjIAv9Y>wyEURE<2?C9w5|5!@aD1BI5faPW|oi(hW+<32su+`%(pn3W!t)c!y zbp)sH5sMLQj&I+9L{(RpHmCdyLrZ#kxzzZp>t>7PC%Oaa>J$h3NTq@dKmAaV zo85UOb!9NO^g@*XbXUIc z#&e2v^ZmA?GrDun``RjvVtI%7%?c|go=xmAnJF%unC<1X5qJ(b`BCm+X@X?7ZF%h* z-R1lz1?yh(@8tW9oc?kyYE*~~9;s1fR5<7Rxp|sb(WM<6(a?0!eU1D4T%jDenSynp zBMv}wt*Qlnp(70~OmU6;ghG^O(8GzwUS>jAO?m9xUjCW3!;A?Ls>ZGP%CuqB z+Sj@srd4zakB0NuS+%Y|H&B6sD>lQ6efgdJ9zG@&=6*areXf@_Df&DhC-B^&z7*K9o_Q(?~7DIKCoCUpH$-fEy=%XTefEPGs_9oBwX zkn0;dH)G5%aj2+zIFvvgZu%_4$@BbF&$U6@hhouLOkGN)xq%KroWIQ8HKDD`TwGX4 zkW`-EIW5@3$Upp-aNyr1kwv1$J0MDjsK>pyp2k(DvVP>CP-?G78b+gI^~nF0w1O}b zOH4<&1zM$=9Bl#`Cctv(tJi}Ch}6S*SCVbqSX|e2)hVe-ZxMYqu!N?O4{8U%yq;F#f9Yj{mZ0Q{KJE8w|Ntknt;Od~9CSg?rX&+hzMdVpH*466{cf%f$ zGWQEjEk~3<^s8vtI3h1LE0 z)36p&OQ#w83hX~@@k`cvVF{?aLoI?=kVhKdbKb!+o7l+Wun0l+pxjOUh2}SOh)F1} zMOYV{tsr-&K9Sd?q`_Kj7F25&lgt&mjgU0=FY91uG{sCEKMhz0V}sgsE~k+WD|d$p zDF-oHF*T_VAAxXfq|W8|yCqt;SBtM&!!5}#IcJPBQy z&@uJ|+Tt{n5d>Mo1I*;ETAx|E&nDmxWmR2)bALU1qwGNR!u!{*@9=vG3c7X#G3<#k z&SUkqUGi8<`}K+Vwl@^nEPHxaOH@X_i$i<^y*O2k@;lKtIhM3&weDIcD7Q?ptF2%% zV$9nLwaP2|tzusdco8XUix*kk@{HxZ1=sYxHN>!>5GWGsMY`ENZ}!p0cvXxq@zY_q+ldD}ph6RL?Us7rZ0j0Yw1ckA^I8@s zLfCY83Iyffg}#U2dlq~zgzsGNA9VQH64L$!3;zaSBLRkf8+7bjwZGNF8+TUv!`P8K Wt!Isd3h#Mo}|Oh`?sj%rZ4i zQ$s1z@syIKs42y0W_H80(!5qqUh;w|V1nS;=y=wwv(CSB&cA-JHhb^qy*=Oiz0bFH z;vP3AUF0ex06>>SbZ`d%2K|MBuNFZUa^!D;&}CuJcGv9ylwQ!8_D4YX+Tld6qW~-x zYJM;$WlAyha7C1(XOssmFe=7BG6018hlE90h6O}nHd%gWX?@;U6$HRiJjr4E-s65F zxvZyM0kIF4z!5uFdWNG+eJ)wF=o+5idg`qe(WW6Swf^+S_m`f!`kvE%i0;B}RD(`b zbHJ+QGj04sDJu@;6y}rJf z#dXRPxW@WHl{~kl#b$~uM85dFTgV9IdX*o3^^z~nmf|vfqu-pmLzf+1or^uvTB7>6 z$Ue7txfxIn_LLp;ZQP@`!WIX=9-mJ+A|=c!4kxURdZyBtMn<6+YlK-3gR# z0oGi2`0$;XqpVaOB?q2`m6@*;>WW-kP$C9Rkv`Sc(K}S4Vj?l$ZIIraeN*|Xse!06 zch?`Tuya}Z^w;OQ7g5)dcc4Uvnw5J%6Wr2Y0Q5<#Vm-jxb*DL-uT{XZv<*`c8!t<7 z`k;*MoMizTiyXT3MQ2Fdpl1W2Ah6ct5X@zra0vofywwZTA*AwBZ4es|xDR+)Lls>P zU*-iak|g#pf==bHZ{R8aeP}?~POkj{#a`$a?AEFzzCHc0MCR@ecGmR+>gMf zGyE5eO_`LFRYu#6kMX{?qrXf><2h=I6DQS_bG$a$$Tl!xvC(biX!Vi^t~U9>tTSTs zYLmfMKBXt1E?!p<@C4OSb+mA#qe7hg_0|Ks?PM>Bu|sFyjlHWA1c}#llpah7?XIa} zbos_~Il>6b=W8?a2CHqt%8Gp|+DE&pLub^guDr3{ZSuB*T@x*0T8E&RfrFTOr)SxX zxE0c}uHzn)F==`tTTVKjdWoPI+Wu|4Z*}xB$5hmUS=bz*lZo&Yk&dfE$%*Hs72(C8(T(8W8e#T~CGuOe=xyl9?Kn407m$u6dw-A7|Kpz9X}} z`aZox^&;N7y45#k@&xR}2xsbNWh-|?-PyD_Y(@J)N=((HpMSLIG+xmWc;V(o#^+=5 zUafffz$Na;Ob>TNF+4qllVwgI#&$npWwVs^amA`vam*>3MS>4!4cjXGSocPJB1%W9 z`gU|g$hHawUoB9+H|xtgDz}z}N|qhF~mdt)vK%qIO`l&RjWY6XtW6b#Dk; zEvwFKqZpC9E!brX!xYc|t`w>8MrL5wwKE*{3S0;oeLL#eBMr6YXb=ERw%@+Wsq zZpj{7ht`>C$thMjR%cmN>2P+xmgNB>9gIq4r=1(AvI}bSQLD@uLoD-Be2s+6XtZJe}7wW|ZA@XU9 zzA1LZN)t8xfcaILq#2ctX*;`n5h(*WhsPi9_YfXk-K|G;KZT1}cEby3BiWlW+L2VU zo5^?qAhr}01LGjd1$_|mL%9JV&3$%`60+Sw5g3w^&YMF#{IC~GgAA{ZSIuo*i7B3}a-A2ovt zSFAbbyh`O+1Ddr+@A^2=PK5$E(f!*&%kU`Hc5u|JABtwD%v!S!IWpn@{hP2CsiM|T4SN(A|HHFamIc`moAv+DX z2WbKunyq*DUAU`ml{hhEm}eS17p^nI4HX8$ff^ zVKdP9rnUF8#21g@eUP4=ZvayRKuEetuDYG%FtFUPl!L(Z_4R!fvTpOd5U2Fj!B?08 zruA1L7JA&>^Geo7f$K#^((4^>9)x{HtG%RL_X3q^`Xk z916=)APShOy*o5QyH;iam|3SE^IeovK{^^`K6z+XnPc_=1*XvXWa74wSg}45c#DjR zf?xyoxnWZoA!63ufz4eB3p{z1rgKVdH`;dU1O5sZM?@EHTGqqFe&y|+Bs6(u^Z?XrB+51NBWlBWdz zn>k2Y{4W+t!7h(+R)KbtmZiT?hv1^b|2VK#ADBna^H~4@@;&yo5E%P6MxmEdm%Y~< zS0cYnwVBadnvb#cH_~|K9SYW;NqPj<On0 zQ?_VG02zLxL-k${f?=9e&KjSGnt^?)@{Bn=uWj>)i$gr{Qc=`2W=DKIlA* zS^96$0ej#4WSdRh`4Joh8+-wMq2NmweAx(JX2E|Lho(qOqbGK-)eQ{*eJ6tYdh7a? fjPsXuPr^HmA7?+`bS)J6+yF?9ZVn|osHgr3KyN%-