/** * 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.gamedata; import java.io.File; import java.util.Iterator; import net.ctdp.rfdynhud.RFDynHUD; import net.ctdp.rfdynhud.editor.EditorPresets; import net.ctdp.rfdynhud.editor.__EDPrivilegedAccess; import net.ctdp.rfdynhud.input.InputMapping; import net.ctdp.rfdynhud.properties.AbstractPropertiesKeeper; import net.ctdp.rfdynhud.render.WidgetsDrawingManager; import net.ctdp.rfdynhud.render.WidgetsManager; import net.ctdp.rfdynhud.render.__RenderPrivilegedAccess; import net.ctdp.rfdynhud.util.ConfigurationLoader; import net.ctdp.rfdynhud.util.RFDHLog; import net.ctdp.rfdynhud.util.ThreeLetterCodeManager; import net.ctdp.rfdynhud.values.RelativePositioning; import net.ctdp.rfdynhud.widgets.WidgetsConfiguration; import net.ctdp.rfdynhud.widgets.WidgetsConfiguration.ConfigurationLoadListener; import net.ctdp.rfdynhud.widgets.__WCPrivilegedAccess; import org.jagatoo.util.Tools; /** * The events manager receives events from rFactor and modifies state-flags appropriately. * * @author Marvin Froehlich (CTDP) */ public abstract class GameEventsManager implements ConfigurationLoadListener { protected final RFDynHUD rfDynHUD; protected final WidgetsDrawingManager widgetsManager; protected final LiveGameData gameData; protected boolean running = false; protected boolean sessionRunning = false; protected boolean isComingOutOfGarage = true; protected boolean sessionJustStarted = false; protected Boolean currentSessionIsRace = null; protected boolean waitingForRender = false; protected boolean waitingForGraphics = false; protected boolean waitingForTelemetry = false; protected boolean waitingForScoring = false; protected boolean waitingForWeather = false; protected boolean waitingForGarageStartLocation = false; protected boolean waitingForSetup = false; protected long setupReloadTryTime = -1L; protected boolean waitingForData = false; protected Boolean cockpitLeftInRaceSession = null; protected boolean needsOnVehicleControlChangedEvent = false; protected boolean isInGarage = true; protected boolean isInPits = true; private int lastViewedVSIId = -1; private VehicleControl lastControl = null; protected boolean physicsLoadedOnce = false; private String lastTrackname = null; protected final GameEventsDispatcher eventsDispatcher; private final WidgetsManager renderListenersManager; private Iterator<File> configurationCandidatesIterator = null; protected final ConfigurationLoader loader = new ConfigurationLoader( this ); private boolean texturesRequested = false; public final LiveGameData getGameData() { return ( gameData ); } protected final WidgetsDrawingManager getWidgetsManager() { return ( widgetsManager ); } protected final GameEventsDispatcher getEventsDispatcher() { return ( eventsDispatcher ); } public final boolean hasWaitingWidgets() { return ( eventsDispatcher.hasWaitingWidgets() ); } public void setConfigurationCandidatesIterator( Iterator<File> configurationCandidatesIterator ) { this.configurationCandidatesIterator = configurationCandidatesIterator; } public final Iterator<File> getConfigurationCandidatesIterator() { return ( configurationCandidatesIterator ); } public final ConfigurationLoader getConfigurationLoader() { return ( loader ); } private void validateInputBindings() { if ( ( rfDynHUD == null ) || ( rfDynHUD.getInputMappings() == null ) ) return; if ( !gameData.isInCockpit() ) return; if ( !widgetsManager.getWidgetsConfiguration().isValid() ) return; if ( !gameData.getProfileInfo().isValid() ) return; String[] warning = gameData.getProfileInfo().validateInputBindings( rfDynHUD.getInputMappings() ); if ( warning != null ) { net.ctdp.rfdynhud.widgets.internal.InternalWidget internalWidget = new net.ctdp.rfdynhud.widgets.internal.InternalWidget(); internalWidget.setMessage( warning ); __WCPrivilegedAccess.addWidget( widgetsManager.getWidgetsConfiguration(), internalWidget, true, gameData ); internalWidget.getSize().setEffectiveSize( 600, 200 ); internalWidget.getPosition().setEffectivePosition( RelativePositioning.TOP_CENTER, ( widgetsManager.getWidgetsConfiguration().getGameResolution().getViewportWidth() - internalWidget.getEffectiveWidth() ) / 2, ( widgetsManager.getWidgetsConfiguration().getGameResolution().getViewportHeight() - internalWidget.getEffectiveHeight() ) / 2 ); AbstractPropertiesKeeper.attachKeeper( internalWidget, true ); __WCPrivilegedAccess.sortWidgets( widgetsManager.getWidgetsConfiguration() ); } } /** * {@inheritDoc} */ @Override public void beforeWidgetsConfigurationCleared( WidgetsConfiguration widgetsConfig, LiveGameData GameData, boolean isEditorMode ) { /* int n = widgetsConfig.getNumWidgets(); for ( int i = 0; i < n; i++ ) widgetsConfig.getWidget( i ).clearRegion( false, ( (WidgetsDrawingManager)widgetsConfig ).getMainTexture( i ) ); */ eventsDispatcher.fireBeforeWidgetsConfigurationCleared( renderListenersManager, gameData, widgetsConfig ); } /** * {@inheritDoc} */ @Override public void afterWidgetsConfigurationLoaded( WidgetsConfiguration widgetsConfig, LiveGameData GameData, boolean isEditorMode ) { needsOnVehicleControlChangedEvent = true; texturesRequested = true; validateInputBindings(); eventsDispatcher.fireAfterWidgetsConfigurationLoaded( renderListenersManager, gameData, widgetsConfig ); widgetsManager.collectTextures( gameData, isEditorMode ); //if ( usePlayer ) widgetsManager.clearCompleteTexture(); //System.gc(); Runtime runtime = Runtime.getRuntime(); RFDHLog.debug( "INFO: Free heap space memory: " + Tools.formatBytes( runtime.freeMemory() ) + " / " + Tools.formatBytes( runtime.totalMemory() ) + " / " + Tools.formatBytes( runtime.maxMemory() ) ); } /** * This method must be called when the game started up. * * @param userObject custom user object from native side (could be an instance of {@link EditorPresets}) */ public void onStartup( Object userObject ) { this.running = true; eventsDispatcher.fireOnStarted( this, gameData, userObject instanceof EditorPresets, renderListenersManager ); } /** * This method must be called when the game shuts down. * * @param userObject custom user object from native side (could be an instance of {@link EditorPresets}) */ public void onShutdown( Object userObject) { this.running = false; eventsDispatcher.fireOnShutdown( this, gameData, userObject instanceof EditorPresets, renderListenersManager ); } /** * Returns whether the game has been started up and not yet been shut down. * * @return whether the game has been started up and not yet been shut down. */ public final boolean isRunning() { return ( running ); } /** * * @param mapping * @param state * @param modifierMask * @param when * @param isEditorMode */ public void fireOnInputStateChanged( InputMapping mapping, boolean state, int modifierMask, long when, boolean isEditorMode ) { eventsDispatcher.fireOnInputStateChanged( mapping, state, modifierMask, when, gameData, isEditorMode ); } private void reloadVehicleInfo() { try { gameData.getVehicleInfo().reload( gameData ); } catch ( Throwable t ) { RFDHLog.exception( t ); } } private void reloadPhysics( boolean onlyOnce, boolean isEditorMode ) { if ( !onlyOnce || !physicsLoadedOnce ) { __GDPrivilegedAccess.loadVehiclePhysics( gameData ); physicsLoadedOnce = true; eventsDispatcher.fireOnVehiclePhysicsUpdated( gameData, isEditorMode ); } } private boolean reloadSetup() { boolean result = false; if ( gameData.getGameDataObjectsFactory().loadVehicleSetupIfChanged( gameData ) ) { result = true; } __GDPrivilegedAccess.setEngineBoostMapping( gameData.getSetup().getEngine().getBoostMapping(), gameData.getTelemetryData() ); return ( result ); } /** * * @param force force reload ignoring, whether it is already in action? */ protected abstract void reloadConfigImpl( boolean force ); /** * * @param force force reload ignoring, whether it is already in action? * @return 0 for no HUD to be drawn, 1 for HUD drawn, 2 for HUD drawn and texture re-requested. */ public final byte reloadConfigAndSetupTexture( boolean force ) { byte result = 1; try { if ( !__GDPrivilegedAccess.simulationMode && ( __EDPrivilegedAccess.editorClassLoader == null ) ) reloadConfigImpl( force ); if ( texturesRequested ) { result = 2; texturesRequested = false; } } catch ( Throwable t ) { RFDHLog.exception( t ); __WCPrivilegedAccess.setValid( widgetsManager.getWidgetsConfiguration(), false ); result = 0; } return ( result ); } /** * * @param userObject custom user object from native side (could be an instance of {@link EditorPresets}) * @param timestamp event timestamp in nano seconds */ protected void onSessionStartedImpl( Object userObject, long timestamp ) { ThreeLetterCodeManager.updateThreeLetterCodes( gameData.getFileSystem().getConfigFolder(), gameData.getScoringInfo().getThreeLetterCodeGenerator() ); __GDPrivilegedAccess.updateInfo( gameData ); if ( gameData.getProfileInfo().isValid() ) { boolean isEditorMode = ( userObject instanceof EditorPresets ); boolean loadPhysicsAndSetup = gameData.getSetup().checkLoadPhysicsAndSetupOnSessionStarted( gameData, isEditorMode ); reloadVehicleInfo(); if ( loadPhysicsAndSetup ) { reloadPhysics( true, isEditorMode ); reloadSetup(); } __GDPrivilegedAccess.onSessionStarted( gameData, timestamp, isEditorMode ); // We cannot load the configuration here, because we don't know, which one to load (no scoring info). } } /** * This method must be called when a session has been started. * Note: LiveGameData must have been updated before. * * @param userObject custom user object from native side (could be an instance of {@link EditorPresets}) * * @return 0 for no HUD to be drawn, 1 for HUD drawn, 2 for HUD drawn and texture re-requested. */ public final byte onSessionStarted( Object userObject ) { RFDHLog.profile( "[PROFILE]: onSessionStarted()" ); long now = System.nanoTime(); boolean isEditorMode = ( userObject instanceof EditorPresets ); //if ( currentSessionIsRace == Boolean.TRUE ) if ( sessionRunning && !isEditorMode && !__GDPrivilegedAccess.simulationMode ) { RFDHLog.debug( "INFO: Got a call to StartSession() in already started session. Looks like an rFactor bug. Ignoring this call." ); return ( ( rfDynHUD == null ) ? (byte)2 : ( rfDynHUD.isInRenderMode() ? (byte)2 : (byte)0 ) ); } this.sessionRunning = true; this.isComingOutOfGarage = true; this.isInGarage = true; this.waitingForGraphics = !isEditorMode; this.waitingForTelemetry = !isEditorMode; this.waitingForScoring = !isEditorMode; this.waitingForWeather = !isEditorMode; this.waitingForGarageStartLocation = !isEditorMode; this.waitingForSetup = false; this.setupReloadTryTime = -1L; this.waitingForData = !isEditorMode; this.sessionJustStarted = true; this.currentSessionIsRace = null; this.lastViewedVSIId = -1; this.lastControl = null; if ( gameData.isInCockpit() ) this.cockpitLeftInRaceSession = false; byte result = 0; if ( texturesRequested ) { result = 2; texturesRequested = false; } try { onSessionStartedImpl( userObject, now ); } catch ( Throwable t ) { RFDHLog.exception( t ); } if ( rfDynHUD != null ) rfDynHUD.setRenderMode( result != 0 ); //Logger.log( ">>> /onSessionStarted(), result: " + result ); return ( result ); } /** * * @param userObject custom user object from native side (could be an instance of {@link EditorPresets}) * @param timestamp event timestamp in nano seconds */ protected void onSessionEndedImpl( Object userObject, long timestamp ) { if ( gameData.getProfileInfo().isValid() ) { __GDPrivilegedAccess.onSessionEnded( gameData, timestamp ); } } /** * * @param userObject custom user object from native side (could be an instance of {@link EditorPresets}) */ public void onSessionEnded( Object userObject ) { RFDHLog.profile( "[PROFILE]: onSessionEnded()" ); long now = System.nanoTime(); if ( rfDynHUD != null ) rfDynHUD.setRenderMode( false ); this.waitingForRender = false; this.waitingForGraphics = false; this.waitingForTelemetry = false; this.waitingForScoring = false; this.waitingForWeather = false; this.waitingForGarageStartLocation = false; this.waitingForSetup = false; this.setupReloadTryTime = -1L; this.waitingForData = false; //this.sessionStartTime = -1f; this.sessionRunning = false; this.currentSessionIsRace = null; try { onSessionEndedImpl( userObject, now ); } catch ( Throwable t ) { RFDHLog.exception( t ); } if ( !( userObject instanceof EditorPresets ) && !__GDPrivilegedAccess.simulationMode ) __WCPrivilegedAccess.setValid( widgetsManager.getWidgetsConfiguration(), false ); } /** * Returns whether the current session is running. * * @return whether the current session is running. */ public final boolean isSessionRunning() { return ( sessionRunning ); } /** * @param userObject custom user object from native side (could be an instance of {@link EditorPresets}) * @param timestamp event timestamp in nano seconds */ protected void onCockpitEnteredImpl( Object userObject, long timestamp ) { ThreeLetterCodeManager.updateThreeLetterCodes( gameData.getFileSystem().getConfigFolder(), gameData.getScoringInfo().getThreeLetterCodeGenerator() ); __GDPrivilegedAccess.updateInfo( gameData ); if ( gameData.getProfileInfo().isValid() ) { boolean isEditorMode = ( userObject instanceof EditorPresets ); __GDPrivilegedAccess.setInCockpit( true, gameData, timestamp, isEditorMode ); if ( !isEditorMode ) { reloadPhysics( false, isEditorMode ); if ( reloadSetup() ) { waitingForSetup = false; eventsDispatcher.fireOnVehicleSetupUpdated( gameData, isEditorMode ); } } widgetsManager.onCockpitEntered( gameData ); eventsDispatcher.fireOnCockpitEntered( gameData, isEditorMode ); } } /** * This method must be called when the cockpit has been entered (the user clicked on "Drive"). * * @param userObject custom user object from native side (could be an instance of {@link EditorPresets}) * * @return 0 for no HUD to be drawn, 1 for HUD drawn, 2 for HUD drawn and texture re-requested. */ public final byte onCockpitEntered( Object userObject ) { RFDHLog.profile( "[PROFILE]: onCockpitEntered()" ); byte result = 0; long now = System.nanoTime(); boolean isEditorMode = ( userObject instanceof EditorPresets ); if ( texturesRequested ) { result = 2; texturesRequested = false; } this.isComingOutOfGarage = true; this.lastViewedVSIId = -1; this.lastControl = null; this.waitingForRender = waitingForRender || !isEditorMode; this.waitingForGraphics = waitingForGraphics || !isEditorMode; this.waitingForTelemetry = waitingForTelemetry || ( !isEditorMode && ( currentSessionIsRace != Boolean.FALSE ) ); this.waitingForScoring = waitingForScoring || ( !isEditorMode && ( currentSessionIsRace != Boolean.FALSE ) ); this.waitingForWeather = waitingForWeather || ( !isEditorMode && ( currentSessionIsRace != Boolean.FALSE ) ); this.waitingForGarageStartLocation = true; this.waitingForSetup = false; //waitingForSetup || ( currentSessionIsRace != Boolean.FALSE ); //!isEditorMode; this.setupReloadTryTime = now + 5000000000L; this.waitingForData = !isEditorMode; this.needsOnVehicleControlChangedEvent = true; if ( !isEditorMode ) { RFDHLog.printlnEx( "Entered cockpit." ); } try { onCockpitEnteredImpl( userObject, now ); } catch ( Throwable t ) { RFDHLog.exception( t ); } if ( rfDynHUD != null ) rfDynHUD.setRenderMode( result != 0 ); //Logger.log( ">>> /onCockpitEntered(), result: " + result ); return ( result ); } /** * This method must be called when the user exited realtime mode (pressed ESCAPE in the cockpit). * * @param userObject custom user object from native side (could be an instance of {@link EditorPresets}) * @param timestamp event timestamp in nano seconds */ protected void onCockpitExitedImpl( Object userObject, long timestamp ) { if ( gameData.getProfileInfo().isValid() ) { __GDPrivilegedAccess.setInCockpit( false, gameData, timestamp, userObject instanceof EditorPresets ); eventsDispatcher.fireOnCockpitExited( gameData, userObject instanceof EditorPresets ); } } /** * This method must be called when the user exited the cockpit (pressed ESCAPE in the cockpit). * * @param userObject custom user object from native side (could be an instance of {@link EditorPresets}) * * @return 0 for no HUD to be drawn, 1 for HUD drawn, 2 for HUD drawn and texture re-requested. */ public final byte onCockpitExited( Object userObject ) { RFDHLog.profile( "[PROFILE]: onCockpitExited()" ); RFDHLog.printlnEx( "Exited cockpit." ); long now = System.nanoTime(); //realtimeStartTime = -1f; this.isComingOutOfGarage = true; this.isInPits = true; this.isInGarage = true; this.waitingForRender = true; //this.waitingForGraphics = true; this.waitingForData = true; this.needsOnVehicleControlChangedEvent = true; if ( gameData.getScoringInfo().getSessionType().isRace() ) cockpitLeftInRaceSession = true; try { onCockpitExitedImpl( userObject, now ); } catch ( Throwable t ) { RFDHLog.exception( t ); } //byte result = reloadConfigAndSetupTexture( false ); __WCPrivilegedAccess.setValid( widgetsManager.getWidgetsConfiguration(), false ); waitingForData = true; if ( rfDynHUD != null ) rfDynHUD.setRenderMode( false ); texturesRequested = false; return ( 0 ); } /** * Checks, whether re-entering the garage and showing the garage WidgetConfiguration is supported. * * @return whether re-entering the garage and showing the garage WidgetConfiguration is supported. */ protected boolean isReenteringGarageSupported() { return ( true ); } /** * Checks, whether the player's vehicle is in the garage. * * @return whether the player's vehicle is in the garage. */ protected abstract boolean checkIsInGarage(); /** * * @param result 0 for no HUD to be drawn, 1 for HUD drawn, 2 for HUD drawn and texture re-requested * @param isEditorMode * * @return the result back again. */ protected byte onGarageExited( byte result, boolean isEditorMode ) { eventsDispatcher.fireOnGarageExited( gameData, isEditorMode ); if ( !isEditorMode ) { result = reloadConfigAndSetupTexture( false ); if ( result != 0 ) eventsDispatcher.fireOnGarageExited( gameData, isEditorMode ); } return ( result ); } /** * * @param result 0 for no HUD to be drawn, 1 for HUD drawn, 2 for HUD drawn and texture re-requested * @param isEditorMode * * @return the result back again. */ protected byte onGarageEntered( byte result, boolean isEditorMode ) { eventsDispatcher.fireOnGarageEntered( gameData, isEditorMode ); if ( !isEditorMode ) { result = reloadConfigAndSetupTexture( false ); if ( result != 0 ) eventsDispatcher.fireOnGarageEntered( gameData, isEditorMode ); } return ( result ); } protected boolean checkIsInPits() { return ( gameData.getScoringInfo().getPlayersVehicleScoringInfo().isInPits() ); } /** * * @param result 0 for no HUD to be drawn, 1 for HUD drawn, 2 for HUD drawn and texture re-requested * @param isEditorMode * * @return the result back again. */ protected byte onPitsExited( byte result, boolean isEditorMode ) { eventsDispatcher.fireOnPitsExited( gameData, isEditorMode ); return ( result ); } /** * * @param result 0 for no HUD to be drawn, 1 for HUD drawn, 2 for HUD drawn and texture re-requested * @param isEditorMode * * @return the result back again. */ protected byte onPitsEntered( byte result, boolean isEditorMode ) { eventsDispatcher.fireOnPitsEntered( gameData, isEditorMode ); return ( result ); } protected byte checkPosition( boolean isEditorMode ) { byte result = 1; if ( isInGarage || isReenteringGarageSupported() ) { boolean isInGarage = checkIsInGarage(); if ( this.isInGarage && !isInGarage ) { this.isInGarage = false; result = onGarageExited( result, isEditorMode ); } else if ( !this.isInGarage && isInGarage ) { this.isInGarage = true; onGarageEntered( result, isEditorMode ); } } final boolean isInPits = checkIsInPits(); if ( this.isInPits && !isInPits ) { this.isInPits = isInPits; result = onPitsExited( result, isEditorMode ); } else if ( !this.isInPits && isInPits ) { this.isInPits = isInPits; result = onPitsEntered( result, isEditorMode ); } return ( result ); } protected void onVehicleSetupUpdated( boolean isEditorMode ) { eventsDispatcher.fireOnVehicleSetupUpdated( gameData, isEditorMode ); } /** * * @param timestamp event timestamp in nano seconds * @param isEditorMode * @return <code>true</code>, if track has changed, <code>false</code> otherwise. */ protected boolean checkTrackChanged( long timestamp, boolean isEditorMode ) { String trackname = gameData.getTrackInfo().getTrackName(); boolean result = !Tools.objectsEqual( trackname, lastTrackname ); lastTrackname = trackname; return ( result ); } /** * * @param timestamp event timestamp in nano seconds * @param isEditorMode */ protected void onTrackChanged( long timestamp, boolean isEditorMode ) { eventsDispatcher.fireOnTrackChanged( gameData.getTrackInfo().getTrackName(), gameData, isEditorMode ); } protected byte mergeResults( byte result1, byte result2 ) { if ( ( result1 == 0 ) || ( result2 == 0 ) ) { if ( ( result1 == 2 ) || ( result2 == 2 ) ) texturesRequested = true; return ( 0 ); } if ( ( result1 == 2 ) || ( result2 == 2 ) ) return ( 2 ); return ( 1 ); } protected void onWaitingForDataCompleted( long timestamp, boolean isEditorMode ) { if ( sessionJustStarted ) { __GDPrivilegedAccess.onSessionStarted2( gameData, timestamp, isEditorMode ); if ( !gameData.isInCockpit() || gameData.getScoringInfo().getSessionType().isRace() ) { String modName = gameData.getModInfo().getName(); String vehicleClass = gameData.getScoringInfo().getPlayersVehicleScoringInfo().getVehicleClass(); String vehicleName = gameData.getVehicleInfo().getTeamNameCleaned(); if ( ( vehicleName != null ) && ( vehicleName.trim().length() == 0 ) ) vehicleName = null; SessionType sessionType = gameData.getScoringInfo().getSessionType(); String trackname = gameData.getTrackInfo().getTrackName(); RFDHLog.printlnEx( "Session started. (Mod: \"" + modName + "\", Vehicle-Class: \"" + vehicleClass + "\", Car: \"" + ( vehicleName == null ? "N/A" : vehicleName ) + "\", Session: \"" + sessionType.name() + "\", Track: \"" + trackname + "\")" ); if ( checkTrackChanged( timestamp, isEditorMode ) ) { onTrackChanged( timestamp, isEditorMode ); } eventsDispatcher.fireOnSessionStarted( gameData.getScoringInfo().getSessionType(), gameData, isEditorMode ); needsOnVehicleControlChangedEvent = true; } this.sessionJustStarted = false; } } public final boolean getWaitingForData( boolean isEditorMode ) { if ( isEditorMode ) return ( waitingForTelemetry || waitingForScoring || waitingForWeather ); return ( waitingForData ); } protected byte checkWaitingData( boolean isEditorMode, boolean forceReload ) { long now = System.nanoTime(); eventsDispatcher.checkAndFireOnNeededDataComplete( gameData, isEditorMode ); boolean waitingForSetup2 = ( now <= setupReloadTryTime ); if ( __GDPrivilegedAccess.simulationMode ) waitingForSetup2 = false; if ( !waitingForScoring && gameData.getScoringInfo().getSessionType().isRace() && ( cockpitLeftInRaceSession == Boolean.FALSE ) ) { waitingForSetup = false; waitingForSetup2 = false; gameData.getSetup().updatedInTimeScope = true; } if ( !waitingForScoring ) cockpitLeftInRaceSession = null; if ( waitingForSetup || waitingForSetup2 ) { if ( reloadSetup() ) { waitingForSetup = false; waitingForSetup2 = false; setupReloadTryTime = -1L; onVehicleSetupUpdated( isEditorMode ); } else if ( waitingForSetup && !waitingForSetup2 ) { waitingForSetup = false; gameData.getSetup().updatedInTimeScope = true; } } if ( !waitingForData ) { byte result = 1; if ( texturesRequested ) { result = 2; texturesRequested = false; } return ( widgetsManager.getWidgetsConfiguration().isValid() ? result : (byte)0 ); } byte result = 0; if ( !waitingForRender && !waitingForGraphics && !waitingForTelemetry && !waitingForScoring && !waitingForWeather/* && !waitingForSetup && !waitingForSetup2*/ ) { onWaitingForDataCompleted( now, isEditorMode ); waitingForData = false; result = reloadConfigAndSetupTexture( forceReload ); } else if ( gameData.isInCockpit() ) { result = 1; if ( texturesRequested ) { result = 2; texturesRequested = false; } result = widgetsManager.getWidgetsConfiguration().isValid() ? result : (byte)0; } return ( result ); } /** * @param result 0 for no HUD to be drawn, 1 for HUD drawn, 2 for HUD drawn and texture re-requested * @param userObject a custom user object passed through to the sim specific implementation (could be an instance of {@link EditorPresets}) * @param timestamp event timestamp in nano seconds * @return 0 for no HUD to be drawn, 1 for HUD drawn, 2 for HUD drawn and texture re-requested. */ protected byte onDrivingAidsUpdatedImpl( byte result, Object userObject, long timestamp ) { gameData.getDrivingAids().updateData( userObject, System.nanoTime() ); return ( checkWaitingData( userObject instanceof EditorPresets, false ) ); } /** * @param userObject a custom user object passed through to the sim specific implementation * @return 0 for no HUD to be drawn, 1 for HUD drawn, 2 for HUD drawn and texture re-requested. */ public final byte onDrivingAidsUpdated( Object userObject ) { RFDHLog.profile( "[PROFILE]: onDrivingAidsUpdated()" ); byte result = 0; long now = System.nanoTime(); try { result = onDrivingAidsUpdatedImpl( result, userObject, now ); } catch ( Throwable t ) { RFDHLog.exception( t ); } //RFDHLog.println( ">>> /onDrivingAidsUpdated(), result: " + result ); return ( result ); } /** * @param result 0 for no HUD to be drawn, 1 for HUD drawn, 2 for HUD drawn and texture re-requested * @param userObject a custom user object passed through to the sim specific implementation (could be an instance of {@link EditorPresets}) * @param timestamp event timestamp in nano seconds * @return 0 for no HUD to be drawn, 1 for HUD drawn, 2 for HUD drawn and texture re-requested. */ protected byte onTelemetryDataUpdatedImpl( byte result, Object userObject, long timestamp ) { gameData.getTelemetryData().updateData( userObject, System.nanoTime() ); this.waitingForTelemetry = false; if ( gameData.getProfileInfo().isValid() ) { result = checkWaitingData( userObject instanceof EditorPresets, false ); } return ( result ); } /** * This method must be called when TelemetryData has been updated. * * @param userObject a custom user object passed through to the sim specific implementation (could be an instance of {@link EditorPresets}) * * @return 0 for no HUD to be drawn, 1 for HUD drawn, 2 for HUD drawn and texture re-requested. */ public byte onTelemetryDataUpdated( Object userObject ) { RFDHLog.profile( "[PROFILE]: onTelemetryDataUpdated()" ); byte result = 0; long now = System.nanoTime(); try { result = onTelemetryDataUpdatedImpl( result, userObject, now ); } catch ( Throwable t ) { RFDHLog.exception( t ); } if ( rfDynHUD != null ) rfDynHUD.setRenderMode( result != 0 ); //RFDHLog.println( ">>> /onTelemetryDataUpdated(), result: " + result ); return ( result ); } /** * * @param updateTimestamp the timestamp at the update * * @return <code>true</code>, if the race has been restarted, <code>false</code> otherwise. */ protected abstract boolean checkRaceRestartImpl( long updateTimestamp ); /** * * @param updateTimestamp the timestamp at the update */ public void checkRaceRestart( long updateTimestamp ) { if ( checkRaceRestartImpl( updateTimestamp ) ) { //RFDHLog.debug( "RACE RESTART" ); onSessionStarted( false ); } } /** * * @param isEditorMode editor mode? */ protected void checkAndFireOnLapStarted( boolean isEditorMode ) { final ScoringInfo scoringInfo = gameData.getScoringInfo(); if ( !scoringInfo.getPlayersVehicleScoringInfo().isInPits() ) this.isComingOutOfGarage = false; //if ( isComingOutOfGarage ) // return; final int n = scoringInfo.getNumVehicles(); for ( int i = 0; i < n; i++ ) { VehicleScoringInfo vsi = scoringInfo.getVehicleScoringInfo( i ); if ( vsi.isLapJustStarted() ) eventsDispatcher.fireOnLapStarted( vsi, gameData, isEditorMode ); } } /** * * @param viewedVSI * @param timestamp event timestamp in nano seconds * @param isEditorMode */ protected void onVehicleControlChanged( VehicleScoringInfo viewedVSI, long timestamp, boolean isEditorMode ) { eventsDispatcher.fireOnVehicleControlChanged( viewedVSI, gameData, isEditorMode ); } /** * * @param result 0 for no HUD to be drawn, 1 for HUD drawn, 2 for HUD drawn and texture re-requested * @param numVehicles * @param userObject a custom user object passed through to the sim specific implementation (could be an instance of {@link EditorPresets}) * @param timestamp event timestamp in nano seconds * @return 0 for no HUD to be drawn, 1 for HUD drawn, 2 for HUD drawn and texture re-requested. */ protected byte onScoringInfoUpdatedImpl( byte result, int numVehicles, Object userObject, long timestamp ) { gameData.getScoringInfo().updateData( numVehicles, userObject, timestamp ); this.waitingForScoring = false; boolean isEditorMode = ( userObject instanceof EditorPresets ); checkRaceRestart( timestamp ); checkAndFireOnLapStarted( isEditorMode ); this.currentSessionIsRace = gameData.getScoringInfo().getSessionType().isRace(); if ( waitingForGarageStartLocation ) { this.isInPits = checkIsInPits(); this.isInGarage = isInPits; this.waitingForGarageStartLocation = false; } if ( gameData.getProfileInfo().isValid() ) { result = checkWaitingData( isEditorMode, false ); eventsDispatcher.fireOnScoringInfoUpdated( gameData, isEditorMode ); if ( !waitingForData && ( result != 0 ) ) { byte result2 = checkPosition( isEditorMode ); result = mergeResults( result, result2 ); VehicleScoringInfo viewedVSI = gameData.getScoringInfo().getViewedVehicleScoringInfo(); if ( ( lastViewedVSIId == -1 ) || ( viewedVSI.getDriverId() != lastViewedVSIId ) || ( viewedVSI.getVehicleControl() != lastControl ) ) { lastViewedVSIId = viewedVSI.getDriverId(); lastControl = viewedVSI.getVehicleControl(); onVehicleControlChanged( viewedVSI, timestamp, isEditorMode ); result2 = reloadConfigAndSetupTexture( false ); if ( result2 == 2 ) { onVehicleControlChanged( viewedVSI, timestamp, isEditorMode ); needsOnVehicleControlChangedEvent = false; } result = mergeResults( result, result2 ); } else if ( needsOnVehicleControlChangedEvent ) { onVehicleControlChanged( viewedVSI, timestamp, isEditorMode ); needsOnVehicleControlChangedEvent = false; } } } return ( result ); } /** * This method must be called when ScoringInfo has been updated. * * @param numVehicles * @param userObject a custom user object passed through to the sim specific implementation (could be an instance of {@link EditorPresets}) * * @return 0 for no HUD to be drawn, 1 for HUD drawn, 2 for HUD drawn and texture re-requested. */ public byte onScoringInfoUpdated( int numVehicles, Object userObject ) { RFDHLog.profile( "[PROFILE]: onScoringInfoUpdated()" ); final long now = System.nanoTime(); byte result = 0; try { result = onScoringInfoUpdatedImpl( result, numVehicles, userObject, now ); } catch ( Throwable t ) { RFDHLog.exception( t ); } if ( rfDynHUD != null ) rfDynHUD.setRenderMode( result != 0 ); //RFDHLog.println( ">>> /onScoringInfoUpdated(), result: " + result ); return ( result ); } /** * @param result 0 for no HUD to be drawn, 1 for HUD drawn, 2 for HUD drawn and texture re-requested * @param userObject a custom user object passed through to the sim specific implementation (could be an instance of {@link EditorPresets}) * @param timestamp event timestamp in nano seconds * @return 0 for no HUD to be drawn, 1 for HUD drawn, 2 for HUD drawn and texture re-requested. */ protected byte onWeatherInfoUpdatedImpl( byte result, Object userObject, long timestamp ) { gameData.getWeatherInfo().updateData( userObject, System.nanoTime() ); this.waitingForWeather = false; return ( checkWaitingData( userObject instanceof EditorPresets, false ) ); } /** * @param userObject a custom user object passed through to the sim specific implementation * @return 0 for no HUD to be drawn, 1 for HUD drawn, 2 for HUD drawn and texture re-requested. */ public final byte onWeatherInfoUpdated( Object userObject ) { RFDHLog.profile( "[PROFILE]: onWeatherInfoUpdated()" ); byte result = 0; long now = System.nanoTime(); try { result = onWeatherInfoUpdatedImpl( result, userObject, now ); } catch ( Throwable t ) { RFDHLog.exception( t ); } //RFDHLog.println( ">>> /onWeatherInfoUpdated(), result: " + result ); return ( result ); } /** * @param result 0 for no HUD to be drawn, 1 for HUD drawn, 2 for HUD drawn and texture re-requested * @param userObject a custom user object passed through to the sim specific implementation (could be an instance of {@link EditorPresets}) * @param timestamp event timestamp in nano seconds * @return 0 for no HUD to be drawn, 1 for HUD drawn, 2 for HUD drawn and texture re-requested. */ protected byte onCommentaryRequestInfoUpdatedImpl( byte result, Object userObject, long timestamp ) { //if ( !isEditorMode ) gameData.getCommentaryRequestInfo().updateData( userObject, System.nanoTime() ); return ( checkWaitingData( userObject instanceof EditorPresets, false ) ); } /** * @param userObject a custom user object passed through to the sim specific implementation (could be an instance of {@link EditorPresets}) * @return 0 for no HUD to be drawn, 1 for HUD drawn, 2 for HUD drawn and texture re-requested. */ public final byte onCommentaryRequestInfoUpdated( Object userObject ) { RFDHLog.profile( "[PROFILE]: onCommentaryRequestInfoUpdated()" ); byte result = 0; long now = System.nanoTime(); try { result = onCommentaryRequestInfoUpdatedImpl( result, userObject, now ); } catch ( Throwable t ) { RFDHLog.exception( t ); } //RFDHLog.println( ">>> /onCommentaryRequestInfoUpdated(), result: " + result ); return ( result ); } /** * @param result 0 for no HUD to be drawn, 1 for HUD drawn, 2 for HUD drawn and texture re-requested * @param userObject a custom user object passed through to the sim specific implementation (could be an instance of {@link EditorPresets}) * @param timestamp event timestamp in nano seconds * * @return 0 for no HUD to be drawn, 1 for HUD drawn, 2 for HUD drawn and texture re-requested. */ protected byte onGraphicsInfoUpdatedImpl( byte result, Object userObject, long timestamp ) { gameData.getGraphicsInfo().updateData( userObject, timestamp ); return ( result ); } /** * @param userObject a custom user object passed through to the sim specific implementation (could be an instance of {@link EditorPresets}) * * @return 0 for no HUD to be drawn, 1 for HUD drawn, 2 for HUD drawn and texture re-requested. */ public final byte onGraphicsInfoUpdated( Object userObject ) { RFDHLog.profile( "[PROFILE]: onGraphicsInfoUpdated()" ); this.waitingForGraphics = false; byte result = 1; long now = System.nanoTime(); try { result = onGraphicsInfoUpdatedImpl( result, userObject, now ); } catch ( Throwable t ) { RFDHLog.exception( t ); } result = mergeResults( result, checkWaitingData( userObject instanceof EditorPresets, false ) ); //RFDHLog.println( ">>> /onGraphicsInfoUpdated(), result: " + result ); return ( result ); } /** * * @param viewportX the left coordinate of the viewport * @param viewportY the top coordinate of the viewport * @param viewportWidth the width of the viewport * @param viewportHeight the height of the viewport * * @return <code>true</code>, if the viewport has changed, <code>false</code> otherwise. */ protected boolean checkAndApplyChangedViewport( short viewportX, short viewportY, short viewportWidth, short viewportHeight ) { boolean vpChanged = __WCPrivilegedAccess.setViewport( viewportX, viewportY, viewportWidth, viewportHeight, widgetsManager.getWidgetsConfiguration() ); if ( ( viewportWidth > gameData.getGameResolution().getResX() ) || ( viewportHeight > gameData.getGameResolution().getResY() ) ) { widgetsManager.resizeMainTexture( viewportWidth, viewportHeight ); } return ( vpChanged ); } protected void onViewportChanged( short viewportX, short viewportY, short viewportWidth, short viewportHeight ) { gameData.getGraphicsInfo().onViewportChanged( viewportX, viewportY, viewportWidth, viewportHeight ); } /** * * @param result 0 for no HUD to be drawn, 1 for HUD drawn, 2 for HUD drawn and texture re-requested * @param viewportX the left coordinate of the viewport * @param viewportY the top coordinate of the viewport * @param viewportWidth the width of the viewport * @param viewportHeight the height of the viewport * @param viewportChanged * * @return 0 for no HUD to be drawn, 1 for HUD drawn, 2 for HUD drawn and texture re-requested. */ protected byte handleViewport( byte result, short viewportX, short viewportY, short viewportWidth, short viewportHeight, boolean viewportChanged ) { if ( viewportChanged ) { RFDHLog.debug( "[DEBUG]: (Viewport changed): ", viewportX, ", ", viewportY, "; ", viewportWidth, "x", viewportHeight ); if ( gameData.getProfileInfo().isValid() ) { //result = reloadConfigAndSetupTexture( true ); waitingForData = true; result = checkWaitingData( false, true ); } onViewportChanged( viewportX, viewportY, viewportWidth, viewportHeight ); } else { result = checkWaitingData( false, false ); } return ( result ); } /** * Will and must be called any time, the game is redendered (called from the C++-Plugin). * * @param result 0 for no HUD to be drawn, 1 for HUD drawn, 2 for HUD drawn and texture re-requested * @param viewportX the left coordinate of the viewport * @param viewportY the top coordinate of the viewport * @param viewportWidth the width of the viewport * @param viewportHeight the height of the viewport * * @return 0 for no HUD to be drawn, 1 for HUD drawn, 2 for HUD drawn and texture re-requested. */ protected byte beforeRenderImpl( byte result, short viewportX, short viewportY, short viewportWidth, short viewportHeight ) { if ( !__GDPrivilegedAccess.simulationMode ) { boolean vpChanged = checkAndApplyChangedViewport( viewportX, viewportY, viewportWidth, viewportHeight ); if ( isSessionRunning() && gameData.getProfileInfo().isValid() ) { handleViewport( result, viewportX, viewportY, viewportWidth, viewportHeight, vpChanged ); } } return ( result ); } /** * Will and must be called any time, the game is redendered (called from the C++-Plugin). * * @param viewportX the left coordinate of the viewport * @param viewportY the top coordinate of the viewport * @param viewportWidth the width of the viewport * @param viewportHeight the height of the viewport * * @return 0 for no HUD to be drawn, 1 for HUD drawn, 2 for HUD drawn and texture re-requested. */ public final byte beforeRender( short viewportX, short viewportY, short viewportWidth, short viewportHeight ) { RFDHLog.profile( "[PROFILE]: beforeRender()" ); this.waitingForRender = false; byte result = 1; try { result = beforeRenderImpl( result, viewportX, viewportY, viewportWidth, viewportHeight ); } catch ( Throwable t ) { RFDHLog.exception( t ); } if ( rfDynHUD != null ) rfDynHUD.setRenderMode( result != 0 ); result = mergeResults( result, checkWaitingData( false, false ) ); //RFDHLog.println( ">>> /beforeRender(), result: " + result ); return ( result ); } /** * Creates a new {@link GameEventsManager}. * * @param gameId a String, identifying the used simulation * @param rfDynHUD the main {@link RFDynHUD} instance * @param drawingManager the widgets drawing manager * @param gdFactory * @param configurationCandidatesIterator */ public GameEventsManager( String gameId, RFDynHUD rfDynHUD, WidgetsDrawingManager drawingManager, _LiveGameDataObjectsFactory gdFactory, Iterator<File> configurationCandidatesIterator ) { this.rfDynHUD = rfDynHUD; this.widgetsManager = drawingManager; this.gameData = gdFactory.newLiveGameData( this ); this.eventsDispatcher = GameEventsDispatcher.createGameEventsDispatcher( gameData.getFileSystem() ); eventsDispatcher.setWidgetsConfiguration( widgetsManager.getWidgetsConfiguration() ); this.renderListenersManager = widgetsManager.getRenderListenersManager(); __RenderPrivilegedAccess.setConfigurationAndLoader( widgetsManager.getWidgetsConfiguration(), loader, renderListenersManager ); } }