Java tutorial
/* * This file is part of Spout. * * Copyright (c) 2011 Spout LLC <http://www.spout.org/> * Spout is licensed under the Spout License Version 1. * * Spout 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. * * Spout 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.api.util; import java.awt.Color; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.UUID; import io.netty.buffer.ByteBuf; import io.netty.util.CharsetUtil; import org.spout.api.Client; import org.spout.api.Platform; import org.spout.api.Server; import org.spout.api.Spout; import org.spout.api.geo.World; import org.spout.api.geo.discrete.Point; import org.spout.api.geo.discrete.Transform; import org.spout.api.inventory.ItemStack; import org.spout.api.material.Material; import org.spout.math.imaginary.Quaternion; import org.spout.math.vector.Vector2; import org.spout.math.vector.Vector3; import org.spout.nbt.CompoundMap; import org.spout.nbt.CompoundTag; import org.spout.nbt.Tag; import org.spout.nbt.stream.NBTInputStream; import org.spout.nbt.stream.NBTOutputStream; /** * Contains several {@link ByteBuf}-related utility methods. */ public final class ByteBufUtils { public static final int VECTOR3_SIZE = 12; public static final int UUID_SIZE = 16; public static final int POINT_SIZE = VECTOR3_SIZE + UUID_SIZE; public static final int QUATERNINON_SIZE = 16; public static final int TRANSFORM_SIZE = POINT_SIZE + QUATERNINON_SIZE + VECTOR3_SIZE; /** * 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(); buf.writeShort(item.getMaterial().getId()); buf.writeByte(item.getAmount()); buf.writeShort(item.getData()); 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<>(); 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<>(type, index, buf.readByte())); break; case Parameter.TYPE_SHORT: parameters.add(new Parameter<>(type, index, buf.readShort())); break; case Parameter.TYPE_INT: parameters.add(new Parameter<>(type, index, buf.readInt())); break; case Parameter.TYPE_FLOAT: parameters.add(new Parameter<>(type, index, buf.readFloat())); break; case Parameter.TYPE_STRING: parameters.add(new Parameter<>(type, index, readString(buf))); break; case Parameter.TYPE_ITEM: short id = buf.readShort(); int count = buf.readByte(); short data = buf.readShort(); ItemStack item = new ItemStack(Material.get(id), data, count); parameters.add(new Parameter<>(type, index, item)); break; } } return parameters; } /** * Writes a UTF-8 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 writeUtf8String(ByteBuf buf, String str) { byte[] bytes = str.getBytes(CharsetUtil.UTF_8); if (bytes.length >= 65536) { throw new IllegalArgumentException("Encoded UTF-8 string too long."); } buf.writeShort(bytes.length); buf.writeBytes(bytes); } /** * Reads a UTF-8 encoded string from the buffer. * * @param buf The buffer. * @return The string. */ public static String readUtf8String(ByteBuf buf) { int len = buf.readUnsignedShort(); byte[] bytes = new byte[len]; buf.readBytes(bytes); return new String(bytes, CharsetUtil.UTF_8); } public static CompoundMap readCompound(ByteBuf buf) { int len = buf.readShort(); if (len > 0) { byte[] bytes = new byte[len]; buf.readBytes(bytes); NBTInputStream str = null; try { str = new NBTInputStream(new ByteArrayInputStream(bytes)); Tag<?> tag = str.readTag(); if (tag instanceof CompoundTag) { return ((CompoundTag) tag).getValue(); } } catch (IOException e) { } finally { if (str != null) { try { str.close(); } catch (IOException e) { } } } } return null; } public static void writeCompound(ByteBuf buf, CompoundMap data) { if (data == null) { buf.writeShort(-1); return; } ByteArrayOutputStream out = new ByteArrayOutputStream(); NBTOutputStream str = null; try { str = new NBTOutputStream(out); str.writeTag(new CompoundTag("", data)); str.close(); str = null; buf.writeShort(out.size()); buf.writeBytes(out.toByteArray()); } catch (IOException e) { } finally { if (str != null) { try { str.close(); } catch (IOException e) { } } } } public static int getShifts(int height) { if (height == 0) { return 0; } int shifts = 0; int tempVal = height; while (tempVal != 1) { tempVal >>= 1; ++shifts; } return shifts; } public static int getExpandedHeight(int shift) { if (shift > 0 && shift < 12) { return 2 << shift; } else if (shift >= 32) { return shift; } return 256; } public static Vector2 readVector2(ByteBuf buf) { float x = buf.readFloat(); float z = buf.readFloat(); return new Vector2(x, z); } public static void writeVector2(ByteBuf buf, Vector2 vec) { buf.writeFloat(vec.getX()); buf.writeFloat(vec.getY()); } public static Color readColor(ByteBuf buf) { int argb = buf.readInt(); return new Color(argb); } public static void writeColor(Color color, ByteBuf buf) { buf.writeInt(color.getRGB()); } public static String readString(ByteBuf buffer) { int length = buffer.readInt(); byte[] stringBytes = new byte[length]; buffer.readBytes(stringBytes); return new String(stringBytes, CharsetUtil.UTF_8); } public static void writeString(ByteBuf buffer, String str) { byte[] stringBytes = str.getBytes(CharsetUtil.UTF_8); buffer.writeInt(stringBytes.length); buffer.writeBytes(stringBytes); } public static UUID readUUID(ByteBuf buffer) { final long lsb = buffer.readLong(); final long msb = buffer.readLong(); return new UUID(msb, lsb); } public static void writeUUID(ByteBuf buffer, UUID uuid) { buffer.writeLong(uuid.getLeastSignificantBits()); buffer.writeLong(uuid.getMostSignificantBits()); } public static Transform readTransform(ByteBuf buffer) { Point position = readPoint(buffer); Quaternion rotation = readQuaternion(buffer); Vector3 scale = readVector3(buffer); return new Transform(position, rotation, scale); } public static void writeTransform(ByteBuf buffer, Transform transform) { writePoint(buffer, transform.getPosition()); writeQuaternion(buffer, transform.getRotation()); writeVector3(buffer, transform.getScale()); } public static Vector3 readVector3(ByteBuf buffer) { final float x = buffer.readFloat(); final float y = buffer.readFloat(); final float z = buffer.readFloat(); return new Vector3(x, y, z); } public static void writeVector3(ByteBuf buffer, Vector3 vec) { buffer.writeFloat(vec.getX()); buffer.writeFloat(vec.getY()); buffer.writeFloat(vec.getZ()); } public static Point readPoint(ByteBuf buffer) { UUID uuid = readUUID(buffer); World world = null; if (Spout.getPlatform() == Platform.SERVER) { world = ((Server) Spout.getEngine()).getWorld(uuid); } else { World world1 = ((Client) Spout.getEngine()).getWorld(); if (world1.getUID().equals(uuid)) { world = world1; } } if (world == null) { throw new IllegalArgumentException("Unknown world with UUID " + uuid + (Spout.getPlatform() == Platform.CLIENT ? "Client UUID: " + ((Client) Spout.getEngine()).getWorld().getUID() + " World: " + ((Client) Spout.getEngine()).getWorld().getName() : "")); } final float x = buffer.readFloat(); final float y = buffer.readFloat(); final float z = buffer.readFloat(); return new Point(world, x, y, z); } public static void writePoint(ByteBuf buffer, Point vec) { writeUUID(buffer, vec.getWorld().getUID()); buffer.writeFloat(vec.getX()); buffer.writeFloat(vec.getY()); buffer.writeFloat(vec.getZ()); } public static Quaternion readQuaternion(ByteBuf buffer) { final float x = buffer.readFloat(); final float y = buffer.readFloat(); final float z = buffer.readFloat(); final float w = buffer.readFloat(); return new Quaternion(x, y, z, w); } public static void writeQuaternion(ByteBuf buffer, Quaternion quaternion) { buffer.writeFloat(quaternion.getX()); buffer.writeFloat(quaternion.getY()); buffer.writeFloat(quaternion.getZ()); buffer.writeFloat(quaternion.getW()); } public static String[] readStringArray(ByteBuf buffer) { int len = buffer.readShort(); String[] args = new String[len]; for (int i = 0; i < args.length; i++) { args[i] = readString(buffer); } return args; } public static void writeStringArray(ByteBuf buffer, String... arguments) { buffer.writeShort(arguments.length); for (String arg : arguments) { writeString(buffer, arg); } } /** * Default private constructor to prevent instantiation. */ private ByteBufUtils() { } }