Skip to content

Commit 3df5d77

Browse files
committed
bugfix
1 parent 2720f24 commit 3df5d77

11 files changed

Lines changed: 389 additions & 34 deletions

src/main/java/com/hfstudio/guidenh/client/command/GuideNhClientBridgeController.java

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
import com.hfstudio.guidenh.guide.internal.structure.GuideNhStructureRuntime;
1515
import com.hfstudio.guidenh.guide.internal.structure.GuideStructureFileStore;
1616
import com.hfstudio.guidenh.network.GuideNhNetwork;
17-
import com.hfstudio.guidenh.network.GuideNhStructureRequestMessage;
17+
import com.hfstudio.guidenh.network.GuideNhStructureRequestSender;
1818

1919
import cpw.mods.fml.common.FMLCommonHandler;
2020
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
@@ -56,7 +56,6 @@ public boolean isServerStructureCommandsAvailable() {
5656
public Path exportStructureToFile(String prefix, String structureText) throws Exception {
5757
var entry = GuideNhStructureRuntime.getClientMemoryStore()
5858
.remember(prefix, structureText);
59-
syncEntryToServerIfAvailable(entry);
6059
return structureFileStore.saveExport(prefix, structureText);
6160
}
6261

@@ -78,23 +77,22 @@ public void placeAllStructures(int x, int y, int z) {
7877
sendClient(GuidebookText.CommandStructureServerRequired);
7978
return;
8079
}
81-
GuideNhNetwork.channel()
82-
.sendToServer(GuideNhStructureRequestMessage.placeAll(x, y, z));
80+
syncAllClientStructuresToServer();
81+
GuideNhStructureRequestSender.sendPlaceAll(GuideNhNetwork.channel(), x, y, z);
8382
}
8483

8584
public void rememberScene(String label, String structureText) {
8685
try {
8786
var entry = GuideNhStructureRuntime.getClientMemoryStore()
8887
.remember(label, structureText);
89-
syncEntryToServerIfAvailable(entry);
9088
} catch (Exception e) {
9189
// Silently ignore parse failures for auto-registered scenes
9290
}
9391
}
9492

9593
public void onServerHello() {
9694
GuideNhStructureRuntime.setServerStructureCommandsAvailable(true);
97-
GuideNhStructureRuntime.setClientStructureSyncNeeded(true);
95+
GuideNhStructureRuntime.setClientStructureSyncNeeded(false);
9896
}
9997

10098
public void onServerDisconnected() {
@@ -133,10 +131,12 @@ public void onClientTick(TickEvent.ClientTickEvent event) {
133131
}
134132
var entry = GuideNhStructureRuntime.getClientMemoryStore()
135133
.remember(result.getDisplayPath(), result.getStructureText());
136-
GuideNhNetwork.channel()
137-
.sendToServer(
138-
GuideNhStructureRequestMessage
139-
.importAndPlace(request.x, request.y, request.z, entry.getStructureText()));
134+
GuideNhStructureRequestSender.sendImportAndPlace(
135+
GuideNhNetwork.channel(),
136+
request.x,
137+
request.y,
138+
request.z,
139+
entry.getStructureText());
140140
} catch (CompletionException e) {
141141
sendClient(
142142
GuidebookText.CommandStructureImportFailure,
@@ -167,8 +167,7 @@ private void syncEntryToServerIfAvailable(
167167
if (!isServerStructureCommandsAvailable()) {
168168
return;
169169
}
170-
GuideNhNetwork.channel()
171-
.sendToServer(GuideNhStructureRequestMessage.cache(entry.getStructureText()));
170+
GuideNhStructureRequestSender.sendCache(GuideNhNetwork.channel(), entry.getStructureText());
172171
}
173172

174173
private void sendClient(GuidebookText key, Object... args) {

src/main/java/com/hfstudio/guidenh/integration/ae2/network/GuideNhAe2BaseTileNetworkBatchReplyMessage.java

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.hfstudio.guidenh.integration.ae2.network;
22

33
import com.hfstudio.guidenh.integration.ae2.Ae2BaseTileNetworkStreamPreview;
4+
import com.hfstudio.guidenh.network.GuideNhCustomPayloadLimits;
45

56
import cpw.mods.fml.common.network.simpleimpl.IMessage;
67
import io.netty.buffer.ByteBuf;
@@ -10,6 +11,11 @@ public class GuideNhAe2BaseTileNetworkBatchReplyMessage implements IMessage {
1011

1112
public static final int FORMAT_V1 = 1;
1213

14+
public static final int MAX_REPLY_PAYLOAD_BYTES = GuideNhCustomPayloadLimits.MAX_PAYLOAD_BYTES;
15+
16+
private static final int HEADER_BYTES = Long.BYTES + 1 + Integer.BYTES;
17+
private static final int FIXED_ENTRY_BYTES = Short.BYTES;
18+
1319
private long corrId;
1420
private byte[][] xpPayloads;
1521

@@ -20,7 +26,7 @@ public GuideNhAe2BaseTileNetworkBatchReplyMessage() {
2026

2127
public GuideNhAe2BaseTileNetworkBatchReplyMessage(long corrId, byte[][] xpPayloads) {
2228
this.corrId = corrId;
23-
this.xpPayloads = xpPayloads != null ? xpPayloads : new byte[0][];
29+
this.xpPayloads = budgetPayloads(xpPayloads);
2430
}
2531

2632
public long getCorrId() {
@@ -38,6 +44,16 @@ public boolean isConsistentPayload(int n) {
3844
return xpPayloads != null && xpPayloads.length == n;
3945
}
4046

47+
public int serializedSizeBytes() {
48+
int n = xpPayloads != null ? xpPayloads.length : 0;
49+
int total = HEADER_BYTES + n * FIXED_ENTRY_BYTES;
50+
for (int i = 0; i < n; i++) {
51+
byte[] chunk = xpPayloads[i] != null ? xpPayloads[i] : new byte[0];
52+
total += Math.min(chunk.length, Ae2BaseTileNetworkStreamPreview.MAX_X_PAYLOAD_BYTES);
53+
}
54+
return total;
55+
}
56+
4157
@Override
4258
public void fromBytes(ByteBuf buf) {
4359
corrId = buf.readLong();
@@ -83,4 +99,29 @@ public void toBytes(ByteBuf buf) {
8399
}
84100
}
85101
}
102+
103+
private static byte[][] budgetPayloads(byte[][] source) {
104+
int n = source != null ? Math.min(source.length, GuideNhAe2BaseTileNetworkBatchRequestMessage.MAX_POSITIONS)
105+
: 0;
106+
byte[][] out = new byte[n][];
107+
int remaining = MAX_REPLY_PAYLOAD_BYTES - HEADER_BYTES - n * FIXED_ENTRY_BYTES;
108+
int maxPayload = Ae2BaseTileNetworkStreamPreview.MAX_X_PAYLOAD_BYTES;
109+
for (int i = 0; i < n; i++) {
110+
byte[] chunk = source[i] != null ? source[i] : new byte[0];
111+
int len = Math.min(chunk.length, maxPayload);
112+
if (len <= 0 || len > remaining) {
113+
out[i] = new byte[0];
114+
continue;
115+
}
116+
if (len == chunk.length) {
117+
out[i] = chunk;
118+
} else {
119+
byte[] trimmed = new byte[len];
120+
System.arraycopy(chunk, 0, trimmed, 0, len);
121+
out[i] = trimmed;
122+
}
123+
remaining -= len;
124+
}
125+
return out;
126+
}
86127
}

src/main/java/com/hfstudio/guidenh/integration/ae2/network/GuideNhAe2BaseTileNetworkBatchRequestMessage.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
/** Client asks server for AE2 AEBaseTile description {@code X} payloads (eligible non-cable tiles) at world coords. */
77
public class GuideNhAe2BaseTileNetworkBatchRequestMessage implements IMessage {
88

9-
public static final int MAX_POSITIONS = 512;
9+
public static final int MAX_POSITIONS = 64;
1010

1111
private long corrId;
1212
private int dim;

src/main/java/com/hfstudio/guidenh/integration/ae2/network/GuideNhAe2CableBatchReplyMessage.java

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.hfstudio.guidenh.integration.ae2.network;
22

33
import com.hfstudio.guidenh.integration.ae2.Ae2CableBusPartStreamCodec;
4+
import com.hfstudio.guidenh.network.GuideNhCustomPayloadLimits;
45

56
import cpw.mods.fml.common.network.simpleimpl.IMessage;
67
import io.netty.buffer.ByteBuf;
@@ -10,6 +11,11 @@ public class GuideNhAe2CableBatchReplyMessage implements IMessage {
1011

1112
public static final int FORMAT_V1 = 1;
1213

14+
public static final int MAX_REPLY_PAYLOAD_BYTES = GuideNhCustomPayloadLimits.MAX_PAYLOAD_BYTES;
15+
16+
private static final int HEADER_BYTES = Long.BYTES + 1 + Integer.BYTES;
17+
private static final int FIXED_ENTRY_BYTES = 1 + 1 + Integer.BYTES + Short.BYTES;
18+
1319
private long corrId;
1420

1521
private byte[] hit;
@@ -31,10 +37,11 @@ public GuideNhAe2CableBatchReplyMessage() {
3137

3238
public GuideNhAe2CableBatchReplyMessage(long corrId, byte[] hit, byte[] cs, int[] sideOut, byte[][] partPacked) {
3339
this.corrId = corrId;
34-
this.hit = hit != null ? hit : new byte[0];
35-
this.cs = cs != null ? cs : new byte[0];
36-
this.sideOut = sideOut != null ? sideOut : new int[0];
37-
this.partPacked = partPacked != null ? partPacked : new byte[0][];
40+
int n = safeEntryCount(hit, cs, sideOut, partPacked);
41+
this.hit = copyBytes(hit, n);
42+
this.cs = copyBytes(cs, n);
43+
this.sideOut = copyInts(sideOut, n);
44+
this.partPacked = budgetPartPayloads(partPacked, n);
3845
}
3946

4047
public long getCorrId() {
@@ -74,6 +81,16 @@ public boolean isConsistentPayload(int n) {
7481
return true;
7582
}
7683

84+
public int serializedSizeBytes() {
85+
int n = hit != null ? hit.length : 0;
86+
int total = HEADER_BYTES + n * FIXED_ENTRY_BYTES;
87+
for (int i = 0; i < n; i++) {
88+
byte[] chunk = i < partPacked.length && partPacked[i] != null ? partPacked[i] : new byte[0];
89+
total += Math.min(chunk.length, 0xFFFF);
90+
}
91+
return total;
92+
}
93+
7794
@Override
7895
public void fromBytes(ByteBuf buf) {
7996
corrId = buf.readLong();
@@ -130,4 +147,43 @@ public void toBytes(ByteBuf buf) {
130147
buf.writeBytes(chunk);
131148
}
132149
}
150+
151+
private static int safeEntryCount(byte[] hit, byte[] cs, int[] sideOut, byte[][] partPacked) {
152+
int n = hit != null ? hit.length : 0;
153+
n = Math.min(n, cs != null ? cs.length : 0);
154+
n = Math.min(n, sideOut != null ? sideOut.length : 0);
155+
n = Math.min(n, partPacked != null ? partPacked.length : 0);
156+
return Math.max(0, Math.min(n, GuideNhAe2CableBatchRequestMessage.MAX_POSITIONS));
157+
}
158+
159+
private static byte[] copyBytes(byte[] source, int n) {
160+
byte[] out = new byte[n];
161+
if (source != null && n > 0) {
162+
System.arraycopy(source, 0, out, 0, Math.min(source.length, n));
163+
}
164+
return out;
165+
}
166+
167+
private static int[] copyInts(int[] source, int n) {
168+
int[] out = new int[n];
169+
if (source != null && n > 0) {
170+
System.arraycopy(source, 0, out, 0, Math.min(source.length, n));
171+
}
172+
return out;
173+
}
174+
175+
private static byte[][] budgetPartPayloads(byte[][] source, int n) {
176+
byte[][] out = new byte[n][];
177+
int remaining = MAX_REPLY_PAYLOAD_BYTES - HEADER_BYTES - n * FIXED_ENTRY_BYTES;
178+
for (int i = 0; i < n; i++) {
179+
byte[] chunk = source != null && i < source.length && source[i] != null ? source[i] : new byte[0];
180+
if (chunk.length <= 0 || chunk.length > 0xFFFF || chunk.length > remaining) {
181+
out[i] = new byte[0];
182+
continue;
183+
}
184+
out[i] = chunk;
185+
remaining -= chunk.length;
186+
}
187+
return out;
188+
}
133189
}

src/main/java/com/hfstudio/guidenh/integration/ae2/network/GuideNhAe2CableBatchRequestMessage.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
/** Client asks server to snapshot AE2 cable stream bytes at world coords (server runs PartCable.writeToStream). */
77
public class GuideNhAe2CableBatchRequestMessage implements IMessage {
88

9-
public static final int MAX_POSITIONS = 512;
9+
public static final int MAX_POSITIONS = 64;
1010

1111
private long corrId;
1212
private int dim;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.hfstudio.guidenh.network;
2+
3+
public final class GuideNhCustomPayloadLimits {
4+
5+
public static final int MAX_PAYLOAD_BYTES = 28 * 1024;
6+
public static final int MAX_STRUCTURE_BYTES_PER_PACKET = 27 * 1024;
7+
8+
private GuideNhCustomPayloadLimits() {}
9+
}

src/main/java/com/hfstudio/guidenh/network/GuideNhServerHelloHandler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public class GuideNhServerHelloHandler implements IMessageHandler<GuideNhServerH
1111
@Override
1212
public IMessage onMessage(GuideNhServerHelloMessage message, MessageContext ctx) {
1313
GuideNhStructureRuntime.setServerStructureCommandsAvailable(true);
14-
GuideNhStructureRuntime.setClientStructureSyncNeeded(true);
14+
GuideNhStructureRuntime.setClientStructureSyncNeeded(false);
1515
return null;
1616
}
1717
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.hfstudio.guidenh.network;
2+
3+
import java.io.ByteArrayOutputStream;
4+
import java.nio.charset.StandardCharsets;
5+
6+
import org.jetbrains.annotations.Nullable;
7+
8+
public final class GuideNhStructureChunkAssembler {
9+
10+
private final byte[][] chunks;
11+
private int received;
12+
private int totalBytes;
13+
14+
public GuideNhStructureChunkAssembler(int chunkCount) {
15+
if (chunkCount <= 0 || chunkCount > GuideNhStructureRequestMessage.MAX_CHUNKS_PER_STRUCTURE) {
16+
throw new IllegalArgumentException("Invalid structure chunk count: " + chunkCount);
17+
}
18+
this.chunks = new byte[chunkCount][];
19+
}
20+
21+
@Nullable
22+
public synchronized String accept(GuideNhStructureRequestMessage message) {
23+
int index = message.getChunkIndex();
24+
if (message.getChunkCount() != chunks.length || index < 0 || index >= chunks.length) {
25+
return null;
26+
}
27+
byte[] bytes = message.getStructureBytes();
28+
if (bytes == null || bytes.length > GuideNhCustomPayloadLimits.MAX_STRUCTURE_BYTES_PER_PACKET) {
29+
return null;
30+
}
31+
if (chunks[index] == null) {
32+
chunks[index] = bytes;
33+
received++;
34+
totalBytes += bytes.length;
35+
}
36+
if (received != chunks.length) {
37+
return null;
38+
}
39+
40+
ByteArrayOutputStream out = new ByteArrayOutputStream(totalBytes);
41+
for (byte[] chunk : chunks) {
42+
if (chunk == null) {
43+
return null;
44+
}
45+
out.write(chunk, 0, chunk.length);
46+
}
47+
return new String(out.toByteArray(), StandardCharsets.UTF_8);
48+
}
49+
}

0 commit comments

Comments
 (0)