PrettyPipes/src/main/java/de/ellpeck/prettypipes/terminal/ItemTerminalTileEntity.java

223 lines
9 KiB
Java
Raw Normal View History

2020-05-07 18:30:40 +02:00
package de.ellpeck.prettypipes.terminal;
import de.ellpeck.prettypipes.PrettyPipes;
import de.ellpeck.prettypipes.Registry;
import de.ellpeck.prettypipes.Utility;
import de.ellpeck.prettypipes.misc.EquatableItemStack;
import de.ellpeck.prettypipes.misc.ItemEqualityType;
2020-05-07 23:06:35 +02:00
import de.ellpeck.prettypipes.misc.ItemOrder;
import de.ellpeck.prettypipes.network.*;
2020-05-07 18:30:40 +02:00
import de.ellpeck.prettypipes.packets.PacketHandler;
import de.ellpeck.prettypipes.packets.PacketNetworkItems;
import de.ellpeck.prettypipes.pipe.PipeTileEntity;
import de.ellpeck.prettypipes.terminal.containers.ItemTerminalContainer;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.inventory.container.Container;
import net.minecraft.inventory.container.INamedContainerProvider;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.ITextComponent;
2020-05-07 21:10:29 +02:00
import net.minecraft.util.text.Style;
import net.minecraft.util.text.TextFormatting;
2020-05-07 18:30:40 +02:00
import net.minecraft.util.text.TranslationTextComponent;
import net.minecraft.world.server.ServerWorld;
2020-05-09 12:57:25 +02:00
import net.minecraftforge.common.util.Constants;
import net.minecraftforge.common.util.Constants.NBT;
import net.minecraftforge.items.IItemHandler;
2020-05-07 18:30:40 +02:00
import net.minecraftforge.items.ItemStackHandler;
import org.apache.commons.lang3.mutable.MutableInt;
2020-05-07 21:10:29 +02:00
import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.tuple.Triple;
2020-05-07 18:30:40 +02:00
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
import java.util.stream.Collectors;
public class ItemTerminalTileEntity extends TileEntity implements INamedContainerProvider, ITickableTileEntity {
public final ItemStackHandler items = new ItemStackHandler(12) {
@Override
public boolean isItemValid(int slot, @Nonnull ItemStack stack) {
2020-05-07 21:10:29 +02:00
return true;
2020-05-07 18:30:40 +02:00
}
};
2020-05-07 21:10:29 +02:00
public Map<EquatableItemStack, NetworkItem> networkItems;
private final Queue<NetworkLock> pendingRequests = new ArrayDeque<>();
2020-05-07 18:30:40 +02:00
2020-05-08 22:58:16 +02:00
protected ItemTerminalTileEntity(TileEntityType<?> tileEntityTypeIn) {
super(tileEntityTypeIn);
}
2020-05-07 18:30:40 +02:00
public ItemTerminalTileEntity() {
2020-05-08 22:58:16 +02:00
this(Registry.itemTerminalTileEntity);
2020-05-07 18:30:40 +02:00
}
@Override
public void tick() {
if (this.world.isRemote)
return;
PipeNetwork network = PipeNetwork.get(this.world);
PipeTileEntity pipe = this.getConnectedPipe();
if (pipe == null)
return;
boolean update = false;
2020-05-07 18:30:40 +02:00
if (this.world.getGameTime() % 10 == 0) {
for (int i = 6; i < 12; i++) {
ItemStack extracted = this.items.extractItem(i, Integer.MAX_VALUE, true);
if (extracted.isEmpty())
continue;
if (!network.tryInsertItem(pipe.getPos(), this.pos, extracted, true))
continue;
this.items.extractItem(i, extracted.getCount(), false);
break;
}
2020-05-07 21:10:29 +02:00
if (!this.pendingRequests.isEmpty()) {
NetworkLock request = this.pendingRequests.remove();
network.resolveNetworkLock(request);
2020-05-09 16:27:49 +02:00
if (network.requestItem(request.location, pipe.getPos(), this.pos, request.stack, request.stack.getCount(), ItemEqualityType.NBT))
update = true;
2020-05-07 21:10:29 +02:00
}
2020-05-07 18:30:40 +02:00
}
if (this.world.getGameTime() % 100 == 0 || update) {
2020-05-07 21:10:29 +02:00
PlayerEntity[] lookingPlayers = this.getLookingPlayers();
2020-05-07 18:30:40 +02:00
if (lookingPlayers.length > 0)
this.updateItems(lookingPlayers);
}
}
@Override
public void remove() {
super.remove();
PipeNetwork network = PipeNetwork.get(this.world);
for (NetworkLock lock : this.pendingRequests)
network.resolveNetworkLock(lock);
}
2020-05-07 23:06:35 +02:00
public PipeTileEntity getConnectedPipe() {
2020-05-07 18:30:40 +02:00
PipeNetwork network = PipeNetwork.get(this.world);
for (Direction dir : Direction.values()) {
PipeTileEntity pipe = network.getPipe(this.pos.offset(dir));
if (pipe != null)
return pipe;
}
return null;
}
public void updateItems(PlayerEntity... playersToSync) {
2020-05-07 23:06:35 +02:00
if (this.getConnectedPipe() == null)
return;
2020-05-07 18:30:40 +02:00
this.networkItems = this.collectItems();
2020-05-07 21:10:29 +02:00
if (playersToSync.length > 0) {
List<ItemStack> clientItems = this.networkItems.values().stream().map(NetworkItem::asStack).collect(Collectors.toList());
for (PlayerEntity player : playersToSync) {
if (!(player.openContainer instanceof ItemTerminalContainer))
continue;
ItemTerminalTileEntity tile = ((ItemTerminalContainer) player.openContainer).tile;
if (tile != this)
continue;
2020-05-08 20:56:27 +02:00
PacketHandler.sendTo(player, new PacketNetworkItems(clientItems));
2020-05-07 21:10:29 +02:00
}
2020-05-07 18:30:40 +02:00
}
}
2020-05-07 21:10:29 +02:00
public void requestItem(PlayerEntity player, ItemStack stack) {
PipeNetwork network = PipeNetwork.get(this.world);
network.startProfile("terminal_request_item");
this.updateItems();
2020-05-09 13:40:46 +02:00
int requested = this.requestItemImpl(stack);
if (requested > 0) {
player.sendMessage(new TranslationTextComponent("info." + PrettyPipes.ID + ".sending", requested, stack.getDisplayName()).setStyle(new Style().setColor(TextFormatting.GREEN)));
} else {
player.sendMessage(new TranslationTextComponent("info." + PrettyPipes.ID + ".not_found", stack.getDisplayName()).setStyle(new Style().setColor(TextFormatting.RED)));
}
network.endProfile();
}
protected int requestItemImpl(ItemStack stack) {
PipeNetwork network = PipeNetwork.get(this.world);
EquatableItemStack equatable = new EquatableItemStack(stack);
2020-05-07 21:10:29 +02:00
NetworkItem item = this.networkItems.get(equatable);
if (item != null) {
int remain = stack.getCount();
for (NetworkLocation location : item.getLocations()) {
2020-05-09 16:27:49 +02:00
int amount = location.getItemAmount(this.world, stack, ItemEqualityType.NBT);
if (amount <= 0)
continue;
amount -= network.getLockedAmount(location.getPos(), stack, ItemEqualityType.NBT);
if (amount > 0) {
if (remain < amount)
amount = remain;
NetworkLock lock = new NetworkLock(location, stack);
this.pendingRequests.add(lock);
network.createNetworkLock(lock);
remain -= amount;
if (remain <= 0)
break;
2020-05-07 21:10:29 +02:00
}
}
2020-05-09 13:40:46 +02:00
return stack.getCount() - remain;
2020-05-07 21:10:29 +02:00
}
2020-05-09 13:40:46 +02:00
return 0;
2020-05-07 21:10:29 +02:00
}
2020-05-09 14:56:58 +02:00
protected PlayerEntity[] getLookingPlayers() {
2020-05-07 21:10:29 +02:00
return this.world.getPlayers().stream()
.filter(p -> p.openContainer instanceof ItemTerminalContainer)
.filter(p -> ((ItemTerminalContainer) p.openContainer).tile == this)
.toArray(PlayerEntity[]::new);
}
private Map<EquatableItemStack, NetworkItem> collectItems() {
2020-05-07 18:30:40 +02:00
PipeNetwork network = PipeNetwork.get(this.world);
network.startProfile("terminal_collect_items");
PipeTileEntity pipe = this.getConnectedPipe();
Map<EquatableItemStack, NetworkItem> items = new HashMap<>();
for (NetworkLocation location : network.getOrderedNetworkItems(pipe.getPos())) {
2020-05-09 12:57:25 +02:00
for (ItemStack stack : location.getItems(this.world).values()) {
2020-05-07 18:30:40 +02:00
EquatableItemStack equatable = new EquatableItemStack(stack);
NetworkItem item = items.computeIfAbsent(equatable, NetworkItem::new);
item.add(location, stack);
}
}
network.endProfile();
2020-05-07 21:10:29 +02:00
return items;
2020-05-07 18:30:40 +02:00
}
@Override
public CompoundNBT write(CompoundNBT compound) {
compound.put("items", this.items.serializeNBT());
2020-05-09 12:57:25 +02:00
compound.put("requests", Utility.serializeAll(this.pendingRequests));
2020-05-07 18:30:40 +02:00
return super.write(compound);
}
@Override
public void read(CompoundNBT compound) {
this.items.deserializeNBT(compound.getCompound("items"));
2020-05-09 12:57:25 +02:00
this.pendingRequests.clear();
this.pendingRequests.addAll(Utility.deserializeAll(compound.getList("requests", NBT.TAG_COMPOUND), NetworkLock::new));
2020-05-07 18:30:40 +02:00
super.read(compound);
}
@Override
public ITextComponent getDisplayName() {
return new TranslationTextComponent("container." + PrettyPipes.ID + ".item_terminal");
}
@Nullable
@Override
public Container createMenu(int window, PlayerInventory inv, PlayerEntity player) {
return new ItemTerminalContainer(Registry.itemTerminalContainer, window, player, this.pos);
}
}