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

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

View File

@ -27,6 +27,12 @@ public abstract class PatternEncodingTermScaleButtonsMixin<T extends AEBaseMenu>
@Unique
private static final ResourceLocation EAP$SCALE_BUTTON_TEXTURE =
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
private ScaledTextureButton eap$mul2Button;
@ -40,6 +46,10 @@ public abstract class PatternEncodingTermScaleButtonsMixin<T extends AEBaseMenu>
private ScaledTextureButton eap$div3Button;
@Unique
private ScaledTextureButton eap$div5Button;
@Unique
private ScaledTextureButton eap$swapOutputsButton;
@Unique
private ScaledTextureButton eap$restoreRatioButton;
@Inject(method = "init", at = @At("TAIL"), remap = false)
private void eap$initScaleButtons(CallbackInfo ci) {
@ -60,6 +70,16 @@ public abstract class PatternEncodingTermScaleButtonsMixin<T extends AEBaseMenu>
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);
@ -68,6 +88,8 @@ public abstract class PatternEncodingTermScaleButtonsMixin<T extends AEBaseMenu>
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 = "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$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);
@ -93,6 +117,8 @@ public abstract class PatternEncodingTermScaleButtonsMixin<T extends AEBaseMenu>
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;
@ -108,6 +134,8 @@ public abstract class PatternEncodingTermScaleButtonsMixin<T extends AEBaseMenu>
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$swapOutputsButton, "zhu_fu_qie_huan", bounds);
eap$placeButton(this.eap$restoreRatioButton, "huan_yuan_mo_ren", bounds);
}
@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
private void eap$ensureAdded(ScaledTextureButton button) {
var accessor = (ScreenAccessor) (Object) this;

View File

@ -2,6 +2,7 @@ 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.ExtendedAEPlus;
@ -15,7 +16,7 @@ import net.neoforged.neoforge.network.handling.IPayloadContext;
public class ScaleEncodingPatternC2SPacket implements CustomPacketPayload {
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<>(
@ -49,10 +50,32 @@ public class ScaleEncodingPatternC2SPacket implements CustomPacketPayload {
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;
@ -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]);
}
}
}