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.block;
018
019import net.tridentsdk.base.Block;
020import net.tridentsdk.base.Position;
021import net.tridentsdk.base.Substance;
022import net.tridentsdk.entity.living.Player;
023import net.tridentsdk.entity.types.EntityType;
024import net.tridentsdk.meta.block.SignMeta;
025import net.tridentsdk.meta.block.Tile;
026import net.tridentsdk.meta.component.Meta;
027import net.tridentsdk.meta.component.MetaCollection;
028import net.tridentsdk.plugin.cmd.PlatformColor;
029import net.tridentsdk.server.packets.play.out.PacketPlayOutSignEditorOpen;
030import net.tridentsdk.server.packets.play.out.PacketPlayOutUpdateSign;
031import net.tridentsdk.server.player.TridentPlayer;
032import net.tridentsdk.server.util.OwnedTridentBlock;
033import net.tridentsdk.server.world.TridentWorld;
034
035import java.util.concurrent.atomic.AtomicReferenceArray;
036
037/**
038 * Implements sign meta
039 *
040 * @author The TridentSDK Team
041 */
042public class SignMetaImpl implements SignMeta, Tile {
043    private volatile byte orientation;
044    private volatile Position position;
045    private final AtomicReferenceArray<String> stringAtomicReferenceArray = new AtomicReferenceArray<>(4);
046
047    @Override
048    public String textAt(int index) {
049        return stringAtomicReferenceArray.get(index);
050    }
051
052    @Override
053    public void setTextAt(int index, String text) {
054        stringAtomicReferenceArray.set(index, text);
055        position.world().entities().stream().filter(e -> e.type() == EntityType.PLAYER).forEach(p -> update((Player) p));
056    }
057
058    private String[] toArray() {
059        String[] strings = new String[4];
060        for (int i = 0; i < 4; i++) {
061            String s = stringAtomicReferenceArray.get(i);
062            if (s == null) {
063                setTextAt(i, s = PlatformColor.EMPTY);
064            }
065
066            strings[i] = s;
067        }
068
069        return strings;
070    }
071
072    @Override
073    public byte encode() {
074        // TODO handle illegal meta
075        ((TridentWorld) position.world()).tilesInternal().add(this);
076        return orientation;
077    }
078
079    @Override
080    public Meta<Block> decode(Block instance, float yaw, byte direction, byte cx, byte cy, byte cz, short damageValue) {
081        byte data = 0x00;
082
083        yaw = (yaw + 180.0f + 45.0f) % 360.0f;     // +180 puts north at 360/0 - +45 puts north/west to 0
084        int orientation = (int)(yaw / 90.0f);
085
086        switch(orientation) {
087            case 0:
088                data |= 3;
089                break;
090            case 1:
091                data |= 4;
092                break;
093            case 2:
094                data |= 2;
095                break;
096            case 3:
097                data |= 5;
098                break;
099        }
100
101        instance.setSubstanceAndMeta(Substance.SIGN_POST, data);
102
103        orientation = data;
104        position = instance.position();
105        ((OwnedTridentBlock) instance).player().connection().sendPacket(new PacketPlayOutSignEditorOpen().set("loc", position));
106        return this;
107    }
108
109    @Override
110    public Meta<Block> make() {
111        return new SignMetaImpl();
112    }
113
114    @Override
115    public Substance[] applyTo(MetaCollection collection) {
116        collection.put(SignMeta.class, this);
117        return new Substance[] {Substance.SIGN}; // TODO wall signs
118    }
119
120    @Override
121    public void update(Player player) {
122        ((TridentPlayer) player).connection().sendPacket(new PacketPlayOutUpdateSign().set("loc", position).set("messages", toArray()));
123    }
124}