Skip to content

Commit

Permalink
Use Stream Codecs for transporter stacks
Browse files Browse the repository at this point in the history
  • Loading branch information
pupnewfster committed May 6, 2024
1 parent f9bb915 commit e052d61
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ public void onUpdateServer() {

if (!deletes.isEmpty() || !needsSync.isEmpty()) {
//Notify clients, so that we send the information before we start clearing our lists
PacketUtils.sendToAllTracking(new PacketTransporterBatch(getLevel().registryAccess(), pos, deletes, needsSync), getTransmitterTile());
PacketUtils.sendToAllTracking(PacketTransporterBatch.create(pos, deletes, needsSync), getTransmitterTile());
// Now remove any entries from transit that have been deleted
OfInt ofInt = deletes.iterator();
while (ofInt.hasNext()) {
Expand Down Expand Up @@ -441,7 +441,7 @@ private TransitResponse updateTransit(boolean doEmit, TransporterStack stack, Tr
if (doEmit) {
int stackId = nextId++;
addStack(stackId, stack);
PacketUtils.sendToAllTracking(new PacketTransporterSync(getLevel().registryAccess(), getBlockPos(), stackId, stack), getTransmitterTile());
PacketUtils.sendToAllTracking(PacketTransporterSync.create(getBlockPos(), stackId, stack), getTransmitterTile());
getTransmitterTile().markForSave();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.IntFunction;
import mekanism.api.NBTConstants;
import mekanism.api.math.MathUtils;
import mekanism.api.text.EnumColor;
import mekanism.common.content.network.transmitter.DiversionTransporter.DiversionControl;
import mekanism.common.content.network.transmitter.LogisticalTransporterBase;
import mekanism.common.content.transporter.TransporterPathfinder.Destination;
import mekanism.common.content.transporter.TransporterPathfinder.IdlePathData;
Expand All @@ -26,20 +25,42 @@
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtUtils;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.util.ByIdMap;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.neoforged.neoforge.network.codec.NeoForgeStreamCodecs;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public class TransporterStack {

//Make sure to call updateForPos before calling this method
public static StreamCodec<RegistryFriendlyByteBuf, TransporterStack> STREAM_CODEC = NeoForgeStreamCodecs.composite(
ByteBufCodecs.optional(EnumColor.STREAM_CODEC), stack -> Optional.ofNullable(stack.color),
ByteBufCodecs.VAR_INT, stack -> stack.progress,
BlockPos.STREAM_CODEC, stack -> stack.originalLocation,
Path.STREAM_CODEC, TransporterStack::getPathType,
ByteBufCodecs.optional(BlockPos.STREAM_CODEC), stack -> Optional.ofNullable(stack.clientNext),
BlockPos.STREAM_CODEC, stack -> stack.clientPrev,
ItemStack.OPTIONAL_STREAM_CODEC, stack -> stack.itemStack,
(color, progress, originalLocation, pathType, clientNext, clientPrev, itemStack) -> {
TransporterStack stack = new TransporterStack();
stack.color = color.orElse(null);
stack.progress = progress == 0 ? 5 : progress;
stack.originalLocation = originalLocation;
stack.pathType = pathType;
stack.clientNext = clientNext.orElse(null);
stack.clientPrev = clientPrev;
stack.itemStack = itemStack;
return stack;
}
);

public ItemStack itemStack = ItemStack.EMPTY;

public int progress;
Expand All @@ -51,6 +72,7 @@ public class TransporterStack {
public Direction idleDir = null;
public BlockPos originalLocation;
public BlockPos homeLocation;
@Nullable
private BlockPos clientNext;
private BlockPos clientPrev;
@Nullable
Expand All @@ -69,38 +91,6 @@ public static TransporterStack readFromUpdate(HolderLookup.Provider provider, Co
return stack;
}

public static TransporterStack readFromPacket(RegistryFriendlyByteBuf dataStream) {
TransporterStack stack = new TransporterStack();
stack.read(dataStream);
if (stack.progress == 0) {
stack.progress = 5;
}
return stack;
}

public void write(RegistryFriendlyByteBuf buf, BlockPos pos) {
buf.writeVarInt(TransporterUtils.getColorIndex(color));
buf.writeVarInt(progress);
buf.writeBlockPos(originalLocation);
buf.writeEnum(getPathType());
buf.writeNullable(getNext(pos), (b, p) -> b.writeBlockPos(p));
buf.writeBlockPos(getPrev(pos));
ItemStack.OPTIONAL_STREAM_CODEC.encode(buf, itemStack);
}

public void read(RegistryFriendlyByteBuf dataStream) {
color = TransporterUtils.readColor(dataStream.readVarInt());
progress = dataStream.readVarInt();
originalLocation = dataStream.readBlockPos();
pathType = dataStream.readEnum(Path.class);
//TODO - 1.20.4: SP: The clientNext and clientPrev have issues in single player as they won't get set
// though in all our use cases we are forcing a read/write to prevent mutation or leaking from one side to another
// so at least for now it doesn't fully matter
clientNext = dataStream.readNullable(buf -> buf.readBlockPos());
clientPrev = dataStream.readBlockPos();
itemStack = ItemStack.OPTIONAL_STREAM_CODEC.decode(dataStream);
}

public void writeToUpdateTag(HolderLookup.Provider provider, LogisticalTransporterBase transporter, CompoundTag updateTag) {
if (color != null) {
NBTUtils.writeEnum(updateTag, NBTConstants.COLOR, color);
Expand Down Expand Up @@ -248,6 +238,13 @@ public boolean isFinal(LogisticalTransporterBase transporter) {
return pathToTarget.indexOf(transporter.getBlockPos()) == (getPathType().hasTarget() ? 1 : 0);
}

//TODO - 1.20.5: Re-evaluate this method
public TransporterStack updateForPos(BlockPos pos) {
clientNext = getNext(pos);
clientPrev = getPrev(pos);
return this;
}

@Nullable
public BlockPos getNext(LogisticalTransporterBase transporter) {
return transporter.isRemote() ? clientNext : getNext(transporter.getBlockPos());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,28 @@
import mekanism.common.network.PacketUtils;
import mekanism.common.tile.transmitter.TileEntityLogisticalTransporterBase;
import net.minecraft.core.BlockPos;
import net.minecraft.core.RegistryAccess;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.neoforged.neoforge.common.util.FriendlyByteBufUtil;
import net.neoforged.neoforge.network.handling.IPayloadContext;
import org.jetbrains.annotations.NotNull;

public record PacketTransporterBatch(BlockPos pos, IntSet deletes, byte[] rawUpdates) implements IMekanismPacket {
public record PacketTransporterBatch(BlockPos pos, IntSet deletes, Int2ObjectMap<TransporterStack> updates) implements IMekanismPacket {

public static final CustomPacketPayload.Type<PacketTransporterBatch> TYPE = new CustomPacketPayload.Type<>(Mekanism.rl("transporter_batch"));
public static final StreamCodec<FriendlyByteBuf, PacketTransporterBatch> STREAM_CODEC = StreamCodec.composite(
public static final StreamCodec<RegistryFriendlyByteBuf, PacketTransporterBatch> STREAM_CODEC = StreamCodec.composite(
BlockPos.STREAM_CODEC, PacketTransporterBatch::pos,
ByteBufCodecs.VAR_INT.apply(ByteBufCodecs.collection(IntOpenHashSet::new)), PacketTransporterBatch::deletes,
ByteBufCodecs.BYTE_ARRAY, PacketTransporterBatch::rawUpdates,
ByteBufCodecs.map(Int2ObjectOpenHashMap::new, ByteBufCodecs.VAR_INT, TransporterStack.STREAM_CODEC), PacketTransporterBatch::updates,
PacketTransporterBatch::new
);

public PacketTransporterBatch(RegistryAccess registryAccess, BlockPos pos, IntSet deletes, Int2ObjectMap<TransporterStack> updates) {
//TODO - 1.20.4: SP: Figure out if there is a better way for us to handle not leaking the instance than just forcing a write and read
// Also validate that we can actually just directly use deletes without copying it or anything
this(pos, deletes, FriendlyByteBufUtil.writeCustomData(buffer -> buffer.writeMap(updates, FriendlyByteBuf::writeVarInt, (buf, stack) -> stack.write(buffer, pos)), registryAccess));
public static PacketTransporterBatch create(BlockPos pos, IntSet deletes, Int2ObjectMap<TransporterStack> updates) {
for (TransporterStack stack : updates.values()) {
stack.updateForPos(pos);
}
return new PacketTransporterBatch(pos, deletes, updates);
}

@NotNull
Expand All @@ -46,8 +45,6 @@ public CustomPacketPayload.Type<PacketTransporterBatch> type() {
public void handle(IPayloadContext context) {
if (PacketUtils.blockEntity(context, pos) instanceof TileEntityLogisticalTransporterBase tile) {
LogisticalTransporterBase transporter = tile.getTransmitter();
Int2ObjectMap<TransporterStack> updates = PacketUtils.read(context.player().level().registryAccess(), rawUpdates, buffer ->
buffer.readMap(Int2ObjectOpenHashMap::new, ByteBufCodecs.VAR_INT, buf -> TransporterStack.readFromPacket(buffer)));
for (Int2ObjectMap.Entry<TransporterStack> entry : updates.int2ObjectEntrySet()) {
transporter.addStack(entry.getIntKey(), entry.getValue());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,30 @@
package mekanism.common.network.to_client.transmitter;

import io.netty.buffer.ByteBuf;
import mekanism.common.Mekanism;
import mekanism.common.content.network.transmitter.LogisticalTransporterBase;
import mekanism.common.content.transporter.TransporterStack;
import mekanism.common.network.IMekanismPacket;
import mekanism.common.network.PacketUtils;
import mekanism.common.tile.transmitter.TileEntityLogisticalTransporterBase;
import net.minecraft.core.BlockPos;
import net.minecraft.core.RegistryAccess;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.neoforged.neoforge.common.util.FriendlyByteBufUtil;
import net.neoforged.neoforge.network.handling.IPayloadContext;
import org.jetbrains.annotations.NotNull;

public record PacketTransporterSync(BlockPos pos, int stackId, byte[] rawStack) implements IMekanismPacket {
public record PacketTransporterSync(BlockPos pos, int stackId, TransporterStack stack) implements IMekanismPacket {

public static final CustomPacketPayload.Type<PacketTransporterSync> TYPE = new CustomPacketPayload.Type<>(Mekanism.rl("transporter_sync"));
public static final StreamCodec<ByteBuf, PacketTransporterSync> STREAM_CODEC = StreamCodec.composite(
public static final StreamCodec<RegistryFriendlyByteBuf, PacketTransporterSync> STREAM_CODEC = StreamCodec.composite(
BlockPos.STREAM_CODEC, PacketTransporterSync::pos,
ByteBufCodecs.INT, PacketTransporterSync::stackId,
ByteBufCodecs.BYTE_ARRAY, PacketTransporterSync::rawStack,
ByteBufCodecs.VAR_INT, PacketTransporterSync::stackId,
TransporterStack.STREAM_CODEC, PacketTransporterSync::stack,
PacketTransporterSync::new
);

public PacketTransporterSync(RegistryAccess registryAccess, BlockPos pos, int stackId, TransporterStack stack) {
//TODO - 1.20.4: SP: Figure out if there is a better way for us to handle not leaking the instance than just forcing a write and read
this(pos, stackId, FriendlyByteBufUtil.writeCustomData(buffer -> stack.write(buffer, pos), registryAccess));
public static PacketTransporterSync create(BlockPos pos, int stackId, TransporterStack stack) {
return new PacketTransporterSync(pos, stackId, stack.updateForPos(pos));
}

@NotNull
Expand All @@ -40,9 +36,7 @@ public CustomPacketPayload.Type<PacketTransporterSync> type() {
@Override
public void handle(IPayloadContext context) {
if (PacketUtils.blockEntity(context, pos) instanceof TileEntityLogisticalTransporterBase tile) {
LogisticalTransporterBase transporter = tile.getTransmitter();
TransporterStack stack = PacketUtils.read(context.player().level().registryAccess(), rawStack, TransporterStack::readFromPacket);
transporter.addStack(stackId, stack);
tile.getTransmitter().addStack(stackId, stack);
}
}
}

0 comments on commit e052d61

Please sign in to comment.