mirror of
https://github.com/Sollace/Unicopia.git
synced 2025-02-01 11:36:43 +01:00
Send tracked data in smaller packets to avoid large buffer allocation warnings being printed
This commit is contained in:
parent
79d97adf0b
commit
1e3560fc04
14 changed files with 99 additions and 123 deletions
|
@ -64,7 +64,6 @@ public class ChangelingDisguiseAbility extends ChangelingFeedAbility {
|
|||
}
|
||||
|
||||
player.calculateDimensions();
|
||||
iplayer.setDirty();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -65,7 +65,6 @@ public class ToggleFlightAbility implements Ability<Hit> {
|
|||
} else {
|
||||
player.getPhysics().cancelFlight(true);
|
||||
}
|
||||
player.setDirty();
|
||||
player.setAnimation(Animation.SPREAD_WINGS, Animation.Recipient.ANYONE);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -48,7 +48,6 @@ class GravityCommand {
|
|||
static int set(ServerCommandSource source, Collection<? extends Entity> targets, float gravity, boolean isSelf) {
|
||||
List<Entity> affected = targets.stream().map(Living::living).filter(Objects::nonNull).map(l -> {
|
||||
l.getPhysics().setBaseGravityModifier(gravity);
|
||||
l.setDirty();
|
||||
if (l.asEntity() instanceof PlayerEntity player) {
|
||||
if (source.getEntity() == player) {
|
||||
player.sendMessage(Text.translatable("commands.gravity.set.self", gravity));
|
||||
|
|
|
@ -31,7 +31,6 @@ import com.minelittlepony.unicopia.input.Interactable;
|
|||
import com.minelittlepony.unicopia.item.GlassesItem;
|
||||
import com.minelittlepony.unicopia.item.UItems;
|
||||
import com.minelittlepony.unicopia.item.enchantment.UEnchantments;
|
||||
import com.minelittlepony.unicopia.network.datasync.Transmittable;
|
||||
import com.minelittlepony.unicopia.network.track.DataTracker;
|
||||
import com.minelittlepony.unicopia.network.track.DataTrackerManager;
|
||||
import com.minelittlepony.unicopia.network.track.Trackable;
|
||||
|
@ -74,7 +73,7 @@ import net.minecraft.util.math.Direction;
|
|||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
public abstract class Living<T extends LivingEntity> implements Equine<T>, Caster<T>, Transmittable {
|
||||
public abstract class Living<T extends LivingEntity> implements Equine<T>, Caster<T> {
|
||||
protected final T entity;
|
||||
|
||||
private final SpellInventory spells;
|
||||
|
@ -479,9 +478,6 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
|
|||
return MathHelper.clamp(level / (float)maxLevel, 0, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDirty() {}
|
||||
|
||||
@Override
|
||||
public void toNBT(NbtCompound compound) {
|
||||
enchants.toNBT(compound);
|
||||
|
@ -498,12 +494,10 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
|
|||
fromSynchronizedNbt(compound);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toSyncronisedNbt(NbtCompound compound) {
|
||||
compound.put("armour", armour.toNBT());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromSynchronizedNbt(NbtCompound compound) {
|
||||
armour.fromNBT(compound.getCompound("armour"));
|
||||
}
|
||||
|
|
|
@ -232,10 +232,8 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
|
|||
entity.calculateDimensions();
|
||||
}
|
||||
|
||||
if (!pony.isClient()) {
|
||||
pony.setDirty();
|
||||
}
|
||||
}
|
||||
|
||||
public double getHorizontalMotion() {
|
||||
return getClientVelocity().horizontalLengthSquared();
|
||||
|
@ -621,6 +619,7 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
|
|||
thrustScale = 0;
|
||||
descentRate = 0;
|
||||
entity.calculateDimensions();
|
||||
pony.setDirty();
|
||||
|
||||
if (entity.isOnGround() || !force) {
|
||||
//BlockState steppingState = pony.asEntity().getSteppingBlockState();
|
||||
|
|
|
@ -175,6 +175,7 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
|
|||
animation.animation().getSound().ifPresent(sound -> {
|
||||
playSound(sound, sound == USounds.ENTITY_PLAYER_WOLOLO ? 0.1F : 0.9F, 1);
|
||||
});
|
||||
setDirty();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -314,7 +315,7 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
|
|||
return getSpecies().getAffinity();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public void setDirty() {
|
||||
dirty = true;
|
||||
}
|
||||
|
|
|
@ -1,17 +1,12 @@
|
|||
package com.minelittlepony.unicopia.network;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||
import com.minelittlepony.unicopia.util.serialization.PacketCodec;
|
||||
import com.sollace.fabwork.api.packets.HandledPacket;
|
||||
|
||||
import io.netty.buffer.ByteBufInputStream;
|
||||
import io.netty.buffer.ByteBufOutputStream;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.nbt.NbtIo;
|
||||
|
||||
/**
|
||||
* Sent to the client to update various data pertaining to a particular player.
|
||||
|
@ -26,11 +21,7 @@ public class MsgPlayerCapabilities implements HandledPacket<PlayerEntity> {
|
|||
|
||||
MsgPlayerCapabilities(PacketByteBuf buffer) {
|
||||
playerId = buffer.readInt();
|
||||
try (InputStream in = new ByteBufInputStream(buffer)) {
|
||||
compoundTag = NbtIo.readCompressed(in);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
compoundTag = PacketCodec.COMPRESSED_NBT.read(buffer);
|
||||
}
|
||||
|
||||
public MsgPlayerCapabilities(Pony player) {
|
||||
|
@ -42,10 +33,7 @@ public class MsgPlayerCapabilities implements HandledPacket<PlayerEntity> {
|
|||
@Override
|
||||
public void toBuffer(PacketByteBuf buffer) {
|
||||
buffer.writeInt(playerId);
|
||||
try (OutputStream out = new ByteBufOutputStream(buffer)) {
|
||||
NbtIo.writeCompressed(compoundTag, out);
|
||||
} catch (IOException e) {
|
||||
}
|
||||
PacketCodec.COMPRESSED_NBT.write(buffer, compoundTag);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
package com.minelittlepony.unicopia.network.datasync;
|
||||
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
|
||||
public interface Transmittable {
|
||||
void setDirty();
|
||||
|
||||
void toSyncronisedNbt(NbtCompound compound);
|
||||
|
||||
void fromSynchronizedNbt(NbtCompound compound);
|
||||
}
|
|
@ -3,7 +3,7 @@ package com.minelittlepony.unicopia.network.track;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import java.util.Optional;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
|
@ -75,30 +75,31 @@ public class DataTracker {
|
|||
}
|
||||
}
|
||||
|
||||
synchronized void getInitialPairs(List<MsgTrackedValues.TrackerEntries> output) {
|
||||
updateTrackables();
|
||||
output.add(new MsgTrackedValues.TrackerEntries(id, true, codecs));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
synchronized void getDirtyPairs(List<MsgTrackedValues.TrackerEntries> output) {
|
||||
if (initial) {
|
||||
synchronized Optional<MsgTrackedValues.TrackerEntries> getInitialPairs() {
|
||||
initial = false;
|
||||
dirtyIndices = new IntOpenHashSet();
|
||||
getInitialPairs(output);
|
||||
} else {
|
||||
updateTrackables();
|
||||
return Optional.of(new MsgTrackedValues.TrackerEntries(id, true, codecs));
|
||||
}
|
||||
|
||||
synchronized Optional<MsgTrackedValues.TrackerEntries> getDirtyPairs() {
|
||||
if (initial) {
|
||||
return getInitialPairs();
|
||||
}
|
||||
|
||||
updateTrackables();
|
||||
|
||||
if (!dirtyIndices.isEmpty()) {
|
||||
if (dirtyIndices.isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
IntSet toSend = dirtyIndices;
|
||||
dirtyIndices = new IntOpenHashSet();
|
||||
List<Pair<?>> pairs = new ArrayList<>();
|
||||
for (int i : toSend) {
|
||||
pairs.add(codecs.get(i));
|
||||
}
|
||||
output.add(new MsgTrackedValues.TrackerEntries(id, false, pairs));
|
||||
}
|
||||
}
|
||||
return Optional.of(new MsgTrackedValues.TrackerEntries(id, false, pairs));
|
||||
}
|
||||
|
||||
synchronized void load(MsgTrackedValues.TrackerEntries values) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package com.minelittlepony.unicopia.network.track;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
|
@ -19,7 +19,6 @@ public class DataTrackerManager {
|
|||
final boolean isClient;
|
||||
private final List<DataTracker> trackers = new ObjectArrayList<>();
|
||||
private final List<ObjectTracker<?>> objectTrackers = new ObjectArrayList<>();
|
||||
|
||||
private final List<PacketEmitter> packetEmitters = new ObjectArrayList<>();
|
||||
|
||||
@Nullable
|
||||
|
@ -44,12 +43,32 @@ public class DataTrackerManager {
|
|||
public synchronized DataTracker checkoutTracker() {
|
||||
DataTracker tracker = new DataTracker(this, trackers.size());
|
||||
trackers.add(tracker);
|
||||
packetEmitters.add((sender, initial) -> {
|
||||
var update = initial ? tracker.getInitialPairs() : tracker.getDirtyPairs();
|
||||
if (update.isPresent()) {
|
||||
sender.accept(Channel.SERVER_TRACKED_ENTITY_DATA.toPacket(new MsgTrackedValues(
|
||||
entity.getId(),
|
||||
Optional.empty(),
|
||||
update
|
||||
)));
|
||||
}
|
||||
});
|
||||
return tracker;
|
||||
}
|
||||
|
||||
public synchronized <T extends TrackableObject> ObjectTracker<T> checkoutTracker(Supplier<T> objFunction) {
|
||||
ObjectTracker<T> tracker = new ObjectTracker<>(objectTrackers.size(), objFunction);
|
||||
objectTrackers.add(tracker);
|
||||
packetEmitters.add((sender, initial) -> {
|
||||
var update = initial ? tracker.getInitialPairs() : tracker.getDirtyPairs();
|
||||
if (update.isPresent()) {
|
||||
sender.accept(Channel.SERVER_TRACKED_ENTITY_DATA.toPacket(new MsgTrackedValues(
|
||||
entity.getId(),
|
||||
update,
|
||||
Optional.empty()
|
||||
)));
|
||||
}
|
||||
});
|
||||
return tracker;
|
||||
}
|
||||
|
||||
|
@ -58,25 +77,6 @@ public class DataTrackerManager {
|
|||
for (var emitter : packetEmitters) {
|
||||
emitter.sendPackets(sender, false);
|
||||
}
|
||||
|
||||
if (trackers.isEmpty() && objectTrackers.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<MsgTrackedValues.TrackerEntries> toTransmit = new ArrayList<>();
|
||||
List<MsgTrackedValues.TrackerObjects> objToTransmit = new ArrayList<>();
|
||||
|
||||
for (var entry : trackers) entry.getDirtyPairs(toTransmit);
|
||||
for (var entry : objectTrackers) entry.getDirtyPairs(objToTransmit);
|
||||
|
||||
if (!toTransmit.isEmpty() || !objToTransmit.isEmpty()) {
|
||||
MsgTrackedValues packet = new MsgTrackedValues(
|
||||
entity.getId(),
|
||||
objToTransmit,
|
||||
toTransmit
|
||||
);
|
||||
sender.accept(Channel.SERVER_TRACKED_ENTITY_DATA.toPacket(packet));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,41 +86,22 @@ public class DataTrackerManager {
|
|||
for (var emitter : packetEmitters) {
|
||||
emitter.sendPackets((Consumer)sender, true);
|
||||
}
|
||||
|
||||
if (trackers.isEmpty() && objectTrackers.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<MsgTrackedValues.TrackerEntries> toTransmit = new ArrayList<>();
|
||||
List<MsgTrackedValues.TrackerObjects> objToTransmit = new ArrayList<>();
|
||||
|
||||
for (var entry : trackers) entry.getInitialPairs(toTransmit);
|
||||
for (var entry : objectTrackers) entry.getInitialPairs(objToTransmit);
|
||||
|
||||
if (!toTransmit.isEmpty() || !objToTransmit.isEmpty()) {
|
||||
MsgTrackedValues packet = new MsgTrackedValues(
|
||||
entity.getId(),
|
||||
objToTransmit,
|
||||
toTransmit
|
||||
);
|
||||
sender.accept(Channel.SERVER_TRACKED_ENTITY_DATA.toPacket(packet));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
synchronized void load(MsgTrackedValues packet) {
|
||||
for (var update : packet.updatedTrackers()) {
|
||||
packet.updatedTrackers().ifPresent(update -> {
|
||||
DataTracker tracker = trackers.get(update.id());
|
||||
if (tracker != null) {
|
||||
tracker.load(update);
|
||||
}
|
||||
}
|
||||
for (var update : packet.updatedObjects()) {
|
||||
});
|
||||
packet.updatedObjects().ifPresent(update -> {
|
||||
ObjectTracker<?> tracker = objectTrackers.get(update.id());
|
||||
if (tracker != null) {
|
||||
tracker.load(update);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public interface PacketEmitter {
|
||||
|
|
|
@ -5,9 +5,11 @@ import java.util.HashMap;
|
|||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.minelittlepony.unicopia.util.serialization.PacketCodec;
|
||||
import com.sollace.fabwork.api.packets.HandledPacket;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
|
@ -17,22 +19,22 @@ import net.minecraft.network.PacketByteBuf;
|
|||
|
||||
public record MsgTrackedValues(
|
||||
int owner,
|
||||
List<TrackerObjects> updatedObjects,
|
||||
List<TrackerEntries> updatedTrackers
|
||||
Optional<TrackerObjects> updatedObjects,
|
||||
Optional<TrackerEntries> updatedTrackers
|
||||
) implements HandledPacket<PlayerEntity> {
|
||||
public MsgTrackedValues(PacketByteBuf buffer) {
|
||||
this(
|
||||
buffer.readInt(),
|
||||
buffer.readCollection(ArrayList::new, TrackerObjects::new),
|
||||
buffer.readCollection(ArrayList::new, TrackerEntries::new)
|
||||
buffer.readOptional(TrackerObjects::new),
|
||||
buffer.readOptional(TrackerEntries::new)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toBuffer(PacketByteBuf buffer) {
|
||||
buffer.writeInt(owner);
|
||||
buffer.writeCollection(updatedObjects, (buf, obj) -> obj.write(buf));
|
||||
buffer.writeCollection(updatedTrackers, (buf, tracker) -> tracker.write(buf));
|
||||
buffer.writeOptional(updatedObjects, (buf, obj) -> obj.write(buf));
|
||||
buffer.writeOptional(updatedTrackers, (buf, tracker) -> tracker.write(buf));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -48,14 +50,15 @@ public record MsgTrackedValues(
|
|||
this(
|
||||
buffer.readInt(),
|
||||
buffer.readCollection(HashSet::new, PacketByteBuf::readUuid),
|
||||
buffer.readMap(HashMap::new, PacketByteBuf::readUuid, PacketByteBuf::readNbt)
|
||||
buffer.readMap(HashMap::new, PacketByteBuf::readUuid, PacketCodec.NBT::read)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
public void write(PacketByteBuf buffer) {
|
||||
buffer.writeInt(id);
|
||||
buffer.writeCollection(removedValues, PacketByteBuf::writeUuid);
|
||||
buffer.writeMap(values, PacketByteBuf::writeUuid, PacketByteBuf::writeNbt);
|
||||
buffer.writeMap(values, PacketByteBuf::writeUuid, PacketCodec.NBT::write);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,8 +3,8 @@ package com.minelittlepony.unicopia.network.track;
|
|||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Supplier;
|
||||
|
@ -73,18 +73,20 @@ public class ObjectTracker<T extends TrackableObject> implements NbtSerialisable
|
|||
quickAccess = Map.copyOf(trackedObjects);
|
||||
}
|
||||
|
||||
synchronized void getInitialPairs(List<MsgTrackedValues.TrackerObjects> output) {
|
||||
if (!trackedObjects.isEmpty()) {
|
||||
synchronized Optional<MsgTrackedValues.TrackerObjects> getInitialPairs() {
|
||||
if (trackedObjects.isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
Map<UUID, NbtCompound> trackableCompounds = new HashMap<>();
|
||||
quickAccess.entrySet().forEach(object -> {
|
||||
trackableCompounds.put(object.getKey(), object.getValue().toTrackedNbt());
|
||||
});
|
||||
|
||||
output.add(new MsgTrackedValues.TrackerObjects(id, Set.of(), trackableCompounds));
|
||||
}
|
||||
return Optional.of(new MsgTrackedValues.TrackerObjects(id, Set.of(), trackableCompounds));
|
||||
}
|
||||
|
||||
synchronized void getDirtyPairs(List<MsgTrackedValues.TrackerObjects> output) {
|
||||
synchronized Optional<MsgTrackedValues.TrackerObjects> getDirtyPairs() {
|
||||
if (!trackedObjects.isEmpty()) {
|
||||
Map<UUID, NbtCompound> trackableCompounds = new HashMap<>();
|
||||
Set<UUID> removedTrackableObjects = new HashSet<>();
|
||||
|
@ -100,9 +102,11 @@ public class ObjectTracker<T extends TrackableObject> implements NbtSerialisable
|
|||
quickAccess = Map.copyOf(trackedObjects);
|
||||
|
||||
if (!trackableCompounds.isEmpty() || !removedTrackableObjects.isEmpty()) {
|
||||
output.add(new MsgTrackedValues.TrackerObjects(id, removedTrackableObjects, trackableCompounds));
|
||||
return Optional.of(new MsgTrackedValues.TrackerObjects(id, removedTrackableObjects, trackableCompounds));
|
||||
}
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
synchronized void load(MsgTrackedValues.TrackerObjects objects) {
|
||||
|
|
|
@ -22,6 +22,7 @@ public record TrackableDataType<T>(int id, PacketCodec<T> codec) {
|
|||
public static final TrackableDataType<Boolean> BOOLEAN = of(new Identifier("boolean"), PacketCodec.BOOLEAN);
|
||||
public static final TrackableDataType<UUID> UUID = of(new Identifier("uuid"), PacketCodec.UUID);
|
||||
public static final TrackableDataType<NbtCompound> NBT = of(new Identifier("nbt"), PacketCodec.NBT);
|
||||
public static final TrackableDataType<NbtCompound> COMPRESSED_NBT = of(new Identifier("compressed_nbt"), PacketCodec.COMPRESSED_NBT);
|
||||
|
||||
public static final TrackableDataType<Optional<BlockPos>> OPTIONAL_POS = of(new Identifier("optional_pos"), PacketCodec.OPTIONAL_POS);
|
||||
public static final TrackableDataType<Race> RACE = TrackableDataType.of(Unicopia.id("race"), PacketCodec.ofRegistry(Race.REGISTRY));
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
package com.minelittlepony.unicopia.util.serialization;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.function.BiConsumer;
|
||||
|
@ -7,7 +10,10 @@ import java.util.function.BiFunction;
|
|||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import io.netty.buffer.ByteBufInputStream;
|
||||
import io.netty.buffer.ByteBufOutputStream;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.nbt.NbtIo;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.registry.Registry;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
@ -27,6 +33,18 @@ public record PacketCodec<T>(PacketByteBuf.PacketReader<T> reader, PacketByteBuf
|
|||
public static final PacketCodec<Identifier> IDENTIFIER = STRING.xMap(Identifier::new, Identifier::toString);
|
||||
|
||||
public static final PacketCodec<NbtCompound> NBT = new PacketCodec<>(PacketByteBuf::readNbt, PacketByteBuf::writeNbt);
|
||||
public static final PacketCodec<NbtCompound> COMPRESSED_NBT = new PacketCodec<>(buffer -> {
|
||||
try (InputStream in = new ByteBufInputStream(buffer)) {
|
||||
return NbtIo.readCompressed(in);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}, (buffer, nbt) -> {
|
||||
try (OutputStream out = new ByteBufOutputStream(buffer)) {
|
||||
NbtIo.writeCompressed(nbt, out);
|
||||
} catch (IOException e) {
|
||||
}
|
||||
});
|
||||
|
||||
public static final PacketCodec<BlockPos> POS = new PacketCodec<>(PacketByteBuf::readBlockPos, PacketByteBuf::writeBlockPos);
|
||||
public static final PacketCodec<Optional<BlockPos>> OPTIONAL_POS = POS.asOptional();
|
||||
|
|
Loading…
Reference in a new issue