/** * Copyright (C) 2009-2014 Cars and Tracks Development Project (CTDP). * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package net.ctdp.rfdynhud.plugins.datasender; import java.io.DataInputStream; import java.io.IOException; import net.ctdp.rfdynhud.gamedata.SessionType; import net.ctdp.rfdynhud.gamedata.VehicleControl; /** * Connects to the editor via a socket and sends/receives data (client side). * * @author Marvin Froehlich (CTDP) */ public abstract class AbstractClientCommunicator extends AbstractCommunicator { protected abstract boolean isRunning(); protected abstract boolean checkServerName( byte[] serverName ); /** * Attempts to query a password hash. * * @return the password hash or <code>null</code>. */ protected abstract byte[] onPasswordRequested(); protected abstract void onConnectionEsteblished( boolean isInCockpit ); protected abstract void onConnectionRefused( String message ); protected abstract void onSessionStarted( SessionType sessionType ); protected abstract void onCockpitEntered(); protected abstract void onCockpitExited(); protected abstract void onPitsEntered(); protected abstract void onPitsExited(); protected abstract void onGarageEntered(); protected abstract void onGarageExited(); protected abstract void onVehicleControlChanged( int driverID, VehicleControl control ); protected abstract void onLapStarted( int driverID, short lap ); protected abstract void onGamePauseStateChanged( boolean paused ); protected abstract void onPlayerJoined( String name, int id, short place ); private void readJoinedDriver( DataInputStream in ) throws IOException { int id = in.readInt(); short place = in.readShort(); int nameLength = in.readByte() & 0xFF; byte[] name = new byte[ nameLength ]; in.readFully( name ); onPlayerJoined( new String( name ), id, place ); } protected abstract void onPlayerLeft( int id ); protected abstract void onSessionTimeReceived( long time ); protected abstract boolean readDatagram( final short code, DataInputStream in ) throws IOException; protected final boolean readInput( DataInputStream in ) throws IOException { boolean running = this.isRunning(); short code = in.readShort(); //debug( "Received command code: ", code ); switch ( code ) { case SERVER_NAME: // FIXME: This may block! byte[] serverName = new byte[ 32 ]; in.readFully( serverName ); if ( !checkServerName( serverName ) ) close(); else writeSimpleCommandImpl( CONNECTION_REQUEST2 ); break; case REQUEST_PASSWORD: case PASSWORD_MISMATCH: byte[] passwordHash = onPasswordRequested(); if ( passwordHash == null ) { close(); return ( running ); } startCommandImpl( PASSWORD_HASH ); writeImpl( passwordHash ); endCommandImpl(); break; case CONNECTION_ESTEBLISHED: onConnectionEsteblished( in.readBoolean() ); break; case CONNECTION_REFUSED: onConnectionRefused( "Connection refused" ); close(); break; case CONNECTION_CLOSED: close(); running = false; break; case ON_SESSION_STARTED: SessionType sessionType = SessionType.values()[in.readByte() & 0xFF]; onSessionStarted( sessionType ); break; case ON_PITS_ENTERED: onPitsEntered(); break; case ON_PITS_EXITED: onPitsExited(); break; case ON_GARAGE_ENTERED: onGarageEntered(); break; case ON_GARAGE_EXITED: onGarageExited(); break; case ON_VEHICLE_CONTROL_CHANGED: int driverID1 = in.readInt(); VehicleControl control = VehicleControl.values()[in.readByte() & 0xFF]; onVehicleControlChanged( driverID1, control ); break; case ON_LAP_STARTED: int driverID2 = in.readInt(); short lap = in.readShort(); onLapStarted( driverID2, lap ); break; case ON_COCKPIT_ENTERED: onCockpitEntered(); break; case ON_COCKPIT_EXITED: onCockpitExited(); break; case ON_GAME_PAUSE_STATE_CHANGED: onGamePauseStateChanged( in.readBoolean() ); break; case ON_PLAYER_JOINED: readJoinedDriver( in ); break; case ON_PLAYER_LEFT: onPlayerLeft( in.readInt() ); break; case SESSION_TIME: onSessionTimeReceived( in.readLong() ); break; default: if ( !readDatagram( code, in ) ) log( "WARNING: Unknown command code read: " + code ); } return ( running ); } public abstract void connect( String connectionString ); protected abstract void close( boolean restart ); public final void close() { close( false ); } protected abstract void onConnectionClosed(); public AbstractClientCommunicator() { } }