getPossibleOutputs(final int energy) {
}
/**
- * Initiates a block update to sync data between server and client.
+ * Syncs data to clients that track the current {@link Chunk} with a {@link ClientSyncPacket}.
+ *
+ * Different flags from the {@link SyncFlags} can be passed to define what should be included
+ * in the packet to avoid unnecessary data being sent.
*
- * @param updateNeighbors if true, it will also update the neighbor blocks and rerender
+ * @param flags the flags of the data to sync
*/
- public void update(final boolean updateNeighbors) {
+ public void syncData(int flags) {
if (level == null || level.isClientSide) return;
- if (updateNeighbors) level.setBlock(
+ ClientSyncPacket packet = new ClientSyncPacket(
worldPosition,
- flipBlockState(),
- BlockFlags.NOTIFY_NEIGHBORS | BlockFlags.RERENDER_MAIN_THREAD
+ flags,
+ sideConfig,
+ transferRate,
+ status,
+ numberMode,
+ mode
+ );
+ PacketHandler.CHANNEL.send(
+ PacketDistributor.TRACKING_CHUNK.with(() -> level.getChunkAt(worldPosition)),
+ packet
);
- level.sendBlockUpdated(worldPosition, getBlockState(), getBlockState(), BlockFlags.BLOCK_UPDATE);
+ }
+
+ /**
+ * Updates the neighbor blocks of the {@link TileEntity}.
+ * Can be useful to connect cables.
+ */
+ public void updateNeighbors() {
+ if (level == null || level.isClientSide) return;
+ level.setBlock(worldPosition, flipBlockState(), BlockFlags.NOTIFY_NEIGHBORS | BlockFlags.RERENDER_MAIN_THREAD);
}
/**
@@ -385,19 +408,23 @@ public Container createMenu(final int windowID, final PlayerInventory inventory,
}
/**
- * Updates the connection to the specified value.
- * If it was different from the previous value, it will trigger a block update.
+ * Updates the status to the specified value.
+ * If it was different from the previous value, it will trigger a client sync.
*
* @param newStatus the new setting to set
*/
- private void updateConnection(final STATUS newStatus) {
+ private void updateStatus(final STATUS newStatus) {
final STATUS oldStatus = status;
status = newStatus;
averageRate = 0;
averageCount = 0;
if (oldStatus != newStatus) {
- if (newStatus != STATUS.TRANSFERRING) transferRate = 0;
- update(false);
+ int flags = SyncFlags.STATUS;
+ if (newStatus != STATUS.TRANSFERRING) {
+ transferRate = 0;
+ flags = flags | SyncFlags.TRANSFER_RATE;
+ }
+ syncData(flags);
}
}
@@ -415,21 +442,22 @@ private boolean hasValidOutput() {
/**
* Calculates the flow rate depending on the energy received within {@value REFRESH_RATE} ticks.
- * Updates the connection status accordingly.
+ * Updates the status accordingly.
*/
private void calculateFlow() {
if (averageCount != 0) {
transferRate = (float) averageRate / averageCount;
- update(false);
+ if (lastSyncedTransferRate != transferRate) syncData(SyncFlags.TRANSFER_RATE);
}
if (transferRate > 0) {
- updateConnection(STATUS.TRANSFERRING);
+ updateStatus(STATUS.TRANSFERRING);
} else {
- updateConnection(STATUS.CONNECTED);
+ updateStatus(STATUS.CONNECTED);
}
lastAverageRate = averageRate;
+ lastSyncedTransferRate = transferRate;
}
@Override
@@ -449,13 +477,13 @@ public void tick() {
(mode == MODE.CONSUMER && !hasValidInput) ||
(mode == MODE.TRANSFER && (!hasValidInput || !sideConfig.hasOutput() || !hasValidOutput()))
) {
- updateConnection(STATUS.DISCONNECTED);
+ updateStatus(STATUS.DISCONNECTED);
return;
}
// if the average rate didn't change, set to connected
if (averageRate == lastAverageRate) {
- updateConnection(STATUS.CONNECTED);
+ updateStatus(STATUS.CONNECTED);
return;
}
diff --git a/src/main/java/dev/rlnt/energymeter/meter/SideConfiguration.java b/src/main/java/dev/rlnt/energymeter/meter/SideConfiguration.java
index 8a59529..100dc9c 100644
--- a/src/main/java/dev/rlnt/energymeter/meter/SideConfiguration.java
+++ b/src/main/java/dev/rlnt/energymeter/meter/SideConfiguration.java
@@ -10,9 +10,10 @@ public class SideConfiguration {
private static final int SIZE = 12;
private final EnumMap directionConfig = new EnumMap<>(Direction.class);
private final EnumMap sideConfig = new EnumMap<>(BLOCK_SIDE.class);
- private Direction facing = Direction.NORTH;
+ private final Direction facing;
- SideConfiguration() {
+ SideConfiguration(Direction facing) {
+ this.facing = facing;
for (final Direction direction : Direction.values()) {
directionConfig.put(direction, IO_SETTING.OFF);
}
@@ -21,12 +22,9 @@ public class SideConfiguration {
}
}
- void setFacing(final Direction facing) {
- this.facing = facing;
- }
-
/**
* Converts the side configuration to a serializable integer array.
+ *
* @return the side configuration as integer array
*/
public int[] serialize() {
@@ -42,6 +40,7 @@ public int[] serialize() {
/**
* Reads the side configuration from an integer array and stores it.
+ *
* @param serialized the integer array to deserialize
*/
public void deserialize(final int[] serialized) {
@@ -56,6 +55,7 @@ public void deserialize(final int[] serialized) {
/**
* Gets an IO setting by a specified direction.
* This automatically takes the facing direction into account.
+ *
* @param direction the direction to get the IO setting from
* @return the IO setting
*/
@@ -66,6 +66,7 @@ public IO_SETTING get(final Direction direction) {
/**
* Gets an IO setting by a specified block side.
* This automatically takes the facing direction into account.
+ *
* @param side the block side to get the IO setting from
* @return the IO setting
*/
@@ -75,7 +76,8 @@ public IO_SETTING get(final BLOCK_SIDE side) {
/**
* Sets the specified block side to the specified IO setting.
- * @param side the side on which the setting should be changed
+ *
+ * @param side the side on which the setting should be changed
* @param setting the setting which should be set
*/
public void set(final BLOCK_SIDE side, final IO_SETTING setting) {
@@ -85,6 +87,7 @@ public void set(final BLOCK_SIDE side, final IO_SETTING setting) {
/**
* Checks if the side configuration has an input set somewhere.
+ *
* @return true if there is an input, false otherwise
*/
public boolean hasInput() {
@@ -93,6 +96,7 @@ public boolean hasInput() {
/**
* Checks if the side configuration has an output set somewhere.
+ *
* @return true if there is an output, false otherwise
*/
public boolean hasOutput() {
@@ -101,6 +105,7 @@ public boolean hasOutput() {
/**
* Checks if the side configuration already has the maximum amount of outputs.
+ *
* @return true if there are max outputs, false otherwise
*/
public boolean hasMaxOutputs() {
@@ -109,6 +114,7 @@ public boolean hasMaxOutputs() {
/**
* Gets the direction from the given block side depending on the facing of the block.
+ *
* @param side the block side to get the direction from
* @return the direction
*/
diff --git a/src/main/java/dev/rlnt/energymeter/network/ClientSyncPacket.java b/src/main/java/dev/rlnt/energymeter/network/ClientSyncPacket.java
new file mode 100644
index 0000000..6ce8ab4
--- /dev/null
+++ b/src/main/java/dev/rlnt/energymeter/network/ClientSyncPacket.java
@@ -0,0 +1,87 @@
+package dev.rlnt.energymeter.network;
+
+import dev.rlnt.energymeter.meter.MeterTile;
+import dev.rlnt.energymeter.meter.SideConfiguration;
+import dev.rlnt.energymeter.network.PacketHandler.SyncFlags;
+import dev.rlnt.energymeter.util.TypeEnums.MODE;
+import dev.rlnt.energymeter.util.TypeEnums.NUMBER_MODE;
+import dev.rlnt.energymeter.util.TypeEnums.STATUS;
+import java.util.function.Supplier;
+import net.minecraft.client.Minecraft;
+import net.minecraft.network.PacketBuffer;
+import net.minecraft.tileentity.TileEntity;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.world.World;
+import net.minecraftforge.fml.network.NetworkEvent;
+
+public class ClientSyncPacket {
+
+ private BlockPos pos;
+ private int flags;
+ private int[] sideConfig;
+ private float transferRate;
+ private STATUS status;
+ private NUMBER_MODE numberMode;
+ private MODE mode;
+
+ public ClientSyncPacket(
+ final BlockPos pos,
+ final int flags,
+ final SideConfiguration sideConfig,
+ final float transferRate,
+ final STATUS status,
+ final NUMBER_MODE numberMode,
+ final MODE mode
+ ) {
+ this.pos = pos;
+ this.flags = flags;
+ this.sideConfig = sideConfig.serialize();
+ this.transferRate = transferRate;
+ this.status = status;
+ this.numberMode = numberMode;
+ this.mode = mode;
+ }
+
+ private ClientSyncPacket() {}
+
+ static ClientSyncPacket decode(final PacketBuffer buffer) {
+ final ClientSyncPacket packet = new ClientSyncPacket();
+ packet.pos = buffer.readBlockPos();
+ packet.flags = buffer.readInt();
+ if ((packet.flags & SyncFlags.SIDE_CONFIG) != 0) packet.sideConfig = buffer.readVarIntArray();
+ if ((packet.flags & SyncFlags.TRANSFER_RATE) != 0) packet.transferRate = buffer.readFloat();
+ if ((packet.flags & SyncFlags.STATUS) != 0) packet.status = STATUS.values()[buffer.readInt()];
+ if ((packet.flags & SyncFlags.NUMBER_MODE) != 0) packet.numberMode = NUMBER_MODE.values()[buffer.readInt()];
+ if ((packet.flags & SyncFlags.MODE) != 0) packet.mode = MODE.values()[buffer.readInt()];
+ return packet;
+ }
+
+ static void handle(final ClientSyncPacket packet, final Supplier context) {
+ context.get().enqueueWork(() -> handlePacket(packet));
+ context.get().setPacketHandled(true);
+ }
+
+ private static void handlePacket(final ClientSyncPacket packet) {
+ World level = Minecraft.getInstance().level;
+ if (level == null) return;
+ TileEntity tileEntity = level.getBlockEntity(packet.pos);
+ if (tileEntity instanceof MeterTile) {
+ final MeterTile tile = (MeterTile) tileEntity;
+ if ((packet.flags & SyncFlags.SIDE_CONFIG) != 0) tile.getSideConfig().deserialize(packet.sideConfig);
+ if ((packet.flags & SyncFlags.TRANSFER_RATE) != 0) tile.setTransferRate(packet.transferRate);
+ if ((packet.flags & SyncFlags.STATUS) != 0) tile.setStatus(packet.status);
+ if ((packet.flags & SyncFlags.NUMBER_MODE) != 0) tile.setNumberMode(packet.numberMode);
+ if ((packet.flags & SyncFlags.MODE) != 0) tile.setMode(packet.mode);
+ }
+ }
+
+ void encode(final PacketBuffer buffer) {
+ buffer.writeBlockPos(pos);
+ buffer.writeInt(flags);
+ if ((flags & SyncFlags.SIDE_CONFIG) != 0) buffer.writeVarIntArray(sideConfig);
+ if ((flags & SyncFlags.TRANSFER_RATE) != 0) buffer.writeFloat(transferRate);
+ if ((flags & SyncFlags.STATUS) != 0) buffer.writeInt(status.ordinal());
+ if ((flags & SyncFlags.NUMBER_MODE) != 0) buffer.writeInt(numberMode.ordinal());
+ if ((flags & SyncFlags.MODE) != 0) buffer.writeInt(mode.ordinal());
+ }
+}
diff --git a/src/main/java/dev/rlnt/energymeter/network/IOUpdatePacket.java b/src/main/java/dev/rlnt/energymeter/network/IOUpdatePacket.java
index 51f7653..3c4df09 100644
--- a/src/main/java/dev/rlnt/energymeter/network/IOUpdatePacket.java
+++ b/src/main/java/dev/rlnt/energymeter/network/IOUpdatePacket.java
@@ -3,12 +3,14 @@
import dev.rlnt.energymeter.meter.MeterContainer;
import dev.rlnt.energymeter.meter.MeterTile;
import dev.rlnt.energymeter.meter.SideConfiguration;
+import dev.rlnt.energymeter.network.PacketHandler.SyncFlags;
import dev.rlnt.energymeter.util.TypeEnums.BLOCK_SIDE;
import java.util.function.Supplier;
import javax.annotation.Nullable;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.Direction;
+import net.minecraft.world.World;
import net.minecraftforge.fml.network.NetworkEvent.Context;
public class IOUpdatePacket {
@@ -42,9 +44,12 @@ static void handle(final IOUpdatePacket packet, final Supplier context)
private static void handlePacket(final IOUpdatePacket packet, @Nullable final ServerPlayerEntity player) {
if (player != null && player.containerMenu instanceof MeterContainer) {
final MeterTile tile = ((MeterContainer) player.containerMenu).getTile();
+ final World level = tile.getLevel();
+ if (level == null || !level.isLoaded(tile.getBlockPos())) return;
tile.getSideConfig().deserialize(packet.sideConfig);
- tile.update(true);
+ tile.updateNeighbors();
tile.updateCache(packet.direction);
+ tile.syncData(SyncFlags.SIDE_CONFIG);
tile.setChanged();
}
}
diff --git a/src/main/java/dev/rlnt/energymeter/network/PacketHandler.java b/src/main/java/dev/rlnt/energymeter/network/PacketHandler.java
index 63faf38..1e0beb9 100644
--- a/src/main/java/dev/rlnt/energymeter/network/PacketHandler.java
+++ b/src/main/java/dev/rlnt/energymeter/network/PacketHandler.java
@@ -4,6 +4,7 @@
import dev.rlnt.energymeter.util.TextUtils;
import net.minecraft.util.ResourceLocation;
+import net.minecraftforge.fml.network.NetworkDirection;
import net.minecraftforge.fml.network.NetworkRegistry;
import net.minecraftforge.fml.network.simple.SimpleChannel;
@@ -22,25 +23,42 @@ public class PacketHandler {
int id = -1;
CHANNEL
- .messageBuilder(IOUpdatePacket.class, ++id)
+ .messageBuilder(ClientSyncPacket.class, ++id, NetworkDirection.PLAY_TO_CLIENT)
+ .decoder(ClientSyncPacket::decode)
+ .encoder(ClientSyncPacket::encode)
+ .consumer(ClientSyncPacket::handle)
+ .add();
+
+ CHANNEL
+ .messageBuilder(IOUpdatePacket.class, ++id, NetworkDirection.PLAY_TO_SERVER)
.decoder(IOUpdatePacket::decode)
.encoder(IOUpdatePacket::encode)
.consumer(IOUpdatePacket::handle)
.add();
CHANNEL
- .messageBuilder(SettingUpdatePacket.class, ++id)
+ .messageBuilder(SettingUpdatePacket.class, ++id, NetworkDirection.PLAY_TO_SERVER)
.decoder(SettingUpdatePacket::decode)
.encoder(SettingUpdatePacket::encode)
.consumer(SettingUpdatePacket::handle)
.add();
}
- private PacketHandler() {
- throw new IllegalStateException("Utility class");
- }
+ private PacketHandler() {}
public static void init() {
// utility method to initialize the packet handler
}
+
+ public static class SyncFlags {
+
+ public static final int SIDE_CONFIG = (1);
+ public static final int TRANSFER_RATE = (1 << 1);
+ public static final int STATUS = (1 << 2);
+ public static final int NUMBER_MODE = (1 << 3);
+ public static final int MODE = (1 << 4);
+ public static final int ALL = SIDE_CONFIG | TRANSFER_RATE | STATUS | NUMBER_MODE | MODE;
+
+ private SyncFlags() {}
+ }
}
diff --git a/src/main/java/dev/rlnt/energymeter/network/SettingUpdatePacket.java b/src/main/java/dev/rlnt/energymeter/network/SettingUpdatePacket.java
index d8c7427..e01b9df 100644
--- a/src/main/java/dev/rlnt/energymeter/network/SettingUpdatePacket.java
+++ b/src/main/java/dev/rlnt/energymeter/network/SettingUpdatePacket.java
@@ -7,6 +7,7 @@
import javax.annotation.Nullable;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.network.PacketBuffer;
+import net.minecraft.world.World;
import net.minecraftforge.fml.network.NetworkEvent;
public class SettingUpdatePacket {
@@ -34,8 +35,9 @@ static void handle(final SettingUpdatePacket packet, final Supplier formatEnergy(final Number number, final boolean extended) {
if (!extended) {
@@ -105,7 +109,8 @@ public static Tuple formatEnergy(final Number number, final bool
/**
* Formats numbers with fraction digits into readable strings by
* adjusting the fraction digit amount.
- * @param input the number to format
+ *
+ * @param input the number to format
* @param maxFraction the maximum amount of fraction digits
* @return the readable string representation of the number
*/
diff --git a/src/main/java/dev/rlnt/energymeter/util/TypeEnums.java b/src/main/java/dev/rlnt/energymeter/util/TypeEnums.java
index ab6f126..251b4bc 100644
--- a/src/main/java/dev/rlnt/energymeter/util/TypeEnums.java
+++ b/src/main/java/dev/rlnt/energymeter/util/TypeEnums.java
@@ -2,9 +2,7 @@
public class TypeEnums {
- private TypeEnums() {
- throw new IllegalStateException("Utility class");
- }
+ private TypeEnums() {}
/**
* Defines the type of the translation to