Skip to content

Commit

Permalink
Implement Codeck within Owo Networking
Browse files Browse the repository at this point in the history
- Adjust networking test
- Fix improper encode and decode for String
- Use VAR_INT codeck for enum
  • Loading branch information
Dragon-Seeker committed Oct 22, 2023
1 parent dd47bef commit e13e5c3
Show file tree
Hide file tree
Showing 9 changed files with 189 additions and 73 deletions.
2 changes: 1 addition & 1 deletion src/main/java/io/wispforest/owo/network/OwoHandshake.java
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ private static Pair<Set<Identifier>, Set<Identifier>> findCollisions(Set<Identif
private static int hashChannel(OwoNetChannel channel) {
int serializersHash = 0;
for (var entry : channel.serializersByIndex.int2ObjectEntrySet()) {
serializersHash += entry.getIntKey() * 31 + entry.getValue().serializer.getRecordClass().getName().hashCode();
serializersHash += entry.getIntKey() * 31 + entry.getValue().getRecordClass().getName().hashCode();
}
return 31 * channel.packetId.hashCode() + serializersHash;
}
Expand Down
135 changes: 106 additions & 29 deletions src/main/java/io/wispforest/owo/network/OwoNetChannel.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

import io.wispforest.owo.mixin.ServerCommonNetworkHandlerAccessor;
import io.wispforest.owo.network.serialization.PacketBufSerializer;
import io.wispforest.owo.network.serialization.RecordSerializer;
import io.wispforest.owo.serialization.impl.RecordCodeck;
import io.wispforest.owo.serialization.impl.StructCodeck;
import io.wispforest.owo.serialization.impl.bytebuf.ByteBufDeserializer;
import io.wispforest.owo.serialization.impl.bytebuf.ByteBufSerializer;
import io.wispforest.owo.util.OwoFreezer;
import io.wispforest.owo.util.ReflectionUtils;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
Expand Down Expand Up @@ -127,14 +130,14 @@ private OwoNetChannel(Identifier id, String ownerClassName, boolean required) {

ServerPlayNetworking.registerGlobalReceiver(packetId, (server, player, handler, buf, responseSender) -> {
int handlerIndex = buf.readVarInt();
final Record message = serializersByIndex.get(handlerIndex).serializer.read(buf);
final Record message = serializersByIndex.get(handlerIndex).serializer.decode(ByteBufDeserializer::new, buf);
server.execute(() -> serverHandlers.get(handlerIndex).handle(message, new ServerAccess(player)));
});

if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) {
ClientPlayNetworking.registerGlobalReceiver(packetId, (client, handler, buf, responseSender) -> {
int handlerIndex = buf.readVarInt();
final Record message = serializersByIndex.get(-handlerIndex).serializer.read(buf);
final Record message = serializersByIndex.get(-handlerIndex).serializer.decode(ByteBufDeserializer::new, buf);
client.execute(() -> clientHandlers.get(handlerIndex).handle(message, new ClientAccess(handler)));
});
}
Expand Down Expand Up @@ -164,17 +167,7 @@ private OwoNetChannel(Identifier id, String ownerClassName, boolean required) {
*/
@SuppressWarnings("unchecked")
public <R extends Record> void registerClientbound(Class<R> messageClass, ChannelHandler<R, ClientAccess> handler) {
int deferredIndex = deferredClientSerializers.removeInt(messageClass);
if (deferredIndex != -1) {
OwoFreezer.checkRegister("Network handlers");

this.clientHandlers.set(deferredIndex, (ChannelHandler<Record, ClientAccess>) handler);
return;
}

int index = this.clientHandlers.size();
this.createSerializer(messageClass, index, EnvType.CLIENT);
this.clientHandlers.add((ChannelHandler<Record, ClientAccess>) handler);
registerClientbound(messageClass, handler, () -> RecordCodeck.create(messageClass));
}

/**
Expand All @@ -189,11 +182,7 @@ public <R extends Record> void registerClientbound(Class<R> messageClass, Channe
* @see PacketBufSerializer#register(Class, PacketByteBuf.PacketWriter, PacketByteBuf.PacketReader)
*/
public <R extends Record> void registerClientboundDeferred(Class<R> messageClass) {
int index = this.clientHandlers.size();
this.createSerializer(messageClass, index, EnvType.CLIENT);
this.clientHandlers.add(null);

this.deferredClientSerializers.put(messageClass, index);
registerClientboundDeferred(messageClass, () -> RecordCodeck.create(messageClass));
}

/**
Expand All @@ -208,11 +197,95 @@ public <R extends Record> void registerClientboundDeferred(Class<R> messageClass
*/
@SuppressWarnings("unchecked")
public <R extends Record> void registerServerbound(Class<R> messageClass, ChannelHandler<R, ServerAccess> handler) {
registerServerbound(messageClass, handler, () -> RecordCodeck.create(messageClass));
}

//--

/**
* Registers a handler <i>on the client</i> for the specified message class.
* This also ensures the required serializer is available. If an exception
* about a missing type adapter is thrown, register one
*
* @param messageClass The type of packet data to send and serialize
* @param codeck The alternative Codeck to Serialize the given Record
* @param handler The handler that will receive the deserialized
* @see #serverHandle(PlayerEntity)
* @see #serverHandle(MinecraftServer)
* @see #serverHandle(ServerWorld, BlockPos)
* @see PacketBufSerializer#register(Class, PacketByteBuf.PacketWriter, PacketByteBuf.PacketReader)
*/
@SuppressWarnings("unchecked")
public <R extends Record> void registerClientbound(Class<R> messageClass, StructCodeck<R> codeck, ChannelHandler<R, ClientAccess> handler) {
registerClientbound(messageClass, handler, () -> codeck);
}

/**
* Registers a message class <i>on the client</i> with deferred handler registration.
* This also ensures the required serializer is available. If an exception
* about a missing type adapter is thrown, register one
*
* @param messageClass The type of packet data to send and serialize
* @param codeck The alternative Codeck to Serialize the given Record
* @see #serverHandle(PlayerEntity)
* @see #serverHandle(MinecraftServer)
* @see #serverHandle(ServerWorld, BlockPos)
* @see PacketBufSerializer#register(Class, PacketByteBuf.PacketWriter, PacketByteBuf.PacketReader)
*/
public <R extends Record> void registerClientboundDeferred(Class<R> messageClass, StructCodeck<R> codeck) {
registerClientboundDeferred(messageClass, () -> codeck);
}

/**
* Registers a handler <i>on the server</i> for the specified message class.
* This also ensures the required serializer is available. If an exception
* about a missing type adapter is thrown, register one
*
* @param messageClass The type of packet data to send and serialize
* @param codeck The alternative Codeck to Serialize the given Record
* @param handler The handler that will receive the deserialized
* @see #clientHandle()
* @see PacketBufSerializer#register(Class, PacketByteBuf.PacketWriter, PacketByteBuf.PacketReader)
*/
@SuppressWarnings("unchecked")
public <R extends Record> void registerServerbound(Class<R> messageClass, StructCodeck<R> codeck, ChannelHandler<R, ServerAccess> handler) {
registerServerbound(messageClass, handler, () -> codeck);
}

//--

@SuppressWarnings("unchecked")
private <R extends Record> void registerClientbound(Class<R> messageClass, ChannelHandler<R, ClientAccess> handler, Supplier<StructCodeck<R>> codeck) {
int deferredIndex = deferredClientSerializers.removeInt(messageClass);
if (deferredIndex != -1) {
OwoFreezer.checkRegister("Network handlers");

this.clientHandlers.set(deferredIndex, (ChannelHandler<Record, ClientAccess>) handler);
return;
}

int index = this.clientHandlers.size();
this.createSerializer(messageClass, index, EnvType.CLIENT, codeck);
this.clientHandlers.add((ChannelHandler<Record, ClientAccess>) handler);
}

private <R extends Record> void registerClientboundDeferred(Class<R> messageClass, Supplier<StructCodeck<R>> codeck) {
int index = this.clientHandlers.size();
this.createSerializer(messageClass, index, EnvType.CLIENT, codeck);
this.clientHandlers.add(null);

this.deferredClientSerializers.put(messageClass, index);
}

@SuppressWarnings("unchecked")
private <R extends Record> void registerServerbound(Class<R> messageClass, ChannelHandler<R, ServerAccess> handler, Supplier<StructCodeck<R>> codeck) {
int index = this.serverHandlers.size();
this.createSerializer(messageClass, index, EnvType.SERVER);
this.createSerializer(messageClass, index, EnvType.SERVER, codeck);
this.serverHandlers.add((ChannelHandler<Record, ServerAccess>) handler);
}

//--

public boolean canSendToPlayer(ServerPlayerEntity player) {
return canSendToPlayer(player.networkHandler);
}
Expand Down Expand Up @@ -339,12 +412,12 @@ private ServerHandle getServerHandle() {
return serverHandle;
}

private <R extends Record> void createSerializer(Class<R> messageClass, int handlerIndex, EnvType target) {
private <R extends Record> void createSerializer(Class<R> messageClass, int handlerIndex, EnvType target, Supplier<StructCodeck<R>> supplier) {
OwoFreezer.checkRegister("Network handlers");

var serializer = serializersByClass.get(messageClass);
if (serializer == null) {
final var indexedSerializer = IndexedSerializer.create(RecordSerializer.create(messageClass), handlerIndex, target);
final var indexedSerializer = IndexedSerializer.create(messageClass, supplier.get(), handlerIndex, target);
serializersByClass.put(messageClass, indexedSerializer);
serializersByIndex.put(target == EnvType.CLIENT ? -handlerIndex : handlerIndex, indexedSerializer);
} else if (serializer.handlerIndex(target) == -1) {
Expand All @@ -371,9 +444,7 @@ private <R extends Record> PacketByteBuf encode(R message, EnvType target) {
}

buffer.writeVarInt(serializer.handlerIndex(target));
serializer.serializer.write(buffer, message);

return buffer;
return serializer.serializer.encode(() -> new ByteBufSerializer<>(buffer), message);
}

public class ClientHandle {
Expand Down Expand Up @@ -496,14 +567,16 @@ static final class IndexedSerializer<R extends Record> {
private int clientHandlerIndex = -1;
private int serverHandlerIndex = -1;

final RecordSerializer<R> serializer;
final Class<R> rClass;
final StructCodeck<R> serializer;

private IndexedSerializer(RecordSerializer<R> serializer) {
private IndexedSerializer(Class<R> rClass, StructCodeck<R> serializer) {
this.serializer = serializer;
this.rClass = rClass;
}

public static <R extends Record> IndexedSerializer<R> create(RecordSerializer<R> serializer, int index, EnvType target) {
return new IndexedSerializer<>(serializer).setHandlerIndex(index, target);
public static <R extends Record> IndexedSerializer<R> create(Class<R> rClass, StructCodeck<R> serializer, int index, EnvType target) {
return new IndexedSerializer<>(rClass, serializer).setHandlerIndex(index, target);
}

public IndexedSerializer<R> setHandlerIndex(int index, EnvType target) {
Expand All @@ -520,6 +593,10 @@ public int handlerIndex(EnvType target) {
case SERVER -> serverHandlerIndex;
};
}

public Class<R> getRecordClass(){
return this.rClass;
}
}
}

26 changes: 26 additions & 0 deletions src/main/java/io/wispforest/owo/serialization/Codeck.java
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,10 @@ public <E> NbtElement decode(Deserializer<E> deserializer) {
Codeck<Text> TEXT = Codeck.JSON_ELEMENT.then(Text.Serializer::fromJson, Text.Serializer::toJsonTree);
//Codeck.STRING.then(Text.Serializer::fromJson, Text.Serializer::toJson);

Codeck<Integer> VAR_INT = Codeck.of(Serializer::writeVarInt, Deserializer::readVarInt);

Codeck<Long> VAR_LONG = Codeck.of(Serializer::writeVarLong, Deserializer::readVarLong);

//--

//Kinda mega cursed but...
Expand Down Expand Up @@ -301,6 +305,28 @@ public <E> Optional<T> decode(Deserializer<E> deserializer) {
return ofOptional().then(o -> o.orElse(null), Optional::ofNullable);
}

default Codeck<T> onError(TriConsumer<Serializer, T, Exception> encode, BiFunction<Deserializer, Exception, T> decode){
return new Codeck<>() {
@Override
public <E> void encode(Serializer<E> serializer, T value) {
try {
Codeck.this.encode(serializer, value);
} catch (Exception e){
encode.accept(serializer, value, e);
}
}

@Override
public <E> T decode(Deserializer<E> deserializer) {
try {
return Codeck.this.decode(deserializer);
} catch (Exception e) {
return decode.apply(deserializer, e);
}
}
};
}

//--

<E> void encode(Serializer<E> serializer, T value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ public static <R extends Record> Codeck<R> createRecordSerializer(Class<R> clazz
* @return The created serializer
*/
public static <E extends Enum<E>> Codeck<E> createEnumSerializer(Class<E> enumClass) {
return Codeck.INT.then(integer -> enumClass.getEnumConstants()[integer], Enum::ordinal);
return Codeck.VAR_INT.then(i -> enumClass.getEnumConstants()[i], Enum::ordinal);
}

@SuppressWarnings("unchecked")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,22 @@
import io.netty.buffer.ByteBuf;
import io.wispforest.owo.serialization.*;
import io.wispforest.owo.serialization.impl.SerializationAttribute;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.network.encoding.StringEncoding;
import net.minecraft.network.encoding.VarInts;
import net.minecraft.network.encoding.VarLongs;
import org.jetbrains.annotations.Nullable;

import java.nio.charset.Charset;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

public class ByteBufDeserializer implements Deserializer<ByteBuf> {

private final boolean useVarInt;

private final ByteBuf buf;

public ByteBufDeserializer(ByteBuf buf){
this.buf = buf;
this.useVarInt = false;
}

//--
Expand Down Expand Up @@ -81,7 +79,7 @@ public double readDouble() {

@Override
public String readString() {
return buf.toString(Charset.defaultCharset());
return StringEncoding.decode(buf, PacketByteBuf.DEFAULT_MAX_STRING_LENGTH);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import io.wispforest.owo.serialization.impl.SerializationAttribute;
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.network.encoding.StringEncoding;
import net.minecraft.network.encoding.VarInts;
import net.minecraft.network.encoding.VarLongs;

Expand Down Expand Up @@ -85,7 +86,7 @@ public void writeDouble(double value) {

@Override
public void writeString(String value) {
this.buf.writeBytes(value.getBytes());
StringEncoding.encode(buf, value, PacketByteBuf.DEFAULT_MAX_STRING_LENGTH);
}

@Override
Expand Down
32 changes: 2 additions & 30 deletions src/testmod/java/io/wispforest/uwu/Uwu.java
Original file line number Diff line number Diff line change
Expand Up @@ -342,45 +342,17 @@ public void onInitialize() {
iterations("Vanilla", (buf) -> {
ItemStack stack = source.getPlayer().getStackInHand(Hand.MAIN_HAND);

//source.sendMessage(Text.of(stack.toString()));
//source.sendMessage(Text.of(String.valueOf(stack.getOrCreateNbt())));

//source.sendMessage(Text.of("---"));

buf.writeItemStack(stack);

//source.sendMessage(Text.of(String.valueOf(buf.writerIndex())));

//source.sendMessage(Text.of("---"));

var stackFromByte = buf.readItemStack();

//source.sendMessage(Text.of(stackFromByte.toString()));
//source.sendMessage(Text.of(String.valueOf(stackFromByte.getOrCreateNbt())));
var stackFromByte = buf.writeItemStack(stack).readItemStack();
});

//Codeck
try {
iterations("Codeck", (buf) -> {
ItemStack stack = source.getPlayer().getStackInHand(Hand.MAIN_HAND);

//source.sendMessage(Text.of(stack.toString()));
//source.sendMessage(Text.of(String.valueOf(stack.getOrCreateNbt())));

//source.sendMessage(Text.of("---"));

Codeck.ITEM_STACK.encode(new ByteBufSerializer<>(buf), stack);

//source.sendMessage(Text.of(String.valueOf(stackByteData.writerIndex())));

//source.sendMessage(Text.of("---"));

ItemStack stackFromByte;

stackFromByte = Codeck.ITEM_STACK.decode(ByteBufDeserializer::new, buf);

//source.sendMessage(Text.of(stackFromByte.toString()))
//source.sendMessage(Text.of(String.valueOf(stackFromByte.getOrCreateNbt())));
var stackFromByte = Codeck.ITEM_STACK.decode(ByteBufDeserializer::new, buf);
});
} catch (Exception exception){
source.sendMessage(Text.of(exception.getMessage()));
Expand Down
Loading

0 comments on commit e13e5c3

Please sign in to comment.