package ru.bclib.api.dataexchange; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; import net.fabricmc.fabric.api.networking.v1.PacketSender; import net.fabricmc.fabric.api.networking.v1.PlayerLookup; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientPacketListener; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.network.ServerGamePacketListenerImpl; import ru.bclib.BCLib; import ru.bclib.api.dataexchange.handler.autosync.Chunker.FileChunkSender; import java.util.List; public abstract class DataHandler extends BaseDataHandler { public abstract static class WithoutPayload extends DataHandler { protected WithoutPayload(ResourceLocation identifier, boolean originatesOnServer) { super(identifier, originatesOnServer); } @Override protected boolean prepareData(boolean isClient) { return true; } @Override protected void serializeData(FriendlyByteBuf buf, boolean isClient) { } @Override protected void deserializeIncomingData(FriendlyByteBuf buf, PacketSender responseSender, boolean isClient) { } } protected DataHandler(ResourceLocation identifier, boolean originatesOnServer) { super(identifier, originatesOnServer); } protected boolean prepareData(boolean isClient) { return true; } abstract protected void serializeData(FriendlyByteBuf buf, boolean isClient); abstract protected void deserializeIncomingData(FriendlyByteBuf buf, PacketSender responseSender, boolean isClient); abstract protected void runOnGameThread(Minecraft client, MinecraftServer server, boolean isClient); @Environment(EnvType.CLIENT) @Override void receiveFromServer(Minecraft client, ClientPacketListener handler, FriendlyByteBuf buf, PacketSender responseSender) { deserializeIncomingData(buf, responseSender, true); client.execute(() -> runOnGameThread(client, null, true)); } @Override void receiveFromClient(MinecraftServer server, ServerPlayer player, ServerGamePacketListenerImpl handler, FriendlyByteBuf buf, PacketSender responseSender) { super.receiveFromClient(server, player, handler, buf, responseSender); deserializeIncomingData(buf, responseSender, false); server.execute(() -> runOnGameThread(null, server, false)); } @Override void sendToClient(MinecraftServer server) { if (prepareData(false)) { FriendlyByteBuf buf = PacketByteBufs.create(); serializeData(buf, false); if (buf.readableBytes()>1024*1024) { final FileChunkSender sender = new FileChunkSender(buf); sender.sendChunks(PlayerLookup.all(server)); } else { for (ServerPlayer player : PlayerLookup.all(server)) { ServerPlayNetworking.send(player, getIdentifier(), buf); } } } } @Override void sendToClient(MinecraftServer server, ServerPlayer player) { if (prepareData(false)) { FriendlyByteBuf buf = PacketByteBufs.create(); serializeData(buf, false); if (buf.readableBytes()>1024*1024) { final FileChunkSender sender = new FileChunkSender(buf); sender.sendChunks(List.of(player)); } else { ServerPlayNetworking.send(player, getIdentifier(), buf); } } } @Environment(EnvType.CLIENT) @Override void sendToServer(Minecraft client) { if (prepareData(true)) { FriendlyByteBuf buf = PacketByteBufs.create(); serializeData(buf, true); ClientPlayNetworking.send(getIdentifier(), buf); } } /** * A Message that always originates on the Client */ public abstract static class FromClient extends BaseDataHandler { public abstract static class WithoutPayload extends FromClient { protected WithoutPayload(ResourceLocation identifier) { super(identifier); } @Override protected boolean prepareDataOnClient() { return true; } @Override protected void serializeDataOnClient(FriendlyByteBuf buf) { } @Override protected void deserializeIncomingDataOnServer(FriendlyByteBuf buf, PacketSender responseSender) { } } protected FromClient(ResourceLocation identifier) { super(identifier, false); } @Environment(EnvType.CLIENT) protected boolean prepareDataOnClient() { return true; } @Environment(EnvType.CLIENT) abstract protected void serializeDataOnClient(FriendlyByteBuf buf); abstract protected void deserializeIncomingDataOnServer(FriendlyByteBuf buf, PacketSender responseSender); abstract protected void runOnServerGameThread(MinecraftServer server); @Environment(EnvType.CLIENT) @Override void receiveFromServer(Minecraft client, ClientPacketListener handler, FriendlyByteBuf buf, PacketSender responseSender) { BCLib.LOGGER.error("[Internal Error] The message '" + getIdentifier() + "' must originate from the client!"); } @Override void receiveFromClient(MinecraftServer server, ServerPlayer player, ServerGamePacketListenerImpl handler, FriendlyByteBuf buf, PacketSender responseSender) { super.receiveFromClient(server, player, handler, buf, responseSender); deserializeIncomingDataOnServer(buf, responseSender); server.execute(() -> runOnServerGameThread(server)); } @Override void sendToClient(MinecraftServer server) { BCLib.LOGGER.error("[Internal Error] The message '" + getIdentifier() + "' must originate from the client!"); } @Override void sendToClient(MinecraftServer server, ServerPlayer player) { BCLib.LOGGER.error("[Internal Error] The message '" + getIdentifier() + "' must originate from the client!"); } @Environment(EnvType.CLIENT) @Override void sendToServer(Minecraft client) { if (prepareDataOnClient()) { FriendlyByteBuf buf = PacketByteBufs.create(); serializeDataOnClient(buf); ClientPlayNetworking.send(getIdentifier(), buf); } } } /** * A Message that always originates on the Server */ public abstract static class FromServer extends BaseDataHandler { public abstract static class WithoutPayload extends FromServer { protected WithoutPayload(ResourceLocation identifier) { super(identifier); } @Override protected boolean prepareDataOnServer() { return true; } @Override protected void serializeDataOnServer(FriendlyByteBuf buf) { } @Override protected void deserializeIncomingDataOnClient(FriendlyByteBuf buf, PacketSender responseSender) { } } protected FromServer(ResourceLocation identifier) { super(identifier, true); } protected boolean prepareDataOnServer() { return true; } abstract protected void serializeDataOnServer(FriendlyByteBuf buf); @Environment(EnvType.CLIENT) abstract protected void deserializeIncomingDataOnClient(FriendlyByteBuf buf, PacketSender responseSender); @Environment(EnvType.CLIENT) abstract protected void runOnClientGameThread(Minecraft client); @Environment(EnvType.CLIENT) @Override final void receiveFromServer(Minecraft client, ClientPacketListener handler, FriendlyByteBuf buf, PacketSender responseSender) { deserializeIncomingDataOnClient(buf, responseSender); client.execute(() -> runOnClientGameThread(client)); } @Override final void receiveFromClient(MinecraftServer server, ServerPlayer player, ServerGamePacketListenerImpl handler, FriendlyByteBuf buf, PacketSender responseSender) { super.receiveFromClient(server, player, handler, buf, responseSender); BCLib.LOGGER.error("[Internal Error] The message '" + getIdentifier() + "' must originate from the server!"); } @Override final void sendToClient(MinecraftServer server) { if (prepareDataOnServer()) { FriendlyByteBuf buf = PacketByteBufs.create(); serializeDataOnServer(buf); for (ServerPlayer player : PlayerLookup.all(server)) { ServerPlayNetworking.send(player, getIdentifier(), buf); } } } @Override final void sendToClient(MinecraftServer server, ServerPlayer player) { if (prepareDataOnServer()) { FriendlyByteBuf buf = PacketByteBufs.create(); serializeDataOnServer(buf); ServerPlayNetworking.send(player, getIdentifier(), buf); } } @Environment(EnvType.CLIENT) @Override final void sendToServer(Minecraft client) { BCLib.LOGGER.error("[Internal Error] The message '" + getIdentifier() + "' must originate from the server!"); } } }