Java tutorial
/* * 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() { } }