/// <summary> /// Is called after a game object property was changed. /// </summary> /// <typeparam name="T">The type of the property value.</typeparam> /// <param name="gameProperty">The game object property.</param> /// <param name="oldValue">The old value.</param> /// <param name="newValue">The new value.</param> protected internal virtual void OnPropertyChanged <T>(GameProperty <T> gameProperty, T oldValue, T newValue) { // This method does not use GamePropertyEventArgs<T> to avoid creation/recycling of this // data structure when it is not really needed. OnPropertyChanged<T> should be called for // all property changes. But the creation of GamePropertyEventArgs<T> is only needed if // someone has attached to the PropertyChanged events. }
// Raises the GameProperty.Changed and GameObject.PropertyChanged events. internal void OnChanged(GameProperty <T> property, T oldValue, T newValue) { var handler = Changed; var gameObject = property.Owner; if (handler != null || gameObject.NeedToCallPropertyChanged) { // GameProperty.Changed or GameOwner.PropertyChanged must be called because event handlers // are registered. // Get args from resource pool var args = GamePropertyEventArgs <T> .Create(property, oldValue, newValue); // Call GameProperty.Changed event handlers. if (handler != null) { handler(gameObject, args); } // Call the virtual OnPropertyChanged method of the GameObject. gameObject.OnPropertyChanged(property, oldValue, newValue); // Call GameObject to raise GameObject.PropertyChanged event. gameObject.OnPropertyChanged(args); gameObject.OnPropertyChanged(property.Metadata.PropertyChangedEventArgs); args.Recycle(); } else { // Call the virtual OnPropertyChanged method of the GameObject. // (Derived classes can override this method.) gameObject.OnPropertyChanged(property, oldValue, newValue); } }
/// <summary> /// Indicates whether the current object is equal to another object of the same type. /// </summary> /// <param name="other">An object to compare with this object.</param> /// <returns> /// <see langword="true"/> if the current object is equal to the <paramref name="other"/> /// parameter; otherwise, <see langword="false"/>. /// </returns> public bool Equals(GameProperty <T> other) { if (_owner != other._owner) { return(false); } return(_metadata == other._metadata); }
// Raises the Changing event. internal void OnChanging(GameProperty <T> property, T oldValue, ref T newValue) { var handler = Changing; if (handler != null) { // Get args from resource pool. var args = GamePropertyEventArgs <T> .Create(property, oldValue, newValue); // Call event handlers. handler(property.Owner, args); // Changing event handlers can coerce the value. Return coerced value to caller. newValue = args.CoercedValue; args.Recycle(); } }
/// <summary> /// Initializes a new instance of the <see cref="GamePropertyChangeHandler{T}"/> class. /// </summary> /// <param name="gameProperty">The game property.</param> public GamePropertyChangeHandler(GameProperty <T> gameProperty) { _gameProperty = gameProperty; }
/// <inheritdoc/> public void Reset() { // Get local data. IGamePropertyData untypedData = Owner.PropertyData.Get(_metadata.Id); // Nothing to do if we have no local data. if (untypedData == null) { return; } // Nothing to do if the local data uses the default value. if (!untypedData.HasLocalValue) { return; } // Assert: We have a local value and must remove it. var data = ((GamePropertyData <T>)untypedData); // If the value is animated, changing the BaseValue does not cause events. var animatableData = untypedData as AnimatableGamePropertyData <T>; // Remember current value. T oldValue; bool isAnimated; if (animatableData != null) { oldValue = animatableData.BaseValue; isAnimated = animatableData.IsAnimated; } else { oldValue = data.Value; isAnimated = false; } // Get the target default value from template or metadata. T defaultValue; if (Owner.Template != null) { defaultValue = new GameProperty <T>(Owner.Template, _metadata).Value; } else { defaultValue = _metadata.DefaultValue; } if (isAnimated || EqualityComparer <T> .Default.Equals(oldValue, defaultValue)) { // oldValue and defaultValue are the same. We only have to reset the flag. data.HasLocalValue = false; data.Value = default(T); return; } var newValue = defaultValue; // Raise Changing event. data.OnChanging(this, oldValue, ref newValue); if (EqualityComparer <T> .Default.Equals(defaultValue, newValue)) { // After coercion in Changing, the target value is still the default value. // Value has been reset. data.HasLocalValue = false; data.Value = default(T); // Raise Changed event if oldValue is different from the newValue. if (!EqualityComparer <T> .Default.Equals(oldValue, defaultValue)) { data.OnChanged(this, oldValue, defaultValue); } } else { // Value was overwritten by Changing event handler! - We still have a local value! // Raise Changed event if oldValue is different from the newValue. if (!EqualityComparer <T> .Default.Equals(oldValue, newValue)) { data.Value = newValue; data.OnChanged(this, oldValue, newValue); } } }