样板终端恢复&主副切换按钮

This commit is contained in:
GaLi 2026-03-28 13:25:35 +08:00
parent 28f9ff09d9
commit d1e323a6a4
3 changed files with 161 additions and 11 deletions

View File

@ -9,6 +9,7 @@ import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
public class ScaledTextureButton extends Button { public class ScaledTextureButton extends Button {
private final OnPress delegateOnPress;
private final ResourceLocation texture; private final ResourceLocation texture;
private final int textureWidth; private final int textureWidth;
private final int textureHeight; private final int textureHeight;
@ -22,7 +23,9 @@ public class ScaledTextureButton extends Button {
int srcX, int srcY, int srcWidth, int srcHeight, float scale, int srcX, int srcY, int srcWidth, int srcHeight, float scale,
Component tooltipText, OnPress onPress) { Component tooltipText, OnPress onPress) {
super(0, 0, Math.round(srcWidth * scale), Math.round(srcHeight * scale), super(0, 0, Math.round(srcWidth * scale), Math.round(srcHeight * scale),
Component.empty(), onPress, DEFAULT_NARRATION); Component.empty(), btn -> {
}, DEFAULT_NARRATION);
this.delegateOnPress = onPress;
this.texture = texture; this.texture = texture;
this.textureWidth = textureWidth; this.textureWidth = textureWidth;
this.textureHeight = textureHeight; this.textureHeight = textureHeight;
@ -41,6 +44,12 @@ public class ScaledTextureButton extends Button {
this.active = visible; this.active = visible;
} }
@Override
public void onPress() {
this.delegateOnPress.onPress(this);
this.setFocused(false);
}
@Override @Override
public void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { public void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) {
if (!this.visible) { if (!this.visible) {
@ -51,19 +60,11 @@ public class ScaledTextureButton extends Button {
this.height = Math.round(this.srcHeight * this.scale); this.height = Math.round(this.srcHeight * this.scale);
int yOffset = this.isHovered() ? 1 : 0; int yOffset = this.isHovered() ? 1 : 0;
Icon bgIcon = isHovered() ? Icon.TOOLBAR_BUTTON_BACKGROUND_HOVER Icon bgIcon = isHovered() ? Icon.TOOLBAR_BUTTON_BACKGROUND_HOVER : Icon.TOOLBAR_BUTTON_BACKGROUND;
: isFocused() ? Icon.TOOLBAR_BUTTON_BACKGROUND_FOCUS : Icon.TOOLBAR_BUTTON_BACKGROUND;
RenderSystem.disableDepthTest(); RenderSystem.disableDepthTest();
RenderSystem.enableBlend(); RenderSystem.enableBlend();
if (isFocused()) {
guiGraphics.fill(getX() - 1, getY() - 1, getX() + width + 1, getY(), 0xFFFFFFFF);
guiGraphics.fill(getX() - 1, getY(), getX(), getY() + height, 0xFFFFFFFF);
guiGraphics.fill(getX() + width, getY(), getX() + width + 1, getY() + height, 0xFFFFFFFF);
guiGraphics.fill(getX() - 1, getY() + height, getX() + width + 1, getY() + height + 1, 0xFFFFFFFF);
}
var pose = guiGraphics.pose(); var pose = guiGraphics.pose();
pose.pushPose(); pose.pushPose();
pose.translate(getX(), getY() + yOffset, 0.0F); pose.translate(getX(), getY() + yOffset, 0.0F);

View File

@ -27,6 +27,12 @@ public abstract class PatternEncodingTermScaleButtonsMixin<T extends AEBaseMenu>
@Unique @Unique
private static final ResourceLocation EAP$SCALE_BUTTON_TEXTURE = private static final ResourceLocation EAP$SCALE_BUTTON_TEXTURE =
ResourceLocation.fromNamespaceAndPath(ExtendedAEPlus.MODID, "textures/gui/beizeng.png"); ResourceLocation.fromNamespaceAndPath(ExtendedAEPlus.MODID, "textures/gui/beizeng.png");
@Unique
private static final ResourceLocation EAP$SWAP_OUTPUT_TEXTURE =
ResourceLocation.fromNamespaceAndPath(ExtendedAEPlus.MODID, "textures/gui/zhu_fu_qie_huan.png");
@Unique
private static final ResourceLocation EAP$RESTORE_RATIO_TEXTURE =
ResourceLocation.fromNamespaceAndPath(ExtendedAEPlus.MODID, "textures/gui/huanyuan.png");
@Unique @Unique
private ScaledTextureButton eap$mul2Button; private ScaledTextureButton eap$mul2Button;
@ -40,6 +46,10 @@ public abstract class PatternEncodingTermScaleButtonsMixin<T extends AEBaseMenu>
private ScaledTextureButton eap$div3Button; private ScaledTextureButton eap$div3Button;
@Unique @Unique
private ScaledTextureButton eap$div5Button; private ScaledTextureButton eap$div5Button;
@Unique
private ScaledTextureButton eap$swapOutputsButton;
@Unique
private ScaledTextureButton eap$restoreRatioButton;
@Inject(method = "init", at = @At("TAIL"), remap = false) @Inject(method = "init", at = @At("TAIL"), remap = false)
private void eap$initScaleButtons(CallbackInfo ci) { private void eap$initScaleButtons(CallbackInfo ci) {
@ -60,6 +70,16 @@ public abstract class PatternEncodingTermScaleButtonsMixin<T extends AEBaseMenu>
ScaleEncodingPatternC2SPacket.Operation.DIV3); ScaleEncodingPatternC2SPacket.Operation.DIV3);
this.eap$div5Button = eap$createScaleButton(32, 16, "/5", this.eap$div5Button = eap$createScaleButton(32, 16, "/5",
ScaleEncodingPatternC2SPacket.Operation.DIV5); 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$mul2Button);
@ -68,6 +88,8 @@ public abstract class PatternEncodingTermScaleButtonsMixin<T extends AEBaseMenu>
eap$ensureAdded(this.eap$div2Button); eap$ensureAdded(this.eap$div2Button);
eap$ensureAdded(this.eap$div3Button); eap$ensureAdded(this.eap$div3Button);
eap$ensureAdded(this.eap$div5Button); eap$ensureAdded(this.eap$div5Button);
eap$ensureAdded(this.eap$swapOutputsButton);
eap$ensureAdded(this.eap$restoreRatioButton);
} }
@Inject(method = "containerTick", at = @At("TAIL"), remap = false) @Inject(method = "containerTick", at = @At("TAIL"), remap = false)
@ -85,6 +107,8 @@ public abstract class PatternEncodingTermScaleButtonsMixin<T extends AEBaseMenu>
eap$ensureAdded(this.eap$div2Button); eap$ensureAdded(this.eap$div2Button);
eap$ensureAdded(this.eap$div3Button); eap$ensureAdded(this.eap$div3Button);
eap$ensureAdded(this.eap$div5Button); eap$ensureAdded(this.eap$div5Button);
eap$ensureAdded(this.eap$swapOutputsButton);
eap$ensureAdded(this.eap$restoreRatioButton);
boolean visible = screen.getMenu().getMode() == EncodingMode.PROCESSING; boolean visible = screen.getMenu().getMode() == EncodingMode.PROCESSING;
this.eap$mul2Button.setVisibility(visible); this.eap$mul2Button.setVisibility(visible);
@ -93,6 +117,8 @@ public abstract class PatternEncodingTermScaleButtonsMixin<T extends AEBaseMenu>
this.eap$div2Button.setVisibility(visible); this.eap$div2Button.setVisibility(visible);
this.eap$div3Button.setVisibility(visible); this.eap$div3Button.setVisibility(visible);
this.eap$div5Button.setVisibility(visible); this.eap$div5Button.setVisibility(visible);
this.eap$swapOutputsButton.setVisibility(visible);
this.eap$restoreRatioButton.setVisibility(visible);
if (!visible) { if (!visible) {
return; return;
@ -108,6 +134,8 @@ public abstract class PatternEncodingTermScaleButtonsMixin<T extends AEBaseMenu>
eap$placeButton(this.eap$mul2Button, "cheng_2", bounds); eap$placeButton(this.eap$mul2Button, "cheng_2", bounds);
eap$placeButton(this.eap$mul3Button, "cheng_3", bounds); eap$placeButton(this.eap$mul3Button, "cheng_3", bounds);
eap$placeButton(this.eap$mul5Button, "cheng_5", bounds); eap$placeButton(this.eap$mul5Button, "cheng_5", bounds);
eap$placeButton(this.eap$swapOutputsButton, "zhu_fu_qie_huan", bounds);
eap$placeButton(this.eap$restoreRatioButton, "huan_yuan_mo_ren", bounds);
} }
@Unique @Unique
@ -127,6 +155,23 @@ public abstract class PatternEncodingTermScaleButtonsMixin<T extends AEBaseMenu>
); );
} }
@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 -> PacketDistributor.sendToServer(new ScaleEncodingPatternC2SPacket(op))
);
}
@Unique @Unique
private void eap$ensureAdded(ScaledTextureButton button) { private void eap$ensureAdded(ScaledTextureButton button) {
var accessor = (ScreenAccessor) (Object) this; var accessor = (ScreenAccessor) (Object) this;

View File

@ -2,6 +2,7 @@ package com.extendedae_plus.network;
import appeng.api.stacks.GenericStack; import appeng.api.stacks.GenericStack;
import appeng.menu.me.items.PatternEncodingTermMenu; import appeng.menu.me.items.PatternEncodingTermMenu;
import appeng.menu.slot.FakeSlot;
import appeng.parts.encoding.EncodingMode; import appeng.parts.encoding.EncodingMode;
import appeng.util.ConfigInventory; import appeng.util.ConfigInventory;
import com.extendedae_plus.ExtendedAEPlus; import com.extendedae_plus.ExtendedAEPlus;
@ -15,7 +16,7 @@ import net.neoforged.neoforge.network.handling.IPayloadContext;
public class ScaleEncodingPatternC2SPacket implements CustomPacketPayload { public class ScaleEncodingPatternC2SPacket implements CustomPacketPayload {
public enum Operation { public enum Operation {
MUL2, DIV2, MUL3, DIV3, MUL5, DIV5 MUL2, DIV2, MUL3, DIV3, MUL5, DIV5, SWAP_OUTPUTS, RESTORE_RATIO
} }
public static final Type<ScaleEncodingPatternC2SPacket> TYPE = new Type<>( public static final Type<ScaleEncodingPatternC2SPacket> TYPE = new Type<>(
@ -49,10 +50,32 @@ public class ScaleEncodingPatternC2SPacket implements CustomPacketPayload {
return; 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) { int scale = switch (msg.op) {
case MUL2, DIV2 -> 2; case MUL2, DIV2 -> 2;
case MUL3, DIV3 -> 3; case MUL3, DIV3 -> 3;
case MUL5, DIV5 -> 5; case MUL5, DIV5 -> 5;
default -> 1;
}; };
boolean divide = switch (msg.op) { boolean divide = switch (msg.op) {
case DIV2, DIV3, DIV5 -> true; case DIV2, DIV3, DIV5 -> true;
@ -110,4 +133,85 @@ public class ScaleEncodingPatternC2SPacket implements CustomPacketPayload {
} }
} }
} }
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 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]);
}
}
} }