Skip to content

Commit f50e125

Browse files
committed
First working multi-layer, anywhere-in-field check
1 parent f363622 commit f50e125

File tree

9 files changed

+244
-259
lines changed

9 files changed

+244
-259
lines changed

src/main/java/com/robotgryphon/compactcrafting/blocks/FieldProjectorTile.java

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

3-
import com.robotgryphon.compactcrafting.CompactCrafting;
43
import com.robotgryphon.compactcrafting.core.Registration;
54
import com.robotgryphon.compactcrafting.crafting.CraftingHelper;
65
import com.robotgryphon.compactcrafting.field.FieldProjection;
@@ -19,20 +18,16 @@
1918
import net.minecraft.util.Direction;
2019
import net.minecraft.util.math.AxisAlignedBB;
2120
import net.minecraft.util.math.BlockPos;
22-
import net.minecraft.util.math.vector.Vector3i;
2321
import net.minecraft.world.server.ServerWorld;
2422
import net.minecraftforge.fml.RegistryObject;
2523

26-
import java.util.Collection;
27-
import java.util.List;
28-
import java.util.Optional;
29-
import java.util.Set;
24+
import java.util.*;
3025
import java.util.stream.Collectors;
3126

3227
public class FieldProjectorTile extends TileEntity implements ITickableTileEntity {
3328

3429
private boolean isCrafting = false;
35-
private Optional<FieldProjection> field = Optional.empty();
30+
private FieldProjection field = null;
3631
private MiniaturizationRecipe currentRecipe = null;
3732
private int fieldCheckTimeout = 0;
3833

@@ -54,10 +49,9 @@ public void remove() {
5449
* @return
5550
*/
5651
public Optional<BlockPos> getOppositeProjector() {
57-
if (!field.isPresent())
52+
if (field == null)
5853
return Optional.empty();
5954

60-
FieldProjection field = this.field.get();
6155
FieldProjectionSize size = field.getFieldSize();
6256

6357
int offset = (size.getProjectorDistance() * 2) + 1;
@@ -89,9 +83,8 @@ public Optional<BlockPos> getMainProjectorPosition() {
8983
if (this.isMainProjector())
9084
return Optional.of(this.pos);
9185

92-
if (this.field.isPresent()) {
93-
FieldProjection fp = this.field.get();
94-
BlockPos north = fp.getProjectorInDirection(Direction.NORTH);
86+
if (this.field != null) {
87+
BlockPos north = field.getProjectorInDirection(Direction.NORTH);
9588

9689
return Optional.of(north);
9790
}
@@ -103,21 +96,22 @@ public void invalidateField() {
10396
if(world == null || world.isRemote)
10497
return;
10598

106-
if(this.field.isPresent()) {
107-
BlockPos center = this.field.get().getCenterPosition();
99+
if(field != null) {
100+
BlockPos center = this.field.getCenterPosition();
108101
ProjectionFieldSavedData data = ProjectionFieldSavedData.get((ServerWorld) world);
109102
data.ACTIVE_FIELDS.remove(center);
110103
data.markDirty();
111104

112-
this.field = Optional.empty();
105+
this.field = null;
113106
this.fieldCheckTimeout = 20;
114107
}
115108
}
116109

117110
@Override
118111
public void tick() {
112+
// TODO: Do this in the field projector placement method instead
119113
// If we don't have a valid field, search again
120-
if (!field.isPresent()) {
114+
if (field == null) {
121115
if (fieldCheckTimeout > 0) {
122116
fieldCheckTimeout--;
123117
return;
@@ -127,7 +121,7 @@ public void tick() {
127121
doFieldCheck();
128122

129123
// If we still don't have a valid field, get out of tick logic
130-
if (!field.isPresent())
124+
if (field == null)
131125
return;
132126
}
133127

@@ -143,19 +137,18 @@ private void doFieldCheck() {
143137

144138
Optional<FieldProjection> field = FieldProjection.tryCreateFromPosition(world, this.pos);
145139
if (field.isPresent()) {
146-
this.field = field;
147-
FieldProjection fp = field.get();
140+
this.field = field.get();
148141

149142
if(world != null && !world.isRemote) {
150143
ProjectionFieldSavedData data = ProjectionFieldSavedData.get((ServerWorld) world);
151-
data.ACTIVE_FIELDS.put(fp.getCenterPosition(), ProjectorFieldData.fromInstance(fp));
144+
data.ACTIVE_FIELDS.put(this.field.getCenterPosition(), ProjectorFieldData.fromInstance(this.field));
152145
data.markDirty();
153146
}
154147

155148
return;
156149
}
157150

158-
this.field = Optional.empty();
151+
this.field = null;
159152

160153
// If we didn't find a valid field, restart timer and keep looking
161154
fieldCheckTimeout = 20;
@@ -165,14 +158,13 @@ private void doFieldCheck() {
165158
* Scans the field and attempts to match a recipe that's placed in it.
166159
*/
167160
public void doRecipeScan() {
168-
if(!this.field.isPresent())
161+
if(this.field == null)
169162
return;
170163

171164
if(this.world == null)
172165
return;
173166

174-
FieldProjection fp = this.field.get();
175-
FieldProjectionSize size = fp.getFieldSize();
167+
FieldProjectionSize size = field.getFieldSize();
176168

177169
// Only the primary projector needs to worry about the recipe scan
178170
if(!isMainProjector())
@@ -191,7 +183,13 @@ public void doRecipeScan() {
191183
return;
192184
}
193185

194-
AxisAlignedBB fieldBounds = fp.getBounds();
186+
Collection<RegistryObject<MiniaturizationRecipe>> entries = Registration.MINIATURIZATION_RECIPES.getEntries();
187+
188+
// If there are no registered recipes, then we obv can't match anything - exit early
189+
if (entries.isEmpty())
190+
return;
191+
192+
AxisAlignedBB fieldBounds = field.getBounds();
195193
BlockPos[] nonAirPositions = BlockPos.getAllInBox(fieldBounds)
196194
.filter(p -> !world.isAirBlock(p))
197195
.map(BlockPos::toImmutable)
@@ -202,37 +200,43 @@ public void doRecipeScan() {
202200
// ===========================================================================================================
203201
// RECIPE BEGIN
204202
// ===========================================================================================================
205-
206-
Collection<RegistryObject<MiniaturizationRecipe>> entries = Registration.MINIATURIZATION_RECIPES.getEntries();
207-
if (entries.isEmpty())
208-
return;
209-
210-
Set<MiniaturizationRecipe> matchedRecipes = entries
203+
Set<MiniaturizationRecipe> recipesBoundFitted = entries
211204
.stream()
212205
.map(RegistryObject::get)
213206
.filter(recipe -> recipe.fitsInFieldSize(size))
214207
.filter(recipe -> BlockSpaceUtil.boundsFitsInside(filledBounds, recipe.getDimensions()))
215208
.collect(Collectors.toSet());
216209

217-
BlockPos[] testLocations = new BlockPos[] {
218-
new BlockPos(5, 0, 5),
219-
new BlockPos(7, 0, 5),
220-
new BlockPos(5, 0, 7)
221-
};
210+
// All the recipes we have registered won't fit in the filled bounds -
211+
// blocks were placed in a larger space than the max recipe size
212+
if(recipesBoundFitted.size() == 0)
213+
return;
214+
215+
// BlockPos[] testLocations = new BlockPos[] {
216+
// new BlockPos(5, 0, 5),
217+
// new BlockPos(7, 0, 5),
218+
// new BlockPos(5, 0, 7)
219+
// };
220+
//
221+
// BlockPos[] rotatedCW = BlockSpaceUtil.rotateLayerPositions(testLocations, new Vector3i(5, 0, 5));
222222

223-
BlockPos[] rotatedCW = BlockSpaceUtil.rotateLayerPositions(testLocations, new Vector3i(5, 0, 5));
223+
// Begin recipe dry run - loop, check bottom layer for matches
224+
MiniaturizationRecipe matchedRecipe = null;
225+
for(MiniaturizationRecipe recipe : recipesBoundFitted) {
226+
boolean recipeMatches = recipe.matches(world, field.getFieldSize(), fieldBounds, filledBounds);
227+
if(!recipeMatches)
228+
continue;
224229

225-
CompactCrafting.LOGGER.debug(".");
230+
matchedRecipe = recipe;
231+
break;
232+
}
226233

227-
// Optional<MiniaturizationRecipe> matched = matchedRecipes.findFirst();
228-
//
229-
// this.currentRecipe = matched.orElse(null);
234+
this.currentRecipe = matchedRecipe;
230235
}
231236

232237
private void tickCrafting() {
233-
if (this.field.isPresent()) {
234-
FieldProjection fieldProjection = this.field.get();
235-
AxisAlignedBB fieldBounds = fieldProjection.getBounds();
238+
if (this.field != null) {
239+
AxisAlignedBB fieldBounds = field.getBounds();
236240

237241
// Get out, client worlds
238242
if (world == null || world.isRemote())
@@ -246,11 +250,11 @@ private void tickCrafting() {
246250
this.isCrafting = true;
247251

248252
// We know the "recipe" in the field is an exact match already, so wipe the field
249-
fieldProjection.clearBlocks(world);
253+
field.clearBlocks(world);
250254

251255
CraftingHelper.consumeCatalystItem(catalystEntities.get(0), 1);
252256

253-
BlockPos fieldCenter = field.get().getCenterPosition();
257+
BlockPos fieldCenter = field.getCenterPosition();
254258
for (ItemStack is : currentRecipe.getOutputs()) {
255259
ItemEntity itemEntity = new ItemEntity(world, fieldCenter.getX() + 0.5f, fieldCenter.getY() + 0.5f, fieldCenter.getZ() + 0.5f, is);
256260
world.addEntity(itemEntity);
@@ -295,15 +299,14 @@ private int collectItems(List<ItemEntity> itemsInRange) {
295299
public AxisAlignedBB getRenderBoundingBox() {
296300
// Check - if we have a valid field use the entire field plus space
297301
// Otherwise just use the super implementation
298-
if (this.field.isPresent()) {
299-
FieldProjection fp = this.field.get();
300-
return fp.getBounds().grow(10);
302+
if (this.field != null) {
303+
return field.getBounds().grow(10);
301304
}
302305

303306
return super.getRenderBoundingBox();
304307
}
305308

306309
public Optional<FieldProjection> getField() {
307-
return this.field;
310+
return Optional.ofNullable(this.field);
308311
}
309312
}

src/main/java/com/robotgryphon/compactcrafting/core/Registration.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,8 @@ public class Registration {
9696
Collections.addAll(template, layerBlocks);
9797

9898
rec.setLayers(new IRecipeLayer[]{
99-
new SingleComponentRecipeLayer("O", template)
99+
new SingleComponentRecipeLayer("O", template),
100+
new SingleComponentRecipeLayer("G", template)
100101
});
101102

102103
rec.catalyst = Items.ANVIL;
@@ -105,6 +106,7 @@ public class Registration {
105106
};
106107

107108
rec.addComponent("O", Blocks.OBSIDIAN.getDefaultState());
109+
rec.addComponent("G", Blocks.GLOWSTONE.getDefaultState());
108110

109111
return rec;
110112
});

src/main/java/com/robotgryphon/compactcrafting/crafting/CraftingHelper.java

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,9 @@
22

33
import net.minecraft.entity.item.ItemEntity;
44
import net.minecraft.item.ItemStack;
5-
import net.minecraft.util.math.AxisAlignedBB;
6-
import net.minecraft.util.math.BlockPos;
7-
import net.minecraft.world.IWorldReader;
85

96
public abstract class CraftingHelper {
107

11-
public static boolean hasBlocksInField(IWorldReader world, AxisAlignedBB area) {
12-
// Remove blocks from the world
13-
return BlockPos.getAllInBox(area)
14-
.anyMatch(p -> !world.isAirBlock(p));
15-
}
16-
178
/**
189
* Consumes a number of items from a stack in the world.
1910
*

src/main/java/com/robotgryphon/compactcrafting/field/FieldHelper.java

Lines changed: 3 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,17 @@
44
import com.robotgryphon.compactcrafting.blocks.FieldProjectorTile;
55
import com.robotgryphon.compactcrafting.core.BlockUpdateType;
66
import com.robotgryphon.compactcrafting.core.Registration;
7-
import com.robotgryphon.compactcrafting.recipes.MiniaturizationRecipe;
8-
import com.robotgryphon.compactcrafting.recipes.RecipeHelper;
97
import com.robotgryphon.compactcrafting.world.ProjectionFieldSavedData;
108
import com.robotgryphon.compactcrafting.world.ProjectorFieldData;
11-
import net.minecraft.block.BlockState;
12-
import net.minecraft.fluid.FluidState;
139
import net.minecraft.util.math.AxisAlignedBB;
1410
import net.minecraft.util.math.BlockPos;
1511
import net.minecraft.world.IWorld;
16-
import net.minecraft.world.IWorldReader;
1712
import net.minecraft.world.TickPriority;
1813
import net.minecraft.world.server.ServerWorld;
1914

20-
import java.util.*;
21-
import java.util.stream.Stream;
15+
import java.util.ArrayList;
16+
import java.util.List;
17+
import java.util.Optional;
2218

2319
/**
2420
* Provides utilities to help with projector field management.
@@ -36,7 +32,6 @@ public static void checkBlockPlacement(IWorld world, BlockPos pos, BlockUpdateTy
3632
List<BlockPos> projectors = new ArrayList<>();
3733
int maxDimensions = FieldProjectionSize.maximum().getDimensions();
3834
for(BlockPos center : data.ACTIVE_FIELDS.keySet()) {
39-
// FieldProjectorTile mainTile = (FieldProjectorTile) world.getTileEntity(fielf)
4035
boolean closeEnough = center.withinDistance(pos, maxDimensions);
4136
if(closeEnough) {
4237
ProjectorFieldData field = data.ACTIVE_FIELDS.get(center);
@@ -75,55 +70,5 @@ public static void checkBlockPlacement(IWorld world, BlockPos pos, BlockUpdateTy
7570
}
7671
}
7772

78-
public static Stream<AxisAlignedBB> splitIntoLayers(FieldProjectionSize size, AxisAlignedBB full) {
79-
80-
int s = size.getSize();
81-
BlockPos bottomCenter = new BlockPos(full.getCenter()).down(s);
82-
AxisAlignedBB bottomLayerBounds = new AxisAlignedBB(bottomCenter).grow(s, 0, s);
83-
84-
AxisAlignedBB[] layers = new AxisAlignedBB[size.getDimensions()];
85-
for(int layer = 0; layer < size.getDimensions(); layer++) {
86-
AxisAlignedBB layerBounds = bottomLayerBounds.offset(0, layer, 0);
87-
layers[layer] = layerBounds;
88-
}
89-
90-
return Stream.of(layers);
91-
}
92-
93-
/**
94-
* Converts a layer of a field into its relative recipe component definition.
95-
*
96-
* @param world
97-
* @param recipe
98-
* @param fieldSize
99-
* @param layer
100-
* @return
101-
*/
102-
public static Map<BlockPos, String> remapLayerToRecipe(IWorldReader world, MiniaturizationRecipe recipe, FieldProjectionSize fieldSize, AxisAlignedBB layer) {
103-
Map<BlockPos, String> relativeMap = new HashMap<>();
104-
105-
BlockPos[] filled = BlockPos.getAllInBox(layer)
106-
.filter(pos -> !world.isAirBlock(pos))
107-
.map(BlockPos::toImmutable)
108-
.toArray(BlockPos[]::new);
109-
110-
for(BlockPos pos : filled) {
111-
BlockState state = world.getBlockState(pos);
112-
FluidState fluid = world.getFluidState(pos);
113-
114-
// TODO: Fluid crafting! :D
115-
116-
Optional<String> recipeComponentKey = recipe.getRecipeComponentKey(state);
117-
if(recipeComponentKey.isPresent())
118-
{
119-
// Get relative position in layer and add to map
120-
BlockPos normalized = RecipeHelper.normalizeLayerPosition(layer, pos);
121-
relativeMap.put(normalized, recipeComponentKey.get());
122-
}
123-
}
124-
125-
return relativeMap;
126-
}
127-
12873

12974
}

0 commit comments

Comments
 (0)