package org.reunionemu.jreunion.server; import java.nio.channels.SocketChannel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.reunionemu.jreunion.events.Event; import org.reunionemu.jreunion.events.EventDispatcher; import org.reunionemu.jreunion.events.EventListener; import org.reunionemu.jreunion.events.client.ClientDisconnectEvent; import org.reunionemu.jreunion.events.client.ClientEvent; import org.reunionemu.jreunion.events.client.ClientReceiveEvent; import org.reunionemu.jreunion.events.client.ClientSendEvent; import org.reunionemu.jreunion.events.network.NetworkDataEvent; import org.reunionemu.jreunion.events.network.NetworkDisconnectEvent; import org.reunionemu.jreunion.events.network.NetworkEvent; import org.reunionemu.jreunion.events.network.NetworkSendEvent; import org.reunionemu.jreunion.game.Player; import org.reunionemu.jreunion.protocol.OtherProtocol; import org.reunionemu.jreunion.protocol.Protocol; /** * @author Aidamina * @license http://reunion.googlecode.com/svn/trunk/license.txt */ public class Client extends EventDispatcher implements EventListener, Sendable { public StringBuffer getInputBuffer() { return inputBuffer; } public StringBuffer getOutputBuffer() { return outputBuffer; } private int version; public int getVersion() { return version; } public void setVersion(int version) { this.version = version; } private String username; private String password; private Protocol protocol; private SocketChannel socketChannel; private long accountId; private State state; private Player player; private StringBuffer inputBuffer = new StringBuffer(); private StringBuffer outputBuffer = new StringBuffer(); public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public SocketChannel getSocketChannel() { return socketChannel; } public Protocol getProtocol(){ return this.protocol; } private World world; public World getWorld() { return world; } private void setWorld(World world) { this.world = world; } private void setSocketChannel(SocketChannel socketChannel) { this.socketChannel = socketChannel; } public long getAccountId() { return accountId; } public void setAccountId(long accountId) { this.accountId = accountId; } public Player getPlayer() { return player; } public void setPlayer(Player player) { this.player = player; } public LoginType loginType; public LoginType getLoginType() { return loginType; } public void setLoginType(LoginType loginType) { this.loginType = loginType; } public Client(World world, SocketChannel socketChannel) { super(); setWorld(world); accountId = -1; state = State.DISCONNECTED; setSocketChannel(socketChannel); world.addEventListener(ClientSendEvent.class, this, new ClientEvent.ClientFilter(this)); Server.getInstance().getNetwork().addEventListener(NetworkDisconnectEvent.class, this, new NetworkEvent.NetworkFilter(socketChannel)); } public State getState() { return state; } public void sendWrongVersion(int clientVersion) { String requiredVersion = Integer.toString((int)getWorld().getServerSetings().getDefaultVersion()); String message = "Wrong clientversion: current version " + clientVersion + " required version " + requiredVersion; sendPacket(PacketFactory.Type.FAIL,message); } public void sendData(String data) { //synchronized(this){ this.outputBuffer.append(data); if(!data.endsWith("\n")){ this.outputBuffer.append("\n"); } //} this.fireEvent(NetworkSendEvent.class, this.getSocketChannel()); } public void sendPacket(PacketFactory.Type packetType, Object ...args){ sendData(PacketFactory.createPacket(packetType, args)); } public void setState(State state) { this.state = state; } public String toString(){ StringBuffer buffer = new StringBuffer(); buffer.append("{"); if(player!=null) { buffer.append("player: "); buffer.append(player); buffer.append(Server.logger.isDebugEnabled() ? ", " : ""); } if(getState() != State.INGAME || Server.logger.isDebugEnabled()){ if (socketChannel != null) { buffer.append("socket: "); // buffer.append(socketChannel); buffer.append("local=" + this.getSocketChannel().socket() .getLocalSocketAddress() + " remote=" + this.getSocketChannel().socket() .getRemoteSocketAddress()); buffer.append(", "); } if (this.getProtocol() != null) { buffer.append("encryption level: "); buffer.append(getProtocol() instanceof OtherProtocol ? ((OtherProtocol) getProtocol()) .getEncryptionLevel() : "Default"); buffer.append(", "); } buffer.append("state: "); buffer.append(getState()); } buffer.append("}"); return buffer.toString(); } public void disconnect() { Server.getInstance().getNetwork().disconnect(this.getSocketChannel()); } public static enum State { DISCONNECTED, ACCEPTED, GOT_VERSION , GOT_LOGIN , GOT_USERNAME, GOT_PASSWORD, GOT_AUTH, CHAR_LIST, LOADING, PORTING, LOADED, INGAME; } public enum LoginType{ PLAY, LOGIN } public byte[] flush(){ StringBuffer outputBuffer = this.getOutputBuffer(); if(outputBuffer.length()==0) return null; String packetData = outputBuffer.toString(); outputBuffer.setLength(0); LoggerFactory.getLogger(Network.class).debug("Sending to {}:{}", this, packetData); return protocol.encryptServer(packetData); } @Override public void handleEvent(Event event) { if(event instanceof NetworkEvent){ NetworkEvent networkEvent = (NetworkEvent) event; if(event instanceof NetworkDataEvent) { //synchronized(this){ NetworkDataEvent networkDataEvent = (NetworkDataEvent) networkEvent; byte [] data = networkDataEvent.getData(); if(protocol==null){ protocol = Protocol.find(this, data); if(protocol==null) { this.disconnect(); throw new RuntimeException("Unknown Protocol");//TODO: Proper handling } LoggerFactory.getLogger(Client.class).info(this + " protocol discovered: "+protocol); } String decryptedData = protocol.decryptServer(data); LoggerFactory.getLogger(Client.class).debug("{}: \n {}", this, decryptedData); this.inputBuffer.append(decryptedData); if(!decryptedData.endsWith("\n")) inputBuffer.append("\n"); fireEvent(ClientReceiveEvent.class, this); //} } if(event instanceof NetworkDisconnectEvent){ //LoggerFactory.getLogger(Client.class).debug(event); fireEvent(ClientDisconnectEvent.class, this); } } } }