Skip to content

Commit fcbfd1f

Browse files
committed
All rotations now check state
1 parent 156988e commit fcbfd1f

File tree

3 files changed

+82
-84
lines changed

3 files changed

+82
-84
lines changed

src/main/java/com/robotgryphon/compactcrafting/recipes/MiniaturizationRecipe.java

Lines changed: 55 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.robotgryphon.compactcrafting.recipes;
22

3-
import com.robotgryphon.compactcrafting.CompactCrafting;
43
import com.robotgryphon.compactcrafting.field.FieldProjectionSize;
54
import com.robotgryphon.compactcrafting.field.MiniaturizationFieldBlockData;
65
import com.robotgryphon.compactcrafting.util.BlockSpaceUtil;
@@ -15,6 +14,7 @@
1514
import net.minecraft.world.IWorldReader;
1615
import net.minecraftforge.registries.ForgeRegistryEntry;
1716

17+
import java.util.Arrays;
1818
import java.util.HashMap;
1919
import java.util.Map;
2020
import java.util.Optional;
@@ -51,12 +51,12 @@ private void recalculateDimensions() {
5151
int x = 0;
5252
int z = 0;
5353

54-
for(IRecipeLayer layer : this.layers) {
54+
for (IRecipeLayer layer : this.layers) {
5555
AxisAlignedBB dimensions = layer.getDimensions();
56-
if(dimensions.getXSize() > x)
56+
if (dimensions.getXSize() > x)
5757
x = (int) Math.ceil(dimensions.getXSize());
5858

59-
if(dimensions.getZSize() > z)
59+
if (dimensions.getZSize() > z)
6060
z = (int) Math.ceil(dimensions.getZSize());
6161
}
6262

@@ -92,17 +92,17 @@ public boolean matches(IWorldReader world, FieldProjectionSize fieldSize, Miniat
9292
// We know that the recipe will at least fit inside the current projection field
9393
AxisAlignedBB filledBounds = fieldBlocks.getFilledBounds();
9494

95-
Rotation[] validRotations = new Rotation[] {
95+
Rotation[] validRotations = new Rotation[]{
9696
Rotation.NONE,
9797
Rotation.CLOCKWISE_90,
9898
Rotation.CLOCKWISE_180,
9999
Rotation.COUNTERCLOCKWISE_90
100100
};
101101

102-
for(Rotation rot : validRotations) {
102+
for (Rotation rot : validRotations) {
103103
boolean matchesRot = checkRotation(world, rot, filledBounds);
104-
if(matchesRot)
105-
return true;
104+
if (matchesRot)
105+
return true;
106106
}
107107

108108
return false;
@@ -113,12 +113,45 @@ private boolean checkRotation(IWorldReader world, Rotation rot, AxisAlignedBB fi
113113

114114
int maxY = (int) dimensions.getYSize();
115115
for (int offset = 0; offset < maxY; offset++) {
116+
Optional<IRecipeLayer> layer = getLayer(offset);
117+
116118
BlockPos[] layerFilled = BlockSpaceUtil.getFilledBlocksByLayer(world, filledBounds, offset);
117-
BlockPos[] layerRotated = BlockSpaceUtil.rotatePositionsInPlace(layerFilled, rot);
118119

119-
boolean layerMatches = doLayerBlocksMatch(world, rot, filledBounds, layerRotated);
120+
// If we have no layer definition do lighter processing
121+
// TODO: Consider changing the layers to a map so we can make air layers null/nonexistent
122+
if(!layer.isPresent() && layerFilled.length > 0) {
123+
// We're being safe here - if there's no layer definition we assume the layer is all-air
124+
return false;
125+
}
126+
127+
Map<BlockPos, BlockPos> layerRotated = BlockSpaceUtil.rotatePositionsInPlace(layerFilled, rot);
128+
129+
// Check that the rotated positions are correct
130+
boolean layerMatches = areLayerPositionsCorrect(filledBounds, layerRotated.values().toArray(new BlockPos[0]));
120131
if (!layerMatches)
121132
return false;
133+
134+
// Check the states are correct
135+
for(BlockPos unrotatedPos : layerFilled) {
136+
BlockPos rotatedPos = layerRotated.get(unrotatedPos);
137+
BlockPos normalizedRotatedPos = BlockSpaceUtil.normalizeLayerPosition(filledBounds, rotatedPos);
138+
139+
BlockState actualState = world.getBlockState(unrotatedPos);
140+
141+
IRecipeLayer l = layer.get();
142+
String requiredComponentKeyForPosition = l.getRequiredComponentKeyForPosition(normalizedRotatedPos);
143+
Optional<String> recipeComponentKey = this.getRecipeComponentKey(actualState);
144+
145+
if(!recipeComponentKey.isPresent()) {
146+
// At this point we don't have a lookup for the state that's at the position
147+
// No match can be made here
148+
return false;
149+
}
150+
151+
boolean statesEqual = recipeComponentKey.get().equals(requiredComponentKeyForPosition);
152+
if(!statesEqual)
153+
return false;
154+
}
122155
}
123156

124157
return true;
@@ -138,8 +171,8 @@ public Optional<BlockState> getRecipeComponent(String i) {
138171
}
139172

140173
public Optional<String> getRecipeComponentKey(BlockState state) {
141-
for(String comp : this.components.keySet()) {
142-
if(components.get(comp) == state)
174+
for (String comp : this.components.keySet()) {
175+
if (components.get(comp) == state)
143176
return Optional.of(comp);
144177
}
145178

@@ -155,16 +188,15 @@ public AxisAlignedBB getDimensions() {
155188
}
156189

157190
/**
158-
* Checks if a given recipe layer matches the filled blocks provided.
191+
* Checks if a given recipe layer matches all the positions for a rotation.
159192
*
160-
* @param world
161193
* @param fieldFilledBounds The boundaries of all filled blocks in the field.
162-
* @param filledPositions The filled positions on the layer to check.
194+
* @param filledPositions The filled positions on the layer to check.
163195
* @return
164196
*/
165-
public boolean doLayerBlocksMatch(IWorldReader world, Rotation rot, AxisAlignedBB fieldFilledBounds, BlockPos[] filledPositions) {
197+
public boolean areLayerPositionsCorrect(AxisAlignedBB fieldFilledBounds, BlockPos[] filledPositions) {
166198
// Recipe layers using this method must define at least one filled space
167-
if(filledPositions.length == 0)
199+
if (filledPositions.length == 0)
168200
return false;
169201

170202
Optional<IRecipeLayer> layer = getRecipeLayerFromPositions(fieldFilledBounds, filledPositions);
@@ -177,7 +209,7 @@ public boolean doLayerBlocksMatch(IWorldReader world, Rotation rot, AxisAlignedB
177209
int requiredFilled = l.getNumberFilledPositions();
178210

179211
// Early exit if we don't have the correct number of blocks in the layer
180-
if(totalFilled != requiredFilled)
212+
if (totalFilled != requiredFilled)
181213
return false;
182214

183215
BlockPos[] fieldNormalizedPositionsFieldOffset = BlockSpaceUtil.normalizeLayerPositions(fieldFilledBounds, filledPositions);
@@ -192,38 +224,13 @@ public boolean doLayerBlocksMatch(IWorldReader world, Rotation rot, AxisAlignedB
192224
.map(BlockPos::toImmutable)
193225
.toArray(BlockPos[]::new);
194226

195-
for(BlockPos normalizedFieldPosition : fieldNormalizedPositionsLayerOffset) {
196-
197-
// normalizedFieldPosition is the normalized position in the ROTATED layout
198-
boolean required = l.isPositionRequired(normalizedFieldPosition);
199-
if(!required) {
200-
// is block set? - if so, exit as a failure
201-
}
202-
203-
String requiredCompKey = l.getRequiredComponentKeyForPosition(normalizedFieldPosition);
204-
if(requiredCompKey == null) {
205-
CompactCrafting.LOGGER.error("Relative position marked as required but the recipe layer did not have a lookup.");
206-
return false;
207-
}
208-
209-
// Optional<String> realComponentInPosition = this.getRecipeComponentKey(state);
210-
//
211-
//
212-
//
213-
// // No lookup defined in the recipe for the state in the position
214-
// if(!realComponentInPosition.isPresent())
215-
// return false;
216-
//
217-
// // Does component match in position?
218-
// if(!realComponentInPosition.get().equals(requiredCompKey))
219-
// return false;
220-
}
221-
222-
return true;
227+
return Arrays.stream(fieldNormalizedPositionsLayerOffset)
228+
.parallel()
229+
.allMatch(l::isPositionRequired);
223230
}
224231

225232
private Optional<IRecipeLayer> getRecipeLayerFromPositions(AxisAlignedBB fieldFilledBounds, BlockPos[] filledPositions) {
226-
if(filledPositions.length == 0)
233+
if (filledPositions.length == 0)
227234
return Optional.empty();
228235

229236
int filledYLevel = filledPositions[0].getY();
@@ -234,7 +241,7 @@ private Optional<IRecipeLayer> getRecipeLayerFromPositions(AxisAlignedBB fieldFi
234241
}
235242

236243
public Optional<IRecipeLayer> getLayer(int y) {
237-
if(y < 0 || y > this.layers.length - 1)
244+
if (y < 0 || y > this.layers.length - 1)
238245
return Optional.empty();
239246

240247
return Optional.of(this.layers[y]);

src/main/java/com/robotgryphon/compactcrafting/util/BlockSpaceUtil.java

Lines changed: 20 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99

1010
import java.util.Arrays;
1111
import java.util.Collection;
12+
import java.util.HashMap;
13+
import java.util.Map;
14+
import java.util.stream.Collectors;
1215
import java.util.stream.Stream;
1316

1417
public abstract class BlockSpaceUtil {
@@ -33,45 +36,32 @@ public static AxisAlignedBB getLayerBoundsByYOffset(AxisAlignedBB fullBounds, in
3336
);
3437
}
3538

36-
public static BlockPos[] rotatePositionsInPlace(BlockPos[] positions) {
39+
public static Map<BlockPos, BlockPos> rotatePositionsInPlace(BlockPos[] positions) {
3740
return rotatePositionsInPlace(positions, Rotation.CLOCKWISE_90);
3841
}
3942

40-
public static BlockPos rotatePositionInPlace(AxisAlignedBB bounds, BlockPos rotated, Rotation rotation) {
41-
Rotation rotBack = rotation.add(Rotation.CLOCKWISE_180);
42-
43-
BlockPos normalized = normalizeLayerPosition(bounds, rotated);
44-
BlockPos rotatedBack = normalized.rotate(rotBack);
45-
BlockPos denormalized = denormalizeLayerPosition(bounds, rotatedBack);
46-
47-
AxisAlignedBB boundsRotated = new AxisAlignedBB(denormalized, denormalized);
48-
BlockPos reNormalized = normalizeLayerPosition(boundsRotated, denormalized);
49-
50-
return denormalizeLayerPosition(bounds, reNormalized);
51-
52-
}
53-
54-
public static BlockPos[] rotatePositionsInPlace(BlockPos[] positions, Rotation rot) {
43+
public static Map<BlockPos, BlockPos> rotatePositionsInPlace(BlockPos[] positions, Rotation rot) {
5544
AxisAlignedBB bounds = getBoundsForBlocks(positions);
5645

5746
// Rotation around a normalized world offset (smallest position is 0,0)
58-
BlockPos[] rotatedPreNormalize = Stream.of(positions)
59-
.map(p -> normalizeLayerPosition(bounds, p))
60-
.map(p -> p.rotate(rot))
61-
.map(p -> denormalizeLayerPosition(bounds, p))
62-
.map(BlockPos::toImmutable)
63-
.toArray(BlockPos[]::new);
47+
Map<BlockPos, BlockPos> rotatedPreNormalize = Stream.of(positions)
48+
.map(p -> new BlockPos[] { p, normalizeLayerPosition(bounds, p) })
49+
.map(p -> new BlockPos[] { p[0], p[1].rotate(rot) })
50+
.map(p -> new BlockPos[] { p[0], denormalizeLayerPosition(bounds, p[1]) })
51+
.map(p -> new BlockPos[] { p[0], p[1].toImmutable() })
52+
.collect(Collectors.toMap(p -> p[0], p -> p[1]));
6453

65-
AxisAlignedBB rotatedBounds = BlockSpaceUtil.getBoundsForBlocks(rotatedPreNormalize);
54+
AxisAlignedBB rotatedBounds = BlockSpaceUtil.getBoundsForBlocks(rotatedPreNormalize.values());
6655

6756
// Re-Normalize the positions to fix the offsetting that rotation does (we're rotating in place)
68-
BlockPos[] reNormalized = normalizeLayerPositions(rotatedBounds, rotatedPreNormalize);
69-
70-
// Rotated positions were normalized before to fix the offsetting that rotation does - denormalize again
71-
return Stream.of(reNormalized)
72-
.map(p -> denormalizeLayerPosition(bounds, p))
73-
.map(BlockPos::toImmutable)
74-
.toArray(BlockPos[]::new);
57+
Map<BlockPos, BlockPos> realPositions = new HashMap<>();
58+
rotatedPreNormalize.forEach((k, rp) -> {
59+
BlockPos reNormalized = normalizeLayerPosition(rotatedBounds, rp);
60+
BlockPos realPosition = denormalizeLayerPosition(bounds, reNormalized);
61+
realPositions.put(k.toImmutable(), realPosition.toImmutable());
62+
});
63+
64+
return realPositions;
7565
}
7666

7767
public static boolean boundsFitsInside(AxisAlignedBB check, AxisAlignedBB space) {

src/test/java/com/robotgryphon/compactcrafting/RotationsTest.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import java.util.Arrays;
1111
import java.util.List;
12+
import java.util.Map;
1213
import java.util.stream.Stream;
1314

1415
public class RotationsTest {
@@ -19,9 +20,9 @@ void SingleBlockRotatesCorrectly() {
1920
new BlockPos(1, 0, 0)
2021
};
2122

22-
BlockPos[] newLocations = BlockSpaceUtil.rotatePositionsInPlace(singleBlock);
23+
Map<BlockPos, BlockPos> newLocations = BlockSpaceUtil.rotatePositionsInPlace(singleBlock);
2324

24-
BlockPos rotatedPos = newLocations[0];
25+
BlockPos rotatedPos = newLocations.get(singleBlock[0]);
2526

2627
Assertions.assertEquals(new BlockPos(0, 0, 1), rotatedPos);
2728
}
@@ -82,10 +83,10 @@ void ComplexShapeRotatesInPlaceCorrectly() {
8283
new BlockPos(2, 0, 2)
8384
};
8485

85-
BlockPos[] rotatedPattern = BlockSpaceUtil.rotatePositionsInPlace(complexPattern, Rotation.CLOCKWISE_90);
86+
Map<BlockPos, BlockPos> rotatedPattern = BlockSpaceUtil.rotatePositionsInPlace(complexPattern, Rotation.CLOCKWISE_90);
8687

8788
List<BlockPos> expected = Arrays.asList(relativeWestPositions);
88-
List<BlockPos> actual = Arrays.asList(rotatedPattern);
89+
List<BlockPos> actual = Arrays.asList(rotatedPattern.values().toArray(new BlockPos[0]));
8990

9091
Assertions.assertTrue(actual.containsAll(expected));
9192
}
@@ -153,10 +154,10 @@ void ComplexShapeRotates180Correctly () {
153154
new BlockPos(5, 0, 0)
154155
};
155156

156-
BlockPos[] rotatedPattern = BlockSpaceUtil.rotatePositionsInPlace(complexPattern, Rotation.CLOCKWISE_180);
157+
Map<BlockPos, BlockPos> rotatedPattern = BlockSpaceUtil.rotatePositionsInPlace(complexPattern, Rotation.CLOCKWISE_180);
157158

158159
List<BlockPos> expected = Arrays.asList(relativeWestPositions);
159-
List<BlockPos> actual = Arrays.asList(rotatedPattern);
160+
List<BlockPos> actual = Arrays.asList(rotatedPattern.values().toArray(new BlockPos[0]));
160161

161162
Assertions.assertTrue(actual.containsAll(expected));
162163
}

0 commit comments

Comments
 (0)