mirror of
https://github.com/Ellpeck/PrettyPipes.git
synced 2024-12-04 16:28:34 +01:00
Compare commits
4 commits
24b1bbd84b
...
805393ba6e
Author | SHA1 | Date | |
---|---|---|---|
805393ba6e | |||
2c8ab9ed07 | |||
704027c3dc | |||
e6e9d4358f |
8 changed files with 201 additions and 150 deletions
|
@ -122,13 +122,23 @@ public final class Utility {
|
||||||
return ItemStack.EMPTY;
|
return ItemStack.EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ListTag serializeAll(HolderLookup.Provider provider, Collection<? extends INBTSerializable<CompoundTag>> items) {
|
public static <T> ListTag serializeAll(Collection<T> items, Function<T, CompoundTag> serializer) {
|
||||||
var list = new ListTag();
|
var list = new ListTag();
|
||||||
for (INBTSerializable<CompoundTag> item : items)
|
for (var item : items)
|
||||||
list.add(item.serializeNBT(provider));
|
list.add(serializer.apply(item));
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T> List<T> deserializeAll(ListTag list, Function<CompoundTag, T> deserializer) {
|
||||||
|
List<T> items = new ArrayList<>();
|
||||||
|
for (var i = 0; i < list.size(); i++) {
|
||||||
|
var item = deserializer.apply(list.getCompound(i));
|
||||||
|
if (item != null)
|
||||||
|
items.add(item);
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
public static void sendBlockEntityToClients(BlockEntity tile) {
|
public static void sendBlockEntityToClients(BlockEntity tile) {
|
||||||
var world = (ServerLevel) tile.getLevel();
|
var world = (ServerLevel) tile.getLevel();
|
||||||
var entities = world.getChunkSource().chunkMap.getPlayers(new ChunkPos(tile.getBlockPos()), false);
|
var entities = world.getChunkSource().chunkMap.getPlayers(new ChunkPos(tile.getBlockPos()), false);
|
||||||
|
@ -137,16 +147,6 @@ public final class Utility {
|
||||||
e.connection.send(packet);
|
e.connection.send(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T extends INBTSerializable<CompoundTag>> List<T> deserializeAll(ListTag list, Function<CompoundTag, T> supplier) {
|
|
||||||
List<T> items = new ArrayList<>();
|
|
||||||
for (var i = 0; i < list.size(); i++) {
|
|
||||||
var item = supplier.apply(list.getCompound(i));
|
|
||||||
if (item != null)
|
|
||||||
items.add(item);
|
|
||||||
}
|
|
||||||
return items;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IItemHandler getBlockItemHandler(Level world, BlockPos pos, Direction direction) {
|
public static IItemHandler getBlockItemHandler(Level world, BlockPos pos, Direction direction) {
|
||||||
var state = world.getBlockState(pos);
|
var state = world.getBlockState(pos);
|
||||||
var block = state.getBlock();
|
var block = state.getBlock();
|
||||||
|
|
|
@ -118,8 +118,8 @@ public class PipeNetwork extends SavedData implements GraphListener<BlockPos, Ne
|
||||||
for (var edge : this.graph.edgeSet())
|
for (var edge : this.graph.edgeSet())
|
||||||
edges.add(edge.serializeNBT(provider));
|
edges.add(edge.serializeNBT(provider));
|
||||||
nbt.put("edges", edges);
|
nbt.put("edges", edges);
|
||||||
nbt.put("items", Utility.serializeAll(provider, this.pipeItems.values()));
|
nbt.put("items", Utility.serializeAll(this.pipeItems.values(), i -> i.serializeNBT(provider)));
|
||||||
nbt.put("locks", Utility.serializeAll(provider, this.networkLocks.values()));
|
nbt.put("locks", Utility.serializeAll(this.networkLocks.values(), l -> l.serializeNBT(provider)));
|
||||||
return nbt;
|
return nbt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,23 +277,24 @@ public class PipeNetwork extends SavedData implements GraphListener<BlockPos, Ne
|
||||||
this.tileCache.remove(pos);
|
this.tileCache.remove(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Pair<BlockPos, ItemStack>> getCurrentlyCrafting(BlockPos node, ItemEquality... equalityTypes) {
|
public List<Pair<BlockPos, ItemStack>> getCurrentlyCrafting(BlockPos node, boolean includeCanceled, ItemEquality... equalityTypes) {
|
||||||
this.startProfile("get_currently_crafting");
|
this.startProfile("get_currently_crafting");
|
||||||
List<Pair<BlockPos, ItemStack>> items = new ArrayList<>();
|
List<Pair<BlockPos, ItemStack>> items = new ArrayList<>();
|
||||||
var craftingPipes = this.getAllCraftables(node).stream().map(c -> this.getPipe(c.getLeft())).distinct().iterator();
|
var craftingPipes = this.getAllCraftables(node).stream().map(c -> this.getPipe(c.getLeft())).distinct().iterator();
|
||||||
while (craftingPipes.hasNext()) {
|
while (craftingPipes.hasNext()) {
|
||||||
var pipe = craftingPipes.next();
|
var pipe = craftingPipes.next();
|
||||||
for (var request : pipe.craftResultRequests) {
|
for (var craft : pipe.activeCrafts) {
|
||||||
var dest = request.getMiddle();
|
var data = craft.getRight();
|
||||||
var stack = request.getRight();
|
if (!includeCanceled && data.canceled)
|
||||||
|
continue;
|
||||||
// add up all the items that should go to the same location
|
// add up all the items that should go to the same location
|
||||||
var existing = items.stream()
|
var existing = items.stream()
|
||||||
.filter(s -> s.getLeft().equals(dest) && ItemEquality.compareItems(s.getRight(), stack, equalityTypes))
|
.filter(s -> s.getLeft().equals(data.resultDestPipe) && ItemEquality.compareItems(s.getRight(), data.resultStackRemain, equalityTypes))
|
||||||
.findFirst();
|
.findFirst();
|
||||||
if (existing.isPresent()) {
|
if (existing.isPresent()) {
|
||||||
existing.get().getRight().grow(stack.getCount());
|
existing.get().getRight().grow(data.resultStackRemain.getCount());
|
||||||
} else {
|
} else {
|
||||||
items.add(Pair.of(dest, stack.copy()));
|
items.add(Pair.of(data.resultDestPipe, data.resultStackRemain.copy()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -301,8 +302,8 @@ public class PipeNetwork extends SavedData implements GraphListener<BlockPos, Ne
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getCurrentlyCraftingAmount(BlockPos destNode, ItemStack stack, ItemEquality... equalityTypes) {
|
public int getCurrentlyCraftingAmount(BlockPos destNode, ItemStack stack, boolean includeCanceled, ItemEquality... equalityTypes) {
|
||||||
return this.getCurrentlyCrafting(destNode).stream()
|
return this.getCurrentlyCrafting(destNode, includeCanceled).stream()
|
||||||
.filter(p -> p.getLeft().equals(destNode) && ItemEquality.compareItems(p.getRight(), stack, equalityTypes))
|
.filter(p -> p.getLeft().equals(destNode) && ItemEquality.compareItems(p.getRight(), stack, equalityTypes))
|
||||||
.mapToInt(p -> p.getRight().getCount()).sum();
|
.mapToInt(p -> p.getRight().getCount()).sum();
|
||||||
}
|
}
|
||||||
|
|
|
@ -270,8 +270,8 @@ public class PipeBlock extends BaseEntityBlock implements SimpleWaterloggedBlock
|
||||||
network.onPipeChanged(pos, state);
|
network.onPipeChanged(pos, state);
|
||||||
if (worldIn.getBlockEntity(pos) instanceof PipeBlockEntity pipe) {
|
if (worldIn.getBlockEntity(pos) instanceof PipeBlockEntity pipe) {
|
||||||
pipe.getItems().clear();
|
pipe.getItems().clear();
|
||||||
for (var locks : pipe.craftIngredientRequests) {
|
for (var craft : pipe.activeCrafts) {
|
||||||
for (var lock : locks.getRight())
|
for (var lock : craft.getRight().ingredientsToRequest)
|
||||||
network.resolveNetworkLock(lock);
|
network.resolveNetworkLock(lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import de.ellpeck.prettypipes.misc.ItemFilter;
|
||||||
import de.ellpeck.prettypipes.network.NetworkLock;
|
import de.ellpeck.prettypipes.network.NetworkLock;
|
||||||
import de.ellpeck.prettypipes.network.PipeNetwork;
|
import de.ellpeck.prettypipes.network.PipeNetwork;
|
||||||
import de.ellpeck.prettypipes.pipe.containers.MainPipeContainer;
|
import de.ellpeck.prettypipes.pipe.containers.MainPipeContainer;
|
||||||
|
import de.ellpeck.prettypipes.pipe.modules.craft.CraftingModuleItem;
|
||||||
import de.ellpeck.prettypipes.pressurizer.PressurizerBlockEntity;
|
import de.ellpeck.prettypipes.pressurizer.PressurizerBlockEntity;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
|
@ -71,11 +72,7 @@ public class PipeBlockEntity extends BlockEntity implements MenuProvider, IPipeC
|
||||||
PipeBlockEntity.this.setChanged();
|
PipeBlockEntity.this.setChanged();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// TODO instead of having these loose lists, it would be nice to have a "ModuleData" system that allows modules to store an object of custom data on the pipe
|
public final List<Pair<Integer, CraftingModuleItem.ActiveCraft>> activeCrafts = new ArrayList<>();
|
||||||
// crafting module slot, ingredient request network locks (one list for each recipe)
|
|
||||||
public final List<Pair<Integer, List<NetworkLock>>> craftIngredientRequests = new ArrayList<>();
|
|
||||||
// crafting module slot, destination pipe for the result, result item
|
|
||||||
public final List<Triple<Integer, BlockPos, ItemStack>> craftResultRequests = new ArrayList<>();
|
|
||||||
public PressurizerBlockEntity pressurizer;
|
public PressurizerBlockEntity pressurizer;
|
||||||
public BlockState cover;
|
public BlockState cover;
|
||||||
public int moduleDropCheck;
|
public int moduleDropCheck;
|
||||||
|
@ -102,25 +99,16 @@ public class PipeBlockEntity extends BlockEntity implements MenuProvider, IPipeC
|
||||||
super.saveAdditional(compound, provider);
|
super.saveAdditional(compound, provider);
|
||||||
compound.put("modules", this.modules.serializeNBT(provider));
|
compound.put("modules", this.modules.serializeNBT(provider));
|
||||||
compound.putInt("module_drop_check", this.moduleDropCheck);
|
compound.putInt("module_drop_check", this.moduleDropCheck);
|
||||||
var requests = new ListTag();
|
|
||||||
for (var tuple : this.craftIngredientRequests) {
|
|
||||||
var nbt = new CompoundTag();
|
|
||||||
nbt.putInt("module_slot", tuple.getLeft());
|
|
||||||
nbt.put("locks", Utility.serializeAll(provider, tuple.getRight()));
|
|
||||||
requests.add(nbt);
|
|
||||||
}
|
|
||||||
compound.put("craft_requests", requests);
|
|
||||||
if (this.cover != null)
|
if (this.cover != null)
|
||||||
compound.put("cover", NbtUtils.writeBlockState(this.cover));
|
compound.put("cover", NbtUtils.writeBlockState(this.cover));
|
||||||
var results = new ListTag();
|
var crafts = new ListTag();
|
||||||
for (var triple : this.craftResultRequests) {
|
for (var craft : this.activeCrafts) {
|
||||||
var nbt = new CompoundTag();
|
var tag = new CompoundTag();
|
||||||
nbt.putInt("module_slot", triple.getLeft());
|
tag.putInt("module_slot", craft.getLeft());
|
||||||
nbt.putLong("dest_pipe", triple.getMiddle().asLong());
|
tag.put("data", craft.getRight().serializeNBT(provider));
|
||||||
nbt.put("item", triple.getRight().save(provider));
|
crafts.add(tag);
|
||||||
results.add(nbt);
|
|
||||||
}
|
}
|
||||||
compound.put("craft_results", results);
|
compound.put("active_crafts", crafts);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -128,22 +116,11 @@ public class PipeBlockEntity extends BlockEntity implements MenuProvider, IPipeC
|
||||||
this.modules.deserializeNBT(provider, compound.getCompound("modules"));
|
this.modules.deserializeNBT(provider, compound.getCompound("modules"));
|
||||||
this.moduleDropCheck = compound.getInt("module_drop_check");
|
this.moduleDropCheck = compound.getInt("module_drop_check");
|
||||||
this.cover = compound.contains("cover") ? NbtUtils.readBlockState(this.level != null ? this.level.holderLookup(Registries.BLOCK) : BuiltInRegistries.BLOCK.asLookup(), compound.getCompound("cover")) : null;
|
this.cover = compound.contains("cover") ? NbtUtils.readBlockState(this.level != null ? this.level.holderLookup(Registries.BLOCK) : BuiltInRegistries.BLOCK.asLookup(), compound.getCompound("cover")) : null;
|
||||||
this.craftIngredientRequests.clear();
|
this.activeCrafts.clear();
|
||||||
var requests = compound.getList("craft_requests", Tag.TAG_COMPOUND);
|
var crafts = compound.getList("active_crafts", Tag.TAG_COMPOUND);
|
||||||
for (var i = 0; i < requests.size(); i++) {
|
for (var i = 0; i < crafts.size(); i++) {
|
||||||
var nbt = requests.getCompound(i);
|
var tag = crafts.getCompound(i);
|
||||||
this.craftIngredientRequests.add(Pair.of(
|
this.activeCrafts.add(Pair.of(tag.getInt("module_slot"), new CraftingModuleItem.ActiveCraft(provider, tag.getCompound("data"))));
|
||||||
nbt.getInt("module_slot"),
|
|
||||||
Utility.deserializeAll(nbt.getList("locks", Tag.TAG_COMPOUND), c -> new NetworkLock(provider, c))));
|
|
||||||
}
|
|
||||||
this.craftResultRequests.clear();
|
|
||||||
var results = compound.getList("craft_results", Tag.TAG_COMPOUND);
|
|
||||||
for (var i = 0; i < results.size(); i++) {
|
|
||||||
var nbt = results.getCompound(i);
|
|
||||||
this.craftResultRequests.add(Triple.of(
|
|
||||||
nbt.getInt("module_slot"),
|
|
||||||
BlockPos.of(nbt.getLong("dest_pipe")),
|
|
||||||
ItemStack.parseOptional(provider, nbt.getCompound("item"))));
|
|
||||||
}
|
}
|
||||||
super.loadAdditional(compound, provider);
|
super.loadAdditional(compound, provider);
|
||||||
}
|
}
|
||||||
|
@ -152,7 +129,7 @@ public class PipeBlockEntity extends BlockEntity implements MenuProvider, IPipeC
|
||||||
public CompoundTag getUpdateTag(HolderLookup.Provider provider) {
|
public CompoundTag getUpdateTag(HolderLookup.Provider provider) {
|
||||||
// sync pipe items on load
|
// sync pipe items on load
|
||||||
var nbt = this.saveWithoutMetadata(provider);
|
var nbt = this.saveWithoutMetadata(provider);
|
||||||
nbt.put("items", Utility.serializeAll(provider, this.getItems()));
|
nbt.put("items", Utility.serializeAll(this.getItems(), i -> i.serializeNBT(provider)));
|
||||||
return nbt;
|
return nbt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import de.ellpeck.prettypipes.Utility;
|
||||||
import de.ellpeck.prettypipes.items.IModule;
|
import de.ellpeck.prettypipes.items.IModule;
|
||||||
import de.ellpeck.prettypipes.items.ModuleItem;
|
import de.ellpeck.prettypipes.items.ModuleItem;
|
||||||
import de.ellpeck.prettypipes.items.ModuleTier;
|
import de.ellpeck.prettypipes.items.ModuleTier;
|
||||||
|
import de.ellpeck.prettypipes.misc.EquatableItemStack;
|
||||||
import de.ellpeck.prettypipes.misc.ItemEquality;
|
import de.ellpeck.prettypipes.misc.ItemEquality;
|
||||||
import de.ellpeck.prettypipes.misc.ItemFilter;
|
import de.ellpeck.prettypipes.misc.ItemFilter;
|
||||||
import de.ellpeck.prettypipes.network.NetworkLock;
|
import de.ellpeck.prettypipes.network.NetworkLock;
|
||||||
|
@ -17,16 +18,21 @@ import de.ellpeck.prettypipes.terminal.CraftingTerminalBlockEntity;
|
||||||
import de.ellpeck.prettypipes.terminal.ItemTerminalBlockEntity;
|
import de.ellpeck.prettypipes.terminal.ItemTerminalBlockEntity;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.core.HolderLookup;
|
||||||
import net.minecraft.core.component.DataComponentType;
|
import net.minecraft.core.component.DataComponentType;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.nbt.Tag;
|
||||||
import net.minecraft.util.Mth;
|
import net.minecraft.util.Mth;
|
||||||
import net.minecraft.world.entity.player.Inventory;
|
import net.minecraft.world.entity.player.Inventory;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.neoforged.neoforge.common.util.INBTSerializable;
|
||||||
import net.neoforged.neoforge.items.IItemHandler;
|
import net.neoforged.neoforge.items.IItemHandler;
|
||||||
import net.neoforged.neoforge.items.ItemHandlerHelper;
|
import net.neoforged.neoforge.items.ItemHandlerHelper;
|
||||||
import net.neoforged.neoforge.items.ItemStackHandler;
|
import net.neoforged.neoforge.items.ItemStackHandler;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
import org.apache.commons.lang3.tuple.Triple;
|
import org.apache.commons.lang3.tuple.Triple;
|
||||||
|
import org.jetbrains.annotations.UnknownNullability;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
@ -71,72 +77,67 @@ public class CraftingModuleItem extends ModuleItem {
|
||||||
return;
|
return;
|
||||||
var slot = tile.getModuleSlot(module);
|
var slot = tile.getModuleSlot(module);
|
||||||
var network = PipeNetwork.get(tile.getLevel());
|
var network = PipeNetwork.get(tile.getLevel());
|
||||||
// process crafting ingredient requests
|
if (!tile.activeCrafts.isEmpty()) {
|
||||||
if (!tile.craftIngredientRequests.isEmpty()) {
|
var activeCraft = tile.activeCrafts.getFirst();
|
||||||
network.startProfile("crafting_ingredients");
|
if (activeCraft.getLeft() == slot) {
|
||||||
var request = tile.craftIngredientRequests.getFirst();
|
var craftData = activeCraft.getRight();
|
||||||
if (request.getLeft() == slot) {
|
|
||||||
var locks = request.getRight();
|
|
||||||
var lock = locks.getFirst();
|
|
||||||
var equalityTypes = ItemFilter.getEqualityTypes(tile);
|
|
||||||
var dest = tile.getAvailableDestination(Direction.values(), lock.stack, true, true);
|
|
||||||
if (dest != null) {
|
|
||||||
var ensureItemOrder = module.get(Contents.TYPE).ensureItemOrder;
|
|
||||||
// if we're ensuring the correct item order and the item is already on the way, don't do anything yet
|
|
||||||
if (!ensureItemOrder || network.getPipeItemsOnTheWay(dest.getLeft()).findAny().isEmpty()) {
|
|
||||||
var requestRemain = network.requestExistingItem(lock.location, tile.getBlockPos(), dest.getLeft(), lock, dest.getRight(), equalityTypes);
|
|
||||||
network.resolveNetworkLock(lock);
|
|
||||||
locks.remove(lock);
|
|
||||||
|
|
||||||
// if we couldn't fit all items into the destination, create another request for the rest
|
// process crafting ingredient requests
|
||||||
var remain = lock.stack.copy();
|
if (!craftData.ingredientsToRequest.isEmpty()) {
|
||||||
remain.shrink(dest.getRight().getCount() - requestRemain.getCount());
|
network.startProfile("crafting_ingredients");
|
||||||
if (!remain.isEmpty()) {
|
var lock = craftData.ingredientsToRequest.getFirst();
|
||||||
var remainRequest = new NetworkLock(lock.location, remain);
|
var equalityTypes = ItemFilter.getEqualityTypes(tile);
|
||||||
// if we're ensuring item order, we need to insert the remaining request at the start so that it gets processed first
|
var dest = tile.getAvailableDestination(Direction.values(), lock.stack, true, true);
|
||||||
var index = ensureItemOrder ? 0 : tile.craftResultRequests.size();
|
if (dest != null) {
|
||||||
locks.add(index, remainRequest);
|
var ensureItemOrder = module.get(Contents.TYPE).ensureItemOrder;
|
||||||
network.createNetworkLock(remainRequest);
|
// if we're ensuring the correct item order and the item is already on the way, don't do anything yet
|
||||||
}
|
if (!ensureItemOrder || network.getPipeItemsOnTheWay(dest.getLeft()).findAny().isEmpty()) {
|
||||||
|
var requestRemain = network.requestExistingItem(lock.location, tile.getBlockPos(), dest.getLeft(), lock, dest.getRight(), equalityTypes);
|
||||||
|
network.resolveNetworkLock(lock);
|
||||||
|
craftData.ingredientsToRequest.remove(lock);
|
||||||
|
craftData.inProgress = true;
|
||||||
|
|
||||||
if (locks.isEmpty())
|
var traveling = lock.stack.copy();
|
||||||
tile.craftIngredientRequests.remove(request);
|
traveling.shrink(requestRemain.getCount());
|
||||||
}
|
craftData.travelingIngredients.add(traveling);
|
||||||
}
|
|
||||||
}
|
// if we couldn't fit all items into the destination, create another request for the rest
|
||||||
network.endProfile();
|
var remain = lock.stack.copy();
|
||||||
}
|
|
||||||
// pull requested crafting results from the network once they are stored
|
|
||||||
if (!tile.craftResultRequests.isEmpty()) {
|
|
||||||
network.startProfile("crafting_results");
|
|
||||||
var items = network.getOrderedNetworkItems(tile.getBlockPos());
|
|
||||||
var equalityTypes = ItemFilter.getEqualityTypes(tile);
|
|
||||||
for (var request : tile.craftResultRequests) {
|
|
||||||
if (request.getLeft() == slot) {
|
|
||||||
var remain = request.getRight().copy();
|
|
||||||
var destPipe = network.getPipe(request.getMiddle());
|
|
||||||
if (destPipe != null) {
|
|
||||||
var dest = destPipe.getAvailableDestinationOrConnectable(remain, true, true);
|
|
||||||
if (dest == null)
|
|
||||||
continue;
|
|
||||||
for (var item : items) {
|
|
||||||
var requestRemain = network.requestExistingItem(item, request.getMiddle(), dest.getLeft(), null, dest.getRight(), equalityTypes);
|
|
||||||
remain.shrink(dest.getRight().getCount() - requestRemain.getCount());
|
remain.shrink(dest.getRight().getCount() - requestRemain.getCount());
|
||||||
if (remain.isEmpty())
|
if (!remain.isEmpty()) {
|
||||||
break;
|
var remainRequest = new NetworkLock(lock.location, remain);
|
||||||
}
|
// if we're ensuring item order, we need to insert the remaining request at the start so that it gets processed first
|
||||||
if (remain.getCount() != request.getRight().getCount()) {
|
var index = ensureItemOrder ? 0 : craftData.ingredientsToRequest.size();
|
||||||
tile.craftResultRequests.remove(request);
|
craftData.ingredientsToRequest.add(index, remainRequest);
|
||||||
// if we couldn't pull everything, log a new request
|
network.createNetworkLock(remainRequest);
|
||||||
if (!remain.isEmpty())
|
}
|
||||||
tile.craftResultRequests.add(Triple.of(slot, request.getMiddle(), remain));
|
|
||||||
network.endProfile();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
network.endProfile();
|
||||||
|
}
|
||||||
|
|
||||||
|
// pull requested crafting results from the network once they are stored
|
||||||
|
if (!craftData.resultStackRemain.isEmpty()) {
|
||||||
|
network.startProfile("crafting_results");
|
||||||
|
var items = network.getOrderedNetworkItems(tile.getBlockPos());
|
||||||
|
var equalityTypes = ItemFilter.getEqualityTypes(tile);
|
||||||
|
var destPipe = network.getPipe(craftData.resultDestPipe);
|
||||||
|
if (destPipe != null) {
|
||||||
|
var dest = destPipe.getAvailableDestinationOrConnectable(craftData.resultStackRemain, true, true);
|
||||||
|
if (dest != null) {
|
||||||
|
for (var item : items) {
|
||||||
|
var requestRemain = network.requestExistingItem(item, craftData.resultDestPipe, dest.getLeft(), null, dest.getRight(), equalityTypes);
|
||||||
|
craftData.resultStackRemain.shrink(dest.getRight().getCount() - requestRemain.getCount());
|
||||||
|
if (craftData.resultStackRemain.isEmpty()) {
|
||||||
|
tile.activeCrafts.remove(activeCraft);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
network.endProfile();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
network.endProfile();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,30 +206,44 @@ public class CraftingModuleItem extends ModuleItem {
|
||||||
locks.addAll(ret.getLeft());
|
locks.addAll(ret.getLeft());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tile.craftIngredientRequests.add(Pair.of(slot, locks));
|
|
||||||
|
|
||||||
var remain = stack.copy();
|
var remain = stack.copy();
|
||||||
remain.shrink(resultAmount * toCraft);
|
remain.shrink(resultAmount * toCraft);
|
||||||
|
|
||||||
var result = stack.copy();
|
var result = stack.copy();
|
||||||
result.shrink(remain.getCount());
|
result.shrink(remain.getCount());
|
||||||
tile.craftResultRequests.add(Triple.of(slot, destPipe, result));
|
|
||||||
|
var activeCraft = new ActiveCraft(locks, new ArrayList<>(), destPipe, result);
|
||||||
|
tile.activeCrafts.add(Pair.of(slot, activeCraft));
|
||||||
|
|
||||||
return remain;
|
return remain;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ItemStack store(ItemStack module, PipeBlockEntity tile, ItemStack stack, Direction direction) {
|
public ItemStack store(ItemStack module, PipeBlockEntity tile, ItemStack stack, Direction direction) {
|
||||||
if (module.get(Contents.TYPE).insertSingles) {
|
var slot = tile.getModuleSlot(module);
|
||||||
var handler = tile.getItemHandler(direction);
|
var equalityTypes = ItemFilter.getEqualityTypes(tile);
|
||||||
if (handler != null) {
|
var matchingCraft = tile.activeCrafts.stream()
|
||||||
while (!stack.isEmpty()) {
|
.filter(c -> c.getLeft() == slot && !c.getRight().getTravelingIngredient(stack, equalityTypes).isEmpty())
|
||||||
var remain = ItemHandlerHelper.insertItem(handler, stack.copyWithCount(1), false);
|
.findAny().orElse(null);
|
||||||
if (!remain.isEmpty())
|
if (matchingCraft != null) {
|
||||||
break;
|
var data = matchingCraft.getRight();
|
||||||
stack.shrink(1);
|
data.travelingIngredients.remove(data.getTravelingIngredient(stack, equalityTypes));
|
||||||
|
|
||||||
|
if (module.get(Contents.TYPE).insertSingles) {
|
||||||
|
var handler = tile.getItemHandler(direction);
|
||||||
|
if (handler != null) {
|
||||||
|
while (!stack.isEmpty()) {
|
||||||
|
var remain = ItemHandlerHelper.insertItem(handler, stack.copyWithCount(1), false);
|
||||||
|
if (!remain.isEmpty())
|
||||||
|
break;
|
||||||
|
stack.shrink(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if we canceled the request and all input items are delivered (ie the machine actually got what it expected), remove it from the queue
|
||||||
|
if (data.canceled && data.travelingIngredients.size() <= 0 && data.ingredientsToRequest.size() <= 0)
|
||||||
|
tile.activeCrafts.remove(matchingCraft);
|
||||||
}
|
}
|
||||||
return stack;
|
return stack;
|
||||||
}
|
}
|
||||||
|
@ -262,4 +277,68 @@ public class CraftingModuleItem extends ModuleItem {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class ActiveCraft implements INBTSerializable<CompoundTag> {
|
||||||
|
|
||||||
|
public List<NetworkLock> ingredientsToRequest;
|
||||||
|
public List<ItemStack> travelingIngredients;
|
||||||
|
public BlockPos resultDestPipe;
|
||||||
|
public ItemStack resultStackRemain;
|
||||||
|
public boolean inProgress;
|
||||||
|
// we only remove canceled requests from the queue once their items are fully delivered to the crafting location, so that unfinished recipes don't get stuck in crafters etc.
|
||||||
|
public boolean canceled;
|
||||||
|
|
||||||
|
public ActiveCraft(List<NetworkLock> ingredientsToRequest, List<ItemStack> travelingIngredients, BlockPos resultDestPipe, ItemStack resultStackRemain) {
|
||||||
|
this.ingredientsToRequest = ingredientsToRequest;
|
||||||
|
this.travelingIngredients = travelingIngredients;
|
||||||
|
this.resultDestPipe = resultDestPipe;
|
||||||
|
this.resultStackRemain = resultStackRemain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ActiveCraft(HolderLookup.Provider provider, CompoundTag tag) {
|
||||||
|
this.deserializeNBT(provider, tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @UnknownNullability CompoundTag serializeNBT(HolderLookup.Provider provider) {
|
||||||
|
var ret = new CompoundTag();
|
||||||
|
ret.put("ingredients_to_request", Utility.serializeAll(this.ingredientsToRequest, n -> n.serializeNBT(provider)));
|
||||||
|
ret.put("traveling_ingredients", Utility.serializeAll(this.travelingIngredients, s -> (CompoundTag) s.save(provider, new CompoundTag())));
|
||||||
|
ret.putLong("result_dest_pipe", this.resultDestPipe.asLong());
|
||||||
|
ret.put("result_stack_remain", this.resultStackRemain.saveOptional(provider));
|
||||||
|
ret.putBoolean("in_progress", this.inProgress);
|
||||||
|
ret.putBoolean("canceled", this.canceled);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deserializeNBT(HolderLookup.Provider provider, CompoundTag nbt) {
|
||||||
|
this.ingredientsToRequest = Utility.deserializeAll(nbt.getList("ingredients_to_request", Tag.TAG_COMPOUND), t -> new NetworkLock(provider, t));
|
||||||
|
this.travelingIngredients = Utility.deserializeAll(nbt.getList("traveling_ingredients", Tag.TAG_COMPOUND), t -> ItemStack.parse(provider, t).orElseThrow());
|
||||||
|
this.resultDestPipe = BlockPos.of(nbt.getLong("result_dest_pipe"));
|
||||||
|
this.resultStackRemain = ItemStack.parseOptional(provider, nbt.getCompound("result_stack_remain"));
|
||||||
|
this.inProgress = nbt.getBoolean("in_progress");
|
||||||
|
this.canceled = nbt.getBoolean("canceled");
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemStack getTravelingIngredient(ItemStack stack, ItemEquality... equalityTypes) {
|
||||||
|
for (var traveling : this.travelingIngredients) {
|
||||||
|
if (ItemEquality.compareItems(stack, traveling, equalityTypes))
|
||||||
|
return traveling;
|
||||||
|
}
|
||||||
|
return ItemStack.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean markCanceledOrResolve(PipeNetwork network) {
|
||||||
|
if (this.inProgress) {
|
||||||
|
this.canceled = true;
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
for (var lock : this.ingredientsToRequest)
|
||||||
|
network.resolveNetworkLock(lock);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ public class RetrievalModuleItem extends ModuleItem {
|
||||||
continue;
|
continue;
|
||||||
var remain = dest.getRight().copy();
|
var remain = dest.getRight().copy();
|
||||||
// are we already waiting for crafting results? If so, don't request those again
|
// are we already waiting for crafting results? If so, don't request those again
|
||||||
remain.shrink(network.getCurrentlyCraftingAmount(tile.getBlockPos(), copy, equalityTypes));
|
remain.shrink(network.getCurrentlyCraftingAmount(tile.getBlockPos(), copy, true, equalityTypes));
|
||||||
if (network.requestItem(tile.getBlockPos(), dest.getLeft(), remain, equalityTypes).isEmpty())
|
if (network.requestItem(tile.getBlockPos(), dest.getLeft(), remain, equalityTypes).isEmpty())
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,7 +136,7 @@ public class ItemTerminalBlockEntity extends BlockEntity implements IPipeConnect
|
||||||
if (playersToSync.length > 0) {
|
if (playersToSync.length > 0) {
|
||||||
var clientItems = this.networkItems.values().stream().map(NetworkItem::asStack).collect(Collectors.toList());
|
var clientItems = this.networkItems.values().stream().map(NetworkItem::asStack).collect(Collectors.toList());
|
||||||
var clientCraftables = PipeNetwork.get(this.level).getAllCraftables(pipe.getBlockPos()).stream().map(Pair::getRight).collect(Collectors.toList());
|
var clientCraftables = PipeNetwork.get(this.level).getAllCraftables(pipe.getBlockPos()).stream().map(Pair::getRight).collect(Collectors.toList());
|
||||||
var currentlyCrafting = this.getCurrentlyCrafting().stream().sorted(Comparator.comparingInt(ItemStack::getCount).reversed()).collect(Collectors.toList());
|
var currentlyCrafting = this.getCurrentlyCrafting(false).stream().sorted(Comparator.comparingInt(ItemStack::getCount).reversed()).collect(Collectors.toList());
|
||||||
for (var player : playersToSync) {
|
for (var player : playersToSync) {
|
||||||
if (!(player.containerMenu instanceof ItemTerminalContainer container))
|
if (!(player.containerMenu instanceof ItemTerminalContainer container))
|
||||||
continue;
|
continue;
|
||||||
|
@ -200,12 +200,12 @@ public class ItemTerminalBlockEntity extends BlockEntity implements IPipeConnect
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ItemStack> getCurrentlyCrafting() {
|
private List<ItemStack> getCurrentlyCrafting(boolean includeCanceled) {
|
||||||
var network = PipeNetwork.get(this.level);
|
var network = PipeNetwork.get(this.level);
|
||||||
var pipe = this.getConnectedPipe();
|
var pipe = this.getConnectedPipe();
|
||||||
if (pipe == null)
|
if (pipe == null)
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
var crafting = network.getCurrentlyCrafting(pipe.getBlockPos());
|
var crafting = network.getCurrentlyCrafting(pipe.getBlockPos(), includeCanceled);
|
||||||
return crafting.stream().map(Pair::getRight).collect(Collectors.toList());
|
return crafting.stream().map(Pair::getRight).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,14 +216,8 @@ public class ItemTerminalBlockEntity extends BlockEntity implements IPipeConnect
|
||||||
return;
|
return;
|
||||||
for (var craftable : network.getAllCraftables(pipe.getBlockPos())) {
|
for (var craftable : network.getAllCraftables(pipe.getBlockPos())) {
|
||||||
var otherPipe = network.getPipe(craftable.getLeft());
|
var otherPipe = network.getPipe(craftable.getLeft());
|
||||||
if (otherPipe != null) {
|
if (otherPipe != null)
|
||||||
for (var locks : otherPipe.craftIngredientRequests) {
|
otherPipe.activeCrafts.removeIf(c -> c.getRight().markCanceledOrResolve(network));
|
||||||
for (var lock : locks.getRight())
|
|
||||||
network.resolveNetworkLock(lock);
|
|
||||||
}
|
|
||||||
otherPipe.craftIngredientRequests.clear();
|
|
||||||
otherPipe.craftResultRequests.clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
var lookingPlayers = this.getLookingPlayers();
|
var lookingPlayers = this.getLookingPlayers();
|
||||||
if (lookingPlayers.length > 0)
|
if (lookingPlayers.length > 0)
|
||||||
|
@ -234,7 +228,7 @@ public class ItemTerminalBlockEntity extends BlockEntity implements IPipeConnect
|
||||||
public void saveAdditional(CompoundTag compound, HolderLookup.Provider pRegistries) {
|
public void saveAdditional(CompoundTag compound, HolderLookup.Provider pRegistries) {
|
||||||
super.saveAdditional(compound, pRegistries);
|
super.saveAdditional(compound, pRegistries);
|
||||||
compound.put("items", this.items.serializeNBT(pRegistries));
|
compound.put("items", this.items.serializeNBT(pRegistries));
|
||||||
compound.put("requests", Utility.serializeAll(pRegistries, this.existingRequests));
|
compound.put("requests", Utility.serializeAll(this.existingRequests, i -> i.serializeNBT(pRegistries)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -68,10 +68,10 @@
|
||||||
"info.prettypipes.blacklist.description": "Items in filter slots are disallowed",
|
"info.prettypipes.blacklist.description": "Items in filter slots are disallowed",
|
||||||
"info.prettypipes.insert_singles_on": "\u00A72S",
|
"info.prettypipes.insert_singles_on": "\u00A72S",
|
||||||
"info.prettypipes.insert_singles_off": "\u00A74\u00A7mS",
|
"info.prettypipes.insert_singles_off": "\u00A74\u00A7mS",
|
||||||
"info.prettypipes.insert_singles.description": "Whether items should be inserted one at a time, rather than as a stack\nRecommended for use with the Crafter",
|
"info.prettypipes.insert_singles.description": "Whether items should be inserted one at a time, rather than as a stack\n\u00A7oRecommended for use with the Crafter",
|
||||||
"info.prettypipes.ensure_item_order_on": "\u00A72O",
|
"info.prettypipes.ensure_item_order_on": "\u00A72O",
|
||||||
"info.prettypipes.ensure_item_order_off": "\u00A74\u00A7mO",
|
"info.prettypipes.ensure_item_order_off": "\u00A74\u00A7mO",
|
||||||
"info.prettypipes.ensure_item_order.description": "Whether the module should wait for items to be inserted in the order they appear in the input slots\nRecommended for use with the Crafter",
|
"info.prettypipes.ensure_item_order.description": "Whether the module should wait for items to be inserted in the order they appear in the input slots\n\u00A7oRecommended for use with the Crafter",
|
||||||
"info.prettypipes.shift": "Hold Shift for info",
|
"info.prettypipes.shift": "Hold Shift for info",
|
||||||
"info.prettypipes.populate": "P",
|
"info.prettypipes.populate": "P",
|
||||||
"info.prettypipes.populate.description": "Populate filter slots with items from adjacent inventories",
|
"info.prettypipes.populate.description": "Populate filter slots with items from adjacent inventories",
|
||||||
|
@ -94,7 +94,7 @@
|
||||||
"info.prettypipes.energy": "%s / %s FE",
|
"info.prettypipes.energy": "%s / %s FE",
|
||||||
"info.prettypipes.crafting": "Awaiting",
|
"info.prettypipes.crafting": "Awaiting",
|
||||||
"info.prettypipes.cancel_all": "Cancel",
|
"info.prettypipes.cancel_all": "Cancel",
|
||||||
"info.prettypipes.cancel_all.desc": "Stops waiting for current crafting outputs\nDoesn't remove inputs from blocks",
|
"info.prettypipes.cancel_all.desc": "Stops waiting for current crafting outputs\nOngoing crafting operations are still completed",
|
||||||
"info.prettypipes.no_pipe_connected": "The terminal needs to be connected to a pipe network",
|
"info.prettypipes.no_pipe_connected": "The terminal needs to be connected to a pipe network",
|
||||||
"info.prettypipes.too_many_pipes_connected": "The terminal can only be connected to a single pipe at a time",
|
"info.prettypipes.too_many_pipes_connected": "The terminal can only be connected to a single pipe at a time",
|
||||||
"dir.prettypipes.up": "Up",
|
"dir.prettypipes.up": "Up",
|
||||||
|
|
Loading…
Reference in a new issue