protected override void OnUpdate() { var beginSystem = World.GetExistingSystem <ChangeDetectionSystemBegin>(); if (beginSystem == null) { UnityEngine.Debug.LogWarning($"{nameof(ChangeDetectionSystemEnd)} cannot detect changes without the existance of {nameof(ChangeDetectionSystemBegin)}"); return; } if (!beginSystem.HasUpdatedAtLeastOnce) { return; } ChangeDetection.RecordEntityTrace(EntityManager, _endTrace); // compare 'begin values' with 'end values' ChangeDetection.CompareAndLogChanges(beginSystem.Trace, _endTrace); }
/// <inheritdoc /> public Task SetParametersAsync(ParameterView parameters) { // Implementing the parameter binding manually, instead of just calling // parameters.SetParameterProperties(this), is just a very slight perf optimization // and makes it simpler impose rules about the params being required or not. var hasSuppliedValue = false; var previousValue = Value; var previousFixed = IsFixed; Value = default; ChildContent = null; Name = null; IsFixed = false; foreach (var parameter in parameters) { if (parameter.Name.Equals(nameof(Value), StringComparison.OrdinalIgnoreCase)) { Value = (TValue)parameter.Value; hasSuppliedValue = true; } else if (parameter.Name.Equals(nameof(ChildContent), StringComparison.OrdinalIgnoreCase)) { ChildContent = (RenderFragment)parameter.Value; } else if (parameter.Name.Equals(nameof(Name), StringComparison.OrdinalIgnoreCase)) { Name = (string)parameter.Value; if (string.IsNullOrEmpty(Name)) { throw new ArgumentException($"The parameter '{nameof(Name)}' for component '{nameof(CascadingValue<TValue>)}' does not allow null or empty values."); } } else if (parameter.Name.Equals(nameof(IsFixed), StringComparison.OrdinalIgnoreCase)) { IsFixed = (bool)parameter.Value; } else { throw new ArgumentException($"The component '{nameof(CascadingValue<TValue>)}' does not accept a parameter with the name '{parameter.Name}'."); } } if (_hasSetParametersPreviously && IsFixed != previousFixed) { throw new InvalidOperationException($"The value of {nameof(IsFixed)} cannot be changed dynamically."); } _hasSetParametersPreviously = true; // It's OK for the value to be null, but some "Value" param must be supplied // because it serves no useful purpose to have a <CascadingValue> otherwise. if (!hasSuppliedValue) { throw new ArgumentException($"Missing required parameter '{nameof(Value)}' for component '{GetType().Name}'."); } // Rendering is most efficient when things are queued from rootmost to leafmost. // Given a components A (parent) -> B (child), you want them to be queued in order // [A, B] because if you had [B, A], then the render for A might change B's params // making it render again, so you'd render [B, A, B], which is wasteful. // At some point we might consider making the render queue actually enforce this // ordering during insertion. // // For the CascadingValue component, this observation is why it's important to render // ourself before notifying subscribers (which can be grandchildren or deeper). // If we rerendered subscribers first, then our own subsequent render might cause an // further update that makes those nested subscribers get rendered twice. _renderHandle.Render(Render); if (_subscribers != null && ChangeDetection.MayHaveChanged(previousValue, Value)) { NotifySubscribers(parameters.Lifetime); } return(Task.CompletedTask); }
bool TempInputsHaveChanged(TempEntry entry, ChangeDetection detection) { for (int i = 0; i < entry.Inputs.Count; i++) { if (CheckChanged(detection, new FileInfo(entry.InputPaths[i]), entry.Inputs[i])) return true; } return entry.TempDependencies.Any(t => TempInputsHaveChanged(t, detection)); }
bool CheckChanged(ChangeDetection detection, FileInfo file, FileEntry entry) { if (!file.Exists) return true; if ((detection & ChangeDetection.Length) != 0 && file.Length != entry.Length) return true; if ((detection & ChangeDetection.Timestamp) != 0 && file.LastWriteTimeUtc != entry.Timestamp) return true; if ((detection & ChangeDetection.Hash) != 0 && HashFile(file) != entry.Hash) return true; return false; }
protected override void OnUpdate() { HasUpdatedAtLeastOnce = true; ChangeDetection.RecordEntityTrace(EntityManager, Trace); }