Skip to content

Commit 70d9795

Browse files
committed
Registry encoding compression
1 parent 8c58f7e commit 70d9795

File tree

7 files changed

+75
-13
lines changed

7 files changed

+75
-13
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Functional Changes:
44
- Fix Combat Roll not cancelling attack properly
55
- Increase attack range (slightly) on all built-in weapon attribute presets
66
- Improve idle animation handling with server side logic
7+
- Add registry encoding compression to avoid transmission issues
78
- Add support `player.entity_interaction_range` attribute, to serve as attack range
89
- Add support for weapon attributes resolved from item data component. For example:
910

common/src/main/java/net/bettercombat/config/ServerConfig.java

+2
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ Entities struck (+1) in a swing more than this, won't get weakened any further.
102102
public boolean fallback_compatibility_enabled = true;
103103
@Comment("Allow printing the content of weapon attributes registry")
104104
public boolean weapon_registry_logging = false;
105+
@Comment("Compress the weapon attributes registry for transmission")
106+
public boolean weapon_registry_compression = true;
105107

106108
public float getUpswingMultiplier() {
107109
return Math.max(0.2F, Math.min(1, upswing_multiplier));

common/src/main/java/net/bettercombat/logic/WeaponRegistry.java

+16-7
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import net.bettercombat.api.WeaponAttributesHelper;
1212
import net.bettercombat.api.component.BetterCombatDataComponents;
1313
import net.bettercombat.network.Packets;
14+
import net.bettercombat.utils.CompressionHelper;
1415
import net.minecraft.item.Item;
1516
import net.minecraft.item.ItemStack;
1617
import net.minecraft.registry.Registries;
@@ -137,7 +138,8 @@ public static void resolveAndRegisterAttributes(Identifier itemId, AttributesCon
137138

138139
// NETWORK SYNC
139140

140-
private static Packets.WeaponRegistrySync encodedRegistrations = new Packets.WeaponRegistrySync(List.of());
141+
private static Encoded encodedRegistrations = new Encoded(true, List.of());
142+
public record Encoded(boolean compressed, List<String> chunks) {}
141143
private static final int CHUNK_SIZE = 10000;
142144
private static final Gson gson = new GsonBuilder().create();
143145
public static class SyncFormat {
@@ -146,8 +148,8 @@ public static class SyncFormat {
146148
}
147149

148150
public static void encodeRegistry() {
151+
var compressed = BetterCombatMod.config.weapon_registry_compression;
149152
List<String> chunks = new ArrayList<>();
150-
151153
var syncContent = new SyncFormat();
152154
containers.forEach((key, value) -> {
153155
syncContent.attributes.put(key.toString(), value);
@@ -157,31 +159,38 @@ public static void encodeRegistry() {
157159
});
158160

159161
var json = gson.toJson(syncContent);
162+
if (compressed) {
163+
json = CompressionHelper.gzipCompress(json);
164+
}
160165
if (BetterCombatMod.config.weapon_registry_logging) {
161166
LOGGER.info("Weapon Attribute assignments loaded: " + json);
162167
}
163168
for (int i = 0; i < json.length(); i += CHUNK_SIZE) {
164169
chunks.add(json.substring(i, Math.min(json.length(), i + CHUNK_SIZE)));
165170
}
166171

167-
encodedRegistrations = new Packets.WeaponRegistrySync(chunks);
172+
encodedRegistrations = new Encoded(compressed, chunks);
173+
174+
var referencePacket = new Packets.WeaponRegistrySync(compressed, chunks);
168175
var buffer = Platform.createByteBuffer();
169-
encodedRegistrations.write(buffer);
176+
referencePacket.write(buffer);
170177
LOGGER.info("Encoded Weapon Attribute registry size (with package overhead): " + buffer.readableBytes()
171178
+ " bytes (in " + chunks.size() + " string chunks with the size of " + CHUNK_SIZE + ")");
172179
}
173180

174181
public static void decodeRegistry(Packets.WeaponRegistrySync syncPacket) {
182+
var compressed = syncPacket.compressed();
175183
String json = "";
176184
for (var chunk : syncPacket.chunks()) {
177185
json = json.concat(chunk);
178186
}
187+
if (compressed) {
188+
json = CompressionHelper.gzipDecompress(json);
189+
}
179190
LOGGER.info("Decoded Weapon Attribute registry in " + syncPacket.chunks().size() + " string chunks");
180191
if (BetterCombatMod.config.weapon_registry_logging) {
181192
LOGGER.info("Weapon Attribute registry received: " + json);
182193
}
183-
LOGGER.info("Weapon Attribute registry received (pretty printed): ");
184-
LOGGER.info(json);
185194

186195
SyncFormat sync = gson.fromJson(json, SyncFormat.class);
187196
containers.clear();
@@ -194,7 +203,7 @@ public static void decodeRegistry(Packets.WeaponRegistrySync syncPacket) {
194203
});
195204
}
196205

197-
public static Packets.WeaponRegistrySync getEncodedRegistry() {
206+
public static Encoded getEncodedRegistry() {
198207
return encodedRegistrations;
199208
}
200209
}

common/src/main/java/net/bettercombat/network/Packets.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -117,25 +117,27 @@ public Id<? extends CustomPayload> getId() {
117117
}
118118
}
119119

120-
public record WeaponRegistrySync(List<String> chunks) implements CustomPayload {
120+
public record WeaponRegistrySync(boolean compressed, List<String> chunks) implements CustomPayload {
121121
public static Identifier ID = Identifier.of(BetterCombatMod.ID, "weapon_registry");
122122
public static final CustomPayload.Id<WeaponRegistrySync> PACKET_ID = new CustomPayload.Id<>(ID);
123123
public static final PacketCodec<PacketByteBuf, WeaponRegistrySync> CODEC = PacketCodec.of(WeaponRegistrySync::write, WeaponRegistrySync::read);
124124

125125
public void write(PacketByteBuf buffer) {
126+
buffer.writeBoolean(compressed);
126127
buffer.writeInt(chunks.size());
127128
for (var chunk: chunks) {
128129
buffer.writeString(chunk);
129130
}
130131
}
131132

132133
public static WeaponRegistrySync read(PacketByteBuf buffer) {
134+
var compressed = buffer.readBoolean();
133135
var chunkCount = buffer.readInt();
134136
var chunks = new ArrayList<String>();
135137
for (int i = 0; i < chunkCount; ++i) {
136138
chunks.add(buffer.readString());
137139
}
138-
return new WeaponRegistrySync(chunks);
140+
return new WeaponRegistrySync(compressed, chunks);
139141
}
140142

141143
@Override
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package net.bettercombat.utils;
2+
3+
import java.io.ByteArrayInputStream;
4+
import java.io.ByteArrayOutputStream;
5+
import java.io.IOException;
6+
import java.util.zip.GZIPInputStream;
7+
import java.util.zip.GZIPOutputStream;
8+
9+
import java.util.Base64;
10+
11+
public class CompressionHelper {
12+
13+
// Compresses a string using GZIP and returns the result as a Base64 encoded string
14+
public static String gzipCompress(String uncompressed) {
15+
if (uncompressed == null || uncompressed.isEmpty()) {
16+
return uncompressed;
17+
}
18+
try (ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
19+
GZIPOutputStream gzipStream = new GZIPOutputStream(byteStream)) {
20+
gzipStream.write(uncompressed.getBytes());
21+
gzipStream.close(); // Ensure all data is flushed
22+
return Base64.getEncoder().encodeToString(byteStream.toByteArray());
23+
} catch (IOException e) {
24+
throw new RuntimeException("Failed to compress string", e);
25+
}
26+
}
27+
28+
// Decompresses a Base64 encoded GZIP string back into the original string
29+
public static String gzipDecompress(String compressed) {
30+
if (compressed == null || compressed.isEmpty()) {
31+
return compressed;
32+
}
33+
try (ByteArrayInputStream byteStream = new ByteArrayInputStream(Base64.getDecoder().decode(compressed));
34+
GZIPInputStream gzipStream = new GZIPInputStream(byteStream);
35+
ByteArrayOutputStream resultStream = new ByteArrayOutputStream()) {
36+
37+
byte[] buffer = new byte[1024];
38+
int length;
39+
while ((length = gzipStream.read(buffer)) > 0) {
40+
resultStream.write(buffer, 0, length);
41+
}
42+
return resultStream.toString();
43+
} catch (IOException e) {
44+
throw new RuntimeException("Failed to decompress string", e);
45+
}
46+
}
47+
}

fabric/src/main/java/net/bettercombat/fabric/network/FabricServerNetwork.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public static void init() {
3737
throw new AssertionError("Weapon registry is empty!");
3838
}
3939
// System.out.println("Starting WeaponRegistrySyncTask, chunks: " + WeaponRegistry.getEncodedRegistry().chunks().size());
40-
handler.addTask(new WeaponRegistrySyncTask(WeaponRegistry.getEncodedRegistry().chunks()));
40+
handler.addTask(new WeaponRegistrySyncTask(WeaponRegistry.getEncodedRegistry()));
4141
} else {
4242
handler.disconnect(Text.literal("Network configuration task not supported: " + WeaponRegistrySyncTask.name));
4343
}
@@ -84,7 +84,7 @@ public void sendPacket(Consumer<Packet<?>> sender) {
8484
}
8585
}
8686

87-
public record WeaponRegistrySyncTask(List<String> encodedRegistry) implements ServerPlayerConfigurationTask {
87+
public record WeaponRegistrySyncTask(WeaponRegistry.Encoded encodedRegistry) implements ServerPlayerConfigurationTask {
8888
public static final String name = BetterCombatMod.ID + ":" + "weapon_registry";
8989
public static final Key KEY = new Key(name);
9090

@@ -95,7 +95,7 @@ public Key getKey() {
9595

9696
@Override
9797
public void sendPacket(Consumer<Packet<?>> sender) {
98-
var packet = new Packets.WeaponRegistrySync(encodedRegistry);
98+
var packet = new Packets.WeaponRegistrySync(encodedRegistry.compressed(), encodedRegistry.chunks());
9999
sender.accept(ServerConfigurationNetworking.createS2CPacket(packet));
100100
}
101101
}

neoforge/src/main/java/net/bettercombat/neoforge/network/NetworkEvents.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,8 @@ public Key getKey() {
107107

108108
@Override
109109
public void run(Consumer<CustomPayload> sender) {
110-
var packet = new Packets.WeaponRegistrySync(WeaponRegistry.getEncodedRegistry().chunks());
110+
var encodded = WeaponRegistry.getEncodedRegistry();
111+
var packet = new Packets.WeaponRegistrySync(encodded.compressed(), encodded.chunks());
111112
sender.accept(packet);
112113
}
113114
}

0 commit comments

Comments
 (0)