diff --git a/src/as/com/threerings/ezgame/client/GameControlBackend.as b/src/as/com/threerings/ezgame/client/GameControlBackend.as index 8182fcc8..f7d6cae8 100644 --- a/src/as/com/threerings/ezgame/client/GameControlBackend.as +++ b/src/as/com/threerings/ezgame/client/GameControlBackend.as @@ -173,9 +173,6 @@ public class GameControlBackend _ezObj.ezGameService.setProperty( _ctx.getClient(), propName, encoded, index, false, null, createLoggingConfirmListener("setProperty")); - - // set it immediately in the game object - _ezObj.applyPropertySet(propName, value, index); } public function testAndSetProperty_v1 ( diff --git a/src/as/com/threerings/ezgame/data/PropertySetEvent.as b/src/as/com/threerings/ezgame/data/PropertySetEvent.as index b9943c73..22d63e0c 100644 --- a/src/as/com/threerings/ezgame/data/PropertySetEvent.as +++ b/src/as/com/threerings/ezgame/data/PropertySetEvent.as @@ -34,6 +34,7 @@ public class PropertySetEvent extends NamedEvent // from abstract DEvent override public function applyToObject (target :DObject) :Boolean { + // since we're in actionscript, we're always on the client _oldValue = EZGameObject(target).applyPropertySet(_name, _data, _index); return true; diff --git a/src/java/com/threerings/ezgame/data/EZGameObject.java b/src/java/com/threerings/ezgame/data/EZGameObject.java index 4ceb0b5a..4ebc3552 100644 --- a/src/java/com/threerings/ezgame/data/EZGameObject.java +++ b/src/java/com/threerings/ezgame/data/EZGameObject.java @@ -9,6 +9,8 @@ import java.util.Arrays; import java.util.HashMap; import java.util.Map; +import com.samskivert.util.ObjectUtil; + import com.threerings.util.Name; import com.threerings.io.ObjectInputStream; @@ -85,6 +87,8 @@ public class EZGameObject extends GameObject /** * Called by PropertySetEvent to effect the property update. + * + * @return the old value. */ public Object applyPropertySet (String propName, Object data, int index) { @@ -123,6 +127,7 @@ public class EZGameObject extends GameObject } else if (data != null) { _props.put(propName, data); + } else { _props.remove(propName); } @@ -131,44 +136,70 @@ public class EZGameObject extends GameObject } /** - * Compares whether the old value and the test value are the same. + * Test the specified property against the specified value. This is + * called on the server to validate testAndSet events. + * + * @return true if the property contains the value specified. */ public boolean testProperty ( - String propName, int index, boolean testAndSet, Object testValue) + String propName, int index, Object testValue) { - boolean result = false; - if (! isOnServer() || // if this is the client, don't test - only test on server - ! testAndSet) // test was not requested - { - result = true; - - } else { - Object oldValue = _props.get(propName); - - // test if both are null - if (testValue == null || oldValue == null) { - result = (oldValue == testValue); - - } else { + Object curValue = _props.get(propName); - // if the old value is an array, extract the appropriate element first - if (index >= 0 && oldValue instanceof byte[][]) - { - byte[][] arr = (byte[][]) oldValue; - if (arr != null) { oldValue = arr[index]; } + if (curValue != null && index >= 0) { + // see if there's an array there already + if (isOnServer()) { + if (curValue instanceof byte[][]) { + byte[][] curArray = (byte[][]) curValue; + if (curArray.length > index) { + curValue = curArray[index]; + + } else { + // the index is out of range, but since we auto-grow, + // we treat it like null + curValue = null; + } + + } else { + // curData is not an array, so the test fails + return false; } - - // now perform byte comparison - if (oldValue instanceof byte[] && - testValue instanceof byte[]) - { - result = Arrays.equals ( - (byte[]) oldValue, (byte[]) testValue); + + } else { + if (curValue instanceof Object[]) { + Object[] curArray = (Object[]) curValue; + if (curArray.length > index) { + curValue = curArray[index]; + + } else { + // the index is out of range, but since we auto-grow, + // we treat it like null + curValue = null; + } + + } else { + // curData is not an array, so the test fails + return false; } } } - - return result; + + // let's test the values! + if ((testValue instanceof Object[]) && (curValue instanceof Object[])) { + // testing an array against another array + return Arrays.deepEquals((Object[]) testValue, (Object[]) curValue); + + } else if ((testValue instanceof byte[]) && (curValue instanceof byte[])) { + // testing a property against another property (may have + // been from inside an array) + return Arrays.equals((byte[]) testValue, (byte[]) curValue); + + // TODO: other array types must be tested if we're on the client + // ?? + } else { + // will catch null == null... + return ObjectUtil.equals(testValue, curValue); + } } diff --git a/src/java/com/threerings/ezgame/data/PropertySetEvent.java b/src/java/com/threerings/ezgame/data/PropertySetEvent.java index 92adcafd..27102218 100644 --- a/src/java/com/threerings/ezgame/data/PropertySetEvent.java +++ b/src/java/com/threerings/ezgame/data/PropertySetEvent.java @@ -30,11 +30,12 @@ public class PropertySetEvent extends NamedEvent * Create a PropertySetEvent. */ public PropertySetEvent ( - int targetOid, String propName, Object value, int index) + int targetOid, String propName, Object value, int index, Object oldValue) { super(targetOid, propName); _data = value; _index = index; + _oldValue = oldValue; } /** @@ -68,7 +69,10 @@ public class PropertySetEvent extends NamedEvent if (!ezObj.isOnServer()) { _data = EZObjectMarshaller.decode(_data); } - _oldValue = ezObj.applyPropertySet(_name, _data, _index); + if (_oldValue == UNSET_OLD_VALUE) { + // only apply the property change if we haven't already + _oldValue = ezObj.applyPropertySet(_name, _data, _index); + } return true; } @@ -95,5 +99,5 @@ public class PropertySetEvent extends NamedEvent protected Object _data; /** The old value. */ - protected transient Object _oldValue; + protected transient Object _oldValue = UNSET_OLD_VALUE; } diff --git a/src/java/com/threerings/ezgame/server/EZGameManager.java b/src/java/com/threerings/ezgame/server/EZGameManager.java index 83c32e77..a1c8dba6 100644 --- a/src/java/com/threerings/ezgame/server/EZGameManager.java +++ b/src/java/com/threerings/ezgame/server/EZGameManager.java @@ -132,7 +132,10 @@ public class EZGameManager extends GameManager throws InvocationException { validateUser(caller); - setProperty(propName, data, index, testAndSet, testValue); + if (testAndSet && !_gameObj.testProperty(propName, index, testValue)) { + return; // the test failed: do not set the property + } + setProperty(propName, data, index); } // from EZGameProvider @@ -221,7 +224,7 @@ public class EZGameManager extends GameManager } if (playerId == 0) { - setProperty(msgOrPropName, result, -1, false, null); + setProperty(msgOrPropName, result, -1); } else { sendPrivateMessage(playerId, msgOrPropName, result); @@ -402,15 +405,12 @@ public class EZGameManager extends GameManager * Helper method to post a property set event. */ protected void setProperty ( - String propName, Object value, int index, - boolean testAndSet, Object testValue) + String propName, Object value, int index) { - if (_gameObj.testProperty (propName, index, testAndSet, testValue)) - { - _gameObj.postEvent( - new PropertySetEvent( - _gameObj.getOid(), propName, value, index)); - } + // apply the property set immediately + Object oldValue = _gameObj.applyPropertySet(propName, value, index); + _gameObj.postEvent(new PropertySetEvent( + _gameObj.getOid(), propName, value, index, oldValue)); } /**