/// <summary> /// Updates and synchronizes this Player's Custom Properties. Optionally, expectedProperties can be provided as condition. /// </summary> /// <remarks> /// Custom Properties are a set of string keys and arbitrary values which is synchronized /// for the players in a Room. They are available when the client enters the room, as /// they are in the response of OpJoin and OpCreate. /// /// Custom Properties either relate to the (current) Room or a Player (in that Room). /// /// Both classes locally cache the current key/values and make them available as /// property: CustomProperties. This is provided only to read them. /// You must use the method SetCustomProperties to set/modify them. /// /// Any client can set any Custom Properties anytime (when in a room). /// It's up to the game logic to organize how they are best used. /// /// You should call SetCustomProperties only with key/values that are new or changed. This reduces /// traffic and performance. /// /// Unless you define some expectedProperties, setting key/values is always permitted. /// In this case, the property-setting client will not receive the new values from the server but /// instead update its local cache in SetCustomProperties. /// /// If you define expectedProperties, the server will skip updates if the server property-cache /// does not contain all expectedProperties with the same values. /// In this case, the property-setting client will get an update from the server and update it's /// cached key/values at about the same time as everyone else. /// /// The benefit of using expectedProperties can be only one client successfully sets a key from /// one known value to another. /// As example: Store who owns an item in a Custom Property "ownedBy". It's 0 initally. /// When multiple players reach the item, they all attempt to change "ownedBy" from 0 to their /// actorNumber. If you use expectedProperties {"ownedBy", 0} as condition, the first player to /// take the item will have it (and the others fail to set the ownership). /// /// Properties get saved with the game state for Turnbased games (which use IsPersistent = true). /// </remarks> /// <param name="propertiesToSet">Hashtable of Custom Properties that changes.</param> /// <param name="expectedProperties">Provide some keys/values to use as condition for setting the new values. Client must be in room.</param> /// <param name="webFlags">Defines if this SetCustomProperties-operation gets forwarded to your WebHooks. Client must be in room.</param> public void SetCustomProperties(Hashtable propertiesToSet, Hashtable expectedProperties = null, WebFlags webFlags = null) { Hashtable customProps = propertiesToSet.StripToStringKeys() as Hashtable; // merge (and delete null-values), unless we use CAS (expected props) if (expectedProperties == null) { this.CustomProperties.Merge(customProps); this.CustomProperties.StripKeysWithNullValues(); } // send (sync) these new values if in room if (this.RoomReference != null && this.RoomReference.IsLocalClientInside) { this.RoomReference.LoadBalancingClient.loadBalancingPeer.OpSetPropertiesOfActor(this.actorID, customProps, expectedProperties, webFlags); } }
/// <summary> /// Updates and synchronizes this Player's Custom Properties. Optionally, expectedProperties can be provided as condition. /// </summary> /// <remarks> /// Custom Properties are a set of string keys and arbitrary values which is synchronized /// for the players in a Room. They are available when the client enters the room, as /// they are in the response of OpJoin and OpCreate. /// /// Custom Properties either relate to the (current) Room or a Player (in that Room). /// /// Both classes locally cache the current key/values and make them available as /// property: CustomProperties. This is provided only to read them. /// You must use the method SetCustomProperties to set/modify them. /// /// Any client can set any Custom Properties anytime (when in a room). /// It's up to the game logic to organize how they are best used. /// /// You should call SetCustomProperties only with key/values that are new or changed. This reduces /// traffic and performance. /// /// Unless you define some expectedProperties, setting key/values is always permitted. /// In this case, the property-setting client will not receive the new values from the server but /// instead update its local cache in SetCustomProperties. /// /// If you define expectedProperties, the server will skip updates if the server property-cache /// does not contain all expectedProperties with the same values. /// In this case, the property-setting client will get an update from the server and update it's /// cached key/values at about the same time as everyone else. /// /// The benefit of using expectedProperties can be only one client successfully sets a key from /// one known value to another. /// As example: Store who owns an item in a Custom Property "ownedBy". It's 0 initally. /// When multiple players reach the item, they all attempt to change "ownedBy" from 0 to their /// actorNumber. If you use expectedProperties {"ownedBy", 0} as condition, the first player to /// take the item will have it (and the others fail to set the ownership). /// /// Properties get saved with the game state for Turnbased games (which use IsPersistent = true). /// </remarks> /// <param name="propertiesToSet">Hashtable of Custom Properties to be set. </param> /// <param name="expectedValues">If non-null, these are the property-values the server will check as condition for this update.</param> /// <param name="webFlags">Defines if this SetCustomProperties-operation gets forwarded to your WebHooks. Client must be in room.</param> public void SetCustomProperties(Hashtable propertiesToSet, Hashtable expectedValues = null, WebFlags webFlags = null) { if (propertiesToSet == null) { return; } Hashtable customProps = propertiesToSet.StripToStringKeys() as Hashtable; Hashtable customPropsToCheck = expectedValues.StripToStringKeys() as Hashtable; // no expected values -> set and callback bool noCas = customPropsToCheck == null || customPropsToCheck.Count == 0; if (noCas) { this.CustomProperties.Merge(customProps); this.CustomProperties.StripKeysWithNullValues(); } // send (sync) these new values if in room if (this.RoomReference != null && this.RoomReference.IsLocalClientInside) { this.RoomReference.LoadBalancingClient.loadBalancingPeer.OpSetPropertiesOfActor(this.actorID, customProps, customPropsToCheck, webFlags); } }