Skip to content

Commit 8d02d01

Browse files
committed
fix: Fix StackOverflowException when scanning for kitchen #675
1 parent bd7cdf2 commit 8d02d01

1 file changed

Lines changed: 60 additions & 33 deletions

File tree

common/src/main/java/net/blay09/mods/cookingforblockheads/crafting/KitchenMultiblockScanner.java

Lines changed: 60 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package net.blay09.mods.cookingforblockheads.crafting;
22

33
import net.blay09.mods.balm.Balm;
4+
import net.blay09.mods.cookingforblockheads.CookingForBlockheads;
45
import net.blay09.mods.cookingforblockheads.api.Kitchen;
56
import net.blay09.mods.cookingforblockheads.api.KitchenItemProcessor;
67
import net.blay09.mods.cookingforblockheads.api.KitchenItemProvider;
@@ -10,56 +11,82 @@
1011
import net.minecraft.core.BlockPos;
1112
import net.minecraft.core.Direction;
1213
import net.minecraft.world.level.Level;
13-
import net.minecraft.world.level.block.entity.BlockEntity;
14-
import net.minecraft.world.level.block.state.BlockState;
1514

15+
import java.util.ArrayDeque;
1616
import java.util.ArrayList;
1717
import java.util.HashSet;
1818
import java.util.List;
1919
import java.util.Set;
2020

2121
public class KitchenMultiblockScanner {
22-
private final Set<BlockPos> checkedPos = new HashSet<>();
22+
static final int MAX_SCANNED_POSITIONS = 4096;
23+
24+
private final Set<BlockPos> closedList = new HashSet<>();
2325
private final List<KitchenItemProvider> itemProviders = new ArrayList<>();
2426
private final List<KitchenRecipeProvider> recipeProviders = new ArrayList<>();
2527
private final List<KitchenItemProcessor> itemProcessors = new ArrayList<>();
2628

2729
public void findNeighbourCraftingBlocks(Level level, BlockPos pos) {
28-
findNeighbourCraftingBlocks(level, pos, true);
29-
}
30+
final var openList = new ArrayDeque<BlockPos>();
31+
gatherNeighboursInto(openList, closedList, pos, true);
32+
33+
while (!openList.isEmpty()) {
34+
final var current = openList.removeLast();
35+
final var state = level.getBlockState(current);
36+
final var blockEntity = level.getBlockEntity(current);
37+
38+
boolean continueSearch = false;
39+
boolean extendUpwards = false;
40+
if (blockEntity != null) {
41+
var itemProvider = Balm.capabilities().getCapability(blockEntity, ModCapabilities.KITCHEN_ITEM_PROVIDER);
42+
if (itemProvider != null) {
43+
itemProviders.add(itemProvider);
44+
}
45+
46+
final var recipeProvider = Balm.capabilities().getCapability(blockEntity, ModCapabilities.KITCHEN_RECIPE_PROVIDER);
47+
if (recipeProvider != null) {
48+
recipeProviders.add(recipeProvider);
49+
}
3050

31-
public void findNeighbourCraftingBlocks(Level level, BlockPos pos, boolean extendedUpSearch) {
32-
for (Direction direction : Direction.values()) {
33-
int upSearch = (extendedUpSearch && direction == Direction.UP) ? 2 : 1;
34-
for (int n = 1; n <= upSearch; n++) {
35-
BlockPos position = pos.relative(direction, n);
36-
if (!checkedPos.contains(position)) {
37-
checkedPos.add(position);
51+
final var itemProcessor = Balm.capabilities().getCapability(blockEntity, ModCapabilities.KITCHEN_ITEM_PROCESSOR);
52+
if (itemProcessor != null) {
53+
itemProcessors.add(itemProcessor);
54+
}
3855

39-
BlockState state = level.getBlockState(position);
40-
BlockEntity blockEntity = level.getBlockEntity(position);
41-
if (blockEntity != null) {
42-
var itemProvider = Balm.capabilities().getCapability(blockEntity, ModCapabilities.KITCHEN_ITEM_PROVIDER);
43-
if (itemProvider != null) {
44-
itemProviders.add(itemProvider);
45-
}
56+
if (itemProvider != null || recipeProvider != null || itemProcessor != null || state.is(ModBlockTags.KITCHEN_CONNECTORS)) {
57+
continueSearch = true;
58+
extendUpwards = true;
59+
}
60+
} else if (state.is(ModBlockTags.KITCHEN_CONNECTORS)) {
61+
continueSearch = true;
62+
}
4663

47-
final var recipeProvider = Balm.capabilities().getCapability(blockEntity, ModCapabilities.KITCHEN_RECIPE_PROVIDER);
48-
if (recipeProvider != null) {
49-
recipeProviders.add(recipeProvider);
50-
}
64+
if (closedList.size() >= MAX_SCANNED_POSITIONS) {
65+
CookingForBlockheads.logger.warn("Stopping kitchen multiblock search at {}", closedList.size());
66+
break;
67+
}
5168

52-
final var itemProcessor = Balm.capabilities().getCapability(blockEntity, ModCapabilities.KITCHEN_ITEM_PROCESSOR);
53-
if (itemProcessor != null) {
54-
itemProcessors.add(itemProcessor);
55-
}
69+
if (continueSearch) {
70+
gatherNeighboursInto(openList, closedList, current, extendUpwards);
71+
}
72+
}
73+
}
5674

57-
if (itemProvider != null || recipeProvider != null || itemProcessor != null || state.is(ModBlockTags.KITCHEN_CONNECTORS)) {
58-
findNeighbourCraftingBlocks(level, position, true);
59-
}
60-
} else if (state.is(ModBlockTags.KITCHEN_CONNECTORS)) {
61-
findNeighbourCraftingBlocks(level, position, false);
62-
}
75+
private void gatherNeighboursInto(ArrayDeque<BlockPos> openList, Set<BlockPos> closedList, BlockPos pos, boolean extendedUp) {
76+
for (final var direction : Direction.values()) {
77+
if (extendedUp && direction == Direction.UP) {
78+
final var above = pos.above();
79+
if (closedList.add(above)) {
80+
openList.addLast(above);
81+
}
82+
final var aboveTwo = pos.above(2);
83+
if (closedList.add(aboveTwo)) {
84+
openList.addLast(aboveTwo);
85+
}
86+
} else {
87+
final var neighbour = pos.relative(direction);
88+
if (closedList.add(neighbour)) {
89+
openList.addLast(neighbour);
6390
}
6491
}
6592
}

0 commit comments

Comments
 (0)