Revision: 427 http://skycastle.svn.sourceforge.net/skycastle/?rev=427&view=rev Author: zzorn Date: 2008-04-02 06:53:17 -0700 (Wed, 02 Apr 2008) Log Message: ----------- Starting to get the action system in a better shape. Should compile now, but tests wont pass yet. Modified Paths: -------------- trunk/skycastle/modules/core/src/main/java/org/skycastle/core/AbstractGameObject.java trunk/skycastle/modules/core/src/main/java/org/skycastle/core/ClientContext.java trunk/skycastle/modules/core/src/main/java/org/skycastle/core/ServerSideContext.java trunk/skycastle/modules/core/src/main/java/org/skycastle/core/UnitTestingContext.java trunk/skycastle/modules/core/src/main/java/org/skycastle/core/acting/ActEvent.java trunk/skycastle/modules/core/src/main/java/org/skycastle/core/acting/ActionFacadeImpl.java trunk/skycastle/modules/core/src/test/java/org/skycastle/core/AbstractGameObjectActionsTest.java Added Paths: ----------- trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/action/ActionFinishedMessage.java Removed Paths: ------------- trunk/skycastle/modules/core/src/main/java/org/skycastle/core/acting/AbstractAct.java trunk/skycastle/modules/core/src/main/java/org/skycastle/core/acting/ActScheduler.java trunk/skycastle/modules/core/src/main/java/org/skycastle/core/acting/ActSchedulerImpl.java trunk/skycastle/modules/core/src/main/java/org/skycastle/core/acting/ActionScheduler.java trunk/skycastle/modules/core/src/main/java/org/skycastle/core/acting/ClientActScheduler.java trunk/skycastle/modules/core/src/main/java/org/skycastle/core/acting/ServerActScheduler.java trunk/skycastle/modules/core/src/main/java/org/skycastle/core/acting/UnitTestActScheduler.java Modified: trunk/skycastle/modules/core/src/main/java/org/skycastle/core/AbstractGameObject.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/core/AbstractGameObject.java 2008-03-31 07:16:31 UTC (rev 426) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/core/AbstractGameObject.java 2008-04-02 13:53:17 UTC (rev 427) @@ -29,19 +29,14 @@ public abstract class AbstractGameObject implements GameObject { - public void run() throws Exception - { - // Check for any scheduled tasks - } - //====================================================================== // Private Fields private final GameObjectContext myGameObjectContext; private final PropertyFacade myPropertyFacade; - private final ActionFacade myActionFacade; + private final ActionFacadeImpl myActionFacade; private final MessagingFacade myMessagingFacade; private GameObjectId myId; @@ -236,6 +231,14 @@ } //---------------------------------------------------------------------- + // Task Implementation + + public void run() throws Exception + { + myActionFacade.runScheduledActs( myGameObjectContext.getCurrentGameTime_ms() ); + } + + //---------------------------------------------------------------------- // Other Public Methods /** Modified: trunk/skycastle/modules/core/src/main/java/org/skycastle/core/ClientContext.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/core/ClientContext.java 2008-03-31 07:16:31 UTC (rev 426) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/core/ClientContext.java 2008-04-02 13:53:17 UTC (rev 427) @@ -10,9 +10,20 @@ public class ClientContext implements GameObjectContext { + + //====================================================================== + // Private Fields + private final GameModel myGameModel; + private GameObjectId myId; + //====================================================================== + // Public Methods + + //---------------------------------------------------------------------- + // Constructors + /** * Creates a new {@link org.skycastle.core.ClientContext}. */ @@ -25,25 +36,37 @@ myGameModel = gameModel; } + //---------------------------------------------------------------------- + // GameObjectContext Implementation + + public GameObjectId createGameObjectId( final GameObject gameObject ) { return myId; } + public void addTaskCallback( final long timeToNextInvocation_ms, final GameObject gameObject ) { throw new UnsupportedOperationException( "This method has not yet been implemented." ); // IMPLEMENT - } + public InvocationType getActionInvocationType() { return InvocationType.LATER_IN_SWING_THREAD; - } + public GameObject getGameObjectById( final GameObjectId gameObjectId, final boolean forModification ) { return myGameModel.getGameObject( gameObjectId ); } + + + public long getCurrentGameTime_ms() + { + throw new UnsupportedOperationException( "This method has not yet been implemented." ); // IMPLEMENT + } + } Modified: trunk/skycastle/modules/core/src/main/java/org/skycastle/core/ServerSideContext.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/core/ServerSideContext.java 2008-03-31 07:16:31 UTC (rev 426) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/core/ServerSideContext.java 2008-04-02 13:53:17 UTC (rev 427) @@ -23,6 +23,7 @@ //---------------------------------------------------------------------- // GameObjectContext Implementation + public GameObjectId createGameObjectId( final GameObject gameObject ) { final DataManager dataManager = AppContext.getDataManager(); @@ -34,10 +35,10 @@ return id; } + public void addTaskCallback( final long timeToNextInvocation_ms, final GameObject gameObject ) { throw new UnsupportedOperationException( "This method has not yet been implemented." ); // IMPLEMENT - } @@ -62,4 +63,10 @@ return retrievedGameObject; } + + public long getCurrentGameTime_ms() + { + throw new UnsupportedOperationException( "This method has not yet been implemented." ); // IMPLEMENT + } + } Modified: trunk/skycastle/modules/core/src/main/java/org/skycastle/core/UnitTestingContext.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/core/UnitTestingContext.java 2008-03-31 07:16:31 UTC (rev 426) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/core/UnitTestingContext.java 2008-04-02 13:53:17 UTC (rev 427) @@ -11,19 +11,21 @@ implements GameObjectContext { + //====================================================================== + // Public Methods + //---------------------------------------------------------------------- // GameObjectContext Implementation - public GameObjectId createGameObjectId( final GameObject gameObject ) { return new GameObjectId( "TestGameObject" + String.valueOf( gameObject.hashCode() ) ); } + public void addTaskCallback( final long timeToNextInvocation_ms, final GameObject gameObject ) { throw new UnsupportedOperationException( "This method has not yet been implemented." ); // IMPLEMENT - } @@ -38,4 +40,10 @@ throw new UnsupportedOperationException( "This method has not yet been implemented." ); // IMPLEMENT } + + public long getCurrentGameTime_ms() + { + throw new UnsupportedOperationException( "This method has not yet been implemented." ); // IMPLEMENT + } + } Deleted: trunk/skycastle/modules/core/src/main/java/org/skycastle/core/acting/AbstractAct.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/core/acting/AbstractAct.java 2008-03-31 07:16:31 UTC (rev 426) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/core/acting/AbstractAct.java 2008-04-02 13:53:17 UTC (rev 427) @@ -1,138 +0,0 @@ -package org.skycastle.core.acting; - -import org.skycastle.core.GameObject; -import org.skycastle.messaging.MessageListener; -import org.skycastle.util.ParameterChecker; -import org.skycastle.util.parameters.ParameterSet; - -/** - * @author Hans Häggström - */ -public abstract class AbstractAct - implements Act -{ - - //====================================================================== - // Private Fields - - private ParameterSet myParameters; - private Object myHostObject; - private InvocationType myInvocationType; - private ParameterSet myConfigurationParameters; - - //====================================================================== - // Private Constants - - private static final long serialVersionUID = 1L; - - //====================================================================== - // Public Methods - - //---------------------------------------------------------------------- - // Other Public Methods - - public final void stop( final double timeSinceLastCall_s ) - { - final GameObject hostObject = getHostObject(); - stop( hostObject, hostObject, myParameters, myConfigurationParameters, timeSinceLastCall_s ); - } - - - public final double doStep( final double timeSinceLastCall ) - { - final GameObject hostObject = getHostObject(); - return doStep( hostObject, hostObject, myParameters, myConfigurationParameters, timeSinceLastCall ); - } - - - public final void initialize( final GameObject hostObject, - final ParameterSet parameters, - ParameterSet configurationParameters, - InvocationType invocationType ) - { - ParameterChecker.checkNotNull( hostObject, "hostObject" ); - ParameterChecker.checkNotNull( parameters, "parameters" ); - ParameterChecker.checkNotNull( configurationParameters, "configurationParameters" ); - ParameterChecker.checkNotNull( invocationType, "invocationType" ); - - myParameters = parameters; - myConfigurationParameters = configurationParameters; - myInvocationType = invocationType; - - myHostObject = myInvocationType.storeGameObject( hostObject ); - } - - - /** - * @return a reference to the host {@link GameObject} that this {@link Act} is running in. - */ - public final GameObject getHostObject() - { - return myInvocationType.retrieveGameObject( myHostObject ); - } - - //====================================================================== - // Protected Methods - - //---------------------------------------------------------------------- - // Abstract Protected Methods - - /** - * Called when the act is stopped by an external force. - * - * @param hostObject a reference to the {@link GameObject} the {@link Act} is operating in. - * @param timeSinceLastCall_s number of in-game seconds since the previous doStep call, or since the - * start call if this is the first doStep call. 0 if no calls has been - * done yet. - * @param messageHandler a listener that can handle messages sent out by this {@link Act}. - * @param parameters the parameters that the act was called with. - * @param configurationParameters the parameters that the action is configured with. - */ - protected abstract void stop( GameObject hostObject, - MessageListener messageHandler, - final ParameterSet parameters, - ParameterSet configurationParameters, - double timeSinceLastCall_s ); - - /** - * Executes one step of the act. - * - * @param hostObject a reference to the {@link GameObject} the {@link Act} is operating in. - * @param timeSinceLastCall_s number of in-game seconds since the previous doStep call, or since the - * start call if this is the first doStep call. - * @param messageHandler a listener that can handle messages sent out by this {@link Act}. - * @param parameters the parameters that the act was called with. - * @param configurationParameters the parameters that the action is configured with. - * - * @return time until the task should be invoked next, in in-game seconds. - * <p/> - * If a negative number or Double.NAN or Double.INFINITY is returned, the act is not repeated, and - * the {@link Act} is considered finished. - */ - protected abstract double doStep( GameObject hostObject, - MessageListener messageHandler, - final ParameterSet parameters, - ParameterSet configurationParameters, - double timeSinceLastCall_s ); - - //---------------------------------------------------------------------- - // Other Protected Methods - - /** - * @return the parameters for this {@link Act}, specified by the action invoker. - */ - protected final ParameterSet getParameters() - { - return myParameters; - } - - - /** - * @return parameters used to configure the {@link Act}. Specified by the {@link Action}. - */ - protected final ParameterSet getConfigurationParameters() - { - return myConfigurationParameters; - } - -} Modified: trunk/skycastle/modules/core/src/main/java/org/skycastle/core/acting/ActEvent.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/core/acting/ActEvent.java 2008-03-31 07:16:31 UTC (rev 426) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/core/acting/ActEvent.java 2008-04-02 13:53:17 UTC (rev 427) @@ -22,7 +22,6 @@ private final String myActionIdentifier; private final long myActId; - private boolean myFirstTime; private long myTimeToCall_ms; private long myLastCallTime_ms = 0; @@ -39,20 +38,21 @@ final ParameterSet actionCallParameters, final ParameterSet configurationParameters, final String actionIdentifier, - final long actId ) + final long actId, + final long lastCallTime_ms ) { - myActionIdentifier = actionIdentifier; - myActId = actId; ParameterChecker.checkNotNull( act, "act" ); ParameterChecker.checkNotNull( actionCallParameters, "actionCallParameters" ); ParameterChecker.checkNotNull( configurationParameters, "configurationParameters" ); + ParameterChecker.checkNotNull( actionIdentifier, "actionIdentifier" ); + myActionIdentifier = actionIdentifier; + myActId = actId; myAct = act; myTimeToCall_ms = timeToCall_ms; myActionCallParameters = actionCallParameters; myConfigurationParameters = configurationParameters; - - myFirstTime = true; + myLastCallTime_ms = lastCallTime_ms; } //---------------------------------------------------------------------- @@ -77,6 +77,18 @@ //---------------------------------------------------------------------- // Other Public Methods + public String getActionIdentifier() + { + return myActionIdentifier; + } + + + public long getActId() + { + return myActId; + } + + /** * @return true if a callback to the {@link org.skycastle.core.GameObject} run method inherited from * {@link com.sun.sgs.app.Task} has been scheduled for the time of this event. @@ -148,11 +160,7 @@ public void stopAct( GameObject hostObject, long currentTime_ms ) { - long timeSinceLastCall = 0; - if ( !myFirstTime ) - { - timeSinceLastCall = currentTime_ms - myLastCallTime_ms; - } + final long timeSinceLastCall = currentTime_ms - myLastCallTime_ms; myAct.stop( hostObject, hostObject, @@ -181,25 +189,13 @@ private long callAct( final GameObject hostObject, final long currentTime_ms ) { - final long timeUntilNextCall; + final long timeSinceLastCall = currentTime_ms - myLastCallTime_ms; - if ( myFirstTime ) - { - timeUntilNextCall = myAct.start( hostObject, - hostObject, - myActionCallParameters, - myConfigurationParameters ); - myFirstTime = false; - } - else - { - long timeSinceLastCall = currentTime_ms - myLastCallTime_ms; - timeUntilNextCall = myAct.doStep( hostObject, - hostObject, - myActionCallParameters, - myConfigurationParameters, - timeSinceLastCall ); - } + final long timeUntilNextCall = myAct.doStep( hostObject, + hostObject, + myActionCallParameters, + myConfigurationParameters, + timeSinceLastCall ); myLastCallTime_ms = currentTime_ms; return timeUntilNextCall; Deleted: trunk/skycastle/modules/core/src/main/java/org/skycastle/core/acting/ActScheduler.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/core/acting/ActScheduler.java 2008-03-31 07:16:31 UTC (rev 426) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/core/acting/ActScheduler.java 2008-04-02 13:53:17 UTC (rev 427) @@ -1,33 +0,0 @@ -package org.skycastle.core.acting; - -import org.skycastle.core.GameObject; -import org.skycastle.messaging.MessageListener; -import org.skycastle.messaging.modifications.action.InvokeActionMessage; - -/** - * Runs scheduled {@link Act}s for a {@link GameObject}. - * - * @author Hans Häggström - */ -public interface ActScheduler -{ - - /** - */ - void schedule( InvokeActionMessage invokeActionMessage ); - - - /** - * Stops the ongoing or scheduled act with the specified id. - * - * @param actionId the id of the act to be stopped. Act id:s are recieved with the information messages - * that tell about ongoing actions, or directly by querying the game object. - */ - void stop( String actionIdentifier, long actionId ); - - /** - * @param messageListener A listener that is notified when act states change. - */ - void setActionUpdateMessageListener( MessageListener messageListener ); - -} Deleted: trunk/skycastle/modules/core/src/main/java/org/skycastle/core/acting/ActSchedulerImpl.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/core/acting/ActSchedulerImpl.java 2008-03-31 07:16:31 UTC (rev 426) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/core/acting/ActSchedulerImpl.java 2008-04-02 13:53:17 UTC (rev 427) @@ -1,144 +0,0 @@ -package org.skycastle.core.acting; - -import org.skycastle.core.GameObject; -import org.skycastle.core.GameObjectContext; -import org.skycastle.messaging.MessageListener; -import org.skycastle.messaging.modifications.action.InvokeActionMessage; -import org.skycastle.util.ParameterChecker; -import org.skycastle.util.parameters.ParameterSet; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.PriorityQueue; - -/** - * @author Hans Haggstrom - */ -public final class ActSchedulerImpl - implements ActScheduler -{ - - //====================================================================== - // Private Fields - - private final PriorityQueue<ActEvent> myActQueue = new PriorityQueue<ActEvent>(); - - private final GameObject myHostObject; - private final GameObjectContext myGameObjectContext; - - //====================================================================== - // Public Methods - - //---------------------------------------------------------------------- - // ActScheduler Implementation - - public void schedule( final InvokeActionMessage invokeActionMessage ) - { - invokeActionMessage. - - queueAct( act, myGameObjectContext.getCurrentGameTime_ms(), ); - } - - - public void stop( final String actionIdentifier, final long actionId ) - { - throw new UnsupportedOperationException( "This method has not yet been implemented." ); // IMPLEMENT - } - - - public void setActionUpdateMessageListener( final MessageListener messageListener ) - { - throw new UnsupportedOperationException( "This method has not yet been implemented." ); // IMPLEMENT - } - - //---------------------------------------------------------------------- - // Other Public Methods - - - /** - * Runs all {@link Act} events that are overdue. - * - * @param currentTime_ms the current in-game time, in milliseconds since epoch. - */ - public final void runScheduledActs( long currentTime_ms ) - { - Collection<ActEvent> eventsToReinsert = null; - - // Invoke due events - while ( myActQueue.peek() != null && myActQueue.peek().getTimeToCall_ms() <= currentTime_ms ) - { - final ActEvent nextEvent = myActQueue.poll(); - - final boolean reinsert = nextEvent.invoke( myHostObject, currentTime_ms ); - - if ( reinsert ) - { - if ( eventsToReinsert == null ) - { - eventsToReinsert = new ArrayList<ActEvent>( 5 ); - } - - eventsToReinsert.add( nextEvent ); - } - } - - // Re-insert events that continue - // (we do it outside the loop so that we avoid potential infinite or expensive loops with events that repeat very frequently) - if ( eventsToReinsert != null ) - { - myActQueue.addAll( eventsToReinsert ); - } - } - - //====================================================================== - // Protected Methods - - //---------------------------------------------------------------------- - // Protected Constructors - - protected ActSchedulerImpl( final GameObject hostObject, final GameObjectContext gameObjectContext ) - { - ParameterChecker.checkNotNull( hostObject, "hostObject" ); - ParameterChecker.checkNotNull( gameObjectContext, "gameObjectContext" ); - - myGameObjectContext = gameObjectContext; - myHostObject = hostObject; - } - - - protected final void queueAct( Act act, - long currentTime_ms, - ParameterSet callParameters, - ParameterSet configurationParameters, - final String actionIdentifier, - final long actId ) - { - myActQueue.add( new ActEvent( act, - currentTime_ms, - callParameters, - configurationParameters, - actionIdentifier, - actId ) ); - } - - - protected final void stopAct( String actionId, long actId, long currentTime_ms ) - { - for ( ActEvent event : myActQueue ) - { - if ( event.hasActId( actionId, actId ) ) - { - myActQueue.remove( event ); - event.stopAct( myHostObject, currentTime_ms ); - return; - } - } - } - - - protected final GameObject getHostObject() - { - return myHostObject; - } - -} Modified: trunk/skycastle/modules/core/src/main/java/org/skycastle/core/acting/ActionFacadeImpl.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/core/acting/ActionFacadeImpl.java 2008-03-31 07:16:31 UTC (rev 426) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/core/acting/ActionFacadeImpl.java 2008-04-02 13:53:17 UTC (rev 427) @@ -1,19 +1,18 @@ package org.skycastle.core.acting; import org.skycastle.core.*; -import org.skycastle.messaging.MessageListener; import org.skycastle.messaging.modifications.ModificationMessage; import org.skycastle.messaging.modifications.action.InvokeActionMessage; +import org.skycastle.messaging.updates.action.ActionFinishedMessage; import org.skycastle.messaging.updates.action.ActionStartedMessage; -import org.skycastle.messaging.updates.action.ActionStopped; import org.skycastle.util.ParameterChecker; import org.skycastle.util.listenable.map.ListenableLinkedMap; import org.skycastle.util.parameters.ParameterSet; import org.skycastle.util.parameters.ParameterSetImpl; import org.skycastle.util.parameters.ValidationError; -import org.skycastle.util.scheduler.Scheduler; import java.util.*; +import java.util.logging.Logger; /** * @author Hans Häggström @@ -26,10 +25,9 @@ //====================================================================== // Private Fields - private final PriorityQueue<ActEvent> myActQueue = new PriorityQueue<ActEvent>(); + private final Queue<ActEvent> myActQueue = new PriorityQueue<ActEvent>(); private final ListenableLinkedMap<String, Action> myActions = new ListenableLinkedMap<String, Action>(); private final LinkedList<InvokeActionMessage> myQueuedActions = new LinkedList<InvokeActionMessage>(); - private final Scheduler myScheduler = new Scheduler(); private final Random myRandom = new Random(); @@ -38,6 +36,8 @@ private static final long serialVersionUID = 1L; + private static final Logger LOGGER = Logger.getLogger( ActionFacadeImpl.class.getName() ); + //====================================================================== // Public Methods @@ -67,8 +67,9 @@ } catch ( ActionInvocationException e ) { - e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. - throw new UnsupportedOperationException( "This method has not yet been implemented." ); // IMPLEMENT + // TODO: Logger wrapper that also embeds stacktraces? + LOGGER.warning( "Exception when running action: " + e ); + e.printStackTrace(); } } @@ -106,13 +107,15 @@ final String identifier = action.getIdentifier(); ParameterChecker.checkIsIdentifier( identifier, "identifier" ); - if ( !hasAction( identifier ) ) + if ( hasAction( identifier ) ) { - myActions.put( identifier, action ); + // TODO: Notify caller/admin about failure? + // TODO: Or should it just replace the earlier action? Security problem? + throw new IllegalStateException( "Can not add action '" + action.getIdentifier() + "' as the game object already has an action with the same name " ); } else { - // TODO: Notify about failure? + myActions.put( identifier, action ); } } @@ -147,7 +150,8 @@ Collection<ActEvent> eventsToReinsert = null; // Invoke due events - while ( myActQueue.peek() != null && myActQueue.peek().getTimeToCall_ms() <= currentTime_ms ) + while ( myActQueue.peek() != null && + myActQueue.peek().getTimeToCall_ms() <= currentTime_ms ) { final ActEvent nextEvent = myActQueue.poll(); @@ -162,6 +166,13 @@ eventsToReinsert.add( nextEvent ); } + else + { + // We are finished with this act + getGameObject().sendUpdateToObservers( new ActionFinishedMessage( getId(), + nextEvent.getActionIdentifier(), + nextEvent.getActId() ) ); + } } // Re-insert events that continue @@ -177,38 +188,6 @@ //====================================================================== // Protected Methods - protected final void queueAct( Act act, - long currentTime_ms, - ParameterSet callParameters, - ParameterSet configurationParameters, - final String actionIdentifier, - final long actId ) - { - myActQueue.add( new ActEvent( act, - currentTime_ms, - callParameters, - configurationParameters, - actionIdentifier, - actId ) ); - - addCallbackToNextEvent(); - } - - - protected final void stopAct( String actionId, long actId, long currentTime_ms ) - { - for ( ActEvent event : myActQueue ) - { - if ( event.hasActId( actionId, actId ) ) - { - myActQueue.remove( event ); - event.stopAct( myHostObject, currentTime_ms ); - return; - } - } - } - - /** * Runs the next available action, or does nothing if no new actions can be started, or if there are no * new actions. @@ -245,11 +224,26 @@ } + private void stopAct( String actionId, long actId, long currentTime_ms ) + { + for ( ActEvent event : myActQueue ) + { + if ( event.hasActId( actionId, actId ) ) + { + myActQueue.remove( event ); + event.stopAct( getGameObject(), currentTime_ms ); + return; + } + } + } + + private void addCallbackToNextEvent() { // Get next event in queue, and schedule a callback if not already scheduled. final ActEvent nextEvent = myActQueue.peek(); - if ( !nextEvent.hasScheduledCallback() ) + if ( nextEvent != null && + !nextEvent.hasScheduledCallback() ) { nextEvent.setHasScheduledCallback( true ); getContext().addTaskCallback( nextEvent.getTimeToCall_ms(), getGameObject() ); @@ -262,7 +256,6 @@ { myQueuedActions.remove( invokeActionMessage ); - final ParameterSet parameters = invokeActionMessage.getParameters(); final Action action = myActions.get( invokeActionMessage.getActionIdentifier() ); checkTargetIdCorrect( invokeActionMessage ); @@ -270,42 +263,45 @@ checkActionExists( invokeActionMessage, action ); checkActionParametersValid( invokeActionMessage, action ); - final Class<? extends Act> actClass = action.getActClass(); - try + final Act act = createActInstance( invokeActionMessage, action ); + + final ActEvent event = startAct( act, action, invokeActionMessage ); + + if ( event != null ) { + // Schedule further steps to complete the action + queueActEvent( event ); + getGameObject().sendUpdateToObservers( new ActionStartedMessage( getId(), invokeActionMessage.getActionIdentifier(), invokeActionMessage.getActId() ) ); + } + else + { + // Only one step action, send finish message directly + getGameObject().sendUpdateToObservers( new ActionFinishedMessage( getId(), + invokeActionMessage.getActionIdentifier(), + invokeActionMessage.getActId() ) ); + } + } - Act act = actClass.newInstance(); - final MessageListener messageHandler = null; - double timeUntilDoTaskShouldBeCalled = act.start( getGameObject(), - messageHandler, - parameters, - action.getConfigurationParameters() ); + private void queueActEvent( final ActEvent event ) + { + myActQueue.add( event ); - final double earlierNextInvocation = myScheduler.getTimeUntilNextInvocation(); + addCallbackToNextEvent(); + } - if ( timeUntilDoTaskShouldBeCalled >= 0 ) - { - myScheduler.addTaskWithPreviousInvocationTime( act, - timeUntilDoTaskShouldBeCalled, - myScheduler.getTime() ); - } - final double nextInvocation = myScheduler.getTimeUntilNextInvocation(); - - if ( nextInvocation < earlierNextInvocation && - !Double.isInfinite( nextInvocation ) ) - { - getContext().addTaskCallback( nextInvocation, getGameObject() ); - } - - - getGameObject().sendUpdateToObservers( new ActionStopped( getId(), - invokeActionMessage.getActionIdentifier(), - invokeActionMessage.getActId() ) ); + private static Act createActInstance( final InvokeActionMessage invokeActionMessage, final Action action ) + throws ActionInvocationException + { + Act act; + final Class<? extends Act> actClass = action.getActClass(); + try + { + act = actClass.newInstance(); } catch ( InstantiationException e ) { @@ -321,6 +317,30 @@ e.getMessage(), e ); } + + return act; + } + + + /** + * Invoke start on an act. + * + * @return the act event that should be invoked later if needed. + */ + private ActEvent startAct( Act act, Action action, InvokeActionMessage invokeActionMessage ) throws ActionInvocationException + { + ParameterSet parameters = invokeActionMessage.getParameters(); + long actId = invokeActionMessage.getActId(); + + // Initialize / run act + final long timeUntilNextCall; + try + { + timeUntilNextCall = act.start( getGameObject(), + getGameObject(), + parameters, + action.getConfigurationParameters() ); + } catch ( Exception e ) { // TODO: Check for any SGS exceptions and throw them onward unmodified, as SGS needs them for management @@ -330,6 +350,22 @@ "thrown when invoking action '" + invokeActionMessage.getActionIdentifier() + "'.", e ); } + + // If it requires further steps, create an event + ActEvent actEvent = null; + if ( timeUntilNextCall >= 0 ) + { + final long currentGameTime_ms = getContext().getCurrentGameTime_ms(); + actEvent = new ActEvent( act, + currentGameTime_ms + timeUntilNextCall, + parameters, + action.getConfigurationParameters(), + action.getIdentifier(), + actId, + currentGameTime_ms ); + } + + return actEvent; } Deleted: trunk/skycastle/modules/core/src/main/java/org/skycastle/core/acting/ActionScheduler.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/core/acting/ActionScheduler.java 2008-03-31 07:16:31 UTC (rev 426) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/core/acting/ActionScheduler.java 2008-04-02 13:53:17 UTC (rev 427) @@ -1,37 +0,0 @@ -package org.skycastle.core.acting; - -import org.skycastle.core.GameObject; -import org.skycastle.messaging.MessageListener; -import org.skycastle.util.parameters.ParameterSet; - -/** - * Takes care of running requested actions for a {@link GameObject}. - * - * @author Hans Häggström - */ -public interface ActionScheduler -{ - - /** - * @param actionIdentifier identifier of the action to schedule. - * @param actionParameters parameters for the action. - * @param actionId an unique or random id for this execution of an action. Used when stopping a - * specific act. - */ - void schedule( String actionIdentifier, ParameterSet actionParameters, long actionId ); - - - /** - * Stops the ongoing or scheduled act with the specified id. - * - * @param actionId the id of the act to be stopped. Act id:s are recieved with the information messages - * that tell about ongoing actions, or directly by querying the game object. - */ - void stop( long actionId ); - - /** - * @param messageListener A listener that is notified when act states change. - */ - void setActionUpdateMessageListener( MessageListener messageListener ); - -} Deleted: trunk/skycastle/modules/core/src/main/java/org/skycastle/core/acting/ClientActScheduler.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/core/acting/ClientActScheduler.java 2008-03-31 07:16:31 UTC (rev 426) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/core/acting/ClientActScheduler.java 2008-04-02 13:53:17 UTC (rev 427) @@ -1,34 +0,0 @@ -package org.skycastle.core.acting; - -import org.skycastle.messaging.MessageListener; - -/** - * A client side implementation of {@link ActScheduler}. - * - * @author Hans Haggstrom - */ -public class ClientActScheduler - implements ActScheduler -{ - - //---------------------------------------------------------------------- - // ActScheduler Implementation - - public void schedule( final Act act ) - { - throw new UnsupportedOperationException( "This method has not yet been implemented." ); // IMPLEMENT - } - - - public void stop( final String actionIdentifier, final long actionId ) - { - throw new UnsupportedOperationException( "This method has not yet been implemented." ); // IMPLEMENT - } - - - public void setActionUpdateMessageListener( final MessageListener messageListener ) - { - throw new UnsupportedOperationException( "This method has not yet been implemented." ); // IMPLEMENT - } - -} Deleted: trunk/skycastle/modules/core/src/main/java/org/skycastle/core/acting/ServerActScheduler.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/core/acting/ServerActScheduler.java 2008-03-31 07:16:31 UTC (rev 426) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/core/acting/ServerActScheduler.java 2008-04-02 13:53:17 UTC (rev 427) @@ -1,37 +0,0 @@ -package org.skycastle.core.acting; - -import com.sun.sgs.app.AppContext; -import org.skycastle.core.GameObject; -import org.skycastle.messaging.MessageListener; - -/** - * An {@link ActScheduler} for use on the server. Runs the {@link Act}s as {@link com.sun.sgs.app.Task}s on - * the {@link org.skycastle.core.GameObject} that they are applied to. - * - * @author Hans Haggstrom - */ -public class ServerActScheduler - extends ActSchedulerImpl -{ - public ServerActScheduler( final GameObject hostObject ) - { - super( hostObject, myGameObjectContext ); - } - - public void schedule( final Act act ) - { - AppContext.getTaskManager().scheduleTask( getHostObject() ); - - throw new UnsupportedOperationException( "This method has not yet been implemented." ); // IMPLEMENT - } - - public void stop( final String actionIdentifier, final long actionId ) - { - throw new UnsupportedOperationException( "This method has not yet been implemented." ); // IMPLEMENT - } - - public void setActionUpdateMessageListener( final MessageListener messageListener ) - { - throw new UnsupportedOperationException( "This method has not yet been implemented." ); // IMPLEMENT - } -} Deleted: trunk/skycastle/modules/core/src/main/java/org/skycastle/core/acting/UnitTestActScheduler.java =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/core/acting/UnitTestActScheduler.java 2008-03-31 07:16:31 UTC (rev 426) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/core/acting/UnitTestActScheduler.java 2008-04-02 13:53:17 UTC (rev 427) @@ -1,34 +0,0 @@ -package org.skycastle.core.acting; - -import org.skycastle.messaging.MessageListener; - -/** - * An {@link ActScheduler} implementation for unit tests. Runs acts in same thread, allows updating time. - * - * @author Hans Haggstrom - */ -public class UnitTestActScheduler - implements ActScheduler -{ - - //---------------------------------------------------------------------- - // ActScheduler Implementation - - public void schedule( final Act act ) - { - throw new UnsupportedOperationException( "This method has not yet been implemented." ); // IMPLEMENT - } - - - public void stop( final String actionIdentifier, final long actionId ) - { - throw new UnsupportedOperationException( "This method has not yet been implemented." ); // IMPLEMENT - } - - - public void setActionUpdateMessageListener( final MessageListener messageListener ) - { - throw new UnsupportedOperationException( "This method has not yet been implemented." ); // IMPLEMENT - } - -} Copied: trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/action/ActionFinishedMessage.java (from rev 426, trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/action/ActionStopped.java) =================================================================== --- trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/action/ActionFinishedMessage.java (rev 0) +++ trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/action/ActionFinishedMessage.java 2008-04-02 13:53:17 UTC (rev 427) @@ -0,0 +1,26 @@ +package org.skycastle.messaging.updates.action; + +import org.skycastle.core.GameObjectId; +import org.skycastle.core.clientside.GameModel; + +/** + * Indicates that the specified action has stopped, either by a failure or by completing naturally. + * <p/> + * If the action is immediate, no separate {@link ActionStartedMessage} will be sent, just an {@link ActionFinishedMessage}. + * + * @author Hans H�ggstr�m + */ +public final class ActionFinishedMessage + extends ActionUpdateMessage + +{ + public ActionFinishedMessage( final GameObjectId updatedObjectId, final String memberIdentifier, final long actId ) + { + super( updatedObjectId, memberIdentifier, actId ); + } + + public void applyStateChangeToModel( final GameModel gameModel ) + { + throw new UnsupportedOperationException( "This method has not yet been implemented." ); // IMPLEMENT + } +} Modified: trunk/skycastle/modules/core/src/test/java/org/skycastle/core/AbstractGameObjectActionsTest.java =================================================================== --- trunk/skycastle/modules/core/src/test/java/org/skycastle/core/AbstractGameObjectActionsTest.java 2008-03-31 07:16:31 UTC (rev 426) +++ trunk/skycastle/modules/core/src/test/java/org/skycastle/core/AbstractGameObjectActionsTest.java 2008-04-02 13:53:17 UTC (rev 427) @@ -1,7 +1,7 @@ package org.skycastle.core; import junit.framework.TestCase; -import org.skycastle.core.acting.AbstractAct; +import org.skycastle.core.acting.Act; import org.skycastle.core.acting.Action; import org.skycastle.core.acting.ActionImpl; import org.skycastle.core.acting.InvocationType; @@ -113,37 +113,41 @@ } public static class DummyAct - extends AbstractAct + implements Act { private static final String TIMES_CALLED = "timesCalled"; private static final String STOP_CALLED = "stopCalled"; private static final String REPEAT_INTERVALL = "repeatIntervall"; - public double start( final GameObject hostObject, - final MessageListener messageHandler, - final ParameterSet actParameters, - final ParameterSet configurationParameters ) + public long start( final GameObject hostObject, + final MessageListener messageHandler, + final ParameterSet actParameters, + final ParameterSet configurationParameters ) { hostObject.setPropertyValue( ACTION_INVOKED, true ); - return actParameters.getDouble( REPEAT_INTERVALL, -1 ); + return actParameters.getLong( REPEAT_INTERVALL, -1 ); } - public void stop( final GameObject hostObject, final MessageListener messageHandler ) + public void stop( final GameObject hostObject, + final MessageListener messageHandler, + final ParameterSet parameters, + final ParameterSet configurationParameters, + final long timeSinceLastCall_ms ) { hostObject.setPropertyValue( STOP_CALLED, true ); } - protected double doStep( final GameObject hostObject, - final MessageListener messageHandler, - final ParameterSet parameters, - final ParameterSet configurationParameters, - final double timeSinceLastCall_s ) + public long doStep( final GameObject hostObject, + final MessageListener messageHandler, + final ParameterSet parameters, + final ParameterSet configurationParameters, + final long timeSinceLastCall_ms ) { final int value = hostObject.getPropertyValue( TIMES_CALLED, 0 ) + 1; hostObject.setPropertyValue( TIMES_CALLED, value ); - return parameters.getDouble( REPEAT_INTERVALL, -1 ); + return parameters.getLong( REPEAT_INTERVALL, -1 ); } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.