org.spout.vanilla.protocol.VanillaByteBufUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.spout.vanilla.protocol.VanillaByteBufUtils.java

Source

/*
 * This file is part of Vanilla.
 *
 * Copyright (c) 2011 Spout LLC <http://www.spout.org/>
 * Vanilla is licensed under the Spout License Version 1.
 *
 * Vanilla is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option)
 * any later version.
 *
 * In addition, 180 days after any changes are published, you can use the
 * software, incorporating those changes, under the terms of the MIT license,
 * as described in the Spout License Version 1.
 *
 * Vanilla is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
 * more details.
 *
 * You should have received a copy of the GNU Lesser General Public License,
 * the MIT license and the Spout License Version 1 along with this program.
 * If not, see <http://www.gnu.org/licenses/> for the GNU Lesser General Public
 * License and see <http://spout.in/licensev1> for the full license, including
 * the MIT license.
 */
package org.spout.vanilla.protocol;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import io.netty.buffer.ByteBuf;

import org.spout.api.inventory.ItemStack;
import org.spout.api.material.Material;
import org.spout.api.material.block.BlockFace;
import org.spout.api.util.Parameter;

import org.spout.math.GenericMath;
import org.spout.nbt.CompoundMap;
import org.spout.vanilla.material.VanillaMaterials;

import static org.spout.api.util.ByteBufUtils.readCompound;
import static org.spout.api.util.ByteBufUtils.writeCompound;

public final class VanillaByteBufUtils {
    /**
     * Writes a list of parameters (e.g. mob metadata) to the buffer.
     *
     * @param buf The buffer.
     * @param parameters The parameters.
     */
    @SuppressWarnings("unchecked")
    public static void writeParameters(ByteBuf buf, List<Parameter<?>> parameters) {
        for (Parameter<?> parameter : parameters) {
            int type = parameter.getType();
            int index = parameter.getIndex();
            if (index > 0x1F) {
                throw new IllegalArgumentException("Index has a maximum of 0x1F!");
            }

            buf.writeByte(type << 5 | index & 0x1F);

            switch (type) {
            case Parameter.TYPE_BYTE:
                buf.writeByte(((Parameter<Byte>) parameter).getValue());
                break;
            case Parameter.TYPE_SHORT:
                buf.writeShort(((Parameter<Short>) parameter).getValue());
                break;
            case Parameter.TYPE_INT:
                buf.writeInt(((Parameter<Integer>) parameter).getValue());
                break;
            case Parameter.TYPE_FLOAT:
                buf.writeFloat(((Parameter<Float>) parameter).getValue());
                break;
            case Parameter.TYPE_STRING:
                writeString(buf, ((Parameter<String>) parameter).getValue());
                break;
            case Parameter.TYPE_ITEM:
                ItemStack item = ((Parameter<ItemStack>) parameter).getValue();
                writeItemStack(buf, item);
                break;
            }
        }

        buf.writeByte(127);
    }

    /**
     * Reads a list of parameters from the buffer.
     *
     * @param buf The buffer.
     * @return The parameters.
     */
    public static List<Parameter<?>> readParameters(ByteBuf buf) throws IOException {
        List<Parameter<?>> parameters = new ArrayList<Parameter<?>>();

        for (int b = buf.readUnsignedByte(); b != 127; b = buf.readUnsignedByte()) {
            int type = (b & 0xE0) >> 5;
            int index = b & 0x1F;

            switch (type) {
            case Parameter.TYPE_BYTE:
                parameters.add(new Parameter<Byte>(type, index, buf.readByte()));
                break;
            case Parameter.TYPE_SHORT:
                parameters.add(new Parameter<Short>(type, index, buf.readShort()));
                break;
            case Parameter.TYPE_INT:
                parameters.add(new Parameter<Integer>(type, index, buf.readInt()));
                break;
            case Parameter.TYPE_FLOAT:
                parameters.add(new Parameter<Float>(type, index, buf.readFloat()));
                break;
            case Parameter.TYPE_STRING:
                parameters.add(new Parameter<String>(type, index, readString(buf)));
                break;
            case Parameter.TYPE_ITEM:
                parameters.add(new Parameter<ItemStack>(type, index, readItemStack(buf)));
                break;
            }
        }

        return parameters;
    }

    /**
     * Writes a string to the buffer.
     *
     * @param buf The buffer.
     * @param str The string.
     * @throws IllegalArgumentException if the string is too long <em>after</em> it is encoded.
     */
    public static void writeString(ByteBuf buf, String str) {
        int len = str.length();
        if (len >= 65536) {
            throw new IllegalArgumentException("String too long.");
        }
        buf.writeShort(len);
        for (int i = 0; i < len; ++i) {
            buf.writeChar(str.charAt(i));
        }
    }

    /**
     * Reads a string from the buffer.
     *
     * @param buf The buffer.
     * @return The string.
     */
    public static String readString(ByteBuf buf) {
        int len = buf.readUnsignedShort();

        char[] characters = new char[len];
        for (int i = 0; i < len; i++) {
            characters[i] = buf.readChar();
        }

        return new String(characters);
    }

    /**
     * Gets the size of a String represented in the formats read and written by
     * {@link #writeString(ByteBuf, String)} and {@link #readString(ByteBuf)}.
     * 
     * @param str to get the written length of
     * @return String length
     */
    public static int getStringLength(String str) {
        return str.length() * 2 + 2;
    }

    public static ItemStack readItemStack(ByteBuf buffer) throws IOException {
        short id = buffer.readShort();
        if (id < 0) {
            return null;
        } else {
            Material material = VanillaMaterials.getMaterial(id);
            if (material == null) {
                throw new IOException("Unknown material with id of " + id);
            }
            int count = buffer.readUnsignedByte();
            int damage = buffer.readUnsignedShort();
            CompoundMap nbtData = readCompound(buffer);
            return new ItemStack(material, damage, count).setNBTData(nbtData);
        }
    }

    public static void writeItemStack(ByteBuf buffer, ItemStack item) {
        short id = item == null ? (short) -1 : VanillaMaterials.getMinecraftId(item.getMaterial());
        buffer.writeShort(id);
        if (id != -1) {
            buffer.writeByte(item.getAmount());
            buffer.writeShort(item.getData());
            writeCompound(buffer, item.getNBTData());
        }
    }

    public static byte getNativeDirection(BlockFace face) {
        switch (face) {
        case SOUTH:
            return 3;
        case WEST:
            return 0;
        case NORTH:
            return 1;
        case EAST:
            return 2;
        default:
            return -1;
        }
    }

    public static int protocolifyPosition(float pos) {
        return GenericMath.floor(pos * 32);
    }

    public static float deProtocolifyPosition(int pos) {
        return pos / 32F;
    }

    public static int protocolifyPitch(float pitch) {
        return GenericMath.wrapByte(GenericMath.floor((pitch / 360) * 256));
    }

    public static float deProtocolifyPitch(int pitch) {
        return 360f * (pitch / 256f);
    }

    public static int protocolifyYaw(float yaw) {
        return protocolifyPitch(-yaw);
    }

    public static float deProtocolifyYaw(int yaw) {
        return -deProtocolifyPitch(yaw);
    }

    private VanillaByteBufUtils() {
    }

}