/**
* 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.simulation;
import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.GZIPOutputStream;
import net.ctdp.rfdynhud.gamedata.CommentaryRequestInfo.CommentaryInfoUpdateListener;
import net.ctdp.rfdynhud.gamedata.DrivingAids.DrivingAidsUpdateListener;
import net.ctdp.rfdynhud.gamedata.GameEventsListener;
import net.ctdp.rfdynhud.gamedata.GraphicsInfo.GraphicsInfoUpdateListener;
import net.ctdp.rfdynhud.gamedata.LiveGameData;
import net.ctdp.rfdynhud.gamedata.ScoringInfo;
import net.ctdp.rfdynhud.gamedata.ScoringInfo.ScoringInfoUpdateListener;
import net.ctdp.rfdynhud.gamedata.TelemetryData.TelemetryDataUpdateListener;
import net.ctdp.rfdynhud.gamedata.WeatherInfo.WeatherInfoUpdateListener;
import net.ctdp.rfdynhud.gamedata.VehicleScoringInfo;
import net.ctdp.rfdynhud.plugins.GameEventsPlugin;
import net.ctdp.rfdynhud.render.WidgetsManager;
import net.ctdp.rfdynhud.render.WidgetsRenderListener;
import net.ctdp.rfdynhud.widgets.WidgetsConfiguration;
import org.jagatoo.logging.Log;
import org.jagatoo.util.streams.StreamUtils;
/**
* Insert class comment here.
*
* @author Marvin Froehlich (CTDP)
*/
public class SimulationRecorder implements GameEventsListener, GraphicsInfoUpdateListener, TelemetryDataUpdateListener, ScoringInfoUpdateListener, WeatherInfoUpdateListener, DrivingAidsUpdateListener, CommentaryInfoUpdateListener, WidgetsRenderListener
{
private final String logPrefix;
private final boolean onlyRecordInCockpit;
private final boolean resetWhenEnteringCockpit;
private final File file;
private DataOutputStream os = null;
private long t0 = -1L;
public void log( Object... message )
{
if ( ( message != null ) && ( message.length > 0 ) )
{
if ( ( message.length == 1 ) && ( message[0] instanceof Throwable ) )
{
Log.println( GameEventsPlugin.LOG_CHANNEL, message );
}
else
{
Object[] message2 = new Object[ message.length + 1 ];
message2[0] = logPrefix;
System.arraycopy( message, 0, message2, 1, message.length );
Log.println( GameEventsPlugin.LOG_CHANNEL, message2 );
}
}
}
public void wireListeners( LiveGameData gameData, WidgetsManager widgetsManager )
{
gameData.registerGameEventsListener( this );
gameData.registerDataUpdateListener( this );
gameData.getCommentaryRequestInfo().registerListener( this );
gameData.getGraphicsInfo().registerListener( this );
gameData.getTelemetryData().registerListener( this );
gameData.getScoringInfo().registerListener( this );
gameData.getWeatherInfo().registerListener( this );
gameData.getDrivingAids().registerListener( this );
widgetsManager.registerListener( this );
}
public void unwireListeners( LiveGameData gameData, WidgetsManager widgetsManager )
{
gameData.unregisterGameEventsListener( this );
gameData.unregisterDataUpdateListener( this );
gameData.getCommentaryRequestInfo().unregisterListener( this );
gameData.getGraphicsInfo().unregisterListener( this );
gameData.getTelemetryData().unregisterListener( this );
gameData.getScoringInfo().unregisterListener( this );
gameData.getWeatherInfo().unregisterListener( this );
gameData.getDrivingAids().unregisterListener( this );
widgetsManager.unregisterListener( this );
}
private void resetStream() throws IOException
{
StreamUtils.closeStream( os );
this.os = null;
this.os = new DataOutputStream( new BufferedOutputStream( new GZIPOutputStream( new FileOutputStream( file ) ) ) );
t0 = -1L;
}
private void writeTimecode() throws IOException
{
if ( t0 == -1L )
t0 = System.nanoTime() / 1000000L;
long t = ( System.nanoTime() / 1000000L ) - t0;
os.writeLong( t );
}
private boolean sessionStarted = false;
@Override
public void onSessionStarted( LiveGameData gameData, boolean isEditorMode )
{
if ( sessionStarted )
return;
//if ( onlyRecordInCockpit && !gameData.isInCockpit() )
// return;
try
{
resetStream();
os.write( SimulationConstants.ON_SESSION_STARTED );
writeTimecode();
}
catch ( IOException e )
{
log( e );
}
sessionStarted = true;
}
@Override
public void onVehiclePhysicsUpdated( LiveGameData gameData )
{
if ( onlyRecordInCockpit && !gameData.isInCockpit() )
return;
try
{
os.write( SimulationConstants.ON_PHYSICS );
writeTimecode();
}
catch ( IOException e )
{
log( e );
}
}
@Override
public void onVehicleSetupUpdated( LiveGameData gameData, boolean isEditorMode )
{
if ( onlyRecordInCockpit && !gameData.isInCockpit() )
return;
try
{
os.write( SimulationConstants.ON_SETUP );
writeTimecode();
}
catch ( IOException e )
{
log( e );
}
}
@Override
public void onTrackChanged( String trackname, LiveGameData gameData, boolean isEditorMode )
{
if ( onlyRecordInCockpit && !gameData.isInCockpit() )
return;
try
{
os.write( SimulationConstants.ON_TRACK );
writeTimecode();
os.writeShort( trackname.length() );
os.writeChars( trackname );
}
catch ( IOException e )
{
log( e );
}
}
@Override
public void onCockpitEntered( LiveGameData gameData, boolean isEditorMode )
{
try
{
if ( resetWhenEnteringCockpit )
resetStream();
os.write( SimulationConstants.ON_COCKPIT_ENTERED );
writeTimecode();
}
catch ( IOException e )
{
log( e );
}
}
@Override
public void onGamePauseStateChanged( LiveGameData gameData, boolean isEditorMode, boolean isPaused )
{
}
@Override
public void onCockpitExited( LiveGameData gameData, boolean isEditorMode )
{
try
{
os.write( SimulationConstants.ON_COCKPIT_EXITED );
writeTimecode();
}
catch ( IOException e )
{
log( e );
}
}
@Override
public void onGarageEntered( LiveGameData gameData, boolean isEditorMode )
{
if ( onlyRecordInCockpit && !gameData.isInCockpit() )
return;
try
{
os.write( SimulationConstants.ON_GARAGE_ENTERED );
writeTimecode();
}
catch ( IOException e )
{
log( e );
}
}
@Override
public void onGarageExited( LiveGameData gameData, boolean isEditorMode )
{
if ( onlyRecordInCockpit && !gameData.isInCockpit() )
return;
try
{
os.write( SimulationConstants.ON_GARAGE_EXITED );
writeTimecode();
}
catch ( IOException e )
{
log( e );
}
}
@Override
public void onPitsEntered( LiveGameData gameData, boolean isEditorMode )
{
if ( onlyRecordInCockpit && !gameData.isInCockpit() )
return;
try
{
os.write( SimulationConstants.ON_PITS_ENTERED );
writeTimecode();
}
catch ( IOException e )
{
log( e );
}
}
@Override
public void onPitsExited( LiveGameData gameData, boolean isEditorMode )
{
if ( onlyRecordInCockpit && !gameData.isInCockpit() )
return;
try
{
os.write( SimulationConstants.ON_PITS_EXITED );
writeTimecode();
}
catch ( IOException e )
{
log( e );
}
}
private static final int getVSIIndex( VehicleScoringInfo vsi, ScoringInfo scoringInfo )
{
for ( int i = 0; i < scoringInfo.getNumVehicles(); i++ )
{
if ( scoringInfo.getVehicleScoringInfo( i ) == vsi )
{
return ( i );
}
}
return ( -1 );
}
@Override
public void onVehicleControlChanged( VehicleScoringInfo viewedVSI, LiveGameData gameData, boolean isEditorMode )
{
/*
if ( onlyRecordInCockpit && !gameData.isInCockpit() )
return;
try
{
os.write( SimulationConstants.ON_CONTROL );
writeTimecode();
os.writeShort( getVSIIndex( viewedVSI, gameData.getScoringInfo() ) );
}
catch ( IOException e )
{
log( e );
}
*/
}
@Override
public void onLapStarted( VehicleScoringInfo vsi, LiveGameData gameData, boolean isEditorMode )
{
if ( onlyRecordInCockpit && !gameData.isInCockpit() )
return;
try
{
os.write( SimulationConstants.ON_LAP );
writeTimecode();
os.writeShort( getVSIIndex( vsi, gameData.getScoringInfo() ) );
}
catch ( IOException e )
{
log( e );
}
}
@Override
public void onDrivingAidsUpdated( LiveGameData gameData, boolean isEditorMode )
{
if ( onlyRecordInCockpit && !gameData.isInCockpit() )
return;
try
{
os.write( SimulationConstants.ON_DATA_UPDATED_DRIVING_AIDS );
writeTimecode();
gameData.getDrivingAids().writeToStream( os );
}
catch ( IOException e )
{
log( e );
}
}
@Override
public void onGraphicsInfoUpdated( LiveGameData gameData, boolean isEditorMode )
{
if ( onlyRecordInCockpit && !gameData.isInCockpit() )
return;
try
{
os.write( SimulationConstants.ON_DATA_UPDATED_GRAPHICS );
writeTimecode();
gameData.getGraphicsInfo().writeToStream( os );
}
catch ( IOException e )
{
log( e );
}
}
@Override
public void onTelemetryDataUpdated( LiveGameData gameData, boolean isEditorMode )
{
if ( onlyRecordInCockpit && !gameData.isInCockpit() )
return;
try
{
os.write( SimulationConstants.ON_DATA_UPDATED_TELEMETRY );
writeTimecode();
gameData.getTelemetryData().writeToStream( os );
}
catch ( IOException e )
{
log( e );
}
}
@Override
public void onPlayerJoined( LiveGameData gameData, VehicleScoringInfo joinedVSI, boolean rejoined )
{
}
@Override
public void onPlayerLeft( LiveGameData gameData, Integer vsiID )
{
}
@Override
public void onScoringInfoUpdated( LiveGameData gameData, boolean isEditorMode )
{
if ( onlyRecordInCockpit && !gameData.isInCockpit() )
return;
if ( gameData.getScoringInfo().getNumVehicles() == 0 )
return;
try
{
os.write( SimulationConstants.ON_DATA_UPDATED_SCORING );
writeTimecode();
os.writeInt( gameData.getScoringInfo().getNumVehicles() );
gameData.getScoringInfo().writeToStream( os );
}
catch ( IOException e )
{
log( e );
}
}
@Override
public void onWeatherInfoUpdated( LiveGameData gameData, boolean isEditorMode )
{
if ( onlyRecordInCockpit && !gameData.isInCockpit() )
return;
try
{
os.write( SimulationConstants.ON_DATA_UPDATED_WEATHER );
writeTimecode();
gameData.getWeatherInfo().writeToStream( os );
}
catch ( IOException e )
{
log( e );
}
}
@Override
public void onCommentaryInfoUpdated( LiveGameData gameData, boolean isEditorMode )
{
if ( onlyRecordInCockpit && !gameData.isInCockpit() )
return;
try
{
os.write( SimulationConstants.ON_DATA_UPDATED_COMMENTARY );
writeTimecode();
gameData.getCommentaryRequestInfo().writeToStream( os );
}
catch ( IOException e )
{
log( e );
}
}
@Override
public void onViewportChanged( LiveGameData gameData, int viewportX, int viewportY, int viewportWidth, int viewportHeight )
{
/*
if ( onlyRecordInCockpit && !gameData.isInRealtimeMode() )
return;
try
{
os.write( SimulationConstants.ON_VIEWPORT_CHANGED );
writeTimecode();
os.writeShort( viewportX );
os.writeShort( viewportY );
os.writeShort( viewportWidth );
os.writeShort( viewportHeight );
}
catch ( IOException e )
{
log( e );
}
*/
}
@Override
public void beforeWidgetsConfigurationCleared( LiveGameData gameData, WidgetsConfiguration widgetsConfig )
{
}
@Override
public void afterWidgetsConfigurationLoaded( LiveGameData gameData, WidgetsConfiguration widgetsConfig )
{
}
@Override
public void beforeWidgetsAreRendered( LiveGameData gameData, WidgetsConfiguration widgetsConfig, long sessionTime, long frameCounter )
{
if ( onlyRecordInCockpit && !gameData.isInCockpit() )
return;
try
{
os.write( SimulationConstants.BEFORE_RENDERED );
writeTimecode();
}
catch ( IOException e )
{
log( e );
}
}
public void close()
{
StreamUtils.closeStream( os );
}
public SimulationRecorder( File file, boolean onlyRecordInCockpit, boolean resetWhenEnteringCockpit, String logPrefix ) throws IOException
{
this.logPrefix = logPrefix;
this.onlyRecordInCockpit = onlyRecordInCockpit;
this.resetWhenEnteringCockpit = resetWhenEnteringCockpit;
this.file = file;
resetStream();
}
public SimulationRecorder( File file, String logPrefix ) throws IOException
{
this( file, true, false, logPrefix );
}
}