[skycastle-commits] SF.net SVN: skycastle: [441] trunk/skycastle/modules

  • From: zzorn@xxxxxxxxxxxxxxxxxxxxx
  • To: skycastle-commits@xxxxxxxxxxxxx
  • Date: Sat, 05 Apr 2008 12:04:45 -0700

Revision: 441
          http://skycastle.svn.sourceforge.net/skycastle/?rev=441&view=rev
Author:   zzorn
Date:     2008-04-05 12:04:43 -0700 (Sat, 05 Apr 2008)

Log Message:
-----------
More work on server and client.  Replaced the GameModel with GameObjectContext. 
 The code should compile and tests should be green.

Modified Paths:
--------------
    
trunk/skycastle/modules/client/src/main/java/org/skycastle/client/SkycastleClient.java
    
trunk/skycastle/modules/core/src/main/java/org/skycastle/core/ClientContext.java
    
trunk/skycastle/modules/core/src/main/java/org/skycastle/core/GameObjectId.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/clientside/GameModel.java
    
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/UpdateMessage.java
    
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/action/ActionFinishedMessage.java
    
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/action/ActionInvocationFailedMessage.java
    
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/action/ActionStartedMessage.java
    
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/action/ActionStatusChangeMessage.java
    
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/object/GameObjectAddedMessage.java
    
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/object/GameObjectRemovedMessage.java
    
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/property/PropertyAddedMessage.java
    
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/property/PropertyChangedMessage.java
    
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/property/PropertyRemovedMessage.java
    
trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/negotiation/AbstractProtocolNegotiator.java
    
trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/negotiation/ClientSideProtocolNegotiator.java
    
trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/negotiation/NegotiationStatus.java
    
trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/negotiation/ProtocolNegotiator.java
    
trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/negotiation/ServerSideProtocolNegotiator.java
    
trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/protocols/AbstractProtocol.java
    
trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/protocols/Protocol.java
    
trunk/skycastle/modules/core/src/test/java/org/skycastle/core/AbstractGameObjectActionsTest.java
    
trunk/skycastle/modules/core/src/test/java/org/skycastle/core/AbstractGameObjectPropertiesTest.java
    
trunk/skycastle/modules/core/src/test/java/org/skycastle/core/geometry/space/grid/GridTest.java
    
trunk/skycastle/modules/core/src/test/java/org/skycastle/protocol/negotiation/ProtocolNegotiationTest.java
    
trunk/skycastle/modules/core/src/test/java/org/skycastle/protocol/protocols/SerializationProtocolTest.java
    
trunk/skycastle/modules/server/src/main/java/org/skycastle/server/SkycastleClientSessionHandler.java
    
trunk/skycastle/modules/server/src/main/java/org/skycastle/server/SkycastleServer.java
    
trunk/skycastle/modules/utils/src/main/java/org/skycastle/util/issue/IssueImpl.java

Added Paths:
-----------
    
trunk/skycastle/modules/core/src/main/java/org/skycastle/core/CallbackEvent.java
    
trunk/skycastle/modules/core/src/main/java/org/skycastle/core/DirectReference.java
    
trunk/skycastle/modules/core/src/main/java/org/skycastle/core/GameObjectReference.java
    
trunk/skycastle/modules/core/src/main/java/org/skycastle/core/ObjectReference.java
    
trunk/skycastle/modules/core/src/main/java/org/skycastle/core/PersistentReference.java

Removed Paths:
-------------
    
trunk/skycastle/modules/client/src/main/java/org/skycastle/client/model/AbstractGameModel.java
    
trunk/skycastle/modules/client/src/main/java/org/skycastle/client/model/clientside/
    
trunk/skycastle/modules/client/src/main/java/org/skycastle/client/model/composite/
    
trunk/skycastle/modules/client/src/main/java/org/skycastle/client/model/local/
    
trunk/skycastle/modules/client/src/test/java/org/skycastle/client/model/clientside/
    
trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/AbstractProtocol.java
    
trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/Protocol.java

Modified: 
trunk/skycastle/modules/client/src/main/java/org/skycastle/client/SkycastleClient.java
===================================================================
--- 
trunk/skycastle/modules/client/src/main/java/org/skycastle/client/SkycastleClient.java
      2008-04-05 14:11:05 UTC (rev 440)
+++ 
trunk/skycastle/modules/client/src/main/java/org/skycastle/client/SkycastleClient.java
      2008-04-05 19:04:43 UTC (rev 441)
@@ -4,6 +4,7 @@
 import com.sun.sgs.client.ClientChannelListener;
 import com.sun.sgs.client.simple.SimpleClient;
 import com.sun.sgs.client.simple.SimpleClientListener;
+import org.skycastle.core.GameContext;
 import org.skycastle.messaging.Message;
 import org.skycastle.messaging.updates.UpdateMessage;
 import org.skycastle.protocol.ProtocolException;
@@ -135,7 +136,7 @@
 
                 // Apply the update message to the client side model
                 // TODO: Use cient side GameContext directly instead, and 
specify a namespace prefix for this server and account
-                updateMessage.applyStateChangeToModel();
+                updateMessage.applyStateChangeToModel( 
GameContext.getGameObjectContext() );
             }
             catch ( ProtocolException e )
             {

Deleted: 
trunk/skycastle/modules/client/src/main/java/org/skycastle/client/model/AbstractGameModel.java
===================================================================
--- 
trunk/skycastle/modules/client/src/main/java/org/skycastle/client/model/AbstractGameModel.java
      2008-04-05 14:11:05 UTC (rev 440)
+++ 
trunk/skycastle/modules/client/src/main/java/org/skycastle/client/model/AbstractGameModel.java
      2008-04-05 19:04:43 UTC (rev 441)
@@ -1,92 +0,0 @@
-package org.skycastle.client.model;
-
-import org.skycastle.core.GameObject;
-import org.skycastle.core.GameObjectId;
-import org.skycastle.core.clientside.GameModel;
-import org.skycastle.core.clientside.GameModelListener;
-import org.skycastle.util.ParameterChecker;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Common functionality.
- */
-public abstract class AbstractGameModel
-        implements GameModel
-{
-
-    //======================================================================
-    // Private Fields
-
-    private final List<GameModelListener> myListeners = new 
ArrayList<GameModelListener>();
-
-    private final GameModelListener myListenerDelegate = new 
GameModelListener()
-    {
-
-        public void onGameObjectAdded( final GameObject addedObject )
-        {
-            for ( GameModelListener listener : myListeners )
-            {
-                listener.onGameObjectAdded( addedObject );
-            }
-        }
-
-
-        public void onGameObjectRemoved( final GameObjectId removedObjectId )
-        {
-            for ( GameModelListener listener : myListeners )
-            {
-                listener.onGameObjectRemoved( removedObjectId );
-            }
-        }
-
-    };
-
-    //======================================================================
-    // Public Methods
-
-    //----------------------------------------------------------------------
-    // GameModel Implementation
-
-
-    public final void addGameModelListener( GameModelListener 
addedGameModelListener )
-    {
-        ParameterChecker.checkNotNull( addedGameModelListener, 
"addedGameModelListener" );
-        ParameterChecker.checkNotAlreadyContained( addedGameModelListener, 
myListeners, "myListeners" );
-
-        myListeners.add( addedGameModelListener );
-    }
-
-
-    public final void removeGameModelListener( GameModelListener 
removedGameModelListener )
-    {
-        ParameterChecker.checkNotNull( removedGameModelListener, 
"removedGameModelListener" );
-        ParameterChecker.checkContained( removedGameModelListener, 
myListeners, "myListeners" );
-
-        myListeners.remove( removedGameModelListener );
-    }
-
-    //======================================================================
-    // Protected Methods
-
-    //----------------------------------------------------------------------
-    // Protected Constructors
-
-    /**
-     * Creates a new {@link AbstractGameModel}.
-     */
-    protected AbstractGameModel()
-    {
-    }
-
-
-    /**
-     * @return a listener that will forward any events to all registered 
listeners.
-     */
-    protected final GameModelListener getListenerDelegate()
-    {
-        return myListenerDelegate;
-    }
-
-}

Added: 
trunk/skycastle/modules/core/src/main/java/org/skycastle/core/CallbackEvent.java
===================================================================
--- 
trunk/skycastle/modules/core/src/main/java/org/skycastle/core/CallbackEvent.java
                            (rev 0)
+++ 
trunk/skycastle/modules/core/src/main/java/org/skycastle/core/CallbackEvent.java
    2008-04-05 19:04:43 UTC (rev 441)
@@ -0,0 +1,63 @@
+package org.skycastle.core;
+
+/**
+ * Represents a future callback that needs to be done to a specific {@link 
GameObject}.
+ *
+ * @author Hans Häggström
+ */
+class CallbackEvent
+        implements Comparable<CallbackEvent>
+{
+
+    //======================================================================
+    // Private Fields
+
+    private final long myTime;
+    private final GameObject myGameObject;
+
+    //======================================================================
+    // Public Methods
+
+    //----------------------------------------------------------------------
+    // Comparable Implementation
+
+    public int compareTo( final CallbackEvent o )
+    {
+        if ( myTime < o.getTime() )
+        {
+            return -1;
+        }
+        else if ( myTime > o.getTime() )
+        {
+            return 1;
+        }
+        else
+        {
+            return 0;
+        }
+    }
+
+    //----------------------------------------------------------------------
+    // Other Public Methods
+
+    public long getTime()
+    {
+        return myTime;
+    }
+
+
+    public GameObject getGameObject()
+    {
+        return myGameObject;
+    }
+
+    //======================================================================
+    // Private Methods
+
+    protected CallbackEvent( final GameObject gameObject, final long time )
+    {
+        myGameObject = gameObject;
+        myTime = time;
+    }
+
+}

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-04-05 14:11:05 UTC (rev 440)
+++ 
trunk/skycastle/modules/core/src/main/java/org/skycastle/core/ClientContext.java
    2008-04-05 19:04:43 UTC (rev 441)
@@ -1,9 +1,16 @@
 package org.skycastle.core;
 
-import org.skycastle.core.clientside.GameModel;
 import org.skycastle.util.ParameterChecker;
+import org.skycastle.util.issue.Issue;
+import org.skycastle.util.issue.IssueImpl;
+import org.skycastle.util.issue.IssueListener;
+import org.skycastle.util.issue.Severity;
 
+import java.util.*;
+
 /**
+ * A client side implementation of {@link GameObjectContext}.
+ *
  * @author Hans Häggström
  */
 public class ClientContext
@@ -13,9 +20,11 @@
     //======================================================================
     // Private Fields
 
-    private final GameModel myGameModel;
+    private final Map<GameObjectId, GameObject> myGameObjects = new 
HashMap<GameObjectId, GameObject>( 1001 );
+    private final Queue<CallbackEvent> myEvents = new 
PriorityQueue<CallbackEvent>();
+    private final Set<IssueListener> myIssueListeners = new 
HashSet<IssueListener>( 5 );
 
-    private GameObjectId myId;
+    private long myInGameClock_ms = 0L;
 
     //======================================================================
     // Public Methods
@@ -24,42 +33,182 @@
     // Constructors
 
     /**
-     * Creates a new {@link org.skycastle.core.ClientContext}.
+     * Creates a new {@link ClientContext}.
+     * <p/>
+     * The in-game time starts at 0.
      */
-    public ClientContext( final GameModel gameModel, final GameObjectId id )
+    public ClientContext()
     {
-        myId = id;
-        ParameterChecker.checkNotNull( gameModel, "gameModel" );
-        ParameterChecker.checkNotNull( id, "id" );
+    }
 
-        myGameModel = gameModel;
+
+    /**
+     * Creates a new {@link ClientContext}.
+     *
+     * @param inGameClock_ms starting value for the in-game time in 
milliseconds since in-game epoch.
+     */
+    public ClientContext( final long inGameClock_ms )
+    {
+        myInGameClock_ms = inGameClock_ms;
     }
 
+
+    /**
+     * Creates a new {@link ClientContext}.
+     *
+     * @param inGameClock_ms starting value for the in-game time in 
milliseconds since in-game epoch.
+     * @param issueListener  an {@link IssueListener} to register with this 
{@link ClientContext}.¨ It will be
+     *                       notified of any problems, such as exceptions when 
calling scheduled callbacks.
+     */
+    public ClientContext( final long inGameClock_ms, final IssueListener 
issueListener )
+    {
+        this( inGameClock_ms );
+
+        addIssueListener( issueListener );
+    }
+
     //----------------------------------------------------------------------
     // GameObjectContext Implementation
 
+    public final GameObjectId createGameObjectId( final GameObject gameObject )
+    {
+        // IMPLEMENT: TODO: How should we create the ID?  For client side 
GameObjects, we need some specific prefix...
+        // DEBUG
+        return new GameObjectId( GameObjectId.GAME_OBJECT_BINDING_PREFIX + 
String.valueOf( gameObject.hashCode() ) );
+    }
 
-    public GameObjectId createGameObjectId( final GameObject gameObject )
+
+    public final void addTaskCallback( final long timeOfCallback_ms, final 
GameObject gameObject )
     {
-        return myId;
+        myEvents.add( new CallbackEvent( gameObject, timeOfCallback_ms ) );
     }
 
 
-    public void addTaskCallback( final long timeToNextInvocation_ms, final 
GameObject gameObject )
+    public final GameObject getGameObjectById( final GameObjectId gameObjectId,
+                                               final boolean forModification )
     {
-        throw new UnsupportedOperationException( "This method has not yet been 
implemented." ); // IMPLEMENT
+        return myGameObjects.get( gameObjectId );
     }
 
 
-    public GameObject getGameObjectById( final GameObjectId gameObjectId, 
final boolean forModification )
+    public final long getCurrentGameTime_ms()
     {
-        return myGameModel.getGameObject( gameObjectId );
+        return myInGameClock_ms;
     }
 
+    //----------------------------------------------------------------------
+    // Other Public Methods
 
-    public long getCurrentGameTime_ms()
+    /**
+     * @param gameObject the {@link GameObject} to add to this {@link 
ClientContext}.
+     */
+    public final void addGameObject( final GameObject gameObject )
     {
-        throw new UnsupportedOperationException( "This method has not yet been 
implemented." ); // IMPLEMENT
+        ParameterChecker.checkNotNull( gameObject, "gameObject" );
+
+        myGameObjects.put( gameObject.getId(), gameObject );
     }
 
+
+    /**
+     * @param gameObject the {@link GameObject} to remove from this {@link 
ClientContext}.
+     */
+    public final void removeGameObject( final GameObjectId gameObject )
+    {
+        ParameterChecker.checkNotNull( gameObject, "gameObject" );
+
+        myGameObjects.remove( gameObject );
+    }
+
+
+    /**
+     * Adds the specified {@link IssueListener}.
+     *
+     * @param addedIssueListener A listener that is notified about any errors, 
warnings, and other issues that
+     *                           are detected during client operation, such as 
exceptions when calling
+     *                           scheduled callbacks.   Should not be null or 
already added.
+     */
+    public final void addIssueListener( final IssueListener addedIssueListener 
)
+    {
+        ParameterChecker.checkNotNull( addedIssueListener, 
"addedIssueListener" );
+        ParameterChecker.checkNotAlreadyContained( addedIssueListener, 
myIssueListeners, "myIssueListeners" );
+
+        myIssueListeners.add( addedIssueListener );
+    }
+
+
+    /**
+     * Removes the specified {@link IssueListener}.
+     *
+     * @param removedIssueListener should not be null, and should be present.
+     */
+    public final void removeIssueListener( final IssueListener 
removedIssueListener )
+    {
+        ParameterChecker.checkNotNull( removedIssueListener, 
"removedIssueListener" );
+        ParameterChecker.checkContained( removedIssueListener, 
myIssueListeners, "myIssueListeners" );
+
+        myIssueListeners.remove( removedIssueListener );
+    }
+
+
+    /**
+     * Increases the in-game time with the specied number of milliseconds, and 
calls any scheduled callbacks.
+     * <p/>
+     * If there are problems running any of the tasks, an issue is filed that 
is visible to the registered
+     * {@link IssueListener}s.
+     *
+     * @param timeIntervallToAdvance_ms number of in-game milliseconds to 
advance the time.
+     */
+    public final void advanceTimeAndCallCallbacks( final long 
timeIntervallToAdvance_ms )
+    {
+        setTimeAndCallCallbacks( myInGameClock_ms + timeIntervallToAdvance_ms 
);
+    }
+
+
+    /**
+     * Sets the in-game time to a specified value and calls any scheduled 
callbacks. All callbacks that are
+     * scheduled at the current time or in the past will be called.
+     * <p/>
+     * If there are problems running any of the tasks, an issue is filed that 
is visible to the registered
+     * {@link IssueListener}s.
+     *
+     * @param newTime_ms the new in-game time to use, specified as in-game 
milliseconds since in-game epoch.
+     */
+    public final void setTimeAndCallCallbacks( final long newTime_ms )
+    {
+        myInGameClock_ms = newTime_ms;
+
+        while ( myEvents.peek() != null &&
+                myEvents.peek().getTime() <= myInGameClock_ms )
+        {
+            final GameObject gameObject = myEvents.poll().getGameObject();
+
+            try
+            {
+                gameObject.run();
+            }
+            catch ( Exception e )
+            {
+                final Issue issue = new IssueImpl(
+                        "Problem when calling a client side task callback on 
the game object '" + gameObject + "'.",
+                        e,
+                        Severity.ERROR,
+                        "TaskCallbackException" );
+
+                reportIssue( issue );
+            }
+        }
+    }
+
+    //======================================================================
+    // Private Methods
+
+    private void reportIssue( final Issue issue )
+    {
+        for ( final IssueListener issueListener : myIssueListeners )
+        {
+            issueListener.onIssue( issue );
+        }
+    }
+
 }

Added: 
trunk/skycastle/modules/core/src/main/java/org/skycastle/core/DirectReference.java
===================================================================
--- 
trunk/skycastle/modules/core/src/main/java/org/skycastle/core/DirectReference.java
                          (rev 0)
+++ 
trunk/skycastle/modules/core/src/main/java/org/skycastle/core/DirectReference.java
  2008-04-05 19:04:43 UTC (rev 441)
@@ -0,0 +1,49 @@
+package org.skycastle.core;
+
+/**
+ * A simple direct reference, useful for client side and unit testing 
contexts, where we don't need to take
+ * into account multi-node issues or persistency.
+ *
+ * @author Hans Häggström
+ */
+public final class DirectReference<T>
+        implements ObjectReference<T>
+{
+
+    //======================================================================
+    // Private Fields
+
+    private final T myReferencedObject;
+
+    //======================================================================
+    // Public Methods
+
+    //----------------------------------------------------------------------
+    // Constructors
+
+    /**
+     * Creates a new {@link org.skycastle.core.DirectReference}.
+     *
+     * @param objectToBeReferenced the object to reference to.
+     */
+    public DirectReference( final T objectToBeReferenced )
+    {
+        myReferencedObject = objectToBeReferenced;
+    }
+
+    //----------------------------------------------------------------------
+    // ObjectReference Implementation
+
+
+    public T getForReading()
+    {
+        return myReferencedObject;
+    }
+
+
+    public T getForWriting()
+    {
+        return myReferencedObject;
+    }
+
+}

Modified: 
trunk/skycastle/modules/core/src/main/java/org/skycastle/core/GameObjectId.java
===================================================================
--- 
trunk/skycastle/modules/core/src/main/java/org/skycastle/core/GameObjectId.java 
    2008-04-05 14:11:05 UTC (rev 440)
+++ 
trunk/skycastle/modules/core/src/main/java/org/skycastle/core/GameObjectId.java 
    2008-04-05 19:04:43 UTC (rev 441)
@@ -9,6 +9,7 @@
  */
 // TODO: Use the ID used by managed objects? - no way to get object by id, 
only by binding a string name to it.
 // IDEA: Could keep track also of on which server or client the object is?
+// IDEA: Merge with GameObjectReference??    
 public final class GameObjectId
         implements Serializable
 {
@@ -19,6 +20,15 @@
     private final String myBoundName;
 
     //======================================================================
+    // Public Constants
+
+    /**
+     * The prefix to use for all {@link GameObject} identifiers.  Allows other 
parts of the binding name space
+     * to be used for other purposes .
+     */
+    public static final String GAME_OBJECT_BINDING_PREFIX = "GameObject_";
+
+    //======================================================================
     // Private Constants
 
     private static final long serialVersionUID = 1L;
@@ -36,34 +46,39 @@
     {
         ParameterChecker.checkIsIdentifier( boundGameObjectName, 
"boundGameObjectName" );
 
+        if ( !boundGameObjectName.startsWith( GAME_OBJECT_BINDING_PREFIX ) )
+        {
+            throw new IllegalArgumentException( "The GameObjectId should 
should start with '" + GAME_OBJECT_BINDING_PREFIX + "', but it was '" + 
boundGameObjectName + "'." );
+        }
+
         myBoundName = boundGameObjectName;
     }
 
     //----------------------------------------------------------------------
-    // Other Public Methods
-
-    //----------------------------------------------------------------------
     // Caononical Methods
 
+    @Override
     public String toString()
     {
         return myBoundName;
     }
 
 
-    public boolean equals( final Object o )
+    @Override
+    public boolean equals( final Object obj )
     {
-        if ( this == o )
+        if ( this == obj )
         {
             return true;
         }
-        if ( o == null || getClass() != o.getClass() )
+        if ( obj == null || getClass() != obj.getClass() )
         {
             return false;
         }
 
-        final GameObjectId that = (GameObjectId) o;
+        final GameObjectId that = (GameObjectId) obj;
 
+        //noinspection 
RedundantIfStatement,AccessingNonPublicFieldOfAnotherObject
         if ( myBoundName != null ? !myBoundName.equals( that.myBoundName ) : 
that.myBoundName != null )
         {
             return false;
@@ -73,9 +88,10 @@
     }
 
 
+    @Override
     public int hashCode()
     {
-        return ( myBoundName != null ? myBoundName.hashCode() : 0 );
+        return myBoundName != null ? myBoundName.hashCode() : 0;
     }
 
 }

Added: 
trunk/skycastle/modules/core/src/main/java/org/skycastle/core/GameObjectReference.java
===================================================================
--- 
trunk/skycastle/modules/core/src/main/java/org/skycastle/core/GameObjectReference.java
                              (rev 0)
+++ 
trunk/skycastle/modules/core/src/main/java/org/skycastle/core/GameObjectReference.java
      2008-04-05 19:04:43 UTC (rev 441)
@@ -0,0 +1,36 @@
+package org.skycastle.core;
+
+/**
+ * A reference to a {@link GameObject}.  The reference can be serialized and 
persisted on the server side.
+ *
+ * @author Hans Häggström
+ */
+// IDEA: Could GameObjectId and GameObjectReference be combined?  They seem to 
have more or less the same
+// purpose, although GameObjectId is backed up by bindings, and works on both 
server and client side,
+// while GameObjectReference is backed up by a ManagedObjectReference and only 
works on server side..
+public class GameObjectReference
+        extends PersistentReference<GameObject>
+{
+
+    //======================================================================
+    // Private Constants
+
+    private static final long serialVersionUID = 1L;
+
+    //======================================================================
+    // Public Methods
+
+    //----------------------------------------------------------------------
+    // Constructors
+
+    /**
+     * Creates a new {@link org.skycastle.core.GameObjectReference} to the 
specified {@link GameObject}.
+     *
+     * @param gameObject the {@link GameObject} to create a reference to.
+     */
+    public GameObjectReference( final GameObject gameObject )
+    {
+        super( gameObject );
+    }
+
+}

Added: 
trunk/skycastle/modules/core/src/main/java/org/skycastle/core/ObjectReference.java
===================================================================
--- 
trunk/skycastle/modules/core/src/main/java/org/skycastle/core/ObjectReference.java
                          (rev 0)
+++ 
trunk/skycastle/modules/core/src/main/java/org/skycastle/core/ObjectReference.java
  2008-04-05 19:04:43 UTC (rev 441)
@@ -0,0 +1,25 @@
+package org.skycastle.core;
+
+import java.io.Serializable;
+
+/**
+ * Reference to some object, which can be retrieved either for reading or 
reading and writing.
+ *
+ * @author Hans Häggström
+ */
+public interface ObjectReference<T>
+        extends Serializable
+{
+
+    /**
+     * @return the referenced object.  The object should only be read from.
+     */
+    T getForReading();
+
+    /**
+     * @return the referenced object.  The object can be read from and written 
to. Note that using this if the
+     *         object is only read from is bad for the performance, as reads 
can be done in parallell, but not
+     *         writes.
+     */
+    T getForWriting();
+}

Added: 
trunk/skycastle/modules/core/src/main/java/org/skycastle/core/PersistentReference.java
===================================================================
--- 
trunk/skycastle/modules/core/src/main/java/org/skycastle/core/PersistentReference.java
                              (rev 0)
+++ 
trunk/skycastle/modules/core/src/main/java/org/skycastle/core/PersistentReference.java
      2008-04-05 19:04:43 UTC (rev 441)
@@ -0,0 +1,68 @@
+package org.skycastle.core;
+
+import com.sun.sgs.app.AppContext;
+import com.sun.sgs.app.ManagedObject;
+import com.sun.sgs.app.ManagedReference;
+
+import java.io.Serializable;
+
+/**
+ * A reference to a persistent {@link ManagedObject} on the server, that uses 
generics to maintain the type of
+ * the object during compile time, to enable better correctness checking.
+ * <p/>
+ * Wraps a {@link ManagedReference}.
+ *
+ * @author Hans Häggström
+ * @type T the type of the wrapped object.
+ */
+public class PersistentReference<T extends ManagedObject>
+        implements ObjectReference<T>, Serializable
+{
+
+    //======================================================================
+    // Private Fields
+
+    private final ManagedReference myManagedReference;
+
+    //======================================================================
+    // Private Constants
+
+    private static final long serialVersionUID = 1L;
+
+    //======================================================================
+    // Public Methods
+
+    //----------------------------------------------------------------------
+    // Constructors
+
+    /**
+     * Creates a new {@link PersistentReference}.
+     *
+     * @param objectToReference the {@link ManagedObject} to create a 
reference to.
+     */
+    public PersistentReference( final T objectToReference )
+    {
+        myManagedReference = AppContext.getDataManager().createReference( 
objectToReference );
+    }
+
+    //----------------------------------------------------------------------
+    // ObjectReference Implementation
+
+    /**
+     * @return the referenced object.  The object should preferably only be 
read from. It can be written to
+     *         also, but that will result in slower code than if getForWriting 
had been called instead.
+     */
+    public T getForReading()
+    {
+        //noinspection unchecked
+        return (T) myManagedReference.get( Object.class );
+    }
+
+
+    public T getForWriting()
+    {
+        //noinspection unchecked
+        return (T) myManagedReference.getForUpdate( Object.class );
+    }
+
+}

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-04-05 14:11:05 UTC (rev 440)
+++ 
trunk/skycastle/modules/core/src/main/java/org/skycastle/core/ServerSideContext.java
        2008-04-05 19:04:43 UTC (rev 441)
@@ -35,7 +35,7 @@
     }
 
 
-    public void addTaskCallback( final long timeToNextInvocation_ms, final 
GameObject gameObject )
+    public void addTaskCallback( final long timeOfCallback_ms, final 
GameObject gameObject )
     {
         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-04-05 14:11:05 UTC (rev 440)
+++ 
trunk/skycastle/modules/core/src/main/java/org/skycastle/core/UnitTestingContext.java
       2008-04-05 19:04:43 UTC (rev 441)
@@ -1,125 +1,37 @@
 package org.skycastle.core;
 
-import java.util.PriorityQueue;
-import java.util.Queue;
+import junit.framework.Assert;
+import org.skycastle.util.issue.Issue;
+import org.skycastle.util.issue.IssueListener;
 
 /**
  * A {@link GameObjectContext} used for unit testing.
+ * <p/>
+ * Works like a {@link ClientContext}, but fails directly when an issue is 
reported.
  *
  * @author Hans Häggström
  */
-public class UnitTestingContext
-        implements GameObjectContext
+public final class UnitTestingContext
+        extends ClientContext
 {
 
-    //======================================================================
-    // Private Fields
-
-    private final Queue<CallbackEvent> myEvents = new 
PriorityQueue<CallbackEvent>();
-
-    private long myInGameClock_ms = 0;
-
-    //======================================================================
-    // Public Methods
-
     //----------------------------------------------------------------------
-    // GameObjectContext Implementation
+    // Constructors
 
-    public GameObjectId createGameObjectId( final GameObject gameObject )
+    /**
+     * Creates a {@link UnitTestingContext}.
+     */
+    public UnitTestingContext()
     {
-        return new GameObjectId( "TestGameObject" + String.valueOf( 
gameObject.hashCode() ) );
-    }
-
-
-    public void addTaskCallback( final long timeOfCallback_ms, final 
GameObject gameObject )
-    {
-        myEvents.add( new CallbackEvent( gameObject, timeOfCallback_ms ) );
-    }
-
-
-    public GameObject getGameObjectById( final GameObjectId gameObjectId, 
final boolean forModification )
-    {
-        throw new UnsupportedOperationException( "This method has not yet been 
implemented." ); // IMPLEMENT
-    }
-
-
-    public long getCurrentGameTime_ms()
-    {
-        return myInGameClock_ms;
-    }
-
-    //----------------------------------------------------------------------
-    // Other Public Methods
-
-    public void advanceTimeAndCallCallbacks( final long 
timeIntervallToAdvance_ms ) throws Exception
-    {
-        myInGameClock_ms += timeIntervallToAdvance_ms;
-
-        while ( myEvents.peek() != null &&
-                myEvents.peek().getTime() <= myInGameClock_ms )
+        super( 0L, new IssueListener()
         {
-            myEvents.poll().getGameObject().run();
-        }
-    }
 
-    //======================================================================
-    // Inner Classes
-
-    private class CallbackEvent
-            implements Comparable<CallbackEvent>
-    {
-
-        
//======================================================================
-        // Private Fields
-
-        private final long myTime;
-        private final GameObject myGameObject;
-
-        
//======================================================================
-        // Public Methods
-
-        
//----------------------------------------------------------------------
-        // Comparable Implementation
-
-        public int compareTo( final CallbackEvent o )
-        {
-            if ( myTime < o.getTime() )
+            public void onIssue( final Issue issue )
             {
-                return -1;
+                Assert.fail( issue.toString() );
             }
-            else if ( myTime > o.getTime() )
-            {
-                return 1;
-            }
-            else
-            {
-                return 0;
-            }
-        }
 
-        
//----------------------------------------------------------------------
-        // Other Public Methods
-
-        public long getTime()
-        {
-            return myTime;
-        }
-
-
-        public GameObject getGameObject()
-        {
-            return myGameObject;
-        }
-
-        
//======================================================================
-        // Private Methods
-
-        private CallbackEvent( final GameObject gameObject, final long time )
-        {
-            myGameObject = gameObject;
-            myTime = time;
-        }
-
+        } );
     }
 
 }

Modified: 
trunk/skycastle/modules/core/src/main/java/org/skycastle/core/clientside/GameModel.java
===================================================================
--- 
trunk/skycastle/modules/core/src/main/java/org/skycastle/core/clientside/GameModel.java
     2008-04-05 14:11:05 UTC (rev 440)
+++ 
trunk/skycastle/modules/core/src/main/java/org/skycastle/core/clientside/GameModel.java
     2008-04-05 19:04:43 UTC (rev 441)
@@ -25,17 +25,4 @@
      */
     void removeGameObject( GameObjectId gameObjectId );
 
-    /**
-     * Adds the specified GameModelListener.
-     *
-     * @param addedGameModelListener should not be null or already added.
-     */
-    void addGameModelListener( GameModelListener addedGameModelListener );
-
-    /**
-     * Removes the specified GameModelListener.
-     *
-     * @param removedGameModelListener should not be null, and should be 
present.
-     */
-    void removeGameModelListener( GameModelListener removedGameModelListener );
 }

Modified: 
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/UpdateMessage.java
===================================================================
--- 
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/UpdateMessage.java
       2008-04-05 14:11:05 UTC (rev 440)
+++ 
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/UpdateMessage.java
       2008-04-05 19:04:43 UTC (rev 441)
@@ -1,6 +1,8 @@
 package org.skycastle.messaging.updates;
 
 import org.skycastle.core.GameObject;
+import org.skycastle.core.GameObjectContext;
+import org.skycastle.core.GameObjectId;
 import org.skycastle.core.clientside.GameModel;
 import org.skycastle.messaging.AbstractMessage;
 import org.skycastle.messaging.Message;
@@ -15,13 +17,17 @@
 public interface UpdateMessage
         extends Message
 {
+
     /**
      * Applies this update to a {@link GameModel}.
      * <p/>
      * Typically used on the client data model, which consists of proxy 
objects that should mirror the state
      * of the real objects on the server side.
      *
-     * @param gameModel The {@link GameModel} to update.
+     * @param gameObjectContext A {@link GameObjectContext} that provides 
methods to access {@link
+     *                          GameObject}s by {@link GameObjectId}s and do 
other modifications to the local
+     *                          data model.
      */
-    void applyStateChangeToModel( final GameModel gameModel );
+    void applyStateChangeToModel( final GameObjectContext gameObjectContext );
+
 }

Modified: 
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/action/ActionFinishedMessage.java
===================================================================
--- 
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/action/ActionFinishedMessage.java
        2008-04-05 14:11:05 UTC (rev 440)
+++ 
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/action/ActionFinishedMessage.java
        2008-04-05 19:04:43 UTC (rev 441)
@@ -1,12 +1,13 @@
 package org.skycastle.messaging.updates.action;
 
+import org.skycastle.core.GameObjectContext;
 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}.
+ * If the action is immediate, no separate {@link ActionStartedMessage} will 
be sent, just an {@link
+ * ActionFinishedMessage}.
  *
  * @author Hans H�ggstr�m
  */
@@ -26,7 +27,9 @@
     //----------------------------------------------------------------------
     // Constructors
 
-    public ActionFinishedMessage( final GameObjectId updatedObjectId, final 
String memberIdentifier, final long actId )
+    public ActionFinishedMessage( final GameObjectId updatedObjectId,
+                                  final String memberIdentifier,
+                                  final long actId )
     {
         super( updatedObjectId, memberIdentifier, actId );
     }
@@ -34,9 +37,9 @@
     //----------------------------------------------------------------------
     // UpdateMessage Implementation
 
-    public void applyStateChangeToModel( final GameModel gameModel )
+    public void applyStateChangeToModel( final GameObjectContext 
gameObjectContext )
     {
         throw new UnsupportedOperationException( "This method has not yet been 
implemented." ); // IMPLEMENT
+
     }
-
 }

Modified: 
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/action/ActionInvocationFailedMessage.java
===================================================================
--- 
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/action/ActionInvocationFailedMessage.java
        2008-04-05 14:11:05 UTC (rev 440)
+++ 
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/action/ActionInvocationFailedMessage.java
        2008-04-05 19:04:43 UTC (rev 441)
@@ -1,10 +1,11 @@
 package org.skycastle.messaging.updates.action;
 
+import org.skycastle.core.GameObjectContext;
 import org.skycastle.core.GameObjectId;
-import org.skycastle.core.clientside.GameModel;
 
 /**
- * Indicates that an {@link 
org.skycastle.messaging.modifications.action.InvokeActionMessage} failed for 
some reason.
+ * Indicates that an {@link 
org.skycastle.messaging.modifications.action.InvokeActionMessage} failed for 
some
+ * reason.
  *
  * @author Hans H�ggstr�m
  */
@@ -41,9 +42,10 @@
     // UpdateMessage Implementation
 
 
-    public void applyStateChangeToModel( final GameModel gameModel )
+    public void applyStateChangeToModel( final GameObjectContext 
gameObjectContext )
     {
         throw new UnsupportedOperationException( "This method has not yet been 
implemented." ); // IMPLEMENT
+
     }
 
     //----------------------------------------------------------------------

Modified: 
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/action/ActionStartedMessage.java
===================================================================
--- 
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/action/ActionStartedMessage.java
 2008-04-05 14:11:05 UTC (rev 440)
+++ 
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/action/ActionStartedMessage.java
 2008-04-05 19:04:43 UTC (rev 441)
@@ -1,7 +1,7 @@
 package org.skycastle.messaging.updates.action;
 
+import org.skycastle.core.GameObjectContext;
 import org.skycastle.core.GameObjectId;
-import org.skycastle.core.clientside.GameModel;
 
 /**
  * @author Hans H�ggstr�m
@@ -21,7 +21,9 @@
     //----------------------------------------------------------------------
     // Constructors
 
-    public ActionStartedMessage( final GameObjectId updatedObjectId, final 
String memberIdentifier, final long actId )
+    public ActionStartedMessage( final GameObjectId updatedObjectId,
+                                 final String memberIdentifier,
+                                 final long actId )
     {
         super( updatedObjectId, memberIdentifier, actId );
     }
@@ -29,10 +31,11 @@
     //----------------------------------------------------------------------
     // UpdateMessage Implementation
 
-
-    public void applyStateChangeToModel( final GameModel gameModel )
+    public void applyStateChangeToModel( final GameObjectContext 
gameObjectContext )
     {
         throw new UnsupportedOperationException( "This method has not yet been 
implemented." ); // IMPLEMENT
+
     }
 
+
 }

Modified: 
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/action/ActionStatusChangeMessage.java
===================================================================
--- 
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/action/ActionStatusChangeMessage.java
    2008-04-05 14:11:05 UTC (rev 440)
+++ 
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/action/ActionStatusChangeMessage.java
    2008-04-05 19:04:43 UTC (rev 441)
@@ -1,7 +1,7 @@
 package org.skycastle.messaging.updates.action;
 
+import org.skycastle.core.GameObjectContext;
 import org.skycastle.core.GameObjectId;
-import org.skycastle.core.clientside.GameModel;
 import org.skycastle.util.parameters.ValidationError;
 
 import java.util.Set;
@@ -67,11 +67,11 @@
     // UpdateMessage Implementation
 
 
-    public void applyStateChangeToModel( final GameModel gameModel )
+    public void applyStateChangeToModel( final GameObjectContext 
gameObjectContext )
     {
         throw new UnsupportedOperationException( "This method has not yet been 
implemented." ); // IMPLEMENT
+
     }
-
     //----------------------------------------------------------------------
     // Other Public Methods
 

Modified: 
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/object/GameObjectAddedMessage.java
===================================================================
--- 
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/object/GameObjectAddedMessage.java
       2008-04-05 14:11:05 UTC (rev 440)
+++ 
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/object/GameObjectAddedMessage.java
       2008-04-05 19:04:43 UTC (rev 441)
@@ -1,9 +1,8 @@
 package org.skycastle.messaging.updates.object;
 
 import org.skycastle.core.GameObject;
+import org.skycastle.core.GameObjectContext;
 import org.skycastle.core.GameObjectId;
-import org.skycastle.core.clientside.GameModel;
-import org.skycastle.core.clientside.ProxyGameObject;
 import org.skycastle.messaging.AbstractMessage;
 import org.skycastle.messaging.updates.UpdateMessage;
 import org.skycastle.util.ParameterChecker;
@@ -17,6 +16,13 @@
  * Any available properties, actions, etc. will be indicated with further 
update messages.
  *
  * @author Hans Haggstrom
+ * @deprecated This is not really needed.  The client only needs the root 
account object, after that all game
+ *             objects can be accessed through it.
+ *             <p/>
+ *             TODO: We do need messages to notify collection properties about 
added and removed entries
+ *             though, without having to resend the whole collection.
+ *             <p/>
+ *             Maybe change these messages to work on collection properties of 
GameObjects instead?
  */
 public final class GameObjectAddedMessage
         extends AbstractMessage
@@ -55,7 +61,6 @@
     //----------------------------------------------------------------------
     // Message Implementation
 
-
     @Override
     public ValidationError validate( final Set<String> allowedContainedTypes, 
final String errorPrefix )
     {
@@ -72,12 +77,9 @@
     //----------------------------------------------------------------------
     // UpdateMessage Implementation
 
-
-    public void applyStateChangeToModel( final GameModel gameModel )
+    public void applyStateChangeToModel( final GameObjectContext 
gameObjectContext )
     {
-        ParameterChecker.checkNotNull( gameModel, "gameModel" );
+        throw new UnsupportedOperationException( "This method has not yet been 
implemented." ); // IMPLEMENT
 
-        gameModel.addGameObject( new ProxyGameObject( myAddedObjectId ) );
     }
-
 }

Modified: 
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/object/GameObjectRemovedMessage.java
===================================================================
--- 
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/object/GameObjectRemovedMessage.java
     2008-04-05 14:11:05 UTC (rev 440)
+++ 
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/object/GameObjectRemovedMessage.java
     2008-04-05 19:04:43 UTC (rev 441)
@@ -1,7 +1,7 @@
 package org.skycastle.messaging.updates.object;
 
+import org.skycastle.core.GameObjectContext;
 import org.skycastle.core.GameObjectId;
-import org.skycastle.core.clientside.GameModel;
 import org.skycastle.messaging.AbstractMessage;
 import org.skycastle.messaging.updates.UpdateMessage;
 import org.skycastle.util.ParameterChecker;
@@ -13,6 +13,7 @@
  * A message to indicate that the specified GameObject is no longer available 
for the client.
  *
  * @author Hans Haggstrom
+ * @deprecated This is not really needed.
  */
 public final class GameObjectRemovedMessage
         extends AbstractMessage
@@ -68,12 +69,11 @@
     //----------------------------------------------------------------------
     // UpdateMessage Implementation
 
-
-    public void applyStateChangeToModel( final GameModel gameModel )
+    public void applyStateChangeToModel( final GameObjectContext 
gameObjectContext )
     {
-        ParameterChecker.checkNotNull( gameModel, "gameModel" );
+        throw new UnsupportedOperationException( "This method has not yet been 
implemented." ); // IMPLEMENT
 
-        gameModel.removeGameObject( myRemovedObjectId );
     }
 
+
 }

Modified: 
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/property/PropertyAddedMessage.java
===================================================================
--- 
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/property/PropertyAddedMessage.java
       2008-04-05 14:11:05 UTC (rev 440)
+++ 
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/property/PropertyAddedMessage.java
       2008-04-05 19:04:43 UTC (rev 441)
@@ -1,7 +1,7 @@
 package org.skycastle.messaging.updates.property;
 
+import org.skycastle.core.GameObjectContext;
 import org.skycastle.core.GameObjectId;
-import org.skycastle.core.clientside.GameModel;
 import org.skycastle.messaging.updates.MemberUpdateMessage;
 import org.skycastle.util.ParameterChecker;
 import org.skycastle.util.parameters.ParameterMetadata;
@@ -79,9 +79,10 @@
     //----------------------------------------------------------------------
     // UpdateMessage Implementation
 
-    public void applyStateChangeToModel( final GameModel gameModel )
+    public void applyStateChangeToModel( final GameObjectContext 
gameObjectContext )
     {
         throw new UnsupportedOperationException( "This method has not yet been 
implemented." ); // IMPLEMENT
+
     }
 
     //----------------------------------------------------------------------

Modified: 
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/property/PropertyChangedMessage.java
===================================================================
--- 
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/property/PropertyChangedMessage.java
     2008-04-05 14:11:05 UTC (rev 440)
+++ 
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/property/PropertyChangedMessage.java
     2008-04-05 19:04:43 UTC (rev 441)
@@ -1,7 +1,7 @@
 package org.skycastle.messaging.updates.property;
 
+import org.skycastle.core.GameObjectContext;
 import org.skycastle.core.GameObjectId;
-import org.skycastle.core.clientside.GameModel;
 import org.skycastle.messaging.updates.MemberUpdateMessage;
 import org.skycastle.util.parameters.ValidationError;
 
@@ -32,7 +32,7 @@
     //----------------------------------------------------------------------
     // Constructors
 
-    public void applyStateChangeToModel( final GameModel gameModel )
+    public void applyStateChangeToModel( final GameObjectContext 
gameObjectContext )
     {
         throw new UnsupportedOperationException( "This method has not yet been 
implemented." ); // IMPLEMENT
 

Modified: 
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/property/PropertyRemovedMessage.java
===================================================================
--- 
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/property/PropertyRemovedMessage.java
     2008-04-05 14:11:05 UTC (rev 440)
+++ 
trunk/skycastle/modules/core/src/main/java/org/skycastle/messaging/updates/property/PropertyRemovedMessage.java
     2008-04-05 19:04:43 UTC (rev 441)
@@ -1,8 +1,8 @@
 package org.skycastle.messaging.updates.property;
 
 import org.skycastle.core.GameObject;
+import org.skycastle.core.GameObjectContext;
 import org.skycastle.core.GameObjectId;
-import org.skycastle.core.clientside.GameModel;
 import org.skycastle.messaging.updates.MemberUpdateMessage;
 
 /**
@@ -34,9 +34,10 @@
         super( updatedObjectId, propertyName );
     }
 
-    public void applyStateChangeToModel( final GameModel gameModel )
+    public void applyStateChangeToModel( final GameObjectContext 
gameObjectContext )
     {
         throw new UnsupportedOperationException( "This method has not yet been 
implemented." ); // IMPLEMENT
 
     }
+
 }

Deleted: 
trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/AbstractProtocol.java
===================================================================
--- 
trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/AbstractProtocol.java
     2008-04-05 14:11:05 UTC (rev 440)
+++ 
trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/AbstractProtocol.java
     2008-04-05 19:04:43 UTC (rev 441)
@@ -1,50 +0,0 @@
-package org.skycastle.protocol;
-
-import org.skycastle.util.ParameterChecker;
-
-/**
- * Provides common functionality.
- *
- * @author Hans Haggstrom
- */
-public abstract class AbstractProtocol
-        implements Protocol
-{
-
-    //======================================================================
-    // Private Fields
-
-    private String myProtocolId;
-
-    //======================================================================
-    // Private Constants
-
-    //======================================================================
-    // Public Methods
-
-    //----------------------------------------------------------------------
-    // Protocol Implementation
-
-    public final String getProtocolId()
-    {
-        return myProtocolId;
-    }
-
-    //======================================================================
-    // Protected Methods
-
-    //----------------------------------------------------------------------
-    // Protected Constructors
-
-    /**
-     * @param protocolId an identifier for this protocol.   Used for protocol 
negotiation.  Should be Java identifier
-     *                   style (start with letter, no whitespace, etc).
-     */
-    protected AbstractProtocol( final String protocolId )
-    {
-        ParameterChecker.checkIsIdentifier( protocolId, "protocolId" );
-
-        myProtocolId = protocolId;
-    }
-
-}

Deleted: 
trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/Protocol.java
===================================================================
--- 
trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/Protocol.java 
    2008-04-05 14:11:05 UTC (rev 440)
+++ 
trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/Protocol.java 
    2008-04-05 19:04:43 UTC (rev 441)
@@ -1,41 +0,0 @@
-package org.skycastle.protocol;
-
-import org.skycastle.messaging.Message;
-
-/**
- * A protocol used to communicate between server and client.
- * <p/>
- * The transport happens as byte array messages.
- * <p/>
- * The transfered data is messages with source and target game object, a 
message type, and a set of named
- * parameters of primitive data structures and collections.
- *
- * @author Hans Haggstrom
- */
-public interface Protocol
-{
-    /**
-     * @return a string ID used to identify this protocol during protocol 
negotiations.  The ID should be a
-     *         valid Java identifier (sart with letter, contain no spaces, 
etc).
-     */
-    String getProtocolId();
-
-    /**
-     * @param messageToSend the message to encode to bytes for network 
transfer.
-     *
-     * @return the bytes representing the message to transfer
-     *
-     * @throws ProtocolException if there was some error when encoding the 
message.
-     */
-    byte[] encode( Message messageToSend ) throws ProtocolException;
-
-    /**
-     * @param receivedBytes an array of bytes received over the network.  Note 
that malicious crackers may
-     *                      send any kind of messages, so the error handling 
should be robust.
-     *
-     * @return the message represented by the specified bytes.
-     *
-     * @throws ProtocolException if there was some error when decoding the 
received message.
-     */
-    Message decode( byte[] receivedBytes ) throws ProtocolException;
-}

Modified: 
trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/negotiation/AbstractProtocolNegotiator.java
===================================================================
--- 
trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/negotiation/AbstractProtocolNegotiator.java
       2008-04-05 14:11:05 UTC (rev 440)
+++ 
trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/negotiation/AbstractProtocolNegotiator.java
       2008-04-05 19:04:43 UTC (rev 441)
@@ -1,5 +1,6 @@
 package org.skycastle.protocol.negotiation;
 
+import org.skycastle.core.ObjectReference;
 import org.skycastle.protocol.protocols.Protocol;
 import org.skycastle.protocol.registry.ProtocolRegistry;
 import org.skycastle.util.ParameterChecker;
@@ -19,7 +20,7 @@
     //======================================================================
     // Private Fields
 
-    private final ProtocolRegistry myProtocolRegistry;
+    private final ObjectReference<ProtocolRegistry> 
myProtocolRegistryReference;
 
     private NegotiationStatus myStatus = NegotiationStatus.ONGOING;
     private Protocol myProtocol = null;
@@ -34,10 +35,14 @@
     protected static final String VERSION_KEY = "Version";
     protected static final String CLIENT_KEY = "Client";
 
+    @SuppressWarnings( { "HardcodedLineSeparator" } )
+    protected static final String PROTOCOL_NEWLINE_CHARACTER = "\n";
+
     //======================================================================
     // Private Constants
 
     private static final int MAX_MESSAGE_LENGTH = 2000;
+    private static final long serialVersionUID = 1L;
 
     //======================================================================
     // Public Methods
@@ -88,13 +93,13 @@
     // Protected Constructors
 
     /**
-     * @param protocolRegistry a registry containing the available protocols.
+     * @param protocolRegistryReference a registry containing the available 
protocols.
      */
-    protected AbstractProtocolNegotiator( final ProtocolRegistry 
protocolRegistry )
+    protected AbstractProtocolNegotiator( final 
ObjectReference<ProtocolRegistry> protocolRegistryReference )
     {
-        ParameterChecker.checkNotNull( protocolRegistry, "protocolRegistry" );
+        ParameterChecker.checkNotNull( protocolRegistryReference, 
"protocolRegistryReference" );
 
-        myProtocolRegistry = protocolRegistry;
+        myProtocolRegistryReference = protocolRegistryReference;
     }
 
     //----------------------------------------------------------------------
@@ -119,7 +124,7 @@
      */
     protected final Set<String> getAvailableProtocolsIds()
     {
-        return myProtocolRegistry.getAvailableProtocolIds();
+        return 
myProtocolRegistryReference.getForReading().getAvailableProtocolIds();
     }
 
 
@@ -137,10 +142,13 @@
      */
     protected final void setProtocol( final String protocolId )
     {
-        myProtocol = myProtocolRegistry.getProtocol( protocolId );
+        myProtocol = myProtocolRegistryReference.getForReading().getProtocol( 
protocolId );
     }
 
 
+    /**
+     * @return a space separated list of the string ID:s of the available 
protocols .
+     */
     protected final String getAvailableProtocolIdsAsString()
     {
         final StringBuffer protocolIds = new StringBuffer();
@@ -158,11 +166,11 @@
 
     private Map<String, String> splitIntoKeysAndValues( final String 
incomingString )
     {
-        final Map<String, String> parameters = new HashMap<String, String>();
+        final Map<String, String> parameters = new HashMap<String, String>( 10 
);
 
         if ( incomingString != null )
         {
-            final String[] lines = incomingString.split( "\n" );
+            final String[] lines = incomingString.split( 
PROTOCOL_NEWLINE_CHARACTER );
             for ( final String line : lines )
             {
                 final int spaceIndex = line.indexOf( " " );

Modified: 
trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/negotiation/ClientSideProtocolNegotiator.java
===================================================================
--- 
trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/negotiation/ClientSideProtocolNegotiator.java
     2008-04-05 14:11:05 UTC (rev 440)
+++ 
trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/negotiation/ClientSideProtocolNegotiator.java
     2008-04-05 19:04:43 UTC (rev 441)
@@ -1,5 +1,6 @@
 package org.skycastle.protocol.negotiation;
 
+import org.skycastle.core.DirectReference;
 import org.skycastle.protocol.registry.ProtocolRegistry;
 
 import java.util.Map;
@@ -24,6 +25,11 @@
     private int myStep = 0;
 
     //======================================================================
+    // Private Constants
+
+    private static final long serialVersionUID = 1L;
+
+    //======================================================================
     // Public Methods
 
     //----------------------------------------------------------------------
@@ -38,7 +44,7 @@
                                          final String clientType,
                                          final String version )
     {
-        super( protocolRegistry );
+        super( new DirectReference<ProtocolRegistry>( protocolRegistry ) );
         myClientType = clientType;
         myVersion = version;
     }
@@ -90,10 +96,10 @@
                 myServerType = parameters.get( SERVER_KEY );
                 myServerVersion = parameters.get( VERSION_KEY );
 
-                return PROTOCOL_NEGOTIATION_START + "\n" +
-                       CLIENT_KEY + " " + myClientType + "\n" +
-                       VERSION_KEY + " " + myVersion + "\n" +
-                       KNOWN_PROTOCOLS_KEY + " " + 
getAvailableProtocolIdsAsString() + "\n";
+                return PROTOCOL_NEGOTIATION_START + PROTOCOL_NEWLINE_CHARACTER 
+
+                       CLIENT_KEY + " " + myClientType + 
PROTOCOL_NEWLINE_CHARACTER +
+                       VERSION_KEY + " " + myVersion + 
PROTOCOL_NEWLINE_CHARACTER +
+                       KNOWN_PROTOCOLS_KEY + " " + 
getAvailableProtocolIdsAsString() + PROTOCOL_NEWLINE_CHARACTER;
 
 
             case 2: // Read protocol selected by server

Modified: 
trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/negotiation/NegotiationStatus.java
===================================================================
--- 
trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/negotiation/NegotiationStatus.java
        2008-04-05 14:11:05 UTC (rev 440)
+++ 
trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/negotiation/NegotiationStatus.java
        2008-04-05 19:04:43 UTC (rev 441)
@@ -94,11 +94,11 @@
 
 
     /**
-     * @return true if the negotiation succeeded, false if it failed or is 
still ongoing.
+     * @return true if the negotiation are finished and succeeded, false if it 
failed or is still ongoing.
      */
     public boolean isSuccess()
     {
-        return mySuccess;
+        return isFinished() && mySuccess;
     }
 
 

Modified: 
trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/negotiation/ProtocolNegotiator.java
===================================================================
--- 
trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/negotiation/ProtocolNegotiator.java
       2008-04-05 14:11:05 UTC (rev 440)
+++ 
trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/negotiation/ProtocolNegotiator.java
       2008-04-05 19:04:43 UTC (rev 441)
@@ -2,6 +2,8 @@
 
 import org.skycastle.protocol.protocols.Protocol;
 
+import java.io.Serializable;
+
 /**
  * A state machine that can negotiate a protocol to use with another party 
connected over a network.
  * <p/>
@@ -11,6 +13,7 @@
  * @author Hans Haggstrom
  */
 public interface ProtocolNegotiator
+        extends Serializable
 {
     /**
      * Does the next step in the negotiation.

Modified: 
trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/negotiation/ServerSideProtocolNegotiator.java
===================================================================
--- 
trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/negotiation/ServerSideProtocolNegotiator.java
     2008-04-05 14:11:05 UTC (rev 440)
+++ 
trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/negotiation/ServerSideProtocolNegotiator.java
     2008-04-05 19:04:43 UTC (rev 441)
@@ -1,5 +1,8 @@
 package org.skycastle.protocol.negotiation;
 
+import com.sun.sgs.app.ManagedObject;
+import org.skycastle.core.ObjectReference;
+import org.skycastle.protocol.protocols.Protocol;
 import org.skycastle.protocol.registry.ProtocolRegistry;
 import org.skycastle.util.ParameterChecker;
 
@@ -29,19 +32,28 @@
     private int myStep = 0;
 
     //======================================================================
+    // Private Constants
+
+    private static final long serialVersionUID = 1L;
+
+    //======================================================================
     // Public Methods
 
     //----------------------------------------------------------------------
     // Constructors
 
     /**
-     * @param protocolRegistry a registry containing the available protocols.
+     * @param protocolRegistryReference a referenced to the {@link 
ProtocolRegistry} that contains available
+     *                                  {@link Protocol}s.  We use a reference 
as the {@link ProtocolRegistry}
+     *                                  is stored as a separate {@link 
ManagedObject} on the server side.
+     * @param serverType                a string identifying the server to the 
clients.
+     * @param serverVersion             a version string identifying the 
server version to the clients.
      */
-    public ServerSideProtocolNegotiator( final ProtocolRegistry 
protocolRegistry,
+    public ServerSideProtocolNegotiator( final 
ObjectReference<ProtocolRegistry> protocolRegistryReference,
                                          final String serverType,
                                          final String serverVersion )
     {
-        super( protocolRegistry );
+        super( protocolRegistryReference );
 
         ParameterChecker.checkNotNull( serverType, "serverType" );
         ParameterChecker.checkNotNull( serverVersion, "serverVersion" );
@@ -53,7 +65,6 @@
     //----------------------------------------------------------------------
     // ProtocolNegotiator Implementation
 
-
     public boolean startsNegotiations()
     {
         return true;
@@ -82,16 +93,17 @@
     //======================================================================
     // Protected Methods
 
+    @Override
     protected String handleMessage( final String incomingMessage, final 
Map<String, String> parameters )
     {
         myStep++;
         switch ( myStep )
         {
             case 1: // Take contact with client
-                return PROTOCOL_NEGOTIATION_START + "\n" +
-                       SERVER_KEY + " " + myServerType + "\n" +
-                       VERSION_KEY + " " + myServerVersion + "\n" +
-                       KNOWN_PROTOCOLS_KEY + " " + 
getAvailableProtocolIdsAsString() + "\n";
+                return PROTOCOL_NEGOTIATION_START + PROTOCOL_NEWLINE_CHARACTER 
+
+                       SERVER_KEY + " " + myServerType + 
PROTOCOL_NEWLINE_CHARACTER +
+                       VERSION_KEY + " " + myServerVersion + 
PROTOCOL_NEWLINE_CHARACTER +
+                       KNOWN_PROTOCOLS_KEY + " " + 
getAvailableProtocolIdsAsString() + PROTOCOL_NEWLINE_CHARACTER;
 
 
             case 2: // Read introduction from client, send protocol selection
@@ -116,7 +128,7 @@
                     setStatus( NegotiationStatus.NO_COMMON_PROTOCOL_FOUND );
                 }
 
-                return SELECTED_PROTOCOL_KEY + " " + selectedProtocol + "\n";
+                return SELECTED_PROTOCOL_KEY + " " + selectedProtocol + 
PROTOCOL_NEWLINE_CHARACTER;
 
 
             default: // Too many steps
@@ -133,9 +145,8 @@
         if ( spaceSeparatedClientProtocols != null )
         {
             final Set<String> clientKnownProtocols = new HashSet<String>( 
Arrays.asList(
-                    spaceSeparatedClientProtocols.split(
-                            " " ) ) );
-            for ( String supportedProtocol : getAvailableProtocolsIds() )
+                    spaceSeparatedClientProtocols.split( " " ) ) );
+            for ( final String supportedProtocol : getAvailableProtocolsIds() )
             {
                 if ( clientKnownProtocols.contains( supportedProtocol ) )
                 {

Modified: 
trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/protocols/AbstractProtocol.java
===================================================================
--- 
trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/protocols/AbstractProtocol.java
   2008-04-05 14:11:05 UTC (rev 440)
+++ 
trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/protocols/AbstractProtocol.java
   2008-04-05 19:04:43 UTC (rev 441)
@@ -8,7 +8,6 @@
 import org.skycastle.util.parameters.validators.ParameterValidator;
 import org.skycastle.util.parameters.validators.type.TypeValidator;
 
-import java.io.Serializable;
 import java.util.Collection;
 import java.util.Map;
 
@@ -18,7 +17,7 @@
  * @author Hans Haggstrom
  */
 public abstract class AbstractProtocol
-        implements Protocol, Serializable
+        implements Protocol
 {
 
     //======================================================================

Modified: 
trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/protocols/Protocol.java
===================================================================
--- 
trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/protocols/Protocol.java
   2008-04-05 14:11:05 UTC (rev 440)
+++ 
trunk/skycastle/modules/core/src/main/java/org/skycastle/protocol/protocols/Protocol.java
   2008-04-05 19:04:43 UTC (rev 441)
@@ -3,6 +3,8 @@
 import org.skycastle.messaging.Message;
 import org.skycastle.protocol.ProtocolException;
 
+import java.io.Serializable;
+
 /**
  * A protocol used to communicate between server and client.
  * <p/>
@@ -14,6 +16,7 @@
  * @author Hans Haggstrom
  */
 public interface Protocol
+        extends Serializable
 {
     /**
      * @return a string ID used to identify this protocol during protocol 
negotiations.  The ID should be a

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-04-05 14:11:05 UTC (rev 440)
+++ 
trunk/skycastle/modules/core/src/test/java/org/skycastle/core/AbstractGameObjectActionsTest.java
    2008-04-05 19:04:43 UTC (rev 441)
@@ -136,7 +136,7 @@
         myGameObject.addAction( testAction );
         assertTrue( "Action should be added",
                     myGameObject.hasAction( TEST_ACTION_NAME ) );
-        myCallerId = new GameObjectId( "someSender" );
+        myCallerId = new GameObjectId( "GameObject_someSender" );
     }
 
     //======================================================================
@@ -202,7 +202,8 @@
         private long calculateTimeUntilNextInvocation( final GameObject 
hostObject )
         {
             long timeUntilNextCallback_ms = -1;
-            if ( hostObject.getPropertyValue( STEPS_CALLED, 0 ) < 
hostObject.getPropertyValue( NUMBER_OF_STEPS, 0 ) )
+            if ( hostObject.getPropertyValue( STEPS_CALLED,
+                                              0 ) < 
hostObject.getPropertyValue( NUMBER_OF_STEPS, 0 ) )
             {
                 timeUntilNextCallback_ms = hostObject.getPropertyValue( 
REPEAT_INTERVALL, -1 );
             }

Modified: 
trunk/skycastle/modules/core/src/test/java/org/skycastle/core/AbstractGameObjectPropertiesTest.java
===================================================================
--- 
trunk/skycastle/modules/core/src/test/java/org/skycastle/core/AbstractGameObjectPropertiesTest.java
 2008-04-05 14:11:05 UTC (rev 440)
+++ 
trunk/skycastle/modules/core/src/test/java/org/skycastle/core/AbstractGameObjectPropertiesTest.java
 2008-04-05 19:04:43 UTC (rev 441)
@@ -31,6 +31,7 @@
     private GameObject myGameObject;
 
     private List<Message> mySentMessages;
+    private static final String SOME_OTHER_GAME_OBJECT_ID = 
"GameObject_SomeOtherObjectMaybePlayer";
 
     //======================================================================
     // Public Methods
@@ -132,7 +133,7 @@
     {
         assertEquals( 0, getNumberOfProperties() );
 
-        myGameObject.onMessage( new AddPropertyMessage( new GameObjectId( 
"SomeOtherObjectMaybePlayer" ),
+        myGameObject.onMessage( new AddPropertyMessage( new GameObjectId( 
SOME_OTHER_GAME_OBJECT_ID ),
                                                         myGameObject.getId(),
                                                         "breakfast",
                                                         "juice",
@@ -141,7 +142,7 @@
         assertEquals( "juice", myGameObject.getPropertyValue( "breakfast", 
null ) );
         assertEquals( 1, getNumberOfProperties() );
 
-        myGameObject.onMessage( new SetPropertyMessage( new GameObjectId( 
"SomeOtherObjectMaybePlayer" ),
+        myGameObject.onMessage( new SetPropertyMessage( new GameObjectId( 
SOME_OTHER_GAME_OBJECT_ID ),
                                                         myGameObject.getId(),
                                                         "breakfast",
                                                         "sandwich" ) );
@@ -149,7 +150,7 @@
         assertEquals( "sandwich", myGameObject.getPropertyValue( "breakfast", 
null ) );
         assertEquals( 1, getNumberOfProperties() );
 
-        myGameObject.onMessage( new RemovePropertyMessage( new GameObjectId( 
"SomeOtherObjectMaybePlayer" ),
+        myGameObject.onMessage( new RemovePropertyMessage( new GameObjectId( 
SOME_OTHER_GAME_OBJECT_ID ),
                                                            
myGameObject.getId(),
                                                            "breakfast" ) );
 

Modified: 
trunk/skycastle/modules/core/src/test/java/org/skycastle/core/geometry/space/grid/GridTest.java
===================================================================
--- 
trunk/skycastle/modules/core/src/test/java/org/skycastle/core/geometry/space/grid/GridTest.java
     2008-04-05 14:11:05 UTC (rev 440)
+++ 
trunk/skycastle/modules/core/src/test/java/org/skycastle/core/geometry/space/grid/GridTest.java
     2008-04-05 19:04:43 UTC (rev 441)
@@ -49,19 +49,19 @@
     public void testAddingAndAccessingGameObjects() throws Exception
     {
         assertObjectAccessWorks( true, 5.5f, 4.5f, 5, 4 );
-        assertObjectAccessWorks( true, 5, 4, 5, 4 );
+        assertObjectAccessWorks( true, 5.0f, 4.0f, 5, 4 );
         assertObjectAccessWorks( true, 0.5f, 0.5f, 0, 0 );
         assertObjectAccessWorks( true, 9.5f, 9.5f, 9, 9 );
 
         assertObjectAccessWorks( false, 6.5f, 4.5f, 5, 4 );
         assertObjectAccessWorks( false, 6.5f, 5.5f, 5, 4 );
-        assertObjectAccessWorks( false, 6, 4.5f, 5, 4 );
+        assertObjectAccessWorks( false, 6.0f, 4.5f, 5, 4 );
     }
 
 
     public void testTileTypeSettingAndGetting() throws Exception
     {
-        assertEquals( null, myGridSpace.getTileType( 4, 5 ) );
+        assertNull( myGridSpace.getTileType( 4, 5 ) );
 
         myGridSpace.setTileType( 4, 5, TEST_TILE_TYPE );
 
@@ -93,7 +93,7 @@
 
         myGridSpace.addObject( testObject, x, y, 0 );
 
-        final List<GameObject> collectionBasket = new ArrayList<GameObject>();
+        final List<GameObject> collectionBasket = new ArrayList<GameObject>( 
10 );
         myGridSpace.collectObjectsInTile( xGrid, yGrid, collectionBasket );
 
         assertEquals( shouldContain, collectionBasket.contains( testObject ) );

Modified: 
trunk/skycastle/modules/core/src/test/java/org/skycastle/protocol/negotiation/ProtocolNegotiationTest.java
===================================================================
--- 
trunk/skycastle/modules/core/src/test/java/org/skycastle/protocol/negotiation/ProtocolNegotiationTest.java
  2008-04-05 14:11:05 UTC (rev 440)
+++ 
trunk/skycastle/modules/core/src/test/java/org/skycastle/protocol/negotiation/ProtocolNegotiationTest.java
  2008-04-05 19:04:43 UTC (rev 441)
@@ -5,11 +5,13 @@
  */
 
 import junit.framework.TestCase;
+import org.skycastle.core.DirectReference;
 import org.skycastle.messaging.Message;
 import org.skycastle.protocol.MessageValidator;
 import org.skycastle.protocol.ProtocolException;
 import org.skycastle.protocol.protocols.AbstractProtocol;
 import org.skycastle.protocol.protocols.Protocol;
+import org.skycastle.protocol.registry.ProtocolRegistry;
 import org.skycastle.protocol.registry.ProtocolRegistryImpl;
 import org.skycastle.util.StringUtilities;
 
@@ -160,7 +162,8 @@
         myClientSideNegotiator = new ClientSideProtocolNegotiator( 
myClientProtocolRegistry,
                                                                    CLIENT_TYPE,
                                                                    
CLIENT_VERSION );
-        myServerSideNegotiator = new ServerSideProtocolNegotiator( 
myServerProtocolRegistry,
+        myServerSideNegotiator = new ServerSideProtocolNegotiator( new 
DirectReference<ProtocolRegistry>(
+                myServerProtocolRegistry ),
                                                                    "Test 
Server",
                                                                    "0.1" );
     }

Modified: 
trunk/skycastle/modules/core/src/test/java/org/skycastle/protocol/protocols/SerializationProtocolTest.java
===================================================================
--- 
trunk/skycastle/modules/core/src/test/java/org/skycastle/protocol/protocols/SerializationProtocolTest.java
  2008-04-05 14:11:05 UTC (rev 440)
+++ 
trunk/skycastle/modules/core/src/test/java/org/skycastle/protocol/protocols/SerializationProtocolTest.java
  2008-04-05 19:04:43 UTC (rev 441)
@@ -35,7 +35,8 @@
 
     public void testNonAllowedType() throws Exception
     {
-        final PropertyChangedMessage sentMessage = new PropertyChangedMessage( 
new GameObjectId( "foo" ),
+        final PropertyChangedMessage sentMessage = new PropertyChangedMessage( 
new GameObjectId(
+                "GameObject_foo" ),
                                                                                
"TakeThisIfYouCan",
                                                                                
new StringBuffer(
                                                                                
        "Evil infiltrator buffer" ) );
@@ -71,7 +72,7 @@
         someMoreProps.setParameter( "ShouldBeRecursive", true );
         parameterSet.setObjectParameter( "PropertiesOfFavouriteProperty", 
someMoreProps );
 
-        final PropertyChangedMessage message = new PropertyChangedMessage( new 
GameObjectId( "foo" ),
+        final PropertyChangedMessage message = new PropertyChangedMessage( new 
GameObjectId( "GameObject_foo" ),
                                                                            
"bar",
                                                                            
parameterSet );
 

Modified: 
trunk/skycastle/modules/server/src/main/java/org/skycastle/server/SkycastleClientSessionHandler.java
===================================================================
--- 
trunk/skycastle/modules/server/src/main/java/org/skycastle/server/SkycastleClientSessionHandler.java
        2008-04-05 14:11:05 UTC (rev 440)
+++ 
trunk/skycastle/modules/server/src/main/java/org/skycastle/server/SkycastleClientSessionHandler.java
        2008-04-05 19:04:43 UTC (rev 441)
@@ -1,13 +1,17 @@
 package org.skycastle.server;
 
-import com.sun.sgs.app.*;
-import org.skycastle.core.DefaultGameObject;
-import org.skycastle.core.GameObject;
+import com.sun.sgs.app.AppContext;
+import com.sun.sgs.app.ClientSession;
+import com.sun.sgs.app.ClientSessionListener;
+import com.sun.sgs.app.DataManager;
+import org.skycastle.core.*;
 import org.skycastle.messaging.Message;
 import org.skycastle.messaging.modifications.ModificationMessage;
+import org.skycastle.messaging.updates.UpdateMessage;
 import org.skycastle.protocol.ProtocolException;
 import org.skycastle.protocol.negotiation.ProtocolNegotiator;
 import org.skycastle.protocol.negotiation.ServerSideProtocolNegotiator;
+import org.skycastle.protocol.registry.ProtocolRegistry;
 
 import java.io.Serializable;
 import java.util.logging.Level;
@@ -26,36 +30,33 @@
     /**
      * The session this {@code ClientSessionListener} is listening to.
      */
-    private final ClientSession mySession;
+    // NOTE: The ClientSession interface doesn't extend Serializable, but the 
implementation does,
+    // so we can store it in a Serializable class.
+    @SuppressWarnings( { "NonSerializableFieldInSerializableClass" } )
+    private final ClientSession myClientSession;
+
     private final ProtocolNegotiator myProtocolNegotiator;
 
-    private ManagedReference myProtocolRegistryReferenceReference;
-    private ManagedReference myClientAccountReference;
+    // NOTE: For some reason the ManagedReference interface is not 
serializable, but the implementation is,
+    // so we supress a serialization warning for IDE:s that look for those 
problems.
+    @SuppressWarnings( { "NonSerializableFieldInSerializableClass" } )
 
-    //======================================================================
-    // Non-Private Fields
+    private GameObjectReference myClientAccountReference;
 
-    /**
-     * The server listener. This is used for querying connected users etc.
-     */
-    protected ManagedReference serverListener;
-
     //======================================================================
     // Private Constants
 
     /**
-     * The version of the serialized form of this class.
+     * The {@link Logger} for this class.
      */
-    private static final long serialVersionUID = 1L;
+    private static final Logger LOGGER = Logger.getLogger( 
SkycastleClientSessionHandler.class.getName() );
 
-    /**
-     * The {@link Logger} for this class.
-     */
-    private static final Logger LOGGER =
-            Logger.getLogger( SkycastleClientSessionHandler.class.getName() );
     private static final String SERVER_TYPE = "SkycastleServer";
     private static final String SERVER_VERSION = "0.1";
 
+    private static final long serialVersionUID = 1L;
+    private static final String ACCOUNT_PREFIX = "account_";
+
     //======================================================================
     // Public Methods
 
@@ -66,49 +67,24 @@
      * Creates a new {@code HelloChannelsSessionListener} for the given 
session, and joins it to the given
      * channels.
      *
-     * @param clientSession the session this listener is associated with
-     * @param protocolRegistryReferenceReference
-     *
+     * @param clientSession             the session this listener is 
associated with
+     * @param protocolRegistryReference a reference to the {@link 
ProtocolRegistry} that contains the
+     *                                  available protocols.
      */
-    // TODO: Implement our own generic version of ManagedReference that just 
wraps a ManagedReference
-    public SkycastleClientSessionHandler( ClientSession clientSession,
-                                          SkycastleServer initServerListener,
-                                          final ManagedReference 
protocolRegistryReferenceReference )
+    public SkycastleClientSessionHandler( final ClientSession clientSession,
+                                          final 
PersistentReference<ProtocolRegistry> protocolRegistryReference )
     {
-        mySession = clientSession;
-        myProtocolRegistryReferenceReference = 
protocolRegistryReferenceReference;
+        myClientSession = clientSession;
 
-        final DataManager dataManager = AppContext.getDataManager();
-        serverListener = dataManager.createReference( initServerListener );
-
-        // TODO: We need to pass in a reference instead of a concrete class, 
because we store the protocol negotiator in this object....
-        myProtocolNegotiator = new ServerSideProtocolNegotiator( 
myProtocolRegistryReferenceReference,
+        myProtocolNegotiator = new ServerSideProtocolNegotiator( 
protocolRegistryReference,
                                                                  SERVER_TYPE,
                                                                  
SERVER_VERSION );
 
-
+        // If the server should start protocol negotiations, have it send the 
opening message
         if ( myProtocolNegotiator.startsNegotiations() )
         {
-            final byte[] firstMessage = myProtocolNegotiator.handleMessage( 
null );
-            clientSession.send( firstMessage );
+            clientSession.send( myProtocolNegotiator.handleMessage( null ) );
         }
-
-        // Get users account.  The account will typically contain actions for 
resuming some existing avatars
-        // or creating new avatars, and doing general account management and 
maybe out-of-game chat.
-
-        // NOTE: The client session should already be authenticated, so just 
use the username to find the account
-        GameObject clientAccount = dataManager.getBinding( "account_" + 
clientSession.getName(),
-                                                           GameObject.class );
-
-        // If client doesn't yet have any account, create a new one
-        if ( clientAccount == null )
-        {
-            clientAccount = new DefaultGameObject();
-        }
-
-        myClientAccountReference = dataManager.createReference( clientAccount 
);
-
-        // TODO: Notify the users account that the user connected
     }
 
     //----------------------------------------------------------------------
@@ -119,44 +95,29 @@
      * <p/>
      * Logs when data arrives from the client, and echoes the message back.
      */
-    public void receivedMessage( final byte[] message )
+    public void receivedMessage( final byte[] byteMessage )
     {
         if ( myProtocolNegotiator.getStatus().isFinished() )
         {
-            try
+            if ( myProtocolNegotiator.getStatus().isSuccess() )
             {
-                // Decode incoming message
-                final Message decodedMessage = 
myProtocolNegotiator.getProtocol().decode( message );
-
-                // TODO: Set the messages sender and such so that the client 
is not claiming to be someone else...
-
-                // TODO: Should we validate the message here also?
-                //decodedMessage.validate(  )
-
-                // Send the incoming message to the clients account for 
processing
-                final GameObject clientAvatar = myClientAccountReference.get( 
GameObject.class );
-                clientAvatar.onMessage( decodedMessage );
-
-                // TODO: Or should we send it directly to the target game 
object??
-                // If the message is a ModificationMessage it has a target.
-                // The client should anyway send only modification messages, 
update messages don't make that much sense.
-                ModificationMessage modificationMessage = 
(ModificationMessage) decodedMessage;
-                // TODO: Get game object for specific gameObjectId, using e.g. 
the GameContext - we could build this functionality into the GameObjectId now!  
Maybe even support generics?
-                GameObject target = 
modificationMessage.getTargetId().getGameObjectForModification();
-                target.onMessage( modificationMessage );
+                handleMessage( byteMessage );
             }
-            catch ( ProtocolException e )
-            {
-                // TODO: Log exception with client somehow?  Enable fast 
detection of errorneous or flooding DoS:in clients
-                e.printStackTrace();
-            }
         }
         else
         {
             // Continue protocol negotiation
-            final byte[] reply = myProtocolNegotiator.handleMessage( message );
+            final byte[] reply = myProtocolNegotiator.handleMessage( 
byteMessage );
 
-            mySession.send( reply );
+            if ( reply != null )
+            {
+                myClientSession.send( reply );
+            }
+
+            if ( myProtocolNegotiator.getStatus().isFinished() )
+            {
+                onProtocolNegotiationFinished( 
myProtocolNegotiator.getStatus().isSuccess() );
+            }
         }
     }
 
@@ -166,7 +127,7 @@
      * <p/>
      * Logs when the client disconnects.
      */
-    public void disconnected( boolean graceful )
+    public void disconnected( final boolean graceful )
     {
         // TODO: Notify the users account that the user disconnected (the 
avatars can go into off-line mode, etc).
 
@@ -174,8 +135,113 @@
         final String grace = graceful ? "graceful" : "forced";
         LOGGER.log( Level.INFO,
                     "User {0} has logged out {1}",
-                    new Object[]{ mySession.getName(), grace }
+                    new Object[]{ myClientSession.getName(), grace }
         );
     }
 
+    //======================================================================
+    // Private Methods
+
+    private void handleMessage( final byte[] byteMessage )
+    {
+        try
+        {
+            // Decode incoming message
+            final Message message = myProtocolNegotiator.getProtocol().decode( 
byteMessage );
+
+            // TODO: Set the messages sender and such so that the client is 
not claiming to be someone else...
+
+
+            if ( message instanceof ModificationMessage )
+            {
+                handleModificationMessage( message, (ModificationMessage) 
message );
+            }
+            else if ( message instanceof UpdateMessage )
+            {
+                throw new ProtocolException(
+                        "The client can not send UpdateMessages to the server. 
 Recieved a message of type: '" + message.getClass() + "'." );
+            }
+            else
+            {
+                throw new ProtocolException( "Unknown message type '" + 
message.getClass() + "'." );
+            }
+        }
+        catch ( ProtocolException e )
+        {
+            LOGGER.warning( "Problem when decoding message from a client: " + 
e.getMessage() );
+
+            // TODO: Log exception with client/account somehow?  Enable fast 
detection of errorneous or flooding DoS:in clients
+            e.printStackTrace();
+        }
+    }
+
+
+    private void handleModificationMessage( final Message message,
+                                            final ModificationMessage 
modificationMessage )
+    {
+        final GameObjectId targetId = modificationMessage.getTargetId();
+        final GameObject target = 
GameContext.getGameObjectContext().getGameObjectById(
+                targetId,
+                true );
+
+        target.onMessage( message );
+    }
+
+
+    private void onProtocolNegotiationFinished( final boolean success )
+    {
+        if ( success )
+        {
+            // If the protocol negotiation finished successfully, get the 
users account
+            final GameObject account = getUserAccount( 
myClientSession.getName() );
+
+            // TODO: Notify the account object that the user logged in.
+
+            myClientAccountReference = new GameObjectReference( account );
+        }
+        else
+        {
+            // If negotiation failed with error, disconnect
+            myClientSession.disconnect();
+        }
+    }
+
+
+    /**
+     * Get users account.  The account will typically contain actions for 
resuming some existing avatars or
+     * creating new avatars, and doing general account management and maybe 
out-of-game chat.
+     * <p/>
+     * The client session should already be authenticated, so just use the 
username to find the account
+     * <p/>
+     * If the specified userLoginName does not yet have an account associated 
with it, a new one is created.
+     *
+     * @param userLoginName the login name of the user.  It should already 
have been authenticated and
+     *                      verified.
+     *
+     * @return a {@link GameObject} with the specified users account object.
+     */
+    private GameObject getUserAccount( final String userLoginName )
+    {
+        final DataManager dataManager = AppContext.getDataManager();
+
+        final String bindingName = ACCOUNT_PREFIX + userLoginName;
+
+        GameObject clientAccount = dataManager.getBinding( bindingName, 
GameObject.class );
+        if ( clientAccount == null )
+        {
+            // If client doesn't yet have any account, create a new one
+            clientAccount = new DefaultGameObject();
+            // TODO: Do we need to store the client user name with the 
account?  Any other data?
+            // TODO: This is a game / server extension point, as different 
servers could have different options and provided UI layouts here.
+            // By default, we could however have some standard stuff like 
information about the server
+            // and account, and a list of available games and the users 
avatars in them.
+            // TODO: Use some server configuration property or object to 
determine which class should be instantiated as the account object for new 
users.
+
+            // Store created account for future access
+            dataManager.setBinding( bindingName, clientAccount );
+        }
+
+        return clientAccount;
+    }
+
 }
\ No newline at end of file

Modified: 
trunk/skycastle/modules/server/src/main/java/org/skycastle/server/SkycastleServer.java
===================================================================
--- 
trunk/skycastle/modules/server/src/main/java/org/skycastle/server/SkycastleServer.java
      2008-04-05 14:11:05 UTC (rev 440)
+++ 
trunk/skycastle/modules/server/src/main/java/org/skycastle/server/SkycastleServer.java
      2008-04-05 19:04:43 UTC (rev 441)
@@ -1,6 +1,10 @@
 package org.skycastle.server;
 
-import com.sun.sgs.app.*;
+import com.sun.sgs.app.AppListener;
+import com.sun.sgs.app.ClientSession;
+import com.sun.sgs.app.ClientSessionListener;
+import org.skycastle.core.PersistentReference;
+import org.skycastle.protocol.registry.ProtocolRegistry;
 import org.skycastle.protocol.registry.ProtocolRegistryImpl;
 
 import java.io.Serializable;
@@ -19,15 +23,20 @@
 {
 
     //======================================================================
+    // Private Fields
+
+    private PersistentReference<ProtocolRegistry> myProtocolRegistryReference;
+
+    //======================================================================
     // Private Constants
 
     /**
      * The {@link Logger} for this class.
      */
-    private static final Logger LOGGER =
-            Logger.getLogger( SkycastleServer.class.getName() );
-    private ManagedReference myProtocolRegistryReferenceReference;
+    private static final Logger LOGGER = Logger.getLogger( 
SkycastleServer.class.getName() );
 
+    private static final long serialVersionUID = 1L;
+
     //======================================================================
     // Public Methods
 
@@ -37,7 +46,7 @@
     public void initialize( final Properties properties )
     {
         // Create protocol registry
-        myProtocolRegistryReferenceReference = 
AppContext.getDataManager().createReference( new ProtocolRegistryImpl() );
+        myProtocolRegistryReference = new 
PersistentReference<ProtocolRegistry>( new ProtocolRegistryImpl() );
     }
 
 
@@ -46,7 +55,7 @@
         // DEBUG:
         LOGGER.log( Level.INFO, "User {0} has logged in", 
clientSession.getName() );
 
-        return new SkycastleClientSessionHandler( clientSession, this, 
myProtocolRegistryReferenceReference );
+        return new SkycastleClientSessionHandler( clientSession, 
myProtocolRegistryReference );
     }
 
 }

Modified: 
trunk/skycastle/modules/utils/src/main/java/org/skycastle/util/issue/IssueImpl.java
===================================================================
--- 
trunk/skycastle/modules/utils/src/main/java/org/skycastle/util/issue/IssueImpl.java
 2008-04-05 14:11:05 UTC (rev 440)
+++ 
trunk/skycastle/modules/utils/src/main/java/org/skycastle/util/issue/IssueImpl.java
 2008-04-05 19:04:43 UTC (rev 441)
@@ -98,7 +98,7 @@
      */
     public String toString()
     {
-        return "Report{ severity: " + mySeverity +
+        return "Issue{ severity: " + mySeverity +
                ", type: " + myType +
                ", summary: " + mySummary +
                ", cause: " + myCause +


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

Other related posts:

  • » [skycastle-commits] SF.net SVN: skycastle: [441] trunk/skycastle/modules