增加高级阻挡按钮(仅ui和切换)
This commit is contained in:
parent
61e73aa81a
commit
bd3de00f13
|
|
@ -0,0 +1,27 @@
|
||||||
|
package com.extendedae_plus.client;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
public final class ClientAdvancedBlockingState {
|
||||||
|
private static final Map<String, Boolean> states = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
private ClientAdvancedBlockingState() {}
|
||||||
|
|
||||||
|
public static String key(String dimension, long blockPosLong) {
|
||||||
|
return dimension + "@" + blockPosLong;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void set(String key, boolean v) {
|
||||||
|
states.put(key, v);
|
||||||
|
System.out.println("[EPP][CLIENT][S2C] Received advancedBlocking key=" + key + ", value=" + v);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean has(String key) {
|
||||||
|
return states.containsKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean get(String key) {
|
||||||
|
return states.getOrDefault(key, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.extendedae_plus.mixin.accessor;
|
||||||
|
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||||
|
|
||||||
|
import appeng.helpers.patternprovider.PatternProviderLogic;
|
||||||
|
import appeng.helpers.patternprovider.PatternProviderLogicHost;
|
||||||
|
|
||||||
|
@Mixin(PatternProviderLogic.class)
|
||||||
|
public interface PatternProviderLogicAccessor {
|
||||||
|
@Accessor("host")
|
||||||
|
PatternProviderLogicHost ext$host();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.extendedae_plus.mixin.accessor;
|
||||||
|
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||||
|
|
||||||
|
import appeng.menu.implementations.PatternProviderMenu;
|
||||||
|
import appeng.helpers.patternprovider.PatternProviderLogic;
|
||||||
|
|
||||||
|
@Mixin(PatternProviderMenu.class)
|
||||||
|
public interface PatternProviderMenuAdvancedAccessor {
|
||||||
|
@Accessor("logic")
|
||||||
|
PatternProviderLogic ext$logic();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
package com.extendedae_plus.mixin.ae2;
|
||||||
|
|
||||||
|
import appeng.helpers.patternprovider.PatternProviderLogic;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
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;
|
||||||
|
|
||||||
|
import com.extendedae_plus.api.AdvancedBlockingHolder;
|
||||||
|
|
||||||
|
@Mixin(PatternProviderLogic.class)
|
||||||
|
public class PatternProviderLogicAdvancedMixin implements AdvancedBlockingHolder {
|
||||||
|
@Unique
|
||||||
|
private static final String EPP_ADV_BLOCKING_KEY = "epp_advanced_blocking";
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private boolean epp$advancedBlocking = false;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean ext$getAdvancedBlocking() {
|
||||||
|
return epp$advancedBlocking;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void ext$setAdvancedBlocking(boolean value) {
|
||||||
|
this.epp$advancedBlocking = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "writeToNBT", at = @At("TAIL"), remap = false)
|
||||||
|
private void epp$writeAdvancedToNbt(CompoundTag tag, CallbackInfo ci) {
|
||||||
|
tag.putBoolean(EPP_ADV_BLOCKING_KEY, this.epp$advancedBlocking);
|
||||||
|
System.out.println("[EPP][NBT] writeToNBT: " + EPP_ADV_BLOCKING_KEY + "=" + this.epp$advancedBlocking);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "readFromNBT", at = @At("TAIL"), remap = false)
|
||||||
|
private void epp$readAdvancedFromNbt(CompoundTag tag, CallbackInfo ci) {
|
||||||
|
if (tag.contains(EPP_ADV_BLOCKING_KEY)) {
|
||||||
|
this.epp$advancedBlocking = tag.getBoolean(EPP_ADV_BLOCKING_KEY);
|
||||||
|
System.out.println("[EPP][NBT] readFromNBT: " + EPP_ADV_BLOCKING_KEY + "=" + this.epp$advancedBlocking);
|
||||||
|
} else {
|
||||||
|
System.out.println("[EPP][NBT] readFromNBT: key missing, default=" + this.epp$advancedBlocking);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,95 @@
|
||||||
|
package com.extendedae_plus.mixin.ae2;
|
||||||
|
|
||||||
|
import appeng.menu.implementations.PatternProviderMenu;
|
||||||
|
import appeng.helpers.patternprovider.PatternProviderLogic;
|
||||||
|
import appeng.menu.guisync.GuiSync;
|
||||||
|
import appeng.helpers.patternprovider.PatternProviderLogicHost;
|
||||||
|
import net.minecraft.world.entity.player.Inventory;
|
||||||
|
import net.minecraft.world.inventory.MenuType;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
import com.extendedae_plus.api.AdvancedBlockingHolder;
|
||||||
|
import com.extendedae_plus.api.PatternProviderMenuAdvancedSync;
|
||||||
|
|
||||||
|
@Mixin(PatternProviderMenu.class)
|
||||||
|
public abstract class PatternProviderMenuAdvancedMixin implements PatternProviderMenuAdvancedSync {
|
||||||
|
static {
|
||||||
|
System.out.println("[EPP][MIXIN] Loaded PatternProviderMenuAdvancedMixin");
|
||||||
|
}
|
||||||
|
@Shadow
|
||||||
|
protected abstract boolean isServerSide();
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
protected PatternProviderLogic logic;
|
||||||
|
|
||||||
|
// 选择一个未占用的 GUI 同步 id(AE2 已用到 7),这里使用 20 以避冲突
|
||||||
|
@GuiSync(20)
|
||||||
|
public boolean eppAdvancedBlocking = false;
|
||||||
|
|
||||||
|
@Inject(method = "broadcastChanges", at = @At("HEAD"))
|
||||||
|
private void epp$syncAdvancedBlocking(CallbackInfo ci) {
|
||||||
|
if (this.isServerSide()) {
|
||||||
|
var l = this.logic;
|
||||||
|
if (l instanceof AdvancedBlockingHolder holder) {
|
||||||
|
this.eppAdvancedBlocking = holder.ext$getAdvancedBlocking();
|
||||||
|
System.out.println("[EPP][MENU][S->C] broadcastChanges: eppAdvancedBlocking=" + this.eppAdvancedBlocking);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.out.println("[EPP][MENU][CLIENT] broadcastChanges called on client side");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "broadcastChanges", at = @At("TAIL"))
|
||||||
|
private void epp$syncAdvancedBlockingTail(CallbackInfo ci) {
|
||||||
|
System.out.println("[EPP][MENU] broadcastChanges tail");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构造器尾注入(public ctor)
|
||||||
|
@Inject(method = "<init>(ILnet/minecraft/world/entity/player/Inventory;Lappeng/helpers/patternprovider/PatternProviderLogicHost;)V", at = @At("TAIL"))
|
||||||
|
private void epp$initAdvancedSync_Public(int id, Inventory playerInventory, PatternProviderLogicHost host, CallbackInfo ci) {
|
||||||
|
try {
|
||||||
|
var l = this.logic;
|
||||||
|
if (l instanceof AdvancedBlockingHolder holder) {
|
||||||
|
this.eppAdvancedBlocking = holder.ext$getAdvancedBlocking();
|
||||||
|
System.out.println("[EPP][MENU] <init>-public set initial eppAdvancedBlocking=" + this.eppAdvancedBlocking);
|
||||||
|
}
|
||||||
|
} catch (Throwable t) {
|
||||||
|
System.out.println("[EPP][MENU] <init>-public init error: " + t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构造器尾注入(protected ctor with MenuType)
|
||||||
|
@Inject(method = "<init>(Lnet/minecraft/world/inventory/MenuType;ILnet/minecraft/world/entity/player/Inventory;Lappeng/helpers/patternprovider/PatternProviderLogicHost;)V", at = @At("TAIL"))
|
||||||
|
private void epp$initAdvancedSync_Protected(MenuType<? extends PatternProviderMenu> menuType, int id, Inventory playerInventory, PatternProviderLogicHost host, CallbackInfo ci) {
|
||||||
|
try {
|
||||||
|
var l = this.logic;
|
||||||
|
if (l instanceof AdvancedBlockingHolder holder) {
|
||||||
|
this.eppAdvancedBlocking = holder.ext$getAdvancedBlocking();
|
||||||
|
System.out.println("[EPP][MENU] <init>-protected set initial eppAdvancedBlocking=" + this.eppAdvancedBlocking);
|
||||||
|
}
|
||||||
|
} catch (Throwable t) {
|
||||||
|
System.out.println("[EPP][MENU] <init>-protected init error: " + t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean ext$getAdvancedBlockingSynced() {
|
||||||
|
return this.eppAdvancedBlocking;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调试:当 Screen 每帧读取这些 getter 时打印,验证 Mixin 是否生效
|
||||||
|
@Inject(method = "getBlockingMode", at = @At("HEAD"), remap = false)
|
||||||
|
private void epp$debug_getBlockingMode(CallbackInfoReturnable<?> cir) {
|
||||||
|
System.out.println("[EPP][MENU][DEBUG] getBlockingMode() called; eppAdvancedBlocking=" + this.eppAdvancedBlocking);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "getShowInAccessTerminal", at = @At("HEAD"), remap = false)
|
||||||
|
private void epp$debug_getShowInAccessTerminal(CallbackInfoReturnable<?> cir) {
|
||||||
|
System.out.println("[EPP][MENU][DEBUG] getShowInAccessTerminal() called; eppAdvancedBlocking=" + this.eppAdvancedBlocking);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,147 @@
|
||||||
|
package com.extendedae_plus.mixin.ae2;
|
||||||
|
|
||||||
|
import appeng.client.gui.AEBaseScreen;
|
||||||
|
import appeng.client.gui.Icon;
|
||||||
|
import appeng.client.gui.implementations.PatternProviderScreen;
|
||||||
|
import appeng.client.gui.style.ScreenStyle;
|
||||||
|
import appeng.client.gui.widgets.ToggleButton;
|
||||||
|
import appeng.menu.implementations.PatternProviderMenu;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.world.entity.player.Inventory;
|
||||||
|
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;
|
||||||
|
|
||||||
|
import com.extendedae_plus.api.PatternProviderMenuAdvancedSync;
|
||||||
|
import com.extendedae_plus.network.ModNetwork;
|
||||||
|
import com.extendedae_plus.network.ToggleAdvancedBlockingC2SPacket;
|
||||||
|
import com.extendedae_plus.client.ClientAdvancedBlockingState;
|
||||||
|
import com.extendedae_plus.mixin.accessor.PatternProviderMenuAdvancedAccessor;
|
||||||
|
import com.extendedae_plus.mixin.accessor.PatternProviderLogicAccessor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 为 AE2 原版样板供应器界面添加“高级阻挡模式”按钮(仅客户端UI反馈)。
|
||||||
|
* - 位于左侧工具栏
|
||||||
|
* - 点击后切换图标(YES/NO)并切换 tooltip 提示
|
||||||
|
* - 当前不做任何网络/服务端逻辑
|
||||||
|
*/
|
||||||
|
@Mixin(PatternProviderScreen.class)
|
||||||
|
public abstract class PatternProviderScreenMixin<C extends PatternProviderMenu> extends AEBaseScreen<C> {
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private ToggleButton eppAdvancedBlockingToggle;
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private boolean eppAdvancedBlockingEnabled = false;
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private String eppProviderKey = null;
|
||||||
|
|
||||||
|
public PatternProviderScreenMixin(C menu, Inventory playerInventory, Component title, ScreenStyle style) {
|
||||||
|
super(menu, playerInventory, title, style);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "<init>", at = @At("RETURN"))
|
||||||
|
private void epp$initAdvancedBlocking(C menu, Inventory playerInventory, Component title, ScreenStyle style, CallbackInfo ci) {
|
||||||
|
// 计算供应器唯一键:维度ID + 方块坐标
|
||||||
|
try {
|
||||||
|
var logic = ((PatternProviderMenuAdvancedAccessor) menu).ext$logic();
|
||||||
|
var host = ((PatternProviderLogicAccessor) logic).ext$host();
|
||||||
|
var be = host.getBlockEntity();
|
||||||
|
var level = be.getLevel();
|
||||||
|
String dimId = level.dimension().location().toString();
|
||||||
|
long posLong = be.getBlockPos().asLong();
|
||||||
|
this.eppProviderKey = ClientAdvancedBlockingState.key(dimId, posLong);
|
||||||
|
System.out.println("[EPP][CLIENT] init: providerKey=" + this.eppProviderKey);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
System.out.println("[EPP][CLIENT] init: providerKey resolve failed: " + t);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 优先使用该供应器最近一次 S2C 状态;否则回退读取 @GuiSync 初始化
|
||||||
|
if (this.eppProviderKey != null && ClientAdvancedBlockingState.has(this.eppProviderKey)) {
|
||||||
|
this.eppAdvancedBlockingEnabled = ClientAdvancedBlockingState.get(this.eppProviderKey);
|
||||||
|
System.out.println("[EPP][CLIENT] init: use ClientState key=" + this.eppProviderKey + ", value=" + this.eppAdvancedBlockingEnabled);
|
||||||
|
} else if (menu instanceof PatternProviderMenuAdvancedSync sync) {
|
||||||
|
this.eppAdvancedBlockingEnabled = sync.ext$getAdvancedBlockingSynced();
|
||||||
|
System.out.println("[EPP][CLIENT] init: use GuiSync value=" + this.eppAdvancedBlockingEnabled);
|
||||||
|
}
|
||||||
|
// 使用 ToggleButton 以便在 YES/NO 图标与提示之间动态切换
|
||||||
|
this.eppAdvancedBlockingToggle = new ToggleButton(
|
||||||
|
Icon.BLOCKING_MODE_YES,
|
||||||
|
Icon.BLOCKING_MODE_NO,
|
||||||
|
// 提示文本:名称与说明
|
||||||
|
Component.literal("高级阻挡模式"),
|
||||||
|
Component.literal("高级阻挡模式:当开启时,执行更严格的阻挡判定"),
|
||||||
|
(state) -> {
|
||||||
|
// 客户端立即反馈:切换图标/提示
|
||||||
|
this.eppAdvancedBlockingEnabled = state;
|
||||||
|
this.eppAdvancedBlockingToggle.setState(state);
|
||||||
|
System.out.println("[EPP][CLIENT] Click toggle: state=" + state);
|
||||||
|
// 发送 C2S 切换请求
|
||||||
|
ModNetwork.CHANNEL.sendToServer(new ToggleAdvancedBlockingC2SPacket());
|
||||||
|
// 可根据状态调整提示文本(演示性:开启/关闭不同第二行)
|
||||||
|
if (state) {
|
||||||
|
this.eppAdvancedBlockingToggle.setTooltipOn(java.util.List.of(
|
||||||
|
Component.literal("高级阻挡模式"),
|
||||||
|
Component.literal("高级阻挡模式:已开启")));
|
||||||
|
this.eppAdvancedBlockingToggle.setTooltipOff(java.util.List.of(
|
||||||
|
Component.literal("高级阻挡模式"),
|
||||||
|
Component.literal("高级阻挡模式:已开启")));
|
||||||
|
} else {
|
||||||
|
this.eppAdvancedBlockingToggle.setTooltipOn(java.util.List.of(
|
||||||
|
Component.literal("高级阻挡模式"),
|
||||||
|
Component.literal("高级阻挡模式:已关闭")));
|
||||||
|
this.eppAdvancedBlockingToggle.setTooltipOff(java.util.List.of(
|
||||||
|
Component.literal("高级阻挡模式"),
|
||||||
|
Component.literal("高级阻挡模式:已关闭")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
this.eppAdvancedBlockingToggle.setState(this.eppAdvancedBlockingEnabled);
|
||||||
|
// 初始 tooltip
|
||||||
|
this.eppAdvancedBlockingToggle.setTooltipOn(java.util.List.of(
|
||||||
|
Component.literal("高级阻挡模式"),
|
||||||
|
Component.literal(this.eppAdvancedBlockingEnabled ? "高级阻挡模式:已开启" : "高级阻挡模式:已关闭")
|
||||||
|
));
|
||||||
|
this.eppAdvancedBlockingToggle.setTooltipOff(java.util.List.of(
|
||||||
|
Component.literal("高级阻挡模式"),
|
||||||
|
Component.literal(this.eppAdvancedBlockingEnabled ? "高级阻挡模式:已开启" : "高级阻挡模式:已关闭")
|
||||||
|
));
|
||||||
|
|
||||||
|
this.addToLeftToolbar(this.eppAdvancedBlockingToggle);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 每帧刷新:从菜单同步布尔值,保持按钮状态一致
|
||||||
|
@Inject(method = "updateBeforeRender", at = @At("TAIL"), remap = false)
|
||||||
|
private void epp$updateAdvancedBlocking(CallbackInfo ci) {
|
||||||
|
// 打印一条轻量 tick 日志以确认该方法被调用(频繁输出可在验证后移除)
|
||||||
|
// System.out.println("[EPP][CLIENT] updateBeforeRender tick, local=" + this.eppAdvancedBlockingEnabled);
|
||||||
|
|
||||||
|
if (this.eppAdvancedBlockingToggle == null) return;
|
||||||
|
|
||||||
|
boolean desired = this.eppAdvancedBlockingEnabled;
|
||||||
|
// 优先使用该供应器最近一次 S2C 值
|
||||||
|
if (this.eppProviderKey != null && ClientAdvancedBlockingState.has(this.eppProviderKey)) {
|
||||||
|
desired = ClientAdvancedBlockingState.get(this.eppProviderKey);
|
||||||
|
} else if (this.menu instanceof PatternProviderMenuAdvancedSync sync) {
|
||||||
|
desired = sync.ext$getAdvancedBlockingSynced();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (desired != this.eppAdvancedBlockingEnabled) {
|
||||||
|
this.eppAdvancedBlockingEnabled = desired;
|
||||||
|
this.eppAdvancedBlockingToggle.setState(desired);
|
||||||
|
System.out.println("[EPP][CLIENT] updateBeforeRender apply: eppAdvancedBlocking=" + desired);
|
||||||
|
// 同步 tooltip 二行提示
|
||||||
|
this.eppAdvancedBlockingToggle.setTooltipOn(java.util.List.of(
|
||||||
|
Component.literal("高级阻挡模式"),
|
||||||
|
Component.literal(desired ? "高级阻挡模式:已开启" : "高级阻挡模式:已关闭")
|
||||||
|
));
|
||||||
|
this.eppAdvancedBlockingToggle.setTooltipOff(java.util.List.of(
|
||||||
|
Component.literal("高级阻挡模式"),
|
||||||
|
Component.literal(desired ? "高级阻挡模式:已开启" : "高级阻挡模式:已关闭")
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
package com.extendedae_plus.api;
|
||||||
|
|
||||||
|
public interface AdvancedBlockingHolder {
|
||||||
|
boolean ext$getAdvancedBlocking();
|
||||||
|
void ext$setAdvancedBlocking(boolean value);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
package com.extendedae_plus.api;
|
||||||
|
|
||||||
|
public interface PatternProviderMenuAdvancedSync {
|
||||||
|
boolean ext$getAdvancedBlockingSynced();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
package com.extendedae_plus.network;
|
||||||
|
|
||||||
|
import com.extendedae_plus.client.ClientAdvancedBlockingState;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraftforge.network.NetworkEvent;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public class AdvancedBlockingSyncS2CPacket {
|
||||||
|
private final String dimensionId;
|
||||||
|
private final long blockPosLong;
|
||||||
|
private final boolean enabled;
|
||||||
|
|
||||||
|
public AdvancedBlockingSyncS2CPacket(String dimensionId, long blockPosLong, boolean enabled) {
|
||||||
|
this.dimensionId = dimensionId;
|
||||||
|
this.blockPosLong = blockPosLong;
|
||||||
|
this.enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void encode(AdvancedBlockingSyncS2CPacket msg, FriendlyByteBuf buf) {
|
||||||
|
buf.writeUtf(msg.dimensionId);
|
||||||
|
buf.writeLong(msg.blockPosLong);
|
||||||
|
buf.writeBoolean(msg.enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AdvancedBlockingSyncS2CPacket decode(FriendlyByteBuf buf) {
|
||||||
|
String dim = buf.readUtf();
|
||||||
|
long pos = buf.readLong();
|
||||||
|
boolean en = buf.readBoolean();
|
||||||
|
return new AdvancedBlockingSyncS2CPacket(dim, pos, en);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void handle(AdvancedBlockingSyncS2CPacket msg, Supplier<NetworkEvent.Context> ctxSupplier) {
|
||||||
|
var ctx = ctxSupplier.get();
|
||||||
|
ctx.enqueueWork(() -> {
|
||||||
|
String key = ClientAdvancedBlockingState.key(msg.dimensionId, msg.blockPosLong);
|
||||||
|
ClientAdvancedBlockingState.set(key, msg.enabled);
|
||||||
|
});
|
||||||
|
ctx.setPacketHandled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -56,6 +56,18 @@ public class ModNetwork {
|
||||||
.decoder(ProvidersListS2CPacket::decode)
|
.decoder(ProvidersListS2CPacket::decode)
|
||||||
.consumerNetworkThread(ProvidersListS2CPacket::handle)
|
.consumerNetworkThread(ProvidersListS2CPacket::handle)
|
||||||
.add();
|
.add();
|
||||||
|
|
||||||
|
CHANNEL.messageBuilder(ToggleAdvancedBlockingC2SPacket.class, nextId(), NetworkDirection.PLAY_TO_SERVER)
|
||||||
|
.encoder(ToggleAdvancedBlockingC2SPacket::encode)
|
||||||
|
.decoder(ToggleAdvancedBlockingC2SPacket::decode)
|
||||||
|
.consumerNetworkThread(ToggleAdvancedBlockingC2SPacket::handle)
|
||||||
|
.add();
|
||||||
|
|
||||||
|
CHANNEL.messageBuilder(AdvancedBlockingSyncS2CPacket.class, nextId(), NetworkDirection.PLAY_TO_CLIENT)
|
||||||
|
.encoder(AdvancedBlockingSyncS2CPacket::encode)
|
||||||
|
.decoder(AdvancedBlockingSyncS2CPacket::decode)
|
||||||
|
.consumerNetworkThread(AdvancedBlockingSyncS2CPacket::handle)
|
||||||
|
.add();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int nextId() { return id++; }
|
private static int nextId() { return id++; }
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
package com.extendedae_plus.network;
|
||||||
|
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraftforge.network.NetworkEvent;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraftforge.network.NetworkDirection;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import appeng.menu.implementations.PatternProviderMenu;
|
||||||
|
import com.extendedae_plus.mixin.accessor.PatternProviderMenuAdvancedAccessor;
|
||||||
|
import com.extendedae_plus.api.AdvancedBlockingHolder;
|
||||||
|
import com.extendedae_plus.mixin.accessor.PatternProviderLogicAccessor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* C2S:切换高级阻挡模式。
|
||||||
|
* 不含额外负载,直接基于玩家当前打开的 PatternProviderMenu 进行切换。
|
||||||
|
*/
|
||||||
|
public class ToggleAdvancedBlockingC2SPacket {
|
||||||
|
public ToggleAdvancedBlockingC2SPacket() {}
|
||||||
|
|
||||||
|
public static void encode(ToggleAdvancedBlockingC2SPacket msg, FriendlyByteBuf buf) {}
|
||||||
|
|
||||||
|
public static ToggleAdvancedBlockingC2SPacket decode(FriendlyByteBuf buf) {
|
||||||
|
return new ToggleAdvancedBlockingC2SPacket();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void handle(ToggleAdvancedBlockingC2SPacket msg, Supplier<NetworkEvent.Context> ctxSupplier) {
|
||||||
|
var ctx = ctxSupplier.get();
|
||||||
|
ctx.enqueueWork(() -> {
|
||||||
|
ServerPlayer player = ctx.getSender();
|
||||||
|
if (player == null) return;
|
||||||
|
if (!(player.containerMenu instanceof PatternProviderMenu menu)) return;
|
||||||
|
|
||||||
|
// 通过 accessor 获取逻辑与当前状态
|
||||||
|
var accessor = (PatternProviderMenuAdvancedAccessor) menu;
|
||||||
|
var logic = accessor.ext$logic();
|
||||||
|
if (logic instanceof AdvancedBlockingHolder holder) {
|
||||||
|
boolean current = holder.ext$getAdvancedBlocking();
|
||||||
|
boolean next = !current;
|
||||||
|
System.out.println("[EPP][C2S] ToggleAdvancedBlockingC2SPacket: player=" + player.getGameProfile().getName()
|
||||||
|
+ ", menu=" + menu.getClass().getName()
|
||||||
|
+ ", before=" + current + ", after=" + next);
|
||||||
|
holder.ext$setAdvancedBlocking(next);
|
||||||
|
// 关键:保存持久化,触发 AE2 写入逻辑(writeToNBT),并由菜单 @GuiSync 同步回客户端
|
||||||
|
logic.saveChanges();
|
||||||
|
System.out.println("[EPP][C2S] logic.saveChanges() called for advancedBlocking=" + next);
|
||||||
|
// 直接下发 S2C 强制同步(带供应器标识:维度+方块坐标)
|
||||||
|
var host = ((PatternProviderLogicAccessor) logic).ext$host();
|
||||||
|
var be = host.getBlockEntity();
|
||||||
|
var level = be.getLevel();
|
||||||
|
String dimId = level.dimension().location().toString();
|
||||||
|
long posLong = be.getBlockPos().asLong();
|
||||||
|
ModNetwork.CHANNEL.sendTo(new AdvancedBlockingSyncS2CPacket(dimId, posLong, next), player.connection.connection, NetworkDirection.PLAY_TO_CLIENT);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ctx.setPacketHandled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
"HighlightButtonMixin",
|
"HighlightButtonMixin",
|
||||||
"PickFromWirelessMixin",
|
"PickFromWirelessMixin",
|
||||||
"PatternEncodingTermScreenMixin",
|
"PatternEncodingTermScreenMixin",
|
||||||
|
"ae2.PatternProviderScreenMixin",
|
||||||
"jei.EncodePatternTransferHandlerMixin",
|
"jei.EncodePatternTransferHandlerMixin",
|
||||||
"ae2.QuartzCuttingKnifeItemMixin",
|
"ae2.QuartzCuttingKnifeItemMixin",
|
||||||
"accessor.AEBaseScreenAccessor",
|
"accessor.AEBaseScreenAccessor",
|
||||||
|
|
@ -27,7 +28,11 @@
|
||||||
"ContainerPatternEncodingTermMenuMixin",
|
"ContainerPatternEncodingTermMenuMixin",
|
||||||
"MEStorageMenuMixin",
|
"MEStorageMenuMixin",
|
||||||
"accessor.MEStorageMenuAccessor",
|
"accessor.MEStorageMenuAccessor",
|
||||||
"accessor.PatternEncodingTermMenuAccessor"
|
"accessor.PatternEncodingTermMenuAccessor",
|
||||||
|
"ae2.PatternProviderLogicAdvancedMixin",
|
||||||
|
"ae2.PatternProviderMenuAdvancedMixin",
|
||||||
|
"accessor.PatternProviderMenuAdvancedAccessor",
|
||||||
|
"accessor.PatternProviderLogicAccessor"
|
||||||
],
|
],
|
||||||
"injectors": {
|
"injectors": {
|
||||||
"defaultRequire": 1
|
"defaultRequire": 1
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user