Skip to content

Commit a8d21e2

Browse files
committed
Basic crafting hologram + animation
1 parent 2c59bc4 commit a8d21e2

File tree

12 files changed

+304
-42
lines changed

12 files changed

+304
-42
lines changed

assets/colors.gif

-1.42 MB
Binary file not shown.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.robotgryphon.compactcrafting.blocks;
2+
3+
import net.minecraft.block.Block;
4+
import net.minecraft.block.BlockState;
5+
import net.minecraft.tileentity.TileEntity;
6+
import net.minecraft.world.IBlockReader;
7+
8+
import javax.annotation.Nullable;
9+
10+
public class FieldCraftingPreviewBlock extends Block {
11+
public FieldCraftingPreviewBlock(Properties properties) {
12+
super(properties);
13+
}
14+
15+
@Override
16+
public boolean hasTileEntity(BlockState state) {
17+
return true;
18+
}
19+
20+
@Nullable
21+
@Override
22+
public TileEntity createTileEntity(BlockState state, IBlockReader world) {
23+
return new FieldCraftingPreviewTile();
24+
}
25+
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
package com.robotgryphon.compactcrafting.blocks;
2+
3+
import com.robotgryphon.compactcrafting.core.Registration;
4+
import com.robotgryphon.compactcrafting.crafting.EnumCraftingState;
5+
import com.robotgryphon.compactcrafting.recipes.MiniaturizationRecipe;
6+
import com.robotgryphon.compactcrafting.recipes.MiniaturizationRecipeManager;
7+
import net.minecraft.block.BlockState;
8+
import net.minecraft.block.Blocks;
9+
import net.minecraft.entity.item.ItemEntity;
10+
import net.minecraft.item.ItemStack;
11+
import net.minecraft.nbt.CompoundNBT;
12+
import net.minecraft.network.NetworkManager;
13+
import net.minecraft.network.play.server.SUpdateTileEntityPacket;
14+
import net.minecraft.tileentity.ITickableTileEntity;
15+
import net.minecraft.tileentity.TileEntity;
16+
import net.minecraft.util.ResourceLocation;
17+
import net.minecraft.util.math.AxisAlignedBB;
18+
import net.minecraft.util.math.BlockPos;
19+
20+
import java.util.Optional;
21+
22+
public class FieldCraftingPreviewTile extends TileEntity implements ITickableTileEntity {
23+
private FieldProjectorTile masterProjector;
24+
private int craftingProgress = 0;
25+
private MiniaturizationRecipe recipe;
26+
27+
public FieldCraftingPreviewTile() {
28+
super(Registration.FIELD_CRAFTING_PREVIEW_TILE.get());
29+
}
30+
31+
public int getProgress() {
32+
return this.craftingProgress;
33+
}
34+
35+
public Optional<MiniaturizationRecipe> getRecipe() {
36+
return Optional.ofNullable(recipe);
37+
}
38+
39+
public void setMasterProjector(FieldProjectorTile master) {
40+
this.masterProjector = master;
41+
this.recipe = master.getCurrentRecipe().get();
42+
this.markDirty();
43+
}
44+
45+
@Override
46+
public AxisAlignedBB getRenderBoundingBox() {
47+
return new AxisAlignedBB(pos).grow(6.0f);
48+
}
49+
50+
@Override
51+
public void tick() {
52+
this.craftingProgress++;
53+
if(world.isRemote) {
54+
return;
55+
}
56+
57+
if(this.craftingProgress >= 200) {
58+
if(masterProjector != null) {
59+
masterProjector.updateCraftingState(EnumCraftingState.DONE);
60+
61+
BlockPos fieldCenter = masterProjector.getField().get().getCenterPosition();
62+
63+
getRecipe().ifPresent(recipe -> {
64+
for (ItemStack is : recipe.getOutputs()) {
65+
ItemEntity itemEntity = new ItemEntity(world, fieldCenter.getX() + 0.5f, fieldCenter.getY() + 0.5f, fieldCenter.getZ() + 0.5f, is);
66+
world.addEntity(itemEntity);
67+
}
68+
});
69+
}
70+
71+
world.setBlockState(pos, Blocks.AIR.getDefaultState());
72+
}
73+
}
74+
75+
@Override
76+
public void read(BlockState state, CompoundNBT compound) {
77+
super.read(state, compound);
78+
79+
craftingProgress = compound.getInt("progress");
80+
81+
if(compound.contains("recipe")) {
82+
ResourceLocation recipeId = new ResourceLocation(compound.getString("recipe"));
83+
this.recipe = MiniaturizationRecipeManager.get(recipeId).orElse(null);
84+
}
85+
}
86+
87+
@Override
88+
public CompoundNBT write(CompoundNBT compound) {
89+
super.write(compound);
90+
if(recipe != null) {
91+
compound.putString("recipe", recipe.getRegistryName().toString());
92+
}
93+
94+
compound.putInt("progress", craftingProgress);
95+
return compound;
96+
}
97+
98+
@Override
99+
public SUpdateTileEntityPacket getUpdatePacket() {
100+
return new SUpdateTileEntityPacket(pos, 1, getUpdateTag());
101+
}
102+
103+
@Override
104+
public CompoundNBT getUpdateTag() {
105+
return write(new CompoundNBT());
106+
}
107+
108+
@Override
109+
public void onDataPacket(NetworkManager net, SUpdateTileEntityPacket packet) {
110+
read(getBlockState(), packet.getNbtCompound());
111+
}
112+
}

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

Lines changed: 51 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.robotgryphon.compactcrafting.core.EnumProjectorColorType;
55
import com.robotgryphon.compactcrafting.core.Registration;
66
import com.robotgryphon.compactcrafting.crafting.CraftingHelper;
7+
import com.robotgryphon.compactcrafting.crafting.EnumCraftingState;
78
import com.robotgryphon.compactcrafting.field.FieldProjection;
89
import com.robotgryphon.compactcrafting.field.FieldProjectionSize;
910
import com.robotgryphon.compactcrafting.field.MiniaturizationFieldBlockData;
@@ -32,7 +33,7 @@
3233

3334
public class FieldProjectorTile extends TileEntity implements ITickableTileEntity {
3435

35-
private boolean isCrafting = false;
36+
private EnumCraftingState craftingState = EnumCraftingState.NOT_MATCHED;
3637
private FieldProjection field = null;
3738
private MiniaturizationRecipe currentRecipe = null;
3839
private int fieldCheckTimeout = 0;
@@ -49,7 +50,7 @@ public Color getProjectionColor(EnumProjectorColorType type) {
4950
int green = base.getGreen();
5051
int blue = base.getBlue();
5152

52-
switch(type) {
53+
switch (type) {
5354
case FIELD:
5455
case SCAN_LINE:
5556
return new Color(red, green, blue, 100);
@@ -120,10 +121,10 @@ public Optional<BlockPos> getMainProjectorPosition() {
120121
}
121122

122123
public void invalidateField() {
123-
if(world == null || world.isRemote)
124+
if (world == null || world.isRemote)
124125
return;
125126

126-
if(field != null) {
127+
if (field != null) {
127128
BlockPos center = this.field.getCenterPosition();
128129
ProjectionFieldSavedData data = ProjectionFieldSavedData.get((ServerWorld) world);
129130
data.ACTIVE_FIELDS.remove(center);
@@ -152,7 +153,7 @@ public void tick() {
152153
return;
153154
}
154155

155-
if(this.currentRecipe != null)
156+
if (this.currentRecipe != null)
156157
tickCrafting();
157158
}
158159

@@ -166,7 +167,7 @@ private void doFieldCheck() {
166167
if (field.isPresent()) {
167168
this.field = field.get();
168169

169-
if(world != null && !world.isRemote) {
170+
if (world != null && !world.isRemote) {
170171
ProjectionFieldSavedData data = ProjectionFieldSavedData.get((ServerWorld) world);
171172
data.ACTIVE_FIELDS.put(this.field.getCenterPosition(), ProjectorFieldData.fromInstance(this.field));
172173
data.markDirty();
@@ -185,25 +186,24 @@ private void doFieldCheck() {
185186
* Scans the field and attempts to match a recipe that's placed in it.
186187
*/
187188
public void doRecipeScan() {
188-
if(this.field == null)
189+
if (this.field == null)
189190
return;
190191

191-
if(this.world == null)
192+
if (this.world == null)
192193
return;
193194

194195
FieldProjectionSize size = field.getFieldSize();
195196

196197
// Only the primary projector needs to worry about the recipe scan
197-
if(!isMainProjector())
198-
{
198+
if (!isMainProjector()) {
199199
Optional<BlockPos> center = ProjectorHelper.getCenterForSize(world, pos, size);
200-
if(!center.isPresent())
200+
if (!center.isPresent())
201201
return;
202202

203203
BlockPos masterPos = ProjectorHelper.getProjectorLocationForDirection(world, center.get(), Direction.NORTH, size);
204204

205205
FieldProjectorTile masterTile = (FieldProjectorTile) world.getTileEntity(masterPos);
206-
if(masterTile == null)
206+
if (masterTile == null)
207207
return;
208208

209209
masterTile.doRecipeScan();
@@ -215,6 +215,7 @@ public void doRecipeScan() {
215215
// If there are no registered recipes, then we obv can't match anything - exit early
216216
if (entries.isEmpty()) {
217217
this.currentRecipe = null;
218+
this.craftingState = EnumCraftingState.NOT_MATCHED;
218219
return;
219220
}
220221

@@ -223,8 +224,9 @@ public void doRecipeScan() {
223224
MiniaturizationFieldBlockData fieldBlocks = MiniaturizationFieldBlockData.getFromField(world, fieldBounds);
224225

225226
// If no positions filled, exit early
226-
if(fieldBlocks.getNumberFilledBlocks() == 0) {
227+
if (fieldBlocks.getNumberFilledBlocks() == 0) {
227228
this.currentRecipe = null;
229+
this.craftingState = EnumCraftingState.NOT_MATCHED;
228230
return;
229231
}
230232

@@ -238,19 +240,21 @@ public void doRecipeScan() {
238240

239241
// All the recipes we have registered won't fit in the filled bounds -
240242
// blocks were placed in a larger space than the max recipe size
241-
if(recipesBoundFitted.size() == 0) {
243+
if (recipesBoundFitted.size() == 0) {
242244
this.currentRecipe = null;
245+
this.craftingState = EnumCraftingState.NOT_MATCHED;
243246
return;
244247
}
245248

246249
// Begin recipe dry run - loop, check bottom layer for matches
247250
MiniaturizationRecipe matchedRecipe = null;
248-
for(MiniaturizationRecipe recipe : recipesBoundFitted) {
251+
for (MiniaturizationRecipe recipe : recipesBoundFitted) {
249252
boolean recipeMatches = recipe.matches(world, field.getFieldSize(), fieldBlocks);
250-
if(!recipeMatches)
253+
if (!recipeMatches)
251254
continue;
252255

253256
matchedRecipe = recipe;
257+
this.craftingState = EnumCraftingState.MATCHED;
254258
break;
255259
}
256260

@@ -271,22 +275,32 @@ private void tickCrafting() {
271275
// We dropped a catalyst item in
272276
// At this point, we had a valid recipe and a valid catalyst entity
273277
// Start crafting
274-
this.isCrafting = true;
278+
switch (craftingState) {
279+
case MATCHED:
280+
craftingState = EnumCraftingState.CRAFTING;
275281

276-
// We know the "recipe" in the field is an exact match already, so wipe the field
277-
field.clearBlocks(world);
282+
// We know the "recipe" in the field is an exact match already, so wipe the field
283+
field.clearBlocks(world);
278284

279-
CraftingHelper.consumeCatalystItem(catalystEntities.get(0), 1);
285+
CraftingHelper.consumeCatalystItem(catalystEntities.get(0), 1);
280286

281-
BlockPos fieldCenter = field.getCenterPosition();
282-
for (ItemStack is : currentRecipe.getOutputs()) {
283-
ItemEntity itemEntity = new ItemEntity(world, fieldCenter.getX() + 0.5f, fieldCenter.getY() + 0.5f, fieldCenter.getZ() + 0.5f, is);
284-
world.addEntity(itemEntity);
285-
}
287+
BlockPos centerField = field.getCenterPosition();
288+
world.setBlockState(centerField, Registration.FIELD_CRAFTING_PREVIEW_BLOCK.get().getDefaultState());
289+
FieldCraftingPreviewTile tile = (FieldCraftingPreviewTile) world.getTileEntity(centerField);
290+
if(tile != null)
291+
tile.setMasterProjector(this);
292+
293+
break;
286294

287-
// We aren't crafting any more - recipe complete, reset for next one
288-
this.isCrafting = false;
289-
this.currentRecipe = null;
295+
case CRAFTING:
296+
break;
297+
298+
case DONE:
299+
// We aren't crafting any more - recipe complete, reset for next one
300+
this.craftingState = EnumCraftingState.NOT_MATCHED;
301+
this.currentRecipe = null;
302+
break;
303+
}
290304
}
291305
}
292306
}
@@ -333,4 +347,13 @@ public AxisAlignedBB getRenderBoundingBox() {
333347
public Optional<FieldProjection> getField() {
334348
return Optional.ofNullable(this.field);
335349
}
350+
351+
public Optional<MiniaturizationRecipe> getCurrentRecipe() {
352+
return Optional.ofNullable(this.currentRecipe);
353+
}
354+
355+
public void updateCraftingState(EnumCraftingState state) {
356+
this.craftingState = state;
357+
this.markDirty();
358+
}
336359
}

src/main/java/com/robotgryphon/compactcrafting/client/ClientSetup.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.robotgryphon.compactcrafting.client;
22

33
import com.robotgryphon.compactcrafting.CompactCrafting;
4+
import com.robotgryphon.compactcrafting.client.render.FieldCraftingPreviewRenderer;
45
import com.robotgryphon.compactcrafting.client.render.FieldProjectorRenderer;
56
import com.robotgryphon.compactcrafting.core.Constants;
67
import com.robotgryphon.compactcrafting.core.Registration;
@@ -18,6 +19,7 @@ public class ClientSetup {
1819
@SubscribeEvent
1920
public static void init(final FMLClientSetupEvent event) {
2021
ClientRegistry.bindTileEntityRenderer(Registration.FIELD_PROJECTOR_TILE.get(), FieldProjectorRenderer::new);
22+
ClientRegistry.bindTileEntityRenderer(Registration.FIELD_CRAFTING_PREVIEW_TILE.get(), FieldCraftingPreviewRenderer::new);
2123
}
2224

2325
@SubscribeEvent

0 commit comments

Comments
 (0)