feat: 实体加速器
This commit is contained in:
parent
d95b8ff049
commit
0b50dfc66c
|
|
@ -1,11 +1,14 @@
|
|||
package com.extendedae_plus;
|
||||
|
||||
import appeng.init.client.InitScreens;
|
||||
import appeng.menu.locator.MenuLocators;
|
||||
import com.extendedae_plus.client.ClientProxy;
|
||||
import com.extendedae_plus.config.ModConfigs;
|
||||
import com.extendedae_plus.init.*;
|
||||
import com.extendedae_plus.menu.EntitySpeedTickerMenu;
|
||||
import com.extendedae_plus.menu.locator.CuriosItemLocator;
|
||||
import com.extendedae_plus.network.ModNetwork;
|
||||
import com.extendedae_plus.screen.EntitySpeedTickerScreen;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.client.event.ModelEvent;
|
||||
|
|
@ -65,6 +68,8 @@ public class ExtendedAEPlus {
|
|||
private void commonSetup(final FMLCommonSetupEvent event) {
|
||||
// 注册本模组网络通道与数据包
|
||||
event.enqueueWork(() -> {
|
||||
// 注册升级卡
|
||||
new UpgradeCards(event);
|
||||
ModNetwork.register();
|
||||
// 注册自定义 Curios 宿主定位器,便于将菜单宿主信息在服务端与客户端间同步
|
||||
MenuLocators.register(CuriosItemLocator.class, CuriosItemLocator::writeToPacket, CuriosItemLocator::readFromPacket);
|
||||
|
|
@ -93,6 +98,11 @@ public class ExtendedAEPlus {
|
|||
// 直接在此处执行客户端一次性注册(UI/屏幕/渲染器绑定)
|
||||
// 注册客户端配置界面
|
||||
ClientProxy.registerConfigScreen();
|
||||
|
||||
InitScreens.register(ModMenuTypes.ENTITY_TICKER_MENU.get(),
|
||||
EntitySpeedTickerScreen<EntitySpeedTickerMenu>::new,
|
||||
"/screens/entity_speed_ticker.json");
|
||||
|
||||
// 菜单 -> 屏幕 绑定
|
||||
ClientProxy.registerMenuScreens();
|
||||
}
|
||||
|
|
@ -101,6 +111,8 @@ public class ExtendedAEPlus {
|
|||
public static void onRegisterGeometryLoaders(final ModelEvent.RegisterGeometryLoaders evt) {
|
||||
try {
|
||||
ClientProxy.initBuiltInModels();
|
||||
// 注册 AE2 部件模型(例如 entity_ticker_part_item),仿照 CrazyAddons 的做法
|
||||
ModItems.registerPartModels();
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,251 @@
|
|||
package com.extendedae_plus.ae.parts;
|
||||
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.config.PowerMultiplier;
|
||||
import appeng.api.networking.GridFlags;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.ticking.IGridTickable;
|
||||
import appeng.api.networking.ticking.TickRateModulation;
|
||||
import appeng.api.networking.ticking.TickingRequest;
|
||||
import appeng.api.parts.IPartCollisionHelper;
|
||||
import appeng.api.parts.IPartItem;
|
||||
import appeng.api.parts.IPartModel;
|
||||
import appeng.api.upgrades.IUpgradeableObject;
|
||||
import appeng.core.definitions.AEItems;
|
||||
import appeng.items.parts.PartModels;
|
||||
import appeng.menu.MenuOpener;
|
||||
import appeng.menu.locator.MenuLocators;
|
||||
import appeng.parts.automation.UpgradeablePart;
|
||||
import appeng.parts.p2p.P2PModels;
|
||||
import com.extendedae_plus.ExtendedAEPlus;
|
||||
import com.extendedae_plus.init.ModMenuTypes;
|
||||
import com.extendedae_plus.menu.EntitySpeedTickerMenu;
|
||||
import com.extendedae_plus.util.PowerUtils;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.MenuProvider;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityTicker;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* EntitySpeedTickerPart 是一个可升级的 AE2 部件<p>
|
||||
* 该部件可以加速目标方块实体的 tick 速率,消耗 AE 网络能量,并支持加速卡升级<p>
|
||||
* 功能受<a href="https://github.com/GilbertzRivi/crazyae2addons">Crazy AE2 Addons</a>启发
|
||||
*/
|
||||
public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTickable, MenuProvider, IUpgradeableObject {
|
||||
// 当前打开的菜单实例(如果有)
|
||||
public EntitySpeedTickerMenu menu;
|
||||
|
||||
// P2P 模型,用于渲染部件的外观
|
||||
private static final P2PModels MODELS = new P2PModels(
|
||||
new ResourceLocation(ExtendedAEPlus.MODID, "part/entity_speed_ticker_part"));
|
||||
|
||||
/**
|
||||
* 获取该部件的所有模型(用于渲染)
|
||||
* @return 模型列表
|
||||
*/
|
||||
@PartModels
|
||||
public static List<IPartModel> getModels() {
|
||||
return MODELS.getModels();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造函数,初始化部件并设置网络节点属性
|
||||
* @param partItem 部件物品
|
||||
*/
|
||||
public EntitySpeedTickerPart(IPartItem<?> partItem) {
|
||||
super(partItem);
|
||||
// 设置网络节点属性:需要通道、空闲功耗为1,并注册为 IGridTickable 服务
|
||||
this.getMainNode()
|
||||
.setFlags(GridFlags.REQUIRE_CHANNEL)
|
||||
.setIdlePowerUsage(1)
|
||||
.addService(IGridTickable.class, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前状态下的静态模型(用于渲染)
|
||||
* @return 当前状态的模型
|
||||
*/
|
||||
public IPartModel getStaticModels() {
|
||||
return MODELS.getModel(this.isPowered(), this.isActive());
|
||||
}
|
||||
|
||||
/**
|
||||
* 当玩家激活部件(右键)时调用,打开自定义菜单
|
||||
* @param player 玩家
|
||||
* @param hand 手
|
||||
* @param pos 点击位置
|
||||
* @return 总是返回 true,表示激活成功
|
||||
*/
|
||||
@Override
|
||||
public boolean onPartActivate(Player player, InteractionHand hand, Vec3 pos) {
|
||||
// 仅在服务端打开菜单
|
||||
if (!player.getCommandSenderWorld().isClientSide()) {
|
||||
MenuOpener.open(ModMenuTypes.ENTITY_TICKER_MENU.get(), player, MenuLocators.forPart(this));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 定义部件的碰撞箱(用于物理碰撞和渲染)
|
||||
* @param bch 碰撞辅助器
|
||||
*/
|
||||
@Override
|
||||
public void getBoxes(IPartCollisionHelper bch) {
|
||||
bch.addBox(5, 5, 12, 11, 11, 13);
|
||||
bch.addBox(3, 3, 13, 13, 13, 14);
|
||||
bch.addBox(2, 2, 14, 14, 14, 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取定时请求,决定本部件多久 tick 一次
|
||||
* @param iGridNode 网络节点
|
||||
* @return TickingRequest 对象
|
||||
*/
|
||||
@Override
|
||||
public TickingRequest getTickingRequest(IGridNode iGridNode) {
|
||||
// 每 1 tick 执行一次
|
||||
return new TickingRequest(1, 1, false, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当升级卡数量发生变化时调用,通知菜单更新
|
||||
*/
|
||||
@Override
|
||||
public void upgradesChanged() {
|
||||
if (this.menu != null) {
|
||||
// 使用 AE2 风格:当升级发生变化时让菜单广播变化(槽/数据会被同步),客户端会基于槽内容重新计算并刷新界面
|
||||
this.menu.broadcastChanges();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 网络定时回调,每次 tick 时调用
|
||||
* @param iGridNode 网络节点
|
||||
* @param ticksSinceLastCall 距离上次调用经过的 tick 数
|
||||
* @return TickRateModulation.IDLE 表示继续保持当前 tick 速率
|
||||
*/
|
||||
@Override
|
||||
public TickRateModulation tickingRequest(IGridNode iGridNode, int ticksSinceLastCall) {
|
||||
// 获取目标方块实体(本部件朝向的方块)
|
||||
BlockEntity target = getLevel().getBlockEntity(getBlockEntity().getBlockPos().relative(getSide()));
|
||||
// 仅在目标存在且部件处于激活状态时执行加速
|
||||
if (target != null && isActive()) {
|
||||
ticker(target);
|
||||
}
|
||||
return TickRateModulation.IDLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 以指定速度对目标方块实体进行 tick 操作
|
||||
* @param blockEntity 需要被 tick 的方块实体
|
||||
* @param <T> 方块实体类型
|
||||
*/
|
||||
private <T extends BlockEntity> void ticker(@NotNull T blockEntity) {
|
||||
if (this.getGridNode() == null
|
||||
|| this.getMainNode() == null
|
||||
|| this.getMainNode().getGrid() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// String id = Objects.requireNonNull(ForgeRegistries.BLOCKS.getKey(blockEntity.getBlockState().getBlock())).toString();
|
||||
|
||||
// 获取方块实体的位置
|
||||
BlockPos pos = blockEntity.getBlockPos();
|
||||
if (blockEntity.getLevel() == null) return;
|
||||
|
||||
// 获取该方块实体的 Ticker
|
||||
@SuppressWarnings("unchecked")
|
||||
BlockEntityTicker<T> blockEntityTicker = this.getLevel()
|
||||
.getBlockState(pos)
|
||||
.getTicker(this.getLevel(), (BlockEntityType<T>) blockEntity.getType());
|
||||
if (blockEntityTicker == null) return;
|
||||
|
||||
int speedCardCount = getUpgrades().getInstalledUpgrades(AEItems.SPEED_CARD);
|
||||
int energyCardCount = getUpgrades().getInstalledUpgrades(AEItems.ENERGY_CARD);
|
||||
|
||||
// 计算本次 tick 所需能量
|
||||
// - 基础消耗为 512
|
||||
// - 加速卡的数量对能耗有分段增长:
|
||||
// 0: 无增长
|
||||
// 1: 翻倍
|
||||
// 2-6: 指数增长(较快)
|
||||
// 7-8: 幂级数增长(极高)
|
||||
// 使用工具类统一计算增长因子与原始功耗,并从网络中抽取对应能量
|
||||
double requiredPower = PowerUtils.getFinalPower(speedCardCount, energyCardCount);
|
||||
|
||||
// 先模拟提取以检查网络中是否有足够能量,再真正抽取
|
||||
double simulated = getMainNode().getGrid().getEnergyService()
|
||||
.extractAEPower(requiredPower, Actionable.SIMULATE, PowerMultiplier.CONFIG);
|
||||
if (simulated < requiredPower) return;
|
||||
|
||||
double extractedPower = getMainNode().getGrid().getEnergyService()
|
||||
.extractAEPower(requiredPower, Actionable.MODULATE, PowerMultiplier.CONFIG);
|
||||
if (extractedPower < requiredPower) return;
|
||||
|
||||
// 计算加速倍数:基于 2 的次方,并把 8 张映射到最大 1024x(2^10)
|
||||
int speed = PowerUtils.getSpeedMultiplier(speedCardCount);
|
||||
|
||||
// 执行 tick 操作
|
||||
for (int i = 0; i < speed - 1; i++) {
|
||||
blockEntityTicker.tick(
|
||||
blockEntity.getLevel(),
|
||||
blockEntity.getBlockPos(),
|
||||
blockEntity.getBlockState(),
|
||||
blockEntity
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断部件是否有自定义名称
|
||||
* @return 是否有自定义名称
|
||||
*/
|
||||
@Override
|
||||
public boolean hasCustomName() {
|
||||
return super.hasCustomName();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取部件的显示名称
|
||||
* @return 显示名称
|
||||
*/
|
||||
@Override
|
||||
public @NotNull Component getDisplayName() {
|
||||
return super.getDisplayName();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建自定义菜单(GUI)
|
||||
* @param containerId 容器ID
|
||||
* @param playerInventory 玩家背包
|
||||
* @param player 玩家
|
||||
* @return 菜单实例
|
||||
*/
|
||||
@Override
|
||||
public @Nullable AbstractContainerMenu createMenu(int containerId,
|
||||
@NotNull Inventory playerInventory,
|
||||
@NotNull Player player) {
|
||||
return new EntitySpeedTickerMenu(containerId, playerInventory, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可用的升级卡槽数量
|
||||
* @return 升级卡槽数量
|
||||
*/
|
||||
@Override
|
||||
protected int getUpgradeSlots() {
|
||||
return 8;
|
||||
}
|
||||
}
|
||||
|
|
@ -12,6 +12,8 @@ public final class ModConfigs {
|
|||
public static final ForgeConfigSpec.BooleanValue PATTERN_TERMINAL_SHOW_SLOTS_DEFAULT;
|
||||
public static final ForgeConfigSpec.IntValue SMART_SCALING_MAX_MULTIPLIER;
|
||||
public static final ForgeConfigSpec.IntValue SMART_SCALING_MIN_BENEFIT_FACTOR;
|
||||
public static final ForgeConfigSpec.IntValue EntityTickerCost;
|
||||
|
||||
|
||||
static {
|
||||
ForgeConfigSpec.Builder builder = new ForgeConfigSpec.Builder();
|
||||
|
|
@ -77,6 +79,12 @@ public final class ModConfigs {
|
|||
"影响进入界面时SlotsRow的默认可见性,仅影响客户端显示"
|
||||
)
|
||||
.define("patternTerminalShowSlotsDefault", true);
|
||||
|
||||
|
||||
EntityTickerCost = builder
|
||||
.comment("实体加速器的能量消耗基础值")
|
||||
.defineInRange("EntityTickerCost", 512, 0, Integer.MAX_VALUE);
|
||||
|
||||
builder.pop();
|
||||
COMMON_SPEC = builder.build();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ public final class ModCreativeTabs {
|
|||
output.accept(ModItems.ACCELERATOR_64x.get());
|
||||
output.accept(ModItems.ACCELERATOR_256x.get());
|
||||
output.accept(ModItems.ACCELERATOR_1024x.get());
|
||||
output.accept(ModItems.ENTITY_TICKER_PART_ITEM.get());
|
||||
})
|
||||
.build());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
package com.extendedae_plus.init;
|
||||
|
||||
import appeng.api.parts.IPart;
|
||||
import appeng.api.parts.PartModels;
|
||||
import appeng.items.parts.PartModelsHelper;
|
||||
import com.extendedae_plus.ExtendedAEPlus;
|
||||
import com.extendedae_plus.items.EntitySpeedTickerPartItem;
|
||||
import net.minecraft.world.item.BlockItem;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraftforge.registries.DeferredRegister;
|
||||
|
|
@ -47,4 +51,20 @@ public final class ModItems {
|
|||
"1024x_crafting_accelerator",
|
||||
() -> new BlockItem(ModBlocks.ACCELERATOR_1024x.get(), new Item.Properties())
|
||||
);
|
||||
|
||||
public static final RegistryObject<EntitySpeedTickerPartItem> ENTITY_TICKER_PART_ITEM =
|
||||
ITEMS.register("entity_speed_ticker",
|
||||
() -> new EntitySpeedTickerPartItem(new Item.Properties()));
|
||||
|
||||
/**
|
||||
* 为 PartItem 注册 AE2 部件模型。
|
||||
* 在客户端进行模型/几何体注册时调用。
|
||||
*/
|
||||
public static void registerPartModels() {
|
||||
PartModels.registerModels(
|
||||
PartModelsHelper.createModels(
|
||||
ENTITY_TICKER_PART_ITEM.get().getPartClass().asSubclass(IPart.class)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
package com.extendedae_plus.init;
|
||||
|
||||
import appeng.menu.implementations.MenuTypeBuilder;
|
||||
import com.extendedae_plus.ExtendedAEPlus;
|
||||
import com.extendedae_plus.ae.parts.EntitySpeedTickerPart;
|
||||
import com.extendedae_plus.menu.EntitySpeedTickerMenu;
|
||||
import com.extendedae_plus.menu.NetworkPatternControllerMenu;
|
||||
import net.minecraft.world.inventory.MenuType;
|
||||
import net.minecraftforge.common.extensions.IForgeMenuType;
|
||||
|
|
@ -9,12 +12,19 @@ import net.minecraftforge.registries.ForgeRegistries;
|
|||
import net.minecraftforge.registries.RegistryObject;
|
||||
|
||||
public final class ModMenuTypes {
|
||||
private ModMenuTypes() {}
|
||||
|
||||
public static final DeferredRegister<MenuType<?>> MENUS =
|
||||
DeferredRegister.create(ForgeRegistries.MENU_TYPES, ExtendedAEPlus.MODID);
|
||||
|
||||
private ModMenuTypes() {
|
||||
}
|
||||
|
||||
public static final RegistryObject<MenuType<NetworkPatternControllerMenu>> NETWORK_PATTERN_CONTROLLER =
|
||||
MENUS.register("network_pattern_controller",
|
||||
() -> IForgeMenuType.create(NetworkPatternControllerMenu::new));
|
||||
|
||||
public static final RegistryObject<MenuType<EntitySpeedTickerMenu>> ENTITY_TICKER_MENU =
|
||||
MENUS.register("entity_speed_ticker",
|
||||
() -> MenuTypeBuilder
|
||||
.create(EntitySpeedTickerMenu::new, EntitySpeedTickerPart.class)
|
||||
.build("entity_speed_ticker"));
|
||||
}
|
||||
|
|
|
|||
15
src/main/java/com/extendedae_plus/init/UpgradeCards.java
Normal file
15
src/main/java/com/extendedae_plus/init/UpgradeCards.java
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
package com.extendedae_plus.init;
|
||||
|
||||
import appeng.api.upgrades.Upgrades;
|
||||
import appeng.core.definitions.AEItems;
|
||||
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
|
||||
|
||||
|
||||
public class UpgradeCards {
|
||||
public UpgradeCards(final FMLCommonSetupEvent event) {
|
||||
event.enqueueWork(() -> {
|
||||
Upgrades.add(AEItems.SPEED_CARD, ModItems.ENTITY_TICKER_PART_ITEM.get(), 8, "group.entity_ticker.name");
|
||||
Upgrades.add(AEItems.ENERGY_CARD, ModItems.ENTITY_TICKER_PART_ITEM.get(), 8, "group.entity_ticker.name");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.extendedae_plus.items;
|
||||
|
||||
import appeng.items.parts.PartItem;
|
||||
import com.extendedae_plus.ae.parts.EntitySpeedTickerPart;
|
||||
|
||||
|
||||
public class EntitySpeedTickerPartItem extends PartItem<EntitySpeedTickerPart> {
|
||||
public EntitySpeedTickerPartItem(Properties properties) {
|
||||
super(properties, EntitySpeedTickerPart.class, EntitySpeedTickerPart::new);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
package com.extendedae_plus.menu;
|
||||
|
||||
import appeng.core.definitions.AEItems;
|
||||
import appeng.menu.implementations.UpgradeableMenu;
|
||||
import appeng.menu.slot.OptionalFakeSlot;
|
||||
import com.extendedae_plus.ae.parts.EntitySpeedTickerPart;
|
||||
import com.extendedae_plus.init.ModMenuTypes;
|
||||
import com.extendedae_plus.screen.EntitySpeedTickerScreen;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
|
||||
// 实体加速器菜单,负责与客户端界面同步数据
|
||||
public class EntitySpeedTickerMenu extends UpgradeableMenu<EntitySpeedTickerPart> {
|
||||
// 已安装的速度卡数量
|
||||
public int speedCardCount;
|
||||
// 已安装的能量卡数量
|
||||
public int energyCardCount;
|
||||
|
||||
// 构造方法,初始化菜单并与部件绑定
|
||||
public EntitySpeedTickerMenu(int id, Inventory ip, EntitySpeedTickerPart host) {
|
||||
super(ModMenuTypes.ENTITY_TICKER_MENU.get(), id, ip, host);
|
||||
// 让部件持有当前菜单实例,便于通信
|
||||
getHost().menu = this;
|
||||
}
|
||||
|
||||
// 当服务器数据同步到客户端时调用
|
||||
@Override
|
||||
public void onServerDataSync() {
|
||||
super.onServerDataSync();
|
||||
// 重新统计速度卡和能量卡数量
|
||||
this.speedCardCount = this.getUpgrades().getInstalledUpgrades(AEItems.SPEED_CARD);
|
||||
this.energyCardCount = this.getUpgrades().getInstalledUpgrades(AEItems.ENERGY_CARD);
|
||||
// 如果在客户端,刷新界面
|
||||
if (isClientSide()) {
|
||||
if (Minecraft.getInstance().screen instanceof EntitySpeedTickerScreen screen) {
|
||||
screen.refreshGui();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 当任意槽位发生变化时调用
|
||||
@Override
|
||||
public void onSlotChange(net.minecraft.world.inventory.Slot slot) {
|
||||
super.onSlotChange(slot);
|
||||
// 客户端重新统计卡数量并刷新界面
|
||||
if (isClientSide()) {
|
||||
this.speedCardCount = this.getUpgrades().getInstalledUpgrades(AEItems.SPEED_CARD);
|
||||
this.energyCardCount = this.getUpgrades().getInstalledUpgrades(AEItems.ENERGY_CARD);
|
||||
if (Minecraft.getInstance().screen instanceof EntitySpeedTickerScreen screen) {
|
||||
screen.refreshGui();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void broadcastChanges(){
|
||||
// 遍历所有槽位,清理未启用但有物品显示的 OptionalFakeSlot
|
||||
for (Object o : this.slots) {
|
||||
if (o instanceof OptionalFakeSlot fs) {
|
||||
if (!fs.isSlotEnabled() && !fs.getDisplayStack().isEmpty()) {
|
||||
fs.clearStack();
|
||||
}
|
||||
}
|
||||
}
|
||||
// 调用标准的同步方法,通知监听者数据已更新
|
||||
this.standardDetectAndSendChanges();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package com.extendedae_plus.screen;
|
||||
|
||||
import appeng.client.gui.implementations.UpgradeableScreen;
|
||||
import appeng.client.gui.style.ScreenStyle;
|
||||
import com.extendedae_plus.menu.EntitySpeedTickerMenu;
|
||||
import com.extendedae_plus.util.PowerUtils;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
|
||||
public class EntitySpeedTickerScreen<C extends EntitySpeedTickerMenu> extends UpgradeableScreen<C> {
|
||||
|
||||
public EntitySpeedTickerScreen(
|
||||
EntitySpeedTickerMenu menu, Inventory playerInventory, Component title, ScreenStyle style) {
|
||||
super((C) menu, playerInventory, title, style);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateBeforeRender(){
|
||||
super.updateBeforeRender();
|
||||
textData();
|
||||
}
|
||||
|
||||
public void refreshGui(){
|
||||
textData();
|
||||
}
|
||||
|
||||
private void textData() {
|
||||
int speedCardCount = getMenu().speedCardCount;
|
||||
int energyCardCount = getMenu().energyCardCount;
|
||||
|
||||
double finalPower = PowerUtils.getFinalPower(speedCardCount, energyCardCount);
|
||||
int speed = PowerUtils.getSpeedMultiplier(speedCardCount);
|
||||
double remainingRatio = PowerUtils.getRemainingRatio(energyCardCount);
|
||||
|
||||
setTextContent("speed", Component.translatable("screen.extendedae_plus.entity_speed_ticker.speed", speed));
|
||||
setTextContent("energy", Component.translatable("screen.extendedae_plus.entity_speed_ticker.energy", PowerUtils.formatPower(finalPower)));
|
||||
setTextContent("power_ratio", Component.translatable("screen.extendedae_plus.entity_speed_ticker.power_ratio", PowerUtils.formatPercentage(remainingRatio)));
|
||||
}
|
||||
}
|
||||
130
src/main/java/com/extendedae_plus/util/PowerUtils.java
Normal file
130
src/main/java/com/extendedae_plus/util/PowerUtils.java
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
package com.extendedae_plus.util;
|
||||
|
||||
import com.extendedae_plus.config.ModConfigs;
|
||||
|
||||
/**
|
||||
* 用于计算实体加速器的能耗与加速倍率的工具类
|
||||
*/
|
||||
public final class PowerUtils {
|
||||
private PowerUtils() {}
|
||||
|
||||
/**
|
||||
* 计算加速卡数量对应的加速倍率(返回 2 的幂次方)
|
||||
* 0 张卡 = 1x,8 张卡 = 1024x
|
||||
*/
|
||||
public static int getSpeedMultiplier(int speedCardCount) {
|
||||
if (speedCardCount <= 0) return 1;
|
||||
// 线性映射 0~8 -> 0~10,最大 2^10=1024
|
||||
int exponent = (int) Math.round((10.0 / 8.0) * speedCardCount);
|
||||
exponent = Math.min(exponent, 10);
|
||||
return (int) Math.pow(2, exponent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算加速卡数量对应的能耗增长因子
|
||||
* 0: 1x,1: 2x,2-6: 2^(2*count),7-8: 2^(3*count)
|
||||
*/
|
||||
public static double getGrowthFactor(int speedCardCount) {
|
||||
if (speedCardCount <= 0) return 1.0;
|
||||
if (speedCardCount == 1) return 2.0;
|
||||
if (speedCardCount <= 6) return Math.pow(2.0, 2.0 * speedCardCount);
|
||||
return Math.pow(2.0, 3.0 * speedCardCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算加速卡数量对应的原始能耗(未减免)
|
||||
* @param speedCardCount 加速卡数量
|
||||
* @return 原始能耗
|
||||
*/
|
||||
public static double getRawPower(int speedCardCount) {
|
||||
double base = ModConfigs.EntityTickerCost.get();
|
||||
return base * getGrowthFactor(speedCardCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算能源卡数量对应的能耗减免百分比
|
||||
* 0: 0%,1: 10%,8: 50%,2-7: 0.5*(1-0.7^n)
|
||||
*/
|
||||
public static double getReductionPercent(int energyCardCount) {
|
||||
if (energyCardCount <= 0) return 0.0;
|
||||
if (energyCardCount == 1) return 0.1;
|
||||
if (energyCardCount >= 8) return 0.5;
|
||||
return 0.5 * (1.0 - Math.pow(0.7, energyCardCount));
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算最终能耗(取整,最小为 1)
|
||||
* @param speedCardCount 加速卡数量
|
||||
* @param energyCardCount 能源卡数量
|
||||
* @return 最终能耗(int)
|
||||
*/
|
||||
public static int getFinalPowerDraw(int speedCardCount, int energyCardCount) {
|
||||
double raw = getRawPower(speedCardCount);
|
||||
double reduction = getReductionPercent(energyCardCount);
|
||||
// 与原始实现兼容:raw * (1 - reduction) 后按 0.5 的单位转换(与 AE/FE 换算保持一致)
|
||||
double adjusted = raw * (1.0 - reduction) / 2.0;
|
||||
return (int) Math.max(1, Math.round(adjusted));
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算最终能耗(浮点数)
|
||||
* @param speedCardCount 加速卡数量
|
||||
* @param energyCardCount 能源卡数量
|
||||
* @return 最终能耗(double)
|
||||
*/
|
||||
public static double getFinalPower(int speedCardCount, int energyCardCount) {
|
||||
double raw = getRawPower(speedCardCount);
|
||||
double reduction = getReductionPercent(energyCardCount);
|
||||
// 返回与实际抽取值一致的浮点能耗(包含与原实现一致的 /2 单位转换)
|
||||
return raw * (1.0 - reduction) / 2.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回能源卡减免后剩余的功耗比率(例如 1 张能源卡 -> 0.9)
|
||||
* @param energyCardCount 能源卡数量
|
||||
* @return 剩余功耗比率
|
||||
*/
|
||||
public static double getRemainingRatio(int energyCardCount) {
|
||||
return 1.0 - getReductionPercent(energyCardCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将能耗数字按单位缩写(K/M/G/T/P/E)格式化为更短的字符串
|
||||
* 例如 1500 -> "1.50K", 2000000 -> "2.00M"
|
||||
*/
|
||||
public static String formatPower(double value) {
|
||||
double abs = Math.abs(value);
|
||||
if (abs >= 1e18) return formatWithSuffix(value, 1e18, "E");
|
||||
if (abs >= 1e15) return formatWithSuffix(value, 1e15, "P");
|
||||
if (abs >= 1e12) return formatWithSuffix(value, 1e12, "T");
|
||||
if (abs >= 1e9) return formatWithSuffix(value, 1e9, "G");
|
||||
if (abs >= 1e6) return formatWithSuffix(value, 1e6, "M");
|
||||
if (abs >= 1e3) return formatWithSuffix(value, 1e3, "K");
|
||||
// 小于 1000 直接返回整数形式
|
||||
if (Math.floor(value) == value) {
|
||||
return String.format("%d", (long) value);
|
||||
}
|
||||
return String.format("%.2f", value);
|
||||
}
|
||||
|
||||
private static String formatWithSuffix(double value, double unit, String suffix) {
|
||||
double v = value / unit;
|
||||
// 如果 v 是整数则不显示小数
|
||||
if (Math.abs(v - Math.round(v)) < 1e-9) {
|
||||
return String.format("%d%s", Math.round(v), suffix);
|
||||
}
|
||||
return String.format("%.2f%s", v, suffix);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将剩余功耗比率格式化为百分比字符串(例如 0.9 -> "90%")
|
||||
*/
|
||||
public static String formatPercentage(double ratio) {
|
||||
double pct = ratio * 100.0;
|
||||
// 如果为整数则无小数
|
||||
if (Math.abs(pct - Math.round(pct)) < 1e-9) {
|
||||
return String.format("%d%%", Math.round(pct));
|
||||
}
|
||||
return String.format("%.2f%%", pct);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
{
|
||||
"$schema": "schema.json",
|
||||
"includes": [
|
||||
"common/common.json",
|
||||
"common/player_inventory.json"
|
||||
],
|
||||
"background": {
|
||||
"texture": "guis/blank_background.png",
|
||||
"srcRect": [
|
||||
0,
|
||||
0,
|
||||
176,
|
||||
205
|
||||
]
|
||||
},
|
||||
"text": {
|
||||
"dialog_title": {
|
||||
"text": {
|
||||
"translate": "item.extendedae_plus.entity_speed_ticker"
|
||||
},
|
||||
"position": {
|
||||
"left": 8,
|
||||
"top": 6
|
||||
}
|
||||
},
|
||||
"speed": {
|
||||
"position": {
|
||||
"top": 45,
|
||||
"left": 88
|
||||
},
|
||||
"align": "CENTER"
|
||||
},
|
||||
"energy": {
|
||||
"position": {
|
||||
"top": 60,
|
||||
"left": 88
|
||||
},
|
||||
"align": "CENTER"
|
||||
},
|
||||
"power_ratio": {
|
||||
"position": {
|
||||
"top": 75,
|
||||
"left": 88
|
||||
},
|
||||
"align": "CENTER"
|
||||
}
|
||||
},
|
||||
"widgets": {
|
||||
"toolbox": {
|
||||
"right": -2,
|
||||
"bottom": 50,
|
||||
"width": 68,
|
||||
"height": 68
|
||||
}
|
||||
},
|
||||
"slots": {
|
||||
"TOOLBOX": {
|
||||
"bottom": 42,
|
||||
"right": -10,
|
||||
"grid": "BREAK_AFTER_3COLS"
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
src/main/resources/assets/ae2/textures/guis/blank_background.png
Normal file
BIN
src/main/resources/assets/ae2/textures/guis/blank_background.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
|
|
@ -1,4 +1,9 @@
|
|||
{
|
||||
"item.extendedae_plus.entity_speed_ticker": "Entity Speed Ticker",
|
||||
"screen.extendedae_plus.entity_speed_ticker.energy": "Energy Usage: %s FE/t",
|
||||
"screen.extendedae_plus.entity_speed_ticker.power_ratio": "Power ratio: %s",
|
||||
"screen.extendedae_plus.entity_speed_ticker.speed": "Current speed multiplier: %d",
|
||||
|
||||
"gui.expatternprovider.toggle_slots": "Toggle Slots",
|
||||
"gui.expatternprovider.hide_slots": "Hide Slots",
|
||||
"gui.expatternprovider.show_slots": "Show Slots",
|
||||
|
|
@ -27,6 +32,7 @@
|
|||
"extendedae_plus.tooltip.locked": "Locked: %s"
|
||||
,
|
||||
"screen.extendedae_plus.title": "ExtendedAE Plus Config",
|
||||
|
||||
"config.extendedae_plus.pageMultiplier": "Pattern Provider Page Multiplier",
|
||||
"config.extendedae_plus.pageMultiplier_with_range": "Pattern Provider Page Multiplier (1-64)",
|
||||
"config.extendedae_plus.wirelessMaxRange": "Wireless Max Range",
|
||||
|
|
|
|||
|
|
@ -29,6 +29,11 @@
|
|||
"item.extendedae_plus.256x_crafting_accelerator": "256x并行处理单元",
|
||||
"item.extendedae_plus.1024x_crafting_accelerator": "1024x并行处理单元",
|
||||
|
||||
"item.extendedae_plus.entity_speed_ticker": "实体加速器",
|
||||
"screen.extendedae_plus.entity_speed_ticker.energy": "能耗: %s FE/t",
|
||||
"screen.extendedae_plus.entity_speed_ticker.power_ratio": "功耗比例: %s",
|
||||
"screen.extendedae_plus.entity_speed_ticker.speed": "当前加速倍率: %d",
|
||||
|
||||
"config.jade.plugin_extendedae_plus.wireless_transceiver_info": "无线收发器信息",
|
||||
"config.jade.plugin_extendedae_plus.wt_frequency": "显示频率",
|
||||
"config.jade.plugin_extendedae_plus.wt_master_mode": "显示主/从模式",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"parent": "ae2:item/p2p_tunnel_base",
|
||||
"textures": {
|
||||
"type": "extendedae_plus:part/entity_speed_ticker"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"parent": "ae2:part/p2p/p2p_tunnel_base",
|
||||
"textures": {
|
||||
"type": "extendedae_plus:part/entity_speed_ticker"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
Loading…
Reference in New Issue
Block a user