Skip to content

Commit 2472c9c

Browse files
authored
Optimize MultiPart and ParallelHatch performance (GregTechCEu#2684)
1 parent 085e73f commit 2472c9c

File tree

16 files changed

+134
-107
lines changed

16 files changed

+134
-107
lines changed

src/main/java/com/gregtechceu/gtceu/api/machine/feature/multiblock/IMultiController.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.gregtechceu.gtceu.api.machine.feature.multiblock;
22

3+
import com.gregtechceu.gtceu.api.capability.IParallelHatch;
34
import com.gregtechceu.gtceu.api.machine.feature.IInteractedMachine;
45
import com.gregtechceu.gtceu.api.machine.feature.IMachineFeature;
56
import com.gregtechceu.gtceu.api.machine.multiblock.MultiblockControllerMachine;
@@ -21,6 +22,7 @@
2122
import org.jetbrains.annotations.Nullable;
2223

2324
import java.util.List;
25+
import java.util.Optional;
2426
import java.util.concurrent.locks.Lock;
2527

2628
/**
@@ -139,6 +141,15 @@ default BlockPattern getPattern() {
139141
*/
140142
List<IMultiPart> getParts();
141143

144+
/**
145+
* The instance of {@link IParallelHatch} attached to this Controller.
146+
* <p>
147+
* Note that this will return a singular instance, and will not account for multiple attached IParallelHatches
148+
*
149+
* @return an {@link Optional} of the attached IParallelHatch, empty if one is not attached
150+
*/
151+
Optional<IParallelHatch> getParallelHatch();
152+
142153
/**
143154
* Called from part, when part is invalid due to chunk unload or broken.
144155
*/

src/main/java/com/gregtechceu/gtceu/api/machine/feature/multiblock/IMultiPart.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@
1414
import net.minecraft.world.level.block.state.BlockState;
1515

1616
import org.jetbrains.annotations.Nullable;
17+
import org.jetbrains.annotations.UnmodifiableView;
1718

1819
import java.util.List;
20+
import java.util.SortedSet;
1921

2022
/**
2123
* @author KilaBash
@@ -42,9 +44,12 @@ default boolean canShared() {
4244
boolean isFormed();
4345

4446
/**
45-
* Get all attached controllers
47+
* Get this MultiPart's controllers
48+
*
49+
* @return An Unmodifiable View of the part's controllers
4650
*/
47-
List<IMultiController> getControllers();
51+
@UnmodifiableView
52+
SortedSet<IMultiController> getControllers();
4853

4954
/**
5055
* Called when it was removed from a multiblock.

src/main/java/com/gregtechceu/gtceu/api/machine/multiblock/MultiblockControllerMachine.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.gregtechceu.gtceu.GTCEu;
44
import com.gregtechceu.gtceu.api.block.IMachineBlock;
55
import com.gregtechceu.gtceu.api.block.MetaMachineBlock;
6+
import com.gregtechceu.gtceu.api.capability.IParallelHatch;
67
import com.gregtechceu.gtceu.api.machine.IMachineBlockEntity;
78
import com.gregtechceu.gtceu.api.machine.MetaMachine;
89
import com.gregtechceu.gtceu.api.machine.MultiblockMachineDefinition;
@@ -31,10 +32,12 @@
3132
import lombok.Getter;
3233
import lombok.Setter;
3334
import org.jetbrains.annotations.NotNull;
35+
import org.jetbrains.annotations.Nullable;
3436

3537
import java.util.ArrayList;
3638
import java.util.Collections;
3739
import java.util.List;
40+
import java.util.Optional;
3841
import java.util.Set;
3942
import java.util.concurrent.locks.Lock;
4043
import java.util.concurrent.locks.ReentrantLock;
@@ -54,6 +57,7 @@ public class MultiblockControllerMachine extends MetaMachine implements IMultiCo
5457
MultiblockControllerMachine.class, MetaMachine.MANAGED_FIELD_HOLDER);
5558
private MultiblockState multiblockState;
5659
private final List<IMultiPart> parts = new ArrayList<>();
60+
private @Nullable IParallelHatch parallelHatch = null;
5761
@Getter
5862
@DescSynced
5963
@UpdateListener(methodName = "onPartsUpdated")
@@ -140,6 +144,11 @@ public List<IMultiPart> getParts() {
140144
return this.parts;
141145
}
142146

147+
@Override
148+
public Optional<IParallelHatch> getParallelHatch() {
149+
return Optional.ofNullable(parallelHatch);
150+
}
151+
143152
//////////////////////////////////////
144153
// *** Multiblock LifeCycle ***//
145154
//////////////////////////////////////
@@ -178,6 +187,9 @@ public void onStructureFormed() {
178187
}
179188
this.parts.sort(getDefinition().getPartSorter());
180189
for (var part : parts) {
190+
if (part instanceof IParallelHatch pHatch) {
191+
parallelHatch = pHatch;
192+
}
181193
part.addedToController(this);
182194
}
183195
updatePartPositions();
@@ -189,6 +201,7 @@ public void onStructureInvalid() {
189201
for (IMultiPart part : parts) {
190202
part.removedFromController(this);
191203
}
204+
parallelHatch = null;
192205
parts.clear();
193206
updatePartPositions();
194207
}

src/main/java/com/gregtechceu/gtceu/api/machine/multiblock/WorkableElectricMultiblockMachine.java

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
import java.util.ArrayList;
3232
import java.util.List;
3333
import java.util.Objects;
34-
import java.util.Optional;
3534

3635
import javax.annotation.ParametersAreNonnullByDefault;
3736

@@ -84,13 +83,10 @@ public void onPartUnload() {
8483

8584
@Override
8685
public void addDisplayText(List<Component> textList) {
87-
int numParallels = 0;
88-
Optional<IParallelHatch> optional = this.getParts().stream().filter(IParallelHatch.class::isInstance)
89-
.map(IParallelHatch.class::cast).findAny();
90-
if (optional.isPresent()) {
91-
IParallelHatch parallelHatch = optional.get();
92-
numParallels = parallelHatch.getCurrentParallel();
93-
}
86+
int numParallels = this.getParallelHatch()
87+
.map(IParallelHatch::getCurrentParallel)
88+
.orElse(0);
89+
9490
MultiblockDisplayText.builder(textList, isFormed())
9591
.setWorkingStatus(recipeLogic.isWorkingEnabled(), recipeLogic.isActive())
9692
.addEnergyUsageLine(energyContainer)

src/main/java/com/gregtechceu/gtceu/api/machine/multiblock/part/MultiblockPartMachine.java

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,21 @@
88

99
import com.lowdragmc.lowdraglib.syncdata.annotation.DescSynced;
1010
import com.lowdragmc.lowdraglib.syncdata.annotation.RequireRerender;
11+
import com.lowdragmc.lowdraglib.syncdata.annotation.UpdateListener;
1112
import com.lowdragmc.lowdraglib.syncdata.field.ManagedFieldHolder;
1213

1314
import net.minecraft.MethodsReturnNonnullByDefault;
1415
import net.minecraft.core.BlockPos;
1516
import net.minecraft.server.level.ServerLevel;
1617

17-
import java.util.ArrayList;
18-
import java.util.HashSet;
18+
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
19+
import it.unimi.dsi.fastutil.objects.ReferenceLinkedOpenHashSet;
20+
import org.jetbrains.annotations.UnmodifiableView;
21+
22+
import java.util.Collections;
1923
import java.util.List;
2024
import java.util.Set;
25+
import java.util.SortedSet;
2126

2227
import javax.annotation.ParametersAreNonnullByDefault;
2328

@@ -35,11 +40,12 @@ public class MultiblockPartMachine extends MetaMachine implements IMultiPart {
3540

3641
@DescSynced
3742
@RequireRerender
38-
protected final Set<BlockPos> controllerPositions;
43+
@UpdateListener(methodName = "onControllersUpdated")
44+
protected final Set<BlockPos> controllerPositions = new ObjectOpenHashSet<>(8);
45+
protected final SortedSet<IMultiController> controllers = new ReferenceLinkedOpenHashSet<>(8);
3946

4047
public MultiblockPartMachine(IMachineBlockEntity holder) {
4148
super(holder);
42-
this.controllerPositions = new HashSet<>();
4349
}
4450

4551
//////////////////////////////////////
@@ -61,35 +67,50 @@ public boolean isFormed() {
6167
return !controllerPositions.isEmpty();
6268
}
6369

64-
@Override
65-
public List<IMultiController> getControllers() {
66-
List<IMultiController> result = new ArrayList<>();
67-
for (var blockPos : controllerPositions) {
70+
// Not sure if necessary, but added to match the Controller class
71+
@SuppressWarnings("unused")
72+
public void onControllersUpdated(Set<BlockPos> newPositions, Set<BlockPos> old) {
73+
controllers.clear();
74+
for (BlockPos blockPos : newPositions) {
6875
if (MetaMachine.getMachine(getLevel(), blockPos) instanceof IMultiController controller) {
69-
result.add(controller);
76+
controllers.add(controller);
7077
}
7178
}
72-
return result;
79+
}
80+
81+
@Override
82+
@UnmodifiableView
83+
public SortedSet<IMultiController> getControllers() {
84+
// Necessary to rebuild the set of controllers on client-side
85+
if (controllers.size() != controllerPositions.size()) {
86+
onControllersUpdated(controllerPositions, Collections.emptySet());
87+
}
88+
return Collections.unmodifiableSortedSet(controllers);
7389
}
7490

7591
@Override
7692
public List<IRecipeHandlerTrait> getRecipeHandlers() {
77-
return traits.stream().filter(IRecipeHandlerTrait.class::isInstance).map(IRecipeHandlerTrait.class::cast)
93+
return traits.stream()
94+
.filter(IRecipeHandlerTrait.class::isInstance)
95+
.map(IRecipeHandlerTrait.class::cast)
7896
.toList();
7997
}
8098

8199
@Override
82100
public void onUnload() {
83101
super.onUnload();
84-
var level = getLevel();
85-
for (BlockPos pos : controllerPositions) {
86-
if (level instanceof ServerLevel && level.isLoaded(pos) &&
87-
MetaMachine.getMachine(level, pos) instanceof IMultiController controller) {
88-
removedFromController(controller);
89-
controller.onPartUnload();
102+
if (getLevel() instanceof ServerLevel serverLevel) {
103+
// Need to copy if > 1 so that we can call removedFromController safely without CME
104+
Set<IMultiController> toIter = controllers.size() > 1 ? new ObjectOpenHashSet<>(controllers) : controllers;
105+
for (IMultiController controller : toIter) {
106+
if (serverLevel.isLoaded(controller.self().getPos())) {
107+
removedFromController(controller);
108+
controller.onPartUnload();
109+
}
90110
}
91111
}
92112
controllerPositions.clear();
113+
controllers.clear();
93114
}
94115

95116
//////////////////////////////////////
@@ -99,10 +120,12 @@ public void onUnload() {
99120
@Override
100121
public void removedFromController(IMultiController controller) {
101122
controllerPositions.remove(controller.self().getPos());
123+
controllers.remove(controller);
102124
}
103125

104126
@Override
105127
public void addedToController(IMultiController controller) {
106128
controllerPositions.add(controller.self().getPos());
129+
controllers.add(controller);
107130
}
108131
}

src/main/java/com/gregtechceu/gtceu/api/machine/trait/NotifiableComputationContainer.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public int requestCWUt(int cwut, boolean simulate, @NotNull Collection<IOpticalC
6363
if (machine instanceof IOpticalComputationProvider provider) {
6464
return provider.requestCWUt(cwut, simulate, seen);
6565
} else if (machine instanceof IMultiPart part) {
66-
if (part.getControllers().isEmpty()) {
66+
if (!part.isFormed()) {
6767
return 0;
6868
}
6969
for (IMultiController controller : part.getControllers()) {
@@ -104,7 +104,7 @@ public int getMaxCWUt(@NotNull Collection<IOpticalComputationProvider> seen) {
104104
if (machine instanceof IOpticalComputationProvider provider) {
105105
return provider.getMaxCWUt(seen);
106106
} else if (machine instanceof IMultiPart part) {
107-
if (part.getControllers().isEmpty()) {
107+
if (!part.isFormed()) {
108108
return 0;
109109
}
110110
for (IMultiController controller : part.getControllers()) {
@@ -147,7 +147,7 @@ public boolean canBridge(@NotNull Collection<IOpticalComputationProvider> seen)
147147
if (machine instanceof IOpticalComputationProvider provider) {
148148
return provider.canBridge(seen);
149149
} else if (machine instanceof IMultiPart part) {
150-
if (part.getControllers().isEmpty()) {
150+
if (!part.isFormed()) {
151151
return false;
152152
}
153153
for (IMultiController controller : part.getControllers()) {

src/main/java/com/gregtechceu/gtceu/client/renderer/machine/HPCAPartRenderer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public void renderMachine(List<BakedQuad> quads, MachineDefinition definition, @
7070
super.renderMachine(quads, definition, machine, frontFacing, side, rand, modelFacing, modelState);
7171
if (machine instanceof HPCAComponentPartMachine hpcaComponent) {
7272
ResourceLocation texture, emissiveTexture = null;
73-
var controller = hpcaComponent.getControllers().isEmpty() ? null : hpcaComponent.getControllers().get(0);
73+
var controller = hpcaComponent.isFormed() ? hpcaComponent.getControllers().first() : null;
7474
if (controller != null && (controller instanceof IWorkable workable && workable.isActive())) {
7575
if (hpcaComponent.isDamaged()) {
7676
texture = damagedActiveTexture;

src/main/java/com/gregtechceu/gtceu/client/renderer/machine/RotorHolderMachineRenderer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public void renderMachine(List<BakedQuad> quads, MachineDefinition definition, @
5454
modelState));
5555
if (machine instanceof IRotorHolderMachine rotorHolderMachine) {
5656
var aabb = new AABB(-1, -1, -0.01, 2, 2, 1.01);
57-
if (!rotorHolderMachine.getControllers().isEmpty()) {
57+
if (rotorHolderMachine.isFormed()) {
5858
quads.add(StaticFaceBakery.bakeFace(aabb, modelFacing, ModelFactory.getBlockSprite(BASE_RING),
5959
modelState, -101, 0, true, false));
6060
quads.add(StaticFaceBakery.bakeFace(aabb, modelFacing, ModelFactory.getBlockSprite(BASE_BG),

src/main/java/com/gregtechceu/gtceu/common/data/GTRecipeModifiers.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package com.gregtechceu.gtceu.common.data;
22

33
import com.gregtechceu.gtceu.api.GTValues;
4-
import com.gregtechceu.gtceu.api.capability.IParallelHatch;
54
import com.gregtechceu.gtceu.api.capability.recipe.EURecipeCapability;
65
import com.gregtechceu.gtceu.api.data.medicalcondition.MedicalCondition;
76
import com.gregtechceu.gtceu.api.machine.MetaMachine;
@@ -92,10 +91,7 @@ public class GTRecipeModifiers {
9291
*/
9392
public static @NotNull ModifierFunction hatchParallel(@NotNull MetaMachine machine, @NotNull GTRecipe recipe) {
9493
if (machine instanceof IMultiController controller && controller.isFormed()) {
95-
int parallels = controller.getParts().stream()
96-
.filter(IParallelHatch.class::isInstance)
97-
.map(IParallelHatch.class::cast)
98-
.findAny()
94+
int parallels = controller.getParallelHatch()
9995
.map(hatch -> ParallelLogic.getParallelAmount(machine, recipe, hatch.getCurrentParallel()))
10096
.orElse(1);
10197

src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/part/DataAccessHatchMachine.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,15 +71,13 @@ protected NotifiableItemStackHandler createImportItemHandler() {
7171
@Override
7272
public void onContentsChanged() {
7373
super.onContentsChanged();
74-
rebuildData(!getControllers().isEmpty() && getControllers().get(0) instanceof DataBankMachine);
74+
rebuildData(isFormed() && getControllers().first() instanceof DataBankMachine);
7575
}
7676

7777
@NotNull
7878
@Override
7979
public ItemStack insertItem(int slot, @NotNull ItemStack stack, boolean simulate) {
80-
var controller = DataAccessHatchMachine.this.getControllers().isEmpty() ? null :
81-
DataAccessHatchMachine.this.getControllers().get(0);
82-
boolean isDataBank = controller instanceof DataBankMachine;
80+
boolean isDataBank = isFormed() && getControllers().first() instanceof DataBankMachine;
8381
if (ResearchManager.isStackDataItem(stack, isDataBank) &&
8482
ResearchManager.hasResearchTag(stack)) {
8583
return super.insertItem(slot, stack, simulate);

0 commit comments

Comments
 (0)