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 */
017
018package net.tridentsdk.server.packets.play.in;
019
020import io.netty.buffer.ByteBuf;
021import net.tridentsdk.event.player.PlayerToggleFlyingEvent;
022import net.tridentsdk.registry.Registered;
023import net.tridentsdk.server.netty.ClientConnection;
024import net.tridentsdk.server.netty.packet.InPacket;
025import net.tridentsdk.server.netty.packet.Packet;
026import net.tridentsdk.server.player.PlayerConnection;
027import net.tridentsdk.server.player.TridentPlayer;
028import net.tridentsdk.world.settings.GameMode;
029
030/**
031 * Packet is sent when the player starts/stops flying with the second parameter changed accordingly. All other
032 * parameters are ignored by the vanilla server.
033 */
034public class PacketPlayInPlayerAbilities extends InPacket {
035
036    /**
037     * The flags are whether damage is disabled (god mode, 8, bit 3), whether the player can fly (4, bit 2), whether
038     * the
039     * player is flying (2, bit 1), and whether the player is in creative mode (1, bit 0).  To get the values of
040     * these booleans, simply AND (&) the byte with 1,2,4 and 8 respectively, to get the 0 or 1 bitwise value. To set
041     * them OR (|) them with their repspective masks.
042     */
043    protected byte flags;
044
045    /**
046     * Previous integer value divided by 250
047     */
048    protected float flyingSpeed;
049    /**
050     * Previous integer value divided by 250
051     */
052    protected float walkingSpeed;
053
054    @Override
055    public int id() {
056        return 0x12;
057    }
058
059    @Override
060    public Packet decode(ByteBuf buf) {
061        this.flags = buf.readByte();
062
063        this.flyingSpeed = buf.readFloat();
064        this.walkingSpeed = buf.readFloat();
065
066        return this;
067    }
068
069    public byte flags() {
070        return this.flags;
071    }
072
073    public float flyingSpeed() {
074        return this.flyingSpeed;
075    }
076
077    public float walkingSpeed() {
078        return this.walkingSpeed;
079    }
080
081    @Override
082    public void handleReceived(ClientConnection connection) {
083        TridentPlayer player = ((PlayerConnection) connection).player();
084
085        boolean flying = (byte) (flags & 2) == 2;
086
087        if(player.gameMode() == GameMode.CREATIVE || flying != player.isFlying()) {
088            PlayerToggleFlyingEvent toggleFly = new PlayerToggleFlyingEvent(player, flying, player.isFlyMode());
089
090            // if the player doesn't have fly mode and is attempting to fly, make the event default to cancelled
091            if (!player.isFlyMode() && flying) {
092                toggleFly.cancel(true);
093            }
094
095            // If the player is flying and sends a flying=false flag, stop flying
096            if (player.isFlying() && !flying) {
097                toggleFly.cancel(true);
098            }
099
100            Registered.events().fire(toggleFly);
101
102            player.setFlying(!toggleFly.isIgnored());
103        }
104
105        // TODO: act accordingly
106    }
107}