镜像样板供应器性能优化

This commit is contained in:
GaLi 2026-04-07 11:28:38 +08:00
parent 1b37304fc2
commit c90e7ad7e6
3 changed files with 104 additions and 84 deletions

View File

@ -180,6 +180,9 @@ dependencies {
//biggerae2
// runtimeOnly "curse.maven:bigger-ae2-1013772:6587078"
//obs性能监测
implementation "curse.maven:observable-509575:6697124"
implementation "curse.maven:kotlin-for-forge-351264:7471280"
runtimeOnly fileTree(dir: 'libs', includes: ['*.jar'])

View File

@ -37,7 +37,9 @@ public class MirrorPatternProviderBlockEntity extends PatternProviderBlockEntity
private static final String TAG_MASTER = "mirrorMaster";
private static final String TAG_MASTER_DIMENSION = "dimension";
private static final String TAG_MASTER_POS = "pos";
private static final int SYNC_INTERVAL = 2;
private static final int FAST_SYNC_INTERVAL = 2;
private static final int STABLE_SYNC_INTERVAL = 20;
private static final int UNLOADED_MASTER_RETRY_INTERVAL = 40;
private static final int AE2_PATTERN_SLOTS = 9;
private static final int EXTENDED_PATTERN_PROVIDER_BASE_SLOTS = 36;
private static final InternalInventory DISABLED_PATTERN_INVENTORY = new AppEngInternalInventory(0);
@ -48,6 +50,8 @@ public class MirrorPatternProviderBlockEntity extends PatternProviderBlockEntity
@Nullable
private BlockPos masterPos;
private long nextSyncTick = Long.MIN_VALUE;
public MirrorPatternProviderBlockEntity(BlockPos pos, BlockState blockState) {
super(ModBlockEntities.MIRROR_PATTERN_PROVIDER_BE.get(), pos, blockState);
}
@ -74,18 +78,19 @@ public class MirrorPatternProviderBlockEntity extends PatternProviderBlockEntity
}
private void serverTick(ServerLevel level) {
if (Math.floorMod(level.getGameTime() + this.getBlockPos().asLong(), SYNC_INTERVAL) != 0) {
if (level.getGameTime() < this.nextSyncTick) {
return;
}
this.syncBoundMaster();
this.nextSyncTick = level.getGameTime() + this.syncBoundMaster();
}
@Override
public void onReady() {
super.onReady();
if (this.getLevel() instanceof ServerLevel serverLevel) {
this.syncBoundMaster();
this.scheduleImmediateSync();
this.nextSyncTick = serverLevel.getGameTime() + this.syncBoundMaster();
}
}
@ -109,6 +114,7 @@ public class MirrorPatternProviderBlockEntity extends PatternProviderBlockEntity
this.masterDimension = null;
this.masterPos = null;
this.scheduleImmediateSync();
if (data.contains(TAG_MASTER, Tag.TAG_COMPOUND)) {
var masterTag = data.getCompound(TAG_MASTER);
if (masterTag.contains(TAG_MASTER_DIMENSION, Tag.TAG_STRING) && masterTag.contains(TAG_MASTER_POS, Tag.TAG_LONG)) {
@ -148,7 +154,6 @@ public class MirrorPatternProviderBlockEntity extends PatternProviderBlockEntity
return false;
}
this.bindToMaster(master);
this.syncFromMaster(master);
return true;
}
@ -172,13 +177,11 @@ public class MirrorPatternProviderBlockEntity extends PatternProviderBlockEntity
return false;
}
var changed = !Objects.equals(this.masterDimension, master.dimension()) || !Objects.equals(this.masterPos, master.pos());
this.masterDimension = master.dimension();
this.masterPos = master.pos().immutable();
var changed = this.setBoundMaster(master.dimension(), master.pos());
if (changed) {
this.saveChanges();
this.markForClientUpdate();
this.flushStateChanges();
}
this.scheduleImmediateSync();
return true;
}
@ -227,16 +230,21 @@ public class MirrorPatternProviderBlockEntity extends PatternProviderBlockEntity
return Component.translatable("extendedae_plus.message.mirror_pattern_provider.missing_master");
}
private void syncBoundMaster() {
private int syncBoundMaster() {
var master = this.getMaster();
if (master != null) {
this.syncFromMaster(master);
return;
return this.syncFromMaster(master) ? FAST_SYNC_INTERVAL : STABLE_SYNC_INTERVAL;
}
if (this.shouldClearBrokenBinding()) {
this.clearMasterBinding(true);
if (this.clearMasterBinding(true)) {
this.flushStateChanges();
return FAST_SYNC_INTERVAL;
}
return STABLE_SYNC_INTERVAL;
}
return UNLOADED_MASTER_RETRY_INTERVAL;
}
private boolean shouldClearBrokenBinding() {
@ -258,7 +266,7 @@ public class MirrorPatternProviderBlockEntity extends PatternProviderBlockEntity
return !isValidMaster(masterLevel.getBlockEntity(this.masterPos));
}
private void clearMasterBinding(boolean clearMirroredPatterns) {
private boolean clearMasterBinding(boolean clearMirroredPatterns) {
var hadBinding = this.masterDimension != null || this.masterPos != null;
this.masterDimension = null;
@ -269,30 +277,15 @@ public class MirrorPatternProviderBlockEntity extends PatternProviderBlockEntity
changed |= this.clearMirroredPatterns();
}
if (changed) {
this.saveChanges();
this.markForClientUpdate();
}
return changed;
}
private boolean bindToMaster(PatternProviderBlockEntity master) {
var masterLevel = master.getLevel();
if (masterLevel == null) {
return false;
}
private boolean setBoundMaster(ResourceKey<Level> dimension, BlockPos pos) {
var newPos = pos.immutable();
var changed = !Objects.equals(this.masterDimension, dimension) || !Objects.equals(this.masterPos, newPos);
var newDimension = masterLevel.dimension();
var newPos = master.getBlockPos().immutable();
var changed = !Objects.equals(this.masterDimension, newDimension) || !Objects.equals(this.masterPos, newPos);
this.masterDimension = newDimension;
this.masterDimension = dimension;
this.masterPos = newPos;
if (changed) {
this.saveChanges();
this.markForClientUpdate();
}
return changed;
}
@ -314,13 +307,17 @@ public class MirrorPatternProviderBlockEntity extends PatternProviderBlockEntity
}
private boolean syncFromMaster(PatternProviderBlockEntity master) {
var changed = this.bindToMaster(master);
var masterLevel = master.getLevel();
if (masterLevel == null) {
return false;
}
var changed = this.setBoundMaster(masterLevel.dimension(), master.getBlockPos());
changed |= this.syncMirroredSettings(master);
changed |= this.syncMirroredPatterns(master);
if (changed) {
this.saveChanges();
this.markForClientUpdate();
this.flushStateChanges();
}
return changed;
@ -360,72 +357,62 @@ public class MirrorPatternProviderBlockEntity extends PatternProviderBlockEntity
private boolean syncMirroredPatterns(PatternProviderBlockEntity master) {
var mirrorInventory = this.getPatternInventory();
var desiredInventory = this.createDesiredPatternInventory(master);
var masterInventory = asPatternInventory(master.getLogic().getPatternInv());
var mirrorSize = mirrorInventory.size();
var masterSize = masterInventory.size();
var changed = false;
if (this.hasSamePatterns(desiredInventory, mirrorInventory)) {
return false;
for (int slot = 0; slot < mirrorSize; slot++) {
var desiredStack = slot < masterSize ? masterInventory.getStackInSlot(slot) : ItemStack.EMPTY;
var currentStack = mirrorInventory.getStackInSlot(slot);
if (!sameStack(desiredStack, currentStack)) {
mirrorInventory.setItemDirect(slot, desiredStack.isEmpty() ? ItemStack.EMPTY : desiredStack.copy());
changed = true;
}
}
mirrorInventory.fromItemContainerContents(desiredInventory.toItemContainerContents());
this.getLogic().updatePatterns();
return true;
if (changed) {
this.getLogic().updatePatterns();
}
return changed;
}
private boolean clearMirroredPatterns() {
var patternInventory = this.getPatternInventory();
if (this.isPatternInventoryEmpty(patternInventory)) {
return false;
}
var changed = false;
patternInventory.fromItemContainerContents(ItemContainerContents.EMPTY);
this.getLogic().updatePatterns();
return true;
}
private boolean hasSamePatterns(AppEngInternalInventory masterInventory, AppEngInternalInventory mirrorInventory) {
if (masterInventory.size() != mirrorInventory.size()) {
return false;
}
for (int slot = 0; slot < masterInventory.size(); slot++) {
if (!sameStack(masterInventory.getStackInSlot(slot), mirrorInventory.getStackInSlot(slot))) {
return false;
for (int slot = 0; slot < patternInventory.size(); slot++) {
if (!patternInventory.getStackInSlot(slot).isEmpty()) {
patternInventory.setItemDirect(slot, ItemStack.EMPTY);
changed = true;
}
}
return true;
}
private boolean isPatternInventoryEmpty(AppEngInternalInventory inventory) {
for (int slot = 0; slot < inventory.size(); slot++) {
if (!inventory.getStackInSlot(slot).isEmpty()) {
return false;
}
if (changed) {
this.getLogic().updatePatterns();
}
return true;
return changed;
}
private AppEngInternalInventory getPatternInventory() {
return ((MirrorLogic) this.getLogic()).getActualPatternInventory();
}
private AppEngInternalInventory createDesiredPatternInventory(PatternProviderBlockEntity master) {
var desiredInventory = new AppEngInternalInventory(this.getPatternInventory().size());
var masterInventory = asPatternInventory(master.getLogic().getPatternInv());
var copySlotCount = Math.min(masterInventory.size(), desiredInventory.size());
for (int slot = 0; slot < copySlotCount; slot++) {
desiredInventory.setItemDirect(slot, masterInventory.getStackInSlot(slot).copy());
}
return desiredInventory;
}
private static AppEngInternalInventory asPatternInventory(Object inventory) {
return (AppEngInternalInventory) inventory;
}
private void flushStateChanges() {
this.saveChanges();
this.markForClientUpdate();
}
private void scheduleImmediateSync() {
this.nextSyncTick = Long.MIN_VALUE;
}
private static int getMirrorPatternSlotCapacity() {
int pageMultiplier = 1;
try {

View File

@ -5,16 +5,18 @@ import appeng.crafting.CraftingCalculation;
import appeng.crafting.CraftingPlan;
import appeng.crafting.inv.CraftingSimulationState;
import appeng.me.service.CraftingService;
import appeng.api.networking.crafting.ICraftingProvider;
import com.extendedae_plus.api.crafting.ScaledProcessingPattern;
import com.extendedae_plus.api.smartDoubling.ICraftingCalculationExt;
import com.extendedae_plus.api.smartDoubling.ISmartDoublingAwarePattern;
import com.extendedae_plus.config.ModConfigs;
import com.extendedae_plus.util.smartDoubling.PatternScaler;
import com.google.common.collect.Iterables;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
@ -32,6 +34,7 @@ public abstract class CraftingSimulationStateMixin {
Map<IPatternDetails, Long> crafts = accessor.getCrafts();
// 存放最终分配后的 crafts
Map<IPatternDetails, Long> finalCrafts = new LinkedHashMap<>();
Map<IPatternDetails, Integer> providerCountCache = new HashMap<>();
for (Map.Entry<IPatternDetails, Long> entry : crafts.entrySet()) {
IPatternDetails processingPattern = entry.getKey();
@ -60,7 +63,11 @@ public abstract class CraftingSimulationStateMixin {
// 检查是否开启 provider 轮询分配功能
if (ModConfigs.PROVIDER_ROUND_ROBIN_ENABLE.getRaw()) {
CraftingService craftingService = (CraftingService) ((ICraftingCalculationExt) calculation).getGrid().getCraftingService();
int providerCount = Math.max(Iterables.size(craftingService.getProviders(processingPattern)), 1);
int providerCount = Math.max(
providerCountCache.computeIfAbsent(
getProviderCacheKey(processingPattern),
key -> countProvidersUpTo(craftingService.getProviders(key), totalAmount)),
1);
// totalAmount < providerCount 只激活 totalAmount provider
if (totalAmount < providerCount) {
@ -106,4 +113,27 @@ public abstract class CraftingSimulationStateMixin {
crafts.clear();
crafts.putAll(finalCrafts);
}
}
private static IPatternDetails getProviderCacheKey(IPatternDetails pattern) {
if (pattern instanceof ScaledProcessingPattern scaled) {
return scaled.getOriginal();
}
return pattern;
}
private static int countProvidersUpTo(Iterable<ICraftingProvider> providers, long maxNeeded) {
int count = 0;
int limit = maxNeeded <= 0
? Integer.MAX_VALUE
: maxNeeded >= Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) maxNeeded;
for (var ignored : providers) {
count++;
if (count >= limit) {
break;
}
}
return count;
}
}