Skip to content

Commit 49b38a0

Browse files
committed
Basic implementation of an offset-aware recipe
1 parent 6e5c015 commit 49b38a0

File tree

5 files changed

+87
-36
lines changed

5 files changed

+87
-36
lines changed

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

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.robotgryphon.compactcrafting.crafting.CraftingHelper;
66
import com.robotgryphon.compactcrafting.field.FieldProjection;
77
import com.robotgryphon.compactcrafting.field.FieldProjectionSize;
8+
import com.robotgryphon.compactcrafting.field.ProjectorHelper;
89
import com.robotgryphon.compactcrafting.recipes.MiniaturizationRecipe;
910
import net.minecraft.block.BlockState;
1011
import net.minecraft.entity.item.ItemEntity;
@@ -115,8 +116,6 @@ public void tick() {
115116
return;
116117
}
117118

118-
doFieldCheck();
119-
120119
if(this.currentRecipe != null)
121120
tickCrafting();
122121
}
@@ -137,38 +136,45 @@ private void doFieldCheck() {
137136
fieldCheckTimeout = 20;
138137
}
139138

140-
private void beginCraft() {
141-
this.isCrafting = true;
142-
}
143-
144139
/**
145140
* Scans the field and attempts to match a recipe that's placed in it.
146141
*/
147142
private void doRecipeScan() {
143+
if(!this.field.isPresent())
144+
return;
145+
146+
FieldProjection fp = this.field.get();
147+
FieldProjectionSize size = fp.getFieldSize();
148+
148149
// Only the primary projector needs to worry about the recipe scan
149150
if(!isMainProjector())
151+
{
152+
// getCenterForSize(IWorldReader world, BlockPos initial, FieldProjectionSize size) {
153+
Optional<BlockPos> center = ProjectorHelper.getCenterForSize(world, pos, size);
154+
BlockPos masterPos = ProjectorHelper.getProjectorLocationForDirection(world, center.get(), Direction.NORTH, size);
155+
156+
FieldProjectorTile masterTile = (FieldProjectorTile) world.getTileEntity(masterPos);
157+
masterTile.doRecipeScan();
150158
return;
159+
}
151160

152-
if (this.field.isPresent()) {
153-
FieldProjection fp = this.field.get();
154-
AxisAlignedBB fieldBounds = fp.getBounds();
161+
AxisAlignedBB fieldBounds = fp.getBounds();
155162

156-
Collection<RegistryObject<MiniaturizationRecipe>> entries = Registration.MINIATURIZATION_RECIPES.getEntries();
157-
if (entries.isEmpty())
158-
return;
163+
Collection<RegistryObject<MiniaturizationRecipe>> entries = Registration.MINIATURIZATION_RECIPES.getEntries();
164+
if (entries.isEmpty())
165+
return;
159166

160-
FieldProjection field = this.field.get();
161-
FieldProjectionSize fieldSize = field.getFieldSize();
167+
FieldProjection field = this.field.get();
162168

163-
Stream<MiniaturizationRecipe> matchedRecipes = entries
164-
.stream()
165-
.map(RegistryObject::get)
166-
.filter(recipe -> recipe.fitsInFieldSize(fieldSize))
167-
.filter(recipe -> recipe.matches(world, fieldSize, fieldBounds));
169+
Stream<MiniaturizationRecipe> matchedRecipes = entries
170+
.stream()
171+
.map(RegistryObject::get)
172+
.filter(recipe -> recipe.fitsInFieldSize(size))
173+
.filter(recipe -> recipe.matches(world, size, fieldBounds));
168174

169-
Optional<MiniaturizationRecipe> matched = matchedRecipes.findFirst();
170-
matched.ifPresent(miniaturizationRecipe -> this.currentRecipe = miniaturizationRecipe);
171-
}
175+
Optional<MiniaturizationRecipe> matched = matchedRecipes.findFirst();
176+
177+
this.currentRecipe = matched.orElse(null);
172178
}
173179

174180
private void tickCrafting() {
@@ -177,7 +183,7 @@ private void tickCrafting() {
177183
AxisAlignedBB fieldBounds = fieldProjection.getBounds();
178184

179185
// Get out, client worlds
180-
if (world.isRemote())
186+
if (world == null || world.isRemote())
181187
return;
182188

183189
List<ItemEntity> catalystEntities = getCatalystsInField(fieldBounds, currentRecipe.catalyst);

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import net.minecraftforge.registries.RegistryBuilder;
2525

2626
import java.util.Collections;
27+
import java.util.HashSet;
2728
import java.util.Set;
2829
import java.util.function.Supplier;
2930

@@ -82,11 +83,18 @@ public class Registration {
8283
{
8384
MiniaturizationRecipe rec = new MiniaturizationRecipe();
8485

85-
Set<BlockPos> layerTemplate = Collections.singleton(new BlockPos(0, 0, 0));
86+
Set<BlockPos> template = new HashSet<>();
87+
BlockPos[] layerBlocks = new BlockPos[] {
88+
new BlockPos(0, 0, 0),
89+
new BlockPos(2, 0, 0),
90+
};
91+
92+
Collections.addAll(template, layerBlocks);
93+
8694

8795
// Example: One obsidian block anywhere in the field can turn into crying obsidian
8896
rec.layers = new IRecipeLayer[]{
89-
new SingleComponentRecipeLayer("O", layerTemplate)
97+
new SingleComponentRecipeLayer("O", template)
9098
};
9199

92100
rec.recalculateDimensions();

src/main/java/com/robotgryphon/compactcrafting/events/EventHandler.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package com.robotgryphon.compactcrafting.events;
22

3+
import com.robotgryphon.compactcrafting.core.BlockUpdateType;
34
import com.robotgryphon.compactcrafting.field.FieldHelper;
45
import net.minecraft.util.math.BlockPos;
56
import net.minecraft.world.IWorld;
7+
import net.minecraftforge.event.world.BlockEvent;
68
import net.minecraftforge.eventbus.api.SubscribeEvent;
79
import net.minecraftforge.fml.common.Mod;
810

@@ -12,7 +14,7 @@
1214
public class EventHandler {
1315

1416
@SubscribeEvent
15-
public static void onBlockPlaced(final net.minecraftforge.event.world.BlockEvent.EntityPlaceEvent blockPlaced) {
17+
public static void onBlockPlaced(final BlockEvent.EntityPlaceEvent blockPlaced) {
1618
// Check if block is in or around a projector field
1719

1820
IWorld world = blockPlaced.getWorld();
@@ -23,6 +25,21 @@ public static void onBlockPlaced(final net.minecraftforge.event.world.BlockEvent
2325
return;
2426

2527
// Send the event position over to the field helper, so any nearby projectors can be notified
26-
FieldHelper.checkBlockPlacement(world, pos);
28+
FieldHelper.checkBlockPlacement(world, pos, BlockUpdateType.PLACE);
29+
}
30+
31+
@SubscribeEvent
32+
public static void onBlockPlaced(final BlockEvent.BreakEvent blockDestroyed) {
33+
// Check if block is in or around a projector field
34+
35+
IWorld world = blockDestroyed.getWorld();
36+
BlockPos pos = blockDestroyed.getPos();
37+
38+
// We don't care about client worlds RN
39+
if(world.isRemote())
40+
return;
41+
42+
// Send the event position over to the field helper, so any nearby projectors can be notified
43+
FieldHelper.checkBlockPlacement(world, pos, BlockUpdateType.REMOVE);
2744
}
2845
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* Provides utilities to help with projector field management.
1515
*/
1616
public abstract class FieldHelper {
17-
public static void checkBlockPlacement(IWorld world, BlockPos pos) {
17+
public static void checkBlockPlacement(IWorld world, BlockPos pos, BlockUpdateType type) {
1818
// Scan all blocks in the maximum field projection range (trying to find projectors)
1919
AxisAlignedBB scanBlocks = new AxisAlignedBB(pos).grow(FieldProjectionSize.maximum().getProjectorDistance() + 1);
2020

@@ -35,7 +35,7 @@ public static void checkBlockPlacement(IWorld world, BlockPos pos) {
3535
continue;
3636
}
3737

38-
tile.handleNearbyBlockUpdate(pos, BlockUpdateType.PLACE);
38+
tile.handleNearbyBlockUpdate(pos, type);
3939
}
4040
}
4141

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

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,11 @@
44
import net.minecraft.block.BlockState;
55
import net.minecraft.util.math.AxisAlignedBB;
66
import net.minecraft.util.math.BlockPos;
7+
import net.minecraft.util.math.MutableBoundingBox;
78
import net.minecraft.util.math.vector.Vector3i;
89
import net.minecraft.world.IWorldReader;
910

10-
import java.util.Collections;
11-
import java.util.Map;
12-
import java.util.Optional;
13-
import java.util.Set;
11+
import java.util.*;
1412
import java.util.stream.Collectors;
1513
import java.util.stream.Stream;
1614

@@ -71,16 +69,38 @@ public boolean matchesFieldLayer(IWorldReader world, MiniaturizationRecipe recip
7169
return false;
7270

7371
// Normalize the block positions so the recipe can match easier
74-
Stream<BlockPos> normalizedPositions = fieldPositions.stream()
72+
BlockPos[] normalizedFilledPositions = fieldPositions.stream()
7573
.map(p -> new BlockPos(
7674
p.getX() - fieldLayer.minX,
7775
p.getY() - fieldLayer.minY,
7876
p.getZ() - fieldLayer.minZ
7977
))
80-
.map(BlockPos::toImmutable);
78+
.map(BlockPos::toImmutable)
79+
.toArray(BlockPos[]::new);
80+
81+
82+
// Create a minimum-filled bounds of blocks in the field
83+
MutableBoundingBox trimmedBounds = new MutableBoundingBox(normalizedFilledPositions[0], normalizedFilledPositions[0]);
84+
for(BlockPos filledPos : normalizedFilledPositions) {
85+
MutableBoundingBox p = new MutableBoundingBox(filledPos, filledPos);
86+
87+
if(!trimmedBounds.intersectsWith(p))
88+
trimmedBounds.expandTo(p);
89+
}
90+
91+
// Whitespace trim done - no padding needed, min and max bounds are already correct
92+
93+
// Check recipe template against padded world layout
94+
95+
8196

8297
// Finally, simply check the normalized template
83-
return normalizedPositions.allMatch(np -> this.filledPositions.contains(np));
98+
return Arrays.stream(normalizedFilledPositions)
99+
.parallel()
100+
.allMatch(np -> {
101+
Vector3i reAdjusted = np.subtract(new Vector3i(trimmedBounds.minX, trimmedBounds.minY, trimmedBounds.minZ));
102+
return this.filledPositions.contains(reAdjusted);
103+
});
84104
}
85105

86106
private Vector3i recalculateDimensions() {

0 commit comments

Comments
 (0)