Merge remote-tracking branch 'origin/develop/1.21.1' into 1.21.1

# Conflicts:
#	src/main/java/com/extendedae_plus/mixin/ExtendedAEPlusMixinPlugin.java
#	src/main/java/com/extendedae_plus/mixin/advancedae/compat/PatternProviderLogicVirtualCompletionMixin.java
#	src/main/java/com/extendedae_plus/mixin/ae2/compat/PatternProviderLogicCompatMixin.java
This commit is contained in:
GaLicn 2025-11-24 20:41:18 +08:00
commit 0a820c734b
112 changed files with 2466 additions and 2116 deletions

View File

@ -5,30 +5,24 @@
# Find more information on toml format here: https://github.com/toml-lang/toml # Find more information on toml format here: https://github.com/toml-lang/toml
# The name of the mod loader type to load - for regular FML @Mod mods it should be javafml # The name of the mod loader type to load - for regular FML @Mod mods it should be javafml
modLoader="javafml" #mandatory modLoader = "javafml" #mandatory
# A version range to match for said mod loader - for regular FML @Mod it will be the FML version. This is currently 2. # A version range to match for said mod loader - for regular FML @Mod it will be the FML version. This is currently 2.
loaderVersion="[1,)" #mandatory loaderVersion = "[1,)" #mandatory
# The license for you mod. This is mandatory metadata and allows for easier comprehension of your redistributive properties. # The license for you mod. This is mandatory metadata and allows for easier comprehension of your redistributive properties.
# Review your options at https://choosealicense.com/. All rights reserved is the default copyright stance, and is thus the default here. # Review your options at https://choosealicense.com/. All rights reserved is the default copyright stance, and is thus the default here.
license="All Rights Reserved" license = "LGPL-3.0-or-later"
# A URL to refer people to when problems occur with this mod # A URL to refer people to when problems occur with this mod
#issueTrackerURL="https://change.me.to.your.issue.tracker.example.invalid/" #optional
# A list of mods - how many allowed here is determined by the individual mod loader # A list of mods - how many allowed here is determined by the individual mod loader
[[mods]] #mandatory [[mods]]
modId = "extendedae_plus"
# The modid of the mod version = "1.21.1-1.4.3"
modId="extendedae_plus" #mandatory displayName = "ExtendedAE-Plus"
issueTrackerURL = "https://github.com/GaLicn/ExtendedAE_Plus/issues"
# The version number of the mod displayURL = "https://github.com/GaLicn/ExtendedAE_Plus"
version="1.21.1-1.4.3" #mandatory
# A display name for the mod
displayName="ExtendedAE-Plus" #mandatory
# A URL to query for updates for this mod. See the JSON update specification https://docs.neoforged.net/docs/misc/updatechecker/ # A URL to query for updates for this mod. See the JSON update specification https://docs.neoforged.net/docs/misc/updatechecker/
#updateJSONURL="https://change.me.example.invalid/updates.json" #optional #updateJSONURL="https://change.me.example.invalid/updates.json" #optional
@ -42,15 +36,14 @@ displayName="ExtendedAE-Plus" #mandatory
#credits="" #optional #credits="" #optional
# A text field displayed in the mod UI # A text field displayed in the mod UI
authors="YourNameHere, OtherNameHere" #optional authors = "GaLi, C-H716" #optional
# The description text for the mod (multi line!) (#mandatory) # The description text for the mod (multi line!) (#mandatory)
description='''Example mod description. description = '''Add more practical features and auxiliary operations to the Applied Energistics 2 mod'''
Newline characters can be used and will be replaced properly.'''
# The [[mixins]] block allows you to declare your mixin config to FML so that it gets loaded. # The [[mixins]] block allows you to declare your mixin config to FML so that it gets loaded.
[[mixins]] [[mixins]]
config="extendedae_plus.mixins.json" config = "extendedae_plus.mixins.json"
# The [[accessTransformers]] block allows you to declare where your AT file is. # The [[accessTransformers]] block allows you to declare where your AT file is.
# If this block is omitted, a fallback attempt will be made to load an AT from META-INF/accesstransformer.cfg # If this block is omitted, a fallback attempt will be made to load an AT from META-INF/accesstransformer.cfg
@ -61,40 +54,40 @@ config="extendedae_plus.mixins.json"
# A dependency - use the . to indicate dependency for a specific modid. Dependencies are optional. # A dependency - use the . to indicate dependency for a specific modid. Dependencies are optional.
[[dependencies.extendedae_plus]] #optional [[dependencies.extendedae_plus]] #optional
# the modid of the dependency # the modid of the dependency
modId="neoforge" #mandatory modId = "neoforge" #mandatory
# The type of the dependency. Can be one of "required", "optional", "incompatible" or "discouraged" (case insensitive). # The type of the dependency. Can be one of "required", "optional", "incompatible" or "discouraged" (case insensitive).
# 'required' requires the mod to exist, 'optional' does not # 'required' requires the mod to exist, 'optional' does not
# 'incompatible' will prevent the game from loading when the mod exists, and 'discouraged' will show a warning # 'incompatible' will prevent the game from loading when the mod exists, and 'discouraged' will show a warning
type="required" #mandatory type = "required" #mandatory
# Optional field describing why the dependency is required or why it is incompatible # Optional field describing why the dependency is required or why it is incompatible
# reason="..." # reason="..."
# The version range of the dependency # The version range of the dependency
versionRange="[21.1.1,)" #mandatory versionRange = "[21.1.1,)" #mandatory
# An ordering relationship for the dependency. # An ordering relationship for the dependency.
# BEFORE - This mod is loaded BEFORE the dependency # BEFORE - This mod is loaded BEFORE the dependency
# AFTER - This mod is loaded AFTER the dependency # AFTER - This mod is loaded AFTER the dependency
ordering="NONE" ordering = "NONE"
# Side this dependency is applied on - BOTH, CLIENT, or SERVER # Side this dependency is applied on - BOTH, CLIENT, or SERVER
side="BOTH" side = "BOTH"
# Here's another dependency # Here's another dependency
[[dependencies.extendedae_plus]] [[dependencies.extendedae_plus]]
modId="minecraft" modId = "minecraft"
type="required" type = "required"
# This version range declares a minimum of the current minecraft version up to but not including the next major version # This version range declares a minimum of the current minecraft version up to but not including the next major version
versionRange="[1.21.1]" versionRange = "[1.21.1]"
ordering="NONE" ordering = "NONE"
side="BOTH" side = "BOTH"
# Require ExtendedAE (ExtendedAE-1.21-2.2.21-neoforge) to be present # Require ExtendedAE (ExtendedAE-1.21-2.2.21-neoforge) to be present
[[dependencies.extendedae_plus]] [[dependencies.extendedae_plus]]
modId="extendedae" modId = "extendedae"
type="required" type = "required"
# Use a permissive range to tolerate upstream version string variations (e.g. 1.21-2.2.21-neoforge) # Use a permissive range to tolerate upstream version string variations (e.g. 1.21-2.2.21-neoforge)
versionRange="*" versionRange = "*"
ordering="AFTER" ordering = "AFTER"
side="BOTH" side = "BOTH"
# Features are specific properties of the game environment, that you may want to declare you require. This example declares # Features are specific properties of the game environment, that you may want to declare you require. This example declares
# that your mod requires GL version 3.2 or higher. Other features will be added. They are side aware so declaring this won't # that your mod requires GL version 3.2 or higher. Other features will be added. They are side aware so declaring this won't

View File

@ -30,7 +30,7 @@ mod_id=extendedae_plus
# The human-readable display name for the mod. # The human-readable display name for the mod.
mod_name=ExtendedAE-Plus mod_name=ExtendedAE-Plus
# The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default.
mod_license=All Rights Reserved mod_license=LGPL-3.0-or-later
# The mod version. See https://semver.org/ # The mod version. See https://semver.org/
mod_version=1.21.1-1.4.3 mod_version=1.21.1-1.4.3
# The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository.
@ -38,9 +38,9 @@ mod_version=1.21.1-1.4.3
# See https://maven.apache.org/guides/mini/guide-naming-conventions.html # See https://maven.apache.org/guides/mini/guide-naming-conventions.html
mod_group_id=com.extendedae_plus mod_group_id=com.extendedae_plus
# The authors of the mod. This is a simple text string that is used for display purposes in the mod list. # The authors of the mod. This is a simple text string that is used for display purposes in the mod list.
mod_authors=YourNameHere, OtherNameHere mod_authors=GaLi, C-H716
# The description of the mod. This is a simple multiline text string that is used for display purposes in the mod list. # The description of the mod. This is a simple multiline text string that is used for display purposes in the mod list.
mod_description=Example mod description.\nNewline characters can be used and will be replaced properly. mod_description=Add more practical features and auxiliary operations to the Applied Energistics 2 mod
## UI item explorer selection (emi | rei | jei) ## UI item explorer selection (emi | rei | jei)
# Default to 'emi' per request; you can override by running with -Puse_Xei=rei or -Puse_Xei=jei # Default to 'emi' per request; you can override by running with -Puse_Xei=rei or -Puse_Xei=jei

View File

@ -1,42 +0,0 @@
package com.extendedae_plus;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.fml.event.config.ModConfigEvent;
import net.neoforged.neoforge.common.ModConfigSpec;
// An example config class. This is not required, but it's a good idea to have one to keep your config organized.
// Demonstrates how to use Neo's config APIs
public class Config {
private static final ModConfigSpec.Builder BUILDER = new ModConfigSpec.Builder();
public static final ModConfigSpec.BooleanValue LOG_DIRT_BLOCK = BUILDER
.comment("Whether to log the dirt block on common setup")
.define("logDirtBlock", true);
public static final ModConfigSpec.IntValue MAGIC_NUMBER = BUILDER
.comment("A magic number")
.defineInRange("magicNumber", 42, 0, Integer.MAX_VALUE);
public static final ModConfigSpec.ConfigValue<String> MAGIC_NUMBER_INTRODUCTION = BUILDER
.comment("What you want the introduction message to be for the magic number")
.define("magicNumberIntroduction", "The magic number is... ");
// a list of strings that are treated as resource locations for items
public static final ModConfigSpec.ConfigValue<List<? extends String>> ITEM_STRINGS = BUILDER
.comment("A list of items to log on common setup.")
.defineListAllowEmpty("items", List.of("minecraft:iron_ingot"), () -> "", Config::validateItemName);
static final ModConfigSpec SPEC = BUILDER.build();
private static boolean validateItemName(final Object obj) {
return obj instanceof String itemName && BuiltInRegistries.ITEM.containsKey(ResourceLocation.parse(itemName));
}
}

View File

@ -6,8 +6,8 @@ import appeng.api.storage.StorageCells;
import appeng.block.AEBaseEntityBlock; import appeng.block.AEBaseEntityBlock;
import appeng.blockentity.crafting.CraftingBlockEntity; import appeng.blockentity.crafting.CraftingBlockEntity;
import appeng.items.parts.PartModelsHelper; import appeng.items.parts.PartModelsHelper;
import com.extendedae_plus.ae.api.storage.InfinityBigIntegerCellHandler;
import com.extendedae_plus.api.ids.EAPComponents; import com.extendedae_plus.api.ids.EAPComponents;
import com.extendedae_plus.api.storage.InfinityBigIntegerCellHandler;
import com.extendedae_plus.config.ModConfigs; import com.extendedae_plus.config.ModConfigs;
import com.extendedae_plus.init.*; import com.extendedae_plus.init.*;
import com.extendedae_plus.util.storage.InfinityStorageManager; import com.extendedae_plus.util.storage.InfinityStorageManager;
@ -37,6 +37,10 @@ public class ExtendedAEPlus {
// Directly reference a slf4j logger // Directly reference a slf4j logger
public static final Logger LOGGER = LogUtils.getLogger(); public static final Logger LOGGER = LogUtils.getLogger();
// 移除 MDK 示例注册改为使用实际模组的方块/物品/创造物品栏注册见 ModBlocksModItemsModCreativeTabs // 移除 MDK 示例注册改为使用实际模组的方块/物品/创造物品栏注册见 ModBlocksModItemsModCreativeTabs
@Nullable
private static InfinityStorageManager storageManager;
@Nullable
private static MinecraftServer storageManagerServer;
// The constructor for the mod class is the first code that is run when your mod is loaded. // The constructor for the mod class is the first code that is run when your mod is loaded.
// FML will recognize some parameter types like IEventBus or ModContainer and pass them in automatically. // FML will recognize some parameter types like IEventBus or ModContainer and pass them in automatically.
@ -74,6 +78,23 @@ public class ExtendedAEPlus {
return ResourceLocation.fromNamespaceAndPath(MODID, path); return ResourceLocation.fromNamespaceAndPath(MODID, path);
} }
private static void onServerStarted(ServerStartedEvent event) {
storageManagerServer = event.getServer();
storageManager = InfinityStorageManager.getInstance(event.getServer());
}
private static void onServerStopped(ServerStoppedEvent event) {
if (storageManagerServer == event.getServer()) {
storageManagerServer = null;
storageManager = null;
}
}
@Nullable
public static InfinityStorageManager currentStorageManager() {
return storageManager;
}
private void commonSetup(FMLCommonSetupEvent event) { private void commonSetup(FMLCommonSetupEvent event) {
// Some common setup code // Some common setup code
LOGGER.info("HELLO FROM COMMON SETUP"); LOGGER.info("HELLO FROM COMMON SETUP");
@ -136,29 +157,6 @@ public class ExtendedAEPlus {
}); });
} }
@Nullable
private static InfinityStorageManager storageManager;
@Nullable
private static MinecraftServer storageManagerServer;
private static void onServerStarted(ServerStartedEvent event) {
storageManagerServer = event.getServer();
storageManager = InfinityStorageManager.getInstance(event.getServer());
}
private static void onServerStopped(ServerStoppedEvent event) {
if (storageManagerServer == event.getServer()) {
storageManagerServer = null;
storageManager = null;
}
}
@Nullable
public static InfinityStorageManager currentStorageManager() {
return storageManager;
}
// You can use SubscribeEvent and let the Event Bus discover methods to call // You can use SubscribeEvent and let the Event Bus discover methods to call
@SubscribeEvent @SubscribeEvent
public void onServerStarting(ServerStartingEvent event) { public void onServerStarting(ServerStartingEvent event) {

View File

@ -9,12 +9,12 @@ import com.extendedae_plus.ae.parts.EntitySpeedTickerPart;
import com.extendedae_plus.ae.screen.EntitySpeedTickerScreen; import com.extendedae_plus.ae.screen.EntitySpeedTickerScreen;
import com.extendedae_plus.api.config.EAPSettings; import com.extendedae_plus.api.config.EAPSettings;
import com.extendedae_plus.config.ModConfigs; import com.extendedae_plus.config.ModConfigs;
import com.extendedae_plus.init.ModItems;
import com.extendedae_plus.init.ModMenuTypes; import com.extendedae_plus.init.ModMenuTypes;
import com.extendedae_plus.util.entitySpeed.ConfigParsingUtils; import com.extendedae_plus.util.entitySpeed.ConfigParsingUtils;
import com.extendedae_plus.util.entitySpeed.PowerUtils; import com.extendedae_plus.util.entitySpeed.PowerUtils;
import it.unimi.dsi.fastutil.shorts.ShortSet; import it.unimi.dsi.fastutil.shorts.ShortSet;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.inventory.Slot; import net.minecraft.world.inventory.Slot;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
@ -23,25 +23,20 @@ import net.minecraft.world.level.block.entity.BlockEntity;
* 实体加速器菜单负责管理客户端与服务端的数据同步处理加速卡能量卡和目标方块的状态 * 实体加速器菜单负责管理客户端与服务端的数据同步处理加速卡能量卡和目标方块的状态
*/ */
public class EntitySpeedTickerMenu extends UpgradeableMenu<EntitySpeedTickerPart> { public class EntitySpeedTickerMenu extends UpgradeableMenu<EntitySpeedTickerPart> {
@GuiSync(716) public YesNo accelerate; // 是否启用加速 private final EntitySpeedTickerPart logic;
@GuiSync(717) public YesNo redstoneControl; // 是否启用红石控制 @GuiSync(716) public int energyCardCount; // 已安装的能量卡数量
private int entitySpeedCardCount; // 已安装的实体加速卡数量 @GuiSync(717) public int effectiveSpeed = 1; // 当前生效的加速倍率
@GuiSync(719) public int energyCardCount; // 已安装的能量卡数量 @GuiSync(718) public double multiplier = 1.0; // 目标方块的配置倍率
@GuiSync(720) public int effectiveSpeed = 1; // 当前生效的加速倍率 @GuiSync(719) public boolean targetBlacklisted = false; // 目标方块是否在黑名单中
@GuiSync(721) public double multiplier = 1.0; // 目标方块的配置倍率 @GuiSync(720) public YesNo networkEnergySufficient; // 网络能量是否充足
@GuiSync(722) public boolean targetBlacklisted = false; // 目标方块是否在黑名单中 @GuiSync(721) private YesNo accelerate; // 是否启用加速
@GuiSync(723) public YesNo networkEnergySufficient; // 网络能量是否充足 @GuiSync(722) private YesNo redstoneControl; // 是否启用红石控制
protected final EntitySpeedTickerPart logic;
@Override
protected void loadSettingsFromHost(IConfigManager cm) {
// 不需要模糊模式
}
/** /**
* 构造函数初始化菜单并绑定部件 * 构造函数初始化菜单并绑定部件
* @param id 菜单ID *
* @param ip 玩家背包 * @param id 菜单ID
* @param ip 玩家背包
* @param host 关联的实体加速器部件 * @param host 关联的实体加速器部件
*/ */
public EntitySpeedTickerMenu(int id, Inventory ip, EntitySpeedTickerPart host) { public EntitySpeedTickerMenu(int id, Inventory ip, EntitySpeedTickerPart host) {
@ -49,32 +44,34 @@ public class EntitySpeedTickerMenu extends UpgradeableMenu<EntitySpeedTickerPart
this.logic = host; this.logic = host;
} }
/** // 服务端 客户端同步时触发包括第一次打开 GUI
* 服务端数据同步到客户端时调用更新卡数量目标状态和生效速度
*/
@Override @Override
public void onServerDataSync(ShortSet updatedFields) { public void onServerDataSync(ShortSet updatedFields) {
super.onServerDataSync(updatedFields); super.onServerDataSync(updatedFields);
updateCardCounts(); // 更新卡数量
updateTargetStatus(); // 更新目标方块的黑名单和倍率 // 客户端只更新可能变化的显示相关字段
updateEffectiveSpeed(); // 计算生效速度 // 顺序必须和 broadcastChanges 里一致
// updateNetworkEnergyStatus(); // 同步能量状态 this.updateTargetStatus(); // multiplier + targetBlacklisted
if (isClientSide()) { this.updateEffectiveSpeed(); // 依赖上面两个字段
refreshClientGui(); // 客户端刷新界面
if (this.isClientSide()) {
this.refreshClientGui();
} }
} }
/** /**
* 当槽位内容变化时调用客户端更新卡数量和生效速度 * 当槽位内容变化时调用客户端更新卡数量和生效速度
*
* @param slot 发生变化的槽位 * @param slot 发生变化的槽位
*/ */
@Override @Override
public void onSlotChange(Slot slot) { public void onSlotChange(Slot slot) {
super.onSlotChange(slot); super.onSlotChange(slot);
if (isClientSide()) { if (this.isClientSide()) {
updateCardCounts(); // 升级卡变化时energyCardCount 已经由 AE2 自动同步
updateEffectiveSpeed(); // 重新计算生效速度并刷新 UI
refreshClientGui(); this.updateEffectiveSpeed();
this.refreshClientGui();
} }
} }
@ -83,14 +80,27 @@ public class EntitySpeedTickerMenu extends UpgradeableMenu<EntitySpeedTickerPart
*/ */
@Override @Override
public void broadcastChanges() { public void broadcastChanges() {
if (isServerSide()) { if (this.isServerSide()) {
this.accelerate = logic.getConfigManager().getSetting(EAPSettings.ACCELERATE); // 1. 先更新配置类开关红石能量充足
this.redstoneControl = logic.getConfigManager().getSetting(EAPSettings.REDSTONE_CONTROL); this.accelerate = this.logic.getConfigManager().getSetting(EAPSettings.ACCELERATE);
this.networkEnergySufficient = logic.isNetworkEnergySufficient() ? YesNo.YES : YesNo.NO; this.redstoneControl = this.logic.getConfigManager().getSetting(EAPSettings.REDSTONE_CONTROL);
this.networkEnergySufficient = this.logic.isNetworkEnergySufficient() ? YesNo.YES : YesNo.NO;
// 2. 再更新升级卡数量
this.energyCardCount = this.getUpgrades().getInstalledUpgrades(AEItems.ENERGY_CARD);
// 3. 最后更新目标状态 + 生效速度
this.updateTargetStatus();
this.updateEffectiveSpeed();
} }
super.broadcastChanges(); super.broadcastChanges();
} }
@Override
protected void loadSettingsFromHost(IConfigManager cm) {
// 不需要模糊模式
}
public YesNo getAccelerate() { public YesNo getAccelerate() {
return this.accelerate; return this.accelerate;
} }
@ -98,25 +108,18 @@ public class EntitySpeedTickerMenu extends UpgradeableMenu<EntitySpeedTickerPart
public YesNo getRedstoneControl() { public YesNo getRedstoneControl() {
return this.redstoneControl; return this.redstoneControl;
} }
/**
* 更新加速卡和能量卡的数量
*/
private void updateCardCounts() {
this.entitySpeedCardCount = this.getUpgrades().getInstalledUpgrades(ModItems.ENTITY_SPEED_CARD.get());
this.energyCardCount = this.getUpgrades().getInstalledUpgrades(AEItems.ENERGY_CARD);
}
/** /**
* 更新目标方块的黑名单状态和倍率 * 更新目标方块的黑名单状态和倍率
*/ */
private void updateTargetStatus() { private void updateTargetStatus() {
BlockEntity target = getTargetBlockEntity(); BlockEntity target = this.getTargetBlockEntity();
if (target == null) { if (target == null) {
this.multiplier = 1.0; this.multiplier = 1.0;
this.targetBlacklisted = false; this.targetBlacklisted = false;
return; return;
} }
String blockId = net.minecraft.core.registries.BuiltInRegistries.BLOCK.getKey(target.getBlockState().getBlock()).toString(); String blockId = BuiltInRegistries.BLOCK.getKey(target.getBlockState().getBlock()).toString();
this.multiplier = ConfigParsingUtils.getMultiplierForBlock(blockId, ModConfigs.ENTITY_TICKER_MULTIPLIERS.get()); this.multiplier = ConfigParsingUtils.getMultiplierForBlock(blockId, ModConfigs.ENTITY_TICKER_MULTIPLIERS.get());
this.targetBlacklisted = ConfigParsingUtils.isBlockBlacklisted(blockId, ModConfigs.ENTITY_TICKER_BLACK_LIST.get()); this.targetBlacklisted = ConfigParsingUtils.isBlockBlacklisted(blockId, ModConfigs.ENTITY_TICKER_BLACK_LIST.get());
} }
@ -125,7 +128,8 @@ public class EntitySpeedTickerMenu extends UpgradeableMenu<EntitySpeedTickerPart
* 计算生效速度考虑黑名单和卡数量 * 计算生效速度考虑黑名单和卡数量
*/ */
private void updateEffectiveSpeed() { private void updateEffectiveSpeed() {
this.effectiveSpeed = targetBlacklisted ? 0 : (int) PowerUtils.computeProductWithCap(getUpgrades(), 8); this.effectiveSpeed =
this.targetBlacklisted ? 0 : (int) PowerUtils.computeProductWithCap(this.getUpgrades(), 8);
} }
/** /**
@ -139,12 +143,13 @@ public class EntitySpeedTickerMenu extends UpgradeableMenu<EntitySpeedTickerPart
/** /**
* 获取目标方块实体 * 获取目标方块实体
*
* @return 目标方块实体或 null * @return 目标方块实体或 null
*/ */
private BlockEntity getTargetBlockEntity() { private BlockEntity getTargetBlockEntity() {
return getHost() != null ? return this.getHost() != null ?
getHost().getLevel().getBlockEntity( this.getHost().getLevel().getBlockEntity(
getHost().getBlockEntity().getBlockPos().relative(getHost().getSide()) this.getHost().getBlockEntity().getBlockPos().relative(this.getHost().getSide())
) : null; ) : null;
} }
} }

View File

@ -18,6 +18,7 @@ import appeng.api.parts.IPartModel;
import appeng.api.storage.MEStorage; import appeng.api.storage.MEStorage;
import appeng.api.upgrades.IUpgradeableObject; import appeng.api.upgrades.IUpgradeableObject;
import appeng.api.util.IConfigManager; import appeng.api.util.IConfigManager;
import appeng.api.util.IConfigManagerBuilder;
import appeng.core.definitions.AEItems; import appeng.core.definitions.AEItems;
import appeng.items.parts.PartModels; import appeng.items.parts.PartModels;
import appeng.menu.MenuOpener; import appeng.menu.MenuOpener;
@ -30,8 +31,10 @@ import com.extendedae_plus.api.config.EAPSettings;
import com.extendedae_plus.config.ModConfigs; import com.extendedae_plus.config.ModConfigs;
import com.extendedae_plus.init.ModItems; import com.extendedae_plus.init.ModItems;
import com.extendedae_plus.init.ModMenuTypes; import com.extendedae_plus.init.ModMenuTypes;
import com.extendedae_plus.util.ExtendedAELogger;
import com.extendedae_plus.util.entitySpeed.ConfigParsingUtils; import com.extendedae_plus.util.entitySpeed.ConfigParsingUtils;
import com.extendedae_plus.util.entitySpeed.PowerUtils; import com.extendedae_plus.util.entitySpeed.PowerUtils;
import net.minecraft.core.BlockPos;
import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
@ -39,6 +42,7 @@ import net.minecraft.world.MenuProvider;
import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityTicker; import net.minecraft.world.level.block.entity.BlockEntityTicker;
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.BlockEntityType;
@ -55,14 +59,14 @@ import java.lang.reflect.Method;
* 功能受<a href="https://github.com/GilbertzRivi/crazyae2addons">Crazy AE2 Addons</a>启发 * 功能受<a href="https://github.com/GilbertzRivi/crazyae2addons">Crazy AE2 Addons</a>启发
*/ */
public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTickable, MenuProvider, IUpgradeableObject { public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTickable, MenuProvider, IUpgradeableObject {
public static final ResourceLocation MODEL_BASE = ResourceLocation.fromNamespaceAndPath( private static final ResourceLocation MODEL_BASE = ResourceLocation.fromNamespaceAndPath(
ExtendedAEPlus.MODID, "part/entity_speed_ticker_part"); ExtendedAEPlus.MODID, "part/entity_speed_ticker_part");
@PartModels @PartModels
public static final PartModel MODELS_OFF; private static final PartModel MODELS_OFF;
@PartModels @PartModels
public static final PartModel MODELS_ON; private static final PartModel MODELS_ON;
@PartModels @PartModels
public static final PartModel MODELS_HAS_CHANNEL; private static final PartModel MODELS_HAS_CHANNEL;
static { static {
MODELS_OFF = new PartModel(MODEL_BASE, ResourceLocation.fromNamespaceAndPath(ExtendedAEPlus.MODID, "part/entity_speed_ticker_off")); MODELS_OFF = new PartModel(MODEL_BASE, ResourceLocation.fromNamespaceAndPath(ExtendedAEPlus.MODID, "part/entity_speed_ticker_off"));
@ -70,10 +74,9 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTicka
MODELS_HAS_CHANNEL = new PartModel(MODEL_BASE, ResourceLocation.fromNamespaceAndPath(ExtendedAEPlus.MODID, "part/entity_speed_ticker_has_channel")); MODELS_HAS_CHANNEL = new PartModel(MODEL_BASE, ResourceLocation.fromNamespaceAndPath(ExtendedAEPlus.MODID, "part/entity_speed_ticker_has_channel"));
} }
private final IConfigManager configManager;
public EntitySpeedTickerMenu menu; // 当前打开的菜单实例 public EntitySpeedTickerMenu menu; // 当前打开的菜单实例
private YesNo networkEnergySufficient; // 网络能量是否充足 private YesNo networkEnergySufficient = YesNo.YES; // 网络能量是否充足
private YesNo redstoneState = YesNo.UNDECIDED;
/** /**
* 构造函数初始化部件并设置网络节点属性 * 构造函数初始化部件并设置网络节点属性
* *
@ -85,40 +88,66 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTicka
.setFlags(GridFlags.REQUIRE_CHANNEL) .setFlags(GridFlags.REQUIRE_CHANNEL)
.setIdlePowerUsage(1) .setIdlePowerUsage(1)
.addService(IGridTickable.class, this); .addService(IGridTickable.class, this);
configManager = IConfigManager.builder(this::configChanged)
.registerSetting(EAPSettings.ACCELERATE, YesNo.NO)
.registerSetting(EAPSettings.REDSTONE_CONTROL, YesNo.YES)
.build();
} }
private void configChanged(IConfigManager manager, Setting<?> setting) { @Override
this.saveChanges(); protected void registerSettings(IConfigManagerBuilder builder) {
} super.registerSettings(builder);
builder.registerSetting(EAPSettings.ACCELERATE, YesNo.YES); // 默认开启加速
public void saveChanges() { builder.registerSetting(EAPSettings.REDSTONE_CONTROL, YesNo.NO); // 默认忽略红石信号
getHost().markForSave();
}
public boolean isAccelerate() {
return this.configManager.getSetting(EAPSettings.ACCELERATE) == YesNo.YES;
}
public boolean isRedstoneControl() {
return this.configManager.getSetting(EAPSettings.REDSTONE_CONTROL) == YesNo.YES;
}
public boolean isNetworkEnergySufficient() {
return this.networkEnergySufficient == YesNo.YES;
} }
/** /**
* 更新网络能量充足状态并通知菜单 * 获取可用的升级卡槽数量
* *
* @param sufficient 是否能量充足 * @return 升级卡槽数量
*/ */
private void setNetworkEnergySufficient(boolean sufficient) { @Override
this.networkEnergySufficient = sufficient ? YesNo.YES : YesNo.NO; protected int getUpgradeSlots() {
saveChanges(); return 8;
}
// 判断当前是否应该休眠
@Override
protected boolean isSleeping() {
// 主开关没开 休眠
if (this.getConfigManager().getSetting(EAPSettings.ACCELERATE) != YesNo.YES) {
return true;
}
// 没开红石控制 一直工作
if (this.getConfigManager().getSetting(EAPSettings.REDSTONE_CONTROL) != YesNo.YES) {
return false;
}
// 开启了红石控制 必须有红石信号才工作
return !this.getHost().hasRedstone(); // 没信号 休眠
}
@Override
protected void onSettingChanged(IConfigManager manager, Setting<?> setting) {
// 每次玩家在 GUI 里点任何按钮包括加速开关红石控制开关都会进来这里
this.getMainNode().ifPresent((grid, node) -> {
if (this.isSleeping()) {
grid.getTickManager().sleepDevice(node);
} else {
grid.getTickManager().wakeDevice(node);
}
});
}
@Override
public void onNeighborChanged(BlockGetter level, BlockPos pos, BlockPos neighbor) {
// 只关心红石控制开启的情况下
if (this.getConfigManager().getSetting(EAPSettings.REDSTONE_CONTROL) == YesNo.YES) {
this.getMainNode().ifPresent((grid, node) -> {
if (this.getHost().hasRedstone()) {
grid.getTickManager().wakeDevice(node); // 有信号 立刻唤醒
} else {
grid.getTickManager().sleepDevice(node); // 没信号 立刻休眠
}
});
}
} }
/** /**
@ -130,7 +159,7 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTicka
*/ */
@Override @Override
public final boolean onUseWithoutItem(Player player, Vec3 pos) { public final boolean onUseWithoutItem(Player player, Vec3 pos) {
if (!isClientSide()) { if (!this.isClientSide()) {
MenuOpener.open(ModMenuTypes.ENTITY_TICKER_MENU.get(), player, MenuLocators.forPart(this)); MenuOpener.open(ModMenuTypes.ENTITY_TICKER_MENU.get(), player, MenuLocators.forPart(this));
} }
return true; return true;
@ -159,8 +188,30 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTicka
*/ */
@Override @Override
public void getBoxes(IPartCollisionHelper bch) { public void getBoxes(IPartCollisionHelper bch) {
bch.addBox(2, 2, 14, 14, 14, 16); bch.addBox(3, 3, 14, 13, 13, 16);
bch.addBox(5, 5, 12, 11, 11, 14); bch.addBox(5, 5, 11, 11, 11, 14);
}
public void saveChanges() {
this.getHost().markForSave();
}
private boolean isAccelerate() {
return this.getConfigManager().getSetting(EAPSettings.ACCELERATE) == YesNo.YES;
}
public boolean isNetworkEnergySufficient() {
return this.networkEnergySufficient == YesNo.YES;
}
/**
* 更新网络能量充足状态并通知菜单
*
* @param sufficient 是否能量充足
*/
private void setNetworkEnergySufficient(boolean sufficient) {
this.networkEnergySufficient = sufficient ? YesNo.YES : YesNo.NO;
this.saveChanges();
} }
/** /**
@ -172,7 +223,7 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTicka
@Override @Override
public TickingRequest getTickingRequest(IGridNode iGridNode) { public TickingRequest getTickingRequest(IGridNode iGridNode) {
// 1 tick 执行一次 // 1 tick 执行一次
return new TickingRequest(1, 1, false); return new TickingRequest(1, 1, this.isSleeping());
} }
/** /**
@ -184,23 +235,24 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTicka
*/ */
@Override @Override
public TickRateModulation tickingRequest(IGridNode iGridNode, int ticksSinceLastCall) { public TickRateModulation tickingRequest(IGridNode iGridNode, int ticksSinceLastCall) {
// 如果部件的加速开关被关闭则不进行加速提前返回 if (!this.isAccelerate()) {
if (!isAccelerate()) {
return TickRateModulation.IDLE; return TickRateModulation.IDLE;
} }
// 检查红石控制 if (this.isSleeping()) {
if (isRedstoneControl() && !getRedstoneState()) { return TickRateModulation.SLEEP;
// 如果启用了红石控制且没有红石信号则不执行加速
return TickRateModulation.IDLE;
} }
// 获取目标方块实体本部件朝向的方块 // 获取目标方块实体本部件朝向的方块
BlockEntity target = getLevel().getBlockEntity(getBlockEntity().getBlockPos().relative(getSide())); BlockEntity target = this.getLevel().getBlockEntity(
this.getBlockEntity().getBlockPos().relative(this.getSide())
);
// 仅在目标存在且部件处于激活状态时执行加速 // 仅在目标存在且部件处于激活状态时执行加速
if (target != null && isActive()) { if (target == null || !this.isActive()) {
ticker(target); return TickRateModulation.IDLE;
} }
this.ticker(target);
return TickRateModulation.IDLE; return TickRateModulation.IDLE;
} }
@ -211,7 +263,7 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTicka
* @param <T> 方块实体类型 * @param <T> 方块实体类型
*/ */
private <T extends BlockEntity> void ticker(@NotNull T blockEntity) { private <T extends BlockEntity> void ticker(@NotNull T blockEntity) {
if (!isValidForTicking()) { if (!this.isValidForTicking()) {
return; return;
} }
@ -220,22 +272,22 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTicka
return; return;
} }
BlockEntityTicker<T> ticker = getTicker(blockEntity); BlockEntityTicker<T> ticker = this.getTicker(blockEntity);
if (ticker == null) { if (ticker == null) {
return; return;
} }
int speed = calculateSpeed(); int speed = this.calculateSpeed();
if (speed <= 0) { if (speed <= 0) {
return; return;
} }
double requiredPower = calculateRequiredPower(speed, blockId); double requiredPower = this.calculateRequiredPower(speed, blockId);
if (!extractPower(requiredPower)) { if (!this.extractPower(requiredPower)) {
return; return;
} }
performTicks(blockEntity, ticker, speed); this.performTicks(blockEntity, ticker, speed);
} }
/** /**
@ -244,7 +296,7 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTicka
* @return 是否可以执行 tick * @return 是否可以执行 tick
*/ */
private boolean isValidForTicking() { private boolean isValidForTicking() {
return getGridNode() != null && getMainNode() != null && getMainNode().getGrid() != null; return this.getGridNode() != null && this.getMainNode() != null && this.getMainNode().getGrid() != null;
} }
/** /**
@ -254,8 +306,8 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTicka
* @return ticker null * @return ticker null
*/ */
private <T extends BlockEntity> BlockEntityTicker<T> getTicker(T blockEntity) { private <T extends BlockEntity> BlockEntityTicker<T> getTicker(T blockEntity) {
return getLevel().getBlockState(blockEntity.getBlockPos()) return this.getLevel().getBlockState(blockEntity.getBlockPos())
.getTicker(getLevel(), (BlockEntityType<T>) blockEntity.getType()); .getTicker(this.getLevel(), (BlockEntityType<T>) blockEntity.getType());
} }
/** /**
@ -264,9 +316,9 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTicka
* @return 生效的加速倍率 * @return 生效的加速倍率
*/ */
private int calculateSpeed() { private int calculateSpeed() {
int entitySpeedCardCount = getUpgrades().getInstalledUpgrades(ModItems.ENTITY_SPEED_CARD.get()); int entitySpeedCardCount = this.getUpgrades().getInstalledUpgrades(ModItems.ENTITY_SPEED_CARD.get());
if (entitySpeedCardCount <= 0) return 0; if (entitySpeedCardCount <= 0) return 0;
return (int) PowerUtils.computeProductWithCap(getUpgrades(), 8); return (int) PowerUtils.computeProductWithCap(this.getUpgrades(), 8);
} }
/** /**
@ -277,7 +329,7 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTicka
* @return 所需能量 * @return 所需能量
*/ */
private double calculateRequiredPower(int speed, String blockId) { private double calculateRequiredPower(int speed, String blockId) {
int energyCardCount = getUpgrades().getInstalledUpgrades(AEItems.ENERGY_CARD); int energyCardCount = this.getUpgrades().getInstalledUpgrades(AEItems.ENERGY_CARD);
double multiplier = ConfigParsingUtils.getMultiplierForBlock(blockId, ModConfigs.ENTITY_TICKER_MULTIPLIERS.get()); double multiplier = ConfigParsingUtils.getMultiplierForBlock(blockId, ModConfigs.ENTITY_TICKER_MULTIPLIERS.get());
return PowerUtils.computeFinalPowerForProduct(speed, energyCardCount) * multiplier; return PowerUtils.computeFinalPowerForProduct(speed, energyCardCount) * multiplier;
} }
@ -289,15 +341,15 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTicka
* @return 是否成功提取足够能量 * @return 是否成功提取足够能量
*/ */
private boolean extractPower(double requiredPower) { private boolean extractPower(double requiredPower) {
IEnergyService energyService = getMainNode().getGrid().getEnergyService(); IEnergyService energyService = this.getMainNode().getGrid().getEnergyService();
MEStorage storage = getMainNode().getGrid().getStorageService().getInventory(); MEStorage storage = this.getMainNode().getGrid().getStorageService().getInventory();
IActionSource source = IActionSource.ofMachine(this); IActionSource source = IActionSource.ofMachine(this);
boolean appFluxLoaded = ModList.get().isLoaded("appflux"); boolean appFluxLoaded = ModList.get().isLoaded("appflux");
boolean preferDiskEnergy = appFluxLoaded && ModConfigs.PRIORITIZE_DISK_ENERGY.get(); boolean preferDiskEnergy = appFluxLoaded && ModConfigs.PRIORITIZE_DISK_ENERGY.get();
// 如果 appflux 存在且优先磁盘能量尝试提取 FE 能量 // 如果 appflux 存在且优先磁盘能量尝试提取 FE 能量
if (appFluxLoaded && preferDiskEnergy) { if (appFluxLoaded && preferDiskEnergy) {
if (tryExtractFE(energyService, storage, requiredPower, source)) { if (this.tryExtractFE(energyService, storage, requiredPower, source)) {
return true; return true;
} }
} }
@ -307,21 +359,21 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTicka
if (simulated >= requiredPower) { if (simulated >= requiredPower) {
double extracted = energyService.extractAEPower(requiredPower, Actionable.MODULATE, PowerMultiplier.CONFIG); double extracted = energyService.extractAEPower(requiredPower, Actionable.MODULATE, PowerMultiplier.CONFIG);
boolean sufficient = extracted >= requiredPower; boolean sufficient = extracted >= requiredPower;
setNetworkEnergySufficient(sufficient); this.setNetworkEnergySufficient(sufficient);
return sufficient; return sufficient;
} }
setNetworkEnergySufficient(false); this.setNetworkEnergySufficient(false);
// 如果 appflux 存在且优先 AE 能量尝试提取 FE 能量作为备用 // 如果 appflux 存在且优先 AE 能量尝试提取 FE 能量作为备用
if (appFluxLoaded && !preferDiskEnergy) { if (appFluxLoaded && !preferDiskEnergy) {
return tryExtractFE(energyService, storage, requiredPower, source); return this.tryExtractFE(energyService, storage, requiredPower, source);
} }
return false; return false;
} }
private boolean tryExtractFE(IEnergyService energyService, MEStorage storage, double requiredPower, IActionSource source) { private boolean tryExtractFE(IEnergyService energyService, MEStorage storage, double requiredPower, IActionSource source) {
try { try {
Class<?> helperClass = Class.forName("com.extendedae_plus.util.FluxEnergyHelper"); Class<?> helperClass = Class.forName("com.extendedae_plus.util.entitySpeed.FluxEnergyHelper");
Method extractMethod = helperClass.getMethod( Method extractMethod = helperClass.getMethod(
"extractFE", "extractFE",
IEnergyService.class, IEnergyService.class,
@ -332,13 +384,13 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTicka
long feRequired = (long) requiredPower << 1; // 1 AE = 2 FE long feRequired = (long) requiredPower << 1; // 1 AE = 2 FE
long feExtracted = (long) extractMethod.invoke(null, energyService, storage, feRequired, source); long feExtracted = (long) extractMethod.invoke(null, energyService, storage, feRequired, source);
if (feExtracted >= feRequired) { if (feExtracted >= feRequired) {
setNetworkEnergySufficient(true); this.setNetworkEnergySufficient(true);
return true; return true;
} }
} catch (Exception e) { } catch (Exception e) {
// 如果反射失败视为 FE 不可用 // 如果反射失败视为 FE 不可用
} }
setNetworkEnergySufficient(false); this.setNetworkEnergySufficient(false);
return false; return false;
} }
@ -354,12 +406,41 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTicka
int speed) { int speed) {
// 执行 speed-1 次额外 tick原生 tick 已包含 1 // 执行 speed-1 次额外 tick原生 tick 已包含 1
for (int i = 0; i < speed - 1; i++) { for (int i = 0; i < speed - 1; i++) {
ticker.tick( try {
blockEntity.getLevel(), ticker.tick(
blockEntity.getBlockPos(), blockEntity.getLevel(),
blockEntity.getBlockState(), blockEntity.getBlockPos(),
blockEntity blockEntity.getBlockState(),
); blockEntity
);
} catch (IllegalStateException e) {
// 捕获随机数生成器的多线程访问异常
// 这通常发生在某些模组 Thermal的机器使用随机数时
// 由于加速导致在同一tick内多次访问随机数生成器而触发 ThreadingDetector
if (e.getMessage() != null && e.getMessage().contains("LegacyRandomSource")) {
// 记录警告并停止当前加速循环避免崩溃
ExtendedAELogger.LOGGER.warn(
"检测到方块实体 {} 在位置 {} 的随机数访问冲突,已停止本次加速以避免崩溃。" +
"建议将此方块类型添加到配置黑名单中。",
blockEntity.getType().toString(),
blockEntity.getBlockPos()
);
break; // 停止后续的加速 tick
} else {
// 如果是其他类型的 IllegalStateException继续抛出
throw e;
}
} catch (Exception e) {
// 捕获其他可能的异常防止崩溃
ExtendedAELogger.LOGGER.error(
"在加速方块实体 {} 位置 {} 时发生错误: {}",
blockEntity.getType().toString(),
blockEntity.getBlockPos(),
e.getMessage(),
e
);
break; // 停止后续的加速 tick
}
} }
} }
@ -397,46 +478,4 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTicka
@NotNull Player player) { @NotNull Player player) {
return new EntitySpeedTickerMenu(containerId, playerInventory, this); return new EntitySpeedTickerMenu(containerId, playerInventory, this);
} }
/**
* 获取可用的升级卡槽数量
*
* @return 升级卡槽数量
*/
@Override
protected int getUpgradeSlots() {
return 8;
}
/**
* 当升级卡数量发生变化时调用通知菜单更新
*/
@Override
public void upgradesChanged() {
if (this.menu != null) {
// 使用 AE2 风格当升级发生变化时让菜单广播变化/数据会被同步客户端会基于槽内容重新计算并刷新界面
this.menu.broadcastChanges();
}
}
public IConfigManager getConfigManager() {
return this.configManager;
}
// 获取红石信号状态
private boolean getRedstoneState() {
// 每次调用都更新红石状态确保及时性
updateRedstoneState();
return redstoneState == YesNo.YES;
}
// 更新红石信号状态
private void updateRedstoneState() {
var be = this.getHost().getBlockEntity();
if (be != null && be.getLevel() != null) {
redstoneState = be.getLevel().hasNeighborSignal(be.getBlockPos())
? YesNo.YES
: YesNo.NO;
}
}
} }

View File

@ -11,16 +11,13 @@ import com.extendedae_plus.api.config.EAPSettings;
import com.extendedae_plus.client.gui.widgets.EAPServerSettingToggleButton; import com.extendedae_plus.client.gui.widgets.EAPServerSettingToggleButton;
import com.extendedae_plus.client.gui.widgets.EAPSettingToggleButton; import com.extendedae_plus.client.gui.widgets.EAPSettingToggleButton;
import com.extendedae_plus.util.entitySpeed.PowerUtils; import com.extendedae_plus.util.entitySpeed.PowerUtils;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Inventory;
import java.util.HashMap;
import java.util.Map;
public class EntitySpeedTickerScreen extends UpgradeableScreen<EntitySpeedTickerMenu> { public class EntitySpeedTickerScreen extends UpgradeableScreen<EntitySpeedTickerMenu> {
private final EAPSettingToggleButton<YesNo> accelerateButton; // 加速开关按钮 private final EAPSettingToggleButton<YesNo> accelerateButton; // 加速开关按钮
private final EAPSettingToggleButton<YesNo> redstoneControlButton; // 加速开关按钮 private final EAPSettingToggleButton<YesNo> redstoneControlButton; // 加速开关按钮
private final TextUpdater textUpdater = new TextUpdater();
/** /**
* 构造函数初始化界面和控件 * 构造函数初始化界面和控件
@ -37,7 +34,7 @@ public class EntitySpeedTickerScreen extends UpgradeableScreen<EntitySpeedTicker
super(menu, playerInventory, title, style); super(menu, playerInventory, title, style);
this.addToLeftToolbar(CommonButtons.togglePowerUnit()); // 添加功率单位切换按钮 this.addToLeftToolbar(CommonButtons.togglePowerUnit()); // 添加功率单位切换按钮
this.accelerateButton = new EAPServerSettingToggleButton<>(EAPSettings.ACCELERATE, YesNo.NO); this.accelerateButton = new EAPServerSettingToggleButton<>(EAPSettings.ACCELERATE, YesNo.YES);
this.addToLeftToolbar(this.accelerateButton); this.addToLeftToolbar(this.accelerateButton);
this.redstoneControlButton = new EAPServerSettingToggleButton<>(EAPSettings.REDSTONE_CONTROL, YesNo.NO); this.redstoneControlButton = new EAPServerSettingToggleButton<>(EAPSettings.REDSTONE_CONTROL, YesNo.NO);
@ -54,47 +51,55 @@ public class EntitySpeedTickerScreen extends UpgradeableScreen<EntitySpeedTicker
} else { } else {
this.accelerateButton.set(this.menu.getAccelerate()); this.accelerateButton.set(this.menu.getAccelerate());
} }
this.redstoneControlButton.set(this.menu.getRedstoneControl()); this.redstoneControlButton.set(this.menu.getRedstoneControl());
this.textData(); // 文本更新统一处理
} this.textUpdater.update();
@Override
public void drawBG(GuiGraphics guiGraphics, int offsetX, int offsetY, int mouseX, int mouseY, float partialTicks) {
super.drawBG(guiGraphics, offsetX, offsetY, mouseX, mouseY, partialTicks);
} }
public void refreshGui() { public void refreshGui() {
this.textData(); this.textUpdater.update();
} }
/** private class TextUpdater {
* 更新界面文本内容包括加速状态速度能耗和倍率 void update() {
*/ if (EntitySpeedTickerScreen.this.menu.targetBlacklisted) {
private void textData() { this.updateBlacklist();
Map<String, Component> textContents = new HashMap<>(); } else {
if (this.getMenu().targetBlacklisted) { this.updateNormal();
// 黑名单禁用时的默认显示 }
textContents.put("enable", Component.translatable("screen.extendedae_plus.entity_speed_ticker.enable")); }
textContents.put("speed", Component.translatable("screen.extendedae_plus.entity_speed_ticker.speed", 0));
textContents.put("energy", Component.translatable("screen.extendedae_plus.entity_speed_ticker.energy", Platform.formatPower(0.0, false))); private void updateBlacklist() {
textContents.put("power_ratio", Component.translatable("screen.extendedae_plus.entity_speed_ticker.power_ratio", PowerUtils.formatPercentage(0.0))); this.set("enable", this.translatable("enable"));
textContents.put("multiplier", Component.translatable("screen.extendedae_plus.entity_speed_ticker.multiplier", String.format("%.2fx", 0.0))); this.set("speed", this.translatable("speed", 0));
} else { this.set("energy", this.translatable("energy", Platform.formatPower(0, false)));
// 正常状态下显示实际数据 this.set("power_ratio", this.translatable("power_ratio", PowerUtils.formatPercentage(0.0)));
int energyCardCount = this.getMenu().energyCardCount; this.set("multiplier", this.translatable("multiplier", "0.00x"));
double multiplier = this.getMenu().multiplier; }
int effectiveSpeed = this.getMenu().effectiveSpeed;
double finalPower = PowerUtils.computeFinalPowerForProduct(effectiveSpeed, energyCardCount); private void updateNormal() {
double remainingRatio = PowerUtils.getRemainingRatio(energyCardCount); int energyCardCount = EntitySpeedTickerScreen.this.menu.energyCardCount;
double multiplier = EntitySpeedTickerScreen.this.menu.multiplier;
textContents.put("enable", this.getMenu().networkEnergySufficient == YesNo.YES ? null : int effectiveSpeed = EntitySpeedTickerScreen.this.menu.effectiveSpeed;
Component.translatable("screen.extendedae_plus.entity_speed_ticker.warning_network_energy_insufficient")); double finalPower = PowerUtils.computeFinalPowerForProduct(effectiveSpeed, energyCardCount);
textContents.put("speed", Component.translatable("screen.extendedae_plus.entity_speed_ticker.speed", effectiveSpeed)); double powerRatio = PowerUtils.getRemainingRatio(energyCardCount);
textContents.put("energy", Component.translatable("screen.extendedae_plus.entity_speed_ticker.energy", Platform.formatPower(finalPower, false)));
textContents.put("power_ratio", Component.translatable("screen.extendedae_plus.entity_speed_ticker.power_ratio", PowerUtils.formatPercentage(remainingRatio))); this.set("enable", EntitySpeedTickerScreen.this.menu.networkEnergySufficient == YesNo.YES
textContents.put("multiplier", Component.translatable("screen.extendedae_plus.entity_speed_ticker.multiplier", String.format("%.2fx", multiplier))); ? null
: this.translatable("warning_network_energy_insufficient"));
this.set("speed", this.translatable("speed", effectiveSpeed));
this.set("energy", this.translatable("energy", Platform.formatPower(finalPower, false)));
this.set("power_ratio", this.translatable("power_ratio", PowerUtils.formatPercentage(powerRatio)));
this.set("multiplier", this.translatable("multiplier", String.format("%.2fx", multiplier)));
}
private Component translatable(String key, Object... args) {
return Component.translatable("screen.extendedae_plus.entity_speed_ticker." + key, args);
}
private void set(String id, Component c) {
EntitySpeedTickerScreen.this.setTextContent(id, c);
} }
textContents.forEach(this::setTextContent);
} }
} }

View File

@ -1,4 +1,4 @@
package com.extendedae_plus.wireless; package com.extendedae_plus.ae.wireless;
import appeng.api.networking.IGridNode; import appeng.api.networking.IGridNode;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;

View File

@ -1,4 +1,4 @@
package com.extendedae_plus.wireless; package com.extendedae_plus.ae.wireless;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -24,13 +24,13 @@ public class WirelessMasterLink {
this.placerId = placerId; this.placerId = placerId;
} }
public long getFrequency() { return frequency; } public long getFrequency() {return this.frequency;}
public void setFrequency(long frequency) { public void setFrequency(long frequency) {
// 如果频率发生变化先撤销旧频率的注册 // 如果频率发生变化先撤销旧频率的注册
if (this.frequency != frequency) { if (this.frequency != frequency) {
if (registered) { if (this.registered) {
unregister(); this.unregister();
} }
this.frequency = frequency; this.frequency = frequency;
} }
@ -38,35 +38,35 @@ public class WirelessMasterLink {
// 频率未变的情况下也要校正注册状态 // 频率未变的情况下也要校正注册状态
// - 当从"从端"切回"主端"registered 可能为 false需要重新注册 // - 当从"从端"切回"主端"registered 可能为 false需要重新注册
// - 当频率为 0 或端点被移除时确保处于未注册 // - 当频率为 0 或端点被移除时确保处于未注册
if (frequency != 0L && !host.isEndpointRemoved()) { if (frequency != 0L && !this.host.isEndpointRemoved()) {
if (!registered) { if (!this.registered) {
register(); this.register();
} }
} else { } else {
if (registered) { if (this.registered) {
unregister(); this.unregister();
} }
} }
} }
public boolean register() { public boolean register() {
ServerLevel level = host.getServerLevel(); ServerLevel level = this.host.getServerLevel();
if (level == null || frequency == 0L) return false; if (level == null || this.frequency == 0L) return false;
// placerId可以为null公共收发器模式 // placerId可以为null公共收发器模式
boolean ok = WirelessMasterRegistry.register(level, frequency, placerId, host); boolean ok = WirelessMasterRegistry.register(level, this.frequency, this.placerId, this.host);
this.registered = ok; this.registered = ok;
return ok; return ok;
} }
public void unregister() { private void unregister() {
ServerLevel level = host.getServerLevel(); ServerLevel level = this.host.getServerLevel();
if (!registered || level == null || frequency == 0L) return; if (!this.registered || level == null || this.frequency == 0L) return;
// placerId可以为null公共收发器模式 // placerId可以为null公共收发器模式
WirelessMasterRegistry.unregister(level, frequency, placerId, host); WirelessMasterRegistry.unregister(level, this.frequency, this.placerId, this.host);
registered = false; this.registered = false;
} }
public void onUnloadOrRemove() { public void onUnloadOrRemove() {
unregister(); this.unregister();
} }
} }

View File

@ -1,7 +1,7 @@
package com.extendedae_plus.wireless; package com.extendedae_plus.ae.wireless;
import com.extendedae_plus.config.ModConfigs; import com.extendedae_plus.config.ModConfigs;
import com.extendedae_plus.util.WirelessTeamUtil; import com.extendedae_plus.util.wireless.WirelessTeamUtil;
import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceKey;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
@ -20,15 +20,14 @@ import java.util.UUID;
* 公共模式placerId为null时使用公共UUID所有人都能访问向下兼容旧版本 * 公共模式placerId为null时使用公共UUID所有人都能访问向下兼容旧版本
*/ */
public final class WirelessMasterRegistry { public final class WirelessMasterRegistry {
private WirelessMasterRegistry() {}
private static final Map<Key, WeakReference<IWirelessEndpoint>> MASTERS = new HashMap<>(); private static final Map<Key, WeakReference<IWirelessEndpoint>> MASTERS = new HashMap<>();
/** /**
* 公共收发器UUID用于没有设置所有者的收发器 * 公共收发器UUID用于没有设置所有者的收发器
* 所有placerId为null的收发器都使用这个UUID实现公共访问 * 所有placerId为null的收发器都使用这个UUID实现公共访问
*/ */
public static final UUID PUBLIC_NETWORK_UUID = new UUID(0, 0); private static final UUID PUBLIC_NETWORK_UUID = new UUID(0, 0);
private WirelessMasterRegistry() {}
public static synchronized boolean register(ServerLevel level, long frequency, @Nullable UUID placerId, IWirelessEndpoint endpoint) { public static synchronized boolean register(ServerLevel level, long frequency, @Nullable UUID placerId, IWirelessEndpoint endpoint) {
Objects.requireNonNull(level, "level"); Objects.requireNonNull(level, "level");
@ -54,7 +53,7 @@ public final class WirelessMasterRegistry {
return true; return true;
} }
public static synchronized void unregister(ServerLevel level, long frequency, @Nullable UUID placerId, IWirelessEndpoint endpoint) { static synchronized void unregister(ServerLevel level, long frequency, @Nullable UUID placerId, IWirelessEndpoint endpoint) {
if (frequency == 0L || level == null) return; if (frequency == 0L || level == null) return;
UUID ownerUUID = placerId != null UUID ownerUUID = placerId != null
@ -100,9 +99,9 @@ public final class WirelessMasterRegistry {
private record Key(@Nullable ResourceKey<Level> dim, long freq, UUID owner) { private record Key(@Nullable ResourceKey<Level> dim, long freq, UUID owner) {
@Override @Override
public String toString() { public String toString() {
return (dim == null ? "*" : dim.location().toString()) return (this.dim == null ? "*" : this.dim.location().toString())
+ "#" + freq + "#" + this.freq
+ "@" + owner; + "@" + this.owner;
} }
} }
} }

View File

@ -1,4 +1,4 @@
package com.extendedae_plus.wireless; package com.extendedae_plus.ae.wireless;
import appeng.api.networking.GridHelper; import appeng.api.networking.GridHelper;
import appeng.api.networking.IGridConnection; import appeng.api.networking.IGridConnection;
@ -35,59 +35,59 @@ public class WirelessSlaveLink {
this.placerId = placerId; this.placerId = placerId;
} }
public long getFrequency() {
return this.frequency;
}
public void setFrequency(long frequency) { public void setFrequency(long frequency) {
if (this.frequency != frequency) { if (this.frequency != frequency) {
this.frequency = frequency; this.frequency = frequency;
// 频率变更立即尝试重连/断开 // 频率变更立即尝试重连/断开
updateStatus(); this.updateStatus();
} }
} }
public long getFrequency() {
return frequency;
}
public boolean isConnected() { public boolean isConnected() {
return !shutdown && connection.getConnection() != null; return !this.shutdown && this.connection.getConnection() != null;
} }
public double getDistance() { public double getDistance() {
return distance; return this.distance;
} }
/** /**
* 建议在 BE serverTick 或者频率/加载状态变化时调用 * 建议在 BE serverTick 或者频率/加载状态变化时调用
*/ */
public void updateStatus() { public void updateStatus() {
if (host.isEndpointRemoved()) { if (this.host.isEndpointRemoved()) {
destroyConnection(); this.destroyConnection();
return; return;
} }
final ServerLevel level = host.getServerLevel(); final ServerLevel level = this.host.getServerLevel();
if (level == null || frequency == 0L) { if (level == null || this.frequency == 0L) {
destroyConnection(); this.destroyConnection();
return; return;
} }
// placerId可以为null公共收发器模式 // placerId可以为null公共收发器模式
IWirelessEndpoint master = WirelessMasterRegistry.get(level, frequency, placerId); IWirelessEndpoint master = WirelessMasterRegistry.get(level, this.frequency, this.placerId);
shutdown = false; this.shutdown = false;
distance = 0.0D; this.distance = 0.0D;
boolean crossDim = ModConfigs.WIRELESS_CROSS_DIM_ENABLE.get(); boolean crossDim = ModConfigs.WIRELESS_CROSS_DIM_ENABLE.get();
if (master != null && !master.isEndpointRemoved() && (crossDim || master.getServerLevel() == level)) { if (master != null && !master.isEndpointRemoved() && (crossDim || master.getServerLevel() == level)) {
if (!crossDim) { if (!crossDim) {
distance = Math.sqrt(master.getBlockPos().distSqr(host.getBlockPos())); this.distance = Math.sqrt(master.getBlockPos().distSqr(this.host.getBlockPos()));
} }
double maxRange = ModConfigs.WIRELESS_MAX_RANGE.get(); double maxRange = ModConfigs.WIRELESS_MAX_RANGE.get();
if (crossDim || distance <= maxRange) { if (crossDim || this.distance <= maxRange) {
// 保持/建立连接 // 保持/建立连接
try { try {
var current = connection.getConnection(); var current = this.connection.getConnection();
IGridNode a = host.getGridNode(); // 从端 IGridNode a = this.host.getGridNode(); // 从端
IGridNode b = master.getGridNode(); // 主端 IGridNode b = master.getGridNode(); // 主端
if (a == null || b == null) { if (a == null || b == null) {
shutdown = true; this.shutdown = true;
} else { } else {
if (current != null) { if (current != null) {
// 如果已连且目标相同则维持 // 如果已连且目标相同则维持
@ -98,37 +98,37 @@ public class WirelessSlaveLink {
} }
// 否则先断开再重建 // 否则先断开再重建
current.destroy(); current.destroy();
connection = new ConnectionWrapper(null); this.connection = new ConnectionWrapper(null);
} }
// AE2 侧是否已经存在连接例如此前创建但 wrapper 丢失 // AE2 侧是否已经存在连接例如此前创建但 wrapper 丢失
IGridConnection existing = findExistingConnection(a, b); IGridConnection existing = this.findExistingConnection(a, b);
if (existing != null) { if (existing != null) {
connection = new ConnectionWrapper(existing); this.connection = new ConnectionWrapper(existing);
return; return;
} }
connection = new ConnectionWrapper(GridHelper.createConnection(a, b)); this.connection = new ConnectionWrapper(GridHelper.createConnection(a, b));
return; return;
} }
} catch (IllegalStateException ex) { } catch (IllegalStateException ex) {
// 连接非法如重复连接等落入重建/关闭逻辑 // 连接非法如重复连接等落入重建/关闭逻辑
} }
} else { } else {
shutdown = true; // 超出范围 this.shutdown = true; // 超出范围
} }
} else { } else {
shutdown = true; // 无主或主端不可用 this.shutdown = true; // 无主或主端不可用
} }
// 需要关闭连接 // 需要关闭连接
destroyConnection(); this.destroyConnection();
} }
public void onUnloadOrRemove() { public void onUnloadOrRemove() {
destroyConnection(); this.destroyConnection();
} }
private void destroyConnection() { private void destroyConnection() {
var current = connection.getConnection(); var current = this.connection.getConnection();
if (current != null) { if (current != null) {
var a = current.a(); var a = current.a();
var b = current.b(); var b = current.b();
@ -144,11 +144,11 @@ public class WirelessSlaveLink {
b.getGrid().getTickManager().wakeDevice(b); b.getGrid().getTickManager().wakeDevice(b);
} }
} catch (Throwable ignored) {} } catch (Throwable ignored) {}
connection.setConnection(null); this.connection.setConnection(null);
} else { } else {
// 兜底如果 wrapper 已丢失 AE2 内仍有直连则尝试查找并销毁 // 兜底如果 wrapper 已丢失 AE2 内仍有直连则尝试查找并销毁
try { try {
IGridNode a = host.getGridNode(); IGridNode a = this.host.getGridNode();
if (a != null) { if (a != null) {
for (IGridConnection gc : a.getConnections()) { for (IGridConnection gc : a.getConnections()) {
// 我们创建的是非 in-world 直连 // 我们创建的是非 in-world 直连
@ -165,7 +165,7 @@ public class WirelessSlaveLink {
} }
} catch (Throwable ignored) {} } catch (Throwable ignored) {}
} }
connection = new ConnectionWrapper(null); this.connection = new ConnectionWrapper(null);
} }
/** /**

View File

@ -1,7 +1,7 @@
package com.extendedae_plus.wireless.endpoint; package com.extendedae_plus.ae.wireless.endpoint;
import appeng.api.networking.IGridNode; import appeng.api.networking.IGridNode;
import com.extendedae_plus.wireless.IWirelessEndpoint; import com.extendedae_plus.ae.wireless.IWirelessEndpoint;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
@ -24,7 +24,7 @@ public class GenericNodeEndpointImpl implements IWirelessEndpoint {
@Override @Override
public ServerLevel getServerLevel() { public ServerLevel getServerLevel() {
var be = blockEntitySupplier.get(); var be = this.blockEntitySupplier.get();
if (be == null) return null; if (be == null) return null;
Level lvl = be.getLevel(); Level lvl = be.getLevel();
return (lvl instanceof ServerLevel) ? (ServerLevel) lvl : null; return (lvl instanceof ServerLevel) ? (ServerLevel) lvl : null;
@ -32,18 +32,18 @@ public class GenericNodeEndpointImpl implements IWirelessEndpoint {
@Override @Override
public BlockPos getBlockPos() { public BlockPos getBlockPos() {
var be = blockEntitySupplier.get(); var be = this.blockEntitySupplier.get();
return be != null ? be.getBlockPos() : BlockPos.ZERO; return be != null ? be.getBlockPos() : BlockPos.ZERO;
} }
@Override @Override
public IGridNode getGridNode() { public IGridNode getGridNode() {
return nodeSupplier.get(); return this.nodeSupplier.get();
} }
@Override @Override
public boolean isEndpointRemoved() { public boolean isEndpointRemoved() {
var be = blockEntitySupplier.get(); var be = this.blockEntitySupplier.get();
return be == null || be.isRemoved(); return be == null || be.isRemoved();
} }
} }

View File

@ -1,8 +1,8 @@
package com.extendedae_plus.wireless.endpoint; package com.extendedae_plus.ae.wireless.endpoint;
import appeng.api.networking.IGridNode; import appeng.api.networking.IGridNode;
import appeng.helpers.InterfaceLogicHost; import appeng.helpers.InterfaceLogicHost;
import com.extendedae_plus.wireless.IWirelessEndpoint; import com.extendedae_plus.ae.wireless.IWirelessEndpoint;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
@ -24,7 +24,7 @@ public class InterfaceNodeEndpointImpl implements IWirelessEndpoint {
@Override @Override
public ServerLevel getServerLevel() { public ServerLevel getServerLevel() {
var be = host.getBlockEntity(); var be = this.host.getBlockEntity();
if (be == null) return null; if (be == null) return null;
Level lvl = be.getLevel(); Level lvl = be.getLevel();
return (lvl instanceof ServerLevel) ? (ServerLevel) lvl : null; return (lvl instanceof ServerLevel) ? (ServerLevel) lvl : null;
@ -32,18 +32,18 @@ public class InterfaceNodeEndpointImpl implements IWirelessEndpoint {
@Override @Override
public BlockPos getBlockPos() { public BlockPos getBlockPos() {
var be = host.getBlockEntity(); var be = this.host.getBlockEntity();
return be != null ? be.getBlockPos() : BlockPos.ZERO; return be != null ? be.getBlockPos() : BlockPos.ZERO;
} }
@Override @Override
public IGridNode getGridNode() { public IGridNode getGridNode() {
return nodeSupplier.get(); return this.nodeSupplier.get();
} }
@Override @Override
public boolean isEndpointRemoved() { public boolean isEndpointRemoved() {
var be = host.getBlockEntity(); var be = this.host.getBlockEntity();
return be == null || be.isRemoved(); return be == null || be.isRemoved();
} }
} }

View File

@ -3,7 +3,7 @@ package com.extendedae_plus.api;
/** /**
* {@code GuiExPatternProviderMixin} 实现用于从通用的 Screen Mixin 中更新按钮布局 * {@code GuiExPatternProviderMixin} 实现用于从通用的 Screen Mixin 中更新按钮布局
*/ */
public interface ExPatternButtonsAccessor { public interface IExPatternButton {
/** /**
* 在每帧调用以维护扩展样板供应器右侧按钮的可见性重注册窗口尺寸变化与定位 * 在每帧调用以维护扩展样板供应器右侧按钮的可见性重注册窗口尺寸变化与定位
*/ */

View File

@ -3,6 +3,6 @@ package com.extendedae_plus.api;
/** /**
* GuiExPatternProviderMixin 实现用于在客户端侧提供当前页号避免反射读取 AE2 内部字段失败 * GuiExPatternProviderMixin 实现用于在客户端侧提供当前页号避免反射读取 AE2 内部字段失败
*/ */
public interface ExPatternPageAccessor { public interface IExPatternPage {
int eap$getCurrentPage(); int eap$getCurrentPage();
} }

View File

@ -1,4 +1,4 @@
package com.extendedae_plus.util; package com.extendedae_plus.api;
import appeng.client.gui.style.Blitter; import appeng.client.gui.style.Blitter;
import appeng.client.gui.style.WidgetStyle; import appeng.client.gui.style.WidgetStyle;

View File

@ -1,5 +0,0 @@
package com.extendedae_plus.api;
public interface PatternProviderMenuAdvancedSync {
boolean eap$getAdvancedBlockingSynced();
}

View File

@ -1,5 +0,0 @@
package com.extendedae_plus.api;
public interface PatternProviderMenuDoublingSync {
boolean eap$getSmartDoublingSynced();
}

View File

@ -1,6 +0,0 @@
package com.extendedae_plus.api;
public interface SmartDoublingAwarePattern {
boolean eap$allowScaling();
void eap$setAllowScaling(boolean allow);
}

View File

@ -1,6 +1,6 @@
package com.extendedae_plus.api; package com.extendedae_plus.api.advancedBlocking;
public interface AdvancedBlockingHolder { public interface IAdvancedBlocking {
boolean eap$getAdvancedBlocking(); boolean eap$getAdvancedBlocking();
void eap$setAdvancedBlocking(boolean value); void eap$setAdvancedBlocking(boolean value);

View File

@ -0,0 +1,5 @@
package com.extendedae_plus.api.advancedBlocking;
public interface IPatternProviderMenuAdvancedSync {
boolean eap$getAdvancedBlockingSynced();
}

View File

@ -1,4 +1,4 @@
package com.extendedae_plus.bridge; package com.extendedae_plus.api.bridge;
import appeng.api.upgrades.IUpgradeInventory; import appeng.api.upgrades.IUpgradeInventory;

View File

@ -1,4 +1,4 @@
package com.extendedae_plus.bridge; package com.extendedae_plus.api.bridge;
import appeng.menu.ToolboxMenu; import appeng.menu.ToolboxMenu;

View File

@ -1,4 +1,4 @@
package com.extendedae_plus.bridge; package com.extendedae_plus.api.bridge;
/** /**
* mixin 包下的桥接接口 mixin 进行 instanceof 检测和回调 * mixin 包下的桥接接口 mixin 进行 instanceof 检测和回调

View File

@ -1,4 +1,4 @@
package com.extendedae_plus.content; package com.extendedae_plus.api.crafting;
import appeng.api.crafting.IPatternDetails; import appeng.api.crafting.IPatternDetails;
import appeng.api.stacks.AEItemKey; import appeng.api.stacks.AEItemKey;
@ -46,54 +46,46 @@ public final class ScaledProcessingPattern implements IPatternDetails {
/* -------------------- API 实现 -------------------- */ /* -------------------- API 实现 -------------------- */
public AEProcessingPattern getOriginal() { public AEProcessingPattern getOriginal() {
return original; return this.original;
} }
@Override @Override
public AEItemKey getDefinition() { public AEItemKey getDefinition() {
return definition; return this.definition;
} }
@Override @Override
public IInput[] getInputs() { public IInput[] getInputs() {
return inputs; return this.inputs;
}
@Override
public List<GenericStack> getOutputs() {
return condensedOutputs;
}
public List<GenericStack> getSparseInputs() {
return sparseInputs;
}
public List<GenericStack> getSparseOutputs() {
return sparseOutputs;
} }
@Override @Override
public GenericStack getPrimaryOutput() { public GenericStack getPrimaryOutput() {
if (!condensedOutputs.isEmpty()) return condensedOutputs.get(0); if (!this.condensedOutputs.isEmpty()) return this.condensedOutputs.get(0);
return original.getPrimaryOutput(); return this.original.getPrimaryOutput();
}
@Override
public List<GenericStack> getOutputs() {
return this.condensedOutputs;
} }
@Override @Override
public boolean supportsPushInputsToExternalInventory() { public boolean supportsPushInputsToExternalInventory() {
return original.supportsPushInputsToExternalInventory(); return this.original.supportsPushInputsToExternalInventory();
} }
@Override @Override
public void pushInputsToExternalInventory(KeyCounter[] inputHolder, PatternInputSink inputSink) { public void pushInputsToExternalInventory(KeyCounter[] inputHolder, PatternInputSink inputSink) {
// 保持和 AEProcessingPattern 一致 sparseInputs 驱动 // 保持和 AEProcessingPattern 一致 sparseInputs 驱动
if (sparseInputs.size() == inputs.length) { if (this.sparseInputs.size() == this.inputs.length) {
IPatternDetails.super.pushInputsToExternalInventory(inputHolder, inputSink); IPatternDetails.super.pushInputsToExternalInventory(inputHolder, inputSink);
} else { } else {
KeyCounter allInputs = new KeyCounter(); KeyCounter allInputs = new KeyCounter();
for (KeyCounter counter : inputHolder) { for (KeyCounter counter : inputHolder) {
allInputs.addAll(counter); allInputs.addAll(counter);
} }
for (GenericStack sparseInput : sparseInputs) { for (GenericStack sparseInput : this.sparseInputs) {
if (sparseInput != null) { if (sparseInput != null) {
AEKey key = sparseInput.what(); AEKey key = sparseInput.what();
long amount = sparseInput.amount(); long amount = sparseInput.amount();
@ -109,6 +101,14 @@ public final class ScaledProcessingPattern implements IPatternDetails {
} }
} }
public List<GenericStack> getSparseInputs() {
return this.sparseInputs;
}
public List<GenericStack> getSparseOutputs() {
return this.sparseOutputs;
}
/* -------------------- 缩放输入代理 -------------------- */ /* -------------------- 缩放输入代理 -------------------- */
public static final class Input implements IPatternDetails.IInput { public static final class Input implements IPatternDetails.IInput {
@ -120,18 +120,22 @@ public final class ScaledProcessingPattern implements IPatternDetails {
this.multiplier = multiplier; this.multiplier = multiplier;
} }
@Override
public GenericStack[] getPossibleInputs() { public GenericStack[] getPossibleInputs() {
return this.template; return this.template;
} }
@Override
public long getMultiplier() { public long getMultiplier() {
return this.multiplier; return this.multiplier;
} }
@Override
public boolean isValid(AEKey input, Level level) { public boolean isValid(AEKey input, Level level) {
return input.matches(this.template[0]); return input.matches(this.template[0]);
} }
@Override
public @Nullable AEKey getRemainingKey(AEKey template) { public @Nullable AEKey getRemainingKey(AEKey template) {
return null; return null;
} }

View File

@ -0,0 +1,7 @@
package com.extendedae_plus.api.smartDoubling;
import appeng.api.networking.IGrid;
public interface ICraftingCalculationExt {
IGrid getGrid();
}

View File

@ -0,0 +1,5 @@
package com.extendedae_plus.api.smartDoubling;
public interface IPatternProviderMenuDoublingSync {
boolean eap$getSmartDoublingSynced();
}

View File

@ -1,6 +1,6 @@
package com.extendedae_plus.api; package com.extendedae_plus.api.smartDoubling;
public interface SmartDoublingHolder { public interface ISmartDoubling {
boolean eap$getSmartDoubling(); boolean eap$getSmartDoubling();
void eap$setSmartDoubling(boolean value); void eap$setSmartDoubling(boolean value);
} }

View File

@ -0,0 +1,6 @@
package com.extendedae_plus.api.smartDoubling;
public interface ISmartDoublingAwarePattern {
boolean eap$allowScaling();
void eap$setAllowScaling(boolean allow);
}

View File

@ -1,9 +1,9 @@
package com.extendedae_plus.ae.api.storage; package com.extendedae_plus.api.storage;
import appeng.api.storage.cells.ICellHandler; import appeng.api.storage.cells.ICellHandler;
import appeng.api.storage.cells.ISaveProvider; import appeng.api.storage.cells.ISaveProvider;
import com.extendedae_plus.ExtendedAEPlus; import com.extendedae_plus.ExtendedAEPlus;
import com.extendedae_plus.ae.items.InfinityBigIntegerCellItem; import com.extendedae_plus.items.InfinityBigIntegerCellItem;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
public class InfinityBigIntegerCellHandler implements ICellHandler { public class InfinityBigIntegerCellHandler implements ICellHandler {

View File

@ -1,4 +1,4 @@
package com.extendedae_plus.ae.api.storage; package com.extendedae_plus.api.storage;
import appeng.api.config.Actionable; import appeng.api.config.Actionable;
import appeng.api.networking.security.IActionSource; import appeng.api.networking.security.IActionSource;
@ -9,7 +9,7 @@ import appeng.api.storage.cells.CellState;
import appeng.api.storage.cells.ISaveProvider; import appeng.api.storage.cells.ISaveProvider;
import appeng.api.storage.cells.StorageCell; import appeng.api.storage.cells.StorageCell;
import appeng.core.AELog; import appeng.core.AELog;
import com.extendedae_plus.ae.items.InfinityBigIntegerCellItem; import com.extendedae_plus.items.InfinityBigIntegerCellItem;
import com.extendedae_plus.util.storage.InfinityConstants; import com.extendedae_plus.util.storage.InfinityConstants;
import com.extendedae_plus.util.storage.InfinityDataStorage; import com.extendedae_plus.util.storage.InfinityDataStorage;
import com.extendedae_plus.util.storage.InfinityStorageManager; import com.extendedae_plus.util.storage.InfinityStorageManager;
@ -51,10 +51,10 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
private boolean isPersisted = true; private boolean isPersisted = true;
public InfinityBigIntegerCellInventory(InfinityBigIntegerCellItem cell, private InfinityBigIntegerCellInventory(InfinityBigIntegerCellItem cell,
ItemStack stack, ItemStack stack,
ISaveProvider saveProvider, ISaveProvider saveProvider,
@Nullable InfinityStorageManager storageManager) { @Nullable InfinityStorageManager storageManager) {
// 保存存储单元类型InfinityBigIntegerCellItem 实例用于访问磁盘属性 // 保存存储单元类型InfinityBigIntegerCellItem 实例用于访问磁盘属性
this.cell = cell; this.cell = cell;
// 保存物品堆栈表示磁盘本身包含运行时的 NBT 数据 // 保存物品堆栈表示磁盘本身包含运行时的 NBT 数据
@ -65,7 +65,7 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
this.AEKey2AmountsMap = null; this.AEKey2AmountsMap = null;
this.storageManager = storageManager; this.storageManager = storageManager;
// 初始化磁盘数据 // 初始化磁盘数据
initData(); this.initData();
} }
// BigInteger 格式化为带单位的字符串保留两位小数 // BigInteger 格式化为带单位的字符串保留两位小数
@ -87,9 +87,9 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
} }
// 静态方法创建存储单元库存 // 静态方法创建存储单元库存
public static InfinityBigIntegerCellInventory createInventory(ItemStack stack, static InfinityBigIntegerCellInventory createInventory(ItemStack stack,
ISaveProvider saveProvider, ISaveProvider saveProvider,
@Nullable InfinityStorageManager storageManager) { @Nullable InfinityStorageManager storageManager) {
// 检查物品堆栈是否为空 // 检查物品堆栈是否为空
Objects.requireNonNull(stack, "Cannot create cell inventory for null itemstack"); Objects.requireNonNull(stack, "Cannot create cell inventory for null itemstack");
// 检查物品是否为 IDISKCellItem 类型 // 检查物品是否为 IDISKCellItem 类型
@ -103,8 +103,8 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
// 获取磁盘的 InfinityDataStorage 数据 // 获取磁盘的 InfinityDataStorage 数据
private InfinityDataStorage getCellStorage() { private InfinityDataStorage getCellStorage() {
// 如果磁盘有 UUID返回对应的 InfinityDataStorage // 如果磁盘有 UUID返回对应的 InfinityDataStorage
if (getUUID() != null && this.storageManager != null) { if (this.getUUID() != null && this.storageManager != null) {
return storageManager.getOrCreateCell(getUUID()); return this.storageManager.getOrCreateCell(this.getUUID());
} else { } else {
// 否则返回空的 InfinityDataStorage // 否则返回空的 InfinityDataStorage
return InfinityDataStorage.EMPTY; return InfinityDataStorage.EMPTY;
@ -114,18 +114,18 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
// 初始化磁盘数据 // 初始化磁盘数据
private void initData() { private void initData() {
// 如果磁盘有 UUID加载存储的物品数据 // 如果磁盘有 UUID加载存储的物品数据
if (hasUUID()) { if (this.hasUUID()) {
this.totalAEKeyType = getCellStorage().amounts.size(); this.totalAEKeyType = this.getCellStorage().amounts.size();
this.totalAEKey2Amounts = getCellStorage().itemCount.equals(BigInteger.ZERO) ? this.totalAEKey2Amounts = this.getCellStorage().itemCount.equals(BigInteger.ZERO) ?
BigInteger.ZERO : BigInteger.ZERO :
getCellStorage().itemCount; this.getCellStorage().itemCount;
} else { } else {
// 否则初始化为空 // 否则初始化为空
this.totalAEKeyType = 0; this.totalAEKeyType = 0;
this.totalAEKey2Amounts = BigInteger.ZERO; this.totalAEKey2Amounts = BigInteger.ZERO;
// 加载物品数据 // 加载物品数据
getCellStoredMap(); this.getCellStoredMap();
} }
} }
@ -153,10 +153,10 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
return; return;
if (this.totalAEKey2Amounts.equals(BigInteger.ZERO)) { if (this.totalAEKey2Amounts.equals(BigInteger.ZERO)) {
if (hasUUID()) { if (this.hasUUID()) {
this.storageManager.removeCell(getUUID()); this.storageManager.removeCell(this.getUUID());
// DataComponents.CUSTOM_DATA 里移除对应字段 // DataComponents.CUSTOM_DATA 里移除对应字段
CustomData data = self.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY); CustomData data = this.self.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY);
CompoundTag tag = data.copyTag(); CompoundTag tag = data.copyTag();
tag.remove(InfinityConstants.INFINITY_CELL_UUID); tag.remove(InfinityConstants.INFINITY_CELL_UUID);
tag.remove(InfinityConstants.INFINITY_ITEM_TOTAL); tag.remove(InfinityConstants.INFINITY_ITEM_TOTAL);
@ -164,9 +164,9 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
// backward compat // backward compat
tag.remove(InfinityConstants.INFINITY_CELL_ITEM_COUNT); tag.remove(InfinityConstants.INFINITY_CELL_ITEM_COUNT);
self.set(DataComponents.CUSTOM_DATA, CustomData.of(tag)); this.self.set(DataComponents.CUSTOM_DATA, CustomData.of(tag));
initData(); this.initData();
} }
return; return;
} }
@ -192,9 +192,9 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
} }
if (keys.isEmpty()) { if (keys.isEmpty()) {
this.storageManager.updateCell(getUUID(), new InfinityDataStorage()); this.storageManager.updateCell(this.getUUID(), new InfinityDataStorage());
} else { } else {
this.storageManager.modifyDisk(getUUID(), keys, amounts, itemCount); this.storageManager.modifyDisk(this.getUUID(), keys, amounts, itemCount);
} }
// 更新存储的物品种类数量 // 更新存储的物品种类数量
@ -204,23 +204,17 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
// 将物品总数与种类数量存入物品堆栈的 NBT用于快捷查看tooltip同时保留旧字段以兼容历史版本 // 将物品总数与种类数量存入物品堆栈的 NBT用于快捷查看tooltip同时保留旧字段以兼容历史版本
// 写回 DataComponents.CUSTOM_DATA替代 getOrCreateTag // 写回 DataComponents.CUSTOM_DATA替代 getOrCreateTag
CompoundTag tag = self.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).copyTag(); CompoundTag tag = this.self.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).copyTag();
tag.putByteArray(InfinityConstants.INFINITY_ITEM_TOTAL, itemCount.toByteArray()); tag.putByteArray(InfinityConstants.INFINITY_ITEM_TOTAL, itemCount.toByteArray());
tag.putInt(InfinityConstants.INFINITY_ITEM_TYPES, this.totalAEKeyType); tag.putInt(InfinityConstants.INFINITY_ITEM_TYPES, this.totalAEKeyType);
tag.putByteArray(InfinityConstants.INFINITY_CELL_ITEM_COUNT, itemCount.toByteArray()); tag.putByteArray(InfinityConstants.INFINITY_CELL_ITEM_COUNT, itemCount.toByteArray());
self.set(DataComponents.CUSTOM_DATA, CustomData.of(tag)); this.self.set(DataComponents.CUSTOM_DATA, CustomData.of(tag));
// 标记数据已持久化 // 标记数据已持久化
this.isPersisted = true; this.isPersisted = true;
} }
// 获取存储单元的描述此处返回null可自定义
@Override
public Component getDescription() {
return null;
}
// 获取存储的物品总数 // 获取存储的物品总数
public BigInteger getTotalAEKey2Amounts() { private BigInteger getTotalAEKey2Amounts() {
return this.totalAEKey2Amounts; return this.totalAEKey2Amounts;
} }
@ -230,14 +224,14 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
} }
// 判断物品堆栈是否有UUID // 判断物品堆栈是否有UUID
public boolean hasUUID() { private boolean hasUUID() {
CustomData data = self.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY); CustomData data = this.self.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY);
return !data.isEmpty() && data.copyTag().contains(InfinityConstants.INFINITY_CELL_UUID); return !data.isEmpty() && data.copyTag().contains(InfinityConstants.INFINITY_CELL_UUID);
} }
// 获取物品堆栈的UUID // 获取物品堆栈的UUID
public UUID getUUID() { public UUID getUUID() {
CustomData data = self.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY); CustomData data = this.self.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY);
if (!data.isEmpty() && data.copyTag().contains(InfinityConstants.INFINITY_CELL_UUID)) { if (!data.isEmpty() && data.copyTag().contains(InfinityConstants.INFINITY_CELL_UUID)) {
return data.copyTag().getUUID(InfinityConstants.INFINITY_CELL_UUID); return data.copyTag().getUUID(InfinityConstants.INFINITY_CELL_UUID);
} }
@ -246,40 +240,13 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
// 获取或初始化存储映射 // 获取或初始化存储映射
private Object2ObjectMap<AEKey, BigInteger> getCellStoredMap() { private Object2ObjectMap<AEKey, BigInteger> getCellStoredMap() {
if (AEKey2AmountsMap == null) { if (this.AEKey2AmountsMap == null) {
AEKey2AmountsMap = new Object2ObjectOpenHashMap<>(); this.AEKey2AmountsMap = new Object2ObjectOpenHashMap<>();
this.loadCellStoredMap(); this.loadCellStoredMap();
} }
return AEKey2AmountsMap; return this.AEKey2AmountsMap;
} }
// 获取所有可用的物品堆栈及其数量
@Override
public void getAvailableStacks(KeyCounter out) {
BigInteger maxLong = BigInteger.valueOf(Long.MAX_VALUE);
if (this.getCellStoredMap() == null) return;
for (var entry : this.getCellStoredMap().object2ObjectEntrySet()) {
AEKey key = entry.getKey();
BigInteger value = entry.getValue();
// 获取 KeyCounter 中已有的值
long existing = out.get(key);
// 计算总和并限制到 Long.MAX_VALUE
BigInteger sum = BigInteger.valueOf(existing).add(value);
long toSet = sum.compareTo(maxLong) > 0 ? Long.MAX_VALUE : sum.longValue();
// 更新 KeyCounter
if (existing == Long.MAX_VALUE) {
continue;
}
long delta = toSet - existing;
if (delta != 0) {
out.add(key, delta);
}
}
}
// 从存储中加载物品映射 // 从存储中加载物品映射
private void loadCellStoredMap() { private void loadCellStoredMap() {
if (this.storageManager == null) { if (this.storageManager == null) {
@ -287,10 +254,10 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
} }
boolean dataCorruption = false; boolean dataCorruption = false;
if (self.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).isEmpty()) return; if (this.self.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).isEmpty()) return;
var keys = getCellStorage().keys; var keys = this.getCellStorage().keys;
var amounts = getCellStorage().amounts; var amounts = this.getCellStorage().amounts;
// 数据损坏 // 数据损坏
if (keys.size() != amounts.size()) { if (keys.size() != amounts.size()) {
AELog.warn("Loading storage cell with mismatched amounts/tags: %d != %d", amounts.size(), keys.size()); AELog.warn("Loading storage cell with mismatched amounts/tags: %d != %d", amounts.size(), keys.size());
@ -306,7 +273,7 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
if (amount.compareTo(BigInteger.ZERO) <= 0 || key == null) { if (amount.compareTo(BigInteger.ZERO) <= 0 || key == null) {
dataCorruption = true; dataCorruption = true;
} else { } else {
AEKey2AmountsMap.put(key, amount); this.AEKey2AmountsMap.put(key, amount);
} }
} }
if (dataCorruption) { if (dataCorruption) {
@ -351,9 +318,9 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
} }
// 如果没有 UUID且服务器端存储管理器已就绪则生成 UUID 并初始化存储 // 如果没有 UUID且服务器端存储管理器已就绪则生成 UUID 并初始化存储
if (storageManager != null && !this.hasUUID()) { if (this.storageManager != null && !this.hasUUID()) {
// 取出自定义 NBT如果没有就返回空 // 取出自定义 NBT如果没有就返回空
CustomData data = self.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY); CustomData data = this.self.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY);
CompoundTag tag = data.copyTag(); CompoundTag tag = data.copyTag();
// 生成新的 UUID 并写入 // 生成新的 UUID 并写入
@ -361,13 +328,13 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
tag.putUUID(InfinityConstants.INFINITY_CELL_UUID, newUUID); tag.putUUID(InfinityConstants.INFINITY_CELL_UUID, newUUID);
// 回写到 ItemStack // 回写到 ItemStack
self.set(DataComponents.CUSTOM_DATA, CustomData.of(tag)); this.self.set(DataComponents.CUSTOM_DATA, CustomData.of(tag));
// 初始化存储 // 初始化存储
this.storageManager.getOrCreateCell(newUUID); this.storageManager.getOrCreateCell(newUUID);
// 加载已存储的映射 // 加载已存储的映射
loadCellStoredMap(); this.loadCellStoredMap();
} }
// 获取当前物品数量 // 获取当前物品数量
BigInteger currentAmount = this.getCellStoredMap().getOrDefault(what, BigInteger.ZERO); BigInteger currentAmount = this.getCellStoredMap().getOrDefault(what, BigInteger.ZERO);
@ -375,7 +342,7 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
if (mode == Actionable.MODULATE) { if (mode == Actionable.MODULATE) {
// 实际插入更新数量并保存 // 实际插入更新数量并保存
BigInteger newAmount = currentAmount.add(BigInteger.valueOf(amount)); BigInteger newAmount = currentAmount.add(BigInteger.valueOf(amount));
getCellStoredMap().put(what, newAmount); this.getCellStoredMap().put(what, newAmount);
this.saveChanges(); this.saveChanges();
} }
return amount; return amount;
@ -393,14 +360,14 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
// 如果提取数量大于等于当前数量 // 如果提取数量大于等于当前数量
if (requested.compareTo(currentAmount) >= 0) { if (requested.compareTo(currentAmount) >= 0) {
if (mode == Actionable.MODULATE) { if (mode == Actionable.MODULATE) {
getCellStoredMap().remove(what); this.getCellStoredMap().remove(what);
this.saveChanges(); this.saveChanges();
} }
return currentAmount.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0 ? Long.MAX_VALUE : currentAmount.longValue(); return currentAmount.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0 ? Long.MAX_VALUE : currentAmount.longValue();
} else { } else {
// 提取部分数量 // 提取部分数量
if (mode == Actionable.MODULATE) { if (mode == Actionable.MODULATE) {
getCellStoredMap().put(what, currentAmount.subtract(requested)); this.getCellStoredMap().put(what, currentAmount.subtract(requested));
this.saveChanges(); this.saveChanges();
} }
return requested.longValue(); return requested.longValue();
@ -409,9 +376,41 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
return 0; return 0;
} }
// 获取所有可用的物品堆栈及其数量
@Override
public void getAvailableStacks(KeyCounter out) {
BigInteger maxLong = BigInteger.valueOf(Long.MAX_VALUE);
if (this.getCellStoredMap() == null) return;
for (var entry : this.getCellStoredMap().object2ObjectEntrySet()) {
AEKey key = entry.getKey();
BigInteger value = entry.getValue();
// 获取 KeyCounter 中已有的值
long existing = out.get(key);
// 计算总和并限制到 Long.MAX_VALUE
BigInteger sum = BigInteger.valueOf(existing).add(value);
long toSet = sum.compareTo(maxLong) > 0 ? Long.MAX_VALUE : sum.longValue();
// 更新 KeyCounter
if (existing == Long.MAX_VALUE) {
continue;
}
long delta = toSet - existing;
if (delta != 0) {
out.add(key, delta);
}
}
}
// 获取存储单元的描述此处返回null可自定义
@Override
public Component getDescription() {
return null;
}
// 获取存储单元内所有物品的总数量格式化字符串 // 获取存储单元内所有物品的总数量格式化字符串
public String getTotalStorage() { public String getTotalStorage() {
// 使用缓存的 totalStored避免每次全表扫描 // 使用缓存的 totalStored避免每次全表扫描
return formatBigInteger(totalAEKey2Amounts); return formatBigInteger(this.totalAEKey2Amounts);
} }
} }

View File

@ -3,13 +3,13 @@ package com.extendedae_plus.client;
import appeng.client.render.crafting.CraftingCubeModel; import appeng.client.render.crafting.CraftingCubeModel;
import appeng.init.client.InitScreens; import appeng.init.client.InitScreens;
import com.extendedae_plus.ExtendedAEPlus; import com.extendedae_plus.ExtendedAEPlus;
import com.extendedae_plus.ae.definitions.upgrades.EntitySpeedCardItem;
import com.extendedae_plus.ae.screen.EntitySpeedTickerScreen; import com.extendedae_plus.ae.screen.EntitySpeedTickerScreen;
import com.extendedae_plus.client.render.crafting.EPlusCraftingCubeModelProvider; import com.extendedae_plus.client.render.crafting.EPlusCraftingCubeModelProvider;
import com.extendedae_plus.content.crafting.EPlusCraftingUnitType; import com.extendedae_plus.content.crafting.EPlusCraftingUnitType;
import com.extendedae_plus.hooks.BuiltInModelHooks; import com.extendedae_plus.hooks.BuiltInModelHooks;
import com.extendedae_plus.init.ModItems; import com.extendedae_plus.init.ModItems;
import com.extendedae_plus.init.ModMenuTypes; import com.extendedae_plus.init.ModMenuTypes;
import com.extendedae_plus.items.materials.EntitySpeedCardItem;
import net.minecraft.client.renderer.item.ItemProperties; import net.minecraft.client.renderer.item.ItemProperties;
import net.neoforged.api.distmarker.Dist; import net.neoforged.api.distmarker.Dist;
import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.bus.api.SubscribeEvent;
@ -21,10 +21,10 @@ import net.neoforged.neoforge.client.event.RegisterMenuScreensEvent;
*/ */
@EventBusSubscriber(modid = ExtendedAEPlus.MODID, value = Dist.CLIENT) @EventBusSubscriber(modid = ExtendedAEPlus.MODID, value = Dist.CLIENT)
public final class ClientProxy { public final class ClientProxy {
private ClientProxy() {}
private static boolean REGISTERED = false; private static boolean REGISTERED = false;
private ClientProxy() {}
public static void init() { public static void init() {
if (REGISTERED) return; if (REGISTERED) return;
REGISTERED = true; REGISTERED = true;

View File

@ -1,4 +1,4 @@
package com.extendedae_plus.client; package com.extendedae_plus.client.event;
import com.extendedae_plus.ExtendedAEPlus; import com.extendedae_plus.ExtendedAEPlus;
import com.extendedae_plus.init.ModItems; import com.extendedae_plus.init.ModItems;

View File

@ -1,22 +1,19 @@
package com.extendedae_plus; package com.extendedae_plus.client.gui;
import appeng.client.gui.style.Blitter; import appeng.client.gui.style.Blitter;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
public class NewIcon { public class NewIcon {
@SuppressWarnings("all")
// 贴图当前存放于 assets/extendedae_plus/textures/gui/nicons.png
// MODID (extendedaeplus) 不同因此这里直接指定贴图所在命名空间
private static final ResourceLocation TEXTURE = ResourceLocation.fromNamespaceAndPath("extendedae_plus", "textures/gui/nicons.png");
public static final Blitter MULTIPLY2; public static final Blitter MULTIPLY2;
public static final Blitter DIVIDE2; public static final Blitter DIVIDE2;
public static final Blitter MULTIPLY5; public static final Blitter MULTIPLY5;
public static final Blitter DIVIDE5; public static final Blitter DIVIDE5;
public static final Blitter MULTIPLY10; public static final Blitter MULTIPLY10;
public static final Blitter DIVIDE10; public static final Blitter DIVIDE10;
@SuppressWarnings("all")
// 贴图当前存放于 assets/extendedae_plus/textures/gui/nicons.png
// MODID (extendedaeplus) 不同因此这里直接指定贴图所在命名空间
private static final ResourceLocation TEXTURE = ResourceLocation.fromNamespaceAndPath("extendedae_plus", "textures/gui/nicons.png");
static { static {
MULTIPLY2 = Blitter.texture(TEXTURE, 64, 64).src(32, 0, 16, 16); MULTIPLY2 = Blitter.texture(TEXTURE, 64, 64).src(32, 0, 16, 16);

View File

@ -1,36 +0,0 @@
package com.extendedae_plus.client.gui;
public final class PageLayoutContext {
private static final ThreadLocal<Boolean> ACTIVE = ThreadLocal.withInitial(() -> false);
private static final ThreadLocal<Integer> CURRENT_PAGE = ThreadLocal.withInitial(() -> 0);
private PageLayoutContext() {}
public static void enable(int page) {
ACTIVE.set(true);
CURRENT_PAGE.set(page);
}
public static void disable() {
ACTIVE.set(false);
}
public static boolean isActive() {
Boolean b = ACTIVE.get();
return b != null && b;
}
public static int getCurrentPage() {
Integer i = CURRENT_PAGE.get();
return i != null ? i : 0;
}
public static void withPage(int page, Runnable action) {
enable(page);
try {
action.run();
} finally {
disable();
}
}
}

View File

@ -1,4 +1,4 @@
package com.extendedae_plus.client.ui; package com.extendedae_plus.client.screen;
import com.extendedae_plus.network.SetWirelessFrequencyC2SPacket; import com.extendedae_plus.network.SetWirelessFrequencyC2SPacket;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
@ -35,60 +35,17 @@ public class FrequencyInputScreen extends Screen {
* @param pos 无线收发器的位置 * @param pos 无线收发器的位置
* @param currentFrequency 当前频率 * @param currentFrequency 当前频率
*/ */
public FrequencyInputScreen(BlockPos pos, long currentFrequency) { private FrequencyInputScreen(BlockPos pos, long currentFrequency) {
super(Component.translatable("gui.extendedae_plus.frequency_input.title")); super(Component.translatable("gui.extendedae_plus.frequency_input.title"));
this.pos = pos; this.pos = pos;
this.currentFrequency = currentFrequency; this.currentFrequency = currentFrequency;
} }
@Override /**
protected void init() { * 静态工厂方法打开频率输入界面
super.init(); */
public static void open(BlockPos pos, long currentFrequency) {
// 计算居中位置 Minecraft.getInstance().setScreen(new FrequencyInputScreen(pos, currentFrequency));
int x = (this.width - WINDOW_WIDTH) / 2;
int y = (this.height - WINDOW_HEIGHT) / 2;
// 创建输入框
// API说明EditBox构造函数参数font, x, y, width, height, component
this.frequencyInput = new EditBox(
this.font,
x + 10,
y + 30,
WINDOW_WIDTH - 20,
20,
Component.translatable("gui.extendedae_plus.frequency_input.field")
);
// 设置输入框属性
this.frequencyInput.setMaxLength(19); // long类型最大19位数字
this.frequencyInput.setValue(String.valueOf(currentFrequency));
this.frequencyInput.setFilter(this::isValidInput); // 只允许数字和负号
this.frequencyInput.setFocused(true);
// 添加输入框到组件列表
this.addRenderableWidget(this.frequencyInput);
// 创建确认按钮
// API说明Button.builder方法在1.21.1中使用
this.confirmButton = Button.builder(
Component.translatable("gui.extendedae_plus.frequency_input.confirm"),
button -> this.onConfirm()
)
.bounds(x + 10, y + 55, 80, 20)
.build();
this.addRenderableWidget(this.confirmButton);
// 创建取消按钮
Button cancelButton = Button.builder(
Component.translatable("gui.extendedae_plus.frequency_input.cancel"),
button -> this.onClose()
)
.bounds(x + 110, y + 55, 80, 20)
.build();
this.addRenderableWidget(cancelButton);
} }
/** /**
@ -110,26 +67,6 @@ public class FrequencyInputScreen extends Screen {
} }
} }
/**
* 按键处理回车键确认ESC键取消
*
* API说明keyPressed方法在1.21.1中保持一致
*/
@Override
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
// 回车键确认
if (keyCode == 257 || keyCode == 335) { // ENTER or NUMPAD_ENTER
this.onConfirm();
return true;
}
// ESC键取消
if (keyCode == 256) { // ESC
this.onClose();
return true;
}
return super.keyPressed(keyCode, scanCode, modifiers);
}
/** /**
* 渲染背景 * 渲染背景
* *
@ -167,6 +104,85 @@ public class FrequencyInputScreen extends Screen {
); );
} }
/**
* 按键处理回车键确认ESC键取消
*
* API说明keyPressed方法在1.21.1中保持一致
*/
@Override
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
// 回车键确认
if (keyCode == 257 || keyCode == 335) { // ENTER or NUMPAD_ENTER
this.onConfirm();
return true;
}
// ESC键取消
if (keyCode == 256) { // ESC
this.onClose();
return true;
}
return super.keyPressed(keyCode, scanCode, modifiers);
}
@Override
protected void init() {
super.init();
// 计算居中位置
int x = (this.width - WINDOW_WIDTH) / 2;
int y = (this.height - WINDOW_HEIGHT) / 2;
// 创建输入框
// API说明EditBox构造函数参数font, x, y, width, height, component
this.frequencyInput = new EditBox(
this.font,
x + 10,
y + 30,
WINDOW_WIDTH - 20,
20,
Component.translatable("gui.extendedae_plus.frequency_input.field")
);
// 设置输入框属性
this.frequencyInput.setMaxLength(19); // long类型最大19位数字
this.frequencyInput.setValue(String.valueOf(this.currentFrequency));
this.frequencyInput.setFilter(this::isValidInput); // 只允许数字和负号
this.frequencyInput.setFocused(true);
// 添加输入框到组件列表
this.addRenderableWidget(this.frequencyInput);
// 创建确认按钮
// API说明Button.builder方法在1.21.1中使用
this.confirmButton = Button.builder(
Component.translatable("gui.extendedae_plus.frequency_input.confirm"),
button -> this.onConfirm()
)
.bounds(x + 10, y + 55, 80, 20)
.build();
this.addRenderableWidget(this.confirmButton);
// 创建取消按钮
Button cancelButton = Button.builder(
Component.translatable("gui.extendedae_plus.frequency_input.cancel"),
button -> this.onClose()
)
.bounds(x + 110, y + 55, 80, 20)
.build();
this.addRenderableWidget(cancelButton);
}
/**
* 暂停游戏状态
* 返回false表示不暂停游戏允许多人游戏中正常使用
*/
@Override
public boolean isPauseScreen() {
return false;
}
/** /**
* 确认按钮处理 * 确认按钮处理
*/ */
@ -182,28 +198,12 @@ public class FrequencyInputScreen extends Screen {
// 发送数据包到服务端 // 发送数据包到服务端
// API说明NeoForge使用PacketDistributor.sendToServer // API说明NeoForge使用PacketDistributor.sendToServer
PacketDistributor.sendToServer(new SetWirelessFrequencyC2SPacket(pos, frequency)); PacketDistributor.sendToServer(new SetWirelessFrequencyC2SPacket(this.pos, frequency));
this.onClose(); this.onClose();
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
// 输入无效不做处理 // 输入无效不做处理
} }
} }
/**
* 暂停游戏状态
* 返回false表示不暂停游戏允许多人游戏中正常使用
*/
@Override
public boolean isPauseScreen() {
return false;
}
/**
* 静态工厂方法打开频率输入界面
*/
public static void open(BlockPos pos, long currentFrequency) {
Minecraft.getInstance().setScreen(new FrequencyInputScreen(pos, currentFrequency));
}
} }

View File

@ -1,6 +1,7 @@
package com.extendedae_plus.client.ui; package com.extendedae_plus.client.screen;
import com.extendedae_plus.network.UploadEncodedPatternToProviderC2SPacket; import com.extendedae_plus.network.UploadEncodedPatternToProviderC2SPacket;
import com.extendedae_plus.util.uploadPattern.ExtendedAEPatternUploadUtil;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.EditBox; import net.minecraft.client.gui.components.EditBox;
@ -14,35 +15,33 @@ import java.util.*;
* 展示若干个可点击的供应器条目点击后发送带 providerId 的上传请求 * 展示若干个可点击的供应器条目点击后发送带 providerId 的上传请求
*/ */
public class ProviderSelectScreen extends Screen { public class ProviderSelectScreen extends Screen {
private static final int PAGE_SIZE = 6;
// 优先使用 JEC 的拼音匹配否则回退到大小写不敏感子串匹配
private static Boolean JEC_AVAILABLE = null;
private static java.lang.reflect.Method JEC_CONTAINS = null;
private final Screen parent; private final Screen parent;
// 原始数据 // 原始数据
private final List<Long> ids; private final List<Long> ids;
private final List<String> names; private final List<String> names;
private final List<Integer> emptySlots; private final List<Integer> emptySlots;
// 分组后的数据同名合并 // 分组后的数据同名合并
private final List<Long> gIds = new ArrayList<>(); // 代表条目使用的 providerId选择空位数最多的那个 private final List<Long> gIds = new ArrayList<>(); // 代表条目使用的 providerId选择空位数最多的那个
private final List<String> gNames = new ArrayList<>(); // 分组名供应器名称 private final List<String> gNames = new ArrayList<>(); // 分组名供应器名称
private final List<Integer> gTotalSlots = new ArrayList<>(); // 该名称下供应器空位总和 private final List<Integer> gTotalSlots = new ArrayList<>(); // 该名称下供应器空位总和
private final List<Integer> gCount = new ArrayList<>(); // 该名称下供应器数量 private final List<Integer> gCount = new ArrayList<>(); // 该名称下供应器数量
// 过滤后的数据由查询生成 // 过滤后的数据由查询生成
private final List<Long> fIds = new ArrayList<>(); private final List<Long> fIds = new ArrayList<>();
private final List<String> fNames = new ArrayList<>(); private final List<String> fNames = new ArrayList<>();
private final List<Integer> fTotalSlots = new ArrayList<>(); private final List<Integer> fTotalSlots = new ArrayList<>();
private final List<Integer> fCount = new ArrayList<>(); private final List<Integer> fCount = new ArrayList<>();
private final List<Button> entryButtons = new ArrayList<>();
// 搜索框 // 搜索框
private EditBox searchBox; private EditBox searchBox;
// 中文名输入框用于添加映射 // 中文名输入框用于添加映射
private EditBox cnInput; private EditBox cnInput;
private String query = ""; private String query = "";
private boolean needsRefresh = false; private boolean needsRefresh = false;
private int page = 0; private int page = 0;
private static final int PAGE_SIZE = 6;
private final List<Button> entryButtons = new ArrayList<>();
public ProviderSelectScreen(Screen parent, List<Long> ids, List<String> names, List<Integer> emptySlots) { public ProviderSelectScreen(Screen parent, List<Long> ids, List<String> names, List<Integer> emptySlots) {
super(Component.translatable("extendedae_plus.screen.choose_provider.title")); super(Component.translatable("extendedae_plus.screen.choose_provider.title"));
@ -52,218 +51,17 @@ public class ProviderSelectScreen extends Screen {
this.emptySlots = emptySlots; this.emptySlots = emptySlots;
// 如果有来自 JEI 的最近处理名称则作为初始查询 // 如果有来自 JEI 的最近处理名称则作为初始查询
try { try {
String recent = com.extendedae_plus.util.ExtendedAEPatternUploadUtil.lastProcessingName; String recent = ExtendedAEPatternUploadUtil.lastProcessingName;
if (recent != null && !recent.isBlank()) { if (recent != null && !recent.isBlank()) {
this.query = recent; this.query = recent;
// 用后即清空避免污染下次 // 用后即清空避免污染下次
com.extendedae_plus.util.ExtendedAEPatternUploadUtil.lastProcessingName = null; ExtendedAEPatternUploadUtil.lastProcessingName = null;
} }
} catch (Throwable ignored) {} } catch (Throwable ignored) {}
buildGroups(); this.buildGroups();
applyFilter(); this.applyFilter();
} }
@Override
protected void init() {
this.clearWidgets();
entryButtons.clear();
int centerX = this.width / 2;
int startY = this.height / 2 - 70;
// 搜索框置于条目上方
if (searchBox == null) {
searchBox = new EditBox(this.font, centerX - 120, startY - 25, 240, 18, Component.translatable("extendedae_plus.screen.search"));
} else {
// 重新定位保持输入值
searchBox.setX(centerX - 120);
searchBox.setY(startY - 25);
searchBox.setWidth(240);
}
searchBox.setValue(query);
searchBox.setResponder(text -> {
// 只有当输入真正发生变化时才重置页码与过滤
if (Objects.equals(text, query)) return;
query = text;
page = 0;
applyFilter();
// 避免在回调中直接重建 UI延迟到下一次 tick
needsRefresh = true;
});
this.addRenderableWidget(searchBox);
int start = page * PAGE_SIZE;
int end = Math.min(start + PAGE_SIZE, fIds.size());
int buttonWidth = 240;
int buttonHeight = 20;
int gap = 5;
for (int i = start; i < end; i++) {
int idx = i;
String label = buildLabel(idx);
Button btn = Button.builder(Component.literal(label), b -> onChoose(idx))
.bounds(centerX - buttonWidth / 2, startY + (i - start) * (buttonHeight + gap), buttonWidth, buttonHeight)
.build();
entryButtons.add(btn);
this.addRenderableWidget(btn);
}
// 分页按钮
int navY = startY + PAGE_SIZE * (buttonHeight + gap) + 10;
Button prev = Button.builder(Component.literal("<"), b -> changePage(-1))
.bounds(centerX - 60, navY, 20, 20)
.build();
Button next = Button.builder(Component.literal(">"), b -> changePage(1))
.bounds(centerX + 40, navY, 20, 20)
.build();
prev.active = page > 0;
next.active = (page + 1) * PAGE_SIZE < fIds.size();
this.addRenderableWidget(prev);
this.addRenderableWidget(next);
// 重载映射按钮热重载 recipe_type_names.json移至下一行与关闭按钮并排
Button reload = Button.builder(Component.translatable("extendedae_plus.screen.reload_mapping"), b -> reloadMapping())
.bounds(centerX - 130, navY + 30, 80, 20)
.build();
this.addRenderableWidget(reload);
// 中文名输入框用于新增映射的值
if (cnInput == null) {
cnInput = new EditBox(this.font, centerX + 50, navY + 30, 120, 20, Component.translatable("extendedae_plus.screen.cn_name"));
} else {
cnInput.setX(centerX + 50);
cnInput.setY(navY + 30);
cnInput.setWidth(120);
}
this.addRenderableWidget(cnInput);
// 增加映射按钮使用当前搜索关键字 -> 中文
Button addMap = Button.builder(Component.translatable("extendedae_plus.screen.add_mapping"), b -> addMappingFromUI())
.bounds(centerX + 175, navY + 30, 60, 20)
.build();
this.addRenderableWidget(addMap);
// 删除映射按中文值精确匹配删除按钮
Button delByCn = Button.builder(Component.literal("删除映射"), b -> deleteMappingByCnFromUI())
.bounds(centerX + 240, navY + 30, 60, 20)
.build();
this.addRenderableWidget(delByCn);
// 关闭按钮
Button close = Button.builder(Component.translatable("gui.cancel"), b -> onClose())
.bounds(centerX - 40, navY + 30, 80, 20)
.build();
this.addRenderableWidget(close);
}
private void changePage(int delta) {
int newPage = page + delta;
if (newPage < 0) return;
if (newPage * PAGE_SIZE >= fIds.size()) return;
page = newPage;
// 避免在回调中直接重建 UI改为下帧刷新
needsRefresh = true;
}
private void reloadMapping() {
try {
com.extendedae_plus.util.ExtendedAEPatternUploadUtil.loadRecipeTypeNames();
var player = Minecraft.getInstance().player;
if (player != null) {
player.sendSystemMessage(Component.literal("ExtendedAE Plus: 已重载映射表"));
}
// 重载后不强制刷新筛选但如需立即应用到名称匹配可手动编辑搜索框或翻页
} catch (Throwable t) {
var player = Minecraft.getInstance().player;
if (player != null) {
player.sendSystemMessage(Component.literal("ExtendedAE Plus: 重载映射表失败: " + t.getClass().getSimpleName()));
}
}
}
private String buildLabel(int idx) {
String name = fNames.get(idx);
int totalSlots = fTotalSlots.get(idx);
int count = fCount.get(idx);
// 不显示具体 id显示合并统计名称总空位x数量
return name + " (" + totalSlots + ") x" + count;
}
private void onChoose(int idx) {
if (idx < 0 || idx >= fIds.size()) return;
long providerId = fIds.get(idx);
var conn = Minecraft.getInstance().getConnection();
if (conn != null) {
conn.send(new UploadEncodedPatternToProviderC2SPacket(providerId));
}
this.onClose();
}
@Override
public void onClose() {
Minecraft.getInstance().setScreen(parent);
}
@Override
public boolean isPauseScreen() {
return false;
}
private void buildGroups() {
// 使用 LinkedHashMap 保持首次出现顺序
Map<String, Group> map = new LinkedHashMap<>();
for (int i = 0; i < names.size(); i++) {
String name = names.get(i);
long id = ids.get(i);
int slots = emptySlots.get(i);
Group g = map.computeIfAbsent(name, k -> new Group());
g.count++;
g.totalSlots += Math.max(0, slots);
// 挑选空位最多的作为代表 id若并列保留先到者
if (slots > g.bestSlots) {
g.bestSlots = slots;
g.bestId = id;
}
}
for (Map.Entry<String, Group> e : map.entrySet()) {
String name = e.getKey();
Group g = e.getValue();
gNames.add(name);
gIds.add(g.bestId);
gTotalSlots.add(g.totalSlots);
gCount.add(g.count);
}
}
private static class Group {
long bestId = Long.MIN_VALUE;
int bestSlots = Integer.MIN_VALUE;
int totalSlots = 0;
int count = 0;
}
private void applyFilter() {
fIds.clear();
fNames.clear();
fTotalSlots.clear();
fCount.clear();
String q = query == null ? "" : query.trim();
for (int i = 0; i < gIds.size(); i++) {
String name = gNames.get(i);
if (q.isEmpty() || nameMatches(name, q)) {
fIds.add(gIds.get(i));
fNames.add(name);
fTotalSlots.add(gTotalSlots.get(i));
fCount.add(gCount.get(i));
}
}
}
// 优先使用 JEC 的拼音匹配否则回退到大小写不敏感子串匹配
private static Boolean JEC_AVAILABLE = null;
private static java.lang.reflect.Method JEC_CONTAINS = null;
private static boolean nameMatches(String name, String key) { private static boolean nameMatches(String name, String key) {
if (name == null) return false; if (name == null) return false;
if (key == null || key.isEmpty()) return true; if (key == null || key.isEmpty()) return true;
@ -294,20 +92,212 @@ public class ProviderSelectScreen extends Screen {
return name.toLowerCase().contains(key.toLowerCase()); return name.toLowerCase().contains(key.toLowerCase());
} }
private void changePage(int delta) {
int newPage = this.page + delta;
if (newPage < 0) return;
if (newPage * PAGE_SIZE >= this.fIds.size()) return;
this.page = newPage;
// 避免在回调中直接重建 UI改为下帧刷新
this.needsRefresh = true;
}
private void reloadMapping() {
try {
ExtendedAEPatternUploadUtil.loadRecipeTypeNames();
var player = Minecraft.getInstance().player;
if (player != null) {
player.sendSystemMessage(Component.literal("ExtendedAE Plus: 已重载映射表"));
}
// 重载后不强制刷新筛选但如需立即应用到名称匹配可手动编辑搜索框或翻页
} catch (Throwable t) {
var player = Minecraft.getInstance().player;
if (player != null) {
player.sendSystemMessage(Component.literal("ExtendedAE Plus: 重载映射表失败: " + t.getClass().getSimpleName()));
}
}
}
private String buildLabel(int idx) {
String name = this.fNames.get(idx);
int totalSlots = this.fTotalSlots.get(idx);
int count = this.fCount.get(idx);
// 不显示具体 id显示合并统计名称总空位x数量
return name + " (" + totalSlots + ") x" + count;
}
private void onChoose(int idx) {
if (idx < 0 || idx >= this.fIds.size()) return;
long providerId = this.fIds.get(idx);
var conn = Minecraft.getInstance().getConnection();
if (conn != null) {
conn.send(new UploadEncodedPatternToProviderC2SPacket(providerId));
}
this.onClose();
}
private void buildGroups() {
// 使用 LinkedHashMap 保持首次出现顺序
Map<String, Group> map = new LinkedHashMap<>();
for (int i = 0; i < this.names.size(); i++) {
String name = this.names.get(i);
long id = this.ids.get(i);
int slots = this.emptySlots.get(i);
Group g = map.computeIfAbsent(name, k -> new Group());
g.count++;
g.totalSlots += Math.max(0, slots);
// 挑选空位最多的作为代表 id若并列保留先到者
if (slots > g.bestSlots) {
g.bestSlots = slots;
g.bestId = id;
}
}
for (Map.Entry<String, Group> e : map.entrySet()) {
String name = e.getKey();
Group g = e.getValue();
this.gNames.add(name);
this.gIds.add(g.bestId);
this.gTotalSlots.add(g.totalSlots);
this.gCount.add(g.count);
}
}
private void applyFilter() {
this.fIds.clear();
this.fNames.clear();
this.fTotalSlots.clear();
this.fCount.clear();
String q = this.query == null ? "" : this.query.trim();
for (int i = 0; i < this.gIds.size(); i++) {
String name = this.gNames.get(i);
if (q.isEmpty() || nameMatches(name, q)) {
this.fIds.add(this.gIds.get(i));
this.fNames.add(name);
this.fTotalSlots.add(this.gTotalSlots.get(i));
this.fCount.add(this.gCount.get(i));
}
}
}
@Override @Override
public boolean keyPressed(int keyCode, int scanCode, int modifiers) { public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
if (searchBox != null && searchBox.keyPressed(keyCode, scanCode, modifiers)) { if (this.searchBox != null && this.searchBox.keyPressed(keyCode, scanCode, modifiers)) {
return true; return true;
} }
return super.keyPressed(keyCode, scanCode, modifiers); return super.keyPressed(keyCode, scanCode, modifiers);
} }
@Override @Override
public boolean charTyped(char codePoint, int modifiers) { public void onClose() {
if (searchBox != null && searchBox.charTyped(codePoint, modifiers)) { Minecraft.getInstance().setScreen(this.parent);
return true; }
@Override
protected void init() {
this.clearWidgets();
this.entryButtons.clear();
int centerX = this.width / 2;
int startY = this.height / 2 - 70;
// 搜索框置于条目上方
if (this.searchBox == null) {
this.searchBox = new EditBox(this.font, centerX - 120, startY - 25, 240, 18, Component.translatable("extendedae_plus.screen.search"));
} else {
// 重新定位保持输入值
this.searchBox.setX(centerX - 120);
this.searchBox.setY(startY - 25);
this.searchBox.setWidth(240);
} }
return super.charTyped(codePoint, modifiers); this.searchBox.setValue(this.query);
this.searchBox.setResponder(text -> {
// 只有当输入真正发生变化时才重置页码与过滤
if (Objects.equals(text, this.query)) return;
this.query = text;
this.page = 0;
this.applyFilter();
// 避免在回调中直接重建 UI延迟到下一次 tick
this.needsRefresh = true;
});
this.addRenderableWidget(this.searchBox);
int start = this.page * PAGE_SIZE;
int end = Math.min(start + PAGE_SIZE, this.fIds.size());
int buttonWidth = 240;
int buttonHeight = 20;
int gap = 5;
for (int i = start; i < end; i++) {
int idx = i;
String label = this.buildLabel(idx);
Button btn = Button.builder(Component.literal(label), b -> this.onChoose(idx))
.bounds(centerX - buttonWidth / 2, startY + (i - start) * (buttonHeight + gap), buttonWidth, buttonHeight)
.build();
this.entryButtons.add(btn);
this.addRenderableWidget(btn);
}
// 分页按钮
int navY = startY + PAGE_SIZE * (buttonHeight + gap) + 10;
Button prev = Button.builder(Component.literal("<"), b -> this.changePage(-1))
.bounds(centerX - 60, navY, 20, 20)
.build();
Button next = Button.builder(Component.literal(">"), b -> this.changePage(1))
.bounds(centerX + 40, navY, 20, 20)
.build();
prev.active = this.page > 0;
next.active = (this.page + 1) * PAGE_SIZE < this.fIds.size();
this.addRenderableWidget(prev);
this.addRenderableWidget(next);
// 重载映射按钮热重载 recipe_type_names.json移至下一行与关闭按钮并排
Button reload = Button.builder(Component.translatable("extendedae_plus.screen.reload_mapping"), b -> this.reloadMapping())
.bounds(centerX - 130, navY + 30, 80, 20)
.build();
this.addRenderableWidget(reload);
// 中文名输入框用于新增映射的值
if (this.cnInput == null) {
this.cnInput = new EditBox(this.font, centerX + 50, navY + 30, 120, 20, Component.translatable("extendedae_plus.screen.cn_name"));
} else {
this.cnInput.setX(centerX + 50);
this.cnInput.setY(navY + 30);
this.cnInput.setWidth(120);
}
this.addRenderableWidget(this.cnInput);
// 增加映射按钮使用当前搜索关键字 -> 中文
Button addMap = Button.builder(Component.translatable("extendedae_plus.screen.add_mapping"), b -> this.addMappingFromUI())
.bounds(centerX + 175, navY + 30, 60, 20)
.build();
this.addRenderableWidget(addMap);
// 删除映射按中文值精确匹配删除按钮
Button delByCn = Button.builder(Component.literal("删除映射"), b -> this.deleteMappingByCnFromUI())
.bounds(centerX + 240, navY + 30, 60, 20)
.build();
this.addRenderableWidget(delByCn);
// 关闭按钮
Button close = Button.builder(Component.translatable("gui.cancel"), b -> this.onClose())
.bounds(centerX - 40, navY + 30, 80, 20)
.build();
this.addRenderableWidget(close);
}
@Override
public void tick() {
super.tick();
if (this.needsRefresh) {
this.needsRefresh = false;
// 重新构建当前屏幕内容
this.init();
}
}
@Override
public boolean isPauseScreen() {
return false;
} }
@Override @Override
@ -324,7 +314,7 @@ public class ProviderSelectScreen extends Screen {
} }
this.query = ""; this.query = "";
this.page = 0; this.page = 0;
applyFilter(); this.applyFilter();
this.needsRefresh = true; this.needsRefresh = true;
return true; return true;
} }
@ -333,18 +323,16 @@ public class ProviderSelectScreen extends Screen {
} }
@Override @Override
public void tick() { public boolean charTyped(char codePoint, int modifiers) {
super.tick(); if (this.searchBox != null && this.searchBox.charTyped(codePoint, modifiers)) {
if (needsRefresh) { return true;
needsRefresh = false;
// 重新构建当前屏幕内容
init();
} }
return super.charTyped(codePoint, modifiers);
} }
private void addMappingFromUI() { private void addMappingFromUI() {
String key = query == null ? "" : query.trim(); String key = this.query == null ? "" : this.query.trim();
String val = cnInput == null ? "" : cnInput.getValue().trim(); String val = this.cnInput == null ? "" : this.cnInput.getValue().trim();
var player = Minecraft.getInstance().player; var player = Minecraft.getInstance().player;
if (key.isEmpty()) { if (key.isEmpty()) {
if (player != null) player.sendSystemMessage(Component.literal("请输入搜索关键字后再添加映射")); if (player != null) player.sendSystemMessage(Component.literal("请输入搜索关键字后再添加映射"));
@ -354,7 +342,7 @@ public class ProviderSelectScreen extends Screen {
if (player != null) player.sendSystemMessage(Component.literal("请输入中文名称")); if (player != null) player.sendSystemMessage(Component.literal("请输入中文名称"));
return; return;
} }
boolean ok = com.extendedae_plus.util.ExtendedAEPatternUploadUtil.addOrUpdateAliasMapping(key, val); boolean ok = ExtendedAEPatternUploadUtil.addOrUpdateAliasMapping(key, val);
if (ok) { if (ok) {
if (player != null) player.sendSystemMessage(Component.literal("已添加/更新映射: " + key + " -> " + val)); if (player != null) player.sendSystemMessage(Component.literal("已添加/更新映射: " + key + " -> " + val));
// 将刚添加的中文名写入搜索框作为当前查询 // 将刚添加的中文名写入搜索框作为当前查询
@ -363,10 +351,10 @@ public class ProviderSelectScreen extends Screen {
this.searchBox.setValue(val); this.searchBox.setValue(val);
} }
// 更新本地过滤显示若名称包含中文可被搜索 // 更新本地过滤显示若名称包含中文可被搜索
applyFilter(); this.applyFilter();
// 回到第一页以展示最新筛选结果 // 回到第一页以展示最新筛选结果
page = 0; this.page = 0;
needsRefresh = true; this.needsRefresh = true;
} else { } else {
if (player != null) player.sendSystemMessage(Component.literal("写入映射失败")); if (player != null) player.sendSystemMessage(Component.literal("写入映射失败"));
} }
@ -374,19 +362,26 @@ public class ProviderSelectScreen extends Screen {
// 使用中文值精确匹配删除映射 // 使用中文值精确匹配删除映射
private void deleteMappingByCnFromUI() { private void deleteMappingByCnFromUI() {
String val = cnInput == null ? "" : cnInput.getValue().trim(); String val = this.cnInput == null ? "" : this.cnInput.getValue().trim();
var player = Minecraft.getInstance().player; var player = Minecraft.getInstance().player;
if (val.isEmpty()) { if (val.isEmpty()) {
if (player != null) player.sendSystemMessage(Component.literal("请输入中文名称后再删除映射")); if (player != null) player.sendSystemMessage(Component.literal("请输入中文名称后再删除映射"));
return; return;
} }
int removed = com.extendedae_plus.util.ExtendedAEPatternUploadUtil.removeMappingsByCnValue(val); int removed = ExtendedAEPatternUploadUtil.removeMappingsByCnValue(val);
if (removed > 0) { if (removed > 0) {
if (player != null) player.sendSystemMessage(Component.literal("已删除 " + removed + " 条映射,中文= " + val)); if (player != null) player.sendSystemMessage(Component.literal("已删除 " + removed + " 条映射,中文= " + val));
applyFilter(); this.applyFilter();
needsRefresh = true; this.needsRefresh = true;
} else { } else {
if (player != null) player.sendSystemMessage(Component.literal("未找到中文为 '" + val + "' 的映射")); if (player != null) player.sendSystemMessage(Component.literal("未找到中文为 '" + val + "' 的映射"));
} }
} }
private static class Group {
long bestId = Long.MIN_VALUE;
int bestSlots = Integer.MIN_VALUE;
int totalSlots = 0;
int count = 0;
}
} }

View File

@ -1,8 +1,8 @@
package com.extendedae_plus.content.wireless; package com.extendedae_plus.content.wireless;
import com.extendedae_plus.ae.items.ChannelCardItem;
import com.extendedae_plus.init.ModBlockEntities; import com.extendedae_plus.init.ModBlockEntities;
import com.extendedae_plus.init.ModItems; import com.extendedae_plus.init.ModItems;
import com.extendedae_plus.items.materials.ChannelCardItem;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionHand;
@ -34,6 +34,14 @@ public class WirelessTransceiverBlock extends Block implements EntityBlock {
return new WirelessTransceiverBlockEntity(pos, state); return new WirelessTransceiverBlockEntity(pos, state);
} }
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> type) {
if (level.isClientSide) return null;
return type == ModBlockEntities.WIRELESS_TRANSCEIVER_BE.get()
? (lvl, pos, st, be) -> WirelessTransceiverBlockEntity.serverTick(lvl, pos, st, (WirelessTransceiverBlockEntity) be)
: null;
}
@Override @Override
public void setPlacedBy(Level level, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack stack) { public void setPlacedBy(Level level, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack stack) {
super.setPlacedBy(level, pos, state, placer, stack); super.setPlacedBy(level, pos, state, placer, stack);
@ -45,41 +53,6 @@ public class WirelessTransceiverBlock extends Block implements EntityBlock {
} }
} }
@Override
public void attack(BlockState state, Level level, BlockPos pos, Player player) {
if (!level.isClientSide) {
BlockEntity be = level.getBlockEntity(pos);
if (be instanceof WirelessTransceiverBlockEntity te) {
ItemStack mainHand = player.getMainHandItem();
// 潜行左键频道卡写入频道卡信息到收发器
if (player.isShiftKeyDown() && mainHand.getItem() == ModItems.CHANNEL_CARD.get()) {
handleChannelCardBinding(te, mainHand, player);
super.attack(state, level, pos, player);
return;
}
// 潜行左键其他物品减频-1 -10
if (player.isShiftKeyDown()) {
if (te.isLocked()) {
player.displayClientMessage(Component.literal("收发器已锁定,无法修改频道"), true);
super.attack(state, level, pos, player);
return;
}
int step = 1;
if (mainHand.is(Items.REDSTONE_TORCH)) step = 10;
if (mainHand.is(Items.STICK)) step = 10;
long f = te.getFrequency();
f -= step;
if (f < 0) f = 0;
te.setFrequency(f);
player.displayClientMessage(Component.literal("频道:" + te.getFrequency()), true);
}
}
}
super.attack(state, level, pos, player);
}
/** /**
* 处理频道卡绑定到收发器 * 处理频道卡绑定到收发器
*/ */
@ -101,6 +74,54 @@ public class WirelessTransceiverBlock extends Block implements EntityBlock {
} }
} }
@Override
public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) {
if (!state.is(newState.getBlock())) {
BlockEntity be = level.getBlockEntity(pos);
if (be instanceof WirelessTransceiverBlockEntity te) {
te.onRemoved();
}
}
super.onRemove(state, level, pos, newState, isMoving);
}
@Override
protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hit) {
BlockEntity be = level.getBlockEntity(pos);
if (!(be instanceof WirelessTransceiverBlockEntity te)) {
return InteractionResult.PASS;
}
boolean sneaking = player.isShiftKeyDown();
if (sneaking) {
if (te.isLocked()) {
if (!level.isClientSide) {
player.displayClientMessage(Component.literal("收发器已锁定,无法修改频道"), true);
}
} else {
long f = te.getFrequency();
// 空手交互按主手逻辑 +1
f += 1;
te.setFrequency(f);
if (!level.isClientSide) {
player.displayClientMessage(Component.literal("频道:" + te.getFrequency()), true);
}
}
return InteractionResult.sidedSuccess(level.isClientSide);
} else {
if (te.isLocked()) {
if (!level.isClientSide) {
player.displayClientMessage(Component.literal("收发器已锁定,无法切换模式"), true);
}
return InteractionResult.sidedSuccess(level.isClientSide);
}
te.setMasterMode(!te.isMasterMode());
if (!level.isClientSide) {
player.displayClientMessage(Component.literal(te.isMasterMode() ? "模式:主端" : "模式:从端"), true);
}
return InteractionResult.sidedSuccess(level.isClientSide);
}
}
// 1.21+: 拆分为 useItemOn useWithoutItem // 1.21+: 拆分为 useItemOn useWithoutItem
@Override @Override
protected ItemInteractionResult useItemOn(net.minecraft.world.item.ItemStack heldItem, BlockState state, Level level, BlockPos pos, protected ItemInteractionResult useItemOn(net.minecraft.world.item.ItemStack heldItem, BlockState state, Level level, BlockPos pos,
@ -150,58 +171,37 @@ public class WirelessTransceiverBlock extends Block implements EntityBlock {
} }
@Override @Override
protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hit) { public void attack(BlockState state, Level level, BlockPos pos, Player player) {
BlockEntity be = level.getBlockEntity(pos); if (!level.isClientSide) {
if (!(be instanceof WirelessTransceiverBlockEntity te)) { BlockEntity be = level.getBlockEntity(pos);
return InteractionResult.PASS; if (be instanceof WirelessTransceiverBlockEntity te) {
} ItemStack mainHand = player.getMainHandItem();
boolean sneaking = player.isShiftKeyDown();
if (sneaking) { // 潜行左键频道卡写入频道卡信息到收发器
if (te.isLocked()) { if (player.isShiftKeyDown() && mainHand.getItem() == ModItems.CHANNEL_CARD.get()) {
if (!level.isClientSide) { this.handleChannelCardBinding(te, mainHand, player);
player.displayClientMessage(Component.literal("收发器已锁定,无法修改频道"), true); super.attack(state, level, pos, player);
return;
} }
} else {
long f = te.getFrequency(); // 潜行左键其他物品减频-1 -10
// 空手交互按主手逻辑 +1 if (player.isShiftKeyDown()) {
f += 1; if (te.isLocked()) {
te.setFrequency(f); player.displayClientMessage(Component.literal("收发器已锁定,无法修改频道"), true);
if (!level.isClientSide) { super.attack(state, level, pos, player);
return;
}
int step = 1;
if (mainHand.is(Items.REDSTONE_TORCH)) step = 10;
if (mainHand.is(Items.STICK)) step = 10;
long f = te.getFrequency();
f -= step;
if (f < 0) f = 0;
te.setFrequency(f);
player.displayClientMessage(Component.literal("频道:" + te.getFrequency()), true); player.displayClientMessage(Component.literal("频道:" + te.getFrequency()), true);
} }
} }
return InteractionResult.sidedSuccess(level.isClientSide);
} else {
if (te.isLocked()) {
if (!level.isClientSide) {
player.displayClientMessage(Component.literal("收发器已锁定,无法切换模式"), true);
}
return InteractionResult.sidedSuccess(level.isClientSide);
}
te.setMasterMode(!te.isMasterMode());
if (!level.isClientSide) {
player.displayClientMessage(Component.literal(te.isMasterMode() ? "模式:主端" : "模式:从端"), true);
}
return InteractionResult.sidedSuccess(level.isClientSide);
} }
} super.attack(state, level, pos, player);
@Override
public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) {
if (!state.is(newState.getBlock())) {
BlockEntity be = level.getBlockEntity(pos);
if (be instanceof WirelessTransceiverBlockEntity te) {
te.onRemoved();
}
}
super.onRemove(state, level, pos, newState, isMoving);
}
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> type) {
if (level.isClientSide) return null;
return type == ModBlockEntities.WIRELESS_TRANSCEIVER_BE.get()
? (lvl, pos, st, be) -> WirelessTransceiverBlockEntity.serverTick(lvl, pos, st, (WirelessTransceiverBlockEntity) be)
: null;
} }
} }

View File

@ -3,11 +3,11 @@ package com.extendedae_plus.content.wireless;
import appeng.api.networking.*; import appeng.api.networking.*;
import appeng.api.util.AECableType; import appeng.api.util.AECableType;
import appeng.blockentity.AEBaseBlockEntity; import appeng.blockentity.AEBaseBlockEntity;
import com.extendedae_plus.ae.wireless.IWirelessEndpoint;
import com.extendedae_plus.ae.wireless.WirelessMasterLink;
import com.extendedae_plus.ae.wireless.WirelessSlaveLink;
import com.extendedae_plus.init.ModBlockEntities; import com.extendedae_plus.init.ModBlockEntities;
import com.extendedae_plus.init.ModItems; import com.extendedae_plus.init.ModItems;
import com.extendedae_plus.wireless.IWirelessEndpoint;
import com.extendedae_plus.wireless.WirelessMasterLink;
import com.extendedae_plus.wireless.WirelessSlaveLink;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.core.HolderLookup; import net.minecraft.core.HolderLookup;
@ -60,6 +60,21 @@ public class WirelessTransceiverBlockEntity extends AEBaseBlockEntity implements
this.slaveLink = new WirelessSlaveLink(this); this.slaveLink = new WirelessSlaveLink(this);
} }
/* ===================== Tick ===================== */
static void serverTick(Level level, BlockPos pos, BlockState state, WirelessTransceiverBlockEntity be) {
if (!(level instanceof ServerLevel)) return;
if (!be.masterMode) {
// 从端需要周期检查与维护连接
be.slaveLink.updateStatus();
}
}
/* ===================== IInWorldGridNodeHost ===================== */
@Override
public @Nullable IGridNode getGridNode(Direction dir) {
return this.getGridNode();
}
@Override @Override
public AECableType getCableConnectionType(Direction dir) { public AECableType getCableConnectionType(Direction dir) {
// 根据相邻方块的实际连接类型渲染优先采用相邻主机返回的类型回退为 GLASS // 根据相邻方块的实际连接类型渲染优先采用相邻主机返回的类型回退为 GLASS
@ -74,12 +89,6 @@ public class WirelessTransceiverBlockEntity extends AEBaseBlockEntity implements
return AECableType.GLASS; return AECableType.GLASS;
} }
/* ===================== IInWorldGridNodeHost ===================== */
@Override
public @Nullable IGridNode getGridNode(Direction dir) {
return getGridNode();
}
/* ===================== IWirelessEndpoint ===================== */ /* ===================== IWirelessEndpoint ===================== */
@Override @Override
public ServerLevel getServerLevel() { public ServerLevel getServerLevel() {
@ -87,14 +96,9 @@ public class WirelessTransceiverBlockEntity extends AEBaseBlockEntity implements
return lvl instanceof ServerLevel sl ? sl : null; return lvl instanceof ServerLevel sl ? sl : null;
} }
@Override
public BlockPos getBlockPos() {
return this.worldPosition;
}
@Override @Override
public IGridNode getGridNode() { public IGridNode getGridNode() {
return managedNode == null ? null : managedNode.getNode(); return this.managedNode == null ? null : this.managedNode.getNode();
} }
@Override @Override
@ -104,56 +108,61 @@ public class WirelessTransceiverBlockEntity extends AEBaseBlockEntity implements
/* ===================== 公共方法(交互调用) ===================== */ /* ===================== 公共方法(交互调用) ===================== */
@Override
public BlockPos getBlockPos() {
return this.worldPosition;
}
/** /**
* 设置放置者UUID和名称在方块放置时调用 * 设置放置者UUID和名称在方块放置时调用
*/ */
public void setPlacerId(@Nullable UUID placerId, @Nullable String placerName) { void setPlacerId(@Nullable UUID placerId, @Nullable String placerName) {
if (this.placerId != null && !this.placerId.equals(placerId)) { if (this.placerId != null && !this.placerId.equals(placerId)) {
// 如果所有者改变需要重新注册 // 如果所有者改变需要重新注册
if (this.masterMode) { if (this.masterMode) {
masterLink.onUnloadOrRemove(); this.masterLink.onUnloadOrRemove();
} else { } else {
slaveLink.onUnloadOrRemove(); this.slaveLink.onUnloadOrRemove();
} }
} }
this.placerId = placerId; this.placerId = placerId;
this.placerName = placerName; this.placerName = placerName;
this.masterLink.setPlacerId(placerId); this.masterLink.setPlacerId(placerId);
this.slaveLink.setPlacerId(placerId); this.slaveLink.setPlacerId(placerId);
setChanged(); this.setChanged();
}
@Nullable
public UUID getPlacerId() {
return this.placerId;
} }
/** /**
* 仅设置UUID兼容旧代码 * 仅设置UUID兼容旧代码
*/ */
public void setPlacerId(@Nullable UUID placerId) { public void setPlacerId(@Nullable UUID placerId) {
setPlacerId(placerId, null); this.setPlacerId(placerId, null);
}
@Nullable
public UUID getPlacerId() {
return placerId;
} }
@Nullable @Nullable
public String getPlacerName() { public String getPlacerName() {
return placerName; return this.placerName;
} }
public long getFrequency() { public long getFrequency() {
return frequency; return this.frequency;
} }
public void setFrequency(long frequency) { public void setFrequency(long frequency) {
if (this.locked) return; if (this.locked) return;
if (this.frequency == frequency) return; if (this.frequency == frequency) return;
this.frequency = frequency; this.frequency = frequency;
if (isMasterMode()) { if (this.isMasterMode()) {
masterLink.setFrequency(frequency); this.masterLink.setFrequency(frequency);
} else { } else {
slaveLink.setFrequency(frequency); this.slaveLink.setFrequency(frequency);
} }
setChanged(); this.setChanged();
} }
/** /**
@ -163,64 +172,55 @@ public class WirelessTransceiverBlockEntity extends AEBaseBlockEntity implements
public void setFrequencyForced(long frequency) { public void setFrequencyForced(long frequency) {
if (this.frequency == frequency) return; if (this.frequency == frequency) return;
this.frequency = frequency; this.frequency = frequency;
if (isMasterMode()) { if (this.isMasterMode()) {
masterLink.setFrequency(frequency); this.masterLink.setFrequency(frequency);
} else { } else {
slaveLink.setFrequency(frequency); this.slaveLink.setFrequency(frequency);
} }
setChanged(); this.setChanged();
} }
public boolean isMasterMode() { public boolean isMasterMode() {
return masterMode; return this.masterMode;
} }
public void setMasterMode(boolean masterMode) { void setMasterMode(boolean masterMode) {
if (this.locked) return; if (this.locked) return;
if (this.masterMode == masterMode) return; if (this.masterMode == masterMode) return;
// 切换前清理原模式状态 // 切换前清理原模式状态
if (this.masterMode) { if (this.masterMode) {
masterLink.onUnloadOrRemove(); this.masterLink.onUnloadOrRemove();
} else { } else {
slaveLink.onUnloadOrRemove(); this.slaveLink.onUnloadOrRemove();
} }
this.masterMode = masterMode; this.masterMode = masterMode;
// 切换后应用频率 // 切换后应用频率
if (this.masterMode) { if (this.masterMode) {
masterLink.setFrequency(frequency); this.masterLink.setFrequency(this.frequency);
} else { } else {
slaveLink.setFrequency(frequency); this.slaveLink.setFrequency(this.frequency);
} }
setChanged(); this.setChanged();
} }
public boolean isLocked() { public boolean isLocked() {
return locked; return this.locked;
} }
public void setLocked(boolean locked) { public void setLocked(boolean locked) {
if (this.locked == locked) return; if (this.locked == locked) return;
this.locked = locked; this.locked = locked;
setChanged(); this.setChanged();
} }
public void onRemoved() { void onRemoved() {
if (this.masterMode) { if (this.masterMode) {
masterLink.onUnloadOrRemove(); this.masterLink.onUnloadOrRemove();
} else { } else {
slaveLink.onUnloadOrRemove(); this.slaveLink.onUnloadOrRemove();
} }
if (managedNode != null) { if (this.managedNode != null) {
managedNode.destroy(); this.managedNode.destroy();
}
}
/* ===================== Tick ===================== */
public static void serverTick(Level level, BlockPos pos, BlockState state, WirelessTransceiverBlockEntity be) {
if (!(level instanceof ServerLevel)) return;
if (!be.masterMode) {
// 从端需要周期检查与维护连接
be.slaveLink.updateStatus();
} }
} }
@ -228,7 +228,7 @@ public class WirelessTransceiverBlockEntity extends AEBaseBlockEntity implements
public void onLoad() { public void onLoad() {
super.onLoad(); super.onLoad();
// 仅服务端创建节点 // 仅服务端创建节点
ServerLevel sl = getServerLevel(); ServerLevel sl = this.getServerLevel();
if (sl == null) return; if (sl == null) return;
// 在首个 tick 创建以保证区块已就绪 // 在首个 tick 创建以保证区块已就绪
GridHelper.onFirstTick(this, be -> { GridHelper.onFirstTick(this, be -> {
@ -244,24 +244,6 @@ public class WirelessTransceiverBlockEntity extends AEBaseBlockEntity implements
}); });
} }
/* ===================== NBT ===================== */
@Override
public void saveAdditional(CompoundTag tag, HolderLookup.Provider registries) {
super.saveAdditional(tag, registries);
tag.putLong("frequency", frequency);
tag.putBoolean("master", masterMode);
tag.putBoolean("locked", locked);
if (placerId != null) {
tag.putUUID("placerId", placerId);
}
if (placerName != null) {
tag.putString("placerName", placerName);
}
if (managedNode != null) {
managedNode.saveToNBT(tag);
}
}
@Override @Override
public void loadTag(CompoundTag tag, HolderLookup.Provider registries) { public void loadTag(CompoundTag tag, HolderLookup.Provider registries) {
super.loadTag(tag, registries); super.loadTag(tag, registries);
@ -279,14 +261,32 @@ public class WirelessTransceiverBlockEntity extends AEBaseBlockEntity implements
this.placerName = tag.getString("placerName"); this.placerName = tag.getString("placerName");
} }
if (managedNode != null) { if (this.managedNode != null) {
managedNode.loadFromNBT(tag); this.managedNode.loadFromNBT(tag);
} }
// 应用到链接器 // 应用到链接器
if (masterMode) { if (this.masterMode) {
masterLink.setFrequency(frequency); this.masterLink.setFrequency(this.frequency);
} else { } else {
slaveLink.setFrequency(frequency); this.slaveLink.setFrequency(this.frequency);
}
}
/* ===================== NBT ===================== */
@Override
public void saveAdditional(CompoundTag tag, HolderLookup.Provider registries) {
super.saveAdditional(tag, registries);
tag.putLong("frequency", this.frequency);
tag.putBoolean("master", this.masterMode);
tag.putBoolean("locked", this.locked);
if (this.placerId != null) {
tag.putUUID("placerId", this.placerId);
}
if (this.placerName != null) {
tag.putString("placerName", this.placerName);
}
if (this.managedNode != null) {
this.managedNode.saveToNBT(tag);
} }
} }
@ -297,15 +297,19 @@ public class WirelessTransceiverBlockEntity extends AEBaseBlockEntity implements
public void onSaveChanges(WirelessTransceiverBlockEntity host, IGridNode node) { public void onSaveChanges(WirelessTransceiverBlockEntity host, IGridNode node) {
host.setChanged(); host.setChanged();
} }
@Override
public void onInWorldConnectionChanged(WirelessTransceiverBlockEntity host, IGridNode node) {}
@Override
public void onOwnerChanged(WirelessTransceiverBlockEntity host, IGridNode node) {}
@Override
public void onGridChanged(WirelessTransceiverBlockEntity host, IGridNode node) {}
@Override @Override
public void onStateChanged(WirelessTransceiverBlockEntity host, IGridNode node, State state) { public void onStateChanged(WirelessTransceiverBlockEntity host, IGridNode node, State state) {
// 可在此响应 POWER/CHANNEL 等变化刷新显示等 // 可在此响应 POWER/CHANNEL 等变化刷新显示等
} }
@Override
public void onInWorldConnectionChanged(WirelessTransceiverBlockEntity host, IGridNode node) {}
@Override
public void onGridChanged(WirelessTransceiverBlockEntity host, IGridNode node) {}
@Override
public void onOwnerChanged(WirelessTransceiverBlockEntity host, IGridNode node) {}
} }
} }

View File

@ -1,11 +1,10 @@
package com.extendedae_plus.hooks; package com.extendedae_plus.hooks;
import appeng.block.crafting.CraftingUnitBlock;
import appeng.util.InteractionUtil; import appeng.util.InteractionUtil;
import com.extendedae_plus.ExtendedAEPlus; import com.extendedae_plus.ExtendedAEPlus;
import com.extendedae_plus.client.ui.FrequencyInputScreen; import com.extendedae_plus.client.screen.FrequencyInputScreen;
import com.extendedae_plus.content.wireless.WirelessTransceiverBlockEntity; import com.extendedae_plus.content.wireless.WirelessTransceiverBlockEntity;
import appeng.block.crafting.CraftingUnitBlock;
import appeng.blockentity.crafting.CraftingBlockEntity;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource; import net.minecraft.sounds.SoundSource;
@ -15,8 +14,6 @@ import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.bus.api.Event;
import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber; import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent; import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent;

View File

@ -1,11 +1,11 @@
package com.extendedae_plus.init; package com.extendedae_plus.init;
import com.extendedae_plus.ExtendedAEPlus; import com.extendedae_plus.ExtendedAEPlus;
import com.extendedae_plus.ae.definitions.upgrades.EntitySpeedCardItem; import com.extendedae_plus.items.EntitySpeedTickerPartItem;
import com.extendedae_plus.ae.items.EntitySpeedTickerPartItem; import com.extendedae_plus.items.InfinityBigIntegerCellItem;
import com.extendedae_plus.ae.items.ChannelCardItem; import com.extendedae_plus.items.materials.ChannelCardItem;
import com.extendedae_plus.ae.items.InfinityBigIntegerCellItem; import com.extendedae_plus.items.materials.EntitySpeedCardItem;
import com.extendedae_plus.ae.items.VirtualCraftingCardItem; import com.extendedae_plus.items.materials.VirtualCraftingCardItem;
import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
@ -13,84 +13,71 @@ import net.neoforged.neoforge.registries.DeferredItem;
import net.neoforged.neoforge.registries.DeferredRegister; import net.neoforged.neoforge.registries.DeferredRegister;
public final class ModItems { public final class ModItems {
private ModItems() {}
public static final DeferredRegister.Items ITEMS = DeferredRegister.createItems(ExtendedAEPlus.MODID); public static final DeferredRegister.Items ITEMS = DeferredRegister.createItems(ExtendedAEPlus.MODID);
public static final DeferredItem<Item> WIRELESS_TRANSCEIVER = ITEMS.register( public static final DeferredItem<Item> WIRELESS_TRANSCEIVER = ITEMS.register(
"wireless_transceiver", "wireless_transceiver",
() -> new BlockItem(ModBlocks.WIRELESS_TRANSCEIVER.get(), new Item.Properties()) () -> new BlockItem(ModBlocks.WIRELESS_TRANSCEIVER.get(), new Item.Properties())
); );
public static final DeferredItem<Item> NETWORK_PATTERN_CONTROLLER = ITEMS.register(
"network_pattern_controller",
() -> new BlockItem(ModBlocks.NETWORK_PATTERN_CONTROLLER.get(), new Item.Properties())
);
// Crafting Accelerators // Crafting Accelerators
public static final DeferredItem<Item> ACCELERATOR_4x = ITEMS.register( public static final DeferredItem<Item> ACCELERATOR_4x = ITEMS.register(
"4x_crafting_accelerator", "4x_crafting_accelerator",
() -> new BlockItem(ModBlocks.ACCELERATOR_4x.get(), new Item.Properties()) () -> new BlockItem(ModBlocks.ACCELERATOR_4x.get(), new Item.Properties())
); );
public static final DeferredItem<Item> ACCELERATOR_16x = ITEMS.register( public static final DeferredItem<Item> ACCELERATOR_16x = ITEMS.register(
"16x_crafting_accelerator", "16x_crafting_accelerator",
() -> new BlockItem(ModBlocks.ACCELERATOR_16x.get(), new Item.Properties()) () -> new BlockItem(ModBlocks.ACCELERATOR_16x.get(), new Item.Properties())
); );
public static final DeferredItem<Item> ACCELERATOR_64x = ITEMS.register( public static final DeferredItem<Item> ACCELERATOR_64x = ITEMS.register(
"64x_crafting_accelerator", "64x_crafting_accelerator",
() -> new BlockItem(ModBlocks.ACCELERATOR_64x.get(), new Item.Properties()) () -> new BlockItem(ModBlocks.ACCELERATOR_64x.get(), new Item.Properties())
); );
public static final DeferredItem<Item> ACCELERATOR_256x = ITEMS.register( public static final DeferredItem<Item> ACCELERATOR_256x = ITEMS.register(
"256x_crafting_accelerator", "256x_crafting_accelerator",
() -> new BlockItem(ModBlocks.ACCELERATOR_256x.get(), new Item.Properties()) () -> new BlockItem(ModBlocks.ACCELERATOR_256x.get(), new Item.Properties())
); );
public static final DeferredItem<Item> ACCELERATOR_1024x = ITEMS.register( public static final DeferredItem<Item> ACCELERATOR_1024x = ITEMS.register(
"1024x_crafting_accelerator", "1024x_crafting_accelerator",
() -> new BlockItem(ModBlocks.ACCELERATOR_1024x.get(), new Item.Properties()) () -> new BlockItem(ModBlocks.ACCELERATOR_1024x.get(), new Item.Properties())
); );
public static final DeferredItem<EntitySpeedTickerPartItem> ENTITY_TICKER_PART_ITEM = ITEMS.register( public static final DeferredItem<EntitySpeedTickerPartItem> ENTITY_TICKER_PART_ITEM = ITEMS.register(
"entity_speed_ticker", "entity_speed_ticker",
() -> new EntitySpeedTickerPartItem(new Item.Properties()) () -> new EntitySpeedTickerPartItem(new Item.Properties())
); );
// AE Upgrade Cards: 实体加速卡四个等级x2,x4,x8,x16 // AE Upgrade Cards: 实体加速卡四个等级x2,x4,x8,x16
// 单一实体加速卡 Item不同等级由 ItemStack.nbt 存储 // 单一实体加速卡 Item不同等级由 ItemStack.nbt 存储
public static final DeferredItem<EntitySpeedCardItem> ENTITY_SPEED_CARD = ITEMS.register( public static final DeferredItem<EntitySpeedCardItem> ENTITY_SPEED_CARD = ITEMS.register(
"entity_speed_card", "entity_speed_card",
() -> new EntitySpeedCardItem(new Item.Properties()) () -> new EntitySpeedCardItem(new Item.Properties())
); );
// 频道卡用于AE机器的无线频道连接 // 频道卡用于AE机器的无线频道连接
public static final DeferredItem<ChannelCardItem> CHANNEL_CARD = ITEMS.register( public static final DeferredItem<ChannelCardItem> CHANNEL_CARD = ITEMS.register(
"channel_card", "channel_card",
() -> new ChannelCardItem(new Item.Properties()) () -> new ChannelCardItem(new Item.Properties())
); );
public static final DeferredItem<VirtualCraftingCardItem> VIRTUAL_CRAFTING_CARD = ITEMS.register( public static final DeferredItem<VirtualCraftingCardItem> VIRTUAL_CRAFTING_CARD = ITEMS.register(
"virtual_crafting_card", "virtual_crafting_card",
() -> new VirtualCraftingCardItem(new Item.Properties()) () -> new VirtualCraftingCardItem(new Item.Properties())
); );
public static final DeferredItem<Item> INFINITY_BIGINTEGER_CELL_ITEM = ITEMS.register(
"infinity_biginteger_cell", InfinityBigIntegerCellItem::new
);
/**
* 工厂创建带 multiplier 的实体加速卡 ItemStack2/4/8/16
*/
public static ItemStack createEntitySpeedCardStack(byte multiplier) {
return EntitySpeedCardItem.withMultiplier(multiplier);
}
// 装配矩阵上传核心物品 // 装配矩阵上传核心物品
public static final DeferredItem<Item> ASSEMBLER_MATRIX_UPLOAD_CORE = ITEMS.register( public static final DeferredItem<Item> ASSEMBLER_MATRIX_UPLOAD_CORE = ITEMS.register(
"assembler_matrix_upload_core", "assembler_matrix_upload_core",
() -> new BlockItem(ModBlocks.ASSEMBLER_MATRIX_UPLOAD_CORE.get(), new Item.Properties()) () -> new BlockItem(ModBlocks.ASSEMBLER_MATRIX_UPLOAD_CORE.get(), new Item.Properties())
); );
static final DeferredItem<Item> NETWORK_PATTERN_CONTROLLER = ITEMS.register(
"network_pattern_controller",
() -> new BlockItem(ModBlocks.NETWORK_PATTERN_CONTROLLER.get(), new Item.Properties())
);
static final DeferredItem<Item> INFINITY_BIGINTEGER_CELL_ITEM = ITEMS.register(
"infinity_biginteger_cell", InfinityBigIntegerCellItem::new
);
private ModItems() {}
/**
* 工厂创建带 multiplier 的实体加速卡 ItemStack2/4/8/16
*/
static ItemStack createEntitySpeedCardStack(byte multiplier) {
return EntitySpeedCardItem.withMultiplier(multiplier);
}
} }

View File

@ -2,9 +2,10 @@ package com.extendedae_plus.integration.jade;
import appeng.api.networking.IGrid; import appeng.api.networking.IGrid;
import appeng.api.networking.IGridNode; import appeng.api.networking.IGridNode;
import com.extendedae_plus.ae.wireless.IWirelessEndpoint;
import com.extendedae_plus.ae.wireless.WirelessMasterRegistry;
import com.extendedae_plus.content.wireless.WirelessTransceiverBlockEntity; import com.extendedae_plus.content.wireless.WirelessTransceiverBlockEntity;
import com.extendedae_plus.wireless.IWirelessEndpoint; import com.extendedae_plus.util.wireless.WirelessTeamUtil;
import com.extendedae_plus.wireless.WirelessMasterRegistry;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
@ -37,7 +38,7 @@ public enum WirelessTransceiverProvider implements IServerDataProvider<BlockAcce
var level = blockEntity.getServerLevel(); var level = blockEntity.getServerLevel();
if (level != null) { if (level != null) {
// 使用WirelessTeamUtil自动判断显示团队或玩家名称 // 使用WirelessTeamUtil自动判断显示团队或玩家名称
Component ownerName = com.extendedae_plus.util.WirelessTeamUtil.getNetworkOwnerName(level, placerId); Component ownerName = WirelessTeamUtil.getNetworkOwnerName(level, placerId);
data.putString("ownerName", ownerName.getString()); data.putString("ownerName", ownerName.getString());
} }
} }

View File

@ -1,7 +1,7 @@
package com.extendedae_plus.integration.jei; package com.extendedae_plus.integration.jei;
import com.extendedae_plus.ExtendedAEPlus; import com.extendedae_plus.ExtendedAEPlus;
import com.extendedae_plus.ae.definitions.upgrades.EntitySpeedCardItem; import com.extendedae_plus.items.materials.EntitySpeedCardItem;
import mezz.jei.api.IModPlugin; import mezz.jei.api.IModPlugin;
import mezz.jei.api.JeiPlugin; import mezz.jei.api.JeiPlugin;
import mezz.jei.api.constants.VanillaTypes; import mezz.jei.api.constants.VanillaTypes;

View File

@ -1,4 +1,4 @@
package com.extendedae_plus.ae.items; package com.extendedae_plus.items;
import appeng.items.parts.PartItem; import appeng.items.parts.PartItem;
import com.extendedae_plus.ae.parts.EntitySpeedTickerPart; import com.extendedae_plus.ae.parts.EntitySpeedTickerPart;

View File

@ -1,8 +1,8 @@
package com.extendedae_plus.ae.items; package com.extendedae_plus.items;
import appeng.api.config.FuzzyMode; import appeng.api.config.FuzzyMode;
import appeng.api.storage.cells.ICellWorkbenchItem; import appeng.api.storage.cells.ICellWorkbenchItem;
import com.extendedae_plus.ae.api.storage.InfinityBigIntegerCellInventory; import com.extendedae_plus.api.storage.InfinityBigIntegerCellInventory;
import com.extendedae_plus.util.storage.InfinityConstants; import com.extendedae_plus.util.storage.InfinityConstants;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import net.minecraft.ChatFormatting; import net.minecraft.ChatFormatting;

View File

@ -1,18 +1,16 @@
package com.extendedae_plus.ae.items; package com.extendedae_plus.items.materials;
import appeng.items.materials.UpgradeCardItem; import appeng.items.materials.UpgradeCardItem;
import com.extendedae_plus.util.WirelessTeamUtil;
import net.minecraft.core.component.DataComponents; import net.minecraft.core.component.DataComponents;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.item.component.CustomData;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TooltipFlag;
import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResultHolder; import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TooltipFlag;
import net.minecraft.world.item.component.CustomData;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -28,15 +26,15 @@ import java.util.UUID;
* 继承 AE2 UpgradeCardItem 以复用升级卡判定与提示框架 * 继承 AE2 UpgradeCardItem 以复用升级卡判定与提示框架
*/ */
public class ChannelCardItem extends UpgradeCardItem { public class ChannelCardItem extends UpgradeCardItem {
public static final String TAG_CHANNEL = "channel"; private static final String TAG_CHANNEL = "channel";
public static final String TAG_OWNER_UUID = "ownerUUID"; private static final String TAG_OWNER_UUID = "ownerUUID";
public static final String TAG_TEAM_NAME = "teamName"; // 用于显示 private static final String TAG_TEAM_NAME = "teamName"; // 用于显示
public ChannelCardItem(Item.Properties properties) { public ChannelCardItem(Item.Properties properties) {
super(properties); super(properties);
} }
public static void setChannel(ItemStack stack, long channel) { private static void setChannel(ItemStack stack, long channel) {
CompoundTag tag = stack.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).copyTag(); CompoundTag tag = stack.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).copyTag();
tag.putLong(TAG_CHANNEL, channel); tag.putLong(TAG_CHANNEL, channel);
stack.set(DataComponents.CUSTOM_DATA, CustomData.of(tag)); stack.set(DataComponents.CUSTOM_DATA, CustomData.of(tag));

View File

@ -1,4 +1,4 @@
package com.extendedae_plus.ae.definitions.upgrades; package com.extendedae_plus.items.materials;
import appeng.items.materials.UpgradeCardItem; import appeng.items.materials.UpgradeCardItem;
import com.extendedae_plus.init.ModItems; import com.extendedae_plus.init.ModItems;
@ -19,7 +19,7 @@ import java.util.List;
* 单一的实体加速卡 Item通过 ItemStack NBT 存储 exponent0/1/2/3来区分等级 * 单一的实体加速卡 Item通过 ItemStack NBT 存储 exponent0/1/2/3来区分等级
*/ */
public class EntitySpeedCardItem extends UpgradeCardItem { public class EntitySpeedCardItem extends UpgradeCardItem {
public static final String NBT_MULTIPLIER = "EAS:mult"; private static final String NBT_MULTIPLIER = "EAS:mult";
public EntitySpeedCardItem(Properties props) { public EntitySpeedCardItem(Properties props) {
super(props); super(props);
@ -55,7 +55,7 @@ public class EntitySpeedCardItem extends UpgradeCardItem {
} }
public List<Component> getTooltipLines(ItemStack stack) { private List<Component> getTooltipLines(ItemStack stack) {
byte mult = readMultiplier(stack); byte mult = readMultiplier(stack);
int cap = 1; int cap = 1;
switch (mult) { switch (mult) {

View File

@ -1,4 +1,4 @@
package com.extendedae_plus.ae.items; package com.extendedae_plus.items.materials;
import appeng.items.materials.UpgradeCardItem; import appeng.items.materials.UpgradeCardItem;

View File

@ -8,52 +8,54 @@ import java.util.List;
import java.util.Set; import java.util.Set;
public class ExtendedAEPlusMixinPlugin implements IMixinConfigPlugin { public class ExtendedAEPlusMixinPlugin implements IMixinConfigPlugin {
private static boolean isClassPresent(String className) { private static boolean isClassPresent(String className) {
try { try {
ClassLoader cl = Thread.currentThread().getContextClassLoader(); ClassLoader cl = Thread.currentThread().getContextClassLoader();
Class.forName(className, false, cl); Class.forName(className, false, cl);
return true; return true;
} catch (Throwable ignored) { } catch (Throwable ignored) {
return false; return false;
} }
} }
private static boolean isJeiPresent() { private static boolean isJeiPresent() {
return isClassPresent("mezz.jei.api.IModPlugin"); return isClassPresent("mezz.jei.api.IModPlugin");
} }
private static boolean isAdvancedAePresent() { private static boolean isAdvancedAePresent() {
return isClassPresent("net.pedroksl.advanced_ae.AdvancedAE"); return isClassPresent("net.pedroksl.advanced_ae.AdvancedAE");
} }
@Override @Override
public void onLoad(String mixinPackage) { } public void onLoad(String mixinPackage) { }
@Override @Override
public String getRefMapperConfig() { return null; } public String getRefMapperConfig() { return null; }
@Override @Override
public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { public boolean shouldApplyMixin(String targetClassName, String mixinClassName) {
if (!isJeiPresent()) { if (!isJeiPresent()) {
// Disable all JEI package mixins and any mixins that reference JEI-only helpers // Disable all JEI package mixins and any mixins that reference JEI-only helpers
if (mixinClassName.startsWith("com.extendedae_plus.mixin.jei")) return false; if (mixinClassName.startsWith("com.extendedae_plus.mixin.jei")) return false;
if (mixinClassName.equals("com.extendedae_plus.mixin.ae2.menu.CraftConfirmMenuGoBackMixin")) return false; if (mixinClassName.equals("com.extendedae_plus.mixin.ae2.menu.CraftConfirmMenuGoBackMixin")) return false;
} }
if (!isAdvancedAePresent()) { if (!isAdvancedAePresent()) {
if (mixinClassName.equals("com.extendedae_plus.mixin.advancedae.compat.PatternProviderLogicVirtualCompletionMixin")) { if (mixinClassName.equals("com.extendedae_plus.mixin.advancedae.compat.PatternProviderLogicVirtualCompletionMixin")) {
return false; return false;
} }
} }
return true; return true;
} }
public List<String> getMixins() { return null; }
@Override
public void acceptTargets(Set<String> myTargets, Set<String> otherTargets) {}
@Override
public List<String> getMixins() {return null;}
@Override @Override
public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { } public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { }
@Override @Override
public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { } public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { }
@Override
public void acceptTargets(Set<String> myTargets, Set<String> otherTargets) { }
} }

View File

@ -1,7 +1,7 @@
package com.extendedae_plus.mixin.advancedae; package com.extendedae_plus.mixin.advancedae;
import appeng.api.crafting.IPatternDetails; import appeng.api.crafting.IPatternDetails;
import com.extendedae_plus.content.ScaledProcessingPattern; import com.extendedae_plus.api.crafting.ScaledProcessingPattern;
import net.pedroksl.advanced_ae.common.logic.AdvPatternProviderLogic; import net.pedroksl.advanced_ae.common.logic.AdvPatternProviderLogic;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;

View File

@ -5,8 +5,8 @@ import appeng.api.config.YesNo;
import appeng.client.gui.AEBaseScreen; import appeng.client.gui.AEBaseScreen;
import appeng.client.gui.style.ScreenStyle; import appeng.client.gui.style.ScreenStyle;
import appeng.client.gui.widgets.SettingToggleButton; import appeng.client.gui.widgets.SettingToggleButton;
import com.extendedae_plus.api.PatternProviderMenuAdvancedSync; import com.extendedae_plus.api.smartDoubling.IPatternProviderMenuDoublingSync;
import com.extendedae_plus.api.PatternProviderMenuDoublingSync; import com.extendedae_plus.api.advancedBlocking.IPatternProviderMenuAdvancedSync;
import com.extendedae_plus.network.ToggleAdvancedBlockingC2SPacket; import com.extendedae_plus.network.ToggleAdvancedBlockingC2SPacket;
import com.extendedae_plus.network.ToggleSmartDoublingC2SPacket; import com.extendedae_plus.network.ToggleSmartDoublingC2SPacket;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
@ -50,7 +50,7 @@ public abstract class AdvPatternProviderScreenMixin extends AEBaseScreen<AdvPatt
private void eap$initAdvancedBlocking(AdvPatternProviderMenu menu, Inventory playerInventory, Component title, ScreenStyle style, CallbackInfo ci) { private void eap$initAdvancedBlocking(AdvPatternProviderMenu menu, Inventory playerInventory, Component title, ScreenStyle style, CallbackInfo ci) {
// 使用 @GuiSync 初始化 // 使用 @GuiSync 初始化
try { try {
if (menu instanceof PatternProviderMenuAdvancedSync sync) { if (menu instanceof IPatternProviderMenuAdvancedSync sync) {
this.eap$AdvancedBlockingEnabled = sync.eap$getAdvancedBlockingSynced(); this.eap$AdvancedBlockingEnabled = sync.eap$getAdvancedBlockingSynced();
} }
} catch (Throwable t) { } catch (Throwable t) {
@ -84,7 +84,7 @@ public abstract class AdvPatternProviderScreenMixin extends AEBaseScreen<AdvPatt
// 智能翻倍按钮与高级阻挡同款样式点击仅发送C2S状态由@GuiSync驱动 // 智能翻倍按钮与高级阻挡同款样式点击仅发送C2S状态由@GuiSync驱动
try { try {
if (menu instanceof PatternProviderMenuDoublingSync sync2) { if (menu instanceof IPatternProviderMenuDoublingSync sync2) {
this.eap$SmartDoublingEnabled = sync2.eap$getSmartDoublingSynced(); this.eap$SmartDoublingEnabled = sync2.eap$getSmartDoublingSynced();
} }
} catch (Throwable t) { } catch (Throwable t) {
@ -119,7 +119,7 @@ public abstract class AdvPatternProviderScreenMixin extends AEBaseScreen<AdvPatt
private void eap$updateAdvancedBlocking(CallbackInfo ci) { private void eap$updateAdvancedBlocking(CallbackInfo ci) {
if (this.eap$AdvancedBlockingToggle != null) { if (this.eap$AdvancedBlockingToggle != null) {
boolean desired = this.eap$AdvancedBlockingEnabled; boolean desired = this.eap$AdvancedBlockingEnabled;
if (this.menu instanceof PatternProviderMenuAdvancedSync sync) { if (this.menu instanceof IPatternProviderMenuAdvancedSync sync) {
desired = sync.eap$getAdvancedBlockingSynced(); desired = sync.eap$getAdvancedBlockingSynced();
} }
this.eap$AdvancedBlockingEnabled = desired; this.eap$AdvancedBlockingEnabled = desired;
@ -128,7 +128,7 @@ public abstract class AdvPatternProviderScreenMixin extends AEBaseScreen<AdvPatt
if (this.eap$SmartDoublingToggle != null) { if (this.eap$SmartDoublingToggle != null) {
boolean desired2 = this.eap$SmartDoublingEnabled; boolean desired2 = this.eap$SmartDoublingEnabled;
if (this.menu instanceof PatternProviderMenuDoublingSync sync2) { if (this.menu instanceof IPatternProviderMenuDoublingSync sync2) {
desired2 = sync2.eap$getSmartDoublingSynced(); desired2 = sync2.eap$getSmartDoublingSynced();
} }
this.eap$SmartDoublingEnabled = desired2; this.eap$SmartDoublingEnabled = desired2;

View File

@ -5,8 +5,8 @@ import appeng.api.config.YesNo;
import appeng.client.gui.AEBaseScreen; import appeng.client.gui.AEBaseScreen;
import appeng.client.gui.style.ScreenStyle; import appeng.client.gui.style.ScreenStyle;
import appeng.client.gui.widgets.SettingToggleButton; import appeng.client.gui.widgets.SettingToggleButton;
import com.extendedae_plus.api.PatternProviderMenuAdvancedSync; import com.extendedae_plus.api.advancedBlocking.IPatternProviderMenuAdvancedSync;
import com.extendedae_plus.api.PatternProviderMenuDoublingSync; import com.extendedae_plus.api.smartDoubling.IPatternProviderMenuDoublingSync;
import com.extendedae_plus.network.ToggleAdvancedBlockingC2SPacket; import com.extendedae_plus.network.ToggleAdvancedBlockingC2SPacket;
import com.extendedae_plus.network.ToggleSmartDoublingC2SPacket; import com.extendedae_plus.network.ToggleSmartDoublingC2SPacket;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
@ -50,7 +50,7 @@ public abstract class SmallAdvPatternProviderScreenMixin extends AEBaseScreen<Sm
private void eap$initAdvancedBlocking(SmallAdvPatternProviderMenu menu, Inventory playerInventory, Component title, ScreenStyle style, CallbackInfo ci) { private void eap$initAdvancedBlocking(SmallAdvPatternProviderMenu menu, Inventory playerInventory, Component title, ScreenStyle style, CallbackInfo ci) {
// 使用 @GuiSync 初始化 // 使用 @GuiSync 初始化
try { try {
if (menu instanceof PatternProviderMenuAdvancedSync sync) { if (menu instanceof IPatternProviderMenuAdvancedSync sync) {
this.eap$AdvancedBlockingEnabled = sync.eap$getAdvancedBlockingSynced(); this.eap$AdvancedBlockingEnabled = sync.eap$getAdvancedBlockingSynced();
} }
} catch (Throwable t) { } catch (Throwable t) {
@ -69,7 +69,7 @@ public abstract class SmallAdvPatternProviderScreenMixin extends AEBaseScreen<Sm
) { ) {
@Override @Override
public java.util.List<Component> getTooltipMessage() { public java.util.List<Component> getTooltipMessage() {
boolean enabled = eap$AdvancedBlockingEnabled; boolean enabled = SmallAdvPatternProviderScreenMixin.this.eap$AdvancedBlockingEnabled;
var title = Component.literal("智能阻挡"); var title = Component.literal("智能阻挡");
var line = enabled var line = enabled
? Component.literal("已启用:对于同一种配方将不再阻挡(需要开启原版的阻挡模式)") ? Component.literal("已启用:对于同一种配方将不再阻挡(需要开启原版的阻挡模式)")
@ -84,7 +84,7 @@ public abstract class SmallAdvPatternProviderScreenMixin extends AEBaseScreen<Sm
// 智能翻倍按钮与高级阻挡同款样式点击仅发送C2S状态由@GuiSync驱动 // 智能翻倍按钮与高级阻挡同款样式点击仅发送C2S状态由@GuiSync驱动
try { try {
if (menu instanceof PatternProviderMenuDoublingSync sync2) { if (menu instanceof IPatternProviderMenuDoublingSync sync2) {
this.eap$SmartDoublingEnabled = sync2.eap$getSmartDoublingSynced(); this.eap$SmartDoublingEnabled = sync2.eap$getSmartDoublingSynced();
} }
} catch (Throwable t) { } catch (Throwable t) {
@ -101,7 +101,7 @@ public abstract class SmallAdvPatternProviderScreenMixin extends AEBaseScreen<Sm
) { ) {
@Override @Override
public java.util.List<Component> getTooltipMessage() { public java.util.List<Component> getTooltipMessage() {
boolean enabled = eap$SmartDoublingEnabled; boolean enabled = SmallAdvPatternProviderScreenMixin.this.eap$SmartDoublingEnabled;
var title = Component.literal("智能翻倍"); var title = Component.literal("智能翻倍");
var line = enabled var line = enabled
? Component.literal("已启用:根据请求量对处理样板进行智能缩放") ? Component.literal("已启用:根据请求量对处理样板进行智能缩放")
@ -119,7 +119,7 @@ public abstract class SmallAdvPatternProviderScreenMixin extends AEBaseScreen<Sm
private void eap$updateAdvancedBlocking(CallbackInfo ci) { private void eap$updateAdvancedBlocking(CallbackInfo ci) {
if (this.eap$AdvancedBlockingToggle != null) { if (this.eap$AdvancedBlockingToggle != null) {
boolean desired = this.eap$AdvancedBlockingEnabled; boolean desired = this.eap$AdvancedBlockingEnabled;
if (this.menu instanceof PatternProviderMenuAdvancedSync sync) { if (this.menu instanceof IPatternProviderMenuAdvancedSync sync) {
desired = sync.eap$getAdvancedBlockingSynced(); desired = sync.eap$getAdvancedBlockingSynced();
} }
this.eap$AdvancedBlockingEnabled = desired; this.eap$AdvancedBlockingEnabled = desired;
@ -128,7 +128,7 @@ public abstract class SmallAdvPatternProviderScreenMixin extends AEBaseScreen<Sm
if (this.eap$SmartDoublingToggle != null) { if (this.eap$SmartDoublingToggle != null) {
boolean desired2 = this.eap$SmartDoublingEnabled; boolean desired2 = this.eap$SmartDoublingEnabled;
if (this.menu instanceof PatternProviderMenuDoublingSync sync2) { if (this.menu instanceof IPatternProviderMenuDoublingSync sync2) {
desired2 = sync2.eap$getSmartDoublingSynced(); desired2 = sync2.eap$getSmartDoublingSynced();
} }
this.eap$SmartDoublingEnabled = desired2; this.eap$SmartDoublingEnabled = desired2;

View File

@ -23,7 +23,7 @@ public abstract class PatternProviderLogicVirtualCompletionMixin {
@Inject(method = "pushPattern", at = @At("RETURN")) @Inject(method = "pushPattern", at = @At("RETURN"))
private void eap$advancedaeVirtualCompletion(IPatternDetails patternDetails, KeyCounter[] inputHolder, private void eap$advancedaeVirtualCompletion(IPatternDetails patternDetails, KeyCounter[] inputHolder,
CallbackInfoReturnable<Boolean> cir) { CallbackInfoReturnable<Boolean> cir) {
if (!cir.getReturnValueZ()) { if (!cir.getReturnValueZ()) {
return; return;
} }

View File

@ -5,7 +5,7 @@ import appeng.api.crafting.IPatternDetails.IInput;
import appeng.api.stacks.AEKey; import appeng.api.stacks.AEKey;
import appeng.api.stacks.GenericStack; import appeng.api.stacks.GenericStack;
import appeng.helpers.patternprovider.PatternProviderTarget; import appeng.helpers.patternprovider.PatternProviderTarget;
import com.extendedae_plus.api.AdvancedBlockingHolder; import com.extendedae_plus.api.advancedBlocking.IAdvancedBlocking;
import net.minecraft.core.HolderLookup; import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.pedroksl.advanced_ae.common.logic.AdvPatternProviderLogic; import net.pedroksl.advanced_ae.common.logic.AdvPatternProviderLogic;
@ -20,7 +20,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.Collections; import java.util.Collections;
@Mixin(value = AdvPatternProviderLogic.class, remap = false) @Mixin(value = AdvPatternProviderLogic.class, remap = false)
public class AdvPatternProviderLogicAdvancedMixin implements AdvancedBlockingHolder { public class AdvPatternProviderLogicAdvancedMixin implements IAdvancedBlocking {
@Unique @Unique
private static final String EAP_ADV_BLOCKING_KEY = "eap_advanced_blocking"; private static final String EAP_ADV_BLOCKING_KEY = "eap_advanced_blocking";
@ -29,7 +29,7 @@ public class AdvPatternProviderLogicAdvancedMixin implements AdvancedBlockingHol
@Override @Override
public boolean eap$getAdvancedBlocking() { public boolean eap$getAdvancedBlocking() {
return eap$advancedBlocking; return this.eap$advancedBlocking;
} }
@Override @Override
@ -63,7 +63,7 @@ public class AdvPatternProviderLogicAdvancedMixin implements AdvancedBlockingHol
// 仅当高级阻挡启用时启用匹配则不阻挡 // 仅当高级阻挡启用时启用匹配则不阻挡
if (this.eap$advancedBlocking) { if (this.eap$advancedBlocking) {
if (eap$targetFullyMatchesPatternInputs(adapter, patternDetails)) { if (this.eap$targetFullyMatchesPatternInputs(adapter, patternDetails)) {
// 返回 false 表示不包含阻挡关键物从而不触发 continue允许发配 // 返回 false 表示不包含阻挡关键物从而不触发 continue允许发配
return false; return false;
} }

View File

@ -2,8 +2,8 @@ package com.extendedae_plus.mixin.advancedae.helpers;
import appeng.api.crafting.IPatternDetails; import appeng.api.crafting.IPatternDetails;
import appeng.crafting.pattern.AEProcessingPattern; import appeng.crafting.pattern.AEProcessingPattern;
import com.extendedae_plus.api.SmartDoublingAwarePattern; import com.extendedae_plus.api.smartDoubling.ISmartDoubling;
import com.extendedae_plus.api.SmartDoublingHolder; import com.extendedae_plus.api.smartDoubling.ISmartDoublingAwarePattern;
import com.extendedae_plus.mixin.advancedae.accessor.AdvPatternProviderLogicPatternsAccessor; import com.extendedae_plus.mixin.advancedae.accessor.AdvPatternProviderLogicPatternsAccessor;
import net.minecraft.core.HolderLookup; import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
@ -16,7 +16,7 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(value = AdvPatternProviderLogic.class, remap = false) @Mixin(value = AdvPatternProviderLogic.class, remap = false)
public class AdvPatternProviderLogicDoublingMixin implements SmartDoublingHolder { public class AdvPatternProviderLogicDoublingMixin implements ISmartDoubling {
@Unique @Unique
private static final String EAP_SMART_DOUBLING_KEY = "eap_smart_doubling"; private static final String EAP_SMART_DOUBLING_KEY = "eap_smart_doubling";
@ -25,7 +25,7 @@ public class AdvPatternProviderLogicDoublingMixin implements SmartDoublingHolder
@Override @Override
public boolean eap$getSmartDoubling() { public boolean eap$getSmartDoubling() {
return eap$smartDoubling; return this.eap$smartDoubling;
} }
@Override @Override
@ -35,7 +35,7 @@ public class AdvPatternProviderLogicDoublingMixin implements SmartDoublingHolder
try { try {
var list = ((AdvPatternProviderLogicPatternsAccessor) this).eap$patterns(); var list = ((AdvPatternProviderLogicPatternsAccessor) this).eap$patterns();
for (IPatternDetails details : list) { for (IPatternDetails details : list) {
if (details instanceof AEProcessingPattern proc && proc instanceof SmartDoublingAwarePattern aware) { if (details instanceof AEProcessingPattern proc && proc instanceof ISmartDoublingAwarePattern aware) {
aware.eap$setAllowScaling(value); aware.eap$setAllowScaling(value);
} }
} }
@ -63,7 +63,7 @@ public class AdvPatternProviderLogicDoublingMixin implements SmartDoublingHolder
var list = ((AdvPatternProviderLogicPatternsAccessor) this).eap$patterns(); var list = ((AdvPatternProviderLogicPatternsAccessor) this).eap$patterns();
boolean allow = this.eap$smartDoubling; boolean allow = this.eap$smartDoubling;
for (IPatternDetails details : list) { for (IPatternDetails details : list) {
if (details instanceof AEProcessingPattern proc && proc instanceof SmartDoublingAwarePattern aware) { if (details instanceof AEProcessingPattern proc && proc instanceof ISmartDoublingAwarePattern aware) {
aware.eap$setAllowScaling(allow); aware.eap$setAllowScaling(allow);
} }
} }

View File

@ -2,8 +2,8 @@ package com.extendedae_plus.mixin.advancedae.menu;
import appeng.menu.AEBaseMenu; import appeng.menu.AEBaseMenu;
import appeng.menu.guisync.GuiSync; import appeng.menu.guisync.GuiSync;
import com.extendedae_plus.api.AdvancedBlockingHolder; import com.extendedae_plus.api.advancedBlocking.IAdvancedBlocking;
import com.extendedae_plus.api.PatternProviderMenuAdvancedSync; import com.extendedae_plus.api.advancedBlocking.IPatternProviderMenuAdvancedSync;
import net.pedroksl.advanced_ae.common.logic.AdvPatternProviderLogic; import net.pedroksl.advanced_ae.common.logic.AdvPatternProviderLogic;
import net.pedroksl.advanced_ae.gui.advpatternprovider.AdvPatternProviderMenu; import net.pedroksl.advanced_ae.gui.advpatternprovider.AdvPatternProviderMenu;
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;
@ -15,22 +15,21 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(AdvPatternProviderMenu.class) @Mixin(AdvPatternProviderMenu.class)
public abstract class AdvPatternProviderMenuAdvancedMixin implements PatternProviderMenuAdvancedSync { public abstract class AdvPatternProviderMenuAdvancedMixin implements IPatternProviderMenuAdvancedSync {
@Final @Final
@Shadow(remap = false) @Shadow(remap = false)
protected AdvPatternProviderLogic logic; protected AdvPatternProviderLogic logic;
// 选择一个未占用的 GUI 同步 idAE2 已用到 7这里使用 21 以避冲突 // 选择一个未占用的 GUI 同步 idAE2 已用到 7这里使用 21 以避冲突
@Unique @Unique
@GuiSync(22) @GuiSync(22) private boolean eap$AdvancedBlocking = false;
public boolean eap$AdvancedBlocking = false;
@Inject(method = "broadcastChanges", at = @At("HEAD")) @Inject(method = "broadcastChanges", at = @At("HEAD"))
private void eap$syncAdvancedBlocking(CallbackInfo ci) { private void eap$syncAdvancedBlocking(CallbackInfo ci) {
// 避免@Shadow父类方法改用公共APIAEBaseMenu#isClientSide() // 避免@Shadow父类方法改用公共APIAEBaseMenu#isClientSide()
if (!((AEBaseMenu) (Object) this).isClientSide()) { if (!((AEBaseMenu) (Object) this).isClientSide()) {
var l = this.logic; var l = this.logic;
if (l instanceof AdvancedBlockingHolder holder) { if (l instanceof IAdvancedBlocking holder) {
this.eap$AdvancedBlocking = holder.eap$getAdvancedBlocking(); this.eap$AdvancedBlocking = holder.eap$getAdvancedBlocking();
} }
} }

View File

@ -2,8 +2,8 @@ package com.extendedae_plus.mixin.advancedae.menu;
import appeng.menu.AEBaseMenu; import appeng.menu.AEBaseMenu;
import appeng.menu.guisync.GuiSync; import appeng.menu.guisync.GuiSync;
import com.extendedae_plus.api.PatternProviderMenuDoublingSync; import com.extendedae_plus.api.smartDoubling.IPatternProviderMenuDoublingSync;
import com.extendedae_plus.api.SmartDoublingHolder; import com.extendedae_plus.api.smartDoubling.ISmartDoubling;
import net.pedroksl.advanced_ae.common.logic.AdvPatternProviderLogic; import net.pedroksl.advanced_ae.common.logic.AdvPatternProviderLogic;
import net.pedroksl.advanced_ae.gui.advpatternprovider.AdvPatternProviderMenu; import net.pedroksl.advanced_ae.gui.advpatternprovider.AdvPatternProviderMenu;
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;
@ -15,20 +15,19 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(AdvPatternProviderMenu.class) @Mixin(AdvPatternProviderMenu.class)
public abstract class AdvPatternProviderMenuDoublingMixin implements PatternProviderMenuDoublingSync { public abstract class AdvPatternProviderMenuDoublingMixin implements IPatternProviderMenuDoublingSync {
@Final @Final
@Shadow(remap = false) @Shadow(remap = false)
protected AdvPatternProviderLogic logic; protected AdvPatternProviderLogic logic;
@Unique @Unique
@GuiSync(23) @GuiSync(23) private boolean eap$SmartDoubling = false;
public boolean eap$SmartDoubling = false;
@Inject(method = "broadcastChanges", at = @At("HEAD")) @Inject(method = "broadcastChanges", at = @At("HEAD"))
private void eap$syncSmartDoubling(CallbackInfo ci) { private void eap$syncSmartDoubling(CallbackInfo ci) {
if (!((AEBaseMenu) (Object) this).isClientSide()) { if (!((AEBaseMenu) (Object) this).isClientSide()) {
var l = this.logic; var l = this.logic;
if (l instanceof SmartDoublingHolder holder) { if (l instanceof ISmartDoubling holder) {
this.eap$SmartDoubling = holder.eap$getSmartDoubling(); this.eap$SmartDoubling = holder.eap$getSmartDoubling();
} }
} }

View File

@ -1,18 +1,18 @@
package com.extendedae_plus.mixin.ae2; package com.extendedae_plus.mixin.ae2;
import appeng.crafting.pattern.AEProcessingPattern; import appeng.crafting.pattern.AEProcessingPattern;
import com.extendedae_plus.api.SmartDoublingAwarePattern; import com.extendedae_plus.api.smartDoubling.ISmartDoublingAwarePattern;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.Unique;
@Mixin(value = AEProcessingPattern.class, remap = false) @Mixin(value = AEProcessingPattern.class, remap = false)
public class AEProcessingPatternMixin implements SmartDoublingAwarePattern { public class AEProcessingPatternMixin implements ISmartDoublingAwarePattern {
@Unique @Unique
private boolean eap$allowScaling = false; // 默认不允许缩放 private boolean eap$allowScaling = false; // 默认不允许缩放
@Override @Override
public boolean eap$allowScaling() { public boolean eap$allowScaling() {
return eap$allowScaling; return this.eap$allowScaling;
} }
@Override @Override

View File

@ -2,7 +2,7 @@ package com.extendedae_plus.mixin.ae2.autopattern;
import appeng.api.crafting.IPatternDetails; import appeng.api.crafting.IPatternDetails;
import appeng.me.service.CraftingService; import appeng.me.service.CraftingService;
import com.extendedae_plus.content.ScaledProcessingPattern; import com.extendedae_plus.api.crafting.ScaledProcessingPattern;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyArg; import org.spongepowered.asm.mixin.injection.ModifyArg;

View File

@ -3,7 +3,7 @@ package com.extendedae_plus.mixin.ae2.autopattern;
import appeng.api.stacks.KeyCounter; import appeng.api.stacks.KeyCounter;
import appeng.crafting.CraftingTreeNode; import appeng.crafting.CraftingTreeNode;
import appeng.crafting.inv.CraftingSimulationState; import appeng.crafting.inv.CraftingSimulationState;
import com.extendedae_plus.util.RequestedAmountHolder; import com.extendedae_plus.util.smartDoubling.RequestedAmountHolder;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;

View File

@ -9,11 +9,11 @@ import appeng.crafting.CraftingTreeNode;
import appeng.crafting.CraftingTreeProcess; import appeng.crafting.CraftingTreeProcess;
import appeng.crafting.pattern.AEProcessingPattern; import appeng.crafting.pattern.AEProcessingPattern;
import appeng.me.service.CraftingService; import appeng.me.service.CraftingService;
import com.extendedae_plus.api.SmartDoublingAwarePattern; import com.extendedae_plus.api.smartDoubling.ISmartDoublingAwarePattern;
import com.extendedae_plus.api.crafting.ScaledProcessingPattern;
import com.extendedae_plus.config.ModConfigs; import com.extendedae_plus.config.ModConfigs;
import com.extendedae_plus.content.ScaledProcessingPattern; import com.extendedae_plus.util.smartDoubling.PatternScaler;
import com.extendedae_plus.util.PatternScaler; import com.extendedae_plus.util.smartDoubling.RequestedAmountHolder;
import com.extendedae_plus.util.RequestedAmountHolder;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyVariable; import org.spongepowered.asm.mixin.injection.ModifyVariable;
@ -40,7 +40,7 @@ public abstract class CraftingTreeProcessMixin {
// 若传入的 details 已经是缩放样板且原始样板不允许缩放则直接解包为原始样板 // 若传入的 details 已经是缩放样板且原始样板不允许缩放则直接解包为原始样板
if (details instanceof ScaledProcessingPattern sp) { if (details instanceof ScaledProcessingPattern sp) {
var proc0 = sp.getOriginal(); var proc0 = sp.getOriginal();
if (proc0 instanceof SmartDoublingAwarePattern aware0 && !aware0.eap$allowScaling()) { if (proc0 instanceof ISmartDoublingAwarePattern aware0 && !aware0.eap$allowScaling()) {
return proc0; return proc0;
} }
} }
@ -48,7 +48,7 @@ public abstract class CraftingTreeProcessMixin {
if (!(details instanceof AEProcessingPattern proc)) return original; if (!(details instanceof AEProcessingPattern proc)) return original;
// 若样板标记为不允许缩放则直接跳过 // 若样板标记为不允许缩放则直接跳过
if (proc instanceof SmartDoublingAwarePattern aware && !aware.eap$allowScaling()) { if (proc instanceof ISmartDoublingAwarePattern aware && !aware.eap$allowScaling()) {
return original; return original;
} }

View File

@ -2,7 +2,7 @@ package com.extendedae_plus.mixin.ae2.autopattern;
import appeng.api.crafting.IPatternDetails; import appeng.api.crafting.IPatternDetails;
import appeng.helpers.patternprovider.PatternProviderLogic; import appeng.helpers.patternprovider.PatternProviderLogic;
import com.extendedae_plus.content.ScaledProcessingPattern; import com.extendedae_plus.api.crafting.ScaledProcessingPattern;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.Redirect;

View File

@ -13,13 +13,12 @@ import appeng.client.gui.style.ScreenStyle;
import appeng.client.gui.style.Text; import appeng.client.gui.style.Text;
import appeng.client.gui.style.TextAlignment; import appeng.client.gui.style.TextAlignment;
import appeng.menu.slot.AppEngSlot; import appeng.menu.slot.AppEngSlot;
import com.extendedae_plus.api.ExPatternPageAccessor; import com.extendedae_plus.api.IExPatternPage;
import com.extendedae_plus.content.ClientPatternHighlightStore; import com.extendedae_plus.content.ClientPatternHighlightStore;
import com.extendedae_plus.network.CraftingMonitorJumpC2SPacket; import com.extendedae_plus.network.CraftingMonitorJumpC2SPacket;
import com.extendedae_plus.network.CraftingMonitorOpenProviderC2SPacket; import com.extendedae_plus.network.CraftingMonitorOpenProviderC2SPacket;
import com.extendedae_plus.util.GuiUtil; import com.extendedae_plus.util.GuiUtil;
import com.glodblock.github.extendedae.client.gui.GuiExPatternProvider; import com.glodblock.github.extendedae.client.gui.GuiExPatternProvider;
import com.mojang.logging.LogUtils;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font; import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.GuiGraphics;
@ -40,6 +39,36 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(value = AEBaseScreen.class, remap = false) @Mixin(value = AEBaseScreen.class, remap = false)
public abstract class AEBaseScreenMixin { public abstract class AEBaseScreenMixin {
@Unique
private static int eap$getIntField(Object self, String name, int def) {
Class<?> c = self.getClass();
while (c != null && c != Object.class) {
try {
var f = c.getDeclaredField(name);
f.setAccessible(true);
Object v = f.get(self);
if (v instanceof Integer i) return i;
} catch (Throwable ignored) {}
c = c.getSuperclass();
}
return def;
}
@Unique
private static Font eap$getFont(Object self) {
Class<?> c = self.getClass();
while (c != null && c != Object.class) {
try {
var f = c.getDeclaredField("font");
f.setAccessible(true);
Object v = f.get(self);
if (v instanceof Font font) return font;
} catch (Throwable ignored) {}
c = c.getSuperclass();
}
return net.minecraft.client.Minecraft.getInstance().font;
}
@Unique @Unique
private ScreenStyle eap$getStyle(Object self) { private ScreenStyle eap$getStyle(Object self) {
try { try {
@ -111,36 +140,6 @@ public abstract class AEBaseScreenMixin {
} }
} }
@Unique
private static int eap$getIntField(Object self, String name, int def) {
Class<?> c = self.getClass();
while (c != null && c != Object.class) {
try {
var f = c.getDeclaredField(name);
f.setAccessible(true);
Object v = f.get(self);
if (v instanceof Integer i) return i;
} catch (Throwable ignored) {}
c = c.getSuperclass();
}
return def;
}
@Unique
private static Font eap$getFont(Object self) {
Class<?> c = self.getClass();
while (c != null && c != Object.class) {
try {
var f = c.getDeclaredField("font");
f.setAccessible(true);
Object v = f.get(self);
if (v instanceof Font font) return font;
} catch (Throwable ignored) {}
c = c.getSuperclass();
}
return net.minecraft.client.Minecraft.getInstance().font;
}
/** /**
* 重写renderSlot方法为所有可见的样板槽位添加数量显示 * 重写renderSlot方法为所有可见的样板槽位添加数量显示
*/ */
@ -266,7 +265,7 @@ public abstract class AEBaseScreenMixin {
int cur = 1; int cur = 1;
int max = 1; int max = 1;
if (self instanceof ExPatternPageAccessor accessor) { if (self instanceof IExPatternPage accessor) {
cur = Math.max(0, accessor.eap$getCurrentPage()) + 1; cur = Math.max(0, accessor.eap$getCurrentPage()) + 1;
} }
try { try {
@ -281,7 +280,7 @@ public abstract class AEBaseScreenMixin {
String pageText = "" + cur + "" + "/" + max + ""; String pageText = "" + cur + "" + "/" + max + "";
ScreenStyle style = eap$getStyle(self); ScreenStyle style = this.eap$getStyle(self);
int color = 0xFFFFFFFF; int color = 0xFFFFFFFF;
if (style != null) { if (style != null) {
try { try {

View File

@ -4,12 +4,11 @@ import appeng.client.gui.AEBaseScreen;
import appeng.client.gui.implementations.InterfaceScreen; import appeng.client.gui.implementations.InterfaceScreen;
import appeng.menu.AEBaseMenu; import appeng.menu.AEBaseMenu;
import appeng.menu.SlotSemantics; import appeng.menu.SlotSemantics;
import com.extendedae_plus.NewIcon; import com.extendedae_plus.client.gui.NewIcon;
import com.extendedae_plus.mixin.accessor.AbstractContainerScreenAccessor; import com.extendedae_plus.mixin.accessor.AbstractContainerScreenAccessor;
import com.extendedae_plus.mixin.accessor.ScreenAccessor; import com.extendedae_plus.mixin.accessor.ScreenAccessor;
import com.extendedae_plus.network.InterfaceAdjustConfigAmountC2SPacket; import com.extendedae_plus.network.InterfaceAdjustConfigAmountC2SPacket;
import com.glodblock.github.extendedae.client.button.ActionEPPButton; import com.glodblock.github.extendedae.client.button.ActionEPPButton;
import com.mojang.logging.LogUtils;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.world.inventory.Slot; import net.minecraft.world.inventory.Slot;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
@ -41,107 +40,117 @@ public abstract class InterfaceScreenMixin<T extends AEBaseMenu> {
@Inject(method = "init", at = @At("TAIL")) @Inject(method = "init", at = @At("TAIL"))
private void eap$addScaleButtons(CallbackInfo ci) { private void eap$addScaleButtons(CallbackInfo ci) {
if (!eap$isSupportedInterfaceScreen()) { if (!this.eap$isSupportedInterfaceScreen()) {
return; return;
} }
if (eap$x2Button == null) { if (this.eap$x2Button == null) {
eap$x2Button = new ActionEPPButton((b) -> eap$sendAdjustForAllConfigs(false, 2), NewIcon.MULTIPLY2); this.eap$x2Button = new ActionEPPButton((b) -> this.eap$sendAdjustForAllConfigs(false, 2), NewIcon.MULTIPLY2);
eap$x2Button.setTooltip(null); this.eap$x2Button.setTooltip(null);
eap$x2Button.setVisibility(true); this.eap$x2Button.setVisibility(true);
} }
if (eap$divideBy2Button == null) { if (this.eap$divideBy2Button == null) {
eap$divideBy2Button = new ActionEPPButton((b) -> eap$sendAdjustForAllConfigs(true, 2), NewIcon.DIVIDE2); this.eap$divideBy2Button = new ActionEPPButton((b) -> this.eap$sendAdjustForAllConfigs(true, 2), NewIcon.DIVIDE2);
eap$divideBy2Button.setTooltip(null); this.eap$divideBy2Button.setTooltip(null);
eap$divideBy2Button.setVisibility(true); this.eap$divideBy2Button.setVisibility(true);
} }
if (eap$x5Button == null) { if (this.eap$x5Button == null) {
eap$x5Button = new ActionEPPButton((b) -> eap$sendAdjustForAllConfigs(false, 5), NewIcon.MULTIPLY5); this.eap$x5Button = new ActionEPPButton((b) -> this.eap$sendAdjustForAllConfigs(false, 5), NewIcon.MULTIPLY5);
eap$x5Button.setTooltip(null); this.eap$x5Button.setTooltip(null);
eap$x5Button.setVisibility(true); this.eap$x5Button.setVisibility(true);
} }
if (eap$divideBy5Button == null) { if (this.eap$divideBy5Button == null) {
eap$divideBy5Button = new ActionEPPButton((b) -> eap$sendAdjustForAllConfigs(true, 5), NewIcon.DIVIDE5); this.eap$divideBy5Button = new ActionEPPButton((b) -> this.eap$sendAdjustForAllConfigs(true, 5), NewIcon.DIVIDE5);
eap$divideBy5Button.setTooltip(null); this.eap$divideBy5Button.setTooltip(null);
eap$divideBy5Button.setVisibility(true); this.eap$divideBy5Button.setVisibility(true);
} }
if (eap$x10Button == null) { if (this.eap$x10Button == null) {
eap$x10Button = new ActionEPPButton((b) -> eap$sendAdjustForAllConfigs(false, 10), NewIcon.MULTIPLY10); this.eap$x10Button = new ActionEPPButton((b) -> this.eap$sendAdjustForAllConfigs(false, 10), NewIcon.MULTIPLY10);
eap$x10Button.setTooltip(null); this.eap$x10Button.setTooltip(null);
eap$x10Button.setVisibility(true); this.eap$x10Button.setVisibility(true);
} }
if (eap$divideBy10Button == null) { if (this.eap$divideBy10Button == null) {
eap$divideBy10Button = new ActionEPPButton((b) -> eap$sendAdjustForAllConfigs(true, 10), NewIcon.DIVIDE10); this.eap$divideBy10Button = new ActionEPPButton((b) -> this.eap$sendAdjustForAllConfigs(true, 10), NewIcon.DIVIDE10);
eap$divideBy10Button.setTooltip(null); this.eap$divideBy10Button.setTooltip(null);
eap$divideBy10Button.setVisibility(true); this.eap$divideBy10Button.setVisibility(true);
} }
// 注册到渲染与交互列表 // 注册到渲染与交互列表
var accessor = (ScreenAccessor) (Object) this; var accessor = (ScreenAccessor) (Object) this;
if (!accessor.eap$getRenderables().contains(eap$divideBy2Button)) accessor.eap$getRenderables().add(eap$divideBy2Button); if (!accessor.eap$getRenderables().contains(this.eap$divideBy2Button))
if (!accessor.eap$getChildren().contains(eap$divideBy2Button)) accessor.eap$getChildren().add(eap$divideBy2Button); accessor.eap$getRenderables().add(this.eap$divideBy2Button);
if (!accessor.eap$getRenderables().contains(eap$x2Button)) accessor.eap$getRenderables().add(eap$x2Button); if (!accessor.eap$getChildren().contains(this.eap$divideBy2Button))
if (!accessor.eap$getChildren().contains(eap$x2Button)) accessor.eap$getChildren().add(eap$x2Button); accessor.eap$getChildren().add(this.eap$divideBy2Button);
if (!accessor.eap$getRenderables().contains(eap$divideBy5Button)) accessor.eap$getRenderables().add(eap$divideBy5Button); if (!accessor.eap$getRenderables().contains(this.eap$x2Button))
if (!accessor.eap$getChildren().contains(eap$divideBy5Button)) accessor.eap$getChildren().add(eap$divideBy5Button); accessor.eap$getRenderables().add(this.eap$x2Button);
if (!accessor.eap$getRenderables().contains(eap$x5Button)) accessor.eap$getRenderables().add(eap$x5Button); if (!accessor.eap$getChildren().contains(this.eap$x2Button)) accessor.eap$getChildren().add(this.eap$x2Button);
if (!accessor.eap$getChildren().contains(eap$x5Button)) accessor.eap$getChildren().add(eap$x5Button); if (!accessor.eap$getRenderables().contains(this.eap$divideBy5Button))
if (!accessor.eap$getRenderables().contains(eap$divideBy10Button)) accessor.eap$getRenderables().add(eap$divideBy10Button); accessor.eap$getRenderables().add(this.eap$divideBy5Button);
if (!accessor.eap$getChildren().contains(eap$divideBy10Button)) accessor.eap$getChildren().add(eap$divideBy10Button); if (!accessor.eap$getChildren().contains(this.eap$divideBy5Button))
if (!accessor.eap$getRenderables().contains(eap$x10Button)) accessor.eap$getRenderables().add(eap$x10Button); accessor.eap$getChildren().add(this.eap$divideBy5Button);
if (!accessor.eap$getChildren().contains(eap$x10Button)) accessor.eap$getChildren().add(eap$x10Button); if (!accessor.eap$getRenderables().contains(this.eap$x5Button))
accessor.eap$getRenderables().add(this.eap$x5Button);
if (!accessor.eap$getChildren().contains(this.eap$x5Button)) accessor.eap$getChildren().add(this.eap$x5Button);
if (!accessor.eap$getRenderables().contains(this.eap$divideBy10Button))
accessor.eap$getRenderables().add(this.eap$divideBy10Button);
if (!accessor.eap$getChildren().contains(this.eap$divideBy10Button))
accessor.eap$getChildren().add(this.eap$divideBy10Button);
if (!accessor.eap$getRenderables().contains(this.eap$x10Button))
accessor.eap$getRenderables().add(this.eap$x10Button);
if (!accessor.eap$getChildren().contains(this.eap$x10Button))
accessor.eap$getChildren().add(this.eap$x10Button);
eap$relayoutButtons(); this.eap$relayoutButtons();
} }
@Inject(method = "containerTick", at = @At("TAIL")) @Inject(method = "containerTick", at = @At("TAIL"))
private void eap$ensureButtons(CallbackInfo ci) { private void eap$ensureButtons(CallbackInfo ci) {
if (!eap$isSupportedInterfaceScreen()) { if (!this.eap$isSupportedInterfaceScreen()) {
return; return;
} }
var accessor = (ScreenAccessor) (Object) this; var accessor = (ScreenAccessor) (Object) this;
if (eap$divideBy2Button != null && !accessor.eap$getRenderables().contains(eap$divideBy2Button)) { if (this.eap$divideBy2Button != null && !accessor.eap$getRenderables().contains(this.eap$divideBy2Button)) {
accessor.eap$getRenderables().add(eap$divideBy2Button); accessor.eap$getRenderables().add(this.eap$divideBy2Button);
accessor.eap$getChildren().add(eap$divideBy2Button); accessor.eap$getChildren().add(this.eap$divideBy2Button);
} }
if (eap$x2Button != null && !accessor.eap$getRenderables().contains(eap$x2Button)) { if (this.eap$x2Button != null && !accessor.eap$getRenderables().contains(this.eap$x2Button)) {
accessor.eap$getRenderables().add(eap$x2Button); accessor.eap$getRenderables().add(this.eap$x2Button);
accessor.eap$getChildren().add(eap$x2Button); accessor.eap$getChildren().add(this.eap$x2Button);
} }
if (eap$divideBy5Button != null && !accessor.eap$getRenderables().contains(eap$divideBy5Button)) { if (this.eap$divideBy5Button != null && !accessor.eap$getRenderables().contains(this.eap$divideBy5Button)) {
accessor.eap$getRenderables().add(eap$divideBy5Button); accessor.eap$getRenderables().add(this.eap$divideBy5Button);
accessor.eap$getChildren().add(eap$divideBy5Button); accessor.eap$getChildren().add(this.eap$divideBy5Button);
} }
if (eap$x5Button != null && !accessor.eap$getRenderables().contains(eap$x5Button)) { if (this.eap$x5Button != null && !accessor.eap$getRenderables().contains(this.eap$x5Button)) {
accessor.eap$getRenderables().add(eap$x5Button); accessor.eap$getRenderables().add(this.eap$x5Button);
accessor.eap$getChildren().add(eap$x5Button); accessor.eap$getChildren().add(this.eap$x5Button);
} }
if (eap$divideBy10Button != null && !accessor.eap$getRenderables().contains(eap$divideBy10Button)) { if (this.eap$divideBy10Button != null && !accessor.eap$getRenderables().contains(this.eap$divideBy10Button)) {
accessor.eap$getRenderables().add(eap$divideBy10Button); accessor.eap$getRenderables().add(this.eap$divideBy10Button);
accessor.eap$getChildren().add(eap$divideBy10Button); accessor.eap$getChildren().add(this.eap$divideBy10Button);
} }
if (eap$x10Button != null && !accessor.eap$getRenderables().contains(eap$x10Button)) { if (this.eap$x10Button != null && !accessor.eap$getRenderables().contains(this.eap$x10Button)) {
accessor.eap$getRenderables().add(eap$x10Button); accessor.eap$getRenderables().add(this.eap$x10Button);
accessor.eap$getChildren().add(eap$x10Button); accessor.eap$getChildren().add(this.eap$x10Button);
} }
int curLeft = ((AbstractContainerScreenAccessor<?>) (Object) this).eap$getLeftPos(); int curLeft = ((AbstractContainerScreenAccessor<?>) (Object) this).eap$getLeftPos();
int curTop = ((AbstractContainerScreenAccessor<?>) (Object) this).eap$getTopPos(); int curTop = ((AbstractContainerScreenAccessor<?>) (Object) this).eap$getTopPos();
int curImgW = ((AbstractContainerScreenAccessor<?>) (Object) this).eap$getImageWidth(); int curImgW = ((AbstractContainerScreenAccessor<?>) (Object) this).eap$getImageWidth();
int curImgH = ((AbstractContainerScreenAccessor<?>) (Object) this).eap$getImageHeight(); int curImgH = ((AbstractContainerScreenAccessor<?>) (Object) this).eap$getImageHeight();
if (curLeft != eap$lastLeftPos || curTop != eap$lastTopPos || curImgW != eap$lastImageWidth || curImgH != eap$lastImageHeight) { if (curLeft != this.eap$lastLeftPos || curTop != this.eap$lastTopPos || curImgW != this.eap$lastImageWidth || curImgH != this.eap$lastImageHeight) {
eap$lastLeftPos = curLeft; this.eap$lastLeftPos = curLeft;
eap$lastTopPos = curTop; this.eap$lastTopPos = curTop;
eap$lastImageWidth = curImgW; this.eap$lastImageWidth = curImgW;
eap$lastImageHeight = curImgH; this.eap$lastImageHeight = curImgH;
eap$relayoutButtons(); this.eap$relayoutButtons();
} }
eap$updateLastConfigFromHover(); this.eap$updateLastConfigFromHover();
} }
@Unique @Unique
private void eap$sendAdjustForHoveredConfig(boolean divide, int factor) { private void eap$sendAdjustForHoveredConfig(boolean divide, int factor) {
try { try {
if (!eap$isSupportedInterfaceScreen()) { if (!this.eap$isSupportedInterfaceScreen()) {
return; return;
} }
Slot hovered = ((AbstractContainerScreenAccessor<?>) (Object) this).eap$getHoveredSlot(); Slot hovered = ((AbstractContainerScreenAccessor<?>) (Object) this).eap$getHoveredSlot();
@ -177,8 +186,8 @@ public abstract class InterfaceScreenMixin<T extends AEBaseMenu> {
int slotField = -1; int slotField = -1;
if (slotFieldObj != null) { if (slotFieldObj != null) {
slotField = slotFieldObj; slotField = slotFieldObj;
} else if (eap$lastConfigIndex >= 0 && eap$lastConfigIndex < configSlots.size()) { } else if (this.eap$lastConfigIndex >= 0 && this.eap$lastConfigIndex < configSlots.size()) {
slotField = eap$lastConfigIndex; slotField = this.eap$lastConfigIndex;
} }
if (slotField < 0) { if (slotField < 0) {
return; return;
@ -192,7 +201,7 @@ public abstract class InterfaceScreenMixin<T extends AEBaseMenu> {
@Unique @Unique
private void eap$sendAdjustForAllConfigs(boolean divide, int factor) { private void eap$sendAdjustForAllConfigs(boolean divide, int factor) {
try { try {
if (!eap$isSupportedInterfaceScreen()) { if (!this.eap$isSupportedInterfaceScreen()) {
return; return;
} }
var conn = Minecraft.getInstance().getConnection(); var conn = Minecraft.getInstance().getConnection();
@ -220,15 +229,33 @@ public abstract class InterfaceScreenMixin<T extends AEBaseMenu> {
int leftPos = ((AbstractContainerScreenAccessor<?>) (Object) this).eap$getLeftPos(); int leftPos = ((AbstractContainerScreenAccessor<?>) (Object) this).eap$getLeftPos();
int topPos = ((AbstractContainerScreenAccessor<?>) (Object) this).eap$getTopPos(); int topPos = ((AbstractContainerScreenAccessor<?>) (Object) this).eap$getTopPos();
int imageWidth = ((AbstractContainerScreenAccessor<?>) (Object) this).eap$getImageWidth(); int imageWidth = ((AbstractContainerScreenAccessor<?>) (Object) this).eap$getImageWidth();
int bx = leftPos + imageWidth + 1; int bx = leftPos - this.eap$divideBy2Button.getWidth() - 1;
int by = topPos + 70; int by = topPos + 30;
int spacing = 22; int spacing = 22;
if (eap$divideBy2Button != null) { eap$divideBy2Button.setX(bx); eap$divideBy2Button.setY(by); } if (this.eap$divideBy2Button != null) {
if (eap$x2Button != null) { eap$x2Button.setX(bx); eap$x2Button.setY(by + spacing); } this.eap$divideBy2Button.setX(bx);
if (eap$divideBy5Button != null) { eap$divideBy5Button.setX(bx); eap$divideBy5Button.setY(by + spacing * 2); } this.eap$divideBy2Button.setY(by);
if (eap$x5Button != null) { eap$x5Button.setX(bx); eap$x5Button.setY(by + spacing * 3); } }
if (eap$divideBy10Button != null) { eap$divideBy10Button.setX(bx); eap$divideBy10Button.setY(by + spacing * 4); } if (this.eap$x2Button != null) {
if (eap$x10Button != null) { eap$x10Button.setX(bx); eap$x10Button.setY(by + spacing * 5); } this.eap$x2Button.setX(bx);
this.eap$x2Button.setY(by + spacing);
}
if (this.eap$divideBy5Button != null) {
this.eap$divideBy5Button.setX(bx);
this.eap$divideBy5Button.setY(by + spacing * 2);
}
if (this.eap$x5Button != null) {
this.eap$x5Button.setX(bx);
this.eap$x5Button.setY(by + spacing * 3);
}
if (this.eap$divideBy10Button != null) {
this.eap$divideBy10Button.setX(bx);
this.eap$divideBy10Button.setY(by + spacing * 4);
}
if (this.eap$x10Button != null) {
this.eap$x10Button.setX(bx);
this.eap$x10Button.setY(by + spacing * 5);
}
} catch (Throwable ignored) {} } catch (Throwable ignored) {}
} }
@ -269,8 +296,8 @@ public abstract class InterfaceScreenMixin<T extends AEBaseMenu> {
} }
} }
if (idx != null && idx >= 0) { if (idx != null && idx >= 0) {
if (eap$lastConfigIndex != idx) { if (this.eap$lastConfigIndex != idx) {
eap$lastConfigIndex = idx; this.eap$lastConfigIndex = idx;
} }
} }
} catch (Throwable ignored) {} } catch (Throwable ignored) {}

View File

@ -7,9 +7,9 @@ import appeng.client.gui.implementations.PatternProviderScreen;
import appeng.client.gui.style.ScreenStyle; import appeng.client.gui.style.ScreenStyle;
import appeng.client.gui.widgets.SettingToggleButton; import appeng.client.gui.widgets.SettingToggleButton;
import appeng.menu.implementations.PatternProviderMenu; import appeng.menu.implementations.PatternProviderMenu;
import com.extendedae_plus.api.ExPatternButtonsAccessor; import com.extendedae_plus.api.IExPatternButton;
import com.extendedae_plus.api.PatternProviderMenuAdvancedSync; import com.extendedae_plus.api.advancedBlocking.IPatternProviderMenuAdvancedSync;
import com.extendedae_plus.api.PatternProviderMenuDoublingSync; import com.extendedae_plus.api.smartDoubling.IPatternProviderMenuDoublingSync;
import com.extendedae_plus.network.ToggleAdvancedBlockingC2SPacket; import com.extendedae_plus.network.ToggleAdvancedBlockingC2SPacket;
import com.extendedae_plus.network.ToggleSmartDoublingC2SPacket; import com.extendedae_plus.network.ToggleSmartDoublingC2SPacket;
import com.extendedae_plus.util.ExtendedAELogger; import com.extendedae_plus.util.ExtendedAELogger;
@ -51,7 +51,7 @@ public abstract class PatternProviderScreenMixin<C extends PatternProviderMenu>
private void eap$initAdvancedBlocking(C menu, Inventory playerInventory, Component title, ScreenStyle style, CallbackInfo ci) { private void eap$initAdvancedBlocking(C menu, Inventory playerInventory, Component title, ScreenStyle style, CallbackInfo ci) {
// 使用 @GuiSync 初始化 // 使用 @GuiSync 初始化
try { try {
if (menu instanceof PatternProviderMenuAdvancedSync sync) { if (menu instanceof IPatternProviderMenuAdvancedSync sync) {
this.eap$AdvancedBlockingEnabled = sync.eap$getAdvancedBlockingSynced(); this.eap$AdvancedBlockingEnabled = sync.eap$getAdvancedBlockingSynced();
} }
} catch (Throwable t) { } catch (Throwable t) {
@ -71,7 +71,7 @@ public abstract class PatternProviderScreenMixin<C extends PatternProviderMenu>
) { ) {
@Override @Override
public java.util.List<net.minecraft.network.chat.Component> getTooltipMessage() { public java.util.List<net.minecraft.network.chat.Component> getTooltipMessage() {
boolean enabled = eap$AdvancedBlockingEnabled; boolean enabled = PatternProviderScreenMixin.this.eap$AdvancedBlockingEnabled;
var title = net.minecraft.network.chat.Component.literal("智能阻挡"); var title = net.minecraft.network.chat.Component.literal("智能阻挡");
var line = enabled var line = enabled
? net.minecraft.network.chat.Component.literal("已启用:对于同一种配方将不再阻挡(需要开启原版的阻挡模式)") ? net.minecraft.network.chat.Component.literal("已启用:对于同一种配方将不再阻挡(需要开启原版的阻挡模式)")
@ -87,7 +87,7 @@ public abstract class PatternProviderScreenMixin<C extends PatternProviderMenu>
// 智能翻倍按钮与高级阻挡同款样式点击仅发送C2S状态由@GuiSync驱动 // 智能翻倍按钮与高级阻挡同款样式点击仅发送C2S状态由@GuiSync驱动
try { try {
if (menu instanceof PatternProviderMenuDoublingSync sync2) { if (menu instanceof IPatternProviderMenuDoublingSync sync2) {
this.eap$SmartDoublingEnabled = sync2.eap$getSmartDoublingSynced(); this.eap$SmartDoublingEnabled = sync2.eap$getSmartDoublingSynced();
} }
} catch (Throwable t) { } catch (Throwable t) {
@ -105,7 +105,7 @@ public abstract class PatternProviderScreenMixin<C extends PatternProviderMenu>
) { ) {
@Override @Override
public java.util.List<net.minecraft.network.chat.Component> getTooltipMessage() { public java.util.List<net.minecraft.network.chat.Component> getTooltipMessage() {
boolean enabled = eap$SmartDoublingEnabled; boolean enabled = PatternProviderScreenMixin.this.eap$SmartDoublingEnabled;
var title = net.minecraft.network.chat.Component.literal("智能翻倍"); var title = net.minecraft.network.chat.Component.literal("智能翻倍");
var line = enabled var line = enabled
? net.minecraft.network.chat.Component.literal("已启用:根据请求量对处理样板进行智能缩放") ? net.minecraft.network.chat.Component.literal("已启用:根据请求量对处理样板进行智能缩放")
@ -123,7 +123,7 @@ public abstract class PatternProviderScreenMixin<C extends PatternProviderMenu>
private void eap$updateAdvancedBlocking(CallbackInfo ci) { private void eap$updateAdvancedBlocking(CallbackInfo ci) {
if (this.eap$AdvancedBlockingToggle != null) { if (this.eap$AdvancedBlockingToggle != null) {
boolean desired = this.eap$AdvancedBlockingEnabled; boolean desired = this.eap$AdvancedBlockingEnabled;
if (this.menu instanceof PatternProviderMenuAdvancedSync sync) { if (this.menu instanceof IPatternProviderMenuAdvancedSync sync) {
desired = sync.eap$getAdvancedBlockingSynced(); desired = sync.eap$getAdvancedBlockingSynced();
} }
// debug removed // debug removed
@ -133,7 +133,7 @@ public abstract class PatternProviderScreenMixin<C extends PatternProviderMenu>
if (this.eap$SmartDoublingToggle != null) { if (this.eap$SmartDoublingToggle != null) {
boolean desired2 = this.eap$SmartDoublingEnabled; boolean desired2 = this.eap$SmartDoublingEnabled;
if (this.menu instanceof PatternProviderMenuDoublingSync sync2) { if (this.menu instanceof IPatternProviderMenuDoublingSync sync2) {
desired2 = sync2.eap$getSmartDoublingSynced(); desired2 = sync2.eap$getSmartDoublingSynced();
} }
// debug removed // debug removed
@ -143,7 +143,7 @@ public abstract class PatternProviderScreenMixin<C extends PatternProviderMenu>
if ((Object) this instanceof GuiExPatternProvider) { if ((Object) this instanceof GuiExPatternProvider) {
try { try {
((ExPatternButtonsAccessor) this).eap$updateButtonsLayout(); ((IExPatternButton) this).eap$updateButtonsLayout();
} catch (Throwable t) { } catch (Throwable t) {
// debug removed // debug removed
} }

View File

@ -15,9 +15,9 @@ import appeng.helpers.patternprovider.PatternProviderLogicHost;
import appeng.menu.AEBaseMenu; import appeng.menu.AEBaseMenu;
import appeng.menu.SlotSemantics; import appeng.menu.SlotSemantics;
import appeng.menu.implementations.PatternProviderMenu; import appeng.menu.implementations.PatternProviderMenu;
import com.extendedae_plus.api.IStyleAccessor;
import com.extendedae_plus.compat.AppliedFluxCompat; import com.extendedae_plus.compat.AppliedFluxCompat;
import com.extendedae_plus.compat.UpgradeSlotCompat; import com.extendedae_plus.compat.UpgradeSlotCompat;
import com.extendedae_plus.util.IStyleAccessor;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Inventory;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
@ -32,6 +32,10 @@ import java.util.List;
@Mixin(value = PatternProviderScreen.class, priority = 1500, remap = false) @Mixin(value = PatternProviderScreen.class, priority = 1500, remap = false)
public abstract class PatternProviderScreenUpgradesMixin<C extends PatternProviderMenu> extends AEBaseScreen<C> { public abstract class PatternProviderScreenUpgradesMixin<C extends PatternProviderMenu> extends AEBaseScreen<C> {
public PatternProviderScreenUpgradesMixin(C menu, Inventory playerInventory, Component title, ScreenStyle style) {
super(menu, playerInventory, title, style);
}
@Inject(method = "<init>", at = @At("TAIL"), remap = false) @Inject(method = "<init>", at = @At("TAIL"), remap = false)
private void eap$initUpgrades(PatternProviderMenu menu, Inventory playerInventory, Component title, ScreenStyle style, CallbackInfo ci) { private void eap$initUpgrades(PatternProviderMenu menu, Inventory playerInventory, Component title, ScreenStyle style, CallbackInfo ci) {
@ -77,7 +81,7 @@ public abstract class PatternProviderScreenUpgradesMixin<C extends PatternProvid
((IStyleAccessor) style).getWidgets().put("toolbox", ws); ((IStyleAccessor) style).getWidgets().put("toolbox", ws);
// 添加工具箱面板 // 添加工具箱面板
if (menu instanceof AEBaseMenu base && base instanceof com.extendedae_plus.bridge.IUpgradableMenu upg && upg.eap$getToolbox() != null && upg.eap$getToolbox().isPresent()) { if (menu instanceof AEBaseMenu base && base instanceof com.extendedae_plus.api.bridge.IUpgradableMenu upg && upg.eap$getToolbox() != null && upg.eap$getToolbox().isPresent()) {
try { try {
this.widgets.add("toolbox", new ToolboxPanel(style, upg.eap$getToolbox().getName())); this.widgets.add("toolbox", new ToolboxPanel(style, upg.eap$getToolbox().getName()));
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
@ -88,12 +92,11 @@ public abstract class PatternProviderScreenUpgradesMixin<C extends PatternProvid
} }
} }
@Unique @Unique
private List<Component> eap$getCompatibleUpgrades() { private List<Component> eap$getCompatibleUpgrades() {
var list = new ArrayList<Component>(); var list = new ArrayList<Component>();
list.add(GuiText.CompatibleUpgrades.text()); list.add(GuiText.CompatibleUpgrades.text());
if (menu instanceof AEBaseMenu base) { if (this.menu instanceof AEBaseMenu base) {
var target = base.getTarget(); var target = base.getTarget();
if (target instanceof PatternProviderLogicHost host) { if (target instanceof PatternProviderLogicHost host) {
list.addAll(Upgrades.getTooltipLinesForMachine(host.getTerminalIcon().getItem())); list.addAll(Upgrades.getTooltipLinesForMachine(host.getTerminalIcon().getItem()));
@ -101,8 +104,4 @@ public abstract class PatternProviderScreenUpgradesMixin<C extends PatternProvid
} }
return list; return list;
} }
public PatternProviderScreenUpgradesMixin(C menu, Inventory playerInventory, Component title, ScreenStyle style) {
super(menu, playerInventory, title, style);
}
} }

View File

@ -3,7 +3,7 @@ package com.extendedae_plus.mixin.ae2.client.gui;
import appeng.client.gui.style.Blitter; import appeng.client.gui.style.Blitter;
import appeng.client.gui.style.ScreenStyle; import appeng.client.gui.style.ScreenStyle;
import appeng.client.gui.style.WidgetStyle; import appeng.client.gui.style.WidgetStyle;
import com.extendedae_plus.util.IStyleAccessor; import com.extendedae_plus.api.IStyleAccessor;
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;

View File

@ -2,6 +2,7 @@ package com.extendedae_plus.mixin.ae2.client.gui;
import appeng.client.Point; import appeng.client.Point;
import appeng.client.gui.layout.SlotGridLayout; import appeng.client.gui.layout.SlotGridLayout;
import com.extendedae_plus.api.IExPatternPage;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.Unique;
@ -32,7 +33,7 @@ public abstract class SlotGridLayoutMixin {
// 读取实际当前页码优先从 GUI accessor其次反射容器失败则为 0 // 读取实际当前页码优先从 GUI accessor其次反射容器失败则为 0
int currentPage = 0; int currentPage = 0;
try { try {
if (screen instanceof com.extendedae_plus.api.ExPatternPageAccessor accessor) { if (screen instanceof IExPatternPage accessor) {
currentPage = accessor.eap$getCurrentPage(); currentPage = accessor.eap$getCurrentPage();
} else { } else {
var menu = ((com.glodblock.github.extendedae.client.gui.GuiExPatternProvider) screen).getMenu(); var menu = ((com.glodblock.github.extendedae.client.gui.GuiExPatternProvider) screen).getMenu();

View File

@ -12,18 +12,17 @@ import appeng.api.upgrades.UpgradeInventories;
import appeng.helpers.patternprovider.PatternProviderLogic; import appeng.helpers.patternprovider.PatternProviderLogic;
import appeng.helpers.patternprovider.PatternProviderLogicHost; import appeng.helpers.patternprovider.PatternProviderLogicHost;
import appeng.me.cluster.implementations.CraftingCPUCluster; import appeng.me.cluster.implementations.CraftingCPUCluster;
import com.extendedae_plus.ae.items.ChannelCardItem; import com.extendedae_plus.ae.wireless.WirelessSlaveLink;
import com.extendedae_plus.bridge.CompatUpgradeProvider; import com.extendedae_plus.ae.wireless.endpoint.GenericNodeEndpointImpl;
import com.extendedae_plus.bridge.InterfaceWirelessLinkBridge; import com.extendedae_plus.api.bridge.CompatUpgradeProvider;
import com.extendedae_plus.api.bridge.InterfaceWirelessLinkBridge;
import com.extendedae_plus.compat.PatternProviderLogicVirtualCompatBridge; import com.extendedae_plus.compat.PatternProviderLogicVirtualCompatBridge;
import com.extendedae_plus.compat.UpgradeSlotCompat; import com.extendedae_plus.compat.UpgradeSlotCompat;
import com.extendedae_plus.init.ModItems; import com.extendedae_plus.init.ModItems;
import com.extendedae_plus.items.materials.ChannelCardItem;
import com.extendedae_plus.mixin.ae2.accessor.CraftingCpuLogicAccessor; import com.extendedae_plus.mixin.ae2.accessor.CraftingCpuLogicAccessor;
import com.extendedae_plus.mixin.ae2.accessor.ExecutingCraftingJobAccessor; import com.extendedae_plus.mixin.ae2.accessor.ExecutingCraftingJobAccessor;
import com.extendedae_plus.mixin.ae2.accessor.ExecutingCraftingJobTaskProgressAccessor;
import com.extendedae_plus.util.ExtendedAELogger; import com.extendedae_plus.util.ExtendedAELogger;
import com.extendedae_plus.wireless.WirelessSlaveLink;
import com.extendedae_plus.wireless.endpoint.GenericNodeEndpointImpl;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
@ -91,7 +90,7 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
this.eap$compatUpgrades = UpgradeInventories.empty(); this.eap$compatUpgrades = UpgradeInventories.empty();
// 尝试监听AppliedFlux的升级变更 // 尝试监听AppliedFlux的升级变更
eap$tryHookAppliedFluxUpgradeChanges(); this.eap$tryHookAppliedFluxUpgradeChanges();
} }
} catch (Throwable t) { } catch (Throwable t) {
ExtendedAELogger.LOGGER.error("[样板供应器] 初始化兼容升级槽失败", t); ExtendedAELogger.LOGGER.error("[样板供应器] 初始化兼容升级槽失败", t);
@ -102,10 +101,10 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
private void eap$compatOnUpgradesChanged() { private void eap$compatOnUpgradesChanged() {
try { try {
this.host.saveChanges(); this.host.saveChanges();
eap$compatLastChannel = -1; this.eap$compatLastChannel = -1;
eap$compatHasInitialized = false; this.eap$compatHasInitialized = false;
eap$compatInitializeChannelLink(); this.eap$compatInitializeChannelLink();
eap$compatSyncVirtualCraftingState(); this.eap$compatSyncVirtualCraftingState();
} catch (Throwable t) { } catch (Throwable t) {
ExtendedAELogger.LOGGER.error("[样板供应器] 兼容升级变更处理失败", t); ExtendedAELogger.LOGGER.error("[样板供应器] 兼容升级变更处理失败", t);
} }
@ -147,10 +146,10 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
this.eap$compatUpgrades.readFromNBT(tag, "compat_upgrades", registries); this.eap$compatUpgrades.readFromNBT(tag, "compat_upgrades", registries);
} }
// 无论哪种模式都重新初始化 // 无论哪种模式都重新初始化
eap$compatLastChannel = -1; this.eap$compatLastChannel = -1;
eap$compatHasInitialized = false; this.eap$compatHasInitialized = false;
eap$compatInitializeChannelLink(); this.eap$compatInitializeChannelLink();
eap$compatSyncVirtualCraftingState(); this.eap$compatSyncVirtualCraftingState();
} catch (Throwable t) { } catch (Throwable t) {
ExtendedAELogger.LOGGER.error("[样板供应器] 读取兼容升级失败", t); ExtendedAELogger.LOGGER.error("[样板供应器] 读取兼容升级失败", t);
} }
@ -183,11 +182,11 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
@Inject(method = "onMainNodeStateChanged", at = @At("TAIL")) @Inject(method = "onMainNodeStateChanged", at = @At("TAIL"))
private void eap$compatOnNodeChange(CallbackInfo ci) { private void eap$compatOnNodeChange(CallbackInfo ci) {
try { try {
eap$compatLastChannel = -1; this.eap$compatLastChannel = -1;
eap$compatHasInitialized = false; this.eap$compatHasInitialized = false;
// 直接初始化不使用延迟 // 直接初始化不使用延迟
eap$compatInitializeChannelLink(); this.eap$compatInitializeChannelLink();
mainNode.ifPresent((grid, node) -> { this.mainNode.ifPresent((grid, node) -> {
try { grid.getTickManager().wakeDevice(node); } catch (Throwable ignored) {} try { grid.getTickManager().wakeDevice(node); } catch (Throwable ignored) {}
}); });
} catch (Throwable t) { } catch (Throwable t) {
@ -200,22 +199,126 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
@Override @Override
public void eap$updateWirelessLink() { public void eap$updateWirelessLink() {
if (eap$compatLink != null) { if (this.eap$compatLink != null) {
eap$compatLink.updateStatus(); this.eap$compatLink.updateStatus();
} }
} }
@Override
public boolean eap$isWirelessConnected() {
if (this.host.getBlockEntity() != null && this.host.getBlockEntity().getLevel() != null && this.host.getBlockEntity().getLevel().isClientSide) {
return this.eap$compatClientConnected;
} else {
return this.eap$compatLink != null && this.eap$compatLink.isConnected();
}
}
@Override
public void eap$setClientWirelessState(boolean connected) {
this.eap$compatClientConnected = connected;
}
@Override
public boolean eap$hasTickInitialized() {
return this.eap$compatHasInitialized;
}
@Override
public void eap$setTickInitialized(boolean initialized) {
this.eap$compatHasInitialized = initialized;
}
@Override
public void eap$handleDelayedInit() {
// 如果还未初始化或者需要重新检查AppliedFlux升级槽
if (!this.eap$compatHasInitialized) {
this.eap$compatInitializeChannelLink();
} else if (!UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
// 安装了AppliedFlux时定期检查升级槽变化
try {
IUpgradeInventory afUpgrades = this.eap$getAppliedFluxUpgrades();
if (afUpgrades != null && this.eap$hasChannelCard(afUpgrades)) {
// 检查频道是否发生变化
for (ItemStack stack : afUpgrades) {
if (!stack.isEmpty() && stack.getItem() == ModItems.CHANNEL_CARD.get()) {
long newChannel = ChannelCardItem.getChannel(stack);
if (newChannel != this.eap$compatLastChannel) {
this.eap$compatLastChannel = -1; // 强制重新初始化
this.eap$compatHasInitialized = false;
this.eap$compatInitializeChannelLink();
this.eap$compatSyncVirtualCraftingState();
}
break;
}
}
} else if (this.eap$compatLastChannel != 0L) {
// 频道卡被移除
this.eap$compatLastChannel = -1;
this.eap$compatHasInitialized = false;
this.eap$compatInitializeChannelLink();
this.eap$compatSyncVirtualCraftingState();
}
} catch (Throwable t) {
}
}
}
/**
* 指示 PatternProviderLogic Ticker 是否需要保持慢速 tick 以轮询频道卡或维持无线连接
*/
@Override
public boolean eap$shouldKeepTicking() {
try {
// 仅在服务端保持tick
if (this.host.getBlockEntity() == null || this.host.getBlockEntity().getLevel() == null || this.host.getBlockEntity().getLevel().isClientSide) {
return false;
}
// 未初始化需要继续tick直到初始化完成
if (!this.eap$compatHasInitialized) {
return true;
}
// 安装了 AppliedFlux根据连接状态与频道卡存在性决定是否维持慢速tick
if (!UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
// 若曾经设置过频道或者当前存在未连通的链接则保持tick
if (this.eap$compatLastChannel != 0L) {
return true;
}
if (this.eap$compatLink != null && !this.eap$compatLink.isConnected()) {
return true;
}
try {
IUpgradeInventory afUpgrades = this.eap$getAppliedFluxUpgrades();
if (afUpgrades != null && this.eap$hasChannelCard(afUpgrades)) {
// 槽中有频道卡保持tick以尽快完成连接
return true;
}
} catch (Throwable ignored) {
}
// 否则可以休眠
return false;
}
// 未安装 AppliedFlux当存在频道卡但连接尚未建立时保持tick
if (this.eap$compatUpgrades != null && this.eap$hasChannelCard(this.eap$compatUpgrades)) {
if (this.eap$compatLink == null || !this.eap$compatLink.isConnected()) {
return true;
}
}
} catch (Throwable ignored) {
}
return false;
}
@Unique @Unique
public void eap$compatInitializeChannelLink() { private void eap$compatInitializeChannelLink() {
try { try {
// 客户端早退 // 客户端早退
if (host.getBlockEntity() != null && host.getBlockEntity().getLevel() != null && host.getBlockEntity().getLevel().isClientSide) { if (this.host.getBlockEntity() != null && this.host.getBlockEntity().getLevel() != null && this.host.getBlockEntity().getLevel().isClientSide) {
return; return;
} }
if (eap$compatHasInitialized) { if (this.eap$compatHasInitialized) {
return; return;
} }
if (mainNode == null || mainNode.getNode() == null) { if (this.mainNode == null || this.mainNode.getNode() == null) {
return; return;
} }
@ -229,7 +332,7 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
// 安装了appflux优先使用appflux的升级槽 // 安装了appflux优先使用appflux的升级槽
try { try {
// 更安全的方式获取AppliedFlux升级槽 // 更安全的方式获取AppliedFlux升级槽
upgrades = eap$getAppliedFluxUpgrades(); upgrades = this.eap$getAppliedFluxUpgrades();
if (upgrades != null) { if (upgrades != null) {
} else { } else {
ExtendedAELogger.LOGGER.warn("[样板供应器] 无法获取 appflux 升级槽,回退到兼容槽"); ExtendedAELogger.LOGGER.warn("[样板供应器] 无法获取 appflux 升级槽,回退到兼容槽");
@ -245,20 +348,20 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
} }
// 双重保险如果主要方式失败尝试备用方式 // 双重保险如果主要方式失败尝试备用方式
if (upgrades == null || !eap$hasChannelCard(upgrades)) { if (upgrades == null || !this.eap$hasChannelCard(upgrades)) {
if (UpgradeSlotCompat.shouldEnableUpgradeSlots()) { if (UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
// 如果我们的槽无频道卡尝试检查是否有AppliedFlux的槽 // 如果我们的槽无频道卡尝试检查是否有AppliedFlux的槽
try { try {
IUpgradeInventory backupUpgrades = eap$getAppliedFluxUpgrades(); IUpgradeInventory backupUpgrades = this.eap$getAppliedFluxUpgrades();
if (backupUpgrades != null && eap$hasChannelCard(backupUpgrades)) { if (backupUpgrades != null && this.eap$hasChannelCard(backupUpgrades)) {
upgrades = backupUpgrades; upgrades = backupUpgrades;
} }
} catch (Throwable t) { } catch (Throwable t) {
} }
} else { } else {
// 如果AppliedFlux的槽无频道卡尝试我们的兼容槽 // 如果AppliedFlux的槽无频道卡尝试我们的兼容槽
if (this.eap$compatUpgrades != null && eap$hasChannelCard(this.eap$compatUpgrades)) { if (this.eap$compatUpgrades != null && this.eap$hasChannelCard(this.eap$compatUpgrades)) {
upgrades = this.eap$compatUpgrades; upgrades = this.eap$compatUpgrades;
} }
} }
@ -275,23 +378,26 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
} }
if (!found) { if (!found) {
eap$compatSyncVirtualCraftingState(); this.eap$compatSyncVirtualCraftingState();
if (eap$compatLink != null) { if (this.eap$compatLink != null) {
eap$compatLink.setFrequency(0L); this.eap$compatLink.setFrequency(0L);
eap$compatLink.updateStatus(); this.eap$compatLink.updateStatus();
}
this.eap$compatLastChannel = 0L;
this.eap$compatHasInitialized = true;
try {
this.host.saveChanges();
} catch (Throwable ignored) {
} }
eap$compatLastChannel = 0L;
eap$compatHasInitialized = true;
try { host.saveChanges(); } catch (Throwable ignored) {}
// 唤醒节点加速 AE2 感知到连接断开 // 唤醒节点加速 AE2 感知到连接断开
mainNode.ifPresent((grid, node) -> { this.mainNode.ifPresent((grid, node) -> {
try { grid.getTickManager().wakeDevice(node); } catch (Throwable ignored) {} try { grid.getTickManager().wakeDevice(node); } catch (Throwable ignored) {}
// 兜底如仍存在针对无线主端的直连 in-world强制销毁 // 兜底如仍存在针对无线主端的直连 in-world强制销毁
try { try {
for (IGridConnection gc : node.getConnections()) { for (IGridConnection gc : node.getConnections()) {
if (gc != null && !gc.isInWorld()) { if (gc != null && !gc.isInWorld()) {
var other = gc.getOtherSide(node); var other = gc.getOtherSide(node);
if (other != null && other.getOwner() instanceof com.extendedae_plus.wireless.IWirelessEndpoint) { if (other != null && other.getOwner() instanceof com.extendedae_plus.ae.wireless.IWirelessEndpoint) {
gc.destroy(); gc.destroy();
try { grid.getTickManager().wakeDevice(node); } catch (Throwable ignored2) {} try { grid.getTickManager().wakeDevice(node); } catch (Throwable ignored2) {}
try { if (other.getGrid() != null) { other.getGrid().getTickManager().wakeDevice(other); } } catch (Throwable ignored2) {} try { if (other.getGrid() != null) { other.getGrid().getTickManager().wakeDevice(other); } } catch (Throwable ignored2) {}
@ -303,140 +409,42 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
return; return;
} }
if (eap$compatLink == null) { if (this.eap$compatLink == null) {
var endpoint = new GenericNodeEndpointImpl(() -> host.getBlockEntity(), () -> this.mainNode.getNode()); var endpoint = new GenericNodeEndpointImpl(() -> this.host.getBlockEntity(), () -> this.mainNode.getNode());
eap$compatLink = new WirelessSlaveLink(endpoint); this.eap$compatLink = new WirelessSlaveLink(endpoint);
} }
eap$compatLink.setFrequency(channel); this.eap$compatLink.setFrequency(channel);
eap$compatLink.updateStatus(); this.eap$compatLink.updateStatus();
eap$compatLastChannel = channel; // 记录当前频道 this.eap$compatLastChannel = channel; // 记录当前频道
try { host.saveChanges(); } catch (Throwable ignored) {} try {
mainNode.ifPresent((grid, node) -> { this.host.saveChanges();
} catch (Throwable ignored) {
}
this.mainNode.ifPresent((grid, node) -> {
try { grid.getTickManager().wakeDevice(node); } catch (Throwable ignored) {} try { grid.getTickManager().wakeDevice(node); } catch (Throwable ignored) {}
}); });
if (eap$compatLink.isConnected()) { if (this.eap$compatLink.isConnected()) {
eap$compatHasInitialized = true; this.eap$compatHasInitialized = true;
} else { } else {
eap$compatHasInitialized = false; this.eap$compatHasInitialized = false;
// 如果连接失败唤醒设备以便稍后重试 // 如果连接失败唤醒设备以便稍后重试
mainNode.ifPresent((grid, node) -> { this.mainNode.ifPresent((grid, node) -> {
try { grid.getTickManager().wakeDevice(node); } catch (Throwable ignored) {} try { grid.getTickManager().wakeDevice(node); } catch (Throwable ignored) {}
}); });
} }
eap$compatSyncVirtualCraftingState(); this.eap$compatSyncVirtualCraftingState();
} catch (Throwable t) { } catch (Throwable t) {
ExtendedAELogger.LOGGER.error("[样板供应器] 初始化频道链接失败", t); ExtendedAELogger.LOGGER.error("[样板供应器] 初始化频道链接失败", t);
} }
} }
@Override
public void eap$setClientWirelessState(boolean connected) {
eap$compatClientConnected = connected;
}
@Override
public boolean eap$isWirelessConnected() {
if (host.getBlockEntity() != null && host.getBlockEntity().getLevel() != null && host.getBlockEntity().getLevel().isClientSide) {
return eap$compatClientConnected;
} else {
return eap$compatLink != null && eap$compatLink.isConnected();
}
}
@Override
public boolean eap$hasTickInitialized() {
return eap$compatHasInitialized;
}
@Override
public void eap$setTickInitialized(boolean initialized) {
eap$compatHasInitialized = initialized;
}
@Override
public void eap$handleDelayedInit() {
// 如果还未初始化或者需要重新检查AppliedFlux升级槽
if (!eap$compatHasInitialized) {
eap$compatInitializeChannelLink();
} else if (!UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
// 安装了AppliedFlux时定期检查升级槽变化
try {
IUpgradeInventory afUpgrades = eap$getAppliedFluxUpgrades();
if (afUpgrades != null && eap$hasChannelCard(afUpgrades)) {
// 检查频道是否发生变化
for (ItemStack stack : afUpgrades) {
if (!stack.isEmpty() && stack.getItem() == ModItems.CHANNEL_CARD.get()) {
long newChannel = ChannelCardItem.getChannel(stack);
if (newChannel != eap$compatLastChannel) {
eap$compatLastChannel = -1; // 强制重新初始化
eap$compatHasInitialized = false;
eap$compatInitializeChannelLink();
eap$compatSyncVirtualCraftingState();
}
break;
}
}
} else if (eap$compatLastChannel != 0L) {
// 频道卡被移除
eap$compatLastChannel = -1;
eap$compatHasInitialized = false;
eap$compatInitializeChannelLink();
eap$compatSyncVirtualCraftingState();
}
} catch (Throwable t) {
}
}
}
/**
* 指示 PatternProviderLogic Ticker 是否需要保持慢速 tick 以轮询频道卡或维持无线连接
*/
public boolean eap$shouldKeepTicking() {
try {
// 仅在服务端保持tick
if (host.getBlockEntity() == null || host.getBlockEntity().getLevel() == null || host.getBlockEntity().getLevel().isClientSide) {
return false;
}
// 未初始化需要继续tick直到初始化完成
if (!eap$compatHasInitialized) {
return true;
}
// 安装了 AppliedFlux根据连接状态与频道卡存在性决定是否维持慢速tick
if (!UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
// 若曾经设置过频道或者当前存在未连通的链接则保持tick
if (eap$compatLastChannel != 0L) {
return true;
}
if (eap$compatLink != null && !eap$compatLink.isConnected()) {
return true;
}
try {
IUpgradeInventory afUpgrades = eap$getAppliedFluxUpgrades();
if (afUpgrades != null && eap$hasChannelCard(afUpgrades)) {
// 槽中有频道卡保持tick以尽快完成连接
return true;
}
} catch (Throwable ignored) {}
// 否则可以休眠
return false;
}
// 未安装 AppliedFlux当存在频道卡但连接尚未建立时保持tick
if (this.eap$compatUpgrades != null && eap$hasChannelCard(this.eap$compatUpgrades)) {
if (eap$compatLink == null || !eap$compatLink.isConnected()) {
return true;
}
}
} catch (Throwable ignored) {}
return false;
}
// CompatUpgradeProvider 实现仅在未安装 appflux 时由我们提供升级槽 // CompatUpgradeProvider 实现仅在未安装 appflux 时由我们提供升级槽
@Unique @Unique
private boolean eap$hasChannelCard(IUpgradeInventory inventory) { private boolean eap$hasChannelCard(IUpgradeInventory inventory) {
return eap$compatInventoryContains(inventory, ModItems.CHANNEL_CARD.get()); return this.eap$compatInventoryContains(inventory, ModItems.CHANNEL_CARD.get());
} }
/** /**
@ -471,14 +479,13 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
@Inject(method = "pushPattern", at = @At("RETURN"), cancellable = true) @Inject(method = "pushPattern", at = @At("RETURN"), cancellable = true)
private void eap$compatAfterPushPattern(IPatternDetails patternDetails, KeyCounter[] inputHolder, CallbackInfoReturnable<Boolean> cir) { private void eap$compatAfterPushPattern(IPatternDetails patternDetails, KeyCounter[] inputHolder, CallbackInfoReturnable<Boolean> cir) {
if (cir.getReturnValueZ()) { if (cir.getReturnValueZ()) {
eap$compatTryVirtualCompletion(patternDetails); this.eap$compatTryVirtualCompletion(patternDetails);
} }
} }
@Unique @Unique
private void eap$compatTryVirtualCompletion(IPatternDetails patternDetails) { private void eap$compatTryVirtualCompletion(IPatternDetails patternDetails) {
if (!eap$compatVirtualCraftingEnabled) { if (!this.eap$compatVirtualCraftingEnabled) {
return; return;
} }
@ -531,7 +538,6 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
} }
} }
} }
continue;
} }
} }
} }
@ -549,8 +555,8 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
@Unique @Unique
private void eap$compatSyncVirtualCraftingState() { private void eap$compatSyncVirtualCraftingState() {
try { try {
IUpgradeInventory upgrades = eap$compatGetEffectiveUpgrades(); IUpgradeInventory upgrades = this.eap$compatGetEffectiveUpgrades();
this.eap$compatVirtualCraftingEnabled = eap$compatInventoryContains(upgrades, ModItems.VIRTUAL_CRAFTING_CARD.get()); this.eap$compatVirtualCraftingEnabled = this.eap$compatInventoryContains(upgrades, ModItems.VIRTUAL_CRAFTING_CARD.get());
} catch (Throwable t) { } catch (Throwable t) {
ExtendedAELogger.LOGGER.error("[样板供应器] 同步虚拟合成卡状态失败", t); ExtendedAELogger.LOGGER.error("[样板供应器] 同步虚拟合成卡状态失败", t);
} }
@ -562,14 +568,14 @@ public abstract class PatternProviderLogicCompatMixin implements CompatUpgradePr
if (UpgradeSlotCompat.shouldEnableUpgradeSlots()) { if (UpgradeSlotCompat.shouldEnableUpgradeSlots()) {
upgrades = this.eap$compatUpgrades; upgrades = this.eap$compatUpgrades;
} else { } else {
upgrades = eap$getAppliedFluxUpgrades(); upgrades = this.eap$getAppliedFluxUpgrades();
} }
if (upgrades == null || upgrades == UpgradeInventories.empty()) { if (upgrades == null || upgrades == UpgradeInventories.empty()) {
if (upgrades != this.eap$compatUpgrades && this.eap$compatUpgrades != null) { if (upgrades != this.eap$compatUpgrades && this.eap$compatUpgrades != null) {
upgrades = this.eap$compatUpgrades; upgrades = this.eap$compatUpgrades;
} else { } else {
var fallback = eap$getAppliedFluxUpgrades(); var fallback = this.eap$getAppliedFluxUpgrades();
if (fallback != null) { if (fallback != null) {
upgrades = fallback; upgrades = fallback;
} }

View File

@ -3,11 +3,11 @@ package com.extendedae_plus.mixin.ae2.helpers;
import appeng.api.upgrades.IUpgradeInventory; import appeng.api.upgrades.IUpgradeInventory;
import appeng.helpers.InterfaceLogic; import appeng.helpers.InterfaceLogic;
import appeng.helpers.InterfaceLogicHost; import appeng.helpers.InterfaceLogicHost;
import com.extendedae_plus.ae.items.ChannelCardItem; import com.extendedae_plus.ae.wireless.WirelessSlaveLink;
import com.extendedae_plus.bridge.InterfaceWirelessLinkBridge; import com.extendedae_plus.ae.wireless.endpoint.InterfaceNodeEndpointImpl;
import com.extendedae_plus.api.bridge.InterfaceWirelessLinkBridge;
import com.extendedae_plus.init.ModItems; import com.extendedae_plus.init.ModItems;
import com.extendedae_plus.wireless.WirelessSlaveLink; import com.extendedae_plus.items.materials.ChannelCardItem;
import com.extendedae_plus.wireless.endpoint.InterfaceNodeEndpointImpl;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
@ -19,50 +19,46 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(InterfaceLogic.class) @Mixin(InterfaceLogic.class)
public abstract class InterfaceLogicChannelCardMixin implements InterfaceWirelessLinkBridge { public abstract class InterfaceLogicChannelCardMixin implements InterfaceWirelessLinkBridge {
@Shadow(remap = false) public abstract IUpgradeInventory getUpgrades();
@Shadow(remap = false) public abstract appeng.api.networking.IGridNode getActionableNode();
@Shadow(remap = false) protected InterfaceLogicHost host;
@Shadow(remap = false) protected appeng.api.networking.IManagedGridNode mainNode;
@Unique
private WirelessSlaveLink eap$link;
@Unique
private long eap$lastChannel = -1;
@Unique
private boolean eap$clientConnected = false;
@Unique
private boolean eap$hasInitialized = false;
@Unique
private int eap$delayedInitTicks = 0;
static { static {
// InterfaceLogicChannelCardMixin 已加载 // InterfaceLogicChannelCardMixin 已加载
} }
@Shadow(remap = false) protected InterfaceLogicHost host;
@Shadow(remap = false) protected appeng.api.networking.IManagedGridNode mainNode;
@Unique
private WirelessSlaveLink eap$link;
@Unique
private long eap$lastChannel = -1;
@Unique
private boolean eap$clientConnected = false;
@Unique
private boolean eap$hasInitialized = false;
@Unique
private int eap$delayedInitTicks = 0;
@Shadow(remap = false)
public abstract IUpgradeInventory getUpgrades();
@Shadow(remap = false)
public abstract appeng.api.networking.IGridNode getActionableNode();
@Inject(method = "onUpgradesChanged", at = @At("TAIL"), remap = false) @Inject(method = "onUpgradesChanged", at = @At("TAIL"), remap = false)
private void eap$onUpgradesChangedTail(CallbackInfo ci) { private void eap$onUpgradesChangedTail(CallbackInfo ci) {
// 升级变更时重置标志并尝试初始化 // 升级变更时重置标志并尝试初始化
eap$lastChannel = -1; this.eap$lastChannel = -1;
eap$hasInitialized = false; this.eap$hasInitialized = false;
eap$initializeChannelLink(); this.eap$initializeChannelLink();
} }
@Inject(method = "gridChanged", at = @At("TAIL"), remap = false) @Inject(method = "gridChanged", at = @At("TAIL"), remap = false)
private void eap$afterGridChanged(CallbackInfo ci) { private void eap$afterGridChanged(CallbackInfo ci) {
// 网格状态变化时重置标志并设置延迟初始化 // 网格状态变化时重置标志并设置延迟初始化
eap$lastChannel = -1; this.eap$lastChannel = -1;
eap$hasInitialized = false; this.eap$hasInitialized = false;
eap$delayedInitTicks = 10; // 适当增加延迟tick等待网格完成引导 this.eap$delayedInitTicks = 10; // 适当增加延迟tick等待网格完成引导
// 尝试唤醒设备确保后续还能继续tick // 尝试唤醒设备确保后续还能继续tick
if (mainNode != null) { if (this.mainNode != null) {
mainNode.ifPresent((grid, node) -> { this.mainNode.ifPresent((grid, node) -> {
try { try {
grid.getTickManager().wakeDevice(node); grid.getTickManager().wakeDevice(node);
} catch (Throwable ignored) { } catch (Throwable ignored) {
@ -74,40 +70,73 @@ public abstract class InterfaceLogicChannelCardMixin implements InterfaceWireles
@Inject(method = "readFromNBT", at = @At("TAIL"), remap = false) @Inject(method = "readFromNBT", at = @At("TAIL"), remap = false)
private void eap$afterReadNBT(net.minecraft.nbt.CompoundTag tag, net.minecraft.core.HolderLookup.Provider registries, CallbackInfo ci) { private void eap$afterReadNBT(net.minecraft.nbt.CompoundTag tag, net.minecraft.core.HolderLookup.Provider registries, CallbackInfo ci) {
// NBT加载时重置标志 // NBT加载时重置标志
eap$lastChannel = -1; this.eap$lastChannel = -1;
eap$hasInitialized = false; this.eap$hasInitialized = false;
// 直接尝试初始化 // 直接尝试初始化
eap$initializeChannelLink(); this.eap$initializeChannelLink();
} }
@Inject(method = "clearContent", at = @At("HEAD"), remap = false) @Inject(method = "clearContent", at = @At("HEAD"), remap = false)
private void eap$onClearContent(CallbackInfo ci) { private void eap$onClearContent(CallbackInfo ci) {
if (eap$link != null) { if (this.eap$link != null) {
eap$link.onUnloadOrRemove(); this.eap$link.onUnloadOrRemove();
} }
} }
@Override
public void eap$updateWirelessLink() {
if (this.eap$link != null) {
this.eap$link.updateStatus();
}
}
@Override
public boolean eap$isWirelessConnected() {
// InterfaceLogic没有isClientSide方法需要通过host判断
if (this.host.getBlockEntity() != null && this.host.getBlockEntity().getLevel() != null && this.host.getBlockEntity().getLevel().isClientSide) {
return this.eap$clientConnected;
} else {
return this.eap$link != null && this.eap$link.isConnected();
}
}
@Override
public void eap$setClientWirelessState(boolean connected) {
this.eap$clientConnected = connected;
}
@Override
public boolean eap$hasTickInitialized() {
return this.eap$hasInitialized;
}
@Override
public void eap$setTickInitialized(boolean initialized) {
this.eap$hasInitialized = initialized;
}
@Override
@Unique @Unique
public void eap$initializeChannelLink() { public void eap$initializeChannelLink() {
// 仅在服务端执行避免在渲染线程/客户端触发任何初始化路径 // 仅在服务端执行避免在渲染线程/客户端触发任何初始化路径
if (host.getBlockEntity() != null && host.getBlockEntity().getLevel() != null && host.getBlockEntity().getLevel().isClientSide) { if (this.host.getBlockEntity() != null && this.host.getBlockEntity().getLevel() != null && this.host.getBlockEntity().getLevel().isClientSide) {
return; return;
} }
// 避免重复初始化 // 避免重复初始化
if (eap$hasInitialized) { if (this.eap$hasInitialized) {
return; return;
} }
// 仅要求节点对象可用不要依赖 isActive无线连接本身会建立连接与激活节点 // 仅要求节点对象可用不要依赖 isActive无线连接本身会建立连接与激活节点
if (mainNode == null || mainNode.getNode() == null) { if (this.mainNode == null || this.mainNode.getNode() == null) {
return; return;
} }
try { try {
long channel = 0L; long channel = 0L;
boolean found = false; boolean found = false;
for (ItemStack stack : getUpgrades()) { for (ItemStack stack : this.getUpgrades()) {
if (!stack.isEmpty() && stack.getItem() == ModItems.CHANNEL_CARD.get()) { if (!stack.isEmpty() && stack.getItem() == ModItems.CHANNEL_CARD.get()) {
channel = ChannelCardItem.getChannel(stack); channel = ChannelCardItem.getChannel(stack);
found = true; found = true;
@ -117,46 +146,52 @@ public abstract class InterfaceLogicChannelCardMixin implements InterfaceWireles
if (!found) { if (!found) {
// 无频道卡断开并视为初始化完成 // 无频道卡断开并视为初始化完成
if (eap$link != null) { if (this.eap$link != null) {
eap$link.setFrequency(0L); this.eap$link.setFrequency(0L);
eap$link.updateStatus(); this.eap$link.updateStatus();
} }
eap$hasInitialized = true; this.eap$hasInitialized = true;
// 保存一次状态 // 保存一次状态
try { host.saveChanges(); } catch (Throwable ignored) {} try {
this.host.saveChanges();
} catch (Throwable ignored) {
}
// 唤醒设备以刷新客户端/邻居 // 唤醒设备以刷新客户端/邻居
try { try {
mainNode.ifPresent((grid, node) -> { this.mainNode.ifPresent((grid, node) -> {
try { grid.getTickManager().wakeDevice(node); } catch (Throwable ignored2) {} try { grid.getTickManager().wakeDevice(node); } catch (Throwable ignored2) {}
}); });
} catch (Throwable ignored2) {} } catch (Throwable ignored2) {}
return; return;
} }
if (eap$link == null) { if (this.eap$link == null) {
var endpoint = new InterfaceNodeEndpointImpl(host, () -> this.mainNode.getNode()); var endpoint = new InterfaceNodeEndpointImpl(this.host, () -> this.mainNode.getNode());
eap$link = new WirelessSlaveLink(endpoint); this.eap$link = new WirelessSlaveLink(endpoint);
} }
eap$link.setFrequency(channel); this.eap$link.setFrequency(channel);
eap$link.updateStatus(); this.eap$link.updateStatus();
try { host.saveChanges(); } catch (Throwable ignored) {} try {
this.host.saveChanges();
} catch (Throwable ignored) {
}
// 唤醒设备加速后续 tick 以完成连接 // 唤醒设备加速后续 tick 以完成连接
try { try {
mainNode.ifPresent((grid, node) -> { this.mainNode.ifPresent((grid, node) -> {
try { grid.getTickManager().wakeDevice(node); } catch (Throwable ignored2) {} try { grid.getTickManager().wakeDevice(node); } catch (Throwable ignored2) {}
}); });
} catch (Throwable ignored2) {} } catch (Throwable ignored2) {}
if (eap$link.isConnected()) { if (this.eap$link.isConnected()) {
eap$hasInitialized = true; // 设置初始化完成标志 this.eap$hasInitialized = true; // 设置初始化完成标志
} else { } else {
// 不标记为完成允许后续tick重试 // 不标记为完成允许后续tick重试
eap$hasInitialized = false; this.eap$hasInitialized = false;
// 设置一个短延迟窗口避免每tick刷屏 // 设置一个短延迟窗口避免每tick刷屏
eap$delayedInitTicks = Math.max(eap$delayedInitTicks, 5); this.eap$delayedInitTicks = Math.max(this.eap$delayedInitTicks, 5);
try { try {
mainNode.ifPresent((grid, node) -> { this.mainNode.ifPresent((grid, node) -> {
try { try {
grid.getTickManager().wakeDevice(node); grid.getTickManager().wakeDevice(node);
} catch (Throwable ignored) { } catch (Throwable ignored) {
@ -169,58 +204,26 @@ public abstract class InterfaceLogicChannelCardMixin implements InterfaceWireles
} }
} }
@Override
public void eap$updateWirelessLink() {
if (eap$link != null) {
eap$link.updateStatus();
}
}
@Override
public boolean eap$isWirelessConnected() {
// InterfaceLogic没有isClientSide方法需要通过host判断
if (host.getBlockEntity() != null && host.getBlockEntity().getLevel() != null && host.getBlockEntity().getLevel().isClientSide) {
return eap$clientConnected;
} else {
return eap$link != null && eap$link.isConnected();
}
}
@Override
public void eap$setClientWirelessState(boolean connected) {
eap$clientConnected = connected;
}
@Override
public boolean eap$hasTickInitialized() {
return eap$hasInitialized;
}
@Override
public void eap$setTickInitialized(boolean initialized) {
eap$hasInitialized = initialized;
}
@Override @Override
public void eap$handleDelayedInit() { public void eap$handleDelayedInit() {
// 仅在服务端执行延迟初始化避免在渲染线程/客户端触发任何初始化路径 // 仅在服务端执行延迟初始化避免在渲染线程/客户端触发任何初始化路径
if (host.getBlockEntity() != null && host.getBlockEntity().getLevel() != null && host.getBlockEntity().getLevel().isClientSide) { if (this.host.getBlockEntity() != null && this.host.getBlockEntity().getLevel() != null && this.host.getBlockEntity().getLevel().isClientSide) {
return; return;
} }
// 若尚未初始化则持续尝试直到网格完成引导 // 若尚未初始化则持续尝试直到网格完成引导
if (!eap$hasInitialized) { if (!this.eap$hasInitialized) {
// 若节点对象尚未就绪则等待无需等待 isActive无线接入后会激活 // 若节点对象尚未就绪则等待无需等待 isActive无线接入后会激活
if (mainNode == null || mainNode.getNode() == null) { if (this.mainNode == null || this.mainNode.getNode() == null) {
// 仍在引导消耗计时器 // 仍在引导消耗计时器
if (eap$delayedInitTicks > 0) { if (this.eap$delayedInitTicks > 0) {
eap$delayedInitTicks--; this.eap$delayedInitTicks--;
} }
if (eap$delayedInitTicks == 0) { if (this.eap$delayedInitTicks == 0) {
// 重新设定一个短延迟窗口并唤醒设备以保证后续还能继续 tick // 重新设定一个短延迟窗口并唤醒设备以保证后续还能继续 tick
eap$delayedInitTicks = 5; this.eap$delayedInitTicks = 5;
try { try {
mainNode.ifPresent((grid, node) -> { this.mainNode.ifPresent((grid, node) -> {
try { try {
grid.getTickManager().wakeDevice(node); grid.getTickManager().wakeDevice(node);
} catch (Throwable ignored) { } catch (Throwable ignored) {
@ -231,7 +234,7 @@ public abstract class InterfaceLogicChannelCardMixin implements InterfaceWireles
} }
} else { } else {
// 网格已引导完成执行初始化 // 网格已引导完成执行初始化
eap$initializeChannelLink(); this.eap$initializeChannelLink();
} }
} }
} }

View File

@ -1,7 +1,7 @@
package com.extendedae_plus.mixin.ae2.helpers; package com.extendedae_plus.mixin.ae2.helpers;
import appeng.helpers.InterfaceLogic; import appeng.helpers.InterfaceLogic;
import com.extendedae_plus.bridge.InterfaceWirelessLinkBridge; import com.extendedae_plus.api.bridge.InterfaceWirelessLinkBridge;
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
@ -27,7 +27,7 @@ public abstract class InterfaceLogicTickerMixin {
if (node != null && node.getLevel() != null && node.getLevel().isClientSide) { if (node != null && node.getLevel() != null && node.getLevel().isClientSide) {
return; return;
} }
if (this$0 instanceof InterfaceWirelessLinkBridge bridge) { if (this.this$0 instanceof InterfaceWirelessLinkBridge bridge) {
bridge.eap$handleDelayedInit(); bridge.eap$handleDelayedInit();
} }
} }
@ -35,7 +35,7 @@ public abstract class InterfaceLogicTickerMixin {
@Inject(method = "tickingRequest", at = @At("TAIL"), remap = false) @Inject(method = "tickingRequest", at = @At("TAIL"), remap = false)
private void eap$tickTail(appeng.api.networking.IGridNode node, int ticksSinceLastCall, private void eap$tickTail(appeng.api.networking.IGridNode node, int ticksSinceLastCall,
CallbackInfoReturnable<appeng.api.networking.ticking.TickRateModulation> cir) { CallbackInfoReturnable<appeng.api.networking.ticking.TickRateModulation> cir) {
if (this$0 instanceof InterfaceWirelessLinkBridge bridge) { if (this.this$0 instanceof InterfaceWirelessLinkBridge bridge) {
bridge.eap$updateWirelessLink(); bridge.eap$updateWirelessLink();
} }
} }

View File

@ -5,7 +5,7 @@ import appeng.api.upgrades.IUpgradeInventory;
import appeng.api.upgrades.UpgradeInventories; import appeng.api.upgrades.UpgradeInventories;
import appeng.helpers.InterfaceLogic; import appeng.helpers.InterfaceLogic;
import appeng.helpers.InterfaceLogicHost; import appeng.helpers.InterfaceLogicHost;
import com.extendedae_plus.bridge.CompatUpgradeProvider; import com.extendedae_plus.api.bridge.CompatUpgradeProvider;
import com.extendedae_plus.compat.UpgradeSlotCompat; import com.extendedae_plus.compat.UpgradeSlotCompat;
import com.extendedae_plus.util.ExtendedAELogger; import com.extendedae_plus.util.ExtendedAELogger;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;

View File

@ -6,7 +6,7 @@ import appeng.api.stacks.AEKey;
import appeng.api.stacks.GenericStack; import appeng.api.stacks.GenericStack;
import appeng.helpers.patternprovider.PatternProviderLogic; import appeng.helpers.patternprovider.PatternProviderLogic;
import appeng.helpers.patternprovider.PatternProviderTarget; import appeng.helpers.patternprovider.PatternProviderTarget;
import com.extendedae_plus.api.AdvancedBlockingHolder; import com.extendedae_plus.api.advancedBlocking.IAdvancedBlocking;
import com.extendedae_plus.api.ids.EAPComponents; import com.extendedae_plus.api.ids.EAPComponents;
import net.minecraft.core.HolderLookup; import net.minecraft.core.HolderLookup;
import net.minecraft.core.component.DataComponentMap; import net.minecraft.core.component.DataComponentMap;
@ -23,7 +23,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.Collections; import java.util.Collections;
@Mixin(value = PatternProviderLogic.class, remap = false) @Mixin(value = PatternProviderLogic.class, remap = false)
public class PatternProviderLogicAdvancedMixin implements AdvancedBlockingHolder { public class PatternProviderLogicAdvancedMixin implements IAdvancedBlocking {
@Unique @Unique
private static final String EAP_ADV_BLOCKING_KEY = "epp_advanced_blocking"; private static final String EAP_ADV_BLOCKING_KEY = "epp_advanced_blocking";
@ -32,7 +32,7 @@ public class PatternProviderLogicAdvancedMixin implements AdvancedBlockingHolder
@Override @Override
public boolean eap$getAdvancedBlocking() { public boolean eap$getAdvancedBlocking() {
return eap$advancedBlocking; return this.eap$advancedBlocking;
} }
@Override @Override
@ -66,7 +66,7 @@ public class PatternProviderLogicAdvancedMixin implements AdvancedBlockingHolder
// 仅当高级阻挡启用时启用匹配则不阻挡 // 仅当高级阻挡启用时启用匹配则不阻挡
if (this.eap$advancedBlocking) { if (this.eap$advancedBlocking) {
if (eap$targetFullyMatchesPatternInputs(adapter, patternDetails)) { if (this.eap$targetFullyMatchesPatternInputs(adapter, patternDetails)) {
// 返回 false 表示不包含阻挡关键物从而不触发 continue允许发配 // 返回 false 表示不包含阻挡关键物从而不触发 continue允许发配
return false; return false;
} }

View File

@ -3,9 +3,9 @@ package com.extendedae_plus.mixin.ae2.helpers;
import appeng.api.crafting.IPatternDetails; import appeng.api.crafting.IPatternDetails;
import appeng.crafting.pattern.AEProcessingPattern; import appeng.crafting.pattern.AEProcessingPattern;
import appeng.helpers.patternprovider.PatternProviderLogic; import appeng.helpers.patternprovider.PatternProviderLogic;
import com.extendedae_plus.api.SmartDoublingAwarePattern;
import com.extendedae_plus.api.SmartDoublingHolder;
import com.extendedae_plus.api.ids.EAPComponents; import com.extendedae_plus.api.ids.EAPComponents;
import com.extendedae_plus.api.smartDoubling.ISmartDoubling;
import com.extendedae_plus.api.smartDoubling.ISmartDoublingAwarePattern;
import com.extendedae_plus.mixin.ae2.accessor.PatternProviderLogicPatternsAccessor; import com.extendedae_plus.mixin.ae2.accessor.PatternProviderLogicPatternsAccessor;
import net.minecraft.core.component.DataComponentMap; import net.minecraft.core.component.DataComponentMap;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
@ -18,7 +18,7 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(value = PatternProviderLogic.class, remap = false) @Mixin(value = PatternProviderLogic.class, remap = false)
public class PatternProviderLogicDoublingMixin implements SmartDoublingHolder { public class PatternProviderLogicDoublingMixin implements ISmartDoubling {
@Unique @Unique
private static final String EAP_SMART_DOUBLING_KEY = "epp_smart_doubling"; private static final String EAP_SMART_DOUBLING_KEY = "epp_smart_doubling";
@ -27,7 +27,7 @@ public class PatternProviderLogicDoublingMixin implements SmartDoublingHolder {
@Override @Override
public boolean eap$getSmartDoubling() { public boolean eap$getSmartDoubling() {
return eap$smartDoubling; return this.eap$smartDoubling;
} }
@Override @Override
@ -37,7 +37,7 @@ public class PatternProviderLogicDoublingMixin implements SmartDoublingHolder {
try { try {
var list = ((PatternProviderLogicPatternsAccessor) this).eap$patterns(); var list = ((PatternProviderLogicPatternsAccessor) this).eap$patterns();
for (IPatternDetails details : list) { for (IPatternDetails details : list) {
if (details instanceof AEProcessingPattern proc && proc instanceof SmartDoublingAwarePattern aware) { if (details instanceof AEProcessingPattern proc && proc instanceof ISmartDoublingAwarePattern aware) {
aware.eap$setAllowScaling(value); aware.eap$setAllowScaling(value);
} }
} }
@ -65,7 +65,7 @@ public class PatternProviderLogicDoublingMixin implements SmartDoublingHolder {
var list = ((PatternProviderLogicPatternsAccessor) this).eap$patterns(); var list = ((PatternProviderLogicPatternsAccessor) this).eap$patterns();
boolean allow = this.eap$smartDoubling; boolean allow = this.eap$smartDoubling;
for (IPatternDetails details : list) { for (IPatternDetails details : list) {
if (details instanceof AEProcessingPattern proc && proc instanceof SmartDoublingAwarePattern aware) { if (details instanceof AEProcessingPattern proc && proc instanceof ISmartDoublingAwarePattern aware) {
aware.eap$setAllowScaling(allow); aware.eap$setAllowScaling(allow);
} }
} }

View File

@ -1,7 +1,7 @@
package com.extendedae_plus.mixin.ae2.helpers.patternprovider; package com.extendedae_plus.mixin.ae2.helpers.patternprovider;
import appeng.helpers.patternprovider.PatternProviderLogic; import appeng.helpers.patternprovider.PatternProviderLogic;
import com.extendedae_plus.bridge.InterfaceWirelessLinkBridge; import com.extendedae_plus.api.bridge.InterfaceWirelessLinkBridge;
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
@ -27,7 +27,7 @@ public abstract class PatternProviderLogicTickerMixin {
if (node != null && node.getLevel() != null && node.getLevel().isClientSide) { if (node != null && node.getLevel() != null && node.getLevel().isClientSide) {
return; return;
} }
if (this$0 instanceof InterfaceWirelessLinkBridge bridge) { if (this.this$0 instanceof InterfaceWirelessLinkBridge bridge) {
bridge.eap$handleDelayedInit(); bridge.eap$handleDelayedInit();
} }
} }
@ -39,7 +39,7 @@ public abstract class PatternProviderLogicTickerMixin {
if (node != null && node.getLevel() != null && node.getLevel().isClientSide) { if (node != null && node.getLevel() != null && node.getLevel().isClientSide) {
return; return;
} }
if (this$0 instanceof InterfaceWirelessLinkBridge bridge) { if (this.this$0 instanceof InterfaceWirelessLinkBridge bridge) {
bridge.eap$updateWirelessLink(); bridge.eap$updateWirelessLink();
if (bridge.eap$shouldKeepTicking()) { if (bridge.eap$shouldKeepTicking()) {
cir.setReturnValue(appeng.api.networking.ticking.TickRateModulation.SLOWER); cir.setReturnValue(appeng.api.networking.ticking.TickRateModulation.SLOWER);

View File

@ -4,15 +4,15 @@ import appeng.api.crafting.PatternDetailsHelper;
import appeng.menu.me.items.PatternEncodingTermMenu; import appeng.menu.me.items.PatternEncodingTermMenu;
import appeng.menu.slot.RestrictedInputSlot; import appeng.menu.slot.RestrictedInputSlot;
import appeng.parts.encoding.EncodingMode; import appeng.parts.encoding.EncodingMode;
import com.extendedae_plus.util.ExtendedAEPatternUploadUtil; import com.extendedae_plus.util.uploadPattern.ExtendedAEPatternUploadUtil;
import com.glodblock.github.glodium.network.packet.sync.ActionMap; import com.glodblock.github.glodium.network.packet.sync.ActionMap;
import com.glodblock.github.glodium.network.packet.sync.IActionHolder; import com.glodblock.github.glodium.network.packet.sync.IActionHolder;
import net.minecraft.core.component.DataComponents;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import org.jetbrains.annotations.NotNull;
import net.minecraft.core.component.DataComponents;
import net.minecraft.world.item.component.CustomData; import net.minecraft.world.item.component.CustomData;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.Unique;
@ -21,9 +21,6 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.Map;
import java.util.function.Consumer;
/** /**
* AE2 PatternEncodingTermMenu 增加一个通用动作持有者实现接收 EPP CGenericPacket 动作 * AE2 PatternEncodingTermMenu 增加一个通用动作持有者实现接收 EPP CGenericPacket 动作
* 注册动作 "upload_to_matrix"仅上传合成图样 ExtendedAE 装配矩阵 * 注册动作 "upload_to_matrix"仅上传合成图样 ExtendedAE 装配矩阵
@ -53,7 +50,7 @@ public abstract class ContainerPatternEncodingTermMenuMixin implements IActionHo
} else { } else {
// 槽位可能尚未同步到位继续下一 tick 重试 // 槽位可能尚未同步到位继续下一 tick 重试
if (attemptsLeft > 0) { if (attemptsLeft > 0) {
eap$scheduleUploadWithRetry(sp, menu, attemptsLeft - 1); this.eap$scheduleUploadWithRetry(sp, menu, attemptsLeft - 1);
} }
} }
} catch (Throwable ignored) { } catch (Throwable ignored) {

View File

@ -4,7 +4,7 @@ import appeng.helpers.InterfaceLogicHost;
import appeng.menu.AEBaseMenu; import appeng.menu.AEBaseMenu;
import appeng.menu.ToolboxMenu; import appeng.menu.ToolboxMenu;
import appeng.menu.implementations.InterfaceMenu; import appeng.menu.implementations.InterfaceMenu;
import com.extendedae_plus.bridge.IUpgradableMenu; import com.extendedae_plus.api.bridge.IUpgradableMenu;
import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.inventory.MenuType; import net.minecraft.world.inventory.MenuType;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
@ -22,6 +22,10 @@ public abstract class InterfaceMenuUpgradesMixin extends AEBaseMenu implements I
@Unique @Unique
private ToolboxMenu eap$toolbox; private ToolboxMenu eap$toolbox;
public InterfaceMenuUpgradesMixin(MenuType<?> menuType, int id, Inventory playerInventory, Object host) {
super(menuType, id, playerInventory, host);
}
@Inject(method = "<init>(Lnet/minecraft/world/inventory/MenuType;ILnet/minecraft/world/entity/player/Inventory;Lappeng/helpers/InterfaceLogicHost;)V", @Inject(method = "<init>(Lnet/minecraft/world/inventory/MenuType;ILnet/minecraft/world/entity/player/Inventory;Lappeng/helpers/InterfaceLogicHost;)V",
at = @At("TAIL")) at = @At("TAIL"))
private void eap$initUpgrades(MenuType<?> menuType, int id, Inventory playerInventory, InterfaceLogicHost host, CallbackInfo ci) { private void eap$initUpgrades(MenuType<?> menuType, int id, Inventory playerInventory, InterfaceLogicHost host, CallbackInfo ci) {
@ -34,8 +38,4 @@ public abstract class InterfaceMenuUpgradesMixin extends AEBaseMenu implements I
public ToolboxMenu eap$getToolbox() { public ToolboxMenu eap$getToolbox() {
return this.eap$toolbox; return this.eap$toolbox;
} }
public InterfaceMenuUpgradesMixin(MenuType<?> menuType, int id, Inventory playerInventory, Object host) {
super(menuType, id, playerInventory, host);
}
} }

View File

@ -4,8 +4,8 @@ import appeng.helpers.patternprovider.PatternProviderLogic;
import appeng.menu.AEBaseMenu; import appeng.menu.AEBaseMenu;
import appeng.menu.guisync.GuiSync; import appeng.menu.guisync.GuiSync;
import appeng.menu.implementations.PatternProviderMenu; import appeng.menu.implementations.PatternProviderMenu;
import com.extendedae_plus.api.AdvancedBlockingHolder; import com.extendedae_plus.api.advancedBlocking.IAdvancedBlocking;
import com.extendedae_plus.api.PatternProviderMenuAdvancedSync; import com.extendedae_plus.api.advancedBlocking.IPatternProviderMenuAdvancedSync;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.Unique;
@ -15,21 +15,20 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(PatternProviderMenu.class) @Mixin(PatternProviderMenu.class)
public abstract class PatternProviderMenuAdvancedMixin implements PatternProviderMenuAdvancedSync { public abstract class PatternProviderMenuAdvancedMixin implements IPatternProviderMenuAdvancedSync {
@Shadow @Shadow
protected PatternProviderLogic logic; protected PatternProviderLogic logic;
// 选择一个未占用的 GUI 同步 idAE2 已用到 7这里使用 20 以避冲突 // 选择一个未占用的 GUI 同步 idAE2 已用到 7这里使用 20 以避冲突
@Unique @Unique
@GuiSync(20) @GuiSync(20) private boolean eap$AdvancedBlocking = false;
public boolean eap$AdvancedBlocking = false;
@Inject(method = "broadcastChanges", at = @At("HEAD")) @Inject(method = "broadcastChanges", at = @At("HEAD"))
private void eap$syncAdvancedBlocking(CallbackInfo ci) { private void eap$syncAdvancedBlocking(CallbackInfo ci) {
// 避免@Shadow父类方法改用公共APIAEBaseMenu#isClientSide() // 避免@Shadow父类方法改用公共APIAEBaseMenu#isClientSide()
if (!((AEBaseMenu) (Object) this).isClientSide()) { if (!((AEBaseMenu) (Object) this).isClientSide()) {
var l = this.logic; var l = this.logic;
if (l instanceof AdvancedBlockingHolder holder) { if (l instanceof IAdvancedBlocking holder) {
this.eap$AdvancedBlocking = holder.eap$getAdvancedBlocking(); this.eap$AdvancedBlocking = holder.eap$getAdvancedBlocking();
// debug removed // debug removed
} }

View File

@ -4,8 +4,8 @@ import appeng.helpers.patternprovider.PatternProviderLogic;
import appeng.menu.AEBaseMenu; import appeng.menu.AEBaseMenu;
import appeng.menu.guisync.GuiSync; import appeng.menu.guisync.GuiSync;
import appeng.menu.implementations.PatternProviderMenu; import appeng.menu.implementations.PatternProviderMenu;
import com.extendedae_plus.api.PatternProviderMenuDoublingSync; import com.extendedae_plus.api.smartDoubling.IPatternProviderMenuDoublingSync;
import com.extendedae_plus.api.SmartDoublingHolder; import com.extendedae_plus.api.smartDoubling.ISmartDoubling;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.Unique;
@ -14,19 +14,18 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(PatternProviderMenu.class) @Mixin(PatternProviderMenu.class)
public abstract class PatternProviderMenuDoublingMixin implements PatternProviderMenuDoublingSync { public abstract class PatternProviderMenuDoublingMixin implements IPatternProviderMenuDoublingSync {
@Shadow @Shadow
protected PatternProviderLogic logic; protected PatternProviderLogic logic;
@Unique @Unique
@GuiSync(21) @GuiSync(21) private boolean eap$SmartDoubling = false;
public boolean eap$SmartDoubling = false;
@Inject(method = "broadcastChanges", at = @At("HEAD")) @Inject(method = "broadcastChanges", at = @At("HEAD"))
private void eap$syncSmartDoubling(CallbackInfo ci) { private void eap$syncSmartDoubling(CallbackInfo ci) {
if (!((AEBaseMenu) (Object) this).isClientSide()) { if (!((AEBaseMenu) (Object) this).isClientSide()) {
var l = this.logic; var l = this.logic;
if (l instanceof SmartDoublingHolder holder) { if (l instanceof ISmartDoubling holder) {
this.eap$SmartDoubling = holder.eap$getSmartDoubling(); this.eap$SmartDoubling = holder.eap$getSmartDoubling();
// debug removed // debug removed
} }

View File

@ -5,8 +5,8 @@ import appeng.helpers.patternprovider.PatternProviderLogicHost;
import appeng.menu.AEBaseMenu; import appeng.menu.AEBaseMenu;
import appeng.menu.ToolboxMenu; import appeng.menu.ToolboxMenu;
import appeng.menu.implementations.PatternProviderMenu; import appeng.menu.implementations.PatternProviderMenu;
import com.extendedae_plus.bridge.CompatUpgradeProvider; import com.extendedae_plus.api.bridge.CompatUpgradeProvider;
import com.extendedae_plus.bridge.IUpgradableMenu; import com.extendedae_plus.api.bridge.IUpgradableMenu;
import com.extendedae_plus.compat.UpgradeSlotCompat; import com.extendedae_plus.compat.UpgradeSlotCompat;
import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.inventory.MenuType; import net.minecraft.world.inventory.MenuType;
@ -26,6 +26,10 @@ public abstract class PatternProviderMenuUpgradesMixin extends AEBaseMenu implem
@Unique @Unique
private ToolboxMenu eap$toolbox; private ToolboxMenu eap$toolbox;
public PatternProviderMenuUpgradesMixin(MenuType<?> menuType, int id, Inventory playerInventory, Object host) {
super(menuType, id, playerInventory, host);
}
@Inject(method = "<init>(Lnet/minecraft/world/inventory/MenuType;ILnet/minecraft/world/entity/player/Inventory;Lappeng/helpers/patternprovider/PatternProviderLogicHost;)V", @Inject(method = "<init>(Lnet/minecraft/world/inventory/MenuType;ILnet/minecraft/world/entity/player/Inventory;Lappeng/helpers/patternprovider/PatternProviderLogicHost;)V",
at = @At("TAIL")) at = @At("TAIL"))
private void eap$initUpgrades(MenuType<?> menuType, int id, Inventory playerInventory, PatternProviderLogicHost host, CallbackInfo ci) { private void eap$initUpgrades(MenuType<?> menuType, int id, Inventory playerInventory, PatternProviderLogicHost host, CallbackInfo ci) {
@ -42,8 +46,4 @@ public abstract class PatternProviderMenuUpgradesMixin extends AEBaseMenu implem
public ToolboxMenu eap$getToolbox() { public ToolboxMenu eap$getToolbox() {
return this.eap$toolbox; return this.eap$toolbox;
} }
public PatternProviderMenuUpgradesMixin(MenuType<?> menuType, int id, Inventory playerInventory, Object host) {
super(menuType, id, playerInventory, host);
}
} }

View File

@ -4,12 +4,12 @@ import appeng.api.networking.security.IActionHost;
import appeng.api.upgrades.IUpgradeInventory; import appeng.api.upgrades.IUpgradeInventory;
import appeng.api.upgrades.IUpgradeableObject; import appeng.api.upgrades.IUpgradeableObject;
import appeng.parts.automation.IOBusPart; import appeng.parts.automation.IOBusPart;
import com.extendedae_plus.ae.items.ChannelCardItem; import com.extendedae_plus.ae.wireless.WirelessSlaveLink;
import com.extendedae_plus.bridge.InterfaceWirelessLinkBridge; import com.extendedae_plus.ae.wireless.endpoint.GenericNodeEndpointImpl;
import com.extendedae_plus.api.bridge.InterfaceWirelessLinkBridge;
import com.extendedae_plus.init.ModItems; import com.extendedae_plus.init.ModItems;
import com.extendedae_plus.items.materials.ChannelCardItem;
import com.extendedae_plus.util.ExtendedAELogger; import com.extendedae_plus.util.ExtendedAELogger;
import com.extendedae_plus.wireless.WirelessSlaveLink;
import com.extendedae_plus.wireless.endpoint.GenericNodeEndpointImpl;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.Unique;
@ -39,16 +39,16 @@ public abstract class IOBusPartChannelCardMixin implements InterfaceWirelessLink
private void eap$onUpgradesChanged(CallbackInfo ci) { private void eap$onUpgradesChanged(CallbackInfo ci) {
// 只在服务端初始化频道链接 // 只在服务端初始化频道链接
if (!((appeng.parts.AEBasePart)(Object)this).isClientSide()) { if (!((appeng.parts.AEBasePart)(Object)this).isClientSide()) {
eap$initializeChannelLink(); this.eap$initializeChannelLink();
} }
} }
@Inject(method = "tickingRequest", at = @At("HEAD")) @Inject(method = "tickingRequest", at = @At("HEAD"))
private void eap$beforeTick(appeng.api.networking.IGridNode node, int ticksSinceLastCall, org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable<appeng.api.networking.ticking.TickRateModulation> cir) { private void eap$beforeTick(appeng.api.networking.IGridNode node, int ticksSinceLastCall, org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable<appeng.api.networking.ticking.TickRateModulation> cir) {
// 在第一次tick时初始化频道链接此时网格节点已经在线 // 在第一次tick时初始化频道链接此时网格节点已经在线
if (!eap$hasTickInitialized && !((appeng.parts.AEBasePart)(Object)this).isClientSide()) { if (!this.eap$hasTickInitialized && !((appeng.parts.AEBasePart) (Object) this).isClientSide()) {
eap$hasTickInitialized = true; this.eap$hasTickInitialized = true;
eap$initializeChannelLink(); this.eap$initializeChannelLink();
} }
} }
@ -56,11 +56,33 @@ public abstract class IOBusPartChannelCardMixin implements InterfaceWirelessLink
private void eap$afterReadFromNBT(CompoundTag extra, net.minecraft.core.HolderLookup.Provider registries, CallbackInfo ci) { private void eap$afterReadFromNBT(CompoundTag extra, net.minecraft.core.HolderLookup.Provider registries, CallbackInfo ci) {
// 从NBT加载时重置频道缓存和tick初始化标志 // 从NBT加载时重置频道缓存和tick初始化标志
if (!((appeng.parts.AEBasePart)(Object)this).isClientSide()) { if (!((appeng.parts.AEBasePart)(Object)this).isClientSide()) {
eap$lastChannel = -1; this.eap$lastChannel = -1;
eap$hasTickInitialized = false; // 重置标志允许再次初始化 this.eap$hasTickInitialized = false; // 重置标志允许再次初始化
} }
} }
@Override
public void eap$updateWirelessLink() {
if (this.eap$link != null) {
this.eap$link.updateStatus();
}
}
@Override
public boolean eap$isWirelessConnected() {
if (((appeng.parts.AEBasePart) (Object) this).isClientSide()) {
return this.eap$clientConnected;
} else {
return this.eap$link != null && this.eap$link.isConnected();
}
}
@Override
public void eap$setClientWirelessState(boolean connected) {
this.eap$clientConnected = connected;
}
@Override
@Unique @Unique
public void eap$initializeChannelLink() { public void eap$initializeChannelLink() {
// 防止重复调用 // 防止重复调用
@ -81,33 +103,33 @@ public abstract class IOBusPartChannelCardMixin implements InterfaceWirelessLink
} }
// 频道没有变化则跳过 // 频道没有变化则跳过
if (eap$lastChannel == channel) { if (this.eap$lastChannel == channel) {
return; return;
} }
eap$lastChannel = channel; this.eap$lastChannel = channel;
if (!found) { if (!found) {
// 无频道卡则断开 // 无频道卡则断开
if (eap$link != null) { if (this.eap$link != null) {
eap$link.setFrequency(0L); this.eap$link.setFrequency(0L);
eap$link.updateStatus(); this.eap$link.updateStatus();
// 立即通知客户端状态变化断开连接无需延迟 // 立即通知客户端状态变化断开连接无需延迟
((appeng.parts.AEBasePart)(Object)this).getHost().markForUpdate(); ((appeng.parts.AEBasePart)(Object)this).getHost().markForUpdate();
} }
return; return;
} }
if (eap$link == null) { if (this.eap$link == null) {
var endpoint = new GenericNodeEndpointImpl( var endpoint = new GenericNodeEndpointImpl(
() -> ((appeng.parts.AEBasePart)(Object)this).getHost().getBlockEntity(), () -> ((appeng.parts.AEBasePart)(Object)this).getHost().getBlockEntity(),
() -> ((IActionHost)(Object)this).getActionableNode() () -> ((IActionHost)(Object)this).getActionableNode()
); );
eap$link = new WirelessSlaveLink(endpoint); this.eap$link = new WirelessSlaveLink(endpoint);
} }
eap$link.setFrequency(channel); this.eap$link.setFrequency(channel);
eap$link.updateStatus(); this.eap$link.updateStatus();
// 通知客户端状态变化 // 通知客户端状态变化
((appeng.parts.AEBasePart)(Object)this).getHost().markForUpdate(); ((appeng.parts.AEBasePart)(Object)this).getHost().markForUpdate();
@ -115,25 +137,4 @@ public abstract class IOBusPartChannelCardMixin implements InterfaceWirelessLink
ExtendedAELogger.LOGGER.error("[服务端] IOBus 初始化频道链接失败", e); ExtendedAELogger.LOGGER.error("[服务端] IOBus 初始化频道链接失败", e);
} }
} }
@Override
public void eap$updateWirelessLink() {
if (eap$link != null) {
eap$link.updateStatus();
}
}
@Override
public boolean eap$isWirelessConnected() {
if (((appeng.parts.AEBasePart)(Object)this).isClientSide()) {
return eap$clientConnected;
} else {
return eap$link != null && eap$link.isConnected();
}
}
@Override
public void eap$setClientWirelessState(boolean connected) {
eap$clientConnected = connected;
}
} }

View File

@ -5,12 +5,12 @@ import appeng.api.networking.security.IActionHost;
import appeng.api.upgrades.IUpgradeInventory; import appeng.api.upgrades.IUpgradeInventory;
import appeng.api.upgrades.IUpgradeableObject; import appeng.api.upgrades.IUpgradeableObject;
import appeng.parts.storagebus.StorageBusPart; import appeng.parts.storagebus.StorageBusPart;
import com.extendedae_plus.ae.items.ChannelCardItem; import com.extendedae_plus.ae.wireless.WirelessSlaveLink;
import com.extendedae_plus.bridge.InterfaceWirelessLinkBridge; import com.extendedae_plus.ae.wireless.endpoint.GenericNodeEndpointImpl;
import com.extendedae_plus.api.bridge.InterfaceWirelessLinkBridge;
import com.extendedae_plus.init.ModItems; import com.extendedae_plus.init.ModItems;
import com.extendedae_plus.items.materials.ChannelCardItem;
import com.extendedae_plus.util.ExtendedAELogger; import com.extendedae_plus.util.ExtendedAELogger;
import com.extendedae_plus.wireless.WirelessSlaveLink;
import com.extendedae_plus.wireless.endpoint.GenericNodeEndpointImpl;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.Unique;
@ -37,7 +37,7 @@ public abstract class StorageBusPartChannelCardMixin implements InterfaceWireles
private void eap$onUpgradesChanged(CallbackInfo ci) { private void eap$onUpgradesChanged(CallbackInfo ci) {
// 只在服务端初始化频道链接 // 只在服务端初始化频道链接
if (!((appeng.parts.AEBasePart)(Object)this).isClientSide()) { if (!((appeng.parts.AEBasePart)(Object)this).isClientSide()) {
eap$initializeChannelLink(); this.eap$initializeChannelLink();
} }
} }
@ -45,7 +45,7 @@ public abstract class StorageBusPartChannelCardMixin implements InterfaceWireles
private void eap$onMainNodeStateChanged(IGridNodeListener.State reason, CallbackInfo ci) { private void eap$onMainNodeStateChanged(IGridNodeListener.State reason, CallbackInfo ci) {
// 在节点状态变化时包括加载后的GRID_BOOT重新初始化频道链接 // 在节点状态变化时包括加载后的GRID_BOOT重新初始化频道链接
if (reason == IGridNodeListener.State.GRID_BOOT && !((appeng.parts.AEBasePart)(Object)this).isClientSide()) { if (reason == IGridNodeListener.State.GRID_BOOT && !((appeng.parts.AEBasePart)(Object)this).isClientSide()) {
eap$initializeChannelLink(); this.eap$initializeChannelLink();
} }
} }
@ -54,11 +54,33 @@ public abstract class StorageBusPartChannelCardMixin implements InterfaceWireles
// 从NBT加载后也重新初始化频道链接只在服务端 // 从NBT加载后也重新初始化频道链接只在服务端
if (!((appeng.parts.AEBasePart)(Object)this).isClientSide()) { if (!((appeng.parts.AEBasePart)(Object)this).isClientSide()) {
// 从NBT加载时重置频道缓存强制重新初始化 // 从NBT加载时重置频道缓存强制重新初始化
eap$lastChannel = -1; this.eap$lastChannel = -1;
eap$initializeChannelLink(); this.eap$initializeChannelLink();
} }
} }
@Override
public void eap$updateWirelessLink() {
if (this.eap$link != null) {
this.eap$link.updateStatus();
}
}
@Override
public boolean eap$isWirelessConnected() {
if (((appeng.parts.AEBasePart) (Object) this).isClientSide()) {
return this.eap$clientConnected;
} else {
return this.eap$link != null && this.eap$link.isConnected();
}
}
@Override
public void eap$setClientWirelessState(boolean connected) {
this.eap$clientConnected = connected;
}
@Override
@Unique @Unique
public void eap$initializeChannelLink() { public void eap$initializeChannelLink() {
// 防止重复调用 // 防止重复调用
@ -79,32 +101,32 @@ public abstract class StorageBusPartChannelCardMixin implements InterfaceWireles
} }
// 频道没有变化则跳过 // 频道没有变化则跳过
if (eap$lastChannel == channel) { if (this.eap$lastChannel == channel) {
return; return;
} }
eap$lastChannel = channel; this.eap$lastChannel = channel;
if (!found) { if (!found) {
if (eap$link != null) { if (this.eap$link != null) {
eap$link.setFrequency(0L); this.eap$link.setFrequency(0L);
eap$link.updateStatus(); this.eap$link.updateStatus();
// 通知客户端状态变化 // 通知客户端状态变化
((appeng.parts.AEBasePart)(Object)this).getHost().markForUpdate(); ((appeng.parts.AEBasePart)(Object)this).getHost().markForUpdate();
} }
return; return;
} }
if (eap$link == null) { if (this.eap$link == null) {
var endpoint = new GenericNodeEndpointImpl( var endpoint = new GenericNodeEndpointImpl(
() -> ((appeng.parts.AEBasePart)(Object)this).getHost().getBlockEntity(), () -> ((appeng.parts.AEBasePart)(Object)this).getHost().getBlockEntity(),
() -> ((IActionHost)(Object)this).getActionableNode() () -> ((IActionHost)(Object)this).getActionableNode()
); );
eap$link = new WirelessSlaveLink(endpoint); this.eap$link = new WirelessSlaveLink(endpoint);
} }
eap$link.setFrequency(channel); this.eap$link.setFrequency(channel);
eap$link.updateStatus(); this.eap$link.updateStatus();
// 通知客户端状态变化 // 通知客户端状态变化
((appeng.parts.AEBasePart)(Object)this).getHost().markForUpdate(); ((appeng.parts.AEBasePart)(Object)this).getHost().markForUpdate();
@ -112,25 +134,4 @@ public abstract class StorageBusPartChannelCardMixin implements InterfaceWireles
ExtendedAELogger.LOGGER.error("[服务端] StorageBus 初始化频道链接失败", e); ExtendedAELogger.LOGGER.error("[服务端] StorageBus 初始化频道链接失败", e);
} }
} }
@Override
public void eap$updateWirelessLink() {
if (eap$link != null) {
eap$link.updateStatus();
}
}
@Override
public boolean eap$isWirelessConnected() {
if (((appeng.parts.AEBasePart)(Object)this).isClientSide()) {
return eap$clientConnected;
} else {
return eap$link != null && eap$link.isConnected();
}
}
@Override
public void eap$setClientWirelessState(boolean connected) {
eap$clientConnected = connected;
}
} }

View File

@ -5,8 +5,9 @@ import appeng.client.gui.implementations.PatternProviderScreen;
import appeng.client.gui.style.ScreenStyle; import appeng.client.gui.style.ScreenStyle;
import appeng.menu.SlotSemantics; import appeng.menu.SlotSemantics;
import appeng.menu.slot.AppEngSlot; import appeng.menu.slot.AppEngSlot;
import com.extendedae_plus.NewIcon; import com.extendedae_plus.api.IExPatternButton;
import com.extendedae_plus.api.ExPatternButtonsAccessor; import com.extendedae_plus.api.IExPatternPage;
import com.extendedae_plus.client.gui.NewIcon;
import com.extendedae_plus.config.ModConfigs; import com.extendedae_plus.config.ModConfigs;
import com.extendedae_plus.network.ScalePatternsC2SPacket; import com.extendedae_plus.network.ScalePatternsC2SPacket;
import com.glodblock.github.extendedae.client.button.ActionEPPButton; import com.glodblock.github.extendedae.client.button.ActionEPPButton;
@ -27,38 +28,63 @@ import java.lang.reflect.Method;
import static com.extendedae_plus.util.ExtendedAELogger.LOGGER; import static com.extendedae_plus.util.ExtendedAELogger.LOGGER;
@Mixin(value = GuiExPatternProvider.class, remap = false) @Mixin(value = GuiExPatternProvider.class, remap = false)
public abstract class GuiExPatternProviderMixin extends PatternProviderScreen<ContainerExPatternProvider> implements ExPatternButtonsAccessor, com.extendedae_plus.api.ExPatternPageAccessor { public abstract class GuiExPatternProviderMixin extends PatternProviderScreen<ContainerExPatternProvider> implements IExPatternButton, IExPatternPage {
@Unique
ScreenStyle eap$screenStyle;
// 跟踪上次屏幕尺寸处理 GUI 缩放/窗口大小变化后按钮丢失问题
@Unique private int eap$lastScreenWidth = -1;
@Unique private int eap$lastScreenHeight = -1;
// 不再使用右侧 VerticalButtonBar直接把按钮注册为独立 AE2 小部件
@Unique @Unique
private static final int SLOTS_PER_PAGE = 36; // 每页显示36个槽位 private static final int SLOTS_PER_PAGE = 36; // 每页显示36个槽位
@Unique private
ScreenStyle eap$screenStyle;
// 跟踪上次屏幕尺寸处理 GUI 缩放/窗口大小变化后按钮丢失问题
@Unique private int eap$lastScreenWidth = -1;
// 不再使用右侧 VerticalButtonBar直接把按钮注册为独立 AE2 小部件
@Unique private int eap$lastScreenHeight = -1;
@Unique @Unique
private int eap$currentPage = 0; private int eap$currentPage = 0;
@Unique @Unique
private int eap$maxPageLocal = 1; private int eap$maxPageLocal = 1;
private ActionEPPButton nextPage;
public GuiExPatternProviderMixin(ContainerExPatternProvider menu, Inventory playerInventory, Component title, ScreenStyle style) {
super(menu, playerInventory, title, style);
}
// 移除手动挪动 Slot 坐标交由 SlotGridLayout + 原生布局控制 // 移除手动挪动 Slot 坐标交由 SlotGridLayout + 原生布局控制
private ActionEPPButton prevPage;
private ActionEPPButton x2Button;
private ActionEPPButton divideBy2Button;
private ActionEPPButton x5Button;
private ActionEPPButton divideBy5Button;
private ActionEPPButton x10Button;
private ActionEPPButton divideBy10Button;
public GuiExPatternProviderMixin(ContainerExPatternProvider menu, Inventory playerInventory, Component title, ScreenStyle style) {
super(menu, playerInventory, title, style);
}
@Unique
private static Field eap$findFieldRecursive(Class<?> cls, String name) {
Class<?> c = cls;
while (c != null && c != Object.class) {
try {
return c.getDeclaredField(name);
} catch (NoSuchFieldException ignored) {}
c = c.getSuperclass();
}
return null;
}
@Unique
private static void eap$setIntFieldRecursive(Object obj, String name, int value) {
if (obj == null) return;
Field f = eap$findFieldRecursive(obj.getClass(), name);
if (f != null) {
try { f.setAccessible(true); f.set(obj, value); } catch (Throwable ignored) {}
}
}
@Unique @Unique
private int getCurrentPage() { private int getCurrentPage() {
// 优先使用本地 GUI 维护的页码 // 优先使用本地 GUI 维护的页码
return Math.max(0, eap$currentPage % Math.max(1, eap$maxPageLocal)); return Math.max(0, this.eap$currentPage % Math.max(1, this.eap$maxPageLocal));
} }
@Unique @Unique
@ -85,36 +111,6 @@ public abstract class GuiExPatternProviderMixin extends PatternProviderScreen<Co
return 1; return 1;
} }
@Unique
private static Field eap$findFieldRecursive(Class<?> cls, String name) {
Class<?> c = cls;
while (c != null && c != Object.class) {
try {
return c.getDeclaredField(name);
} catch (NoSuchFieldException ignored) {}
c = c.getSuperclass();
}
return null;
}
@Unique
private static void eap$setIntFieldRecursive(Object obj, String name, int value) {
if (obj == null) return;
Field f = eap$findFieldRecursive(obj.getClass(), name);
if (f != null) {
try { f.setAccessible(true); f.set(obj, value); } catch (Throwable ignored) {}
}
}
public ActionEPPButton nextPage;
public ActionEPPButton prevPage;
public ActionEPPButton x2Button;
public ActionEPPButton divideBy2Button;
public ActionEPPButton x5Button;
public ActionEPPButton divideBy5Button;
public ActionEPPButton x10Button;
public ActionEPPButton divideBy10Button;
// 在构造器返回后初始化按钮与翻页控制 // 在构造器返回后初始化按钮与翻页控制
@Inject(method = "<init>", at = @At("RETURN")) @Inject(method = "<init>", at = @At("RETURN"))
private void injectInit(ContainerExPatternProvider menu, Inventory playerInventory, Component title, ScreenStyle style, CallbackInfo ci) { private void injectInit(ContainerExPatternProvider menu, Inventory playerInventory, Component title, ScreenStyle style, CallbackInfo ci) {
@ -139,8 +135,8 @@ public abstract class GuiExPatternProviderMixin extends PatternProviderScreen<Co
// 翻页按钮当存在多页时显示支持仅由配置决定的空白页 // 翻页按钮当存在多页时显示支持仅由配置决定的空白页
if (desiredMaxPage > 1) { if (desiredMaxPage > 1) {
this.prevPage = new ActionEPPButton((b) -> { this.prevPage = new ActionEPPButton((b) -> {
int currentPage = getCurrentPage(); int currentPage = this.getCurrentPage();
int maxPage = Math.max(this.eap$maxPageLocal, getMaxPage()); int maxPage = Math.max(this.eap$maxPageLocal, this.getMaxPage());
int newPage = (currentPage - 1 + maxPage) % maxPage; int newPage = (currentPage - 1 + maxPage) % maxPage;
try { try {
ContainerExPatternProvider menu1 = this.getMenu(); ContainerExPatternProvider menu1 = this.getMenu();
@ -164,12 +160,12 @@ public abstract class GuiExPatternProviderMixin extends PatternProviderScreen<Co
this.repositionSlots(SlotSemantics.STORAGE); this.repositionSlots(SlotSemantics.STORAGE);
this.hoveredSlot = null; this.hoveredSlot = null;
// 更新当前页可见状态 // 更新当前页可见状态
eap$updatePageSlotActivity(); this.eap$updatePageSlotActivity();
}, Icon.ARROW_LEFT); }, Icon.ARROW_LEFT);
this.nextPage = new ActionEPPButton((b) -> { this.nextPage = new ActionEPPButton((b) -> {
int currentPage = getCurrentPage(); int currentPage = this.getCurrentPage();
int maxPage = Math.max(this.eap$maxPageLocal, getMaxPage()); int maxPage = Math.max(this.eap$maxPageLocal, this.getMaxPage());
int newPage = (currentPage + 1) % maxPage; int newPage = (currentPage + 1) % maxPage;
try { try {
ContainerExPatternProvider menu1 = this.getMenu(); ContainerExPatternProvider menu1 = this.getMenu();
@ -193,7 +189,7 @@ public abstract class GuiExPatternProviderMixin extends PatternProviderScreen<Co
this.repositionSlots(SlotSemantics.STORAGE); this.repositionSlots(SlotSemantics.STORAGE);
this.hoveredSlot = null; this.hoveredSlot = null;
// 更新当前页可见状态 // 更新当前页可见状态
eap$updatePageSlotActivity(); this.eap$updatePageSlotActivity();
}, Icon.ARROW_RIGHT); }, Icon.ARROW_RIGHT);
// 恢复到 AE2 左侧工具栏 // 恢复到 AE2 左侧工具栏
@ -249,7 +245,7 @@ public abstract class GuiExPatternProviderMixin extends PatternProviderScreen<Co
@Override @Override
public int eap$getCurrentPage() { public int eap$getCurrentPage() {
return getCurrentPage(); return this.getCurrentPage();
} }
// 页码文本绘制移交给 AEBaseScreenMixin.renderLabels 尾部执行 // 页码文本绘制移交给 AEBaseScreenMixin.renderLabels 尾部执行
@ -259,26 +255,26 @@ public abstract class GuiExPatternProviderMixin extends PatternProviderScreen<Co
@Override @Override
public void eap$updateButtonsLayout() { public void eap$updateButtonsLayout() {
// 只处理按钮可见性与定位不再强制 showPage 或挪动 Slot 坐标避免与原布局/tooltip 冲突 // 只处理按钮可见性与定位不再强制 showPage 或挪动 Slot 坐标避免与原布局/tooltip 冲突
if (nextPage != null && prevPage != null) { if (this.nextPage != null && this.prevPage != null) {
this.nextPage.setVisibility(true); this.nextPage.setVisibility(true);
this.prevPage.setVisibility(true); this.prevPage.setVisibility(true);
} }
if (x2Button != null) { if (this.x2Button != null) {
this.x2Button.setVisibility(true); this.x2Button.setVisibility(true);
} }
if (divideBy2Button != null) { if (this.divideBy2Button != null) {
this.divideBy2Button.setVisibility(true); this.divideBy2Button.setVisibility(true);
} }
if (x10Button != null) { if (this.x10Button != null) {
this.x10Button.setVisibility(true); this.x10Button.setVisibility(true);
} }
if (divideBy10Button != null) { if (this.divideBy10Button != null) {
this.divideBy10Button.setVisibility(true); this.divideBy10Button.setVisibility(true);
} }
if (divideBy5Button != null) { if (this.divideBy5Button != null) {
this.divideBy5Button.setVisibility(true); this.divideBy5Button.setVisibility(true);
} }
if (x5Button != null) { if (this.x5Button != null) {
this.x5Button.setVisibility(true); this.x5Button.setVisibility(true);
} }
@ -306,9 +302,9 @@ public abstract class GuiExPatternProviderMixin extends PatternProviderScreen<Co
} catch (Throwable ignored) {} } catch (Throwable ignored) {}
// 如果屏幕尺寸发生变化窗口/GUI缩放重新注册右侧外列的自定义按钮翻页按钮由左侧工具栏托管 // 如果屏幕尺寸发生变化窗口/GUI缩放重新注册右侧外列的自定义按钮翻页按钮由左侧工具栏托管
if (this.width != eap$lastScreenWidth || this.height != eap$lastScreenHeight) { if (this.width != this.eap$lastScreenWidth || this.height != this.eap$lastScreenHeight) {
eap$lastScreenWidth = this.width; this.eap$lastScreenWidth = this.width;
eap$lastScreenHeight = this.height; this.eap$lastScreenHeight = this.height;
try { try {
if (this.divideBy2Button != null) { if (this.divideBy2Button != null) {
this.removeWidget(this.divideBy2Button); this.removeWidget(this.divideBy2Button);
@ -368,7 +364,7 @@ public abstract class GuiExPatternProviderMixin extends PatternProviderScreen<Co
} }
// 每帧确保当前页槽位处于启用状态非当前页禁用 // 每帧确保当前页槽位处于启用状态非当前页禁用
eap$updatePageSlotActivity(); this.eap$updatePageSlotActivity();
} }
// 本文件原包含本地样板缩放实现单机模式 ExtendedAE 网络派发已移除以兼容 1.21.1 与最小可构建集 // 本文件原包含本地样板缩放实现单机模式 ExtendedAE 网络派发已移除以兼容 1.21.1 与最小可构建集
@ -381,7 +377,7 @@ public abstract class GuiExPatternProviderMixin extends PatternProviderScreen<Co
var list = this.getMenu().getSlots(SlotSemantics.ENCODED_PATTERN); var list = this.getMenu().getSlots(SlotSemantics.ENCODED_PATTERN);
if (list == null || list.isEmpty()) return; if (list == null || list.isEmpty()) return;
int currentPage = getCurrentPage(); int currentPage = this.getCurrentPage();
int base = currentPage * SLOTS_PER_PAGE; int base = currentPage * SLOTS_PER_PAGE;
int end = Math.min(list.size(), base + SLOTS_PER_PAGE); int end = Math.min(list.size(), base + SLOTS_PER_PAGE);

View File

@ -2,7 +2,7 @@ package com.extendedae_plus.mixin.jei;
import appeng.integration.modules.itemlists.EncodingHelper; import appeng.integration.modules.itemlists.EncodingHelper;
import appeng.menu.me.items.PatternEncodingTermMenu; import appeng.menu.me.items.PatternEncodingTermMenu;
import com.extendedae_plus.util.ExtendedAEPatternUploadUtil; import com.extendedae_plus.util.uploadPattern.ExtendedAEPatternUploadUtil;
import mezz.jei.api.gui.ingredient.IRecipeSlotsView; import mezz.jei.api.gui.ingredient.IRecipeSlotsView;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.crafting.Recipe; import net.minecraft.world.item.crafting.Recipe;

View File

@ -3,7 +3,7 @@ package com.extendedae_plus.mixin.jei;
import appeng.integration.modules.itemlists.EncodingHelper; import appeng.integration.modules.itemlists.EncodingHelper;
import appeng.integration.modules.rei.transfer.EncodePatternTransferHandler; import appeng.integration.modules.rei.transfer.EncodePatternTransferHandler;
import appeng.menu.me.items.PatternEncodingTermMenu; import appeng.menu.me.items.PatternEncodingTermMenu;
import com.extendedae_plus.util.ExtendedAEPatternUploadUtil; import com.extendedae_plus.util.uploadPattern.ExtendedAEPatternUploadUtil;
import net.minecraft.world.item.crafting.Recipe; import net.minecraft.world.item.crafting.Recipe;
import net.minecraft.world.item.crafting.RecipeHolder; import net.minecraft.world.item.crafting.RecipeHolder;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;

View File

@ -1,9 +1,9 @@
package com.extendedae_plus.network; package com.extendedae_plus.network;
import com.extendedae_plus.ExtendedAEPlus; import com.extendedae_plus.ExtendedAEPlus;
import com.extendedae_plus.ae.items.ChannelCardItem;
import com.extendedae_plus.init.ModItems; import com.extendedae_plus.init.ModItems;
import com.extendedae_plus.util.WirelessTeamUtil; import com.extendedae_plus.items.materials.ChannelCardItem;
import com.extendedae_plus.util.wireless.WirelessTeamUtil;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.network.codec.StreamCodec; import net.minecraft.network.codec.StreamCodec;
@ -37,11 +37,6 @@ public class ChannelCardBindPacket implements CustomPacketPayload {
this.hand = hand; this.hand = hand;
} }
@Override
public Type<? extends CustomPacketPayload> type() {
return TYPE;
}
public static void handle(final ChannelCardBindPacket msg, final IPayloadContext ctx) { public static void handle(final ChannelCardBindPacket msg, final IPayloadContext ctx) {
ctx.enqueueWork(() -> { ctx.enqueueWork(() -> {
if (!(ctx.player() instanceof ServerPlayer player)) { if (!(ctx.player() instanceof ServerPlayer player)) {
@ -79,5 +74,10 @@ public class ChannelCardBindPacket implements CustomPacketPayload {
} }
}); });
} }
@Override
public Type<? extends CustomPacketPayload> type() {
return TYPE;
}
} }

View File

@ -3,31 +3,31 @@ package com.extendedae_plus.network;
import appeng.api.config.Settings; import appeng.api.config.Settings;
import appeng.api.config.YesNo; import appeng.api.config.YesNo;
import appeng.api.networking.IGrid; import appeng.api.networking.IGrid;
import appeng.api.networking.IInWorldGridNodeHost;
import appeng.blockentity.crafting.PatternProviderBlockEntity; import appeng.blockentity.crafting.PatternProviderBlockEntity;
import appeng.helpers.patternprovider.PatternProviderLogic; import appeng.helpers.patternprovider.PatternProviderLogic;
import appeng.helpers.patternprovider.PatternProviderLogicHost; import appeng.helpers.patternprovider.PatternProviderLogicHost;
import appeng.parts.crafting.PatternProviderPart; import appeng.parts.crafting.PatternProviderPart;
import com.extendedae_plus.ExtendedAEPlus; import com.extendedae_plus.ExtendedAEPlus;
import com.extendedae_plus.api.AdvancedBlockingHolder; import com.extendedae_plus.api.advancedBlocking.IAdvancedBlocking;
import com.extendedae_plus.api.SmartDoublingHolder; import com.extendedae_plus.api.smartDoubling.ISmartDoubling;
import appeng.api.networking.IInWorldGridNodeHost;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.network.codec.StreamCodec; import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.neoforged.neoforge.network.handling.IPayloadContext; import net.neoforged.neoforge.network.handling.IPayloadContext;
import java.util.Set;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set;
/** /**
* C2S全网批量切换样板供应器的三种模式 * C2S全网批量切换样板供应器的三种模式
* - 阻挡模式AE2 内置 BLOCKING_MODE 设置 * - 阻挡模式AE2 内置 BLOCKING_MODE 设置
* - 高级阻挡模式AdvancedBlockingHolder mixin * - 高级阻挡模式IAdvancedBlocking mixin
* - 智能翻倍模式SmartDoublingHolder mixin * - 智能翻倍模式ISmartDoubling mixin
* *
* 负载为三个操作码各1字节分别对应blockingadvancedBlockingsmartDoubling * 负载为三个操作码各1字节分别对应blockingadvancedBlockingsmartDoubling
*/ */
@ -44,28 +44,10 @@ public class GlobalToggleProviderModesC2SPacket implements CustomPacketPayload {
}, },
buf -> new GlobalToggleProviderModesC2SPacket(Op.byId(buf.readByte()), Op.byId(buf.readByte()), Op.byId(buf.readByte()), buf.readBlockPos()) buf -> new GlobalToggleProviderModesC2SPacket(Op.byId(buf.readByte()), Op.byId(buf.readByte()), Op.byId(buf.readByte()), buf.readBlockPos())
); );
public enum Op {
NOOP((byte) 0),
SET_TRUE((byte) 1),
SET_FALSE((byte) 2),
TOGGLE((byte) 3);
public final byte id;
Op(byte id) { this.id = id; }
public static Op byId(byte id) {
return switch (id) {
case 1 -> SET_TRUE;
case 2 -> SET_FALSE;
case 3 -> TOGGLE;
default -> NOOP;
};
}
}
private final Op opBlocking; private final Op opBlocking;
private final Op opAdvancedBlocking; private final Op opAdvancedBlocking;
private final Op opSmartDoubling; private final Op opSmartDoubling;
private final BlockPos controllerPos; private final BlockPos controllerPos;
public GlobalToggleProviderModesC2SPacket(Op opBlocking, Op opAdvancedBlocking, Op opSmartDoubling, BlockPos controllerPos) { public GlobalToggleProviderModesC2SPacket(Op opBlocking, Op opAdvancedBlocking, Op opSmartDoubling, BlockPos controllerPos) {
this.opBlocking = opBlocking; this.opBlocking = opBlocking;
this.opAdvancedBlocking = opAdvancedBlocking; this.opAdvancedBlocking = opAdvancedBlocking;
@ -73,11 +55,6 @@ public class GlobalToggleProviderModesC2SPacket implements CustomPacketPayload {
this.controllerPos = controllerPos; this.controllerPos = controllerPos;
} }
@Override
public Type<? extends CustomPacketPayload> type() {
return TYPE;
}
public static void handle(final GlobalToggleProviderModesC2SPacket msg, final IPayloadContext ctx) { public static void handle(final GlobalToggleProviderModesC2SPacket msg, final IPayloadContext ctx) {
ctx.enqueueWork(() -> { ctx.enqueueWork(() -> {
if (!(ctx.player() instanceof ServerPlayer player)) return; if (!(ctx.player() instanceof ServerPlayer player)) return;
@ -176,14 +153,14 @@ public class GlobalToggleProviderModesC2SPacket implements CustomPacketPayload {
} }
} }
// 2) 高级阻挡mixin 接口 // 2) 高级阻挡mixin 接口
if (msg.opAdvancedBlocking != Op.NOOP && logic instanceof AdvancedBlockingHolder adv) { if (msg.opAdvancedBlocking != Op.NOOP && logic instanceof IAdvancedBlocking adv) {
boolean current = adv.eap$getAdvancedBlocking(); boolean current = adv.eap$getAdvancedBlocking();
boolean target = computeTarget(current, msg.opAdvancedBlocking); boolean target = computeTarget(current, msg.opAdvancedBlocking);
adv.eap$setAdvancedBlocking(target); adv.eap$setAdvancedBlocking(target);
changed = changed || (current != target); changed = changed || (current != target);
} }
// 3) 智能翻倍mixin 接口 // 3) 智能翻倍mixin 接口
if (msg.opSmartDoubling != Op.NOOP && logic instanceof SmartDoublingHolder sd) { if (msg.opSmartDoubling != Op.NOOP && logic instanceof ISmartDoubling sd) {
boolean current = sd.eap$getSmartDoubling(); boolean current = sd.eap$getSmartDoubling();
boolean target = computeTarget(current, msg.opSmartDoubling); boolean target = computeTarget(current, msg.opSmartDoubling);
sd.eap$setSmartDoubling(target); sd.eap$setSmartDoubling(target);
@ -208,4 +185,28 @@ public class GlobalToggleProviderModesC2SPacket implements CustomPacketPayload {
private static boolean safeIsBlocking(PatternProviderLogic logic) { private static boolean safeIsBlocking(PatternProviderLogic logic) {
try { return logic.isBlocking(); } catch (Throwable t) { return false; } try { return logic.isBlocking(); } catch (Throwable t) { return false; }
} }
@Override
public Type<? extends CustomPacketPayload> type() {
return TYPE;
}
public enum Op {
NOOP((byte) 0),
SET_TRUE((byte) 1),
SET_FALSE((byte) 2),
TOGGLE((byte) 3);
public final byte id;
Op(byte id) {this.id = id;}
static Op byId(byte id) {
return switch (id) {
case 1 -> SET_TRUE;
case 2 -> SET_FALSE;
case 3 -> TOGGLE;
default -> NOOP;
};
}
}
} }

View File

@ -7,7 +7,7 @@ import appeng.items.tools.powered.WirelessTerminalItem;
import appeng.menu.locator.MenuLocators; import appeng.menu.locator.MenuLocators;
import appeng.menu.me.crafting.CraftAmountMenu; import appeng.menu.me.crafting.CraftAmountMenu;
import com.extendedae_plus.menu.locator.CuriosItemLocator; import com.extendedae_plus.menu.locator.CuriosItemLocator;
import com.extendedae_plus.util.WirelessTerminalLocator; import com.extendedae_plus.util.wireless.WirelessTerminalLocator;
import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.StreamCodec; import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
@ -33,11 +33,6 @@ public class OpenCraftFromJeiC2SPacket implements CustomPacketPayload {
this.stack = stack; this.stack = stack;
} }
@Override
public Type<? extends CustomPacketPayload> type() {
return TYPE;
}
public static void handle(final OpenCraftFromJeiC2SPacket msg, final IPayloadContext ctx) { public static void handle(final OpenCraftFromJeiC2SPacket msg, final IPayloadContext ctx) {
ctx.enqueueWork(() -> { ctx.enqueueWork(() -> {
if (!(ctx.player() instanceof ServerPlayer player)) return; if (!(ctx.player() instanceof ServerPlayer player)) return;
@ -118,4 +113,9 @@ public class OpenCraftFromJeiC2SPacket implements CustomPacketPayload {
} }
}); });
} }
@Override
public Type<? extends CustomPacketPayload> type() {
return TYPE;
}
} }

View File

@ -9,8 +9,8 @@ import appeng.items.tools.powered.WirelessCraftingTerminalItem;
import appeng.items.tools.powered.WirelessTerminalItem; import appeng.items.tools.powered.WirelessTerminalItem;
import appeng.me.helpers.PlayerSource; import appeng.me.helpers.PlayerSource;
import com.extendedae_plus.menu.locator.CuriosItemLocator; import com.extendedae_plus.menu.locator.CuriosItemLocator;
import com.extendedae_plus.util.WirelessTerminalLocator; import com.extendedae_plus.util.wireless.WirelessTerminalLocator;
import com.extendedae_plus.util.WirelessTerminalLocator.LocatedTerminal; import com.extendedae_plus.util.wireless.WirelessTerminalLocator.LocatedTerminal;
import de.mari_023.ae2wtlib.api.registration.WTDefinition; import de.mari_023.ae2wtlib.api.registration.WTDefinition;
import de.mari_023.ae2wtlib.api.terminal.WTMenuHost; import de.mari_023.ae2wtlib.api.terminal.WTMenuHost;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
@ -56,11 +56,6 @@ public class PickFromWirelessC2SPacket implements CustomPacketPayload {
this.hitLoc = hitLoc; this.hitLoc = hitLoc;
} }
@Override
public Type<? extends CustomPacketPayload> type() {
return TYPE;
}
public static void handle(final PickFromWirelessC2SPacket msg, final IPayloadContext ctx) { public static void handle(final PickFromWirelessC2SPacket msg, final IPayloadContext ctx) {
ctx.enqueueWork(() -> { ctx.enqueueWork(() -> {
if (!(ctx.player() instanceof ServerPlayer player)) return; if (!(ctx.player() instanceof ServerPlayer player)) return;
@ -175,4 +170,9 @@ public class PickFromWirelessC2SPacket implements CustomPacketPayload {
player.containerMenu.broadcastChanges(); player.containerMenu.broadcastChanges();
}); });
} }
@Override
public Type<? extends CustomPacketPayload> type() {
return TYPE;
}
} }

View File

@ -1,7 +1,7 @@
package com.extendedae_plus.network; package com.extendedae_plus.network;
import com.extendedae_plus.ExtendedAEPlus; import com.extendedae_plus.ExtendedAEPlus;
import com.extendedae_plus.client.ui.ProviderSelectScreen; import com.extendedae_plus.client.screen.ProviderSelectScreen;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.StreamCodec; import net.minecraft.network.codec.StreamCodec;
@ -48,17 +48,12 @@ public class ProvidersListS2CPacket implements CustomPacketPayload {
private final List<String> names; private final List<String> names;
private final List<Integer> emptySlots; private final List<Integer> emptySlots;
public ProvidersListS2CPacket(List<Long> ids, List<String> names, List<Integer> emptySlots) { ProvidersListS2CPacket(List<Long> ids, List<String> names, List<Integer> emptySlots) {
this.ids = ids; this.ids = ids;
this.names = names; this.names = names;
this.emptySlots = emptySlots; this.emptySlots = emptySlots;
} }
@Override
public Type<? extends CustomPacketPayload> type() {
return TYPE;
}
public static void handle(final ProvidersListS2CPacket msg, final IPayloadContext ctx) { public static void handle(final ProvidersListS2CPacket msg, final IPayloadContext ctx) {
ctx.enqueueWork(() -> handleClient(msg)); ctx.enqueueWork(() -> handleClient(msg));
} }
@ -70,4 +65,9 @@ public class ProvidersListS2CPacket implements CustomPacketPayload {
var current = mc.screen; var current = mc.screen;
mc.setScreen(new ProviderSelectScreen(current, msg.ids, msg.names, msg.emptySlots)); mc.setScreen(new ProviderSelectScreen(current, msg.ids, msg.names, msg.emptySlots));
} }
@Override
public Type<? extends CustomPacketPayload> type() {
return TYPE;
}
} }

View File

@ -13,8 +13,8 @@ import appeng.me.helpers.PlayerSource;
import appeng.menu.locator.MenuLocators; import appeng.menu.locator.MenuLocators;
import appeng.menu.me.crafting.CraftAmountMenu; import appeng.menu.me.crafting.CraftAmountMenu;
import com.extendedae_plus.menu.locator.CuriosItemLocator; import com.extendedae_plus.menu.locator.CuriosItemLocator;
import com.extendedae_plus.util.WirelessTerminalLocator; import com.extendedae_plus.util.wireless.WirelessTerminalLocator;
import com.extendedae_plus.util.WirelessTerminalLocator.LocatedTerminal; import com.extendedae_plus.util.wireless.WirelessTerminalLocator.LocatedTerminal;
import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.StreamCodec; import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
@ -39,11 +39,6 @@ public class PullFromJeiOrCraftC2SPacket implements CustomPacketPayload {
this.stack = stack; this.stack = stack;
} }
@Override
public Type<? extends CustomPacketPayload> type() {
return TYPE;
}
public static void handle(final PullFromJeiOrCraftC2SPacket msg, final IPayloadContext ctx) { public static void handle(final PullFromJeiOrCraftC2SPacket msg, final IPayloadContext ctx) {
ctx.enqueueWork(() -> { ctx.enqueueWork(() -> {
if (!(ctx.player() instanceof ServerPlayer player)) return; if (!(ctx.player() instanceof ServerPlayer player)) return;
@ -107,4 +102,9 @@ public class PullFromJeiOrCraftC2SPacket implements CustomPacketPayload {
} }
}); });
} }
@Override
public Type<? extends CustomPacketPayload> type() {
return TYPE;
}
} }

View File

@ -4,7 +4,7 @@ import appeng.helpers.patternprovider.PatternContainer;
import appeng.menu.implementations.PatternAccessTermMenu; import appeng.menu.implementations.PatternAccessTermMenu;
import appeng.menu.me.items.PatternEncodingTermMenu; import appeng.menu.me.items.PatternEncodingTermMenu;
import com.extendedae_plus.ExtendedAEPlus; import com.extendedae_plus.ExtendedAEPlus;
import com.extendedae_plus.util.ExtendedAEPatternUploadUtil; import com.extendedae_plus.util.uploadPattern.ExtendedAEPatternUploadUtil;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.codec.StreamCodec; import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
@ -27,12 +27,7 @@ public class RequestProvidersListC2SPacket implements CustomPacketPayload {
public static final StreamCodec<FriendlyByteBuf, RequestProvidersListC2SPacket> STREAM_CODEC = public static final StreamCodec<FriendlyByteBuf, RequestProvidersListC2SPacket> STREAM_CODEC =
StreamCodec.unit(INSTANCE); StreamCodec.unit(INSTANCE);
public RequestProvidersListC2SPacket() {} private RequestProvidersListC2SPacket() {}
@Override
public Type<? extends CustomPacketPayload> type() {
return TYPE;
}
public static void handle(final RequestProvidersListC2SPacket msg, final IPayloadContext ctx) { public static void handle(final RequestProvidersListC2SPacket msg, final IPayloadContext ctx) {
ctx.enqueueWork(() -> { ctx.enqueueWork(() -> {
@ -79,4 +74,9 @@ public class RequestProvidersListC2SPacket implements CustomPacketPayload {
player.connection.send(new ProvidersListS2CPacket(idxIds, names, slots)); player.connection.send(new ProvidersListS2CPacket(idxIds, names, slots));
}); });
} }
@Override
public Type<? extends CustomPacketPayload> type() {
return TYPE;
}
} }

View File

@ -4,7 +4,7 @@ import appeng.api.config.Settings;
import appeng.api.config.YesNo; import appeng.api.config.YesNo;
import appeng.menu.implementations.PatternProviderMenu; import appeng.menu.implementations.PatternProviderMenu;
import com.extendedae_plus.ExtendedAEPlus; import com.extendedae_plus.ExtendedAEPlus;
import com.extendedae_plus.api.AdvancedBlockingHolder; import com.extendedae_plus.api.advancedBlocking.IAdvancedBlocking;
import com.extendedae_plus.mixin.advancedae.accessor.AdvPatternProviderMenuAdvancedAccessor; import com.extendedae_plus.mixin.advancedae.accessor.AdvPatternProviderMenuAdvancedAccessor;
import com.extendedae_plus.mixin.ae2.accessor.PatternProviderMenuAdvancedAccessor; import com.extendedae_plus.mixin.ae2.accessor.PatternProviderMenuAdvancedAccessor;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
@ -30,11 +30,6 @@ public class ToggleAdvancedBlockingC2SPacket implements CustomPacketPayload {
private ToggleAdvancedBlockingC2SPacket() {} private ToggleAdvancedBlockingC2SPacket() {}
@Override
public Type<? extends CustomPacketPayload> type() {
return TYPE;
}
public static void handle(final ToggleAdvancedBlockingC2SPacket msg, final IPayloadContext ctx) { public static void handle(final ToggleAdvancedBlockingC2SPacket msg, final IPayloadContext ctx) {
ctx.enqueueWork(() -> { ctx.enqueueWork(() -> {
if (!(ctx.player() instanceof ServerPlayer player)) return; if (!(ctx.player() instanceof ServerPlayer player)) return;
@ -42,7 +37,7 @@ public class ToggleAdvancedBlockingC2SPacket implements CustomPacketPayload {
if (containerMenu instanceof PatternProviderMenu menu) { if (containerMenu instanceof PatternProviderMenu menu) {
var accessor = (PatternProviderMenuAdvancedAccessor) menu; var accessor = (PatternProviderMenuAdvancedAccessor) menu;
var logic = accessor.eap$logic(); var logic = accessor.eap$logic();
if (logic instanceof AdvancedBlockingHolder holder) { if (logic instanceof IAdvancedBlocking holder) {
boolean current = holder.eap$getAdvancedBlocking(); boolean current = holder.eap$getAdvancedBlocking();
boolean next = !current; boolean next = !current;
holder.eap$setAdvancedBlocking(next); holder.eap$setAdvancedBlocking(next);
@ -54,7 +49,7 @@ public class ToggleAdvancedBlockingC2SPacket implements CustomPacketPayload {
}else if (containerMenu instanceof AdvPatternProviderMenu menu){ }else if (containerMenu instanceof AdvPatternProviderMenu menu){
var accessor = (AdvPatternProviderMenuAdvancedAccessor) menu; var accessor = (AdvPatternProviderMenuAdvancedAccessor) menu;
var logic = accessor.eap$logic(); var logic = accessor.eap$logic();
if (logic instanceof AdvancedBlockingHolder holder) { if (logic instanceof IAdvancedBlocking holder) {
boolean current = holder.eap$getAdvancedBlocking(); boolean current = holder.eap$getAdvancedBlocking();
boolean next = !current; boolean next = !current;
holder.eap$setAdvancedBlocking(next); holder.eap$setAdvancedBlocking(next);
@ -66,4 +61,9 @@ public class ToggleAdvancedBlockingC2SPacket implements CustomPacketPayload {
} }
}); });
} }
@Override
public Type<? extends CustomPacketPayload> type() {
return TYPE;
}
} }

View File

@ -2,7 +2,7 @@ package com.extendedae_plus.network;
import appeng.menu.implementations.PatternProviderMenu; import appeng.menu.implementations.PatternProviderMenu;
import com.extendedae_plus.ExtendedAEPlus; import com.extendedae_plus.ExtendedAEPlus;
import com.extendedae_plus.api.SmartDoublingHolder; import com.extendedae_plus.api.smartDoubling.ISmartDoubling;
import com.extendedae_plus.mixin.advancedae.accessor.AdvPatternProviderMenuAdvancedAccessor; import com.extendedae_plus.mixin.advancedae.accessor.AdvPatternProviderMenuAdvancedAccessor;
import com.extendedae_plus.mixin.ae2.accessor.PatternProviderMenuAdvancedAccessor; import com.extendedae_plus.mixin.ae2.accessor.PatternProviderMenuAdvancedAccessor;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
@ -28,11 +28,6 @@ public class ToggleSmartDoublingC2SPacket implements CustomPacketPayload {
private ToggleSmartDoublingC2SPacket() {} private ToggleSmartDoublingC2SPacket() {}
@Override
public Type<? extends CustomPacketPayload> type() {
return TYPE;
}
public static void handle(final ToggleSmartDoublingC2SPacket msg, final IPayloadContext ctx) { public static void handle(final ToggleSmartDoublingC2SPacket msg, final IPayloadContext ctx) {
ctx.enqueueWork(() -> { ctx.enqueueWork(() -> {
if (!(ctx.player() instanceof ServerPlayer player)) return; if (!(ctx.player() instanceof ServerPlayer player)) return;
@ -40,7 +35,7 @@ public class ToggleSmartDoublingC2SPacket implements CustomPacketPayload {
if (containerMenu instanceof PatternProviderMenu menu) { if (containerMenu instanceof PatternProviderMenu menu) {
var accessor = (PatternProviderMenuAdvancedAccessor) menu; var accessor = (PatternProviderMenuAdvancedAccessor) menu;
var logic = accessor.eap$logic(); var logic = accessor.eap$logic();
if (logic instanceof SmartDoublingHolder holder) { if (logic instanceof ISmartDoubling holder) {
boolean current = holder.eap$getSmartDoubling(); boolean current = holder.eap$getSmartDoubling();
boolean next = !current; boolean next = !current;
holder.eap$setSmartDoubling(next); holder.eap$setSmartDoubling(next);
@ -49,7 +44,7 @@ public class ToggleSmartDoublingC2SPacket implements CustomPacketPayload {
}else if (containerMenu instanceof AdvPatternProviderMenu menu){ }else if (containerMenu instanceof AdvPatternProviderMenu menu){
var accessor = (AdvPatternProviderMenuAdvancedAccessor) menu; var accessor = (AdvPatternProviderMenuAdvancedAccessor) menu;
var logic = accessor.eap$logic(); var logic = accessor.eap$logic();
if (logic instanceof SmartDoublingHolder holder) { if (logic instanceof ISmartDoubling holder) {
boolean current = holder.eap$getSmartDoubling(); boolean current = holder.eap$getSmartDoubling();
boolean next = !current; boolean next = !current;
holder.eap$setSmartDoubling(next); holder.eap$setSmartDoubling(next);
@ -58,4 +53,9 @@ public class ToggleSmartDoublingC2SPacket implements CustomPacketPayload {
} }
}); });
} }
@Override
public Type<? extends CustomPacketPayload> type() {
return TYPE;
}
} }

View File

@ -1,7 +1,7 @@
package com.extendedae_plus.network; package com.extendedae_plus.network;
import appeng.menu.me.items.PatternEncodingTermMenu; import appeng.menu.me.items.PatternEncodingTermMenu;
import com.extendedae_plus.util.ExtendedAEPatternUploadUtil; import com.extendedae_plus.util.uploadPattern.ExtendedAEPatternUploadUtil;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.codec.StreamCodec; import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
@ -26,11 +26,6 @@ public class UploadEncodedPatternToProviderC2SPacket implements CustomPacketPayl
this.providerId = providerId; this.providerId = providerId;
} }
@Override
public Type<? extends CustomPacketPayload> type() {
return TYPE;
}
public static void handle(final UploadEncodedPatternToProviderC2SPacket msg, final IPayloadContext ctx) { public static void handle(final UploadEncodedPatternToProviderC2SPacket msg, final IPayloadContext ctx) {
ctx.enqueueWork(() -> { ctx.enqueueWork(() -> {
if (!(ctx.player() instanceof ServerPlayer player)) return; if (!(ctx.player() instanceof ServerPlayer player)) return;
@ -46,4 +41,9 @@ public class UploadEncodedPatternToProviderC2SPacket implements CustomPacketPayl
} }
}); });
} }
@Override
public Type<? extends CustomPacketPayload> type() {
return TYPE;
}
} }

View File

@ -1,6 +1,6 @@
package com.extendedae_plus.network; package com.extendedae_plus.network;
import com.extendedae_plus.util.ExtendedAEPatternUploadUtil; import com.extendedae_plus.util.uploadPattern.ExtendedAEPatternUploadUtil;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.codec.StreamCodec; import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
@ -32,15 +32,15 @@ public class UploadInventoryPatternToProviderC2SPacket implements CustomPacketPa
this.providerId = providerId; this.providerId = providerId;
} }
@Override
public Type<? extends CustomPacketPayload> type() {
return TYPE;
}
public static void handle(final UploadInventoryPatternToProviderC2SPacket msg, final IPayloadContext ctx) { public static void handle(final UploadInventoryPatternToProviderC2SPacket msg, final IPayloadContext ctx) {
ctx.enqueueWork(() -> { ctx.enqueueWork(() -> {
if (!(ctx.player() instanceof ServerPlayer player)) return; if (!(ctx.player() instanceof ServerPlayer player)) return;
ExtendedAEPatternUploadUtil.uploadPatternToProvider(player, msg.playerSlotIndex, msg.providerId); ExtendedAEPatternUploadUtil.uploadPatternToProvider(player, msg.playerSlotIndex, msg.providerId);
}); });
} }
@Override
public Type<? extends CustomPacketPayload> type() {
return TYPE;
}
} }

View File

@ -1,4 +1,4 @@
package com.extendedae_plus.util; package com.extendedae_plus.util.entitySpeed;
import appeng.api.config.Actionable; import appeng.api.config.Actionable;
import appeng.api.networking.energy.IEnergyService; import appeng.api.networking.energy.IEnergyService;

View File

@ -1,8 +1,8 @@
package com.extendedae_plus.util.entitySpeed; package com.extendedae_plus.util.entitySpeed;
import appeng.api.upgrades.IUpgradeInventory; import appeng.api.upgrades.IUpgradeInventory;
import com.extendedae_plus.ae.definitions.upgrades.EntitySpeedCardItem;
import com.extendedae_plus.config.ModConfigs; import com.extendedae_plus.config.ModConfigs;
import com.extendedae_plus.items.materials.EntitySpeedCardItem;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import java.util.ArrayList; import java.util.ArrayList;
@ -47,7 +47,7 @@ public final class PowerUtils {
/** /**
* 根据最高单卡倍率返回上限值 * 根据最高单卡倍率返回上限值
*/ */
public static long capForHighestMultiplier(int highestMultiplier) { private static long capForHighestMultiplier(int highestMultiplier) {
if (highestMultiplier >= 16) return 1024L; if (highestMultiplier >= 16) return 1024L;
if (highestMultiplier >= 8) return 256L; if (highestMultiplier >= 8) return 256L;
if (highestMultiplier >= 4) return 64L; if (highestMultiplier >= 4) return 64L;

View File

@ -1,12 +1,12 @@
package com.extendedae_plus.util; package com.extendedae_plus.util.smartDoubling;
import appeng.api.crafting.IPatternDetails.IInput; import appeng.api.crafting.IPatternDetails.IInput;
import appeng.api.stacks.AEKey; import appeng.api.stacks.AEKey;
import appeng.api.stacks.GenericStack; import appeng.api.stacks.GenericStack;
import appeng.crafting.pattern.AEProcessingPattern; import appeng.crafting.pattern.AEProcessingPattern;
import com.extendedae_plus.api.SmartDoublingAwarePattern; import com.extendedae_plus.api.crafting.ScaledProcessingPattern;
import com.extendedae_plus.api.smartDoubling.ISmartDoublingAwarePattern;
import com.extendedae_plus.config.ModConfigs; import com.extendedae_plus.config.ModConfigs;
import com.extendedae_plus.content.ScaledProcessingPattern;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -20,7 +20,7 @@ public final class PatternScaler {
if (target == null) throw new IllegalArgumentException("target"); if (target == null) throw new IllegalArgumentException("target");
// 双保险若样板标记为不允许缩放直接放弃缩放返回 null 表示调用方应保持原样板 // 双保险若样板标记为不允许缩放直接放弃缩放返回 null 表示调用方应保持原样板
if (base instanceof SmartDoublingAwarePattern aware && !aware.eap$allowScaling()) { if (base instanceof ISmartDoublingAwarePattern aware && !aware.eap$allowScaling()) {
return null; return null;
} }

View File

@ -1,4 +1,4 @@
package com.extendedae_plus.util; package com.extendedae_plus.util.smartDoubling;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.Deque; import java.util.Deque;

Some files were not shown because too many files have changed in this diff Show More