Skip to content

Commit 83d2509

Browse files
committed
block packet API
1 parent a91a79c commit 83d2509

15 files changed

+482
-18
lines changed

src/main/java/com/falsepattern/chunk/api/DataManager.java

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,12 @@
3232
import org.jetbrains.annotations.Nullable;
3333

3434
import net.minecraft.nbt.NBTTagCompound;
35+
import net.minecraft.network.PacketBuffer;
36+
import net.minecraft.network.play.server.S23PacketBlockChange;
3537
import net.minecraft.world.chunk.Chunk;
3638
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
3739

40+
import java.io.IOException;
3841
import java.nio.ByteBuffer;
3942

4043
/**
@@ -95,11 +98,10 @@ interface PacketDataManager extends DataManager {
9598
*/
9699
@Contract(mutates = "param4")
97100
@StableAPI.Expose
98-
void writeToBuffer(Chunk chunk, int subChunkMask, boolean forceUpdate, ByteBuffer data);
101+
void writeToBuffer(Chunk chunk, int subChunkMask, boolean forceUpdate, ByteBuffer buffer);
99102

100103
/**
101104
* Deserializes your data from a packet.
102-
* Mutates this object.
103105
*
104106
* @param chunk The chunk to deserialize.
105107
* @param buffer The packet buffer to read from.
@@ -109,6 +111,39 @@ interface PacketDataManager extends DataManager {
109111
void readFromBuffer(Chunk chunk, int subChunkMask, boolean forceUpdate, ByteBuffer buffer);
110112
}
111113

114+
/**
115+
* Implement this interface if you additionally want to synchronize your data on single and multi-block updates,
116+
* not just chunk updates.
117+
*
118+
* @since TODO
119+
* @author FalsePattern
120+
* @version TODO
121+
*/
122+
@StableAPI(since = "TODO")
123+
interface BlockPacketDataManager extends DataManager {
124+
@Contract(mutates = "param1")
125+
@StableAPI.Expose
126+
void writeBlockToPacket(Chunk chunk, int x, int y, int z, S23PacketBlockChange packet);
127+
128+
@Contract(mutates = "param1,param5")
129+
@StableAPI.Expose
130+
void readBlockFromPacket(Chunk chunk, int x, int y, int z, S23PacketBlockChange packet);
131+
132+
/**
133+
* Serializes your block data into a buffer.
134+
*/
135+
@Contract(mutates = "param2")
136+
@StableAPI.Expose
137+
void writeBlockPacketToBuffer(S23PacketBlockChange packet, PacketBuffer buffer) throws IOException;
138+
139+
/**
140+
* Deserializes your block data from a buffer.
141+
*/
142+
@Contract(mutates = "param1,param2")
143+
@StableAPI.Expose
144+
void readBlockPacketFromBuffer(S23PacketBlockChange packet, PacketBuffer buffer) throws IOException;
145+
}
146+
112147
/**
113148
* The common superinterface for RootDataManager and SubChunkDataManager.
114149
* Contains version information and messages for users attempting to upgrade/remove versions.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.falsepattern.chunk.internal;
2+
3+
public class BlockPosUtil {
4+
private static final int NUM_X_BITS = 26;
5+
private static final int NUM_Z_BITS = 26;
6+
private static final int NUM_Y_BITS = 64 - NUM_X_BITS - NUM_Z_BITS;
7+
private static final long Y_MASK = (1L << NUM_Y_BITS) - 1L;
8+
private static final int Y_SHIFT = NUM_Z_BITS;
9+
private static final int X_SHIFT = Y_SHIFT + NUM_Y_BITS;
10+
private static final long Z_MASK = (1L << NUM_Z_BITS) - 1L;
11+
private static final long X_MASK = (1L << NUM_X_BITS) - 1L;
12+
13+
public static long packToLong(int x, int y, int z) {
14+
return ((long) x & X_MASK) << X_SHIFT | ((long) y & Y_MASK) << Y_SHIFT | ((long) z & Z_MASK);
15+
}
16+
17+
public static int getX(long packed) {
18+
return (int) (packed << 64 - X_SHIFT - NUM_X_BITS >> 64 - NUM_X_BITS);
19+
}
20+
21+
public static int getY(long packed) {
22+
return (int) (packed << 64 - Y_SHIFT - NUM_Y_BITS >> 64 - NUM_Y_BITS);
23+
}
24+
25+
public static int getZ(long packed) {
26+
return (int) (packed << 64 - NUM_Z_BITS >> 64 - NUM_Z_BITS);
27+
}
28+
}

src/main/java/com/falsepattern/chunk/internal/DataRegistryImpl.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
import org.jetbrains.annotations.Nullable;
3434

3535
import net.minecraft.nbt.NBTTagCompound;
36+
import net.minecraft.network.PacketBuffer;
37+
import net.minecraft.network.play.server.S23PacketBlockChange;
3638
import net.minecraft.world.chunk.Chunk;
3739
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
3840
import net.minecraftforge.common.util.Constants;
@@ -55,6 +57,7 @@
5557
public class DataRegistryImpl {
5658
private static final Set<String> managers = new HashSet<>();
5759
private static final Map<String, PacketManagerInfo> packetManagers = new HashMap<>();
60+
private static final Map<String, DataManager.BlockPacketDataManager> blockPacketManagers = new HashMap<>();
5861
private static final Map<String, DataManager.StorageDataManager> NBTManagers = new HashMap<>();
5962
private static final Map<String, DataManager.ChunkDataManager> chunkNBTManagers = new HashMap<>();
6063
private static final Map<String, DataManager.SubChunkDataManager> subChunkNBTManagers = new HashMap<>();
@@ -90,6 +93,10 @@ public static void registerDataManager(DataManager manager)
9093
maxPacketSize += 4 + id.getBytes(StandardCharsets.UTF_8).length + 4 + maxSize;
9194
packetManagers.put(id, new PacketManagerInfo(maxSize, packetManager));
9295
}
96+
if (manager instanceof DataManager.BlockPacketDataManager) {
97+
val blockPacketManager = (DataManager.BlockPacketDataManager) manager;
98+
blockPacketManagers.put(id, blockPacketManager);
99+
}
93100
if (manager instanceof DataManager.StorageDataManager) {
94101
NBTManagers.put(id, (DataManager.StorageDataManager) manager);
95102
if (manager instanceof DataManager.ChunkDataManager) {
@@ -116,6 +123,7 @@ public static void disableDataManager(String domain, String id) {
116123
val removed = packetManagers.remove(manager);
117124
maxPacketSize -= 4 + id.getBytes(StandardCharsets.UTF_8).length + 4 + removed.maxPacketSize;
118125
}
126+
blockPacketManagers.remove(manager);
119127
chunkNBTManagers.remove(manager);
120128
subChunkNBTManagers.remove(manager);
121129
NBTManagers.remove(manager);
@@ -183,6 +191,37 @@ public static int writeToBuffer(Chunk chunk, int subChunkMask, boolean forceUpda
183191
return buf.position();
184192
}
185193

194+
public static void writeBlockToPacket(Chunk chunk, int x, int y, int z, S23PacketBlockChange packet) {
195+
for (val manager: blockPacketManagers.values()) {
196+
manager.writeBlockToPacket(chunk, x, y, z, packet);
197+
}
198+
}
199+
200+
public static void readBlockFromPacket(Chunk chunk, int x, int y, int z, S23PacketBlockChange packet) {
201+
for (val manager: blockPacketManagers.values()) {
202+
manager.readBlockFromPacket(chunk, x, y, z, packet);
203+
}
204+
}
205+
206+
public static void writeBlockPacketToBuffer(S23PacketBlockChange packet, PacketBuffer buffer) throws IOException {
207+
buffer.writeInt(blockPacketManagers.size());
208+
for (val pair: blockPacketManagers.entrySet()) {
209+
val id = pair.getKey();
210+
val manager = pair.getValue();
211+
buffer.writeStringToBuffer(id);
212+
manager.writeBlockPacketToBuffer(packet, buffer);
213+
}
214+
}
215+
216+
public static void readBlockPacketFromBuffer(S23PacketBlockChange packet, PacketBuffer buffer) throws IOException {
217+
int count = buffer.readInt();
218+
for (int i = 0; i < count; i++) {
219+
val id = buffer.readStringFromBuffer(1024);
220+
val manager = blockPacketManagers.get(id);
221+
manager.readBlockPacketFromBuffer(packet, buffer);
222+
}
223+
}
224+
186225
private static ByteBuffer createSlice(ByteBuffer buffer, int start, int length) {
187226
int oldLimit = buffer.limit();
188227
int oldPosition = buffer.position();
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.falsepattern.chunk.internal.impl;
2+
3+
import net.minecraft.world.chunk.Chunk;
4+
5+
public interface CustomPacketBlockChange {
6+
void chunkapi$init(int x, int y, int z, Chunk chunk);
7+
void chunkapi$x(int value);
8+
void chunkapi$y(int value);
9+
void chunkapi$z(int value);
10+
int chunkapi$x();
11+
int chunkapi$y();
12+
int chunkapi$z();
13+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.falsepattern.chunk.internal.impl;
2+
3+
import net.minecraft.network.play.server.S23PacketBlockChange;
4+
import net.minecraft.world.chunk.Chunk;
5+
6+
public interface CustomPacketMultiBlockChange {
7+
void chunkapi$init(int count, short[] crammedPositions, Chunk chunk);
8+
S23PacketBlockChange[] chunkapi$subPackets();
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package com.falsepattern.chunk.internal.mixin.mixins.client.vanilla;
2+
3+
import com.falsepattern.chunk.internal.DataRegistryImpl;
4+
import com.falsepattern.chunk.internal.impl.CustomPacketBlockChange;
5+
import com.falsepattern.chunk.internal.impl.CustomPacketMultiBlockChange;
6+
import lombok.val;
7+
import org.spongepowered.asm.mixin.Mixin;
8+
import org.spongepowered.asm.mixin.Overwrite;
9+
import org.spongepowered.asm.mixin.Shadow;
10+
import org.spongepowered.asm.mixin.injection.At;
11+
import org.spongepowered.asm.mixin.injection.Inject;
12+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
13+
14+
import net.minecraft.client.multiplayer.WorldClient;
15+
import net.minecraft.client.network.NetHandlerPlayClient;
16+
import net.minecraft.network.play.INetHandlerPlayClient;
17+
import net.minecraft.network.play.server.S22PacketMultiBlockChange;
18+
import net.minecraft.network.play.server.S23PacketBlockChange;
19+
20+
@Mixin(NetHandlerPlayClient.class)
21+
public abstract class NetHandlerPlayClientMixin implements INetHandlerPlayClient {
22+
@Shadow
23+
private WorldClient clientWorldController;
24+
25+
@Inject(method = "handleBlockChange",
26+
at = @At(value = "RETURN"),
27+
require = 1)
28+
private void doHandleBlockChange(S23PacketBlockChange packetIn, CallbackInfo ci) {
29+
val cPacket = (CustomPacketBlockChange) packetIn;
30+
val x = cPacket.chunkapi$x();
31+
val y = cPacket.chunkapi$y();
32+
val z = cPacket.chunkapi$z();
33+
val chunk = clientWorldController.getChunkFromBlockCoords(x, z);
34+
DataRegistryImpl.readBlockFromPacket(chunk, x & 0xf, y, z & 0xf, packetIn);
35+
}
36+
37+
/**
38+
* @author FalsePattern
39+
* @reason Integrate
40+
*/
41+
@Overwrite
42+
public void handleMultiBlockChange(S22PacketMultiBlockChange packetIn) {
43+
val cX = packetIn.func_148920_c().chunkXPos;
44+
val cZ = packetIn.func_148920_c().chunkZPos;
45+
val chunk = clientWorldController.getChunkFromChunkCoords(cX, cZ);
46+
val bX = cX * 16;
47+
val bZ = cZ * 16;
48+
for (val subPacket : ((CustomPacketMultiBlockChange) packetIn).chunkapi$subPackets()) {
49+
val cSub = (CustomPacketBlockChange) subPacket;
50+
val x = cSub.chunkapi$x();
51+
val y = cSub.chunkapi$y();
52+
val z = cSub.chunkapi$z();
53+
this.clientWorldController.func_147492_c(x + bX, y, z + bZ, subPacket.func_148880_c(), subPacket.func_148881_g());
54+
DataRegistryImpl.readBlockFromPacket(chunk, x, y, z, subPacket);
55+
}
56+
}
57+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.falsepattern.chunk.internal.mixin.mixins.common.vanilla;
2+
3+
import com.falsepattern.chunk.internal.impl.CustomPacketMultiBlockChange;
4+
import lombok.val;
5+
import org.spongepowered.asm.mixin.Mixin;
6+
import org.spongepowered.asm.mixin.injection.At;
7+
import org.spongepowered.asm.mixin.injection.Redirect;
8+
9+
import net.minecraft.network.PacketBuffer;
10+
import net.minecraft.network.play.server.S22PacketMultiBlockChange;
11+
import net.minecraft.server.management.PlayerManager;
12+
import net.minecraft.world.chunk.Chunk;
13+
14+
@Mixin(PlayerManager.PlayerInstance.class)
15+
public abstract class PlayerInstanceMixin {
16+
/**
17+
* S22PacketMultiBlockChange is an absolute, utter pain in the ass to properly integrate with.
18+
*/
19+
@Redirect(method = "sendChunkUpdate",
20+
at = @At(value = "NEW",
21+
target = "(I[SLnet/minecraft/world/chunk/Chunk;)Lnet/minecraft/network/play/server/S22PacketMultiBlockChange;"),
22+
require = 1)
23+
private S22PacketMultiBlockChange hijackPacket(int count, short[] positions, Chunk chunk) {
24+
val packet = new S22PacketMultiBlockChange();
25+
((CustomPacketMultiBlockChange)packet).chunkapi$init(count, positions, chunk);
26+
return packet;
27+
}
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package com.falsepattern.chunk.internal.mixin.mixins.common.vanilla;
2+
3+
import com.falsepattern.chunk.internal.DataRegistryImpl;
4+
import com.falsepattern.chunk.internal.impl.CustomPacketBlockChange;
5+
import com.falsepattern.chunk.internal.impl.CustomPacketMultiBlockChange;
6+
import io.netty.buffer.AbstractByteBuf;
7+
import io.netty.buffer.Unpooled;
8+
import lombok.val;
9+
import org.spongepowered.asm.mixin.Mixin;
10+
import org.spongepowered.asm.mixin.Overwrite;
11+
import org.spongepowered.asm.mixin.Shadow;
12+
import org.spongepowered.asm.mixin.injection.At;
13+
import org.spongepowered.asm.mixin.injection.Inject;
14+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
15+
16+
import net.minecraft.network.PacketBuffer;
17+
import net.minecraft.network.play.INetHandlerPlayClient;
18+
import net.minecraft.network.play.server.S22PacketMultiBlockChange;
19+
import net.minecraft.network.play.server.S23PacketBlockChange;
20+
import net.minecraft.world.ChunkCoordIntPair;
21+
import net.minecraft.world.chunk.Chunk;
22+
import cpw.mods.fml.common.network.ByteBufUtils;
23+
24+
import java.io.IOException;
25+
26+
@Mixin(S22PacketMultiBlockChange.class)
27+
public abstract class S22PacketMultiBlockChangeMixin implements CustomPacketMultiBlockChange {
28+
@Shadow(aliases = "field_148925_b")
29+
private ChunkCoordIntPair coord;
30+
31+
private S23PacketBlockChange[] subPackets;
32+
33+
@Inject(method = "<init>(I[SLnet/minecraft/world/chunk/Chunk;)V",
34+
at = @At(value = "FIELD",
35+
target = "Lnet/minecraft/network/play/server/S22PacketMultiBlockChange;field_148925_b:Lnet/minecraft/world/ChunkCoordIntPair;"),
36+
require = 1)
37+
private void suppressConstructor(int p_i45181_1_, short[] crammedPositions, Chunk chunk, CallbackInfo ci) {
38+
throw new IllegalStateException(
39+
"S22PacketMultiBlockChange constructor is not supported by ChunkAPI. Please report this to FalsePattern!");
40+
}
41+
42+
@Override
43+
public void chunkapi$init(int count, short[] crammedPositions, Chunk chunk) {
44+
coord = new ChunkCoordIntPair(chunk.xPosition, chunk.zPosition);
45+
subPackets = new S23PacketBlockChange[count];
46+
for (int i = 0; i < count; ++i) {
47+
val subPacket = new S23PacketBlockChange();
48+
int x = crammedPositions[i] >> 12 & 0xf;
49+
int z = crammedPositions[i] >> 8 & 0xf;
50+
int y = crammedPositions[i] & 0xff;
51+
((CustomPacketBlockChange) subPacket).chunkapi$init(x, y, z, chunk);
52+
subPackets[i] = subPacket;
53+
}
54+
}
55+
56+
57+
/**
58+
* Reads the raw packet data from the data stream.
59+
*
60+
* @author FalsePattern
61+
* @reason Integrate
62+
*/
63+
@Overwrite
64+
public void readPacketData(PacketBuffer data) throws IOException {
65+
coord = new ChunkCoordIntPair(data.readInt(), data.readInt());
66+
int count = data.readVarIntFromBuffer();
67+
subPackets = new S23PacketBlockChange[count];
68+
for (int i = 0; i < count; ++i) {
69+
val subPacket = new S23PacketBlockChange();
70+
subPackets[i] = subPacket;
71+
val cSub = (CustomPacketBlockChange) subPacket;
72+
val pos = data.readUnsignedShort();
73+
val x = pos >> 12 & 0xf;
74+
val z = pos >> 8 & 0xf;
75+
val y = pos & 0xff;
76+
cSub.chunkapi$x(x);
77+
cSub.chunkapi$y(y);
78+
cSub.chunkapi$z(z);
79+
DataRegistryImpl.readBlockPacketFromBuffer(subPacket, data);
80+
}
81+
}
82+
83+
/**
84+
* Writes the raw packet data to the data stream.
85+
*
86+
* @author FalsePattern
87+
* @reason Integrate
88+
*/
89+
@Overwrite
90+
public void writePacketData(PacketBuffer data) throws IOException {
91+
data.writeInt(coord.chunkXPos);
92+
data.writeInt(coord.chunkZPos);
93+
94+
if (subPackets != null) {
95+
data.writeVarIntToBuffer(subPackets.length);
96+
for (val subPacket : subPackets) {
97+
val cSub = (CustomPacketBlockChange) subPacket;
98+
int pos = ((cSub.chunkapi$x() & 0xf) << 12) |
99+
((cSub.chunkapi$z() & 0xf) << 8) |
100+
(cSub.chunkapi$y() & 0xff);
101+
data.writeShort(pos);
102+
DataRegistryImpl.writeBlockPacketToBuffer(subPacket, data);
103+
}
104+
} else {
105+
data.writeInt(0);
106+
}
107+
}
108+
109+
@Override
110+
public S23PacketBlockChange[] chunkapi$subPackets() {
111+
return subPackets;
112+
}
113+
}

0 commit comments

Comments
 (0)