feat: 更新实体加速器相关配置缓存刷新机制

This commit is contained in:
C-H716 2025-09-30 09:27:19 +08:00
parent 636050039d
commit e7add431ce
6 changed files with 116 additions and 94 deletions

View File

@ -51,7 +51,7 @@ import java.lang.reflect.Method;
* 实体加速器部件用于加速目标方块实体的 tick 速率消耗 AE 网络能量支持加速卡和能量卡升级
* 灵感来源于 <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 = new ResourceLocation(
ExtendedAEPlus.MODID, "part/entity_speed_ticker_part");
@ -62,18 +62,14 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTick
@PartModels
public static final PartModel MODELS_HAS_CHANNEL = new PartModel(MODEL_BASE, new ResourceLocation(ExtendedAEPlus.MODID, "part/entity_speed_ticker_has_channel"));
public EntitySpeedTickerMenu menu; // 当前打开的菜单实例
private boolean networkEnergySufficient = true; // 网络能量是否充足
private int cachedSpeed = -1; // 缓存的加速倍率
private int cachedEnergyCardCount = -1; // 缓存的能量卡数量
private BlockEntity cachedTarget = null;
private BlockPos cachedTargetPos = null;
private static volatile boolean[] cachedAttempts;
private static volatile Method cachedFEExtractMethod;
private static volatile boolean FE_UNAVAILABLE;
// ===== 静态块反射初始化 FE 方法 =====
// 静态块初始化缓存
static {
cachedAttempts = ModConfig.INSTANCE.prioritizeDiskEnergy ? new boolean[]{false, true, true} : new boolean[]{true, false, true};
if (ModList.get().isLoaded("appflux")) {
try {
Class<?> helperClass = Class.forName("com.extendedae_plus.util.FluxEnergyHelper");
@ -90,8 +86,17 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTick
}
}
}
public EntitySpeedTickerMenu menu; // 当前打开的菜单实例
private boolean networkEnergySufficient = true; // 网络能量是否充足
private int cachedSpeed = -1; // 缓存的加速倍率
private int cachedEnergyCardCount = -1; // 缓存的能量卡数量
private BlockEntity cachedTarget = null;
private BlockPos cachedTargetPos = null;
/**
* 构造函数初始化部件并设置网络节点属性
*
* @param partItem 部件物品
*/
public EntitySpeedTickerPart(IPartItem<?> partItem) {
@ -108,17 +113,26 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTick
);
}
/**
* 更新缓存的 attempts 数组 ModConfig 调用
*/
public static void updateCachedAttempts(boolean prioritizeDiskEnergy) {
synchronized (EntitySpeedTickerPart.class) {
cachedAttempts = prioritizeDiskEnergy ? new boolean[]{false, true, true} : new boolean[]{true, false, true};
}
}
public boolean getAccelerateEnabled() {
return this.getConfigManager().getSetting(com.extendedae_plus.ae.api.config.Settings.ACCELERATE) == YesNo.YES;
}
/**
* 设置加速开关状态并通知菜单
*
* @param enabled 是否启用加速
*/
public void setAccelerateEnabled(boolean enabled) {
this.getConfigManager().putSetting(com.extendedae_plus.ae.api.config.Settings.ACCELERATE, enabled ? YesNo.YES : YesNo.NO);
// 是否启用加速
if (menu != null) {
menu.setAccelerateEnabled(enabled);
}
@ -130,6 +144,7 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTick
/**
* 更新网络能量充足状态并通知菜单
*
* @param sufficient 是否能量充足
*/
private void updateNetworkEnergySufficient(boolean sufficient) {
@ -141,6 +156,7 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTick
/**
* 获取当前状态的渲染模型
*
* @return 当前状态的模型
*/
@Override
@ -156,9 +172,10 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTick
/**
* 处理玩家右键激活部件打开菜单
*
* @param player 玩家
* @param hand
* @param pos 点击位置
* @param hand
* @param pos 点击位置
* @return 总是返回 true
*/
@Override
@ -171,6 +188,7 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTick
/**
* 定义部件的碰撞箱
*
* @param bch 碰撞辅助器
*/
@Override
@ -181,6 +199,7 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTick
/**
* 获取定时请求指定 tick 频率
*
* @param iGridNode 网络节点
* @return TickingRequest 对象
*/
@ -205,7 +224,8 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTick
/**
* 网络定时回调处理目标方块实体的加速
* @param iGridNode 网络节点
*
* @param iGridNode 网络节点
* @param ticksSinceLastCall 距离上次调用的 tick
* @return TickRateModulation.IDLE
*/
@ -223,8 +243,9 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTick
/**
* 对目标方块实体执行加速 tick 操作
*
* @param blockEntity 目标方块实体
* @param <T> 方块实体类型
* @param <T> 方块实体类型
*/
private <T extends BlockEntity> void ticker(@NotNull T blockEntity) {
if (!isValidForTicking()) {
@ -241,7 +262,6 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTick
return;
}
// 如果缓存未初始化第一次 tick计算并更新缓存
if (cachedEnergyCardCount == -1 || cachedSpeed == -1) {
this.cachedEnergyCardCount = getUpgrades().getInstalledUpgrades(AEItems.ENERGY_CARD);
this.cachedSpeed = calculateSpeed();
@ -251,7 +271,6 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTick
return;
}
// 使用 PowerUtils 的缓存获取能耗并应用方块特定的倍率
double requiredPower = PowerUtils.getCachedPower(cachedSpeed, cachedEnergyCardCount)
* ConfigParsingUtils.getMultiplierForBlock(blockId);
if (!extractPower(requiredPower)) {
@ -263,6 +282,7 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTick
/**
* 检查网络节点是否有效
*
* @return 是否可以执行 tick
*/
private boolean isValidForTicking() {
@ -280,8 +300,10 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTick
cachedTarget = getLevel().getBlockEntity(targetPos);
}
}
/**
* 获取目标方块实体的 ticker
*
* @param blockEntity 目标方块实体
* @return ticker null
*/
@ -292,6 +314,7 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTick
/**
* 计算加速倍率
*
* @return 生效的加速倍率
*/
private int calculateSpeed() {
@ -302,6 +325,7 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTick
/**
* 提取网络能量并更新状态优先从 AE2 网络提取 AE 能量不足时从磁盘提取 FE 能量
*
* @param requiredPower 所需能量AE 单位
* @return 是否成功提取足够能量
*/
@ -310,11 +334,8 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTick
MEStorage storage = getMainNode().getGrid().getStorageService().getInventory();
IActionSource source = IActionSource.ofMachine(this);
// 优先级FE如果优先磁盘 -> AE -> FE如果未优先磁盘
boolean[] attempts = ModConfig.INSTANCE.prioritizeDiskEnergy ? new boolean[]{true, false, true} : new boolean[]{false, true, false};
for (int i = 0; i < attempts.length; i++) {
if (!attempts[i]) continue;
for (int i = 0; i < cachedAttempts.length; i++) {
if (!cachedAttempts[i]) continue;
if (i == 0 || i == 2) { // FE 提取
if (!FE_UNAVAILABLE && cachedFEExtractMethod != null) {
try {
@ -329,10 +350,14 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTick
}
}
} else { // AE 提取
double extracted = energyService.extractAEPower(requiredPower, Actionable.MODULATE, PowerMultiplier.CONFIG);
if (extracted >= requiredPower) {
updateNetworkEnergySufficient(true);
return true;
double simulated = energyService.extractAEPower(requiredPower, Actionable.SIMULATE, PowerMultiplier.CONFIG);
if (simulated >= requiredPower) {
double extracted = energyService.extractAEPower(requiredPower, Actionable.MODULATE, PowerMultiplier.CONFIG);
boolean sufficient = extracted >= requiredPower;
updateNetworkEnergySufficient(sufficient);
if (sufficient) {
return true;
}
}
}
}
@ -342,14 +367,14 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTick
/**
* 执行加速 tick 操作
*
* @param blockEntity 目标方块实体
* @param ticker 方块实体 ticker
* @param speed 加速倍率
* @param ticker 方块实体 ticker
* @param speed 加速倍率
*/
private <T extends BlockEntity> void performTicks(T blockEntity,
BlockEntityTicker<T> ticker,
int speed) {
// 执行 speed-1 次额外 tick原生 tick 已包含 1
for (int i = 0; i < speed - 1; i++) {
ticker.tick(
blockEntity.getLevel(),
@ -372,9 +397,10 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTick
/**
* 创建菜单实例
* @param containerId 容器ID
*
* @param containerId 容器ID
* @param playerInventory 玩家背包
* @param player 玩家
* @param player 玩家
* @return 菜单实例
*/
@Override
@ -386,6 +412,7 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTick
/**
* 获取升级卡槽数量
*
* @return 升级卡槽数量
*/
@Override

View File

@ -1,18 +1,30 @@
package com.extendedae_plus.config;
import com.extendedae_plus.ExtendedAEPlus;
import com.extendedae_plus.ae.parts.EntitySpeedTickerPart;
import com.extendedae_plus.util.entitySpeed.ConfigParsingUtils;
import com.extendedae_plus.util.entitySpeed.PowerUtils;
import dev.toma.configuration.Configuration;
import dev.toma.configuration.client.IValidationHandler;
import dev.toma.configuration.config.Config;
import dev.toma.configuration.config.Configurable;
import dev.toma.configuration.config.format.ConfigFormats;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import static com.extendedae_plus.util.Logger.EAP$LOGGER;
@Config(id = ExtendedAEPlus.MODID)
public final class ModConfig {
public static ModConfig INSTANCE;
private static final Object lock = new Object();
private static final long DEBOUNCE_INTERVAL = 1000; // 防抖间隔单位毫秒
private static final AtomicLong lastUpdateTime = new AtomicLong(0);
public static void init() {
synchronized (lock) {
@ -21,6 +33,7 @@ public final class ModConfig {
}
}
}
@Configurable
@Configurable.Comment(value = {
"扩展样板供应器总槽位容量的倍率。",
@ -95,6 +108,7 @@ public final class ModConfig {
})
@Configurable.Range(min = 0, max = Integer.MAX_VALUE)
@Configurable.Synchronized
@Configurable.ValueUpdateCallback(method = "onEntityTickerCostUpdate")
public int entityTickerCost = 512;
@Configurable
@ -103,9 +117,8 @@ public final class ModConfig {
"格式:全名或通配符/正则字符串,例如 'minecraft:chest'、'minecraft:*'、'modid:.*_fluid'"
})
@Configurable.Synchronized
public String[] entityTickerBlackList = {
};
@Configurable.ValueUpdateCallback(method = "onEntityTickerBlackListUpdate")
public String[] entityTickerBlackList = {};
@Configurable
@Configurable.Comment(value = {
@ -113,9 +126,8 @@ public final class ModConfig {
"支持通配符/正则匹配(例如 'minecraft:* 2x' 会对整个命名空间生效)。"
})
@Configurable.Synchronized
public String[] entityTickerMultipliers = {
};
@Configurable.ValueUpdateCallback(method = "onEntityTickerMultipliersUpdate")
public String[] entityTickerMultipliers = {};
@Configurable
@Configurable.Comment(value = {
@ -131,5 +143,45 @@ public final class ModConfig {
"开启后将优先尝试从磁盘提取FE能量反之优先消耗AE网络中的能量"
})
@Configurable.Synchronized
@Configurable.ValueUpdateCallback(method = "onPrioritizeDiskEnergyUpdate")
public boolean prioritizeDiskEnergy = true;
private static final ScheduledExecutorService EXECUTOR = Executors.newSingleThreadScheduledExecutor();
private static ScheduledFuture<?> pendingPowerTask;
private static final Object POWER_LOCK = new Object();
private void onEntityTickerCostUpdate(int newValue, IValidationHandler handler) {
synchronized (POWER_LOCK) {
if (pendingPowerTask != null) {
pendingPowerTask.cancel(false);
}
pendingPowerTask = EXECUTOR.schedule(() -> {
synchronized (PowerUtils.class) {
PowerUtils.initializeCaches();
}
}, 1000, TimeUnit.MILLISECONDS); // 1000ms 防抖
}
}
private void onEntityTickerBlackListUpdate(String[] newValue, IValidationHandler handler) {
synchronized (ConfigParsingUtils.class) {
EAP$LOGGER.info("onEntityTickerBlackListUpdate");
ConfigParsingUtils.reload();
}
}
private void onEntityTickerMultipliersUpdate(String[] newValue, IValidationHandler handler) {
synchronized (ConfigParsingUtils.class) {
EAP$LOGGER.info("onEntityTickerMultipliersUpdate");
ConfigParsingUtils.reload();
}
}
private void onPrioritizeDiskEnergyUpdate(boolean newValue, dev.toma.configuration.client.IValidationHandler handler) {
synchronized (EntitySpeedTickerPart.class) {
EAP$LOGGER.info("onPrioritizeDiskEnergyUpdate");
EntitySpeedTickerPart.updateCachedAttempts(newValue);
}
}
}

View File

@ -85,7 +85,6 @@ public abstract class PatternProviderLogicCompatMixin implements IUpgradeableObj
private void eap$onAppfluxUpgradesChanged(CallbackInfo ci) {
try {
if (UpgradeSlotCompat.shouldEnableChannelCard()) {
Logger.EAP$LOGGER.info("监听到appflux升级变化处理频道卡");
// 升级变更重置并尝试初始化频道卡
eap$compatLastChannel = -1;
eap$compatHasInitialized = false;
@ -100,13 +99,9 @@ public abstract class PatternProviderLogicCompatMixin implements IUpgradeableObj
at = @At("TAIL"))
private void eap$compatInitUpgrades(IManagedGridNode mainNode, PatternProviderLogicHost host, int patternInventorySize, CallbackInfo ci) {
try {
Logger.EAP$LOGGER.info("兼容性PatternProviderLogic初始化被调用");
boolean upgradeSlots = UpgradeSlotCompat.shouldEnableUpgradeSlots();
boolean channelCard = UpgradeSlotCompat.shouldEnableChannelCard();
Logger.EAP$LOGGER.info("升级槽功能: {}, 频道卡功能: {}", upgradeSlots, channelCard);
if (upgradeSlots) {
// 只有在升级槽功能启用时才创建升级槽
this.eap$compatUpgrades = UpgradeInventories.forMachine(
@ -114,12 +109,9 @@ public abstract class PatternProviderLogicCompatMixin implements IUpgradeableObj
1,
this::eap$compatOnUpgradesChanged
);
Logger.EAP$LOGGER.info("创建了完整的升级槽");
} else if (channelCard) {
// 如果装了appflux我们不创建自己的升级槽而是监听appflux的升级槽
Logger.EAP$LOGGER.info("装了appflux将监听其升级槽来处理频道卡");
} else {
Logger.EAP$LOGGER.info("跳过升级槽创建");
}
} catch (Exception e) {
Logger.EAP$LOGGER.error("兼容性升级初始化失败", e);
@ -188,7 +180,6 @@ public abstract class PatternProviderLogicCompatMixin implements IUpgradeableObj
} else {
// 装了appflux时这个方法不应该被调用因为appflux的Mixin会覆盖它
// 但是为了安全起见返回空的升级槽
Logger.EAP$LOGGER.debug("装了appflux时getUpgrades被调用这不应该发生");
return UpgradeInventories.empty();
}
}
@ -250,7 +241,6 @@ public abstract class PatternProviderLogicCompatMixin implements IUpgradeableObj
if (this instanceof IUpgradeableObject) {
IUpgradeableObject upgradeableThis = (IUpgradeableObject) this;
upgrades = upgradeableThis.getUpgrades();
Logger.EAP$LOGGER.debug("从appflux获取到升级槽: {}", upgrades != null);
}
} catch (Exception e) {
Logger.EAP$LOGGER.error("获取appflux升级槽失败", e);
@ -262,7 +252,6 @@ public abstract class PatternProviderLogicCompatMixin implements IUpgradeableObj
if (!stack.isEmpty() && stack.getItem() == ModItems.CHANNEL_CARD.get()) {
channel = ChannelCardItem.getChannel(stack);
found = true;
Logger.EAP$LOGGER.info("找到频道卡,频道: {}", channel);
break;
}
}

View File

@ -28,12 +28,8 @@ public class AppfluxPatternProviderLogicMixin {
at = @At("TAIL"))
private void eap$modifyAppfluxUpgradeSlots(IManagedGridNode mainNode, PatternProviderLogicHost host, int patternInventorySize, CallbackInfo ci) {
try {
Logger.EAP$LOGGER.info("AppfluxPatternProviderLogicMixin被调用");
// 只有当appflux存在且不启用我们的升级槽时才修改数量
if (!UpgradeSlotCompat.shouldEnableUpgradeSlots() && UpgradeSlotCompat.shouldEnableChannelCard()) {
Logger.EAP$LOGGER.info("尝试修改appflux升级槽数量为2个");
// 使用反射找到appflux的升级槽字段并替换
try {
Field upgradesField = this.getClass().getDeclaredField("af_$upgrades");
@ -41,8 +37,6 @@ public class AppfluxPatternProviderLogicMixin {
IUpgradeInventory currentUpgrades = (IUpgradeInventory) upgradesField.get(this);
if (currentUpgrades != null) {
Logger.EAP$LOGGER.info("找到appflux升级槽当前大小: {}", currentUpgrades.size());
// 创建新的2槽升级槽
IUpgradeInventory newUpgrades = UpgradeInventories.forMachine(
host.getTerminalIcon().getItem(),
@ -66,7 +60,6 @@ public class AppfluxPatternProviderLogicMixin {
// 替换升级槽
upgradesField.set(this, newUpgrades);
Logger.EAP$LOGGER.info("成功将appflux升级槽替换为2个槽");
}
} catch (Exception e) {
Logger.EAP$LOGGER.error("反射修改appflux升级槽失败", e);

View File

@ -6,7 +6,6 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Supplier;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
@ -33,8 +32,6 @@ public final class ConfigParsingUtils {
private static volatile Map<String, Boolean> blacklistResultCache = new HashMap<>();
private static volatile Map<String, Double> multiplierResultCache = new HashMap<>();
private static final Object CACHE_LOCK = new Object();
private static final AtomicLong callCounter = new AtomicLong(0);
private static final long CHECK_INTERVAL = 100;
/*
初始化缓存在模组加载时调用
@ -121,7 +118,6 @@ public final class ConfigParsingUtils {
if (blockId == null || BLACKLIST_SUPPLIER.get() == null || BLACKLIST_SUPPLIER.get().length == 0) {
return false;
}
checkConfigChange();
return blacklistResultCache.computeIfAbsent(blockId, id ->
getCachedBlacklist().values().stream().anyMatch(p -> p.matcher(id).matches())
);
@ -134,7 +130,6 @@ public final class ConfigParsingUtils {
if (blockId == null || MULTIPLIERS_SUPPLIER.get() == null || MULTIPLIERS_SUPPLIER.get().length == 0) {
return 1.0;
}
checkConfigChange();
return multiplierResultCache.computeIfAbsent(blockId, id -> {
double maxMultiplier = 1.0;
for (MultiplierEntry me : getCachedMultiplierEntries().values()) {
@ -213,22 +208,6 @@ public final class ConfigParsingUtils {
}
}
/**
* 100 次调用检查配置是否变化
*/
private static void checkConfigChange() {
if (callCounter.incrementAndGet() % CHECK_INTERVAL == 0) {
String[] currentBlacklist = BLACKLIST_SUPPLIER.get();
String[] currentMultipliers = MULTIPLIERS_SUPPLIER.get();
synchronized (CACHE_LOCK) {
if (cachedBlacklistSourceSnapshot == null || !Arrays.equals(cachedBlacklistSourceSnapshot, currentBlacklist) ||
cachedMultiplierSourceSnapshot == null || !Arrays.equals(cachedMultiplierSourceSnapshot, currentMultipliers)) {
reload();
}
}
}
}
/**
* 清空缓存下一次获取时将重新解析
*/
@ -240,7 +219,6 @@ public final class ConfigParsingUtils {
cachedMultiplierSourceSnapshot = null;
blacklistResultCache.clear();
multiplierResultCache.clear();
callCounter.set(0);
}
}
}

View File

@ -9,7 +9,6 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 用于计算实体加速器的能耗与加速倍率的工具类
@ -17,12 +16,8 @@ import java.util.concurrent.atomic.AtomicInteger;
public final class PowerUtils {
private static final int[] VALID_MULTIPLIERS = {2, 4, 8, 16, 32, 64, 128, 256, 512, 1024};
private static final int[] VALID_ENERGY_CARD_COUNTS = {0, 1, 2, 3, 4, 5, 6, 7, 8};
private static final AtomicInteger checkCounter = new AtomicInteger(0); // 原子计数器
private static final int CHECK_COUNTER_THRESHOLD = 100; // 配置检查阈值
private static final int CHECK_COUNTER_RESET_THRESHOLD = 10000; // 计数器重置阈值
private static volatile Map<Integer, Map<Integer, Double>> powerCache = new HashMap<>();
private static volatile Map<Integer, Double> ratioCache = new HashMap<>();
private static volatile int lastEntityTickerCost = -1;
// 静态初始化块预计算缓存
static {
@ -34,7 +29,7 @@ public final class PowerUtils {
/**
* 初始化所有可能的缓存条目
*/
private static void initializeCaches() {
public static void initializeCaches() {
synchronized (PowerUtils.class) {
powerCache.clear();
ratioCache.clear();
@ -54,7 +49,6 @@ public final class PowerUtils {
}
powerCache.put(product, energyCardMap);
}
lastEntityTickerCost = ModConfig.INSTANCE.entityTickerCost;
}
}
@ -131,17 +125,6 @@ public final class PowerUtils {
*/
public static double getCachedPower(int product, int energyCardCount) {
if (product <= 1) return 0.0;
// 100 次调用检查一次配置
if (checkCounter.getAndIncrement() % CHECK_COUNTER_THRESHOLD == 0) {
checkCounter.set(checkCounter.get() % CHECK_COUNTER_RESET_THRESHOLD);
if (lastEntityTickerCost != ModConfig.INSTANCE.entityTickerCost) {
synchronized (PowerUtils.class) {
if (lastEntityTickerCost != ModConfig.INSTANCE.entityTickerCost) {
initializeCaches();
}
}
}
}
Map<Integer, Double> energyCardMap = powerCache.get(product);
if (energyCardMap == null) return 0.0;
Double cachedPower = energyCardMap.get(energyCardCount);