Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize MultiPart and ParallelHatch performance #2684

Merged
merged 3 commits into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.gregtechceu.gtceu.api.machine.feature.multiblock;

import com.gregtechceu.gtceu.api.capability.IParallelHatch;
import com.gregtechceu.gtceu.api.machine.feature.IInteractedMachine;
import com.gregtechceu.gtceu.api.machine.feature.IMachineFeature;
import com.gregtechceu.gtceu.api.machine.multiblock.MultiblockControllerMachine;
Expand All @@ -21,6 +22,7 @@
import org.jetbrains.annotations.Nullable;

import java.util.List;
import java.util.Optional;
import java.util.concurrent.locks.Lock;

/**
Expand Down Expand Up @@ -139,6 +141,15 @@ default BlockPattern getPattern() {
*/
List<IMultiPart> getParts();

/**
* The instance of {@link IParallelHatch} attached to this Controller.
* <p>
* Note that this will return a singular instance, and will not account for multiple attached IParallelHatches
*
* @return an {@link Optional} of the attached IParallelHatch, empty if one is not attached
*/
Optional<IParallelHatch> getParallelHatch();

/**
* Called from part, when part is invalid due to chunk unload or broken.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import org.jetbrains.annotations.Nullable;

import java.util.List;
import java.util.SortedSet;

/**
* @author KilaBash
Expand Down Expand Up @@ -44,7 +45,7 @@ default boolean canShared() {
/**
* Get all attached controllers
*/
List<IMultiController> getControllers();
SortedSet<IMultiController> getControllers();

/**
* Called when it was removed from a multiblock.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.gregtechceu.gtceu.GTCEu;
import com.gregtechceu.gtceu.api.block.IMachineBlock;
import com.gregtechceu.gtceu.api.block.MetaMachineBlock;
import com.gregtechceu.gtceu.api.capability.IParallelHatch;
import com.gregtechceu.gtceu.api.machine.IMachineBlockEntity;
import com.gregtechceu.gtceu.api.machine.MetaMachine;
import com.gregtechceu.gtceu.api.machine.MultiblockMachineDefinition;
Expand Down Expand Up @@ -31,10 +32,12 @@
import lombok.Getter;
import lombok.Setter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
Expand All @@ -54,6 +57,7 @@ public class MultiblockControllerMachine extends MetaMachine implements IMultiCo
MultiblockControllerMachine.class, MetaMachine.MANAGED_FIELD_HOLDER);
private MultiblockState multiblockState;
private final List<IMultiPart> parts = new ArrayList<>();
private @Nullable IParallelHatch parallelHatch = null;
@Getter
@DescSynced
@UpdateListener(methodName = "onPartsUpdated")
Expand Down Expand Up @@ -140,6 +144,11 @@ public List<IMultiPart> getParts() {
return this.parts;
}

@Override
public Optional<IParallelHatch> getParallelHatch() {
return Optional.ofNullable(parallelHatch);
}

//////////////////////////////////////
// *** Multiblock LifeCycle ***//
//////////////////////////////////////
Expand Down Expand Up @@ -178,6 +187,9 @@ public void onStructureFormed() {
}
this.parts.sort(getDefinition().getPartSorter());
for (var part : parts) {
if (part instanceof IParallelHatch pHatch) {
parallelHatch = pHatch;
}
part.addedToController(this);
}
updatePartPositions();
Expand All @@ -189,6 +201,7 @@ public void onStructureInvalid() {
for (IMultiPart part : parts) {
part.removedFromController(this);
}
parallelHatch = null;
parts.clear();
updatePartPositions();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

import javax.annotation.ParametersAreNonnullByDefault;

Expand Down Expand Up @@ -84,13 +83,10 @@ public void onPartUnload() {

@Override
public void addDisplayText(List<Component> textList) {
int numParallels = 0;
Optional<IParallelHatch> optional = this.getParts().stream().filter(IParallelHatch.class::isInstance)
.map(IParallelHatch.class::cast).findAny();
if (optional.isPresent()) {
IParallelHatch parallelHatch = optional.get();
numParallels = parallelHatch.getCurrentParallel();
}
int numParallels = this.getParallelHatch()
.map(IParallelHatch::getCurrentParallel)
.orElse(0);

MultiblockDisplayText.builder(textList, isFormed())
.setWorkingStatus(recipeLogic.isWorkingEnabled(), recipeLogic.isActive())
.addEnergyUsageLine(energyContainer)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,20 @@

import com.lowdragmc.lowdraglib.syncdata.annotation.DescSynced;
import com.lowdragmc.lowdraglib.syncdata.annotation.RequireRerender;
import com.lowdragmc.lowdraglib.syncdata.annotation.UpdateListener;
import com.lowdragmc.lowdraglib.syncdata.field.ManagedFieldHolder;

import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;

import java.util.ArrayList;
import java.util.HashSet;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import it.unimi.dsi.fastutil.objects.ReferenceLinkedOpenHashSet;

import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;

import javax.annotation.ParametersAreNonnullByDefault;

Expand All @@ -35,11 +39,12 @@ public class MultiblockPartMachine extends MetaMachine implements IMultiPart {

@DescSynced
@RequireRerender
protected final Set<BlockPos> controllerPositions;
@UpdateListener(methodName = "onControllersUpdated")
protected final Set<BlockPos> controllerPositions = new ObjectOpenHashSet<>(8);
protected final SortedSet<IMultiController> controllers = new ReferenceLinkedOpenHashSet<>(8);

public MultiblockPartMachine(IMachineBlockEntity holder) {
super(holder);
this.controllerPositions = new HashSet<>();
}

//////////////////////////////////////
Expand All @@ -61,35 +66,49 @@ public boolean isFormed() {
return !controllerPositions.isEmpty();
}

@Override
public List<IMultiController> getControllers() {
List<IMultiController> result = new ArrayList<>();
for (var blockPos : controllerPositions) {
// Not sure if necessary, but added to match the Controller class
@SuppressWarnings("unused")
public void onControllersUpdated(Set<BlockPos> newPositions, Set<BlockPos> old) {
controllers.clear();
for (BlockPos blockPos : newPositions) {
if (MetaMachine.getMachine(getLevel(), blockPos) instanceof IMultiController controller) {
result.add(controller);
controllers.add(controller);
}
}
return result;
}

@Override
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also add the @UnmodifiableView annotation here

public SortedSet<IMultiController> getControllers() {
// Necessary to rebuild the set of controllers on client-side
if (controllers.size() != controllerPositions.size()) {
onControllersUpdated(controllerPositions, Collections.emptySet());
}
return Collections.unmodifiableSortedSet(controllers);
}

@Override
public List<IRecipeHandlerTrait> getRecipeHandlers() {
return traits.stream().filter(IRecipeHandlerTrait.class::isInstance).map(IRecipeHandlerTrait.class::cast)
return traits.stream()
.filter(IRecipeHandlerTrait.class::isInstance)
.map(IRecipeHandlerTrait.class::cast)
.toList();
}

@Override
public void onUnload() {
super.onUnload();
var level = getLevel();
for (BlockPos pos : controllerPositions) {
if (level instanceof ServerLevel && level.isLoaded(pos) &&
MetaMachine.getMachine(level, pos) instanceof IMultiController controller) {
removedFromController(controller);
controller.onPartUnload();
if (getLevel() instanceof ServerLevel serverLevel) {
// Need to copy if > 1 so that we can call removedFromController safely without CME
Set<IMultiController> toIter = controllers.size() > 1 ? new ObjectOpenHashSet<>(controllers) : controllers;
for (IMultiController controller : toIter) {
if (serverLevel.isLoaded(controller.self().getPos())) {
removedFromController(controller);
controller.onPartUnload();
}
}
}
controllerPositions.clear();
controllers.clear();
}

//////////////////////////////////////
Expand All @@ -99,10 +118,12 @@ public void onUnload() {
@Override
public void removedFromController(IMultiController controller) {
controllerPositions.remove(controller.self().getPos());
controllers.remove(controller);
}

@Override
public void addedToController(IMultiController controller) {
controllerPositions.add(controller.self().getPos());
controllers.add(controller);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public int requestCWUt(int cwut, boolean simulate, @NotNull Collection<IOpticalC
if (machine instanceof IOpticalComputationProvider provider) {
return provider.requestCWUt(cwut, simulate, seen);
} else if (machine instanceof IMultiPart part) {
if (part.getControllers().isEmpty()) {
if (!part.isFormed()) {
return 0;
}
for (IMultiController controller : part.getControllers()) {
Expand Down Expand Up @@ -104,7 +104,7 @@ public int getMaxCWUt(@NotNull Collection<IOpticalComputationProvider> seen) {
if (machine instanceof IOpticalComputationProvider provider) {
return provider.getMaxCWUt(seen);
} else if (machine instanceof IMultiPart part) {
if (part.getControllers().isEmpty()) {
if (!part.isFormed()) {
return 0;
}
for (IMultiController controller : part.getControllers()) {
Expand Down Expand Up @@ -147,7 +147,7 @@ public boolean canBridge(@NotNull Collection<IOpticalComputationProvider> seen)
if (machine instanceof IOpticalComputationProvider provider) {
return provider.canBridge(seen);
} else if (machine instanceof IMultiPart part) {
if (part.getControllers().isEmpty()) {
if (!part.isFormed()) {
return false;
}
for (IMultiController controller : part.getControllers()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public void renderMachine(List<BakedQuad> quads, MachineDefinition definition, @
super.renderMachine(quads, definition, machine, frontFacing, side, rand, modelFacing, modelState);
if (machine instanceof HPCAComponentPartMachine hpcaComponent) {
ResourceLocation texture, emissiveTexture = null;
var controller = hpcaComponent.getControllers().isEmpty() ? null : hpcaComponent.getControllers().get(0);
var controller = hpcaComponent.isFormed() ? hpcaComponent.getControllers().first() : null;
if (controller != null && (controller instanceof IWorkable workable && workable.isActive())) {
if (hpcaComponent.isDamaged()) {
texture = damagedActiveTexture;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public void renderMachine(List<BakedQuad> quads, MachineDefinition definition, @
modelState));
if (machine instanceof IRotorHolderMachine rotorHolderMachine) {
var aabb = new AABB(-1, -1, -0.01, 2, 2, 1.01);
if (!rotorHolderMachine.getControllers().isEmpty()) {
if (rotorHolderMachine.isFormed()) {
quads.add(StaticFaceBakery.bakeFace(aabb, modelFacing, ModelFactory.getBlockSprite(BASE_RING),
modelState, -101, 15, true, false));
quads.add(StaticFaceBakery.bakeFace(aabb, modelFacing, ModelFactory.getBlockSprite(BASE_BG),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.gregtechceu.gtceu.common.data;

import com.gregtechceu.gtceu.api.GTValues;
import com.gregtechceu.gtceu.api.capability.IParallelHatch;
import com.gregtechceu.gtceu.api.capability.recipe.EURecipeCapability;
import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition;
import com.gregtechceu.gtceu.api.machine.MetaMachine;
Expand Down Expand Up @@ -92,10 +91,7 @@ public class GTRecipeModifiers {
*/
public static @NotNull ModifierFunction hatchParallel(@NotNull MetaMachine machine, @NotNull GTRecipe recipe) {
if (machine instanceof IMultiController controller && controller.isFormed()) {
int parallels = controller.getParts().stream()
.filter(IParallelHatch.class::isInstance)
.map(IParallelHatch.class::cast)
.findAny()
int parallels = controller.getParallelHatch()
.map(hatch -> ParallelLogic.getParallelAmount(machine, recipe, hatch.getCurrentParallel()))
.orElse(1);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,13 @@ protected NotifiableItemStackHandler createImportItemHandler() {
@Override
public void onContentsChanged() {
super.onContentsChanged();
rebuildData(!getControllers().isEmpty() && getControllers().get(0) instanceof DataBankMachine);
rebuildData(isFormed() && getControllers().first() instanceof DataBankMachine);
}

@NotNull
@Override
public ItemStack insertItem(int slot, @NotNull ItemStack stack, boolean simulate) {
var controller = DataAccessHatchMachine.this.getControllers().isEmpty() ? null :
DataAccessHatchMachine.this.getControllers().get(0);
boolean isDataBank = controller instanceof DataBankMachine;
boolean isDataBank = isFormed() && getControllers().first() instanceof DataBankMachine;
if (ResearchManager.isStackDataItem(stack, isDataBank) &&
ResearchManager.hasResearchTag(stack)) {
return super.insertItem(slot, stack, simulate);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,37 +42,39 @@ public OpticalDataHatchMachine(IMachineBlockEntity holder, boolean isTransmitter
@Override
public boolean isRecipeAvailable(@NotNull GTRecipe recipe, @NotNull Collection<IDataAccessHatch> seen) {
seen.add(this);
if (!getControllers().isEmpty()) {
if (isTransmitter()) {
IMultiController controller = getControllers().get(0);
if (!(controller instanceof IWorkable workable) || !workable.isActive()) return false;

List<IDataAccessHatch> dataAccesses = new ArrayList<>();
List<IDataAccessHatch> transmitters = new ArrayList<>();
for (var part : controller.getParts()) {
Block block = part.self().getBlockState().getBlock();
if (part instanceof IDataAccessHatch hatch && PartAbility.DATA_ACCESS.isApplicable(block)) {
dataAccesses.add(hatch);
}
if (part instanceof IDataAccessHatch hatch &&
PartAbility.OPTICAL_DATA_RECEPTION.isApplicable(block)) {
transmitters.add(hatch);
}
}
if (!isFormed()) {
return false;
}

if (isTransmitter()) {
IMultiController controller = getControllers().first();
if (!(controller instanceof IWorkable workable) || !workable.isActive()) return false;

return isRecipeAvailable(dataAccesses, seen, recipe) ||
isRecipeAvailable(transmitters, seen, recipe);
} else {
BlockEntity tileEntity = getLevel().getBlockEntity(getPos().relative(getFrontFacing()));
if (tileEntity == null) return false;

if (tileEntity instanceof OpticalPipeBlockEntity) {
// noinspection DataFlowIssue
IDataAccessHatch cap = tileEntity.getCapability(GTCapability.CAPABILITY_DATA_ACCESS,
getFrontFacing().getOpposite()).orElse(null);
// noinspection ConstantValue
return cap != null && cap.isRecipeAvailable(recipe, seen);
List<IDataAccessHatch> dataAccesses = new ArrayList<>();
List<IDataAccessHatch> transmitters = new ArrayList<>();
for (var part : controller.getParts()) {
Block block = part.self().getBlockState().getBlock();
if (part instanceof IDataAccessHatch hatch && PartAbility.DATA_ACCESS.isApplicable(block)) {
dataAccesses.add(hatch);
}
if (part instanceof IDataAccessHatch hatch &&
PartAbility.OPTICAL_DATA_RECEPTION.isApplicable(block)) {
transmitters.add(hatch);
}
}

return isRecipeAvailable(dataAccesses, seen, recipe) ||
isRecipeAvailable(transmitters, seen, recipe);
} else {
BlockEntity tileEntity = getLevel().getBlockEntity(getPos().relative(getFrontFacing()));
if (tileEntity == null) return false;

if (tileEntity instanceof OpticalPipeBlockEntity) {
// noinspection DataFlowIssue
IDataAccessHatch cap = tileEntity.getCapability(GTCapability.CAPABILITY_DATA_ACCESS,
getFrontFacing().getOpposite()).orElse(null);
// noinspection ConstantValue
return cap != null && cap.isRecipeAvailable(recipe, seen);
}
}
return false;
Expand Down
Loading
Loading