mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-11-10 20:45:10 +01:00
Mechanical Crafting
- Crafters now apply crafting recipes to held items and play an animation - Connected textures now also apply to the sides - Fixed inventory manipulating behaviours not initializing in time
This commit is contained in:
parent
cea90d50e4
commit
d40fd52043
@ -22,6 +22,7 @@ import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.item.BlockItem;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
@ -96,6 +97,8 @@ public class ValueBoxRenderer {
|
||||
return NUDGE;
|
||||
if (block instanceof FenceBlock)
|
||||
return NUDGE;
|
||||
if (block.isIn(BlockTags.BUTTONS))
|
||||
return NUDGE;
|
||||
if (block == Blocks.END_ROD)
|
||||
return NUDGE;
|
||||
}
|
||||
|
@ -17,12 +17,15 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka
|
||||
private Map<IBehaviourType<?>, TileEntityBehaviour> behaviours;
|
||||
private boolean initialized;
|
||||
private boolean firstNbtRead;
|
||||
private int lazyTickRate;
|
||||
private int lazyTickCounter;
|
||||
|
||||
public SmartTileEntity(TileEntityType<?> tileEntityTypeIn) {
|
||||
super(tileEntityTypeIn);
|
||||
behaviours = new HashMap<>();
|
||||
initialized = false;
|
||||
firstNbtRead = true;
|
||||
setLazyTickRate(10);
|
||||
|
||||
ArrayList<TileEntityBehaviour> list = new ArrayList<>();
|
||||
addBehaviours(list);
|
||||
@ -45,6 +48,11 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
if (lazyTickCounter-- <= 0) {
|
||||
lazyTickCounter = lazyTickRate;
|
||||
lazyTick();
|
||||
}
|
||||
|
||||
behaviours.values().forEach(TileEntityBehaviour::tick);
|
||||
}
|
||||
|
||||
@ -83,6 +91,15 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka
|
||||
super.remove();
|
||||
}
|
||||
|
||||
public void setLazyTickRate(int slowTickRate) {
|
||||
this.lazyTickRate = slowTickRate;
|
||||
this.lazyTickCounter = slowTickRate;
|
||||
}
|
||||
|
||||
public void lazyTick() {
|
||||
|
||||
}
|
||||
|
||||
protected void forEachBehaviour(Consumer<TileEntityBehaviour> action) {
|
||||
behaviours.values().forEach(tb -> {
|
||||
if (!tb.isPaused())
|
||||
|
@ -43,6 +43,7 @@ public class InventoryManagementBehaviour extends TileEntityBehaviour {
|
||||
public void initialize() {
|
||||
super.initialize();
|
||||
attachments.get().forEach(offset -> inventories.put(offset, findInventory(offset)));
|
||||
lazyTick();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -272,6 +272,8 @@ public abstract class KineticTileEntity extends SmartTileEntity implements ITick
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
if (world.isRemote)
|
||||
return;
|
||||
if (speedChangeCounter > 0)
|
||||
|
@ -36,7 +36,6 @@ import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.BlockRayTraceResult;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.IEnviromentBlockReader;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.util.Constants.NBT;
|
||||
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
|
||||
@ -126,8 +125,8 @@ public class ConnectedInputHandler {
|
||||
}
|
||||
|
||||
public static void toggleConnection(World world, BlockPos pos, BlockPos pos2) {
|
||||
MechanicalCrafterTileEntity crafter1 = getCrafter(world, pos);
|
||||
MechanicalCrafterTileEntity crafter2 = getCrafter(world, pos2);
|
||||
MechanicalCrafterTileEntity crafter1 = CrafterHelper.getCrafter(world, pos);
|
||||
MechanicalCrafterTileEntity crafter2 = CrafterHelper.getCrafter(world, pos2);
|
||||
|
||||
if (crafter1 == null || crafter2 == null)
|
||||
return;
|
||||
@ -136,7 +135,7 @@ public class ConnectedInputHandler {
|
||||
BlockPos controllerPos2 = crafter2.getPos().add(crafter2.input.data.get(0));
|
||||
|
||||
if (controllerPos1.equals(controllerPos2)) {
|
||||
MechanicalCrafterTileEntity controller = getCrafter(world, controllerPos1);
|
||||
MechanicalCrafterTileEntity controller = CrafterHelper.getCrafter(world, controllerPos1);
|
||||
|
||||
Set<BlockPos> positions = controller.input.data.stream().map(l -> controllerPos1.add(l))
|
||||
.collect(Collectors.toSet());
|
||||
@ -168,9 +167,9 @@ public class ConnectedInputHandler {
|
||||
}
|
||||
|
||||
if (!crafter1.input.isController)
|
||||
crafter1 = getCrafter(world, controllerPos1);
|
||||
crafter1 = CrafterHelper.getCrafter(world, controllerPos1);
|
||||
if (!crafter2.input.isController)
|
||||
crafter2 = getCrafter(world, controllerPos2);
|
||||
crafter2 = CrafterHelper.getCrafter(world, controllerPos2);
|
||||
if (crafter1 == null || crafter2 == null)
|
||||
return;
|
||||
|
||||
@ -217,18 +216,6 @@ public class ConnectedInputHandler {
|
||||
crafter1.input.data.add(BlockPos.ZERO.subtract(crafter2.input.data.get(0)));
|
||||
}
|
||||
|
||||
public static MechanicalCrafterTileEntity getCrafter(IEnviromentBlockReader reader, BlockPos pos) {
|
||||
TileEntity te = reader.getTileEntity(pos);
|
||||
if (!(te instanceof MechanicalCrafterTileEntity))
|
||||
return null;
|
||||
return (MechanicalCrafterTileEntity) te;
|
||||
}
|
||||
|
||||
public static ConnectedInput getInput(IEnviromentBlockReader reader, BlockPos pos) {
|
||||
MechanicalCrafterTileEntity crafter = getCrafter(reader, pos);
|
||||
return crafter == null ? null : crafter.input;
|
||||
}
|
||||
|
||||
private static void modifyAndUpdate(World world, BlockPos pos, Consumer<ConnectedInput> callback) {
|
||||
TileEntity te = world.getTileEntity(pos);
|
||||
if (!(te instanceof MechanicalCrafterTileEntity))
|
||||
@ -258,13 +245,13 @@ public class ConnectedInputHandler {
|
||||
public IItemHandler getItemHandler(World world, BlockPos pos) {
|
||||
if (!isController) {
|
||||
BlockPos controllerPos = pos.add(data.get(0));
|
||||
ConnectedInput input = getInput(world, controllerPos);
|
||||
ConnectedInput input = CrafterHelper.getInput(world, controllerPos);
|
||||
if (input == this || input == null || !input.isController)
|
||||
return new ItemStackHandler();
|
||||
return input.getItemHandler(world, controllerPos);
|
||||
}
|
||||
|
||||
List<IItemHandlerModifiable> list = data.stream().map(l -> getCrafter(world, pos.add(l)))
|
||||
List<IItemHandlerModifiable> list = data.stream().map(l -> CrafterHelper.getCrafter(world, pos.add(l)))
|
||||
.filter(Predicates.notNull()).map(crafter -> crafter.inventory).collect(Collectors.toList());
|
||||
return new CombinedInvWrapper(Arrays.copyOf(list.toArray(), list.size(), IItemHandlerModifiable[].class));
|
||||
}
|
||||
|
@ -0,0 +1,21 @@
|
||||
package com.simibubi.create.modules.contraptions.components.crafter;
|
||||
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.IEnviromentBlockReader;
|
||||
|
||||
public class CrafterHelper {
|
||||
|
||||
public static MechanicalCrafterTileEntity getCrafter(IEnviromentBlockReader reader, BlockPos pos) {
|
||||
TileEntity te = reader.getTileEntity(pos);
|
||||
if (!(te instanceof MechanicalCrafterTileEntity))
|
||||
return null;
|
||||
return (MechanicalCrafterTileEntity) te;
|
||||
}
|
||||
|
||||
public static ConnectedInputHandler.ConnectedInput getInput(IEnviromentBlockReader reader, BlockPos pos) {
|
||||
MechanicalCrafterTileEntity crafter = getCrafter(reader, pos);
|
||||
return crafter == null ? null : crafter.input;
|
||||
}
|
||||
|
||||
}
|
@ -31,8 +31,8 @@ public class InputCTBehaviour extends ConnectedTextureBehaviour {
|
||||
if (state.get(HORIZONTAL_FACING) != other.get(HORIZONTAL_FACING))
|
||||
return false;
|
||||
|
||||
ConnectedInput input1 = ConnectedInputHandler.getInput(reader, pos);
|
||||
ConnectedInput input2 = ConnectedInputHandler.getInput(reader, otherPos);
|
||||
ConnectedInput input1 = CrafterHelper.getInput(reader, pos);
|
||||
ConnectedInput input2 = CrafterHelper.getInput(reader, otherPos);
|
||||
|
||||
if (input1 == null || input2 == null)
|
||||
return false;
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.simibubi.create.modules.contraptions.components.crafter;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllItems;
|
||||
import com.simibubi.create.foundation.block.IWithTileEntity;
|
||||
import com.simibubi.create.foundation.block.connected.ConnectedTextureBehaviour;
|
||||
import com.simibubi.create.foundation.block.connected.IHaveConnectedTextures;
|
||||
@ -9,6 +10,7 @@ import com.simibubi.create.foundation.utility.Lang;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
import com.simibubi.create.modules.contraptions.base.HorizontalKineticBlock;
|
||||
import com.simibubi.create.modules.contraptions.components.crafter.ConnectedInputHandler.ConnectedInput;
|
||||
import com.simibubi.create.modules.contraptions.components.crafter.MechanicalCrafterTileEntity.Phase;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
@ -90,14 +92,26 @@ public class MechanicalCrafterBlock extends HorizontalKineticBlock
|
||||
|
||||
@Override
|
||||
public void onReplaced(BlockState state, World worldIn, BlockPos pos, BlockState newState, boolean isMoving) {
|
||||
if (state.getBlock() == newState.getBlock()) {
|
||||
if (getTargetDirection(state) != getTargetDirection(newState)) {
|
||||
MechanicalCrafterTileEntity crafter = CrafterHelper.getCrafter(worldIn, pos);
|
||||
if (crafter != null)
|
||||
crafter.blockChanged();
|
||||
}
|
||||
}
|
||||
|
||||
if (state.hasTileEntity() && state.getBlock() != newState.getBlock()) {
|
||||
MechanicalCrafterTileEntity crafter = CrafterHelper.getCrafter(worldIn, pos);
|
||||
if (crafter != null)
|
||||
crafter.ejectWholeGrid();
|
||||
|
||||
for (Direction direction : Direction.values()) {
|
||||
if (direction.getAxis() == state.get(HORIZONTAL_FACING).getAxis())
|
||||
continue;
|
||||
|
||||
BlockPos otherPos = pos.offset(direction);
|
||||
ConnectedInput thisInput = ConnectedInputHandler.getInput(worldIn, pos);
|
||||
ConnectedInput otherInput = ConnectedInputHandler.getInput(worldIn, otherPos);
|
||||
ConnectedInput thisInput = CrafterHelper.getInput(worldIn, pos);
|
||||
ConnectedInput otherInput = CrafterHelper.getInput(worldIn, otherPos);
|
||||
|
||||
if (thisInput == null || otherInput == null)
|
||||
continue;
|
||||
@ -130,6 +144,7 @@ public class MechanicalCrafterBlock extends HorizontalKineticBlock
|
||||
public ActionResultType onWrenched(BlockState state, ItemUseContext context) {
|
||||
if (context.getFace() == state.get(HORIZONTAL_FACING)) {
|
||||
context.getWorld().setBlockState(context.getPos(), state.cycle(POINTING));
|
||||
withTileEntityDo(context.getWorld(), context.getPos(), TileEntity::markDirty);
|
||||
return ActionResultType.SUCCESS;
|
||||
}
|
||||
|
||||
@ -148,6 +163,12 @@ public class MechanicalCrafterBlock extends HorizontalKineticBlock
|
||||
MechanicalCrafterTileEntity crafter = (MechanicalCrafterTileEntity) te;
|
||||
|
||||
if (hit.getFace() == state.get(HORIZONTAL_FACING)) {
|
||||
|
||||
if (crafter.phase != Phase.IDLE && !AllItems.WRENCH.typeOf(heldItem)) {
|
||||
crafter.ejectWholeGrid();
|
||||
return true;
|
||||
}
|
||||
|
||||
ItemStack inSlot = crafter.inventory.getStackInSlot(0);
|
||||
if (inSlot.isEmpty())
|
||||
return false;
|
||||
|
@ -1,12 +1,34 @@
|
||||
package com.simibubi.create.modules.contraptions.components.crafter;
|
||||
|
||||
import static com.simibubi.create.modules.contraptions.base.HorizontalKineticBlock.HORIZONTAL_FACING;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllTileEntities;
|
||||
import com.simibubi.create.foundation.behaviour.base.TileEntityBehaviour;
|
||||
import com.simibubi.create.foundation.behaviour.inventory.InsertingBehaviour;
|
||||
import com.simibubi.create.foundation.behaviour.inventory.InventoryManagementBehaviour.Attachments;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
|
||||
import com.simibubi.create.modules.contraptions.components.crafter.ConnectedInputHandler.ConnectedInput;
|
||||
import com.simibubi.create.modules.contraptions.components.crafter.MechanicalCrafterBlock.Pointing;
|
||||
import com.simibubi.create.modules.contraptions.components.crafter.RecipeGridHandler.GroupedItems;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltTileEntity;
|
||||
|
||||
import net.minecraft.entity.item.ItemEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.particles.ItemParticleData;
|
||||
import net.minecraft.particles.ParticleTypes;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.items.CapabilityItemHandler;
|
||||
@ -16,7 +38,7 @@ import net.minecraftforge.items.ItemStackHandler;
|
||||
public class MechanicalCrafterTileEntity extends KineticTileEntity {
|
||||
|
||||
enum Phase {
|
||||
IDLE, ACCEPTING, ASSEMBLING, EXPORTING
|
||||
IDLE, ACCEPTING, ASSEMBLING, EXPORTING, WAITING, CRAFTING, INSERTING;
|
||||
}
|
||||
|
||||
protected ItemStackHandler inventory = new ItemStackHandler(1) {
|
||||
@ -30,19 +52,53 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
|
||||
return ItemStack.EMPTY;
|
||||
};
|
||||
|
||||
public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) {
|
||||
if (phase != Phase.IDLE)
|
||||
return stack;
|
||||
return super.insertItem(slot, stack, simulate);
|
||||
};
|
||||
|
||||
protected void onContentsChanged(int slot) {
|
||||
if (!getStackInSlot(slot).isEmpty() && phase == Phase.IDLE)
|
||||
checkCompletedRecipe();
|
||||
markDirty();
|
||||
sendData();
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
protected GroupedItems groupedItems = new GroupedItems();
|
||||
protected ConnectedInput input = new ConnectedInput();
|
||||
protected LazyOptional<IItemHandler> invSupplier = LazyOptional.of(() -> input.getItemHandler(world, pos));
|
||||
protected boolean reRender;
|
||||
protected Phase phase;
|
||||
protected int countDown;
|
||||
|
||||
protected GroupedItems groupedItemsBeforeCraft; // for rendering on client
|
||||
private InsertingBehaviour inserting;
|
||||
|
||||
public MechanicalCrafterTileEntity() {
|
||||
super(AllTileEntities.MECHANICAL_CRAFTER.type);
|
||||
setLazyTickRate(20);
|
||||
phase = Phase.IDLE;
|
||||
groupedItemsBeforeCraft = new GroupedItems();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
|
||||
super.addBehaviours(behaviours);
|
||||
inserting = new InsertingBehaviour(this, Attachments.toward(this::getTargetFacing));
|
||||
behaviours.add(inserting);
|
||||
}
|
||||
|
||||
public void blockChanged() {
|
||||
removeBehaviour(InsertingBehaviour.TYPE);
|
||||
inserting = new InsertingBehaviour(this, Attachments.toward(this::getTargetFacing));
|
||||
putBehaviour(inserting);
|
||||
}
|
||||
|
||||
public Direction getTargetFacing() {
|
||||
return MechanicalCrafterBlock.getTargetDirection(world.getBlockState(pos));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -53,9 +109,18 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
|
||||
@Override
|
||||
public CompoundNBT write(CompoundNBT compound) {
|
||||
compound.put("Inventory", inventory.serializeNBT());
|
||||
|
||||
CompoundNBT inputNBT = new CompoundNBT();
|
||||
input.write(inputNBT);
|
||||
compound.put("ConnectedInput", inputNBT);
|
||||
|
||||
CompoundNBT groupedItemsNBT = new CompoundNBT();
|
||||
groupedItems.write(groupedItemsNBT);
|
||||
compound.put("GroupedItems", groupedItemsNBT);
|
||||
|
||||
compound.putString("Phase", phase.name());
|
||||
compound.putInt("CountDown", countDown);
|
||||
|
||||
return super.write(compound);
|
||||
}
|
||||
|
||||
@ -72,13 +137,35 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
|
||||
public void readClientUpdate(CompoundNBT tag) {
|
||||
if (tag.contains("Redraw"))
|
||||
world.notifyBlockUpdate(getPos(), getBlockState(), getBlockState(), 16);
|
||||
|
||||
Phase phaseBefore = phase;
|
||||
GroupedItems before = this.groupedItems;
|
||||
|
||||
super.readClientUpdate(tag);
|
||||
|
||||
if (phaseBefore != phase && phase == Phase.CRAFTING)
|
||||
groupedItemsBeforeCraft = before;
|
||||
if (phaseBefore == Phase.EXPORTING && phase == Phase.WAITING) {
|
||||
Direction facing = getBlockState().get(MechanicalCrafterBlock.HORIZONTAL_FACING);
|
||||
Vec3d vec = new Vec3d(facing.getDirectionVec()).scale(.75).add(VecHelper.getCenterOf(pos));
|
||||
Direction targetDirection = MechanicalCrafterBlock.getTargetDirection(getBlockState());
|
||||
vec = vec.add(new Vec3d(targetDirection.getDirectionVec()).scale(1));
|
||||
world.addParticle(ParticleTypes.CRIT, vec.x, vec.y, vec.z, 0, 0, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(CompoundNBT compound) {
|
||||
inventory.deserializeNBT(compound.getCompound("Inventory"));
|
||||
input.read(compound.getCompound("ConnectedInput"));
|
||||
groupedItems = GroupedItems.read(compound.getCompound("GroupedItems"));
|
||||
phase = Phase.IDLE;
|
||||
String name = compound.getString("Phase");
|
||||
for (Phase phase : Phase.values())
|
||||
if (phase.name().equals(name))
|
||||
this.phase = phase;
|
||||
countDown = compound.getInt("CountDown");
|
||||
super.read(compound);
|
||||
}
|
||||
|
||||
@ -88,10 +175,244 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
|
||||
super.remove();
|
||||
}
|
||||
|
||||
public int getCountDownSpeed() {
|
||||
if (getSpeed() == 0)
|
||||
return 0;
|
||||
return MathHelper.clamp((int) Math.abs(getSpeed() / 2), 1, 250);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
if (phase == Phase.ACCEPTING)
|
||||
return;
|
||||
|
||||
if (phase == Phase.ASSEMBLING) {
|
||||
countDown -= getCountDownSpeed();
|
||||
if (countDown < 0) {
|
||||
countDown = 0;
|
||||
if (world.isRemote)
|
||||
return;
|
||||
if (RecipeGridHandler.getTargetingCrafter(this) != null) {
|
||||
phase = Phase.EXPORTING;
|
||||
countDown = 1000;
|
||||
sendData();
|
||||
return;
|
||||
}
|
||||
ItemStack result = RecipeGridHandler.tryToApplyRecipe(world, groupedItems);
|
||||
if (result != null) {
|
||||
groupedItems = new GroupedItems(result);
|
||||
phase = Phase.CRAFTING;
|
||||
countDown = 2000;
|
||||
sendData();
|
||||
return;
|
||||
}
|
||||
ejectWholeGrid();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (phase == Phase.EXPORTING) {
|
||||
countDown -= getCountDownSpeed();
|
||||
|
||||
if (countDown < 0) {
|
||||
countDown = 0;
|
||||
if (world.isRemote)
|
||||
return;
|
||||
|
||||
MechanicalCrafterTileEntity targetingCrafter = RecipeGridHandler.getTargetingCrafter(this);
|
||||
if (targetingCrafter == null) {
|
||||
ejectWholeGrid();
|
||||
return;
|
||||
}
|
||||
|
||||
Pointing pointing = getBlockState().get(MechanicalCrafterBlock.POINTING);
|
||||
groupedItems.mergeOnto(targetingCrafter.groupedItems, pointing);
|
||||
groupedItems = new GroupedItems();
|
||||
phase = Phase.WAITING;
|
||||
countDown = 0;
|
||||
sendData();
|
||||
targetingCrafter.continueIfAllPrecedingFinished();
|
||||
targetingCrafter.sendData();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (phase == Phase.CRAFTING) {
|
||||
|
||||
if (world.isRemote) {
|
||||
Direction facing = getBlockState().get(MechanicalCrafterBlock.HORIZONTAL_FACING);
|
||||
float progress = countDown / 2000f;
|
||||
Vec3d facingVec = new Vec3d(facing.getDirectionVec());
|
||||
Vec3d vec = facingVec.scale(.65).add(VecHelper.getCenterOf(pos));
|
||||
Vec3d offset = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .125f)
|
||||
.mul(VecHelper.planeByNormal(facingVec)).normalize().scale(progress * .5f).add(vec);
|
||||
if (progress > .5f)
|
||||
world.addParticle(ParticleTypes.CRIT, offset.x, offset.y, offset.z, 0, 0, 0);
|
||||
|
||||
if (!groupedItemsBeforeCraft.grid.isEmpty() && progress < .5f) {
|
||||
if (groupedItems.grid.containsKey(Pair.of(0, 0))) {
|
||||
ItemStack stack = groupedItems.grid.get(Pair.of(0, 0));
|
||||
groupedItemsBeforeCraft = new GroupedItems();
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Vec3d randVec = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .125f)
|
||||
.mul(VecHelper.planeByNormal(facingVec)).normalize().scale(.25f);
|
||||
Vec3d offset2 = randVec.add(vec);
|
||||
randVec = randVec.scale(.35f);
|
||||
world.addParticle(new ItemParticleData(ParticleTypes.ITEM, stack), offset2.x, offset2.y,
|
||||
offset2.z, randVec.x, randVec.y, randVec.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
countDown -= getCountDownSpeed();
|
||||
if (countDown < 0) {
|
||||
countDown = 0;
|
||||
if (world.isRemote)
|
||||
return;
|
||||
tryInsert();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (phase == Phase.INSERTING) {
|
||||
if (!world.isRemote && isTargetingBelt())
|
||||
tryInsert();
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected boolean isTargetingBelt() {
|
||||
BlockPos targetPos = pos.offset(getTargetFacing());
|
||||
if (!AllBlocks.BELT.typeOf(world.getBlockState(targetPos)))
|
||||
return false;
|
||||
TileEntity te = world.getTileEntity(targetPos);
|
||||
if (te == null || !(te instanceof BeltTileEntity))
|
||||
return false;
|
||||
return ((KineticTileEntity) te).getSpeed() != 0;
|
||||
}
|
||||
|
||||
public void tryInsert() {
|
||||
if (inserting.getInventory() == null && !isTargetingBelt()) {
|
||||
ejectWholeGrid();
|
||||
return;
|
||||
}
|
||||
|
||||
boolean chagedPhase = phase != Phase.INSERTING;
|
||||
final List<Pair<Integer, Integer>> inserted = new LinkedList<>();
|
||||
|
||||
groupedItems.grid.forEach((pair, stack) -> {
|
||||
if (isTargetingBelt()) {
|
||||
Direction facing = getTargetFacing();
|
||||
BlockPos targetPos = pos.offset(facing);
|
||||
BeltTileEntity te = (BeltTileEntity) world.getTileEntity(targetPos);
|
||||
if (te.tryInsertingFromSide(facing, stack, false))
|
||||
inserted.add(pair);
|
||||
return;
|
||||
}
|
||||
|
||||
ItemStack remainder = inserting.insert(stack.copy(), false);
|
||||
if (!remainder.isEmpty())
|
||||
stack.setCount(remainder.getCount());
|
||||
else
|
||||
inserted.add(pair);
|
||||
});
|
||||
|
||||
inserted.forEach(groupedItems.grid::remove);
|
||||
if (groupedItems.grid.isEmpty())
|
||||
ejectWholeGrid();
|
||||
else
|
||||
phase = Phase.INSERTING;
|
||||
if (!inserted.isEmpty() || chagedPhase)
|
||||
sendData();
|
||||
}
|
||||
|
||||
public void ejectWholeGrid() {
|
||||
List<MechanicalCrafterTileEntity> chain = RecipeGridHandler.getAllCraftersOfChain(this);
|
||||
if (chain == null)
|
||||
return;
|
||||
chain.forEach(MechanicalCrafterTileEntity::eject);
|
||||
}
|
||||
|
||||
public void eject() {
|
||||
Vec3d ejectPos = VecHelper.getCenterOf(pos)
|
||||
.add(new Vec3d(getBlockState().get(HORIZONTAL_FACING).getDirectionVec()).scale(.75f));
|
||||
groupedItems.grid.forEach((pair, stack) -> dropItem(ejectPos, stack));
|
||||
if (!inventory.getStackInSlot(0).isEmpty())
|
||||
dropItem(ejectPos, inventory.getStackInSlot(0));
|
||||
phase = Phase.IDLE;
|
||||
groupedItems = new GroupedItems();
|
||||
inventory.setStackInSlot(0, ItemStack.EMPTY);
|
||||
sendData();
|
||||
}
|
||||
|
||||
public void dropItem(Vec3d ejectPos, ItemStack stack) {
|
||||
ItemEntity itemEntity = new ItemEntity(world, ejectPos.x, ejectPos.y, ejectPos.z, stack);
|
||||
itemEntity.setDefaultPickupDelay();
|
||||
world.addEntity(itemEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lazyTick() {
|
||||
super.lazyTick();
|
||||
if (world.isRemote)
|
||||
return;
|
||||
if (phase == Phase.IDLE && craftingItemPresent())
|
||||
checkCompletedRecipe();
|
||||
if (phase == Phase.INSERTING)
|
||||
tryInsert();
|
||||
}
|
||||
|
||||
public boolean craftingItemPresent() {
|
||||
return !inventory.getStackInSlot(0).isEmpty();
|
||||
}
|
||||
|
||||
protected void checkCompletedRecipe() {
|
||||
if (getSpeed() == 0)
|
||||
return;
|
||||
if (world.isRemote)
|
||||
return;
|
||||
List<MechanicalCrafterTileEntity> chain = RecipeGridHandler.getAllCraftersOfChainIf(this,
|
||||
MechanicalCrafterTileEntity::craftingItemPresent);
|
||||
if (chain == null)
|
||||
return;
|
||||
chain.forEach(MechanicalCrafterTileEntity::begin);
|
||||
}
|
||||
|
||||
protected void begin() {
|
||||
phase = Phase.ACCEPTING;
|
||||
groupedItems = new GroupedItems(inventory.getStackInSlot(0));
|
||||
inventory.setStackInSlot(0, ItemStack.EMPTY);
|
||||
if (RecipeGridHandler.getPrecedingCrafters(this).isEmpty()) {
|
||||
phase = Phase.ASSEMBLING;
|
||||
countDown = 500;
|
||||
}
|
||||
sendData();
|
||||
}
|
||||
|
||||
protected void continueIfAllPrecedingFinished() {
|
||||
List<MechanicalCrafterTileEntity> preceding = RecipeGridHandler.getPrecedingCrafters(this);
|
||||
if (preceding == null) {
|
||||
ejectWholeGrid();
|
||||
return;
|
||||
}
|
||||
|
||||
for (MechanicalCrafterTileEntity mechanicalCrafterTileEntity : preceding)
|
||||
if (mechanicalCrafterTileEntity.phase != Phase.WAITING)
|
||||
return;
|
||||
|
||||
phase = Phase.ASSEMBLING;
|
||||
countDown = Math.max(100, getCountDownSpeed() + 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> LazyOptional<T> getCapability(Capability<T> cap, Direction side) {
|
||||
if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) {
|
||||
if (getBlockState().get(MechanicalCrafterBlock.HORIZONTAL_FACING) == side)
|
||||
if (getBlockState().get(HORIZONTAL_FACING) == side)
|
||||
return LazyOptional.empty();
|
||||
return invSupplier.cast();
|
||||
}
|
||||
|
@ -3,10 +3,15 @@ package com.simibubi.create.modules.contraptions.components.crafter;
|
||||
import com.mojang.blaze3d.platform.GlStateManager;
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.CreateClient;
|
||||
import com.simibubi.create.foundation.block.render.SpriteShiftEntry;
|
||||
import com.simibubi.create.foundation.block.render.SpriteShifter;
|
||||
import com.simibubi.create.foundation.utility.AngleHelper;
|
||||
import com.simibubi.create.foundation.utility.AnimationTickHolder;
|
||||
import com.simibubi.create.foundation.utility.SuperByteBuffer;
|
||||
import com.simibubi.create.foundation.utility.TessellatorHelper;
|
||||
import com.simibubi.create.modules.contraptions.base.KineticTileEntityRenderer;
|
||||
import com.simibubi.create.modules.contraptions.components.crafter.MechanicalCrafterTileEntity.Phase;
|
||||
import com.simibubi.create.modules.contraptions.components.crafter.RecipeGridHandler.GroupedItems;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
@ -21,11 +26,15 @@ import net.minecraft.state.properties.BlockStateProperties;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.Direction.Axis;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public class MechanicalCrafterTileEntityRenderer extends TileEntityRenderer<MechanicalCrafterTileEntity> {
|
||||
|
||||
public static SpriteShiftEntry animatedTexture = SpriteShifter.get("block/crafter_thingies",
|
||||
"block/crafter_thingies");
|
||||
|
||||
@Override
|
||||
public void render(MechanicalCrafterTileEntity te, double x, double y, double z, float partialTicks,
|
||||
int destroyStage) {
|
||||
@ -36,11 +45,19 @@ public class MechanicalCrafterTileEntityRenderer extends TileEntityRenderer<Mech
|
||||
GlStateManager.pushMatrix();
|
||||
Direction facing = te.getBlockState().get(MechanicalCrafterBlock.HORIZONTAL_FACING);
|
||||
Vec3d vec = new Vec3d(facing.getDirectionVec()).scale(.58).add(.5, .5, .5);
|
||||
|
||||
if (te.phase == Phase.EXPORTING) {
|
||||
Direction targetDirection = MechanicalCrafterBlock.getTargetDirection(te.getBlockState());
|
||||
float progress = MathHelper.clamp((1000 - te.countDown + te.getCountDownSpeed() * partialTicks) / 1000f, 0,
|
||||
1);
|
||||
vec = vec.add(new Vec3d(targetDirection.getDirectionVec()).scale(progress * .75f));
|
||||
}
|
||||
|
||||
GlStateManager.translated(x + vec.x, y + vec.y, z + vec.z);
|
||||
GlStateManager.scalef(1 / 2f, 1 / 2f, 1 / 2f);
|
||||
float yRot = AngleHelper.horizontalAngle(facing);
|
||||
GlStateManager.rotated(yRot, 0, 1, 0);
|
||||
renderItems(te);
|
||||
renderItems(te, partialTicks);
|
||||
GlStateManager.popMatrix();
|
||||
|
||||
TessellatorHelper.prepareFastRender();
|
||||
@ -49,12 +66,72 @@ public class MechanicalCrafterTileEntityRenderer extends TileEntityRenderer<Mech
|
||||
TessellatorHelper.draw();
|
||||
}
|
||||
|
||||
public void renderItems(MechanicalCrafterTileEntity te) {
|
||||
public void renderItems(MechanicalCrafterTileEntity te, float partialTicks) {
|
||||
RenderHelper.enableStandardItemLighting();
|
||||
|
||||
ItemStack stack = te.inventory.getStackInSlot(0);
|
||||
if (!stack.isEmpty())
|
||||
Minecraft.getInstance().getItemRenderer().renderItem(stack, TransformType.FIXED);
|
||||
if (te.phase == Phase.IDLE) {
|
||||
ItemStack stack = te.inventory.getStackInSlot(0);
|
||||
if (!stack.isEmpty()) {
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.translatef(0, 0, -1 / 256f);
|
||||
Minecraft.getInstance().getItemRenderer().renderItem(stack, TransformType.FIXED);
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
} else {
|
||||
// render grouped items
|
||||
GroupedItems items = te.groupedItems;
|
||||
float distance = .5f;
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
|
||||
if (te.phase == Phase.CRAFTING) {
|
||||
items = te.groupedItemsBeforeCraft;
|
||||
items.calcStats();
|
||||
float progress = MathHelper.clamp((2000 - te.countDown + te.getCountDownSpeed() * partialTicks) / 1000f,
|
||||
0, 1);
|
||||
float earlyProgress = MathHelper.clamp(progress * 2, 0, 1);
|
||||
float lateProgress = MathHelper.clamp(progress * 2 - 1, 0, 1);
|
||||
|
||||
// GlStateManager.rotated(lateProgress * 360, 0, 0, 1);
|
||||
GlStateManager.scaled(1 - lateProgress, 1 - lateProgress, 1 - lateProgress);
|
||||
|
||||
Vec3d centering = new Vec3d(-items.minX + (-items.width + 1) / 2f,
|
||||
-items.minY + (-items.height + 1) / 2f, 0).scale(earlyProgress);
|
||||
GlStateManager.translated(centering.x * .5f, centering.y * .5f, 0);
|
||||
|
||||
distance += (-4 * (progress - .5f) * (progress - .5f) + 1) * .25f;
|
||||
}
|
||||
|
||||
final float spacing = distance;
|
||||
items.grid.forEach((pair, stack) -> {
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.translatef(pair.getKey() * spacing, pair.getValue() * spacing, 0);
|
||||
TessellatorHelper.fightZFighting(pair.hashCode() + te.getPos().hashCode());
|
||||
Minecraft.getInstance().getItemRenderer().renderItem(stack, TransformType.FIXED);
|
||||
GlStateManager.popMatrix();
|
||||
});
|
||||
|
||||
GlStateManager.popMatrix();
|
||||
|
||||
if (te.phase == Phase.CRAFTING) {
|
||||
items = te.groupedItems;
|
||||
float progress = MathHelper.clamp((1000 - te.countDown + te.getCountDownSpeed() * partialTicks) / 1000f,
|
||||
0, 1);
|
||||
float earlyProgress = MathHelper.clamp(progress * 2, 0, 1);
|
||||
float lateProgress = MathHelper.clamp(progress * 2 - 1, 0, 1);
|
||||
|
||||
GlStateManager.rotated(earlyProgress * 2 * 360, 0, 0, 1);
|
||||
float upScaling = earlyProgress * 1.125f;
|
||||
float downScaling = 1 + (1 - lateProgress) * .125f;
|
||||
GlStateManager.scaled(upScaling, upScaling, upScaling);
|
||||
GlStateManager.scaled(downScaling, downScaling, downScaling);
|
||||
|
||||
items.grid.forEach((pair, stack) -> {
|
||||
Minecraft.getInstance().getItemRenderer().renderItem(stack, TransformType.FIXED);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
RenderHelper.disableStandardItemLighting();
|
||||
}
|
||||
@ -70,13 +147,24 @@ public class MechanicalCrafterTileEntityRenderer extends TileEntityRenderer<Mech
|
||||
Direction targetDirection = MechanicalCrafterBlock.getTargetDirection(blockState);
|
||||
BlockPos pos = te.getPos();
|
||||
|
||||
// SuperByteBuffer lidBuffer = renderAndTransform(AllBlocks.MECHANICAL_CRAFTER_LID, blockState, pos);
|
||||
// lidBuffer.translate(x, y, z).renderInto(buffer);
|
||||
if (te.phase != Phase.IDLE && te.phase != Phase.CRAFTING && te.phase != Phase.INSERTING) {
|
||||
SuperByteBuffer lidBuffer = renderAndTransform(AllBlocks.MECHANICAL_CRAFTER_LID, blockState, pos);
|
||||
lidBuffer.translate(x, y, z).renderInto(buffer);
|
||||
}
|
||||
|
||||
if (MechanicalCrafterBlock.isValidTarget(getWorld(), pos.offset(targetDirection), blockState)) {
|
||||
SuperByteBuffer beltBuffer = renderAndTransform(AllBlocks.MECHANICAL_CRAFTER_BELT, blockState, pos);
|
||||
SuperByteBuffer beltFrameBuffer = renderAndTransform(AllBlocks.MECHANICAL_CRAFTER_BELT_FRAME, blockState,
|
||||
pos);
|
||||
|
||||
if (te.phase == Phase.EXPORTING) {
|
||||
int textureIndex = (int) ((te.getCountDownSpeed() / 128f * AnimationTickHolder.ticks));
|
||||
beltBuffer.shiftUVtoSheet(animatedTexture.getOriginal(), animatedTexture.getTarget(),
|
||||
(textureIndex % 4) * 4, 0);
|
||||
} else {
|
||||
beltBuffer.shiftUVtoSheet(animatedTexture.getOriginal(), animatedTexture.getTarget(), 0, 0);
|
||||
}
|
||||
|
||||
beltBuffer.translate(x, y, z).renderInto(buffer);
|
||||
beltFrameBuffer.translate(x, y, z).renderInto(buffer);
|
||||
|
||||
|
@ -0,0 +1,214 @@
|
||||
package com.simibubi.create.modules.contraptions.components.crafter;
|
||||
|
||||
import static com.simibubi.create.modules.contraptions.base.HorizontalKineticBlock.HORIZONTAL_FACING;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import com.google.common.base.Predicates;
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.modules.contraptions.components.crafter.MechanicalCrafterBlock.Pointing;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.inventory.CraftingInventory;
|
||||
import net.minecraft.inventory.container.Container;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.crafting.IRecipeType;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.nbt.ListNBT;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.util.Constants.NBT;
|
||||
|
||||
public class RecipeGridHandler {
|
||||
|
||||
public static List<MechanicalCrafterTileEntity> getAllCraftersOfChain(MechanicalCrafterTileEntity root) {
|
||||
return getAllCraftersOfChainIf(root, Predicates.alwaysTrue());
|
||||
}
|
||||
|
||||
public static List<MechanicalCrafterTileEntity> getAllCraftersOfChainIf(MechanicalCrafterTileEntity root,
|
||||
Predicate<MechanicalCrafterTileEntity> test) {
|
||||
List<MechanicalCrafterTileEntity> crafters = new ArrayList<>();
|
||||
List<Pair<MechanicalCrafterTileEntity, MechanicalCrafterTileEntity>> frontier = new ArrayList<>();
|
||||
Set<MechanicalCrafterTileEntity> visited = new HashSet<>();
|
||||
frontier.add(Pair.of(root, null));
|
||||
|
||||
while (!frontier.isEmpty()) {
|
||||
Pair<MechanicalCrafterTileEntity, MechanicalCrafterTileEntity> pair = frontier.remove(0);
|
||||
MechanicalCrafterTileEntity current = pair.getKey();
|
||||
MechanicalCrafterTileEntity last = pair.getValue();
|
||||
|
||||
if (visited.contains(current) || !test.test(current))
|
||||
return null;
|
||||
crafters.add(current);
|
||||
visited.add(current);
|
||||
|
||||
MechanicalCrafterTileEntity target = getTargetingCrafter(current);
|
||||
if (target != last && target != null)
|
||||
frontier.add(Pair.of(target, current));
|
||||
for (MechanicalCrafterTileEntity preceding : getPrecedingCrafters(current))
|
||||
if (preceding != last)
|
||||
frontier.add(Pair.of(preceding, current));
|
||||
}
|
||||
|
||||
return crafters;
|
||||
}
|
||||
|
||||
public static MechanicalCrafterTileEntity getTargetingCrafter(MechanicalCrafterTileEntity crafter) {
|
||||
BlockState state = crafter.getBlockState();
|
||||
if (!AllBlocks.MECHANICAL_CRAFTER.typeOf(state))
|
||||
return null;
|
||||
|
||||
BlockPos targetPos = crafter.getPos().offset(MechanicalCrafterBlock.getTargetDirection(state));
|
||||
MechanicalCrafterTileEntity targetTE = CrafterHelper.getCrafter(crafter.getWorld(), targetPos);
|
||||
if (targetTE == null)
|
||||
return null;
|
||||
|
||||
BlockState targetState = targetTE.getBlockState();
|
||||
if (!AllBlocks.MECHANICAL_CRAFTER.typeOf(targetState))
|
||||
return null;
|
||||
if (state.get(HORIZONTAL_FACING) != targetState.get(HORIZONTAL_FACING))
|
||||
return null;
|
||||
return targetTE;
|
||||
}
|
||||
|
||||
public static List<MechanicalCrafterTileEntity> getPrecedingCrafters(MechanicalCrafterTileEntity crafter) {
|
||||
BlockPos pos = crafter.getPos();
|
||||
World world = crafter.getWorld();
|
||||
List<MechanicalCrafterTileEntity> crafters = new ArrayList<>();
|
||||
BlockState blockState = crafter.getBlockState();
|
||||
if (!AllBlocks.MECHANICAL_CRAFTER.typeOf(blockState))
|
||||
return crafters;
|
||||
|
||||
Direction blockFacing = blockState.get(HORIZONTAL_FACING);
|
||||
Direction blockPointing = MechanicalCrafterBlock.getTargetDirection(blockState);
|
||||
for (Direction facing : Direction.values()) {
|
||||
if (blockFacing.getAxis() == facing.getAxis())
|
||||
continue;
|
||||
if (blockPointing == facing)
|
||||
continue;
|
||||
|
||||
BlockPos neighbourPos = pos.offset(facing);
|
||||
BlockState neighbourState = world.getBlockState(neighbourPos);
|
||||
if (!AllBlocks.MECHANICAL_CRAFTER.typeOf(neighbourState))
|
||||
continue;
|
||||
if (MechanicalCrafterBlock.getTargetDirection(neighbourState) != facing.getOpposite())
|
||||
continue;
|
||||
if (blockFacing != neighbourState.get(HORIZONTAL_FACING))
|
||||
continue;
|
||||
MechanicalCrafterTileEntity te = CrafterHelper.getCrafter(world, neighbourPos);
|
||||
if (te == null)
|
||||
continue;
|
||||
|
||||
crafters.add(te);
|
||||
}
|
||||
|
||||
return crafters;
|
||||
}
|
||||
|
||||
public static ItemStack tryToApplyRecipe(World world, GroupedItems items) {
|
||||
CraftingInventory craftinginventory = getCraftingInventory(items);
|
||||
ItemStack result = world.getRecipeManager().getRecipe(IRecipeType.CRAFTING, craftinginventory, world)
|
||||
.map(r -> r.getCraftingResult(craftinginventory)).orElse(null);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static CraftingInventory getCraftingInventory(GroupedItems items) {
|
||||
items.calcStats();
|
||||
CraftingInventory craftinginventory = new CraftingInventory(new Container(null, -1) {
|
||||
public boolean canInteractWith(PlayerEntity playerIn) {
|
||||
return false;
|
||||
}
|
||||
}, items.width, items.height);
|
||||
|
||||
for (int y = 0; y < items.height; y++) {
|
||||
for (int x = 0; x < items.width; x++) {
|
||||
ItemStack stack = items.grid.get(Pair.of(x + items.minX, y + items.minY));
|
||||
craftinginventory.setInventorySlotContents(x + (items.height - y - 1) * items.width,
|
||||
stack == null ? ItemStack.EMPTY : stack.copy());
|
||||
}
|
||||
}
|
||||
|
||||
return craftinginventory;
|
||||
}
|
||||
|
||||
public static class GroupedItems {
|
||||
Map<Pair<Integer, Integer>, ItemStack> grid = new HashMap<>();
|
||||
int minX, minY, maxX, maxY, width, height;
|
||||
boolean statsReady;
|
||||
|
||||
public GroupedItems() {
|
||||
}
|
||||
|
||||
public GroupedItems(ItemStack stack) {
|
||||
grid.put(Pair.of(0, 0), stack);
|
||||
}
|
||||
|
||||
public void mergeOnto(GroupedItems other, Pointing pointing) {
|
||||
int xOffset = pointing == Pointing.LEFT ? 1 : pointing == Pointing.RIGHT ? -1 : 0;
|
||||
int yOffset = pointing == Pointing.DOWN ? 1 : pointing == Pointing.UP ? -1 : 0;
|
||||
grid.forEach((pair, stack) -> other.grid.put(Pair.of(pair.getKey() + xOffset, pair.getValue() + yOffset),
|
||||
stack));
|
||||
other.statsReady = false;
|
||||
}
|
||||
|
||||
public void write(CompoundNBT nbt) {
|
||||
ListNBT gridNBT = new ListNBT();
|
||||
grid.forEach((pair, stack) -> {
|
||||
CompoundNBT entry = new CompoundNBT();
|
||||
entry.putInt("x", pair.getKey());
|
||||
entry.putInt("y", pair.getValue());
|
||||
entry.put("item", stack.serializeNBT());
|
||||
gridNBT.add(entry);
|
||||
});
|
||||
nbt.put("Grid", gridNBT);
|
||||
}
|
||||
|
||||
public static GroupedItems read(CompoundNBT nbt) {
|
||||
GroupedItems items = new GroupedItems();
|
||||
ListNBT gridNBT = nbt.getList("Grid", NBT.TAG_COMPOUND);
|
||||
gridNBT.forEach(inbt -> {
|
||||
CompoundNBT entry = (CompoundNBT) inbt;
|
||||
int x = entry.getInt("x");
|
||||
int y = entry.getInt("y");
|
||||
ItemStack stack = ItemStack.read(entry.getCompound("item"));
|
||||
items.grid.put(Pair.of(x, y), stack);
|
||||
});
|
||||
return items;
|
||||
}
|
||||
|
||||
public void calcStats() {
|
||||
if (statsReady)
|
||||
return;
|
||||
statsReady = true;
|
||||
|
||||
minX = 0;
|
||||
minY = 0;
|
||||
maxX = 0;
|
||||
maxY = 0;
|
||||
|
||||
for (Pair<Integer, Integer> pair : grid.keySet()) {
|
||||
int x = pair.getKey();
|
||||
int y = pair.getValue();
|
||||
minX = Math.min(minX, x);
|
||||
minY = Math.min(minY, y);
|
||||
maxX = Math.max(maxX, x);
|
||||
maxY = Math.max(maxY, y);
|
||||
}
|
||||
|
||||
width = maxX - minX + 1;
|
||||
height = maxY - minY + 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 477 B After Width: | Height: | Size: 429 B |
Loading…
Reference in New Issue
Block a user