001/*
002 * Trident - A Multithreaded Server Alternative
003 * Copyright 2014 The TridentSDK Team
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *    http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package net.tridentsdk.server.data;
018
019import com.google.common.collect.Iterators;
020import com.google.common.collect.Lists;
021import io.netty.buffer.ByteBuf;
022import net.tridentsdk.server.netty.Codec;
023import net.tridentsdk.util.Vector;
024
025import javax.annotation.concurrent.GuardedBy;
026import javax.annotation.concurrent.ThreadSafe;
027import java.util.List;
028
029@ThreadSafe
030public class ProtocolMetadata implements Writable {
031    @GuardedBy("metadata")
032    private final List<MetadataValue> metadata = Lists.newLinkedList(() -> Iterators.forArray(new MetadataValue[22]));
033
034    public void setMeta(int index, MetadataValue value) {
035        synchronized (metadata) {
036            metadata.set(index, value);
037        }
038    }
039
040    public void setMeta(int index, MetadataType type, Object value) {
041        synchronized (metadata) {
042            metadata.set(index, new MetadataValue(index, value, type));
043        }
044    }
045
046    public MetadataValue get(int index) {
047        synchronized (metadata) {
048            return metadata.get(index);
049        }
050    }
051
052    public void remove(int index) {
053        synchronized (metadata) {
054            metadata.remove(index);
055        }
056    }
057
058    @Override
059    public void write(ByteBuf buf) {
060        List<MetadataValue> localMeta;
061        synchronized (metadata) {
062            localMeta = metadata;
063        }
064
065        for(MetadataValue value : localMeta) {
066            if (value == null) {
067                continue;
068            }
069
070            buf.writeByte((value.type().id() << 5 | value.index & 0x1F) & 0xFF);
071
072            switch(value.type) {
073                case BYTE:
074                    buf.writeByte((byte) value.value);
075                    break;
076
077                case SHORT:
078                    buf.writeShort((short) value.value);
079                    break;
080
081                case INT:
082                    buf.writeInt((int) value.value);
083                    break;
084
085                case FLOAT:
086                    buf.writeFloat((float) value.value);
087                    break;
088
089                case STRING:
090                    Codec.writeString(buf, (String) value.value);
091                    break;
092
093                case SLOT:
094                    ((Slot) value.value).write(buf);
095                    break;
096
097                case XYZ:
098                    Vector vector = (Vector) value.value;
099
100                    buf.writeInt((int) vector.x());
101                    buf.writeInt((int) vector.y());
102                    buf.writeInt((int) vector.z());
103                    break;
104
105                case PYR:
106                    Vector v = (Vector) value.value;
107
108                    buf.writeFloat((float) v.x());
109                    buf.writeFloat((float) v.y());
110                    buf.writeFloat((float) v.z());
111
112                    break;
113            }
114        }
115
116        buf.writeByte(0x7F); // terminate array
117    }
118
119    public static class MetadataValue {
120        private final int index;
121        private final Object value;
122        private final MetadataType type;
123
124        public MetadataValue(int index, Object value, MetadataType type) {
125            this.index = index;
126            this.value = value;
127            this.type = type;
128        }
129
130        public int index() {
131            return index;
132        }
133
134        public Object value() {
135            return value;
136        }
137
138        public MetadataType type() {
139            return type;
140        }
141    }
142}