样板终端增加系列按钮

This commit is contained in:
GaLi 2026-03-28 13:58:39 +08:00
parent 6d530b8f96
commit 87291b32cd
11 changed files with 711 additions and 0 deletions

View File

@ -0,0 +1,98 @@
package com.extendedae_plus.client.gui.widgets;
import appeng.client.gui.Icon;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.Tooltip;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
public class ScaledTextureButton extends Button {
private final OnPress delegateOnPress;
private final ResourceLocation texture;
private final int textureWidth;
private final int textureHeight;
private final int srcX;
private final int srcY;
private final int srcWidth;
private final int srcHeight;
private final float scale;
public ScaledTextureButton(ResourceLocation texture, int textureWidth, int textureHeight,
int srcX, int srcY, int srcWidth, int srcHeight, float scale,
Component tooltipText, OnPress onPress) {
super(0, 0, Math.round(srcWidth * scale), Math.round(srcHeight * scale),
Component.empty(), btn -> {
}, DEFAULT_NARRATION);
this.delegateOnPress = onPress;
this.texture = texture;
this.textureWidth = textureWidth;
this.textureHeight = textureHeight;
this.srcX = srcX;
this.srcY = srcY;
this.srcWidth = srcWidth;
this.srcHeight = srcHeight;
this.scale = scale;
if (tooltipText != null) {
this.setTooltip(Tooltip.create(tooltipText));
}
}
public void setVisibility(boolean visible) {
this.visible = visible;
this.active = visible;
}
@Override
public void onPress() {
this.delegateOnPress.onPress(this);
this.setFocused(false);
}
@Override
public void onClick(double mouseX, double mouseY) {
super.onClick(mouseX, mouseY);
this.setFocused(false);
}
@Override
public void onRelease(double mouseX, double mouseY) {
super.onRelease(mouseX, mouseY);
this.setFocused(false);
}
@Override
public void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) {
if (!this.visible) {
return;
}
this.width = Math.round(this.srcWidth * this.scale);
this.height = Math.round(this.srcHeight * this.scale);
int yOffset = this.isHovered() ? 1 : 0;
RenderSystem.disableDepthTest();
RenderSystem.enableBlend();
var pose = guiGraphics.pose();
pose.pushPose();
pose.translate(getX(), getY() + yOffset, 0.0F);
pose.scale(scale, scale, 1.0F);
Icon.TOOLBAR_BUTTON_BACKGROUND.getBlitter().dest(0, 0).blit(guiGraphics);
if (!this.active) {
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 0.5F);
}
guiGraphics.blit(this.texture, 0, 0, this.srcX, this.srcY, this.srcWidth, this.srcHeight,
this.textureWidth, this.textureHeight);
if (!this.active) {
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
}
pose.popPose();
RenderSystem.enableDepthTest();
}
}

View File

@ -58,6 +58,12 @@ public final class ModNetwork {
.consumerNetworkThread(EncodeWithShiftFlagC2SPacket::handle)
.add();
CHANNEL.messageBuilder(ScaleEncodingPatternC2SPacket.class, nextId(), NetworkDirection.PLAY_TO_SERVER)
.encoder(ScaleEncodingPatternC2SPacket::encode)
.decoder(ScaleEncodingPatternC2SPacket::decode)
.consumerNetworkThread(ScaleEncodingPatternC2SPacket::handle)
.add();
CHANNEL.messageBuilder(UploadEncodedPatternToProviderC2SPacket.class, nextId(), NetworkDirection.PLAY_TO_SERVER)
.encoder(UploadEncodedPatternToProviderC2SPacket::encode)
.decoder(UploadEncodedPatternToProviderC2SPacket::decode)

View File

@ -2,6 +2,7 @@ package com.extendedae_plus.mixin.ae2.accessor;
import appeng.menu.me.items.PatternEncodingTermMenu;
import appeng.menu.slot.RestrictedInputSlot;
import appeng.util.ConfigInventory;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@ -12,4 +13,10 @@ public interface PatternEncodingTermMenuAccessor {
@Accessor(value = "blankPatternSlot",remap = false)
RestrictedInputSlot eap$getBlankPatternSlot();
@Accessor(value = "encodedInputsInv", remap = false)
ConfigInventory eap$getEncodedInputsInv();
@Accessor(value = "encodedOutputsInv", remap = false)
ConfigInventory eap$getEncodedOutputsInv();
}

View File

@ -0,0 +1,232 @@
package com.extendedae_plus.mixin.ae2.client.gui;
import appeng.client.gui.AEBaseScreen;
import appeng.client.gui.me.items.PatternEncodingTermScreen;
import appeng.client.gui.style.ScreenStyle;
import appeng.client.gui.style.WidgetStyle;
import appeng.parts.encoding.EncodingMode;
import com.google.gson.JsonObject;
import com.extendedae_plus.ExtendedAEPlus;
import com.extendedae_plus.client.gui.widgets.ScaledTextureButton;
import com.extendedae_plus.init.ModNetwork;
import com.extendedae_plus.mixin.ae2.accessor.AEBaseScreenAccessor;
import com.extendedae_plus.mixin.minecraft.accessor.AbstractContainerScreenAccessor;
import com.extendedae_plus.mixin.minecraft.accessor.ScreenAccessor;
import com.extendedae_plus.network.ScaleEncodingPatternC2SPacket;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.Rect2i;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@SuppressWarnings({"AddedMixinMembersNamePattern"})
@Mixin(PatternEncodingTermScreen.class)
public abstract class PatternEncodingTermScaleButtonsMixin {
@Unique
private static final ResourceLocation EAP$SCALE_BUTTON_TEXTURE =
new ResourceLocation(ExtendedAEPlus.MODID, "textures/gui/beizeng.png");
@Unique
private static final ResourceLocation EAP$SWAP_OUTPUT_TEXTURE =
new ResourceLocation(ExtendedAEPlus.MODID, "textures/gui/zhu_fu_qie_huan.png");
@Unique
private static final ResourceLocation EAP$RESTORE_RATIO_TEXTURE =
new ResourceLocation(ExtendedAEPlus.MODID, "textures/gui/huanyuan.png");
@Unique
private static final ResourceLocation EAP$LAYOUT_RESOURCE =
new ResourceLocation("ae2", "screens/terminals/encoding/eaep_pattern_terminals.json");
@Unique private ScaledTextureButton eap$mul2Button;
@Unique private ScaledTextureButton eap$mul3Button;
@Unique private ScaledTextureButton eap$mul5Button;
@Unique private ScaledTextureButton eap$div2Button;
@Unique private ScaledTextureButton eap$div3Button;
@Unique private ScaledTextureButton eap$div5Button;
@Unique private ScaledTextureButton eap$swapOutputsButton;
@Unique private ScaledTextureButton eap$restoreRatioButton;
@Unique private static JsonObject eap$layoutWidgets;
@Unique private static boolean eap$layoutWidgetsLoaded;
@Inject(method = "<init>", at = @At("TAIL"))
private void eap$createScaleButtons(CallbackInfo ci) {
if (this.eap$mul2Button == null) {
this.eap$mul2Button = eap$createScaleButton(0, 0, "x2", ScaleEncodingPatternC2SPacket.Operation.MUL2);
this.eap$mul3Button = eap$createScaleButton(16, 0, "x3", ScaleEncodingPatternC2SPacket.Operation.MUL3);
this.eap$mul5Button = eap$createScaleButton(32, 0, "x5", ScaleEncodingPatternC2SPacket.Operation.MUL5);
this.eap$div2Button = eap$createScaleButton(0, 16, "/2", ScaleEncodingPatternC2SPacket.Operation.DIV2);
this.eap$div3Button = eap$createScaleButton(16, 16, "/3", ScaleEncodingPatternC2SPacket.Operation.DIV3);
this.eap$div5Button = eap$createScaleButton(32, 16, "/5", ScaleEncodingPatternC2SPacket.Operation.DIV5);
this.eap$swapOutputsButton = eap$createStandaloneButton(
EAP$SWAP_OUTPUT_TEXTURE, "主副切换", ScaleEncodingPatternC2SPacket.Operation.SWAP_OUTPUTS);
this.eap$restoreRatioButton = eap$createStandaloneButton(
EAP$RESTORE_RATIO_TEXTURE, "恢复比例", ScaleEncodingPatternC2SPacket.Operation.RESTORE_RATIO);
}
eap$ensureAdded(this.eap$mul2Button);
eap$ensureAdded(this.eap$mul3Button);
eap$ensureAdded(this.eap$mul5Button);
eap$ensureAdded(this.eap$div2Button);
eap$ensureAdded(this.eap$div3Button);
eap$ensureAdded(this.eap$div5Button);
eap$ensureAdded(this.eap$swapOutputsButton);
eap$ensureAdded(this.eap$restoreRatioButton);
}
@Inject(method = "updateBeforeRender", at = @At("TAIL"), remap = false)
private void eap$updateScaleButtons(CallbackInfo ci) {
if (this.eap$mul2Button == null) {
return;
}
var screen = (PatternEncodingTermScreen<?>) (Object) this;
eap$ensureAdded(this.eap$mul2Button);
eap$ensureAdded(this.eap$mul3Button);
eap$ensureAdded(this.eap$mul5Button);
eap$ensureAdded(this.eap$div2Button);
eap$ensureAdded(this.eap$div3Button);
eap$ensureAdded(this.eap$div5Button);
eap$ensureAdded(this.eap$swapOutputsButton);
eap$ensureAdded(this.eap$restoreRatioButton);
boolean visible = screen.getMenu().getMode() == EncodingMode.PROCESSING;
this.eap$mul2Button.setVisibility(visible);
this.eap$mul3Button.setVisibility(visible);
this.eap$mul5Button.setVisibility(visible);
this.eap$div2Button.setVisibility(visible);
this.eap$div3Button.setVisibility(visible);
this.eap$div5Button.setVisibility(visible);
this.eap$swapOutputsButton.setVisibility(visible);
this.eap$restoreRatioButton.setVisibility(visible);
if (!visible) {
return;
}
Rect2i bounds = eap$getScreenBounds();
eap$placeButton(this.eap$swapOutputsButton, "zhu_fu_qie_huan", bounds);
eap$placeButton(this.eap$restoreRatioButton, "huan_yuan_mo_ren", bounds);
eap$placeButton(this.eap$mul2Button, "cheng_2", bounds);
eap$placeButton(this.eap$mul3Button, "cheng_3", bounds);
eap$placeButton(this.eap$mul5Button, "cheng_5", bounds);
eap$placeButton(this.eap$div2Button, "chu_2", bounds);
eap$placeButton(this.eap$div3Button, "chu_3", bounds);
eap$placeButton(this.eap$div5Button, "chu_5", bounds);
}
@Unique
private ScaledTextureButton eap$createScaleButton(int srcX, int srcY, String tooltipText,
ScaleEncodingPatternC2SPacket.Operation op) {
return new ScaledTextureButton(
EAP$SCALE_BUTTON_TEXTURE,
48,
32,
srcX,
srcY,
16,
16,
0.375f,
Component.literal(tooltipText),
btn -> ModNetwork.CHANNEL.sendToServer(new ScaleEncodingPatternC2SPacket(op))
);
}
@Unique
private ScaledTextureButton eap$createStandaloneButton(ResourceLocation texture, String tooltipText,
ScaleEncodingPatternC2SPacket.Operation op) {
return new ScaledTextureButton(
texture,
16,
16,
0,
0,
16,
16,
0.375f,
Component.literal(tooltipText),
btn -> ModNetwork.CHANNEL.sendToServer(new ScaleEncodingPatternC2SPacket(op))
);
}
@Unique
private Rect2i eap$getScreenBounds() {
var screen = (AbstractContainerScreenAccessor<?>) this;
return new Rect2i(screen.eap$getLeftPos(), screen.eap$getTopPos(),
screen.eap$getImageWidth(), screen.eap$getImageHeight());
}
@Unique
private void eap$placeButton(ScaledTextureButton button, String widgetId, Rect2i bounds) {
try {
ScreenStyle style = ((AEBaseScreenAccessor<?>) this).eap$getStyle();
WidgetStyle widgetStyle = style.getWidget(widgetId);
var pos = widgetStyle.resolve(bounds);
button.setX(pos.getX());
button.setY(pos.getY());
} catch (IllegalStateException ignored) {
int left = eap$getFallbackWidgetValue(widgetId, "left");
int bottom = eap$getFallbackWidgetValue(widgetId, "bottom");
button.setX(bounds.getX() + left);
button.setY(bounds.getY() + bounds.getHeight() - bottom);
}
}
@Unique
private int eap$getFallbackWidgetValue(String widgetId, String key) {
JsonObject widget = eap$getFallbackWidget(widgetId);
if (widget != null && widget.has(key)) {
return widget.get(key).getAsInt();
}
return switch (widgetId + "#" + key) {
case "zhu_fu_qie_huan#left", "cheng_2#left", "cheng_3#left", "cheng_5#left" -> 125;
case "huan_yuan_mo_ren#left", "chu_2#left", "chu_3#left", "chu_5#left" -> 101;
case "zhu_fu_qie_huan#bottom", "huan_yuan_mo_ren#bottom" -> 159;
case "cheng_2#bottom", "chu_2#bottom" -> 149;
case "cheng_3#bottom", "chu_3#bottom" -> 138;
case "cheng_5#bottom", "chu_5#bottom" -> 127;
default -> 0;
};
}
@Unique
private JsonObject eap$getFallbackWidget(String widgetId) {
if (!eap$layoutWidgetsLoaded) {
eap$layoutWidgetsLoaded = true;
try {
var resourceManager = Minecraft.getInstance().getResourceManager();
try (var reader = resourceManager.openAsReader(EAP$LAYOUT_RESOURCE)) {
JsonObject root = ScreenStyle.GSON.fromJson(reader, JsonObject.class);
if (root != null && root.has("widgets") && root.get("widgets").isJsonObject()) {
eap$layoutWidgets = root.getAsJsonObject("widgets");
}
}
} catch (Exception ignored) {
eap$layoutWidgets = null;
}
}
if (eap$layoutWidgets == null || !eap$layoutWidgets.has(widgetId)) {
return null;
}
var widget = eap$layoutWidgets.get(widgetId);
return widget != null && widget.isJsonObject() ? widget.getAsJsonObject() : null;
}
@Unique
private void eap$ensureAdded(ScaledTextureButton button) {
var accessor = (ScreenAccessor) this;
var renderables = accessor.eap$getRenderables();
var children = accessor.eap$getChildren();
if (!renderables.contains(button)) {
renderables.add(button);
}
if (!children.contains(button)) {
children.add(button);
}
}
}

View File

@ -0,0 +1,212 @@
package com.extendedae_plus.network;
import appeng.api.stacks.GenericStack;
import appeng.menu.me.items.PatternEncodingTermMenu;
import appeng.menu.slot.FakeSlot;
import appeng.parts.encoding.EncodingMode;
import appeng.util.ConfigInventory;
import com.extendedae_plus.mixin.ae2.accessor.PatternEncodingTermMenuAccessor;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.network.NetworkEvent;
import java.util.function.Supplier;
public class ScaleEncodingPatternC2SPacket {
public enum Operation {
MUL2, DIV2, MUL3, DIV3, MUL5, DIV5, SWAP_OUTPUTS, RESTORE_RATIO
}
private final Operation op;
public ScaleEncodingPatternC2SPacket(Operation op) {
this.op = op;
}
public static void encode(ScaleEncodingPatternC2SPacket msg, FriendlyByteBuf buf) {
buf.writeEnum(msg.op);
}
public static ScaleEncodingPatternC2SPacket decode(FriendlyByteBuf buf) {
return new ScaleEncodingPatternC2SPacket(buf.readEnum(Operation.class));
}
public static void handle(ScaleEncodingPatternC2SPacket msg, Supplier<NetworkEvent.Context> ctxSupplier) {
var ctx = ctxSupplier.get();
ctx.enqueueWork(() -> {
ServerPlayer player = ctx.getSender();
if (player == null) {
return;
}
if (!(player.containerMenu instanceof PatternEncodingTermMenu menu)) {
return;
}
if (menu.getMode() != EncodingMode.PROCESSING) {
return;
}
if (msg.op == Operation.SWAP_OUTPUTS) {
rotateProcessingOutputs(menu);
menu.broadcastChanges();
return;
}
if (msg.op == Operation.RESTORE_RATIO) {
var accessor = (PatternEncodingTermMenuAccessor) (Object) menu;
long gcd = computeSharedGcd(accessor.eap$getEncodedInputsInv(), accessor.eap$getEncodedOutputsInv());
if (gcd <= 1L) {
return;
}
var reducedOutputs = reduceInventory(accessor.eap$getEncodedOutputsInv(), gcd);
var reducedInputs = reduceInventory(accessor.eap$getEncodedInputsInv(), gcd);
applyScaled(accessor.eap$getEncodedOutputsInv(), reducedOutputs);
applyScaled(accessor.eap$getEncodedInputsInv(), reducedInputs);
menu.broadcastChanges();
return;
}
int scale = switch (msg.op) {
case MUL2, DIV2 -> 2;
case MUL3, DIV3 -> 3;
case MUL5, DIV5 -> 5;
default -> 1;
};
boolean divide = switch (msg.op) {
case DIV2, DIV3, DIV5 -> true;
default -> false;
};
var accessor = (PatternEncodingTermMenuAccessor) (Object) menu;
var scaledOutputs = scaleInventory(accessor.eap$getEncodedOutputsInv(), scale, divide);
if (scaledOutputs == null) {
return;
}
var scaledInputs = scaleInventory(accessor.eap$getEncodedInputsInv(), scale, divide);
if (scaledInputs == null) {
return;
}
applyScaled(accessor.eap$getEncodedOutputsInv(), scaledOutputs);
applyScaled(accessor.eap$getEncodedInputsInv(), scaledInputs);
menu.broadcastChanges();
});
ctx.setPacketHandled(true);
}
private static GenericStack[] scaleInventory(ConfigInventory inventory, int scale, boolean divide) {
var result = new GenericStack[inventory.size()];
for (int slot = 0; slot < inventory.size(); slot++) {
GenericStack stack = inventory.getStack(slot);
if (stack == null) {
continue;
}
long nextAmount;
if (divide) {
if (stack.amount() % scale != 0) {
return null;
}
nextAmount = stack.amount() / scale;
} else {
nextAmount = stack.amount() * scale;
if (nextAmount < 0L) {
return null;
}
}
result[slot] = new GenericStack(stack.what(), nextAmount);
}
return result;
}
private static GenericStack[] reduceInventory(ConfigInventory inventory, long gcd) {
var result = new GenericStack[inventory.size()];
for (int slot = 0; slot < inventory.size(); slot++) {
GenericStack stack = inventory.getStack(slot);
if (stack == null) {
continue;
}
result[slot] = new GenericStack(stack.what(), stack.amount() / gcd);
}
return result;
}
private static void applyScaled(ConfigInventory inventory, GenericStack[] scaledStacks) {
for (int slot = 0; slot < scaledStacks.length; slot++) {
if (scaledStacks[slot] != null) {
inventory.setStack(slot, scaledStacks[slot]);
}
}
}
private static long computeSharedGcd(ConfigInventory inputs, ConfigInventory outputs) {
long gcd = 0L;
gcd = updateGcd(gcd, inputs);
gcd = updateGcd(gcd, outputs);
return gcd;
}
private static long updateGcd(long currentGcd, ConfigInventory inventory) {
long gcd = currentGcd;
for (int slot = 0; slot < inventory.size(); slot++) {
GenericStack stack = inventory.getStack(slot);
if (stack == null || stack.amount() <= 0L) {
continue;
}
gcd = gcd == 0L ? stack.amount() : gcd(gcd, stack.amount());
if (gcd == 1L) {
return 1L;
}
}
return gcd;
}
private static long gcd(long a, long b) {
long left = Math.abs(a);
long right = Math.abs(b);
while (right != 0L) {
long temp = left % right;
left = right;
right = temp;
}
return left;
}
private static void rotateProcessingOutputs(PatternEncodingTermMenu menu) {
FakeSlot[] outputSlots = menu.getProcessingOutputSlots();
int nonEmptyCount = 0;
for (FakeSlot slot : outputSlots) {
if (!slot.getItem().isEmpty()) {
nonEmptyCount++;
}
}
if (nonEmptyCount < 2) {
return;
}
var newOutputs = new net.minecraft.world.item.ItemStack[outputSlots.length];
for (int i = 0; i < outputSlots.length; i++) {
newOutputs[i] = outputSlots[i].getItem().copy();
}
for (int i = 0; i < outputSlots.length; i++) {
if (outputSlots[i].getItem().isEmpty()) {
continue;
}
for (int j = 1; j < outputSlots.length; j++) {
var nextItem = outputSlots[(i + j) % outputSlots.length].getItem();
if (!nextItem.isEmpty()) {
newOutputs[i] = nextItem.copy();
break;
}
}
}
for (int i = 0; i < newOutputs.length; i++) {
outputSlots[i].set(newOutputs[i]);
}
}
}

View File

@ -0,0 +1,37 @@
{
"$schema": "../../schema.json",
"widgets": {
"zhu_fu_qie_huan": {
"left": 127,
"bottom": 159
},
"huan_yuan_mo_ren": {
"left": 103,
"bottom": 159
},
"cheng_2": {
"left": 127,
"bottom": 149
},
"cheng_3": {
"left": 127,
"bottom": 138
},
"cheng_5": {
"left": 127,
"bottom": 127
},
"chu_2": {
"left": 103,
"bottom": 149
},
"chu_3": {
"left": 103,
"bottom": 138
},
"chu_5": {
"left": 103,
"bottom": 127
}
}
}

View File

@ -0,0 +1,118 @@
{
"$schema": "../schema.json",
"includes": [
"terminal.json",
"encoding/crafting.json",
"encoding/processing.json",
"encoding/smithing_table.json",
"encoding/stonecutting.json",
"encoding/eaep_pattern_terminals.json"
],
"helpTopic": "items-blocks-machines/terminals.md#pattern-encoding-terminal-ui",
"slots": {
"BLANK_PATTERN": {
"left": 147,
"bottom": 165
},
"ENCODED_PATTERN": {
"left": 147,
"bottom": 118
}
},
"text": {
"dialog_title": {
"text": {
"translate": "gui.ae2.Terminal"
},
"position": {
"left": 8,
"top": 6
}
},
"crafting_grid_title": {
"text": {
"translate": "gui.ae2.PatternEncoding"
},
"position": {
"left": 8,
"bottom": 177
}
}
},
"terminalStyle": {
"header": {
"texture": "guis/pattern.png",
"srcRect": [0, 0, 195, 17]
},
"firstRow": {
"texture": "guis/pattern.png",
"srcRect": [0, 17, 195, 18]
},
"row": {
"texture": "guis/pattern.png",
"srcRect": [0, 35, 195, 18]
},
"lastRow": {
"texture": "guis/pattern.png",
"srcRect": [0, 53, 195, 18]
},
"bottom": {
"texture": "guis/pattern.png",
"srcRect": [0, 71, 195, 180]
}
},
"widgets": {
"modeTabButton0": {
"left": 173,
"bottom": 174,
"width": 22,
"height": 22
},
"modeTabButton1": {
"left": 173,
"bottom": 153,
"width": 22,
"height": 22
},
"modeTabButton2": {
"left": 173,
"bottom": 132,
"width": 22,
"height": 22
},
"modeTabButton3": {
"left": 173,
"bottom": 111,
"width": 22,
"height": 22
},
"modePanel0": {
"left": 9,
"bottom": 166
},
"modePanel1": {
"left": 9,
"bottom": 166
},
"modePanel2": {
"left": 9,
"bottom": 166
},
"modePanel3": {
"left": 9,
"bottom": 166
},
"modePanel4": {
"left": 9,
"bottom": 166
},
"modePanel5": {
"left": 9,
"bottom": 166
},
"encodePattern": {
"left": 147,
"bottom": 145
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 345 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 B

View File

@ -14,6 +14,7 @@
"ae2.client.gui.CraftConfirmScreenMixin",
"ae2.client.gui.InterfaceScreenMixin",
"ae2.client.gui.PatternEncodingTermScreenMixin",
"ae2.client.gui.PatternEncodingTermScaleButtonsMixin",
"ae2.client.gui.SlotGridLayoutMixin",
"ae2.client.gui.patternProvider.PatternProviderHighlightCleanupMixin",
"ae2.client.gui.patternProvider.PatternProviderScreenMixin",