org.spout.engine.protocol.builtin.SpoutProtocol.java Source code

Java tutorial

Introduction

Here is the source code for org.spout.engine.protocol.builtin.SpoutProtocol.java

Source

/*
 * 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.engine.protocol.builtin;

import java.net.InetSocketAddress;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;

import java.util.UUID;

import org.spout.api.Spout;
import org.spout.api.command.Command;
import org.spout.api.command.CommandArguments;
import org.spout.api.component.entity.PlayerNetworkComponent;
import org.spout.api.entity.Entity;
import org.spout.api.entity.Player;
import org.spout.api.event.object.EventableListener;
import org.spout.api.protocol.ClientSession;
import org.spout.api.protocol.Message;
import org.spout.api.protocol.MessageCodec;
import org.spout.api.protocol.Protocol;
import org.spout.api.protocol.ServerSession;
import org.spout.api.protocol.Session;
import org.spout.api.protocol.replayable.ReplayableException;
import org.spout.api.util.SyncedMapEvent;
import org.spout.api.util.SyncedMapRegistry;
import org.spout.api.util.SyncedStringMap;

import org.spout.engine.component.entity.SpoutPlayerNetworkComponent;
import org.spout.engine.protocol.builtin.codec.BlockUpdateCodec;
import org.spout.engine.protocol.builtin.codec.ChunkDataCodec;
import org.spout.engine.protocol.builtin.codec.ChunkDatatableCodec;
import org.spout.engine.protocol.builtin.codec.ClickRequestCodec;
import org.spout.engine.protocol.builtin.codec.ClickResponseCodec;
import org.spout.engine.protocol.builtin.codec.CommandCodec;
import org.spout.engine.protocol.builtin.codec.CuboidBlockUpdateCodec;
import org.spout.engine.protocol.builtin.codec.EntityDatatableCodec;
import org.spout.engine.protocol.builtin.codec.LoginCodec;
import org.spout.engine.protocol.builtin.codec.ReadyCodec;
import org.spout.engine.protocol.builtin.codec.SyncedMapCodec;
import org.spout.engine.protocol.builtin.codec.UpdateEntityCodec;
import org.spout.engine.protocol.builtin.codec.WorldChangeCodec;
import org.spout.engine.protocol.builtin.handler.BlockUpdateMessageHandler;
import org.spout.engine.protocol.builtin.handler.ChunkDataMessageHandler;
import org.spout.engine.protocol.builtin.handler.ChunkDatatableMessageHandler;
import org.spout.engine.protocol.builtin.handler.ClickRequestMessageHandler;
import org.spout.engine.protocol.builtin.handler.ClickResponseMessageHandler;
import org.spout.engine.protocol.builtin.handler.CommandMessageHandler;
import org.spout.engine.protocol.builtin.handler.CuboidBlockUpdateMessageHandler;
import org.spout.engine.protocol.builtin.handler.EntityDatatableMessageHandler;
import org.spout.engine.protocol.builtin.handler.LoginMessageHandler;
import org.spout.engine.protocol.builtin.handler.ReadyMessageHandler;
import org.spout.engine.protocol.builtin.handler.SyncedMapMessageHandler;
import org.spout.engine.protocol.builtin.handler.UpdateEntityMessageHandler;
import org.spout.engine.protocol.builtin.handler.WorldChangeMessageHandler;
import org.spout.engine.protocol.builtin.message.CommandMessage;
import org.spout.engine.protocol.builtin.message.LoginMessage;
import org.spout.engine.protocol.builtin.message.SyncedMapMessage;

/**
 * The protocol used in SpoutClient
 */
public class SpoutProtocol extends Protocol {
    public static final SpoutProtocol INSTANCE = new SpoutProtocol();
    public static final int PROTOCOL_VERSION = 0;
    public static final int DEFAULT_PORT = 13756;

    public SpoutProtocol() {
        super("Spout", DEFAULT_PORT, 256);
        registerPacket(SyncedMapCodec.class, new SyncedMapMessageHandler());
        registerPacket(LoginCodec.class, new LoginMessageHandler());
        registerPacket(ReadyCodec.class, new ReadyMessageHandler());
        registerPacket(BlockUpdateCodec.class, new BlockUpdateMessageHandler());
        registerPacket(ChunkDataCodec.class, new ChunkDataMessageHandler());
        registerPacket(ChunkDatatableCodec.class, new ChunkDatatableMessageHandler());
        registerPacket(ClickRequestCodec.class, new ClickRequestMessageHandler());
        registerPacket(ClickResponseCodec.class, new ClickResponseMessageHandler());
        registerPacket(CommandCodec.class, new CommandMessageHandler());
        registerPacket(CuboidBlockUpdateCodec.class, new CuboidBlockUpdateMessageHandler());
        registerPacket(EntityDatatableCodec.class, new EntityDatatableMessageHandler());
        registerPacket(UpdateEntityCodec.class, new UpdateEntityMessageHandler());
        registerPacket(WorldChangeCodec.class, new WorldChangeMessageHandler());
    }

    @Override
    public MessageCodec<?> readHeader(ByteBuf buf) {
        int id = buf.readUnsignedShort();
        //if (Spout.debugMode()) System.out.println("Reading codec header: " + id);
        int length = buf.readInt();
        MessageCodec<?> codec = getCodecLookupService().find(id);
        if (codec == null) {
            Spout.getLogger().warning("Could not find codec with id " + id);
            buf.skipBytes(length);
            return null;
        } else if (buf.readableBytes() < length) {
            throw new ReplayableException("There was not enough information received for a packet with codec id of "
                    + id + ". This may just be a frame issue.");
        } else {
            return codec;
        }
    }

    @Override
    public ByteBuf writeHeader(MessageCodec<?> codec, ByteBuf data) {
        ByteBuf buf = Unpooled.buffer(4);
        buf.writeShort(codec.getOpcode());
        //if (Spout.debugMode()) System.out.println("Writing codec header: " + codec.getOpcode());
        buf.writeInt(data.writerIndex());
        return buf;
    }

    @Override
    public Message getKickMessage(String message) {
        Command cmd = Spout.getCommandManager().getCommand("disconnect", false);
        if (cmd != null) {
            return getCommandMessage(cmd, new CommandArguments("disconnect", message.split(" ")));
        }
        return null;
    }

    @Override
    public Message getCommandMessage(Command command, CommandArguments args) {
        return new CommandMessage(command, args.toArray());
    }

    @Override
    public Message getIntroductionMessage(String playerName, InetSocketAddress addr) {
        return new LoginMessage(playerName, PROTOCOL_VERSION);
    }

    @Override
    public Class<? extends PlayerNetworkComponent> getServerNetworkComponent(ServerSession session) {
        return SpoutPlayerNetworkComponent.class;
    }

    @Override
    public Class<? extends PlayerNetworkComponent> getClientNetworkComponent(ClientSession session) {
        return SpoutPlayerNetworkComponent.class;
    }

    @Override
    public void initializeServerSession(final ServerSession session) {
        //TODO Ensure this is right, very important
        final UUID playerUUID = session.getPlayer().getUID();
        SyncedMapRegistry.getRegistrationMap().registerListener(new EventableListener<SyncedMapEvent>() {
            @Override
            public void onEvent(SyncedMapEvent event) {
                Entity e = Spout.getEngine().getEntity(playerUUID);
                if (e == null || !(e instanceof Player)) {
                    SyncedMapRegistry.getRegistrationMap().unregisterListener(this);
                    return;
                }
                ((Player) e).getNetwork().getSession().send(Session.SendType.FORCE,
                        new SyncedMapMessage(event.getAssociatedObject().getId(), SyncedMapEvent.Action.ADD,
                                event.getModifiedElements()));
            }
        });
        session.send(Session.SendType.FORCE, new SyncedMapMessage(SyncedMapRegistry.REGISTRATION_MAP,
                SyncedMapEvent.Action.SET, SyncedMapRegistry.getRegistrationMap().getItems()));
        for (SyncedStringMap map : SyncedMapRegistry.getAll()) {
            session.send(Session.SendType.FORCE,
                    new SyncedMapMessage(map.getId(), SyncedMapEvent.Action.SET, map.getItems()));
        }
    }

    @Override
    public void initializeClientSession(final ClientSession session) {
    }
}