Send destruction updates in batches to avoid network congestion

This commit is contained in:
Sollace 2021-01-27 18:03:35 +02:00
parent 0bde55a0fb
commit 8e89edfb35
3 changed files with 42 additions and 27 deletions

View file

@ -14,7 +14,7 @@ public class BlockDestructionManager {
public static final int UNSET_DAMAGE = -1; public static final int UNSET_DAMAGE = -1;
public static final int MAX_DAMAGE = 10; public static final int MAX_DAMAGE = 10;
private final Destruction emptyDestruction = new Destruction(BlockPos.ORIGIN); private final Destruction emptyDestruction = new Destruction();
private final World world; private final World world;
@ -36,7 +36,7 @@ public class BlockDestructionManager {
public void setBlockDestruction(BlockPos pos, int amount) { public void setBlockDestruction(BlockPos pos, int amount) {
synchronized (locker) { synchronized (locker) {
destructions.computeIfAbsent(pos.asLong(), p -> new Destruction(pos)).set(amount); destructions.computeIfAbsent(pos.asLong(), p -> new Destruction()).set(amount);
} }
} }
@ -52,17 +52,25 @@ public class BlockDestructionManager {
public void tick() { public void tick() {
synchronized (locker) { synchronized (locker) {
destructions.long2ObjectEntrySet().removeIf(entry -> entry.getValue().tick()); destructions.long2ObjectEntrySet().removeIf(entry -> entry.getValue().tick());
if (world instanceof ServerWorld) {
Long2ObjectMap<Integer> sent = new Long2ObjectOpenHashMap<>();
destructions.forEach((p, item) -> {
if (item.dirty) {
sent.put(p.longValue(), (Integer)item.amount);
}
});
if (!sent.isEmpty()) {
Channel.SERVER_BLOCK_DESTRUCTION.send(world, new MsgBlockDestruction(sent));
}
}
} }
} }
private class Destruction { private class Destruction {
BlockPos pos;
int amount = -1; int amount = -1;
int age = 50; int age = 50;
boolean dirty;
Destruction(BlockPos pos) {
this.pos = pos;
}
boolean tick() { boolean tick() {
if (age-- > 0) { if (age-- > 0) {
@ -78,9 +86,7 @@ public class BlockDestructionManager {
void set(int amount) { void set(int amount) {
this.age = 50; this.age = 50;
this.amount = amount >= 0 && amount < MAX_DAMAGE ? amount : UNSET_DAMAGE; this.amount = amount >= 0 && amount < MAX_DAMAGE ? amount : UNSET_DAMAGE;
if (world instanceof ServerWorld) { this.dirty = true;
Channel.SERVER_BLOCK_DESTRUCTION.send(world, new MsgBlockDestruction(pos, this.amount));
}
} }
} }

View file

@ -16,12 +16,12 @@ public class ClientBlockDestructionManager {
private final Object locker = new Object(); private final Object locker = new Object();
public void setBlockDestruction(BlockPos pos, int amount) { public void setBlockDestruction(long pos, int amount) {
synchronized (locker) { synchronized (locker) {
if (amount <= 0 || amount > BlockDestructionManager.MAX_DAMAGE) { if (amount <= 0 || amount > BlockDestructionManager.MAX_DAMAGE) {
destructions.remove(pos.asLong()); destructions.remove(pos);
} else { } else {
destructions.computeIfAbsent(pos.asLong(), p -> new Destruction(pos)).set(amount); destructions.computeIfAbsent(pos, p -> new Destruction(pos)).set(amount);
} }
} }
} }
@ -52,8 +52,8 @@ public class ClientBlockDestructionManager {
BlockBreakingInfo info; BlockBreakingInfo info;
Destruction(BlockPos pos) { Destruction(long pos) {
this.info = new BlockBreakingInfo(0, pos); this.info = new BlockBreakingInfo(0, BlockPos.fromLong(pos));
} }
boolean tick() { boolean tick() {

View file

@ -2,35 +2,44 @@ package com.minelittlepony.unicopia.network;
import com.minelittlepony.unicopia.client.ClientBlockDestructionManager; import com.minelittlepony.unicopia.client.ClientBlockDestructionManager;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import net.fabricmc.fabric.api.network.PacketContext; import net.fabricmc.fabric.api.network.PacketContext;
import net.minecraft.network.PacketByteBuf; import net.minecraft.network.PacketByteBuf;
import net.minecraft.util.math.BlockPos;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
public class MsgBlockDestruction implements Channel.Packet { public class MsgBlockDestruction implements Channel.Packet {
private final BlockPos pos; private final Long2ObjectMap<Integer> destructions;
private final int amount;
MsgBlockDestruction(PacketByteBuf buffer) { MsgBlockDestruction(PacketByteBuf buffer) {
pos = buffer.readBlockPos(); destructions = new Long2ObjectOpenHashMap<>();
amount = buffer.readByte(); int size = buffer.readInt();
for (int i = 0; i < size; i++) {
destructions.put(buffer.readLong(), (Integer)buffer.readInt());
}
} }
public MsgBlockDestruction(BlockPos pos, int amount) { public MsgBlockDestruction(Long2ObjectMap<Integer> destructions) {
this.pos = pos; this.destructions = destructions;
this.amount = amount;
} }
@Override @Override
public void toBuffer(PacketByteBuf buffer) { public void toBuffer(PacketByteBuf buffer) {
buffer.writeBlockPos(pos); buffer.writeInt(destructions.size());
buffer.writeByte(amount); destructions.forEach((p, i) -> {
buffer.writeLong(p);
buffer.writeInt(i);
});
} }
@Override @Override
public void handle(PacketContext context) { public void handle(PacketContext context) {
((ClientBlockDestructionManager.Source)MinecraftClient.getInstance().worldRenderer).getDestructionManager().setBlockDestruction(pos, amount); ClientBlockDestructionManager destr = ((ClientBlockDestructionManager.Source)MinecraftClient.getInstance().worldRenderer).getDestructionManager();
destructions.forEach((i, d) -> {
destr.setBlockDestruction(i, d);
});
} }
} }