com.Da_Technomancer.crossroads.API.packets.Message.java Source code

Java tutorial

Introduction

Here is the source code for com.Da_Technomancer.crossroads.API.packets.Message.java

Source

/**
 * This class was created by <Vazkii>. It's distributed as
 * part of the Psi Mod. Get the Source Code in github:
 * https://github.com/Vazkii/Psi
 * 
 * Psi is Open Source and distributed under the
 * CC-BY-NC-SA 3.0 License: https://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB
 * 
 * File Created @ [11/01/2016, 22:00:30 (GMT)]
 */

/**
 * Let me, (Technomancer), be clear, Vazkii made this class and I take no credit for it. Using the class is permitted by the license.
 */
package com.Da_Technomancer.crossroads.API.packets;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.HashMap;

import org.apache.commons.lang3.tuple.Pair;

import io.netty.buffer.ByteBuf;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.fml.common.network.ByteBufUtils;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;

@SuppressWarnings({ "serial", "rawtypes" })
public class Message<REQ extends Message> implements Serializable, IMessage, IMessageHandler<REQ, IMessage> {
    @SuppressWarnings("unchecked")
    private static final HashMap<Class, Pair<Reader, Writer>> handlers = new HashMap();
    @SuppressWarnings("unchecked")
    private static final HashMap<Class, Field[]> fieldCache = new HashMap();

    static {
        map(byte.class, Message::readByte, Message::writeByte);
        // map(short.class, Message::readShort, Message::writeShort);
        map(int.class, Message::readInt, Message::writeInt);
        map(long.class, Message::readLong, Message::writeLong);
        map(float.class, Message::readFloat, Message::writeFloat);
        map(double.class, Message::readDouble, Message::writeDouble);
        map(boolean.class, Message::readBoolean, Message::writeBoolean);
        // map(char.class, Message::readChar, Message::writeChar);
        map(String.class, Message::readString, Message::writeString);
        map(NBTTagCompound.class, Message::readNBT, Message::writeNBT);
        // map(ItemStack.class, Message::readItemStack, Message::writeItemStack);
        map(BlockPos.class, Message::readBlockPos, Message::writeBlockPos);
        map(byte[][].class, Message::readByte2DArray, Message::writeByte2DArray);
        map(int[].class, Message::readIntArray, Message::writeIntArray);
        map(double[].class, Message::readDoubleArray, Message::writeDoubleArray);
    }

    // The thing you override!
    public IMessage handleMessage(MessageContext context) {
        return null;
    }

    @Override
    public final IMessage onMessage(REQ message, MessageContext context) {
        return message.handleMessage(context);
    }

    @Override
    public final void fromBytes(ByteBuf buf) {
        try {
            Class<?> clazz = getClass();
            Field[] clFields = getClassFields(clazz);
            for (Field f : clFields) {
                Class<?> type = f.getType();
                if (acceptField(f, type))
                    readField(f, type, buf);
            }
        } catch (Exception e) {
            throw new RuntimeException("Error at reading packet " + this, e);
        }
    }

    @Override
    public final void toBytes(ByteBuf buf) {
        try {
            Class<?> clazz = getClass();
            Field[] clFields = getClassFields(clazz);
            for (Field f : clFields) {
                Class<?> type = f.getType();
                if (acceptField(f, type)) {
                    writeField(f, type, buf);
                }
            }
        } catch (Exception e) {
            throw new RuntimeException("Error at writing packet " + this, e);
        }
    }

    private static Field[] getClassFields(Class<?> clazz) {
        if (fieldCache.containsValue(clazz))
            return fieldCache.get(clazz);
        else {
            Field[] fields = clazz.getFields();
            Arrays.sort(fields, (Field f1, Field f2) -> {
                return f1.getName().compareTo(f2.getName());
            });
            fieldCache.put(clazz, fields);
            return fields;
        }
    }

    @SuppressWarnings("unchecked")
    private final void writeField(Field f, Class clazz, ByteBuf buf)
            throws IllegalArgumentException, IllegalAccessException {
        Pair<Reader, Writer> handler = getHandler(clazz);
        handler.getRight().write(f.get(this), buf);
    }

    private final void readField(Field f, Class clazz, ByteBuf buf)
            throws IllegalArgumentException, IllegalAccessException {
        Pair<Reader, Writer> handler = getHandler(clazz);
        f.set(this, handler.getLeft().read(buf));
    }

    private static Pair<Reader, Writer> getHandler(Class<?> clazz) {
        Pair<Reader, Writer> pair = handlers.get(clazz);
        if (pair == null)
            throw new RuntimeException("No R/W handler for  " + clazz);
        return pair;
    }

    private static boolean acceptField(Field f, Class<?> type) {
        int mods = f.getModifiers();
        if (Modifier.isFinal(mods) || Modifier.isStatic(mods) || Modifier.isTransient(mods))
            return false;

        return handlers.containsKey(type);
    }

    private static <T extends Object> void map(Class<T> type, Reader<T> reader, Writer<T> writer) {
        handlers.put(type, Pair.of(reader, writer));
    }

    private static byte readByte(ByteBuf buf) {
        return buf.readByte();
    }

    private static void writeByte(byte b, ByteBuf buf) {
        buf.writeByte(b);
    }

    /*
     * private static short readShort(ByteBuf buf) { return buf.readShort(); }
     * 
     * private static void writeShort(short s, ByteBuf buf) { buf.writeShort(s);
     * }
     */

    private static int readInt(ByteBuf buf) {
        return buf.readInt();
    }

    private static void writeInt(int i, ByteBuf buf) {
        buf.writeInt(i);
    }

    private static long readLong(ByteBuf buf) {
        return buf.readLong();
    }

    private static void writeLong(long l, ByteBuf buf) {
        buf.writeLong(l);
    }

    private static float readFloat(ByteBuf buf) {
        return buf.readFloat();
    }

    private static void writeFloat(float f, ByteBuf buf) {
        buf.writeFloat(f);
    }

    private static double readDouble(ByteBuf buf) {
        return buf.readDouble();
    }

    private static void writeDouble(double d, ByteBuf buf) {
        buf.writeDouble(d);
    }

    private static boolean readBoolean(ByteBuf buf) {
        return buf.readBoolean();
    }

    private static void writeBoolean(boolean b, ByteBuf buf) {
        buf.writeBoolean(b);
    }

    /*
     * private static char readChar(ByteBuf buf) { return buf.readChar(); }
     * 
     * private static void writeChar(char c, ByteBuf buf) { buf.writeChar(c); }
     */

    private static byte[][] readByte2DArray(ByteBuf buf) {
        int outerSize = buf.readInt();
        int innerSize = buf.readInt();
        byte[][] out = new byte[outerSize][innerSize];
        for (int i = 0; i < outerSize; i++) {
            for (int j = 0; j < innerSize; j++) {
                out[i][j] = buf.readByte();
            }
        }
        return out;
    }

    private static void writeByte2DArray(byte[][] bytes, ByteBuf buf) {
        buf.writeInt(bytes.length);
        buf.writeInt(bytes[0].length);
        for (byte[] inner : bytes) {
            buf.writeBytes(inner);
        }
    }

    private static int[] readIntArray(ByteBuf buf) {
        int size = buf.readInt();
        int[] out = new int[size];
        for (int i = 0; i < size; i++) {
            out[i] = buf.readInt();
        }
        return out;
    }

    private static void writeIntArray(int[] ints, ByteBuf buf) {
        buf.writeInt(ints.length);
        for (int inner : ints) {
            buf.writeInt(inner);
        }
    }

    private static double[] readDoubleArray(ByteBuf buf) {
        int size = buf.readInt();
        double[] out = new double[size];
        for (int i = 0; i < size; i++) {
            out[i] = buf.readDouble();
        }
        return out;
    }

    private static void writeDoubleArray(double[] doubles, ByteBuf buf) {
        buf.writeInt(doubles.length);
        for (double inner : doubles) {
            buf.writeDouble(inner);
        }
    }

    private static String readString(ByteBuf buf) {
        return ByteBufUtils.readUTF8String(buf);
    }

    private static void writeString(String s, ByteBuf buf) {
        ByteBufUtils.writeUTF8String(buf, s);
    }

    private static NBTTagCompound readNBT(ByteBuf buf) {
        return ByteBufUtils.readTag(buf);
    }

    private static void writeNBT(NBTTagCompound cmp, ByteBuf buf) {
        ByteBufUtils.writeTag(buf, cmp);
    }

    /*
     * private static ItemStack readItemStack(ByteBuf buf) { return
     * ByteBufUtils.readItemStack(buf); }
     * 
     * private static void writeItemStack(ItemStack stack, ByteBuf buf) {
     * ByteBufUtils.writeItemStack(buf, stack); }
     */

    private static BlockPos readBlockPos(ByteBuf buf) {
        return BlockPos.fromLong(buf.readLong());
    }

    private static void writeBlockPos(BlockPos pos, ByteBuf buf) {
        buf.writeLong(pos.toLong());
    }

    public static interface Writer<T extends Object> {
        public void write(T t, ByteBuf buf);
    }

    public static interface Reader<T extends Object> {
        public T read(ByteBuf buf);
    }

}