diff --git a/src/main/java/gregtech/api/block/machines/BlockMachine.java b/src/main/java/gregtech/api/block/machines/BlockMachine.java index 419d3754d50..876d9eae530 100755 --- a/src/main/java/gregtech/api/block/machines/BlockMachine.java +++ b/src/main/java/gregtech/api/block/machines/BlockMachine.java @@ -84,7 +84,6 @@ public BlockMachine() { setHardness(6.0f); setResistance(6.0f); setTranslationKey("unnamed"); - setHarvestLevel("wrench", 1); setDefaultState(getDefaultState().withProperty(OPAQUE, true)); } diff --git a/src/main/java/gregtech/api/cover/ICoverable.java b/src/main/java/gregtech/api/cover/ICoverable.java index 061223ca08f..0157a00c632 100644 --- a/src/main/java/gregtech/api/cover/ICoverable.java +++ b/src/main/java/gregtech/api/cover/ICoverable.java @@ -198,4 +198,8 @@ static Cuboid6 getCoverPlateBox(EnumFacing side, double plateThickness) { throw new UnsupportedOperationException(); } } + + public default boolean canRenderMachineGrid() { + return true; + } } diff --git a/src/main/java/gregtech/api/gui/GuiTextures.java b/src/main/java/gregtech/api/gui/GuiTextures.java index 207062eb83f..0f54787ef42 100644 --- a/src/main/java/gregtech/api/gui/GuiTextures.java +++ b/src/main/java/gregtech/api/gui/GuiTextures.java @@ -15,6 +15,7 @@ public class GuiTextures { public static final TextureArea BORDERED_BACKGROUND = AdoptableTextureArea.fullImage("textures/gui/base/bordered_background.png", 195, 136, 4, 4); public static final TextureArea BOXED_BACKGROUND = AdoptableTextureArea.fullImage("textures/gui/base/boxed_background.png", 256, 174, 11, 11); + public static final TextureArea BLANK = AdoptableTextureArea.fullImage("textures/gui/base/blank.png", 1, 1, 0, 0); public static final TextureArea DISPLAY = TextureArea.fullImage("textures/gui/base/display.png"); public static final TextureArea FLUID_SLOT = AdoptableTextureArea.fullImage("textures/gui/base/fluid_slot.png", 18, 18, 1, 1); public static final TextureArea FLUID_TANK_BACKGROUND = TextureArea.fullImage("textures/gui/base/fluid_tank_background.png"); @@ -22,6 +23,7 @@ public class GuiTextures { public static final TextureArea SLOT = AdoptableTextureArea.fullImage("textures/gui/base/slot.png", 18, 18, 1, 1); public static final TextureArea SLOT_DARKENED = TextureArea.fullImage("textures/gui/base/darkened_slot.png"); + //FLUID & ITEM OUTPUT BUTTONS public static final TextureArea BLOCKS_INPUT = TextureArea.fullImage("textures/gui/widget/button_blocks_input.png"); public static final TextureArea BUTTON = TextureArea.fullImage("textures/gui/widget/button.png"); @@ -32,8 +34,12 @@ public class GuiTextures { public static final TextureArea BUTTON_FILTER_NBT = TextureArea.fullImage("textures/gui/widget/button_filter_nbt.png"); public static final TextureArea BUTTON_FLUID_OUTPUT = TextureArea.fullImage("textures/gui/widget/button_fluid_output.png"); public static final TextureArea BUTTON_ITEM_OUTPUT = TextureArea.fullImage("textures/gui/widget/button_item_output.png"); + public static final TextureArea BUTTON_LEFT = TextureArea.fullImage("textures/gui/widget/left.png"); public static final TextureArea BUTTON_OVERCLOCK = TextureArea.fullImage("textures/gui/widget/button_overclock.png"); + public static final TextureArea BUTTON_RIGHT = TextureArea.fullImage("textures/gui/widget/right.png"); public static final TextureArea BUTTON_SWITCH_VIEW = TextureArea.fullImage("textures/gui/widget/button_switch_view.png"); + public static final TextureArea CLIPBOARD_BUTTON = TextureArea.fullImage("textures/gui/widget/clipboard_button.png"); + public static final SizedTextureArea CLIPBOARD_TEXT_BOX = AdoptableTextureArea.fullImage("textures/gui/widget/clipboard_text_box.png", 9, 18, 1, 1); public static final TextureArea DISTRIBUTION_MODE = TextureArea.fullImage("textures/gui/widget/button_distribution_mode.png"); public static final TextureArea LOCK = TextureArea.fullImage("textures/gui/widget/lock.png"); public static final TextureArea SWITCH = TextureArea.fullImage("textures/gui/widget/switch.png"); diff --git a/src/main/java/gregtech/api/gui/Widget.java b/src/main/java/gregtech/api/gui/Widget.java index efdc9688432..81d52b17ba0 100644 --- a/src/main/java/gregtech/api/gui/Widget.java +++ b/src/main/java/gregtech/api/gui/Widget.java @@ -275,7 +275,7 @@ protected void writeClientAction(int id, Consumer packetBufferWrit } @SideOnly(Side.CLIENT) - protected void drawBorder(int x, int y, int width, int height, int stroke, int stroke_width) { + public void drawBorder(int x, int y, int width, int height, int stroke, int stroke_width) { drawGradientRect(x - stroke_width, y - stroke_width, width + 2 * stroke_width, stroke_width, stroke, stroke); drawGradientRect(x - stroke_width, y + height, width + 2 * stroke_width, stroke_width, stroke, stroke); drawGradientRect(x - stroke_width, y - stroke_width, stroke_width, height + 2 * stroke_width, stroke, stroke); @@ -283,7 +283,7 @@ protected void drawBorder(int x, int y, int width, int height, int stroke, int s } @SideOnly(Side.CLIENT) - protected void drawHoveringText(ItemStack itemStack, List tooltip, int maxTextWidth, int mouseX, int mouseY) { + public void drawHoveringText(ItemStack itemStack, List tooltip, int maxTextWidth, int mouseX, int mouseY) { Minecraft mc = Minecraft.getMinecraft(); GuiUtils.drawHoveringText(itemStack, tooltip, mouseX, mouseY, sizes.getScreenWidth(), @@ -291,7 +291,7 @@ protected void drawHoveringText(ItemStack itemStack, List tooltip, int m } @SideOnly(Side.CLIENT) - protected void drawStringSized(String text, double x, double y, int color, boolean dropShadow, float scale, boolean center) { + public void drawStringSized(String text, double x, double y, int color, boolean dropShadow, float scale, boolean center) { GlStateManager.pushMatrix(); FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; double scaledTextWidth = center ? fontRenderer.getStringWidth(text) * scale : 0.0; @@ -302,7 +302,7 @@ protected void drawStringSized(String text, double x, double y, int color, boole } @SideOnly(Side.CLIENT) - protected void drawStringFixedCorner(String text, double x, double y, int color, boolean dropShadow, float scale) { + public void drawStringFixedCorner(String text, double x, double y, int color, boolean dropShadow, float scale) { FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; double scaledWidth = fontRenderer.getStringWidth(text) * scale; double scaledHeight = fontRenderer.FONT_HEIGHT * scale; @@ -310,7 +310,7 @@ protected void drawStringFixedCorner(String text, double x, double y, int color, } @SideOnly(Side.CLIENT) - protected static void drawItemStack(ItemStack itemStack, int x, int y, @Nullable String altTxt) { + public static void drawItemStack(ItemStack itemStack, int x, int y, @Nullable String altTxt) { GlStateManager.pushMatrix(); GlStateManager.translate(0.0F, 0.0F, 32.0F); GlStateManager.color(1F, 1F, 1F, 1F); @@ -331,7 +331,7 @@ protected static void drawItemStack(ItemStack itemStack, int x, int y, @Nullable } @SideOnly(Side.CLIENT) - protected static List getItemToolTip(ItemStack itemStack) { + public static List getItemToolTip(ItemStack itemStack) { Minecraft mc = Minecraft.getMinecraft(); ITooltipFlag flag = mc.gameSettings.advancedItemTooltips ? ITooltipFlag.TooltipFlags.ADVANCED : ITooltipFlag.TooltipFlags.NORMAL; List tooltip = itemStack.getTooltip(mc.player, flag); @@ -346,7 +346,7 @@ protected static List getItemToolTip(ItemStack itemStack) { } @SideOnly(Side.CLIENT) - protected static void drawSelectionOverlay(int x, int y, int width, int height) { + public static void drawSelectionOverlay(int x, int y, int width, int height) { GlStateManager.disableDepth(); GlStateManager.colorMask(true, true, true, false); drawGradientRect(x, y, width, height, -2130706433, -2130706433); @@ -356,14 +356,14 @@ protected static void drawSelectionOverlay(int x, int y, int width, int height) } @SideOnly(Side.CLIENT) - protected static void drawSolidRect(int x, int y, int width, int height, int color) { + public static void drawSolidRect(int x, int y, int width, int height, int color) { Gui.drawRect(x, y, x + width, y + height, color); GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f); GlStateManager.enableBlend(); } @SideOnly(Side.CLIENT) - protected static void drawGradientRect(int x, int y, int width, int height, int startColor, int endColor) { + public static void drawGradientRect(int x, int y, int width, int height, int startColor, int endColor) { drawGradientRect(x, y, width, height, startColor, endColor, false); } diff --git a/src/main/java/gregtech/api/gui/impl/FakeModularGui.java b/src/main/java/gregtech/api/gui/impl/FakeModularGui.java new file mode 100644 index 00000000000..5698981d9b0 --- /dev/null +++ b/src/main/java/gregtech/api/gui/impl/FakeModularGui.java @@ -0,0 +1,123 @@ +package gregtech.api.gui.impl; + +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.ModularUI; +import gregtech.api.gui.Widget; +import gregtech.api.util.RenderUtil; +import gregtech.common.gui.impl.FakeModularUIContainerClipboard; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.util.ITooltipFlag; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.text.TextFormatting; +import net.minecraftforge.fml.client.config.GuiUtils; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +import java.util.List; +import java.util.Optional; + +import static gregtech.api.gui.impl.ModularUIGui.*; + +@SideOnly(Side.CLIENT) +public class FakeModularGui implements IRenderContext { + public final ModularUI modularUI; + public FakeModularUIContainerClipboard container; + protected Minecraft mc; + protected FontRenderer fr; + + public FakeModularGui(ModularUI modularUI, FakeModularUIContainerClipboard fakeModularUIContainer){ + this.modularUI = modularUI; + this.container = fakeModularUIContainer; + this.modularUI.updateScreenSize(this.modularUI.getWidth(), this.modularUI.getHeight()); + this.mc = Minecraft.getMinecraft(); + this.fr = mc.fontRenderer; + } + + public void updateScreen() { + modularUI.guiWidgets.values().forEach(Widget::updateScreen); + } + + public void handleWidgetUpdate(int windowId, int widgetId, PacketBuffer updateData) { + if (windowId == container.windowId) { + Widget widget = modularUI.guiWidgets.get(Optional.of(widgetId)); + int updateId = updateData.readVarInt(); + if (widget != null) { + widget.readUpdateInfo(updateId, updateData); + } + } + } + + public void drawScreen(double x, double y, float partialTicks) { + float halfW = modularUI.getWidth() / 2f; + float halfH = modularUI.getHeight() / 2f; + float scale = 0.5f / Math.max(halfW, halfH); + int mouseX = (int) ((x / scale) + (halfW > halfH? 0: (halfW - halfH))); + int mouseY = (int) ((y / scale) + (halfH > halfW? 0: (halfH - halfW))); + + GlStateManager.translate(-scale * halfW, -scale * halfH, 0.01); + GlStateManager.scale(scale, scale, 1); + GlStateManager.depthMask(false); + + drawGuiContainerBackgroundLayer(partialTicks, mouseX, mouseY); + + GlStateManager.scale(1, 1, 0); + drawGuiContainerForegroundLayer(mouseX, mouseY); + + for (int i = 0; i < this.container.inventorySlots.size(); ++i) { + Slot slot = this.container.inventorySlots.get(i); + if (!slot.getStack().isEmpty() && slot.xPos < mouseX && mouseX < slot.xPos + 18 && slot.yPos < mouseY && mouseY < slot.yPos + 18) { + Widget.drawSolidRect(slot.xPos, slot.yPos, 18, 18, 0X8fffffff); + renderToolTip(slot.getStack(), slot.xPos, slot.yPos); + } + } + + GlStateManager.depthMask(true); + GlStateManager.color(1.0f, 1.0f, 1.0f); + GlStateManager.disableLighting(); + } + + protected void renderToolTip(ItemStack stack, int x, int y) { + FontRenderer font = stack.getItem().getFontRenderer(stack); + GuiUtils.preItemToolTip(stack); + GuiUtils.drawHoveringText(this.getItemToolTip(stack), x, y, modularUI.getScreenWidth(), modularUI.getScreenHeight(), -1, (font == null ? fr : font)); + net.minecraftforge.fml.client.config.GuiUtils.postItemToolTip(); + } + + protected List getItemToolTip(ItemStack itemStack) { + List list = itemStack.getTooltip(mc.player, mc.gameSettings.advancedItemTooltips ? ITooltipFlag.TooltipFlags.ADVANCED : ITooltipFlag.TooltipFlags.NORMAL); + list.set(0, itemStack.getItem().getForgeRarity(itemStack).getColor() + list.get(0)); + for (int i = 1; i < list.size(); ++i) { + list.set(i, TextFormatting.GRAY + list.get(i)); + } + return list; + } + + public void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY) { + GlStateManager.color(rColorForOverlay, gColorForOverlay, bColorForOverlay, 1.0F); + modularUI.backgroundPath.draw(0, 0, modularUI.getWidth(), modularUI.getHeight()); + for (Widget widget : modularUI.guiWidgets.values()) { + GlStateManager.pushMatrix(); + GlStateManager.color(1.0f, 1.0f, 1.0f); + GlStateManager.enableBlend(); + widget.drawInBackground(mouseX, mouseY, this); + GlStateManager.popMatrix(); + } + } + + public void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { + for (Widget widget : modularUI.guiWidgets.values()) { + GlStateManager.pushMatrix(); + GlStateManager.color(1.0f, 1.0f, 1.0f); + widget.drawInForeground(mouseX, mouseY); + GlStateManager.popMatrix(); + } + } + + public boolean mouseClicked(int mouseX, int mouseY, int mouseButton) { + return modularUI.guiWidgets.values().stream().anyMatch(widget -> widget.mouseClicked(mouseX, mouseY, mouseButton)); + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/ImageCycleButtonWidget.java b/src/main/java/gregtech/api/gui/widgets/ImageCycleButtonWidget.java new file mode 100644 index 00000000000..3af8493ca4a --- /dev/null +++ b/src/main/java/gregtech/api/gui/widgets/ImageCycleButtonWidget.java @@ -0,0 +1,149 @@ +package gregtech.api.gui.widgets; + +import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.SizedTextureArea; +import gregtech.api.gui.resources.TextureArea; +import gregtech.api.util.GTUtility; +import gregtech.api.util.Position; +import gregtech.api.util.Size; +import gregtech.api.util.function.BooleanConsumer; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.resources.I18n; +import net.minecraft.item.ItemStack; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.IStringSerializable; +import net.minecraft.util.math.MathHelper; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +import java.util.Arrays; +import java.util.List; +import java.util.function.*; + +public class ImageCycleButtonWidget extends Widget { + + protected TextureArea buttonTexture; + private int textColor = 0xFFFFFF; + private IntSupplier currentOptionSupplier; + private IntConsumer setOptionExecutor; + private int optionCount; + private final int RIGHT_MOUSE = 1; + protected int currentOption; + protected String tooltipHoverString; + protected long hoverStartTime = -1L; + protected boolean isMouseHovered; + + public ImageCycleButtonWidget(int xPosition, int yPosition, int width, int height, TextureArea buttonTexture, int optionCount, IntSupplier currentOptionSupplier, IntConsumer setOptionExecutor) { + super(new Position(xPosition, yPosition), new Size(width, height)); + this.buttonTexture = buttonTexture; + this.currentOptionSupplier = currentOptionSupplier; + this.setOptionExecutor = setOptionExecutor; + this.optionCount = optionCount; + } + + + public ImageCycleButtonWidget(int xPosition, int yPosition, int width, int height, TextureArea buttonTexture, int optionCount, BooleanSupplier supplier, BooleanConsumer updater) { + super(new Position(xPosition, yPosition), new Size(width, height)); + this.buttonTexture = buttonTexture; + this.currentOptionSupplier = () -> supplier.getAsBoolean() ? 1 : 0; + this.setOptionExecutor = (value) -> updater.apply(value >= 1); + this.optionCount = optionCount; + } + + public ImageCycleButtonWidget setTooltipHoverString(String hoverString) { + this.tooltipHoverString = hoverString; + return this; + } + + public ImageCycleButtonWidget setButtonTexture(TextureArea texture) { + this.buttonTexture = texture; + return this; + } + + public ImageCycleButtonWidget setTextColor(int textColor) { + this.textColor = textColor; + return this; + } + + @Override + @SideOnly(Side.CLIENT) + public void drawInBackground(int mouseX, int mouseY, IRenderContext context) { + Position pos = getPosition(); + Size size = getSize(); + if (buttonTexture instanceof SizedTextureArea) { + ((SizedTextureArea) buttonTexture).drawHorizontalCutSubArea(pos.x, pos.y, size.width, size.height, (float)currentOption / optionCount, (float)1 / optionCount); + } else { + buttonTexture.drawSubArea(pos.x, pos.y, size.width, size.height, 0.0, (float)currentOption / optionCount, 1.0, (float)1 / optionCount); + } + } + + @Override + public void drawInForeground(int mouseX, int mouseY) { + boolean isHovered = isMouseOverElement(mouseX, mouseY); + boolean wasHovered = isMouseHovered; + if (isHovered && !wasHovered) { + this.isMouseHovered = true; + this.hoverStartTime = System.currentTimeMillis(); + } else if (!isHovered && wasHovered) { + this.isMouseHovered = false; + this.hoverStartTime = 0L; + } else if (isHovered) { + long timeSinceHover = System.currentTimeMillis() - hoverStartTime; + if (timeSinceHover > 1000L && tooltipHoverString != null) { + List hoverList = Arrays.asList(I18n.format(tooltipHoverString).split("/n")); + drawHoveringText(ItemStack.EMPTY, hoverList, 300, mouseX, mouseY); + } + } + } + + @Override + public void detectAndSendChanges() { + super.detectAndSendChanges(); + if (currentOptionSupplier.getAsInt() != currentOption) { + this.currentOption = currentOptionSupplier.getAsInt(); + writeUpdateInfo(1, buf -> buf.writeVarInt(currentOption)); + } + } + + @Override + public void readUpdateInfo(int id, PacketBuffer buffer) { + super.readUpdateInfo(id, buffer); + if (id == 1) { + this.currentOption = buffer.readVarInt(); + } + } + + @Override + @SideOnly(Side.CLIENT) + public boolean mouseClicked(int mouseX, int mouseY, int button) { + super.mouseClicked(mouseX, mouseY, button); + if (isMouseOverElement(mouseX, mouseY)) { + //Allow only the RMB to reverse cycle + if(button == RIGHT_MOUSE) { + //Wrap from the first option to the last if needed + this.currentOption = currentOption == 0 ? optionCount - 1 : currentOption - 1; + } else { + this.currentOption = (currentOption + 1) % optionCount; + } + writeClientAction(1, buf -> buf.writeVarInt(currentOption)); + playButtonClickSound(); + return true; + } + return false; + } + + + @Override + public void handleClientAction(int id, PacketBuffer buffer) { + super.handleClientAction(id, buffer); + if (id == 1) { + this.currentOption = MathHelper.clamp(buffer.readVarInt(), 0, optionCount); + setOptionExecutor.accept(currentOption); + } + } + +} diff --git a/src/main/java/gregtech/api/gui/widgets/ImageTextFieldWidget.java b/src/main/java/gregtech/api/gui/widgets/ImageTextFieldWidget.java new file mode 100644 index 00000000000..b042e450846 --- /dev/null +++ b/src/main/java/gregtech/api/gui/widgets/ImageTextFieldWidget.java @@ -0,0 +1,33 @@ +package gregtech.api.gui.widgets; + +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.resources.SizedTextureArea; + +import java.util.function.Consumer; +import java.util.function.Supplier; + +public class ImageTextFieldWidget extends TextFieldWidget { + SizedTextureArea textureArea; + + public ImageTextFieldWidget(int xPosition, int yPosition, int width, int height, SizedTextureArea textureArea, Supplier textSupplier, Consumer textResponder) { + super(xPosition, yPosition, width, height, false, textSupplier, textResponder); + this.textureArea = textureArea; + } + + public ImageTextFieldWidget(int xPosition, int yPosition, int width, int height, SizedTextureArea textureArea, Supplier textSupplier, Consumer textResponder, int maxStringLength) { + super(xPosition, yPosition, width, height, false, textSupplier, textResponder, maxStringLength); + this.textureArea = textureArea; + } + + public ImageTextFieldWidget(int xPosition, int yPosition, int width, int height, SizedTextureArea textureArea, Supplier textSupplier, Consumer textResponder, int maxStringLength, int color) { + this(xPosition, yPosition, width, height, textureArea, textSupplier, textResponder, maxStringLength); + this.textField.setTextColor(color); + } + + + @Override + public void drawInBackground(int mouseX, int mouseY, IRenderContext context) { + this.textureArea.drawHorizontalCutArea(this.getPosition().x - 2, this.getPosition().y, this.getSize().width, this.getSize().height); + super.drawInBackground(mouseX, mouseY, context); + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/SimpleTextWidget.java b/src/main/java/gregtech/api/gui/widgets/SimpleTextWidget.java index 9135d98dde0..5bca44fa6e2 100644 --- a/src/main/java/gregtech/api/gui/widgets/SimpleTextWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/SimpleTextWidget.java @@ -24,14 +24,12 @@ public class SimpleTextWidget extends Widget { protected final int color; protected final Supplier textSupplier; protected String lastText = ""; + protected boolean isCentered = true; protected boolean clientWidget; protected boolean isShadow; public SimpleTextWidget(int xPosition, int yPosition, String formatLocale, int color, Supplier textSupplier) { - super(new Position(xPosition, yPosition), Size.ZERO); - this.color = color; - this.formatLocale = formatLocale; - this.textSupplier = textSupplier; + this(xPosition, yPosition, formatLocale, color, textSupplier, true); } public SimpleTextWidget(int xPosition, int yPosition, String formatLocale, int color, Supplier textSupplier, boolean clientWidget) { @@ -43,7 +41,7 @@ public SimpleTextWidget(int xPosition, int yPosition, String formatLocale, int c } public SimpleTextWidget(int xPosition, int yPosition, String formatLocale, Supplier textSupplier) { - this(xPosition, yPosition, formatLocale, 0x404040, textSupplier); + this(xPosition, yPosition, formatLocale, 0x404040, textSupplier, true); } public SimpleTextWidget setShadow(boolean shadow) { @@ -51,6 +49,11 @@ public SimpleTextWidget setShadow(boolean shadow) { return this; } + public SimpleTextWidget setCenter(boolean isCentered) { + this.isCentered = isCentered; + return this; + } + private void updateSize() { FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; int stringWidth = fontRenderer.getStringWidth(lastText); @@ -79,8 +82,8 @@ public void drawInBackground(int mouseX, int mouseY, IRenderContext context) { String text = formatLocale.isEmpty() ? (I18n.hasKey(lastText) ? I18n.format(lastText) : lastText) : I18n.format(formatLocale, lastText); Position position = getPosition(); fontRenderer.drawString(text, - position.x - fontRenderer.getStringWidth(text) / 2f, - position.y - fontRenderer.FONT_HEIGHT / 2f, color, isShadow); + isCentered ? position.x - fontRenderer.getStringWidth(text) / 2 : position.x, + isCentered ? position.y - fontRenderer.FONT_HEIGHT / 2 : position.y, color, isShadow); GlStateManager.color(rColorForOverlay, gColorForOverlay, bColorForOverlay, 1.0F); } diff --git a/src/main/java/gregtech/api/gui/widgets/TextFieldWidget.java b/src/main/java/gregtech/api/gui/widgets/TextFieldWidget.java index 26995fbce86..1f68db69659 100644 --- a/src/main/java/gregtech/api/gui/widgets/TextFieldWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/TextFieldWidget.java @@ -36,6 +36,24 @@ public TextFieldWidget(int xPosition, int yPosition, int width, int height, bool super(new Position(xPosition, yPosition), new Size(width, height)); if (isClientSide()) { this.enableBackground = enableBackground; + FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; + if (enableBackground) { + this.textField = new GuiTextField(0, fontRenderer, xPosition, yPosition, width, height); + } else { + this.textField = new GuiTextField(0, fontRenderer, xPosition + 1, yPosition + (height - fontRenderer.FONT_HEIGHT) / 2 + 1, width - 2, height); + } + this.textField.setCanLoseFocus(true); + this.textField.setEnableBackgroundDrawing(enableBackground); + this.textField.setMaxStringLength(this.maxStringLength); + this.textField.setGuiResponder(MCGuiUtil.createTextFieldResponder(this::onTextChanged)); + } + this.textSupplier = textSupplier; + this.textResponder = textResponder; + } + + public TextFieldWidget(int xPosition, int yPosition, int width, int height, boolean enableBackground, Supplier textSupplier, Consumer textResponder, int maxStringLength) { + super(new Position(xPosition, yPosition), new Size(width, height)); + if (isClientSide()) { FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; if (enableBackground) { this.textField = new GuiTextField(0, fontRenderer, xPosition, yPosition, width, height); @@ -45,6 +63,7 @@ public TextFieldWidget(int xPosition, int yPosition, int width, int height, bool this.textField.setCanLoseFocus(true); this.textField.setEnableBackgroundDrawing(enableBackground); this.textField.setMaxStringLength(maxStringLength); + this.maxStringLength = maxStringLength; this.textField.setGuiResponder(MCGuiUtil.createTextFieldResponder(this::onTextChanged)); } this.textSupplier = textSupplier; @@ -92,6 +111,7 @@ public String getCurrentString() { return this.currentString; } + @Override protected void onPositionUpdate() { if (isClientSide() && textField != null) { diff --git a/src/main/java/gregtech/api/items/gui/PlayerInventoryHolder.java b/src/main/java/gregtech/api/items/gui/PlayerInventoryHolder.java index 84581a2ffff..ac15eb23795 100644 --- a/src/main/java/gregtech/api/items/gui/PlayerInventoryHolder.java +++ b/src/main/java/gregtech/api/items/gui/PlayerInventoryHolder.java @@ -17,7 +17,7 @@ public class PlayerInventoryHolder implements IUIHolder { /*package-local*/ ItemStack sampleItem; @SideOnly(Side.CLIENT) - /*package-local*/ PlayerInventoryHolder(EntityPlayer player, EnumHand hand, ItemStack sampleItem) { + /*package-local*/ public PlayerInventoryHolder(EntityPlayer player, EnumHand hand, ItemStack sampleItem) { this.player = player; this.hand = hand; this.sampleItem = sampleItem; @@ -27,8 +27,6 @@ public PlayerInventoryHolder(EntityPlayer entityPlayer, EnumHand hand) { this.player = entityPlayer; this.hand = hand; this.sampleItem = player.getHeldItem(hand); - Preconditions.checkArgument(sampleItem.getItem() instanceof ItemUIFactory, - "Current Item should implement ItemUIFactory"); } public static void openHandItemUI(EntityPlayer player, EnumHand hand) { @@ -68,11 +66,6 @@ public ItemStack getCurrentItem() { * will also update sample item to this item */ public void setCurrentItem(ItemStack item) { - ItemStack itemStack = player.getHeldItem(hand); - if (!ItemStack.areItemsEqual(sampleItem, itemStack)) - return; - Preconditions.checkArgument(item.getItem() instanceof ItemUIFactory, - "Current Item should implement ItemUIFactory"); this.sampleItem = item; player.setHeldItem(hand, item); } diff --git a/src/main/java/gregtech/api/items/itemhandlers/InaccessibleItemStackHandler.java b/src/main/java/gregtech/api/items/itemhandlers/InaccessibleItemStackHandler.java new file mode 100644 index 00000000000..2044c3fc642 --- /dev/null +++ b/src/main/java/gregtech/api/items/itemhandlers/InaccessibleItemStackHandler.java @@ -0,0 +1,22 @@ +package gregtech.api.items.itemhandlers; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.items.ItemStackHandler; + +import javax.annotation.Nonnull; + +public class InaccessibleItemStackHandler extends ItemStackHandler { + @Nonnull + public ItemStack insertItem(int slot, @Nonnull ItemStack stack, boolean simulate) { + return stack; + } + + @Nonnull + public ItemStack extractItem(int slot, int amount, boolean simulate) { + return ItemStack.EMPTY; + } + + public void setStackInSlot(int slot, ItemStack stack) { + this.stacks.set(slot, stack); + } +} diff --git a/src/main/java/gregtech/api/metatileentity/MetaTileEntity.java b/src/main/java/gregtech/api/metatileentity/MetaTileEntity.java index f690b8a4d39..6809093e3b2 100644 --- a/src/main/java/gregtech/api/metatileentity/MetaTileEntity.java +++ b/src/main/java/gregtech/api/metatileentity/MetaTileEntity.java @@ -1278,4 +1278,7 @@ public boolean keepsInventory() { public boolean getWitherProof() { return false; } + + public void preInit(Object... data) { + } } diff --git a/src/main/java/gregtech/api/metatileentity/MetaTileEntityHolder.java b/src/main/java/gregtech/api/metatileentity/MetaTileEntityHolder.java index 3b34661d759..014ac24481d 100644 --- a/src/main/java/gregtech/api/metatileentity/MetaTileEntityHolder.java +++ b/src/main/java/gregtech/api/metatileentity/MetaTileEntityHolder.java @@ -39,11 +39,15 @@ public MetaTileEntity getMetaTileEntity() { * Sets this holder's current meta tile entity to copy of given one * Note that this method copies given meta tile entity and returns actual instance * so it is safe to call it on sample meta tile entities + * Also can use certain data to preinit the block before data is synced */ - public MetaTileEntity setMetaTileEntity(MetaTileEntity sampleMetaTileEntity) { + public MetaTileEntity setMetaTileEntity(MetaTileEntity sampleMetaTileEntity, Object... data) { Preconditions.checkNotNull(sampleMetaTileEntity, "metaTileEntity"); this.metaTileEntity = sampleMetaTileEntity.createMetaTileEntity(this); this.metaTileEntity.holder = this; + if(data.length != 0) { + this.metaTileEntity.preInit(data); + } this.metaTileEntity.onAttached(); if (hasWorld() && !getWorld().isRemote) { updateBlockOpacity(); @@ -231,8 +235,8 @@ public void onChunkUnload() { } @Override - public boolean shouldRefresh(@Nonnull World world, @Nonnull BlockPos pos, IBlockState oldState, IBlockState newSate) { - return oldState.getBlock() != newSate.getBlock(); //MetaTileEntityHolder should never refresh (until block changes) + public boolean shouldRefresh(@Nonnull World world, @Nonnull BlockPos pos, IBlockState oldState, IBlockState newState) { + return oldState.getBlock() != newState.getBlock(); //MetaTileEntityHolder should never refresh (until block changes) } @Override diff --git a/src/main/java/gregtech/api/metatileentity/MetaTileEntityUIFactory.java b/src/main/java/gregtech/api/metatileentity/MetaTileEntityUIFactory.java index f3351548a03..6a73f9f16c6 100644 --- a/src/main/java/gregtech/api/metatileentity/MetaTileEntityUIFactory.java +++ b/src/main/java/gregtech/api/metatileentity/MetaTileEntityUIFactory.java @@ -25,7 +25,6 @@ public void init() { } @Override - @SuppressWarnings("unchecked") protected ModularUI createUITemplate(MetaTileEntityHolder holder, EntityPlayer entityPlayer) { return holder.getMetaTileEntity().createUI(entityPlayer); } diff --git a/src/main/java/gregtech/api/net/NetworkHandler.java b/src/main/java/gregtech/api/net/NetworkHandler.java index fc8317f51e2..209b55ef4c4 100755 --- a/src/main/java/gregtech/api/net/NetworkHandler.java +++ b/src/main/java/gregtech/api/net/NetworkHandler.java @@ -7,8 +7,10 @@ import gregtech.api.gui.UIFactory; import gregtech.api.gui.impl.ModularUIContainer; import gregtech.api.gui.impl.ModularUIGui; +import gregtech.api.metatileentity.MetaTileEntityHolder; import gregtech.api.util.ClipboardUtil; import gregtech.api.util.GTLog; +import gregtech.common.metatileentities.MetaTileEntityClipboard; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import net.minecraft.block.state.IBlockState; @@ -20,6 +22,7 @@ import net.minecraft.network.INetHandler; import net.minecraft.network.NetHandlerPlayServer; import net.minecraft.network.PacketBuffer; +import net.minecraft.tileentity.TileEntity; import net.minecraft.util.IThreadListener; import net.minecraft.util.IntIdentityHashBiMap; import net.minecraft.util.math.BlockPos; @@ -193,6 +196,27 @@ public static void init() { (buf) -> new PacketClipboard(buf.readString(32767)) )); + registerPacket(6, PacketClipboardUIWidgetUpdate.class, new NetworkHandler.PacketCodec<>( + (packet, buf) -> { + buf.writeVarInt(packet.clipboard.getWorld().provider.getDimension()); + buf.writeBlockPos(packet.clipboard.getPos()); + buf.writeVarInt(packet.id); + if(packet.payloadWriter != null) { + packet.payloadWriter.accept(buf); + } + }, + (buf) -> { + int dim = buf.readVarInt(); + BlockPos pos = buf.readBlockPos(); + TileEntity te = FMLCommonHandler.instance().getMinecraftServerInstance().getWorld(dim).getTileEntity(pos); + if(te instanceof MetaTileEntityHolder && ((MetaTileEntityHolder) te).getMetaTileEntity() instanceof MetaTileEntityClipboard) { + return new PacketClipboardUIWidgetUpdate((MetaTileEntityClipboard) ((MetaTileEntityHolder) te).getMetaTileEntity(), buf); + } + return new PacketClipboardUIWidgetUpdate(null, buf); + } + )); + + registerServerExecutor(PacketUIClientAction.class, (packet, handler) -> { Container openContainer = handler.player.openContainer; if (openContainer instanceof ModularUIContainer && @@ -203,6 +227,12 @@ public static void init() { } }); + NetworkHandler.registerServerExecutor(PacketClipboardUIWidgetUpdate.class, (packet, handler) -> { + if (packet.clipboard != null) { + packet.clipboard.readUIAction(handler.player, packet.id, packet.buf); + } + }); + if (FMLCommonHandler.instance().getSide().isClient()) { initClient(); } diff --git a/src/main/java/gregtech/api/net/PacketClipboardUIWidgetUpdate.java b/src/main/java/gregtech/api/net/PacketClipboardUIWidgetUpdate.java new file mode 100644 index 00000000000..2200e17c68e --- /dev/null +++ b/src/main/java/gregtech/api/net/PacketClipboardUIWidgetUpdate.java @@ -0,0 +1,28 @@ +package gregtech.api.net; + +import gregtech.api.metatileentity.MetaTileEntityHolder; +import gregtech.common.metatileentities.MetaTileEntityClipboard; +import net.minecraft.network.PacketBuffer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraftforge.fml.common.FMLCommonHandler; + +import java.util.function.Consumer; + +public class PacketClipboardUIWidgetUpdate implements NetworkHandler.Packet { + public MetaTileEntityClipboard clipboard; + public int id; + public Consumer payloadWriter; + public PacketBuffer buf; + + public PacketClipboardUIWidgetUpdate(MetaTileEntityClipboard clipboard, int id, Consumer payloadWriter) { + this.clipboard = clipboard; + this.id = id; + this.payloadWriter = payloadWriter; + } + + public PacketClipboardUIWidgetUpdate(MetaTileEntityClipboard clipboard, PacketBuffer buf) { + this(clipboard, buf.readVarInt(), null); + this.buf = buf; + } +} diff --git a/src/main/java/gregtech/api/render/ClipboardRenderer.java b/src/main/java/gregtech/api/render/ClipboardRenderer.java new file mode 100644 index 00000000000..5b158d3b649 --- /dev/null +++ b/src/main/java/gregtech/api/render/ClipboardRenderer.java @@ -0,0 +1,109 @@ +package gregtech.api.render; + +import codechicken.lib.render.CCRenderState; +import codechicken.lib.render.pipeline.IVertexOperation; +import codechicken.lib.texture.TextureUtils; +import codechicken.lib.vec.Cuboid6; +import codechicken.lib.vec.Matrix4; +import codechicken.lib.vec.Rotation; +import gregtech.api.gui.ModularUI; +import gregtech.api.gui.Widget; +import gregtech.api.gui.impl.FakeModularGui; +import gregtech.common.gui.impl.FakeModularUIContainerClipboard; +import gregtech.api.util.GTLog; +import gregtech.api.util.GregFakePlayer; +import gregtech.common.metatileentities.MetaTileEntityClipboard; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.util.FakePlayer; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import org.apache.commons.lang3.tuple.Pair; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +public class ClipboardRenderer implements TextureUtils.IIconRegister { + + private static final Cuboid6 pageBox = new Cuboid6(3 / 16.0, 0.25 / 16.0, 0.25 / 16.0, 13 / 16.0, 14.25 / 16.0, 0.3 / 16.0); + private static final Cuboid6 boardBox = new Cuboid6(2.75 / 16.0, 0 / 16.0, 0 / 16.0, 13.25 / 16.0, 15.25 / 16.0, 0.25 / 16.0); + private static final Cuboid6 clipBox = new Cuboid6(5.75 / 16.0, 14.75 / 16.0, 0.25 / 16.0, 10.25 / 16.0, 15.5 / 16.0, 0.4 / 16.0); + private static final Cuboid6 graspBox = new Cuboid6(7 / 16.0, 15.25 / 16.0, 0.1 / 16.0, 9 / 16.0, 16 / 16.0, 0.35 / 16.0); + + private static final List rotations = Arrays.asList(EnumFacing.NORTH, EnumFacing.WEST, EnumFacing.SOUTH, EnumFacing.EAST); + + private static HashMap boxTextureMap = new HashMap<>(); + + @SideOnly(Side.CLIENT) + private TextureAtlasSprite[] textures = new TextureAtlasSprite[3]; + + + public ClipboardRenderer() { + Textures.iconRegisters.add(this); + } + + @Override + public void registerIcons(TextureMap textureMap) { + this.textures[0] = textureMap.registerSprite(new ResourceLocation("gregtech:blocks/clipboard/wood")); + boxTextureMap.put(boardBox, this.textures[0]); + this.textures[1] = textureMap.registerSprite(new ResourceLocation("gregtech:blocks/clipboard/clip")); + boxTextureMap.put(clipBox, this.textures[1]); + boxTextureMap.put(graspBox, this.textures[1]); + this.textures[2] = textureMap.registerSprite(new ResourceLocation("gregtech:blocks/clipboard/page")); + boxTextureMap.put(pageBox, this.textures[2]); + } + + @SideOnly(Side.CLIENT) + public void renderBoard(CCRenderState renderState, Matrix4 translation, IVertexOperation[] pipeline, EnumFacing rotation, MetaTileEntityClipboard clipboard, float partialTicks) { + translation.translate(0.5, 0.5, 0.5); + translation.rotate(Math.toRadians(90.0 * rotations.indexOf(rotation)), Rotation.axes[1]); + translation.translate(-0.5, -0.5, -0.5); + + // Render Clipboard + for (EnumFacing renderSide : EnumFacing.VALUES) { + boxTextureMap.forEach((box, sprite) -> Textures.renderFace(renderState, translation, pipeline, renderSide, box, sprite)); + } + } + + + @SideOnly(Side.CLIENT) + public void renderGUI(double x, double y, double z, EnumFacing rotation, MetaTileEntityClipboard clipboard, float partialTicks) { + GlStateManager.pushMatrix(); + RenderHelper.disableStandardItemLighting(); + + // All of these are done in reverse order, by the way, if you're reviewing this :P + + GlStateManager.translate(x, y, z); + GlStateManager.translate(0.5, 0.451, 0.5); + GlStateManager.rotate((float) (90.0 * rotations.indexOf(rotation)), 0, 1, 0); + GlStateManager.translate(0, 0, -0.468); + GlStateManager.rotate(180, 1, 0, 0); + GlStateManager.scale(0.875, 0.875, 0.875); + + if (clipboard.guiCache != null) { + Pair result = clipboard.checkLookingAt(); + if (result == null) { + clipboard.guiCache.drawScreen(0, 0, partialTicks); + } else { + clipboard.guiCache.drawScreen(result.getKey(), result.getValue(), partialTicks); + } + } + + RenderHelper.enableStandardItemLighting(); + GlStateManager.popMatrix(); + } + + + + @SideOnly(Side.CLIENT) + public TextureAtlasSprite getParticleTexture() { + return textures[0]; + } +} diff --git a/src/main/java/gregtech/api/render/Textures.java b/src/main/java/gregtech/api/render/Textures.java index e69733b2cae..7015fcf8efd 100644 --- a/src/main/java/gregtech/api/render/Textures.java +++ b/src/main/java/gregtech/api/render/Textures.java @@ -29,13 +29,14 @@ public class Textures { private static final ThreadLocal blockFaces = ThreadLocal.withInitial(BlockFace::new); public static final List iconRegisters = new ArrayList<>(); - public static final SafeRenderer SAFE = new SafeRenderer("storage/safe"); + public static ClipboardRenderer CLIPBOARD_RENDERER = new ClipboardRenderer(); + public static final CrateRenderer WOODEN_CRATE = new CrateRenderer("storage/crates/wooden_crate"); + public static final CrateRenderer METAL_CRATE = new CrateRenderer("storage/crates/metal_crate"); public static final DrumRenderer WOODEN_DRUM = new DrumRenderer("storage/drums/wooden_drum"); public static final DrumRenderer DRUM = new DrumRenderer("storage/drums/drum"); + public static final SafeRenderer SAFE = new SafeRenderer("storage/safe"); public static final TankRenderer WOODEN_TANK = new TankRenderer("storage/tank/wooden"); public static final TankRenderer METAL_TANK = new TankRenderer("storage/tank/metal"); - public static final CrateRenderer WOODEN_CRATE = new CrateRenderer("storage/crates/wooden_crate"); - public static final CrateRenderer METAL_CRATE = new CrateRenderer("storage/crates/metal_crate"); public static final SimpleSidedCubeRenderer STEAM_CASING_BRONZE = new SimpleSidedCubeRenderer("casings/steam/bronze"); public static final SimpleSidedCubeRenderer STEAM_CASING_STEEL = new SimpleSidedCubeRenderer("casings/steam/steel"); public static final SimpleSidedCubeRenderer STEAM_BRICKED_CASING_BRONZE = new SimpleSidedCubeRenderer("casings/steam/bricked_bronze"); diff --git a/src/main/java/gregtech/api/util/GTUtility.java b/src/main/java/gregtech/api/util/GTUtility.java index 4e31ac757c3..92abab7f8bf 100644 --- a/src/main/java/gregtech/api/util/GTUtility.java +++ b/src/main/java/gregtech/api/util/GTUtility.java @@ -900,4 +900,15 @@ public static boolean isFluidStackAmountDivisible(FluidStack fluidStack, int div public static boolean isItemStackCountDivisible(ItemStack itemStack, int divisor) { return itemStack.getCount() % divisor == 0 && itemStack.getCount() % divisor != itemStack.getCount() && itemStack.getCount() / divisor != 0; } + + public static AxisAlignedBB rotateAroundYAxis(AxisAlignedBB aabb, EnumFacing from, EnumFacing to) { + if(from == EnumFacing.UP || from == EnumFacing.DOWN || to == EnumFacing.UP || to == EnumFacing.DOWN) + throw new IllegalArgumentException("Either the second or third parameters were EnumFacing.DOWN or EnumFacing.UP."); + AxisAlignedBB rotatedAABB = new AxisAlignedBB(aabb.minX, aabb.minY, aabb.minZ, aabb.maxX, aabb.maxY, aabb.maxZ); + while(from != to) { + from = from.rotateY(); + rotatedAABB = new AxisAlignedBB(1 - rotatedAABB.maxZ, rotatedAABB.minY, rotatedAABB.minX, 1 - rotatedAABB.minZ, rotatedAABB.maxY, rotatedAABB.maxX); + } + return rotatedAABB; + } } diff --git a/src/main/java/gregtech/api/util/GregFakePlayer.java b/src/main/java/gregtech/api/util/GregFakePlayer.java index 6aafd3d4fe9..6c534956679 100644 --- a/src/main/java/gregtech/api/util/GregFakePlayer.java +++ b/src/main/java/gregtech/api/util/GregFakePlayer.java @@ -1,14 +1,25 @@ package gregtech.api.util; import com.mojang.authlib.GameProfile; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.server.MinecraftServer; +import net.minecraft.stats.StatBase; +import net.minecraft.util.DamageSource; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.world.World; import net.minecraft.world.WorldServer; import net.minecraftforge.common.util.FakePlayer; import net.minecraftforge.common.util.FakePlayerFactory; +import net.minecraftforge.common.util.ITeleporter; +import net.minecraftforge.fml.common.FMLCommonHandler; import java.lang.ref.WeakReference; import java.util.UUID; -public class GregFakePlayer { +public class GregFakePlayer extends EntityPlayer { private static final GameProfile GREGTECH = new GameProfile(UUID.fromString("518FDF18-EC2A-4322-832A-58ED1721309B"), "[GregTech]"); private static WeakReference GREGTECH_PLAYER = null; @@ -22,4 +33,76 @@ public static FakePlayer get(WorldServer world) { return ret; } + public GregFakePlayer(World worldIn) { + super(worldIn, GREGTECH); + } + + @Override + public boolean isSpectator() { + return false; + } + + @Override + public boolean isCreative() { + return false; + } + + @Override + public Vec3d getPositionVector() { + return new Vec3d(0, 0, 0); + } + + @Override + public boolean canUseCommand(int i, String s) { + return false; + } + + @Override + public void sendStatusMessage(ITextComponent chatComponent, boolean actionBar) { + } + + @Override + public void sendMessage(ITextComponent component) { + } + + @Override + public void addStat(StatBase par1StatBase, int par2) { + } + + @Override + public void openGui(Object mod, int modGuiId, World world, int x, int y, int z) { + } + + @Override + public boolean isEntityInvulnerable(DamageSource source) { + return true; + } + + @Override + public boolean canAttackPlayer(EntityPlayer player) { + return false; + } + + @Override + public void onDeath(DamageSource source) { + return; + } + + @Override + public void onUpdate() { + return; + } + + @Override + public Entity changeDimension(int dim, ITeleporter teleporter) { + return this; + } + + @Override + public MinecraftServer getServer() { + return FMLCommonHandler.instance().getMinecraftServerInstance(); + } + + @Override + protected void playEquipSound(ItemStack stack) { } } diff --git a/src/main/java/gregtech/api/util/RenderUtil.java b/src/main/java/gregtech/api/util/RenderUtil.java index d3f98e3f67d..c150c1b1555 100644 --- a/src/main/java/gregtech/api/util/RenderUtil.java +++ b/src/main/java/gregtech/api/util/RenderUtil.java @@ -1,7 +1,17 @@ package gregtech.api.util; import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.EntityPlayerSP; +import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.RenderItem; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; +import net.minecraft.util.math.MathHelper; import net.minecraftforge.client.GuiIngameForge; import org.lwjgl.opengl.GL11; @@ -85,5 +95,4 @@ private static void applyScissor(int x, int y, int w, int h) { int translatedY = r.getScaledHeight() - y - h; GL11.glScissor(x * s, translatedY * s, w * s, h * s); } - } diff --git a/src/main/java/gregtech/common/gui/impl/FakeModularUIContainerClipboard.java b/src/main/java/gregtech/common/gui/impl/FakeModularUIContainerClipboard.java new file mode 100644 index 00000000000..6b95f557ace --- /dev/null +++ b/src/main/java/gregtech/common/gui/impl/FakeModularUIContainerClipboard.java @@ -0,0 +1,127 @@ +package gregtech.common.gui.impl; + +import com.google.common.collect.Lists; +import gregtech.api.gui.INativeWidget; +import gregtech.api.gui.ModularUI; +import gregtech.api.gui.Widget; +import gregtech.api.gui.widgets.WidgetUIAccess; +import gregtech.api.net.NetworkHandler; +import gregtech.api.net.PacketClipboardUIWidgetUpdate; +import gregtech.common.metatileentities.MetaTileEntityClipboard; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.NonNullList; +import net.minecraft.util.Tuple; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + + +// Note: when porting the central monitor, please make this more generic. +public class FakeModularUIContainerClipboard implements WidgetUIAccess { + private final NonNullList inventoryItemStacks = NonNullList.create(); + public final List inventorySlots = Lists.newArrayList(); + public final ModularUI modularUI; + public int windowId; + public MetaTileEntityClipboard clipboard; + + public FakeModularUIContainerClipboard(ModularUI modularUI, MetaTileEntityClipboard clipboard) { + this.modularUI = modularUI; + this.clipboard = clipboard; + modularUI.initWidgets(); + modularUI.guiWidgets.values().forEach(widget -> widget.setUiAccess(this)); + modularUI.guiWidgets.values().stream().flatMap(widget -> widget.getNativeWidgets().stream()).forEach(nativeWidget -> addSlotToContainer(nativeWidget.getHandle())); + modularUI.triggerOpenListeners(); + } + + protected void addSlotToContainer(Slot slotIn) { + slotIn.slotNumber = this.inventorySlots.size(); + this.inventorySlots.add(slotIn); + this.inventoryItemStacks.add(ItemStack.EMPTY); + } + + public void handleSlotUpdate(PacketBuffer updateData) { + try { + int size = updateData.readVarInt(); + for (int i = 0; i < size; i++) { + inventorySlots.get(updateData.readVarInt()).putStack(updateData.readItemStack()); + } + } catch (Exception ignored) { + + } + } + + public void handleClientAction(PacketBuffer buffer) { + int windowId = buffer.readVarInt(); + if (windowId == this.windowId) { + Widget widget = modularUI.guiWidgets.get(buffer.readVarInt()); + if (widget != null) { + widget.handleClientAction(buffer.readVarInt(), buffer); + } + } + } + + public void detectAndSendChanges() { + List> toUpdate = new ArrayList<>(); + for (int i = 0; i < this.inventorySlots.size(); ++i) { + ItemStack real = this.inventorySlots.get(i).getStack(); + ItemStack fake = this.inventoryItemStacks.get(i); + + if (!ItemStack.areItemStacksEqual(fake, real)) { + boolean clientStackChanged = !ItemStack.areItemStacksEqualUsingNBTShareTag(fake, real); + fake = real.isEmpty() ? ItemStack.EMPTY : real.copy(); + this.inventoryItemStacks.set(i, fake); + + if (clientStackChanged) { + toUpdate.add(new Tuple<>(i, fake)); + } + } + } + modularUI.guiWidgets.values().forEach(Widget::detectAndSendChanges); + } + + @Override + public void notifySizeChange() { + + } + + @Override + public void notifyWidgetChange() { + + } + + @Override + public boolean attemptMergeStack(ItemStack itemStack, boolean b, boolean b1) { + return false; + } + + @Override + public void sendSlotUpdate(INativeWidget iNativeWidget) { + } + + @Override + public void sendHeldItemUpdate() { + } + + @Override + public void writeClientAction(Widget widget, int updateId, Consumer payloadWriter) { + NetworkHandler.channel.sendToServer(new PacketClipboardUIWidgetUpdate(this.clipboard, updateId, buffer -> { + buffer.writeVarInt(windowId); + buffer.writeVarInt(modularUI.guiWidgets.inverse().get(widget)); + buffer.writeVarInt(updateId); + payloadWriter.accept(buffer); + }).toFMLPacket()); + } + + @Override + public void writeUpdateInfo(Widget widget, int updateId, Consumer payloadWriter) { + this.clipboard.writeCustomData(0, buf -> { + buf.writeVarInt(windowId); + buf.writeVarInt(modularUI.guiWidgets.inverse().get(widget)); + buf.writeVarInt(updateId); + payloadWriter.accept(buf); + }); + } +} diff --git a/src/main/java/gregtech/common/items/MetaItem1.java b/src/main/java/gregtech/common/items/MetaItem1.java index 8e7d7b63fd2..3a14e45a2ae 100644 --- a/src/main/java/gregtech/common/items/MetaItem1.java +++ b/src/main/java/gregtech/common/items/MetaItem1.java @@ -377,7 +377,7 @@ public void registerSubItems() { NANO_SABER = addItem(463, "nano_saber").addComponents(ElectricStats.createElectricItem(4000000L, GTValues.HV)).addComponents(new NanoSaberBehavior()).setMaxStackSize(1); // Free ID 464 SCANNER = addItem(465, "scanner").addComponents(ElectricStats.createElectricItem(200_000L, GTValues.LV), new ScannerBehavior(50)); - /* CLIPBOARD GOES HERE - ID 466 */ + CLIPBOARD = addItem(466, "clipboard").addComponents(new ClipboardBehavior()).setMaxStackSize(1); TERMINAL = addItem(467, "terminal").addComponents(new TerminalBehaviour()); // Misc Crafting Items: ID 491-515 diff --git a/src/main/java/gregtech/common/items/MetaItems.java b/src/main/java/gregtech/common/items/MetaItems.java index dad05326824..ff4ce16f24e 100644 --- a/src/main/java/gregtech/common/items/MetaItems.java +++ b/src/main/java/gregtech/common/items/MetaItems.java @@ -488,6 +488,8 @@ private MetaItems() { public static MetaItem.MetaValueItem VOLTAGE_COIL_ZPM; public static MetaItem.MetaValueItem VOLTAGE_COIL_UV; + public static MetaItem.MetaValueItem CLIPBOARD; + private static final List orePrefixes = new ArrayList() {{ add(OrePrefix.dust); add(OrePrefix.dustSmall); diff --git a/src/main/java/gregtech/common/items/behaviors/ClipboardBehavior.java b/src/main/java/gregtech/common/items/behaviors/ClipboardBehavior.java new file mode 100644 index 00000000000..e30b3e990f1 --- /dev/null +++ b/src/main/java/gregtech/common/items/behaviors/ClipboardBehavior.java @@ -0,0 +1,257 @@ +package gregtech.common.items.behaviors; + +import codechicken.lib.raytracer.RayTracer; +import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.ModularUI; +import gregtech.api.gui.widgets.*; +import gregtech.api.items.gui.ItemUIFactory; +import gregtech.api.items.gui.PlayerInventoryHolder; +import gregtech.api.items.metaitem.stats.IItemBehaviour; +import gregtech.api.metatileentity.MetaTileEntityHolder; +import gregtech.api.util.RenderUtil; +import gregtech.common.items.MetaItems; +import gregtech.common.metatileentities.MetaTileEntityClipboard; +import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.ActionResult; +import net.minecraft.util.EnumActionResult; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.world.World; + +import static gregtech.common.blocks.MetaBlocks.MACHINE; +import static gregtech.common.metatileentities.MetaTileEntities.CLIPBOARD_TILE; + +public class ClipboardBehavior implements IItemBehaviour, ItemUIFactory { + public static final int MAX_PAGES = 25; + + @Override + public ModularUI createUI(PlayerInventoryHolder holder, EntityPlayer entityPlayer) { + initNBT(holder.getCurrentItem()); + ModularUI.Builder builder = ModularUI.builder(GuiTextures.BACKGROUND, 170, 238); + + builder.widget(new ImageTextFieldWidget(20, 10, 130, 12, GuiTextures.CLIPBOARD_TEXT_BOX, + () -> getTitle(holder), (x) -> setTitle(holder, x), 23, 0xFFFFFF) + .setValidator((x) -> true)); + + for (int i = 0; i < 8; i++) { + int finalI = i; + builder.widget(new ImageCycleButtonWidget(6, 37 + 20 * i, 15, 15, GuiTextures.CLIPBOARD_BUTTON, 4, + () -> getButtonState(holder, finalI), (x) -> setButton(holder, finalI, x))); + builder.widget(new ImageTextFieldWidget(24, 40 + 20 * i, 140, 12, GuiTextures.CLIPBOARD_TEXT_BOX, + () -> getString(holder, finalI), (x) -> setString(holder, finalI, x), 23, 0xFFFFFF) + .setValidator((x) -> true)); + } + + builder.widget(new ClickButtonWidget(30, 200, 16, 16, "", (x) -> incrPageNum(holder, -1)) + .setButtonTexture(GuiTextures.BUTTON_LEFT).setShouldClientCallback(true)); + builder.widget(new ClickButtonWidget(124, 200, 16, 16, "", (x) -> incrPageNum(holder, 1)) + .setButtonTexture(GuiTextures.BUTTON_RIGHT).setShouldClientCallback(true)); + builder.widget(new SimpleTextWidget(85, 208, "", 0xFFFFFF, + () -> (getPageNum(holder) + 1) + " / " + MAX_PAGES)); + + return builder.build(holder, entityPlayer); + } + + public ModularUI createMTEUI(PlayerInventoryHolder holder, EntityPlayer entityPlayer) { // So that people don't click on any text fields + initNBT(holder.getCurrentItem()); + ModularUI.Builder builder = ModularUI.builder(GuiTextures.BACKGROUND, 170, 238); + + builder.image(18, 8, 130, 14, GuiTextures.CLIPBOARD_TEXT_BOX); + builder.widget(new SimpleTextWidget(20, 10, "", 0xFFFFFF, () -> getTitle(holder)).setCenter(false)); + + + for (int i = 0; i < 8; i++) { + int finalI = i; + builder.widget(new ImageCycleButtonWidget(6, 37 + 20 * i, 15, 15, GuiTextures.CLIPBOARD_BUTTON, 4, + () -> getButtonState(holder, finalI), (x) -> setButton(holder, finalI, x))); + builder.image(22, 38 + 20 * i, 140, 12, GuiTextures.CLIPBOARD_TEXT_BOX); + builder.widget(new SimpleTextWidget(24, 40 + 20 * i, "", 0xFFFFFF, () -> getString(holder, finalI)).setCenter(false)); + } + + builder.widget(new ClickButtonWidget(30, 200, 16, 16, "", (x) -> incrPageNum(holder, -1)) + .setButtonTexture(GuiTextures.BUTTON_LEFT).setShouldClientCallback(true)); + builder.widget(new ClickButtonWidget(124, 200, 16, 16, "", (x) -> incrPageNum(holder, 1)) + .setButtonTexture(GuiTextures.BUTTON_RIGHT).setShouldClientCallback(true)); + builder.widget(new SimpleTextWidget(85, 208, "", 0xFFFFFF, + () -> (getPageNum(holder) + 1) + " / " + MAX_PAGES)); + + return builder.build(holder, entityPlayer); + } + + + private static NBTTagCompound getPageCompound(ItemStack stack) { + if (!MetaItems.CLIPBOARD.isItemEqual(stack)) + throw new IllegalArgumentException("Given item stack is not a clipboard!"); + assert stack.getTagCompound() != null; + short pageNum = stack.getTagCompound().getShort("PageIndex"); + return stack.getTagCompound().getCompoundTag("Page" + pageNum); + } + + private static void setPageCompound(ItemStack stack, NBTTagCompound pageCompound) { + if (!MetaItems.CLIPBOARD.isItemEqual(stack)) + throw new IllegalArgumentException("Given item stack is not a clipboard!"); + assert stack.getTagCompound() != null; + short pageNum = stack.getTagCompound().getShort("PageIndex"); + stack.getTagCompound().setTag("Page" + pageNum, pageCompound); + } + + private static void initNBT(ItemStack stack) { + if (!MetaItems.CLIPBOARD.isItemEqual(stack)) + throw new IllegalArgumentException("Given item stack is not a clipboard!"); + NBTTagCompound tagCompound = stack.getTagCompound(); + if (tagCompound == null) { + tagCompound = new NBTTagCompound(); + tagCompound.setShort("PageIndex", (short) 0); + tagCompound.setShort("TotalPages", (short) 0); + + NBTTagCompound pageCompound = new NBTTagCompound(); + pageCompound.setShort("ButStat", (short) 0); + pageCompound.setString("Title", ""); + for (int i = 0; i < 8; i++) { + pageCompound.setString("Task" + i, ""); + } + + for (int i = 0; i < MAX_PAGES; i++) { + tagCompound.setTag("Page" + i, pageCompound.copy()); + } + + stack.setTagCompound(tagCompound); + } + } + + private static void setButton(PlayerInventoryHolder holder, int pos, int newState) { + ItemStack stack = holder.getCurrentItem(); + if (!MetaItems.CLIPBOARD.isItemEqual(stack)) + throw new IllegalArgumentException("Given item stack is not a clipboard!"); + NBTTagCompound tagCompound = getPageCompound(stack); + short buttonState; + buttonState = tagCompound.getShort("ButStat"); + + short clearedState = (short) (buttonState & ~(3 << (pos * 2))); // Clear out the desired slot + buttonState = (short) (clearedState | (newState << (pos * 2))); // And add the new state back in + + tagCompound.setShort("ButStat", buttonState); + setPageCompound(stack, tagCompound); + } + + private static int getButtonState(PlayerInventoryHolder holder, int pos) { + ItemStack stack = holder.getCurrentItem(); + if (!MetaItems.CLIPBOARD.isItemEqual(stack)) + throw new IllegalArgumentException("Given item stack is not a clipboard!"); + NBTTagCompound tagCompound = getPageCompound(stack); + short buttonState; + buttonState = tagCompound.getShort("ButStat"); + return ((buttonState >> pos * 2) & 3); + } + + private static void setString(PlayerInventoryHolder holder, int pos, String newString) { + ItemStack stack = holder.getCurrentItem(); + if (!MetaItems.CLIPBOARD.isItemEqual(stack)) + throw new IllegalArgumentException("Given item stack is not a clipboard!"); + NBTTagCompound tagCompound = getPageCompound(stack); + tagCompound.setString("Task" + pos, newString); + setPageCompound(stack, tagCompound); + } + + private static String getString(PlayerInventoryHolder holder, int pos) { + ItemStack stack = holder.getCurrentItem(); + if (!MetaItems.CLIPBOARD.isItemEqual(stack)) + throw new IllegalArgumentException("Given item stack is not a clipboard!"); + NBTTagCompound tagCompound = getPageCompound(stack); + return tagCompound.getString("Task" + pos); + } + + private static void setTitle(PlayerInventoryHolder holder, String newString) { + ItemStack stack = holder.getCurrentItem(); + if (!MetaItems.CLIPBOARD.isItemEqual(stack)) + throw new IllegalArgumentException("Given item stack is not a clipboard!"); + NBTTagCompound tagCompound = getPageCompound(stack); + assert tagCompound != null; + tagCompound.setString("Title", newString); + setPageCompound(stack, tagCompound); + } + + private static String getTitle(PlayerInventoryHolder holder) { + ItemStack stack = holder.getCurrentItem(); + if (!MetaItems.CLIPBOARD.isItemEqual(stack)) + throw new IllegalArgumentException("Given item stack is not a clipboard!"); + NBTTagCompound tagCompound = getPageCompound(stack); + return tagCompound.getString("Title"); + } + + private static int getPageNum(PlayerInventoryHolder holder) { + ItemStack stack = holder.getCurrentItem(); + if (!MetaItems.CLIPBOARD.isItemEqual(stack)) + throw new IllegalArgumentException("Given item stack is not a clipboard!"); + NBTTagCompound tagCompound = stack.getTagCompound(); + return tagCompound.getInteger("PageIndex"); + } + + private static void incrPageNum(PlayerInventoryHolder holder, int increment) { + ItemStack stack = holder.getCurrentItem(); + if (!MetaItems.CLIPBOARD.isItemEqual(stack)) + throw new IllegalArgumentException("Given item stack is not a clipboard!"); + NBTTagCompound tagCompound = stack.getTagCompound(); + assert tagCompound != null; + + int currentIndex = tagCompound.getInteger("PageIndex"); + // Clamps currentIndex between 0 and MAX_PAGES. + tagCompound.setInteger("PageIndex", Math.max(Math.min(currentIndex + increment, MAX_PAGES - 1), 0)); + stack.setTagCompound(tagCompound); + } + + + @Override + public ActionResult onItemRightClick(World world, EntityPlayer player, EnumHand hand) { + ItemStack heldItem = player.getHeldItem(hand); + if (!world.isRemote && RayTracer.retrace(player).typeOfHit != RayTraceResult.Type.BLOCK) { // So that the player doesn't place a clipboard before suddenly getting the GUI + PlayerInventoryHolder holder = new PlayerInventoryHolder(player, hand); + holder.openUI(); + } + return ActionResult.newResult(EnumActionResult.SUCCESS, heldItem); + } + + @Override + public ActionResult onItemUse(EntityPlayer player, World world, BlockPos pos, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ) { + if(!world.isRemote) { + ItemStack heldItem = player.getHeldItem(hand).copy(); + heldItem.setCount(1); // don't place multiple items at a time + EnumFacing playerFacing = player.getHorizontalFacing(); + // Make sure it's the right block + Block testBlock = world.getBlockState(pos).getBlock(); + IBlockState testState = testBlock.getDefaultState(); + if (!testBlock.isAir(world.getBlockState(pos), world, pos) && testState.isSideSolid(world, pos, playerFacing)) { + // Step away from the block so you don't replace it, and then give it our fun blockstate + BlockPos shiftedPos = pos.offset(playerFacing.getOpposite()); + Block shiftedBlock = world.getBlockState(shiftedPos).getBlock(); + if (shiftedBlock.isAir(world.getBlockState(shiftedPos), world, shiftedPos)) { + IBlockState state = MACHINE.getDefaultState(); + world.setBlockState(shiftedPos, state); + // Get new TE + shiftedBlock.createTileEntity(world, state); + // And manipulate it to our liking + MetaTileEntityHolder holder = (MetaTileEntityHolder) world.getTileEntity(shiftedPos); + if (holder != null) { + MetaTileEntityClipboard clipboard = (MetaTileEntityClipboard) holder.setMetaTileEntity(CLIPBOARD_TILE, heldItem); + if (clipboard != null) { + clipboard.setFrontFacing(playerFacing); + clipboard.setClipboard(heldItem); + ItemStack returnedStack = player.getHeldItem(hand); + if (!player.isCreative()) { + returnedStack.setCount(player.getHeldItem(hand).getCount() - 1); + } + return ActionResult.newResult(EnumActionResult.SUCCESS, returnedStack); + } + } + } + } + } + return ActionResult.newResult(EnumActionResult.FAIL, player.getHeldItem(hand)); + } +} diff --git a/src/main/java/gregtech/common/metatileentities/MetaTileEntities.java b/src/main/java/gregtech/common/metatileentities/MetaTileEntities.java index 2f549f7c0ea..db8c455df43 100644 --- a/src/main/java/gregtech/common/metatileentities/MetaTileEntities.java +++ b/src/main/java/gregtech/common/metatileentities/MetaTileEntities.java @@ -197,6 +197,8 @@ public class MetaTileEntities { public static final MetaTileEntityFisher[] FISHER = new MetaTileEntityFisher[4]; public static MetaTileEntityCreativeEnergy CREATIVE_ENERGY; + + public static MetaTileEntityClipboard CLIPBOARD_TILE; public static void init() { GTLog.logger.info("Registering MetaTileEntities"); @@ -633,6 +635,8 @@ public static void init() { STEAM_HATCH = GregTechAPI.registerMetaTileEntity(1652, new MetaTileEntitySteamHatch(gregtechId("steam_hatch"))); SIMPLE_ORE_WASHER = GregTechAPI.registerMetaTileEntity(1653, new MetaTileEntitySimpleOreWasher(gregtechId("ore_washer.simple"), RecipeMaps.SIMPLE_WASHER_RECIPES, Textures.ORE_WASHER_OVERLAY, 0)); + CLIPBOARD_TILE = GregTechAPI.registerMetaTileEntity(1636, new MetaTileEntityClipboard(gregtechId("clipboard"))); + /* * FOR ADDON DEVELOPERS: * diff --git a/src/main/java/gregtech/common/metatileentities/MetaTileEntityClipboard.java b/src/main/java/gregtech/common/metatileentities/MetaTileEntityClipboard.java new file mode 100644 index 00000000000..d5175cb3827 --- /dev/null +++ b/src/main/java/gregtech/common/metatileentities/MetaTileEntityClipboard.java @@ -0,0 +1,421 @@ +package gregtech.common.metatileentities; + +import codechicken.lib.raytracer.CuboidRayTraceResult; +import codechicken.lib.raytracer.IndexedCuboid6; +import codechicken.lib.render.CCRenderState; +import codechicken.lib.render.pipeline.IVertexOperation; +import codechicken.lib.vec.Cuboid6; +import codechicken.lib.vec.Matrix4; +import codechicken.lib.vec.Vector3; +import gregtech.api.block.BlockCustomParticle; +import gregtech.api.gui.ModularUI; +import gregtech.api.gui.Widget; +import gregtech.api.gui.impl.FakeModularGui; +import gregtech.api.items.gui.PlayerInventoryHolder; +import gregtech.api.items.itemhandlers.InaccessibleItemStackHandler; +import gregtech.api.items.metaitem.MetaItem; +import gregtech.api.items.metaitem.stats.IItemBehaviour; +import gregtech.api.metatileentity.*; +import gregtech.api.util.GTLog; +import gregtech.api.util.GTUtility; +import gregtech.api.util.GregFakePlayer; +import gregtech.common.gui.impl.FakeModularUIContainerClipboard; +import gregtech.common.items.behaviors.ClipboardBehavior; +import net.minecraft.block.Block; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTBase; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagInt; +import net.minecraft.network.PacketBuffer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.*; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; +import org.apache.commons.lang3.tuple.Pair; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import static codechicken.lib.raytracer.RayTracer.*; +import static gregtech.api.render.Textures.CLIPBOARD_RENDERER; +import static gregtech.common.items.MetaItems.CLIPBOARD; + +public class MetaTileEntityClipboard extends MetaTileEntity implements IRenderMetaTileEntity, IFastRenderMetaTileEntity { + private static final AxisAlignedBB CLIPBOARD_AABB = new AxisAlignedBB(2.75 / 16.0, 0.0, 0.0, 13.25 / 16.0, 1.0, 0.4 / 16.0); + public static final float scale = 1; + public FakeModularGui guiCache; + public FakeModularUIContainerClipboard guiContainerCache; + private static final Cuboid6 pageBox = new Cuboid6(3 / 16.0, 0.25 / 16.0, 0.25 / 16.0, 13 / 16.0, 14.25 / 16.0, 0.3 / 16.0); + + private static final int RENDER_PASS_NORMAL = 0; + private static final NBTBase NO_CLIPBOARD_SIG = new NBTTagInt(0); + + + public MetaTileEntityClipboard(ResourceLocation metaTileEntityId) { + super(metaTileEntityId); + } + + @Override + public void update() { + super.update(); + if (this.getWorld().isRemote) { + if (guiCache != null) + guiCache.updateScreen(); + } else { + if (getOffsetTimer() % 20 == 0) + createFakeGui(); + if (guiContainerCache != null) + guiContainerCache.detectAndSendChanges(); + } + } + + @Override + public int getLightOpacity() { + return 0; + } + + @Override + public void renderMetaTileEntityDynamic(double x, double y, double z, float partialTicks) { + if (this.getClipboard() != null) + CLIPBOARD_RENDERER.renderGUI(x, y, z, this.getFrontFacing(), this, partialTicks); + } + + @Override + public void renderMetaTileEntityFast(CCRenderState renderState, Matrix4 translation, float partialTicks) { + CLIPBOARD_RENDERER.renderBoard(renderState, translation.copy(), new IVertexOperation[]{}, getFrontFacing(), this, partialTicks); + } + + public AxisAlignedBB getRenderBoundingBox() { + return new AxisAlignedBB(getPos().add(-1, 0, -1), getPos().add(2, 2, 2)); + } + + @Override + public boolean shouldRenderInPass(int pass) { + return pass == RENDER_PASS_NORMAL; + } + + @Override + public boolean isGlobalRenderer() { + return true; + } + + @Override + public boolean isOpaqueCube() { + return false; + } + + @Override + public MetaTileEntity createMetaTileEntity(MetaTileEntityHolder holder) { + return new MetaTileEntityClipboard(metaTileEntityId); + } + + @Override + public ModularUI createUI(EntityPlayer entityPlayer) { + if (getClipboard().isItemEqual(CLIPBOARD.getStackForm())) { + List behaviours = ((MetaItem) getClipboard().getItem()).getBehaviours(getClipboard()); + Optional clipboardBehaviour = behaviours.stream().filter((x) -> x instanceof ClipboardBehavior).findFirst(); + if (!clipboardBehaviour.isPresent()) + return null; + if (clipboardBehaviour.get() instanceof ClipboardBehavior) { + PlayerInventoryHolder holder = new PlayerInventoryHolder(new GregFakePlayer(entityPlayer.world), EnumHand.MAIN_HAND); // We can't have this actually set the player's hand + holder.setCurrentItem(this.getClipboard()); + if(entityPlayer instanceof GregFakePlayer) { // This is how to tell if this is being called in-world or not + return ((ClipboardBehavior) clipboardBehaviour.get()).createMTEUI(holder, entityPlayer); + } else { + return ((ClipboardBehavior) clipboardBehaviour.get()).createUI(holder, entityPlayer); + } + } + } + return null; + } + + public void createFakeGui() { + // Basically just the original function from the PluginBehavior, but with a lot of now useless stuff stripped out. + try { + GregFakePlayer fakePlayer = new GregFakePlayer(this.getWorld()); + fakePlayer.setHeldItem(EnumHand.MAIN_HAND, this.getClipboard()); + ModularUI ui = this.createUI(fakePlayer); + + ModularUI.Builder builder = new ModularUI.Builder(ui.backgroundPath, ui.getWidth(), ui.getHeight()); + + List widgets = new ArrayList<>(ui.guiWidgets.values()); + + for (Widget widget : widgets) { + builder.widget(widget); + } + ui = builder.build(ui.holder, ui.entityPlayer); + FakeModularUIContainerClipboard fakeModularUIContainer = new FakeModularUIContainerClipboard(ui, this); + this.guiContainerCache = fakeModularUIContainer; + this.guiCache = new FakeModularGui(ui, fakeModularUIContainer); + this.writeCustomData(1, buffer -> { }); + } catch (Exception e) { + GTLog.logger.error(e); + } + } + + + @Override + protected void initializeInventory() { + super.initializeInventory(); + this.itemInventory = new InaccessibleItemStackHandler(); + } + + public ItemStack getClipboard() { + if (this.itemInventory.getStackInSlot(0) == ItemStack.EMPTY) { + ((InaccessibleItemStackHandler) this.itemInventory).setStackInSlot(0, CLIPBOARD.getStackForm()); + } + return this.itemInventory.getStackInSlot(0); + } + + public void setClipboard(ItemStack stack) { + ((InaccessibleItemStackHandler) this.itemInventory).setStackInSlot(0, stack.copy()); + } + + @Override + public void getDrops(NonNullList dropsList, @Nullable EntityPlayer harvester) { + dropsList.clear(); + dropsList.add(this.getClipboard()); + } + + @Override + public float getBlockHardness() { + return 100; + } + + @Override + public int getHarvestLevel() { + return 4; + } + + @Override + public boolean onRightClick(EntityPlayer playerIn, EnumHand hand, EnumFacing facing, CuboidRayTraceResult hitResult) { + if (!playerIn.isSneaking()) { + if (getWorld() != null && !getWorld().isRemote) { + MetaTileEntityUIFactory.INSTANCE.openUI(getHolder(), (EntityPlayerMP) playerIn); + } + } else { + BlockPos pos = this.getPos(); // Saving this for later so it doesn't get mangled + World world = this.getWorld(); // Same here + + NonNullList drops = NonNullList.create(); + getDrops(drops, playerIn); + + Block.spawnAsEntity(playerIn.world, this.getPos(), drops.get(0)); + this.dropAllCovers(); + this.onRemoval(); + + world.removeTileEntity(pos); + world.setBlockState(pos, Blocks.AIR.getDefaultState(), 3); + } + return true; + } + + + @Override + public String getHarvestTool() { + return "axe"; + } + + @Override + public void addCollisionBoundingBox(List collisionList) { + collisionList.add(new IndexedCuboid6(null, GTUtility.rotateAroundYAxis(CLIPBOARD_AABB, EnumFacing.NORTH, this.getFrontFacing()))); + } + + public IndexedCuboid6 getPageCuboid() { + return new IndexedCuboid6(null, GTUtility.rotateAroundYAxis(pageBox.aabb(), EnumFacing.NORTH, this.getFrontFacing())); + } + + @Override + public Pair getParticleTexture() { + return Pair.of(CLIPBOARD_RENDERER.getParticleTexture(), 0xFFFFFF); + } + + public Pair checkLookingAt() { + EntityPlayer player = Minecraft.getMinecraft().player; + if (this.getWorld() != null && player != null) { + Vec3d startVec = getStartVec(player); + Vec3d endVec = getEndVec(player); + CuboidRayTraceResult rayTraceResult = rayTrace(this.getPos(), new Vector3(startVec), new Vector3(endVec), getPageCuboid()); + if (rayTraceResult != null && rayTraceResult.sideHit == this.getFrontFacing().getOpposite()) { + TileEntity tileEntity = this.getWorld().getTileEntity(rayTraceResult.getBlockPos()); + if (tileEntity instanceof MetaTileEntityHolder && ((MetaTileEntityHolder) tileEntity).getMetaTileEntity() instanceof MetaTileEntityClipboard) { + double[] pos = handleRayTraceResult(rayTraceResult, this.getFrontFacing().getOpposite()); + if (pos[0] >= 0 && pos[0] <= 1 && pos[1] >= 0 && pos[1] <= 1) + return Pair.of(pos[0], pos[1]); + } + } + } + return null; + } + + private double[] handleRayTraceResult(CuboidRayTraceResult rayTraceResult, EnumFacing spin) { + double x, y; + double dX = rayTraceResult.sideHit.getAxis() == EnumFacing.Axis.X + ? rayTraceResult.hitVec.z - rayTraceResult.getBlockPos().getZ() + : rayTraceResult.hitVec.x - rayTraceResult.getBlockPos().getX(); + double dY = rayTraceResult.sideHit.getAxis() == EnumFacing.Axis.Y + ? rayTraceResult.hitVec.z - rayTraceResult.getBlockPos().getZ() + : rayTraceResult.hitVec.y - rayTraceResult.getBlockPos().getY(); + if (spin == EnumFacing.NORTH) { + x = 1 - dX; + } else if (spin == EnumFacing.SOUTH) { + x = dX; + } else if (spin == EnumFacing.EAST) { + x = 1 - dX; + if (rayTraceResult.sideHit.getXOffset() < 0 || rayTraceResult.sideHit.getZOffset() > 0) { + x = 1 - x; + } + } else { + x = 1 - dX; + if (rayTraceResult.sideHit.getXOffset() < 0 || rayTraceResult.sideHit.getZOffset() > 0) { + x = 1 - x; + } + } + + y = 1 - dY; // Since y values are quite weird here + + // Scale these to be 0 - 1 + x -= 3.0 / 16; + y -= 1.75 / 16; + x /= 14.0 / 16; + y /= 14.0 / 16; + + return new double[]{x, y}; + } + + @Override + public NBTTagCompound writeToNBT(NBTTagCompound data) { + super.writeToNBT(data); + if (this.getClipboard() != null && this.getClipboard().getTagCompound() != null) + data.setTag("clipboardNBT", this.getClipboard().getTagCompound()); + else + data.setTag("clipboardNBT", NO_CLIPBOARD_SIG); + return data; + } + + + @Override + public void readFromNBT(NBTTagCompound data) { + super.readFromNBT(data); + NBTBase clipboardNBT = data.getTag("clipboardNBT"); + if (clipboardNBT != NO_CLIPBOARD_SIG && clipboardNBT instanceof NBTTagCompound) { + ItemStack clipboard = this.getClipboard(); + clipboard.setTagCompound((NBTTagCompound) clipboardNBT); + this.setClipboard(clipboard); + } + } + + @Override + public void writeInitialSyncData(PacketBuffer buf) { + super.writeInitialSyncData(buf); + if (this.getClipboard() != null && this.getClipboard().getTagCompound() != null) + buf.writeCompoundTag(this.getClipboard().getTagCompound()); + else { + buf.writeCompoundTag(new NBTTagCompound()); + } + } + + @Override + public void receiveInitialSyncData(PacketBuffer buf) { + super.receiveInitialSyncData(buf); + try { + NBTTagCompound clipboardNBT = buf.readCompoundTag(); + if (clipboardNBT != new NBTTagCompound() && clipboardNBT != null) { + ItemStack clipboard = this.getClipboard(); + clipboard.setTagCompound(clipboardNBT); + this.setClipboard(clipboard); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void receiveCustomData(int dataId, PacketBuffer buf) { + super.receiveCustomData(dataId, buf); + if (dataId == 0) { + int windowID = buf.readVarInt(); + int widgetID = buf.readVarInt(); + if (guiCache != null) + guiCache.handleWidgetUpdate(windowID, widgetID, buf); + this.scheduleRenderUpdate(); + } else if (dataId == 1) { + createFakeGui(); + this.scheduleRenderUpdate(); + } else if (dataId == 2) { + int mouseX = buf.readVarInt(); + int mouseY = buf.readVarInt(); + if (guiCache != null && guiContainerCache != null) { + guiCache.mouseClicked(mouseX, mouseY, 0); // Left mouse button + } + this.scheduleRenderUpdate(); + } + } + + @Override + public void preInit(Object... data) { + if (data.length != 0 && data[0] instanceof ItemStack) + this.setClipboard((ItemStack) data[0]); + } + + @Override + public void getSubItems(CreativeTabs creativeTab, NonNullList subItems) { // JEI shouldn't show this + } + + @Override + public void renderMetaTileEntity(CCRenderState renderState, Matrix4 translation, IVertexOperation[] pipeline) { + } + + public void readUIAction(EntityPlayerMP player, int id, PacketBuffer buf) { + if (id == 1) { + if (this.guiContainerCache != null) { + guiContainerCache.handleClientAction(buf); + } + } + } + + @Override + public void onLeftClick(EntityPlayer player, EnumFacing facing, CuboidRayTraceResult hitResult) { + if (this.getWorld().isRemote) return; + Pair clickCoords = this.checkLookingAt(); + if (this.guiContainerCache != null && guiContainerCache.modularUI != null) { + int width = guiContainerCache.modularUI.getWidth(); + int height = guiContainerCache.modularUI.getHeight(); + double scale = 1.0 / Math.max(width, height); + int mouseX = (int) ((clickCoords.getLeft() / scale)); + int mouseY = (int) ((clickCoords.getRight() / scale)); + if (0 <= mouseX && mouseX <= width && 0 <= mouseY && mouseY <= height) { + this.writeCustomData(2, buf -> { + buf.writeVarInt(mouseX); + buf.writeVarInt(mouseY); + }); + } + } + + } + + @Override + public boolean canPlaceCoverOnSide(EnumFacing side) { + return false; + } + + @Override + public boolean canRenderMachineGrid() { + return false; + } + + @Override + public ItemStack getPickItem(CuboidRayTraceResult result, EntityPlayer player) { + return this.getClipboard(); + } +} diff --git a/src/main/java/gregtech/common/render/WrenchOverlayRenderer.java b/src/main/java/gregtech/common/render/WrenchOverlayRenderer.java index 3222e6aead3..eff34535b33 100644 --- a/src/main/java/gregtech/common/render/WrenchOverlayRenderer.java +++ b/src/main/java/gregtech/common/render/WrenchOverlayRenderer.java @@ -4,6 +4,7 @@ import codechicken.lib.vec.Vector3; import gregtech.api.capability.GregtechCapabilities; import gregtech.api.capability.GregtechTileCapabilities; +import gregtech.api.cover.ICoverable; import gregtech.api.cover.ICoverable.PrimaryBoxData; import gregtech.api.metatileentity.MetaTileEntityHolder; import gregtech.api.pipenet.tile.TileEntityPipeBase; @@ -92,6 +93,11 @@ public static boolean useGridForRayTraceResult(RayTraceResult result) { } public static boolean shouldDrawOverlayForItem(ItemStack itemStack, TileEntity tileEntity) { + if (tileEntity instanceof MetaTileEntityHolder) { + if(!((MetaTileEntityHolder) tileEntity).getMetaTileEntity().canRenderMachineGrid()) + return false; + } + if (tileEntity instanceof TileEntityPipeBase) { TileEntityPipeBase pipeTE = (TileEntityPipeBase) tileEntity; Class pipeClass = pipeTE.getPipeBlock().getPipeTypeClass(); diff --git a/src/main/java/gregtech/loaders/recipe/CraftingRecipeLoader.java b/src/main/java/gregtech/loaders/recipe/CraftingRecipeLoader.java index b8cf97ddc22..0795b8a96a4 100644 --- a/src/main/java/gregtech/loaders/recipe/CraftingRecipeLoader.java +++ b/src/main/java/gregtech/loaders/recipe/CraftingRecipeLoader.java @@ -64,6 +64,8 @@ private static void loadCraftingRecipes() { ModHandler.addSmeltingRecipe(new UnificationEntry(OrePrefix.nugget, Materials.Iron), OreDictUnifier.get(OrePrefix.nugget, Materials.WroughtIron)); + ModHandler.addShapedRecipe("clipboard", MetaItems.CLIPBOARD.getStackForm(), " Sd", "BWR", "PPP", 'P', Items.PAPER, 'R', new UnificationEntry(OrePrefix.springSmall, Iron), 'B', new UnificationEntry(OrePrefix.bolt, Iron), 'S', new UnificationEntry(OrePrefix.screw, Iron), 'W', new UnificationEntry(OrePrefix.plate, Wood)); + for (MetaValueItem batteryItem : ToolRecipeHandler.batteryItems[0]) { ModHandler.addShapedEnergyTransferRecipe("scanner_" + batteryItem.unlocalizedName, MetaItems.SCANNER.getStackForm(), batteryItem::isItemEqual, true, diff --git a/src/main/resources/assets/gregtech/blockstates/clipboard.json b/src/main/resources/assets/gregtech/blockstates/clipboard.json new file mode 100644 index 00000000000..607049158bf --- /dev/null +++ b/src/main/resources/assets/gregtech/blockstates/clipboard.json @@ -0,0 +1,10 @@ +{ + "forge_marker": 1, + "defaults": { + "model": "gregtech:clipboard" + }, + "variants": { + "normal": [{}], + "inventory": [{}] + } +} \ No newline at end of file diff --git a/src/main/resources/assets/gregtech/lang/en_us.lang b/src/main/resources/assets/gregtech/lang/en_us.lang index 2b17ba266c1..b07f882e64c 100644 --- a/src/main/resources/assets/gregtech/lang/en_us.lang +++ b/src/main/resources/assets/gregtech/lang/en_us.lang @@ -844,6 +844,9 @@ metaitem.turbine_rotor.name=%s Turbine Rotor metaitem.turbine_rotor.tooltip=Turbine Rotors for your power station metaitem.tool.magnifying_glass.name=%s Magnifying Glass +metaitem.clipboard.name=Clipboard +metaitem.clipboard.tooltip=Can be written on (without any writing Instrument). Right-click on Wall to place, and Shift-Right-Click to remove + metaitem.drill.mode.three_cube=3x3x3 Cube metaitem.drill.mode.five_cube=5x5x5 Cube metaitem.drill.mode.seven_cube=7x7x7 Cube @@ -2162,6 +2165,8 @@ gregtech.machine.stainless_steel_tank.name=Stainless Steel Tank gregtech.machine.titanium_tank.name=Titanium Tank gregtech.machine.tungstensteel_tank.name=Tungstensteel Tank +gregtech.machine.clipboard.name=Clipboard + # Granite blocks tile.granite.black_granite.normal.name=Black Granite tile.granite.black_granite.cracked.name=Black Granite Cobblestone diff --git a/src/main/resources/assets/gregtech/models/block/clipboard.json b/src/main/resources/assets/gregtech/models/block/clipboard.json new file mode 100644 index 00000000000..34b1288b6b3 --- /dev/null +++ b/src/main/resources/assets/gregtech/models/block/clipboard.json @@ -0,0 +1,97 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "0": "clipboard/clipboard", + "1": "clipboard/page", + "particle": "clipboard/clipboard" + }, + "elements": [ + { + "from": [3, 0.25, 0.25], + "to": [13, 14.25, 0.3], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 6.59375, 9.0125]}, + "faces": { + "north": {"uv": [8.5, 8.5, 13.5, 15.5], "texture": "#0"}, + "east": {"uv": [8.5, 8.5, 8.55, 15.5], "texture": "#0"}, + "south": {"uv": [0, 0, 11.42857, 16], "texture": "#1"}, + "west": {"uv": [8.5, 8.5, 8.55, 15.5], "texture": "#0"}, + "up": {"uv": [8.5, 8.5, 13.5, 8.55], "rotation": 180, "texture": "#0"}, + "down": {"uv": [8.5, 8.5, 13.5, 8.55], "rotation": 180, "texture": "#0"} + } + }, + { + "from": [2.75, 0, 0], + "to": [13.25, 15.25, 0.25], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 6.59375, 9.0125]}, + "faces": { + "north": {"uv": [8.5, 0, 14, 7.75], "texture": "#0"}, + "east": {"uv": [8.5, 0, 8.75, 7.75], "texture": "#0"}, + "south": {"uv": [8.5, 0, 14, 7.75], "texture": "#0"}, + "west": {"uv": [8.5, 0, 8.75, 7.75], "texture": "#0"}, + "up": {"uv": [8.5, 0.5, 14, 0.75], "rotation": 180, "texture": "#0"}, + "down": {"uv": [8.5, 0.5, 14, 0.75], "rotation": 180, "texture": "#0"} + } + }, + { + "from": [5.75, 14.75, 0.25], + "to": [10.25, 15.5, 0.4], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 6.59375, 9.0125]}, + "faces": { + "north": {"uv": [0.5, 0.5, 4, 1.25], "texture": "#0"}, + "east": {"uv": [0.5, 0.5, 0.65, 1.25], "texture": "#0"}, + "south": {"uv": [0.5, 0.5, 4, 1.25], "texture": "#0"}, + "west": {"uv": [0.5, 0.5, 0.65, 1.25], "texture": "#0"}, + "up": {"uv": [0.5, 0.5, 4, 0.65], "rotation": 180, "texture": "#0"}, + "down": {"uv": [0.5, 0.5, 4, 0.65], "rotation": 180, "texture": "#0"} + } + }, + { + "from": [7, 15.25, 0.1], + "to": [9, 16, 0.35], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 6.59375, 9.0125]}, + "faces": { + "north": {"uv": [0.5, 0.5, 1.5, 1.25], "texture": "#0"}, + "east": {"uv": [0.5, 0.5, 0.75, 1.25], "texture": "#0"}, + "south": {"uv": [0.5, 0.5, 1.5, 1.25], "texture": "#0"}, + "west": {"uv": [0.5, 0.5, 0.75, 1.25], "texture": "#0"}, + "up": {"uv": [0.5, 0.5, 1.5, 0.75], "rotation": 180, "texture": "#0"}, + "down": {"uv": [0.5, 0.5, 1.5, 0.75], "rotation": 180, "texture": "#0"} + } + } + ], + "display": { + "thirdperson_righthand": { + "translation": [0, 4, 4], + "scale": [0.5, 0.5, 0.5] + }, + "thirdperson_lefthand": { + "translation": [0, 4, 4], + "scale": [0.5, 0.5, 0.5] + }, + "firstperson_righthand": { + "rotation": [-10, 0, 0], + "translation": [-1.5, 7.25, 7], + "scale": [0.5, 0.5, 0.5] + }, + "firstperson_lefthand": { + "rotation": [-10, 0, 0], + "translation": [-1.5, 7.25, 7], + "scale": [0.5, 0.5, 0.5] + }, + "ground": { + "translation": [0, 0.75, 4], + "scale": [0.5, 0.5, 0.5] + }, + "gui": { + "translation": [0.25, 0.25, 0] + }, + "head": { + "translation": [0, -8.25, 22.25], + "scale": [2, 2, 2] + }, + "fixed": { + "rotation": [0, -180, 0], + "translation": [0, 0.25, -8] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/gregtech/models/item/metaitems/clipboard.json b/src/main/resources/assets/gregtech/models/item/metaitems/clipboard.json new file mode 100644 index 00000000000..7be55aa10b1 --- /dev/null +++ b/src/main/resources/assets/gregtech/models/item/metaitems/clipboard.json @@ -0,0 +1,94 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "0": "gregtech:items/metaitems/clipboard/clipboard", + "1": "gregtech:items/metaitems/clipboard/page", + "particle": "gregtech:items/metaitems/clipboard/clipboard" + }, + "elements": [ + { + "from": [6, 1, 9.025], + "to": [11, 8, 9.075], + "rotation": {"angle": 0, "axis": "y", "origin": [8.5, 6.59375, 9.0125]}, + "faces": { + "north": {"uv": [8.5, 8.5, 13.5, 15.5], "texture": "#0"}, + "east": {"uv": [8.5, 8.5, 8.55, 15.5], "texture": "#0"}, + "south": {"uv": [0, 0, 11.42857, 16], "texture": "#1"}, + "west": {"uv": [8.5, 8.5, 8.55, 15.5], "texture": "#0"}, + "up": {"uv": [8.5, 8.5, 13.5, 8.55], "rotation": 180, "texture": "#0"}, + "down": {"uv": [8.5, 8.5, 13.5, 8.55], "rotation": 180, "texture": "#0"} + } + }, + { + "from": [5.75, 0.75, 8.775], + "to": [11.25, 8.5, 9.025], + "rotation": {"angle": 0, "axis": "y", "origin": [8.5, 6.59375, 9.0125]}, + "faces": { + "north": {"uv": [8.5, 0, 14, 7.75], "texture": "#0"}, + "east": {"uv": [8.5, 0, 8.75, 7.75], "texture": "#0"}, + "south": {"uv": [8.5, 0, 14, 7.75], "texture": "#0"}, + "west": {"uv": [8.5, 0, 8.75, 7.75], "texture": "#0"}, + "up": {"uv": [8.5, 0.5, 14, 0.75], "rotation": 180, "texture": "#0"}, + "down": {"uv": [8.5, 0.5, 14, 0.75], "rotation": 180, "texture": "#0"} + } + }, + { + "from": [6.75, 8, 9.025], + "to": [10.25, 8.75, 9.175], + "rotation": {"angle": 0, "axis": "y", "origin": [8.5, 6.59375, 9.0125]}, + "faces": { + "north": {"uv": [0.5, 0.5, 4, 1.25], "texture": "#0"}, + "east": {"uv": [0.5, 0.5, 0.65, 1.25], "texture": "#0"}, + "south": {"uv": [0.5, 0.5, 4, 1.25], "texture": "#0"}, + "west": {"uv": [0.5, 0.5, 0.65, 1.25], "texture": "#0"}, + "up": {"uv": [0.5, 0.5, 4, 0.65], "rotation": 180, "texture": "#0"}, + "down": {"uv": [0.5, 0.5, 4, 0.65], "rotation": 180, "texture": "#0"} + } + }, + { + "from": [8, 8.5, 8.875], + "to": [9, 9.25, 9.125], + "rotation": {"angle": 0, "axis": "y", "origin": [8.5, 6.59375, 9.0125]}, + "faces": { + "north": {"uv": [0.5, 0.5, 1.5, 1.25], "texture": "#0"}, + "east": {"uv": [0.5, 0.5, 0.75, 1.25], "texture": "#0"}, + "south": {"uv": [0.5, 0.5, 1.5, 1.25], "texture": "#0"}, + "west": {"uv": [0.5, 0.5, 0.75, 1.25], "texture": "#0"}, + "up": {"uv": [0.5, 0.5, 1.5, 0.75], "rotation": 180, "texture": "#0"}, + "down": {"uv": [0.5, 0.5, 1.5, 0.75], "rotation": 180, "texture": "#0"} + } + } + ], + "display": { + "thirdperson_righthand": { + "translation": [-0.5, 7, -0.5] + }, + "thirdperson_lefthand": { + "translation": [0.5, 7, -0.5] + }, + "firstperson_righthand": { + "rotation": [-10, 0, 0], + "translation": [-3, 10, 2.5] + }, + "firstperson_lefthand": { + "rotation": [-10, 0, 0], + "translation": [-2, 10, 2.5] + }, + "ground": { + "translation": [0, 3.75, 0] + }, + "gui": { + "translation": [-1, 5.5, 0], + "scale": [1.75, 1.75, 1.75] + }, + "head": { + "translation": [-1, 5.75, 5], + "scale": [2, 2, 2] + }, + "fixed": { + "rotation": [0, -180, 0], + "translation": [1.25, 8.25, 1.5], + "scale": [2.5, 2.5, 2.5] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/gregtech/textures/blocks/clipboard/clip.png b/src/main/resources/assets/gregtech/textures/blocks/clipboard/clip.png new file mode 100644 index 00000000000..fcc101e54f2 Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/blocks/clipboard/clip.png differ diff --git a/src/main/resources/assets/gregtech/textures/blocks/clipboard/page.png b/src/main/resources/assets/gregtech/textures/blocks/clipboard/page.png new file mode 100644 index 00000000000..8e29b159f84 Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/blocks/clipboard/page.png differ diff --git a/src/main/resources/assets/gregtech/textures/blocks/clipboard/wood.png b/src/main/resources/assets/gregtech/textures/blocks/clipboard/wood.png new file mode 100644 index 00000000000..304d851ba10 Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/blocks/clipboard/wood.png differ diff --git a/src/main/resources/assets/gregtech/textures/gui/base/blank.png b/src/main/resources/assets/gregtech/textures/gui/base/blank.png new file mode 100644 index 00000000000..598fdc2de57 Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/gui/base/blank.png differ diff --git a/src/main/resources/assets/gregtech/textures/gui/widget/clipboard_button.png b/src/main/resources/assets/gregtech/textures/gui/widget/clipboard_button.png new file mode 100644 index 00000000000..cc5d98d8aaa Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/gui/widget/clipboard_button.png differ diff --git a/src/main/resources/assets/gregtech/textures/gui/widget/clipboard_checkbox.png b/src/main/resources/assets/gregtech/textures/gui/widget/clipboard_checkbox.png new file mode 100644 index 00000000000..04b8efe7722 Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/gui/widget/clipboard_checkbox.png differ diff --git a/src/main/resources/assets/gregtech/textures/gui/widget/clipboard_text_box.png b/src/main/resources/assets/gregtech/textures/gui/widget/clipboard_text_box.png new file mode 100644 index 00000000000..21e4e0c365a Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/gui/widget/clipboard_text_box.png differ diff --git a/src/main/resources/assets/gregtech/textures/gui/widget/left.png b/src/main/resources/assets/gregtech/textures/gui/widget/left.png new file mode 100644 index 00000000000..3d32885b8b7 Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/gui/widget/left.png differ diff --git a/src/main/resources/assets/gregtech/textures/gui/widget/right.png b/src/main/resources/assets/gregtech/textures/gui/widget/right.png new file mode 100644 index 00000000000..9ad72849025 Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/gui/widget/right.png differ diff --git a/src/main/resources/assets/gregtech/textures/items/metaitems/clipboard/clipboard.png b/src/main/resources/assets/gregtech/textures/items/metaitems/clipboard/clipboard.png new file mode 100644 index 00000000000..af69676cc7f Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/items/metaitems/clipboard/clipboard.png differ diff --git a/src/main/resources/assets/gregtech/textures/items/metaitems/clipboard/page.png b/src/main/resources/assets/gregtech/textures/items/metaitems/clipboard/page.png new file mode 100644 index 00000000000..43ce38269e1 Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/items/metaitems/clipboard/page.png differ