private static void OnBeforeExpectedChange(this ValueAccess access, object target) { object value; if (BufferedChanges.ContainsKey(access) && BufferedChanges[access].TryGetValue(target, out ValueChangeRequest cache)) { value = cache.RequestedValue; access.Set(target, value); } else { value = access.Get(target); } ActiveFields.Push(new ValueData(access, target, value)); }
private static void PopActiveFields() { while (ActiveFields.Count > 0) { ValueData data = ActiveFields.Pop(); if (data == null) { break; // The marker } ValueAccess field = data.Access; object newValue = data.Access.Get(data.Target); bool changed = !Equals(newValue, data.Value); Dictionary <object, ValueChangeRequest> fieldBuffer = BufferedChanges.Assert(field); if (fieldBuffer.TryGetValue(data.Target, out ValueChangeRequest cached)) { if (changed && cached.RequestProcessed) { cached.RequestProcessed = false; } cached.RequestedValue = newValue; field.Set(data.Target, cached.LatestActualValue); continue; } if (!changed) { continue; } fieldBuffer[data.Target] = new ValueChangeRequest { LatestActualValue = data.Value, RequestedValue = newValue }; field.Set(data.Target, data.Value); } }
/// <summary> /// During the execution of any of the <paramref name="triggers" /> methods, any change to the /// value will not be applied but instead written to the change buffer /// <see cref="BufferedChanges" />. /// </summary> /// <param name="value">Accessor to the value</param> /// <param name="triggers"> /// Trigger methods during which the changes to the value are written to the /// buffer instead /// </param> /// <param name="condition">The buffer is only active if the condition evaluates to true</param> public static void Intercept( ValueAccess value, IEnumerable <MethodAccess> triggers, Func <bool> condition) { lock (Patcher.HarmonyLock) { foreach (MethodAccess method in triggers) { Patcher.HarmonyInstance.Patch(method.MemberInfo, PatchPrefix, PatchPostfix); method.SetGlobalHandler( (instance, args) => { if (condition()) { value.OnBeforeExpectedChange(instance); } }); } } }
public ValueData([NotNull] ValueAccess access, object target, object value) { Access = access; Target = target; Value = value; }