Keeping notes

- Added the Clipboard
This commit is contained in:
simibubi 2023-03-25 21:11:07 +01:00
parent 36cd43997d
commit 9dd5cde745
24 changed files with 1068 additions and 3 deletions

View file

@ -566,8 +566,8 @@ bf2b0310500213ff853c748c236eb5d01f61658e assets/create/blockstates/yellow_toolbo
5616dda664dd106d576848124fc0fc1de18d0fd3 assets/create/blockstates/yellow_valve_handle.json 5616dda664dd106d576848124fc0fc1de18d0fd3 assets/create/blockstates/yellow_valve_handle.json
7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json 7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json
b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json
f1bedeb51c35e70a2247178634e61ea637a6622e assets/create/lang/en_ud.json 0f4e5a2fc58580df5b156fdac438ddeb6b57e386 assets/create/lang/en_ud.json
59fd557ef593efa3c7b783195ec5dc789eae1834 assets/create/lang/en_us.json 85d790bedbdc65bb6e6377edcc63e7b00455e879 assets/create/lang/en_us.json
487a511a01b2a4531fb672f917922312db78f958 assets/create/models/block/acacia_window.json 487a511a01b2a4531fb672f917922312db78f958 assets/create/models/block/acacia_window.json
b48060cba1a382f373a05bf0039054053eccf076 assets/create/models/block/acacia_window_pane_noside.json b48060cba1a382f373a05bf0039054053eccf076 assets/create/models/block/acacia_window_pane_noside.json
3066db1bf03cffa1a9c7fbacf47ae586632f4eb3 assets/create/models/block/acacia_window_pane_noside_alt.json 3066db1bf03cffa1a9c7fbacf47ae586632f4eb3 assets/create/models/block/acacia_window_pane_noside_alt.json
@ -1663,6 +1663,10 @@ f7aca6aff65e1de269a99cf2a280d9841b7a0076 assets/create/models/item/brass_sheet.j
87637b39c3a5a386457d52b37eb65f1c4bcabaf0 assets/create/models/item/chocolate_glazed_berries.json 87637b39c3a5a386457d52b37eb65f1c4bcabaf0 assets/create/models/item/chocolate_glazed_berries.json
fe67c3f380d17735a9436a4579a8be1a02b8e4a0 assets/create/models/item/chute.json fe67c3f380d17735a9436a4579a8be1a02b8e4a0 assets/create/models/item/chute.json
6680a68526576ded5dac2aa3bc9fb9de3e744146 assets/create/models/item/cinder_flour.json 6680a68526576ded5dac2aa3bc9fb9de3e744146 assets/create/models/item/cinder_flour.json
0f79260d962011817a41af8c46996f426669b089 assets/create/models/item/clipboard.json
1bd8ad56fe261f3ff2f7bb2ac12f691a76ae5c94 assets/create/models/item/clipboard_0.json
7a4d58451e051796e21138faf3428f3d3c14ef85 assets/create/models/item/clipboard_1.json
376e88de90f33fd32f3f2ffe0062ae5b3bdc1370 assets/create/models/item/clipboard_2.json
c1da21be9f1af4f7a2ef4ec9cd92195d65ada316 assets/create/models/item/clockwork_bearing.json c1da21be9f1af4f7a2ef4ec9cd92195d65ada316 assets/create/models/item/clockwork_bearing.json
0a2a0f0aafeab0088172f77afd40c1fa2cc1f2b8 assets/create/models/item/clutch.json 0a2a0f0aafeab0088172f77afd40c1fa2cc1f2b8 assets/create/models/item/clutch.json
dcb09deae110077bcddf090996b51cc66e9a7de3 assets/create/models/item/cogwheel.json dcb09deae110077bcddf090996b51cc66e9a7de3 assets/create/models/item/cogwheel.json

View file

@ -595,6 +595,7 @@
"item.create.chocolate_glazed_berries": "s\u01DD\u0131\u0279\u0279\u01DD\u15FA p\u01DDz\u0250\u05DF\u2141 \u01DD\u0287\u0250\u05DFo\u0254o\u0265\u0186", "item.create.chocolate_glazed_berries": "s\u01DD\u0131\u0279\u0279\u01DD\u15FA p\u01DDz\u0250\u05DF\u2141 \u01DD\u0287\u0250\u05DFo\u0254o\u0265\u0186",
"item.create.chromatic_compound": "punod\u026Fo\u0186 \u0254\u0131\u0287\u0250\u026Fo\u0279\u0265\u0186", "item.create.chromatic_compound": "punod\u026Fo\u0186 \u0254\u0131\u0287\u0250\u026Fo\u0279\u0265\u0186",
"item.create.cinder_flour": "\u0279no\u05DF\u2132 \u0279\u01DDpu\u0131\u0186", "item.create.cinder_flour": "\u0279no\u05DF\u2132 \u0279\u01DDpu\u0131\u0186",
"item.create.clipboard": "p\u0279\u0250oqd\u0131\u05DF\u0186",
"item.create.copper_backtank": "\u029Eu\u0250\u0287\u029E\u0254\u0250\u15FA \u0279\u01DDddo\u0186", "item.create.copper_backtank": "\u029Eu\u0250\u0287\u029E\u0254\u0250\u15FA \u0279\u01DDddo\u0186",
"item.create.copper_backtank_placeable": "\u01DD\u05DFq\u0250\u01DD\u0254\u0250\u05DF\u0500 \u029Eu\u0250\u0287\u029E\u0254\u0250\u15FA \u0279\u01DDddo\u0186", "item.create.copper_backtank_placeable": "\u01DD\u05DFq\u0250\u01DD\u0254\u0250\u05DF\u0500 \u029Eu\u0250\u0287\u029E\u0254\u0250\u15FA \u0279\u01DDddo\u0186",
"item.create.copper_diving_boots": "s\u0287oo\u15FA bu\u0131\u028C\u0131\u15E1 \u0279\u01DDddo\u0186", "item.create.copper_diving_boots": "s\u0287oo\u15FA bu\u0131\u028C\u0131\u15E1 \u0279\u01DDddo\u0186",

View file

@ -602,6 +602,7 @@
"item.create.chocolate_glazed_berries": "Chocolate Glazed Berries", "item.create.chocolate_glazed_berries": "Chocolate Glazed Berries",
"item.create.chromatic_compound": "Chromatic Compound", "item.create.chromatic_compound": "Chromatic Compound",
"item.create.cinder_flour": "Cinder Flour", "item.create.cinder_flour": "Cinder Flour",
"item.create.clipboard": "Clipboard",
"item.create.copper_backtank": "Copper Backtank", "item.create.copper_backtank": "Copper Backtank",
"item.create.copper_backtank_placeable": "Copper Backtank Placeable", "item.create.copper_backtank_placeable": "Copper Backtank Placeable",
"item.create.copper_diving_boots": "Copper Diving Boots", "item.create.copper_diving_boots": "Copper Diving Boots",
@ -1130,6 +1131,7 @@
"create.gui.sequenced_gearshift.speed.forward_fast": "Double speed, Forwards", "create.gui.sequenced_gearshift.speed.forward_fast": "Double speed, Forwards",
"create.gui.sequenced_gearshift.speed.back": "Input speed, Reversed", "create.gui.sequenced_gearshift.speed.back": "Input speed, Reversed",
"create.gui.sequenced_gearshift.speed.back_fast": "Double speed, Reversed", "create.gui.sequenced_gearshift.speed.back_fast": "Double speed, Reversed",
"create.gui.clipboard.erase_checked": "Erase checked items",
"create.schematicAndQuill.dimensions": "Schematic Size: %1$sx%2$sx%3$s", "create.schematicAndQuill.dimensions": "Schematic Size: %1$sx%2$sx%3$s",
"create.schematicAndQuill.firstPos": "First position set.", "create.schematicAndQuill.firstPos": "First position set.",

View file

@ -0,0 +1,26 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "create:item/clipboard"
},
"overrides": [
{
"predicate": {
"create:clipboard_type": 0.0
},
"model": "create:item/clipboard_0"
},
{
"predicate": {
"create:clipboard_type": 1.0
},
"model": "create:item/clipboard_1"
},
{
"predicate": {
"create:clipboard_type": 2.0
},
"model": "create:item/clipboard_2"
}
]
}

View file

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "create:item/empty_clipboard"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "create:item/clipboard"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "create:item/clipboard_and_quill"
}
}

View file

@ -39,6 +39,8 @@ import com.simibubi.create.content.curiosities.armor.BacktankItem;
import com.simibubi.create.content.curiosities.armor.BacktankItem.BacktankBlockItem; import com.simibubi.create.content.curiosities.armor.BacktankItem.BacktankBlockItem;
import com.simibubi.create.content.curiosities.armor.DivingBootsItem; import com.simibubi.create.content.curiosities.armor.DivingBootsItem;
import com.simibubi.create.content.curiosities.armor.DivingHelmetItem; import com.simibubi.create.content.curiosities.armor.DivingHelmetItem;
import com.simibubi.create.content.curiosities.clipboard.ClipboardItem;
import com.simibubi.create.content.curiosities.clipboard.ClipboardOverrides;
import com.simibubi.create.content.curiosities.symmetry.SymmetryWandItem; import com.simibubi.create.content.curiosities.symmetry.SymmetryWandItem;
import com.simibubi.create.content.curiosities.tools.BlueprintItem; import com.simibubi.create.content.curiosities.tools.BlueprintItem;
import com.simibubi.create.content.curiosities.tools.ExtendoGripItem; import com.simibubi.create.content.curiosities.tools.ExtendoGripItem;
@ -72,7 +74,10 @@ public class AllItems {
REGISTRATE.creativeModeTab(() -> AllCreativeModeTabs.BASE_CREATIVE_TAB); REGISTRATE.creativeModeTab(() -> AllCreativeModeTabs.BASE_CREATIVE_TAB);
} }
// Materials public static final ItemEntry<ClipboardItem> CLIPBOARD = REGISTRATE.item("clipboard", ClipboardItem::new)
.onRegister(ClipboardItem::registerModelOverrides)
.model((c, p) -> ClipboardOverrides.addOverrideModels(c, p))
.register();
public static final ItemEntry<Item> WHEAT_FLOUR = public static final ItemEntry<Item> WHEAT_FLOUR =
taggedIngredient("wheat_flour", forgeItemTag("flour/wheat"), forgeItemTag("flour")), taggedIngredient("wheat_flour", forgeItemTag("flour/wheat"), forgeItemTag("flour")),

View file

@ -0,0 +1,44 @@
package com.simibubi.create.content.curiosities.clipboard;
import com.simibubi.create.AllItems;
import com.simibubi.create.foundation.networking.SimplePacketBase;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.network.NetworkEvent.Context;
public class ClipboardEditPacket extends SimplePacketBase {
private int hotbarSlot;
private CompoundTag data;
public ClipboardEditPacket(int hotbarSlot, CompoundTag data) {
this.hotbarSlot = hotbarSlot;
this.data = data;
}
public ClipboardEditPacket(FriendlyByteBuf buffer) {
hotbarSlot = buffer.readVarInt();
data = buffer.readNbt();
}
@Override
public void write(FriendlyByteBuf buffer) {
buffer.writeVarInt(hotbarSlot);
buffer.writeNbt(data);
}
@Override
public boolean handle(Context context) {
ServerPlayer sender = context.getSender();
ItemStack itemStack = sender.getInventory()
.getItem(hotbarSlot);
if (!AllItems.CLIPBOARD.isIn(itemStack))
return true;
itemStack.setTag(data.isEmpty() ? null : data);
return true;
}
}

View file

@ -0,0 +1,52 @@
package com.simibubi.create.content.curiosities.clipboard;
import java.util.ArrayList;
import java.util.List;
import com.simibubi.create.foundation.utility.NBTHelper;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.world.item.ItemStack;
public class ClipboardEntry {
boolean checked;
MutableComponent text;
public ClipboardEntry(boolean checked, MutableComponent text) {
this.checked = checked;
this.text = text;
}
public static List<List<ClipboardEntry>> readAll(ItemStack clipboardItem) {
CompoundTag tag = clipboardItem.getTag();
if (tag == null)
return new ArrayList<>();
return NBTHelper.readCompoundList(tag.getList("Pages", Tag.TAG_COMPOUND), pageTag -> NBTHelper
.readCompoundList(pageTag.getList("Entries", Tag.TAG_COMPOUND), ClipboardEntry::readNBT));
}
public static void saveAll(List<List<ClipboardEntry>> entries, ItemStack clipboardItem) {
CompoundTag tag = clipboardItem.getOrCreateTag();
tag.put("Pages", NBTHelper.writeCompoundList(entries, list -> {
CompoundTag pageTag = new CompoundTag();
pageTag.put("Entries", NBTHelper.writeCompoundList(list, ClipboardEntry::writeNBT));
return pageTag;
}));
}
public CompoundTag writeNBT() {
CompoundTag nbt = new CompoundTag();
nbt.putBoolean("Checked", checked);
nbt.putString("Text", Component.Serializer.toJson(text));
return nbt;
}
public static ClipboardEntry readNBT(CompoundTag tag) {
return new ClipboardEntry(tag.getBoolean("Checked"), Component.Serializer.fromJson(tag.getString("Text")));
}
}

View file

@ -0,0 +1,62 @@
package com.simibubi.create.content.curiosities.clipboard;
import javax.annotation.Nonnull;
import com.simibubi.create.foundation.gui.ScreenOpener;
import net.minecraft.client.Minecraft;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.level.Level;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.fml.DistExecutor;
public class ClipboardItem extends Item {
public ClipboardItem(Properties pProperties) {
super(pProperties);
}
@Nonnull
@Override
public InteractionResult useOn(UseOnContext context) {
if (context.getPlayer() == null)
return InteractionResult.PASS;
return use(context.getLevel(), context.getPlayer(), context.getHand()).getResult();
}
@Override
public InteractionResultHolder<ItemStack> use(Level world, Player player, InteractionHand hand) {
ItemStack heldItem = player.getItemInHand(hand);
if (hand == InteractionHand.OFF_HAND)
return InteractionResultHolder.pass(heldItem);
player.getCooldowns()
.addCooldown(heldItem.getItem(), 10);
if (world.isClientSide)
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> openScreen(player, heldItem));
CompoundTag tag = heldItem.getOrCreateTag();
tag.putInt("Type", ClipboardOverrides.ClipboardType.EDITING.ordinal());
heldItem.setTag(tag);
return InteractionResultHolder.success(heldItem);
}
@OnlyIn(Dist.CLIENT)
private void openScreen(Player player, ItemStack stack) {
if (Minecraft.getInstance().player == player)
ScreenOpener.open(new ClipboardScreen(player.getInventory().selected, stack));
}
public void registerModelOverrides() {
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> ClipboardOverrides.registerModelOverridesClient(this));
}
}

View file

@ -0,0 +1,57 @@
package com.simibubi.create.content.curiosities.clipboard;
import com.simibubi.create.Create;
import com.tterrag.registrate.providers.DataGenContext;
import com.tterrag.registrate.providers.RegistrateItemModelProvider;
import net.minecraft.client.renderer.item.ItemProperties;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.client.model.generators.ItemModelBuilder;
import net.minecraftforge.client.model.generators.ModelFile.UncheckedModelFile;
public class ClipboardOverrides {
public enum ClipboardType {
EMPTY("empty_clipboard"), WRITTEN("clipboard"), EDITING("clipboard_and_quill");
public String file;
public static ResourceLocation ID = Create.asResource("clipboard_type");
private ClipboardType(String file) {
this.file = file;
}
}
public static void switchTo(ClipboardType type, ItemStack clipboardItem) {
CompoundTag tag = clipboardItem.getOrCreateTag();
tag.putInt("Type", type.ordinal());
}
@OnlyIn(Dist.CLIENT)
public static void registerModelOverridesClient(ClipboardItem item) {
ItemProperties.register(item, ClipboardType.ID, (pStack, pLevel, pEntity, pSeed) -> {
CompoundTag tag = pStack.getTag();
return tag == null ? 0 : tag.getInt("Type");
});
}
public static ItemModelBuilder addOverrideModels(DataGenContext<Item, ClipboardItem> c,
RegistrateItemModelProvider p) {
ItemModelBuilder builder = p.generated(() -> c.get());
for (int i = 0; i < ClipboardType.values().length; i++) {
builder.override()
.predicate(ClipboardType.ID, i)
.model(p.getBuilder(c.getName() + "_" + i)
.parent(new UncheckedModelFile("item/generated"))
.texture("layer0", Create.asResource("item/" + ClipboardType.values()[i].file)))
.end();
}
return builder;
}
}

View file

@ -0,0 +1,775 @@
package com.simibubi.create.content.curiosities.clipboard;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.mutable.MutableBoolean;
import org.apache.commons.lang3.mutable.MutableInt;
import com.google.common.collect.Lists;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.BufferBuilder;
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.Tesselator;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.simibubi.create.content.curiosities.clipboard.ClipboardOverrides.ClipboardType;
import com.simibubi.create.foundation.gui.AbstractSimiScreen;
import com.simibubi.create.foundation.gui.AllGuiTextures;
import com.simibubi.create.foundation.gui.AllIcons;
import com.simibubi.create.foundation.gui.widget.IconButton;
import com.simibubi.create.foundation.networking.AllPackets;
import com.simibubi.create.foundation.utility.Components;
import com.simibubi.create.foundation.utility.Lang;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import net.minecraft.SharedConstants;
import net.minecraft.Util;
import net.minecraft.client.StringSplitter;
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.GuiComponent;
import net.minecraft.client.gui.font.TextFieldHelper;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.gui.screens.inventory.PageButton;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.Rect2i;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.Style;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.util.FormattedCharSequence;
import net.minecraft.util.Mth;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
public class ClipboardScreen extends AbstractSimiScreen {
private ItemStack item;
List<List<ClipboardEntry>> pages;
List<ClipboardEntry> currentEntries;
int editingIndex;
int frameTick;
PageButton forward;
PageButton backward;
int currentPage;
long lastClickTime;
int lastIndex = -1;
int hoveredEntry;
boolean hoveredCheck;
DisplayCache displayCache = DisplayCache.EMPTY;
TextFieldHelper editContext;
IconButton closeBtn;
IconButton clearBtn;
private int targetSlot;
public ClipboardScreen(int targetSlot, ItemStack item) {
this.targetSlot = targetSlot;
this.item = item;
pages = ClipboardEntry.readAll(item);
if (pages.isEmpty())
pages.add(new ArrayList<>());
currentPage = item.getTag() == null ? 0
: item.getTag()
.getInt("PreviouslyOpenedPage");
currentPage = Mth.clamp(currentPage, 0, pages.size() - 1);
currentEntries = pages.get(currentPage);
boolean startEmpty = currentEntries.isEmpty();
if (startEmpty)
currentEntries.add(new ClipboardEntry(false, Components.empty()));
editingIndex = 0;
editContext = new TextFieldHelper(this::getCurrentEntryText, this::setCurrentEntryText, this::getClipboard,
this::setClipboard, this::validateTextForEntry);
editingIndex = startEmpty ? 0 : -1;
}
@Override
protected void init() {
setWindowSize(256, 256);
super.init();
minecraft.keyboardHandler.setSendRepeatsToGui(true);
clearDisplayCache();
int x = guiLeft;
int y = guiTop - 8;
clearWidgets();
clearBtn = new IconButton(x + 234, y + 153, AllIcons.I_CLEAR_CHECKED).withCallback(() -> {
editingIndex = -1;
currentEntries.removeIf(ce -> ce.checked);
if (currentEntries.isEmpty())
currentEntries.add(new ClipboardEntry(false, Components.empty()));
});
clearBtn.setToolTip(Lang.translateDirect("gui.clipboard.erase_checked"));
closeBtn = new IconButton(x + 234, y + 175, AllIcons.I_PRIORITY_VERY_LOW)
.withCallback(() -> minecraft.setScreen(null));
closeBtn.setToolTip(Lang.translateDirect("station.close"));
addRenderableWidget(closeBtn);
addRenderableWidget(clearBtn);
forward = new PageButton(x + 176, y + 229, true, $ -> changePage(true), true);
backward = new PageButton(x + 53, y + 229, false, $ -> changePage(false), true);
addRenderableWidget(forward);
addRenderableWidget(backward);
forward.visible = currentPage < 50;
backward.visible = currentPage > 0;
}
private int getNumPages() {
return pages.size();
}
public void tick() {
super.tick();
frameTick++;
int mx = (int) (this.minecraft.mouseHandler.xpos() * (double) this.minecraft.getWindow()
.getGuiScaledWidth() / (double) this.minecraft.getWindow()
.getScreenWidth());
int my = (int) (this.minecraft.mouseHandler.ypos() * (double) this.minecraft.getWindow()
.getGuiScaledHeight() / (double) this.minecraft.getWindow()
.getScreenHeight());
mx -= guiLeft + 35;
my -= guiTop + 41;
hoveredCheck = false;
hoveredEntry = -1;
if (mx > 0 && mx < 183 && my > 0 && my < 190) {
hoveredCheck = mx < 20;
int totalHeight = 0;
for (int i = 0; i < currentEntries.size(); i++) {
ClipboardEntry clipboardEntry = currentEntries.get(i);
String text = clipboardEntry.text.getString();
totalHeight += Math.max(12, font.split(Components.literal(text), 150)
.size() * 9 + 3);
if (totalHeight > my) {
hoveredEntry = i;
return;
}
}
hoveredEntry = currentEntries.size();
}
}
private String getCurrentEntryText() {
return currentEntries.get(editingIndex).text.getString();
}
private void setCurrentEntryText(String text) {
currentEntries.get(editingIndex).text = Components.literal(text);
}
private void setClipboard(String p_98148_) {
if (minecraft != null)
TextFieldHelper.setClipboardContents(minecraft, p_98148_);
}
private String getClipboard() {
return minecraft != null ? TextFieldHelper.getClipboardContents(minecraft) : "";
}
private boolean validateTextForEntry(String newText) {
int totalHeight = 0;
for (int i = 0; i < currentEntries.size(); i++) {
ClipboardEntry clipboardEntry = currentEntries.get(i);
String text = i == editingIndex ? newText : clipboardEntry.text.getString();
totalHeight += Math.max(12, font.split(Components.literal(text), 150)
.size() * 9 + 3);
}
return totalHeight < 185;
}
private int yOffsetOfEditingEntry() {
int totalHeight = 0;
for (int i = 0; i < currentEntries.size(); i++) {
if (i == editingIndex)
break;
ClipboardEntry clipboardEntry = currentEntries.get(i);
totalHeight += Math.max(12, font.split(clipboardEntry.text, 150)
.size() * 9 + 3);
}
return totalHeight;
}
private void changePage(boolean next) {
int previously = currentPage;
currentPage = Mth.clamp(currentPage + (next ? 1 : -1), 0, 50);
if (currentPage == previously)
return;
editingIndex = -1;
if (pages.size() <= currentPage)
pages.add(new ArrayList<>());
currentEntries = pages.get(currentPage);
if (currentEntries.isEmpty()) {
currentEntries.add(new ClipboardEntry(false, Components.empty()));
editingIndex = 0;
editContext.setCursorToEnd();
clearDisplayCacheAfterChange();
}
forward.visible = currentPage < 50;
backward.visible = currentPage > 0;
if (next)
return;
if (pages.get(currentPage + 1)
.stream()
.allMatch(ce -> ce.text.getString()
.isBlank()))
pages.remove(currentPage + 1);
}
@Override
protected void renderWindow(PoseStack ms, int mouseX, int mouseY, float partialTicks) {
int x = guiLeft;
int y = guiTop - 8;
AllGuiTextures.CLIPBOARD.render(ms, x, y);
font.draw(ms, new TranslatableComponent("book.pageIndicator", currentPage + 1, getNumPages()), x + 150, y + 9,
0x43ffffff);
for (int i = 0; i < currentEntries.size(); i++) {
ClipboardEntry clipboardEntry = currentEntries.get(i);
boolean checked = clipboardEntry.checked;
font.draw(ms, "\u25A1", x + 45, y + 51, checked ? 0x668D7F6B : 0xff8D7F6B);
if (checked)
font.draw(ms, "\u2714", x + 45, y + 50, 0x31B25D);
List<FormattedCharSequence> split = font.split(clipboardEntry.text, 150);
if (split.isEmpty()) {
y += 12;
continue;
}
for (FormattedCharSequence sequence : split) {
if (i != editingIndex)
font.draw(ms, sequence, x + 58, y + 50, checked ? 0x31B25D : 0x311A00);
y += 9;
}
y += 3;
}
if (editingIndex == -1)
return;
boolean checked = currentEntries.get(editingIndex).checked;
setFocused(null);
DisplayCache cache = getDisplayCache();
for (LineInfo line : cache.lines)
font.draw(ms, line.asComponent, line.x, line.y, checked ? 0x31B25D : 0x311A00);
renderHighlight(cache.selection);
renderCursor(ms, cache.cursor, cache.cursorAtEnd);
}
@Override
public void removed() {
minecraft.keyboardHandler.setSendRepeatsToGui(false);
pages.forEach(list -> list.removeIf(ce -> ce.text.getString()
.isBlank()));
pages.removeIf(List::isEmpty);
ClipboardEntry.saveAll(pages, item);
ClipboardOverrides.switchTo(ClipboardType.WRITTEN, item);
for (int i = 0; i < pages.size(); i++)
if (pages.get(i) == currentEntries)
item.getTag()
.putInt("PreviouslyOpenedPage", i);
if (pages.isEmpty())
item.setTag(new CompoundTag());
AllPackets.getChannel()
.sendToServer(new ClipboardEditPacket(targetSlot, item.getOrCreateTag()));
super.removed();
}
@Override
public boolean isPauseScreen() {
return false;
}
@Override
public boolean keyPressed(int pKeyCode, int pScanCode, int pModifiers) {
if (pKeyCode == 266) {
backward.onPress();
return true;
}
if (pKeyCode == 267) {
forward.onPress();
return true;
}
if (editingIndex != -1 && pKeyCode != 256) {
keyPressedWhileEditing(pKeyCode, pScanCode, pModifiers);
clearDisplayCache();
return true;
}
if (super.keyPressed(pKeyCode, pScanCode, pModifiers))
return true;
return true;
}
@Override
public boolean charTyped(char pCodePoint, int pModifiers) {
if (super.charTyped(pCodePoint, pModifiers))
return true;
if (!SharedConstants.isAllowedChatCharacter(pCodePoint))
return false;
if (editingIndex == -1)
return false;
editContext.insertText(Character.toString(pCodePoint));
clearDisplayCache();
return true;
}
private boolean keyPressedWhileEditing(int pKeyCode, int pScanCode, int pModifiers) {
if (Screen.isSelectAll(pKeyCode)) {
editContext.selectAll();
return true;
} else if (Screen.isCopy(pKeyCode)) {
editContext.copy();
return true;
} else if (Screen.isPaste(pKeyCode)) {
editContext.paste();
return true;
} else if (Screen.isCut(pKeyCode)) {
editContext.cut();
return true;
} else {
switch (pKeyCode) {
case 257:
case 335:
if (hasShiftDown()) {
editContext.insertText("\n");
return true;
} else if (!hasControlDown()) {
if (currentEntries.size() <= editingIndex + 1
|| !currentEntries.get(editingIndex + 1).text.getString()
.isEmpty())
currentEntries.add(editingIndex + 1, new ClipboardEntry(false, Components.empty()));
editingIndex += 1;
editContext.setCursorToEnd();
if (validateTextForEntry(" "))
return true;
currentEntries.remove(editingIndex);
editingIndex -= 1;
editContext.setCursorToEnd();
return true;
}
editingIndex = -1;
return true;
case 259:
if (currentEntries.get(editingIndex).text.getString()
.isEmpty() && currentEntries.size() > 1) {
currentEntries.remove(editingIndex);
editingIndex -= 1;
editContext.setCursorToEnd();
return true;
} else if (hasControlDown()) {
int prevPos = editContext.getCursorPos();
editContext.moveByWords(-1);
if (prevPos != editContext.getCursorPos())
editContext.removeCharsFromCursor(prevPos - editContext.getCursorPos());
return true;
}
editContext.removeCharsFromCursor(-1);
return true;
case 261:
if (hasControlDown()) {
int prevPos = editContext.getCursorPos();
editContext.moveByWords(1);
if (prevPos != editContext.getCursorPos())
editContext.removeCharsFromCursor(prevPos - editContext.getCursorPos());
return true;
}
editContext.removeCharsFromCursor(1);
return true;
case 262:
if (hasControlDown()) {
editContext.moveByWords(1, Screen.hasShiftDown());
return true;
}
editContext.moveByChars(1, Screen.hasShiftDown());
return true;
case 263:
if (hasControlDown()) {
editContext.moveByWords(-1, Screen.hasShiftDown());
return true;
}
editContext.moveByChars(-1, Screen.hasShiftDown());
return true;
case 264:
keyDown();
return true;
case 265:
keyUp();
return true;
case 268:
keyHome();
return true;
case 269:
keyEnd();
return true;
default:
return false;
}
}
}
private void keyUp() {
changeLine(-1);
}
private void keyDown() {
changeLine(1);
}
private void changeLine(int pYChange) {
int i = editContext.getCursorPos();
int j = getDisplayCache().changeLine(i, pYChange);
editContext.setCursorPos(j, Screen.hasShiftDown());
}
private void keyHome() {
int i = editContext.getCursorPos();
int j = getDisplayCache().findLineStart(i);
editContext.setCursorPos(j, Screen.hasShiftDown());
}
private void keyEnd() {
DisplayCache cache = getDisplayCache();
int i = editContext.getCursorPos();
int j = cache.findLineEnd(i);
editContext.setCursorPos(j, Screen.hasShiftDown());
}
private void renderCursor(PoseStack pPoseStack, Pos2i pCursorPos, boolean pIsEndOfText) {
if (frameTick / 6 % 2 != 0)
return;
pCursorPos = convertLocalToScreen(pCursorPos);
if (!pIsEndOfText) {
GuiComponent.fill(pPoseStack, pCursorPos.x, pCursorPos.y - 1, pCursorPos.x + 1, pCursorPos.y + 9,
-16777216);
} else {
font.draw(pPoseStack, "_", (float) pCursorPos.x, (float) pCursorPos.y, 0);
}
}
private void renderHighlight(Rect2i[] pSelected) {
Tesselator tesselator = Tesselator.getInstance();
BufferBuilder bufferbuilder = tesselator.getBuilder();
RenderSystem.setShader(GameRenderer::getPositionShader);
RenderSystem.setShaderColor(0.0F, 0.0F, 255.0F, 255.0F);
RenderSystem.disableTexture();
RenderSystem.enableColorLogicOp();
RenderSystem.logicOp(GlStateManager.LogicOp.OR_REVERSE);
bufferbuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION);
for (Rect2i rect2i : pSelected) {
int i = rect2i.getX();
int j = rect2i.getY();
int k = i + rect2i.getWidth();
int l = j + rect2i.getHeight();
bufferbuilder.vertex((double) i, (double) l, 0.0D)
.endVertex();
bufferbuilder.vertex((double) k, (double) l, 0.0D)
.endVertex();
bufferbuilder.vertex((double) k, (double) j, 0.0D)
.endVertex();
bufferbuilder.vertex((double) i, (double) j, 0.0D)
.endVertex();
}
tesselator.end();
RenderSystem.disableColorLogicOp();
RenderSystem.enableTexture();
}
private Pos2i convertScreenToLocal(Pos2i pScreenPos) {
return new Pos2i(pScreenPos.x - (width - 192) / 2 - 36 + 10, pScreenPos.y - 32 - 24 - yOffsetOfEditingEntry());
}
private Pos2i convertLocalToScreen(Pos2i pLocalScreenPos) {
return new Pos2i(pLocalScreenPos.x + (width - 192) / 2 + 36 - 10,
pLocalScreenPos.y + 32 + 24 + yOffsetOfEditingEntry());
}
public boolean mouseClicked(double pMouseX, double pMouseY, int pButton) {
if (super.mouseClicked(pMouseX, pMouseY, pButton))
return true;
if (pButton != 0)
return true;
if (hoveredEntry != -1) {
if (hoveredCheck) {
editingIndex = -1;
if (hoveredEntry < currentEntries.size())
currentEntries.get(hoveredEntry).checked ^= true;
return true;
}
if (hoveredEntry != editingIndex) {
editingIndex = hoveredEntry;
if (hoveredEntry >= currentEntries.size()) {
currentEntries.add(new ClipboardEntry(false, Components.empty()));
if (!validateTextForEntry(" ")) {
currentEntries.remove(hoveredEntry);
editingIndex = -1;
return true;
}
}
clearDisplayCacheAfterChange();
}
}
if (editingIndex == -1)
return false;
long i = Util.getMillis();
DisplayCache cache = getDisplayCache();
int j = cache.getIndexAtPosition(font, convertScreenToLocal(new Pos2i((int) pMouseX, (int) pMouseY)));
if (j >= 0) {
if (j == lastIndex && i - lastClickTime < 250L) {
if (!editContext.isSelecting()) {
selectWord(j);
} else {
editContext.selectAll();
}
} else {
editContext.setCursorPos(j, Screen.hasShiftDown());
}
clearDisplayCache();
}
lastIndex = j;
lastClickTime = i;
return true;
}
private void selectWord(int pIndex) {
String s = getCurrentEntryText();
editContext.setSelectionRange(StringSplitter.getWordPosition(s, -1, pIndex, false),
StringSplitter.getWordPosition(s, 1, pIndex, false));
}
public boolean mouseDragged(double pMouseX, double pMouseY, int pButton, double pDragX, double pDragY) {
if (super.mouseDragged(pMouseX, pMouseY, pButton, pDragX, pDragY))
return true;
if (pButton != 0)
return true;
if (editingIndex == -1)
return false;
DisplayCache cache = getDisplayCache();
int i = cache.getIndexAtPosition(font, convertScreenToLocal(new Pos2i((int) pMouseX, (int) pMouseY)));
editContext.setCursorPos(i, true);
clearDisplayCache();
return true;
}
private DisplayCache getDisplayCache() {
if (displayCache == null)
displayCache = rebuildDisplayCache();
return displayCache;
}
private void clearDisplayCache() {
displayCache = null;
}
private void clearDisplayCacheAfterChange() {
editContext.setCursorToEnd();
clearDisplayCache();
}
private DisplayCache rebuildDisplayCache() {
String s = getCurrentEntryText();
if (s.isEmpty())
return DisplayCache.EMPTY;
int i = editContext.getCursorPos();
int j = editContext.getSelectionPos();
IntList intlist = new IntArrayList();
List<LineInfo> list = Lists.newArrayList();
MutableInt mutableint = new MutableInt();
MutableBoolean mutableboolean = new MutableBoolean();
StringSplitter stringsplitter = font.getSplitter();
stringsplitter.splitLines(s, 150, Style.EMPTY, true, (p_98132_, p_98133_, p_98134_) -> {
int k3 = mutableint.getAndIncrement();
String s2 = s.substring(p_98133_, p_98134_);
mutableboolean.setValue(s2.endsWith("\n"));
String s3 = StringUtils.stripEnd(s2, " \n");
int l3 = k3 * 9;
Pos2i pos1 = convertLocalToScreen(new Pos2i(0, l3));
intlist.add(p_98133_);
list.add(new LineInfo(p_98132_, s3, pos1.x, pos1.y));
});
int[] aint = intlist.toIntArray();
boolean flag = i == s.length();
Pos2i pos;
if (flag && mutableboolean.isTrue()) {
pos = new Pos2i(0, list.size() * 9);
} else {
int k = findLineFromPos(aint, i);
int l = font.width(s.substring(aint[k], i));
pos = new Pos2i(l, k * 9);
}
List<Rect2i> list1 = Lists.newArrayList();
if (i != j) {
int l2 = Math.min(i, j);
int i1 = Math.max(i, j);
int j1 = findLineFromPos(aint, l2);
int k1 = findLineFromPos(aint, i1);
if (j1 == k1) {
int l1 = j1 * 9;
int i2 = aint[j1];
list1.add(createPartialLineSelection(s, stringsplitter, l2, i1, l1, i2));
} else {
int i3 = j1 + 1 > aint.length ? s.length() : aint[j1 + 1];
list1.add(createPartialLineSelection(s, stringsplitter, l2, i3, j1 * 9, aint[j1]));
for (int j3 = j1 + 1; j3 < k1; ++j3) {
int j2 = j3 * 9;
String s1 = s.substring(aint[j3], aint[j3 + 1]);
int k2 = (int) stringsplitter.stringWidth(s1);
list1.add(createSelection(new Pos2i(0, j2), new Pos2i(k2, j2 + 9)));
}
list1.add(createPartialLineSelection(s, stringsplitter, aint[k1], i1, k1 * 9, aint[k1]));
}
}
return new DisplayCache(s, pos, flag, aint, list.toArray(new LineInfo[0]), list1.toArray(new Rect2i[0]));
}
static int findLineFromPos(int[] pLineStarts, int pFind) {
int i = Arrays.binarySearch(pLineStarts, pFind);
return i < 0 ? -(i + 2) : i;
}
private Rect2i createPartialLineSelection(String pInput, StringSplitter pSplitter, int p_98122_, int p_98123_,
int p_98124_, int p_98125_) {
String s = pInput.substring(p_98125_, p_98122_);
String s1 = pInput.substring(p_98125_, p_98123_);
Pos2i firstPos = new Pos2i((int) pSplitter.stringWidth(s), p_98124_);
Pos2i secondPos = new Pos2i((int) pSplitter.stringWidth(s1), p_98124_ + 9);
return createSelection(firstPos, secondPos);
}
private Rect2i createSelection(Pos2i pCorner1, Pos2i pCorner2) {
Pos2i firstPos = convertLocalToScreen(pCorner1);
Pos2i secondPos = convertLocalToScreen(pCorner2);
int i = Math.min(firstPos.x, secondPos.x);
int j = Math.max(firstPos.x, secondPos.x);
int k = Math.min(firstPos.y, secondPos.y);
int l = Math.max(firstPos.y, secondPos.y);
return new Rect2i(i, k, j - i, l - k);
}
@OnlyIn(Dist.CLIENT)
static class DisplayCache {
static final DisplayCache EMPTY = new DisplayCache("", new Pos2i(0, 0), true, new int[] { 0 },
new LineInfo[] { new LineInfo(Style.EMPTY, "", 0, 0) }, new Rect2i[0]);
private final String fullText;
final Pos2i cursor;
final boolean cursorAtEnd;
private final int[] lineStarts;
final LineInfo[] lines;
final Rect2i[] selection;
public DisplayCache(String pFullText, Pos2i pCursor, boolean pCursorAtEnd, int[] pLineStarts, LineInfo[] pLines,
Rect2i[] pSelection) {
fullText = pFullText;
cursor = pCursor;
cursorAtEnd = pCursorAtEnd;
lineStarts = pLineStarts;
lines = pLines;
selection = pSelection;
}
public int getIndexAtPosition(Font pFont, Pos2i pCursorPosition) {
int i = pCursorPosition.y / 9;
if (i < 0)
return 0;
if (i >= lines.length)
return fullText.length();
LineInfo line = lines[i];
return lineStarts[i] + pFont.getSplitter()
.plainIndexAtWidth(line.contents, pCursorPosition.x, line.style);
}
public int changeLine(int pXChange, int pYChange) {
int i = findLineFromPos(lineStarts, pXChange);
int j = i + pYChange;
int k;
if (0 <= j && j < lineStarts.length) {
int l = pXChange - lineStarts[i];
int i1 = lines[j].contents.length();
k = lineStarts[j] + Math.min(l, i1);
} else {
k = pXChange;
}
return k;
}
public int findLineStart(int pLine) {
int i = findLineFromPos(lineStarts, pLine);
return lineStarts[i];
}
public int findLineEnd(int pLine) {
int i = findLineFromPos(lineStarts, pLine);
return lineStarts[i] + lines[i].contents.length();
}
}
@OnlyIn(Dist.CLIENT)
static class LineInfo {
final Style style;
final String contents;
final Component asComponent;
final int x;
final int y;
public LineInfo(Style pStyle, String pContents, int pX, int pY) {
style = pStyle;
contents = pContents;
x = pX;
y = pY;
asComponent = (new TextComponent(pContents)).setStyle(pStyle);
}
}
@OnlyIn(Dist.CLIENT)
static class Pos2i {
public final int x;
public final int y;
Pos2i(int pX, int pY) {
x = pX;
y = pY;
}
}
}

View file

@ -0,0 +1,11 @@
package com.simibubi.create.content.curiosities.clipboard;
import net.minecraft.SharedConstants;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.gui.screens.inventory.BookEditScreen;
public class ClipboardScreenHelper {
}

View file

@ -77,6 +77,8 @@ public enum AllGuiTextures implements ScreenElement {
LINKED_CONTROLLER("curiosities_2", 179, 109), LINKED_CONTROLLER("curiosities_2", 179, 109),
BLUEPRINT("curiosities_2", 0, 109, 179, 109), BLUEPRINT("curiosities_2", 0, 109, 179, 109),
CLIPBOARD("clipboard", 0, 0, 256, 256),
PROJECTOR("projector", 235, 185), PROJECTOR("projector", 235, 185),
PROJECTOR_FILTER_STRENGTH("projector", 0, 14, 162, 22), PROJECTOR_FILTER_STRENGTH("projector", 0, 14, 162, 22),
PROJECTOR_FILTER("projector", 0, 36, 162, 22), PROJECTOR_FILTER("projector", 0, 36, 162, 22),

View file

@ -128,6 +128,8 @@ public class AllIcons implements ScreenElement {
I_FOLLOW_DIAGONAL = next(), I_FOLLOW_DIAGONAL = next(),
I_FOLLOW_MATERIAL = next(), I_FOLLOW_MATERIAL = next(),
I_CLEAR_CHECKED = next(),
I_SCHEMATIC = newRow(), I_SCHEMATIC = newRow(),
I_SEQ_REPEAT = next(), I_SEQ_REPEAT = next(),

View file

@ -37,6 +37,7 @@ import com.simibubi.create.content.contraptions.relays.advanced.sequencer.Config
import com.simibubi.create.content.contraptions.relays.gauge.GaugeObservedPacket; import com.simibubi.create.content.contraptions.relays.gauge.GaugeObservedPacket;
import com.simibubi.create.content.curiosities.armor.NetheriteDivingHandler; import com.simibubi.create.content.curiosities.armor.NetheriteDivingHandler;
import com.simibubi.create.content.curiosities.bell.SoulPulseEffectPacket; import com.simibubi.create.content.curiosities.bell.SoulPulseEffectPacket;
import com.simibubi.create.content.curiosities.clipboard.ClipboardEditPacket;
import com.simibubi.create.content.curiosities.symmetry.ConfigureSymmetryWandPacket; import com.simibubi.create.content.curiosities.symmetry.ConfigureSymmetryWandPacket;
import com.simibubi.create.content.curiosities.symmetry.SymmetryEffectPacket; import com.simibubi.create.content.curiosities.symmetry.SymmetryEffectPacket;
import com.simibubi.create.content.curiosities.toolbox.ToolboxDisposeAllPacket; import com.simibubi.create.content.curiosities.toolbox.ToolboxDisposeAllPacket;
@ -157,6 +158,7 @@ public enum AllPackets {
REQUEST_FLOOR_LIST(ElevatorFloorListPacket.RequestFloorList.class, ElevatorFloorListPacket.RequestFloorList::new, REQUEST_FLOOR_LIST(ElevatorFloorListPacket.RequestFloorList.class, ElevatorFloorListPacket.RequestFloorList::new,
PLAY_TO_SERVER), PLAY_TO_SERVER),
ELEVATOR_SET_FLOOR(ElevatorTargetFloorPacket.class, ElevatorTargetFloorPacket::new, PLAY_TO_SERVER), ELEVATOR_SET_FLOOR(ElevatorTargetFloorPacket.class, ElevatorTargetFloorPacket::new, PLAY_TO_SERVER),
CLIPBOARD_EDIT(ClipboardEditPacket.class, ClipboardEditPacket::new, PLAY_TO_SERVER),
// Server to Client // Server to Client
SYMMETRY_EFFECT(SymmetryEffectPacket.class, SymmetryEffectPacket::new, PLAY_TO_CLIENT), SYMMETRY_EFFECT(SymmetryEffectPacket.class, SymmetryEffectPacket::new, PLAY_TO_CLIENT),

View file

@ -272,6 +272,8 @@
"create.gui.sequenced_gearshift.speed.back": "Input speed, Reversed", "create.gui.sequenced_gearshift.speed.back": "Input speed, Reversed",
"create.gui.sequenced_gearshift.speed.back_fast": "Double speed, Reversed", "create.gui.sequenced_gearshift.speed.back_fast": "Double speed, Reversed",
"create.gui.clipboard.erase_checked": "Erase checked items",
"create.schematicAndQuill.dimensions": "Schematic Size: %1$sx%2$sx%3$s", "create.schematicAndQuill.dimensions": "Schematic Size: %1$sx%2$sx%3$s",
"create.schematicAndQuill.firstPos": "First position set.", "create.schematicAndQuill.firstPos": "First position set.",
"create.schematicAndQuill.secondPos": "Second position set.", "create.schematicAndQuill.secondPos": "Second position set.",

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 290 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 332 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 B