Fix ADV transition and nested input lifecycles
This commit is contained in:
@@ -934,38 +934,41 @@ public sealed class GfxState
|
||||
(o.RotationEnabled && o.RotationPeriodMs > 0)));
|
||||
}
|
||||
|
||||
/// <summary>Force the finite retained presentation serviced by native run-state bit 0x400 to its
|
||||
/// endpoint. This is the EffectSkipOnClick path: type-0 surface commands and ordinary finite object
|
||||
/// channels complete together, while movie masks, ambient cycles, and op-0x242-detached channels remain
|
||||
/// active. Op 0x24e bit 0 disables click skipping; bit 1 suppresses the shared force-complete request.</summary>
|
||||
public int CompleteClickSkippableTimedPresentation(long nowMs)
|
||||
/// <summary>Consume the native run-state-0x400 EffectSkipOnClick action and, when permitted, force its
|
||||
/// finite retained presentation to the endpoint. Bit 0 of op 0x24e rejects the action entirely. Bit 1
|
||||
/// still allows the service wait to end but suppresses the shared force-complete request. Movie masks,
|
||||
/// ambient cycles, and op-0x242-detached channels continue asynchronously after the service resumes.</summary>
|
||||
public bool TryCompleteClickSkippableTimedPresentation(long nowMs, out int completed)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if ((AnimationServiceFlags & 3) != 0) return 0;
|
||||
completed = 0;
|
||||
if ((AnimationServiceFlags & 1) != 0) return false;
|
||||
|
||||
int completed = 0;
|
||||
foreach (var t in _surfaceTransitions.Values)
|
||||
if ((AnimationServiceFlags & 2) == 0)
|
||||
{
|
||||
if (t.Forced || TransitionProgress(t, nowMs) >= 1.0) continue;
|
||||
t.Forced = true;
|
||||
completed++;
|
||||
}
|
||||
foreach (var t in _surfaceTransitions.Values)
|
||||
{
|
||||
if (t.Forced || TransitionProgress(t, nowMs) >= 1.0) continue;
|
||||
t.Forced = true;
|
||||
completed++;
|
||||
}
|
||||
|
||||
completed += CountOneShotChannels(_rangeTransform);
|
||||
foreach (var o in _objects.Values)
|
||||
{
|
||||
if ((o.OneShotAnimationControlFlags & 1) != 0) continue;
|
||||
completed += CountOneShotChannels(o);
|
||||
}
|
||||
ForceCompleteOneShotChannels();
|
||||
completed += CountOneShotChannels(_rangeTransform);
|
||||
foreach (var o in _objects.Values)
|
||||
{
|
||||
if ((o.OneShotAnimationControlFlags & 1) != 0) continue;
|
||||
completed += CountOneShotChannels(o);
|
||||
}
|
||||
ForceCompleteOneShotChannels();
|
||||
|
||||
if (AnimClockDurationTicks != 0) completed++;
|
||||
AnimClockDurationTicks = 0;
|
||||
AnimClockGeneration++;
|
||||
if (AnimClockDurationTicks != 0) completed++;
|
||||
AnimClockDurationTicks = 0;
|
||||
AnimClockGeneration++;
|
||||
}
|
||||
|
||||
if (completed > 0) MarkRetainedMutation();
|
||||
return completed;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -83,7 +83,6 @@ public sealed class VirtualMachine
|
||||
private bool _sharedProfileShutdownHandled;
|
||||
private volatile bool _messageSkipEnabled;
|
||||
private volatile bool _messageSkipServiceActive;
|
||||
private volatile bool _advSkipServiceEnabled;
|
||||
private bool _advReadSkipState;
|
||||
private AdvTextStyle _advTextStyle = AdvTextStyle.Default;
|
||||
private int _messageWindowAlphaSetting;
|
||||
@@ -138,10 +137,18 @@ public sealed class VirtualMachine
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>True while a script-owned timed mouse/input callback loop (HISTORY/HIDEWIN family) owns input.</summary>
|
||||
/// <summary>True while the currently executing script frame owns a timed raw mouse/input callback
|
||||
/// loop (HISTORY/HIDEWIN/FIELD family). A registered callback in a suspended parent frame is dormant
|
||||
/// while a nested ADV scene owns the VM and must not suppress that child's ordinary page input.</summary>
|
||||
public bool IsRawInputCallbackActive
|
||||
{
|
||||
get { lock (_interactiveLock) return _rawInputFrame != null; }
|
||||
get
|
||||
{
|
||||
ExecFrame? rawInputFrame;
|
||||
lock (_interactiveLock) rawInputFrame = _rawInputFrame;
|
||||
if (rawInputFrame == null) return false;
|
||||
lock (_debugControlLock) return ReferenceEquals(rawInputFrame, _debugActiveFrame);
|
||||
}
|
||||
}
|
||||
public string? RawInputCallbackScriptName
|
||||
{
|
||||
@@ -357,13 +364,13 @@ public sealed class VirtualMachine
|
||||
} while (Interlocked.CompareExchange(ref field, after, before) != before);
|
||||
}
|
||||
|
||||
/// <summary>Mirror adv_interpreter_tick's bit-0x40 path. The bit is logical action 6 from the
|
||||
/// <summary>Mirror adv_interpreter_tick's live bit-0x40 poll. The bit is logical action 6 from the
|
||||
/// process-owned binding map, not a hardcoded Ctrl test; Himegari also binds C and retains the
|
||||
/// engine's default Backspace binding. The presentation lifecycle gate prevents a held action
|
||||
/// from leaking into non-ADV script execution.</summary>
|
||||
/// engine's default Backspace binding. Native polls this physical channel independently of the
|
||||
/// op-0x19b/0x19c lifecycle used by persistent/read-message Skip.</summary>
|
||||
private void RefreshPhysicalMessageSkipState()
|
||||
{
|
||||
bool active = _advSkipServiceEnabled && (InputBindings.PollActionMask() & 0x40) != 0;
|
||||
bool active = (InputBindings.PollActionMask() & 0x40) != 0;
|
||||
_host.SetPhysicalMessageSkipActive(active);
|
||||
}
|
||||
|
||||
@@ -790,7 +797,6 @@ public sealed class VirtualMachine
|
||||
_autoVoicePending = false;
|
||||
_messageSkipEnabled = false;
|
||||
_messageSkipServiceActive = false;
|
||||
_advSkipServiceEnabled = false;
|
||||
_advReadSkipState = false;
|
||||
_advTextStyle = AdvTextStyle.Default;
|
||||
_systemMenuActionsEnabled = 1;
|
||||
@@ -799,6 +805,7 @@ public sealed class VirtualMachine
|
||||
_host.SetMessageSkipActive(false);
|
||||
_host.SetPhysicalMessageSkipActive(false);
|
||||
_host.ResetSceneContext();
|
||||
RefreshPhysicalMessageSkipState();
|
||||
}
|
||||
|
||||
private static Stack<int>[] CreateIntegerStacks()
|
||||
@@ -2276,22 +2283,19 @@ public sealed class VirtualMachine
|
||||
Write(a[0], _messageSkipEnabled ? 1 : 0); return pc + 1;
|
||||
case "u00414E80":
|
||||
case "suspend-adv-skip-service": // 0x19b: preserve the toggle while leaving ADV presentation
|
||||
_advSkipServiceEnabled = false;
|
||||
_messageSkipServiceActive = false;
|
||||
_host.SetMessageSkipActive(false);
|
||||
_host.SetPhysicalMessageSkipActive(false);
|
||||
return pc + 1;
|
||||
case "u00414EC0":
|
||||
case "resume-adv-skip-service": // 0x19c: recompute active fast-forward on ADV entry
|
||||
_advSkipServiceEnabled = true;
|
||||
_messageSkipServiceActive =
|
||||
_messageSkipEnabled || _advReadSkipState || _host.IsAdvReadSkipActive;
|
||||
_host.SetMessageSkipActive(_messageSkipServiceActive);
|
||||
RefreshPhysicalMessageSkipState();
|
||||
return pc + 1;
|
||||
case "get-message-skip": // 0x1c7: persistent Skip or host-supplied Ctrl fast-forward
|
||||
// The native per-op tick continually re-arms the transient run-state bit while the
|
||||
// ADV service is enabled. The host channel also carries physical fast-forward input.
|
||||
// Native persistent state and the independently polled physical action-6 channel both
|
||||
// re-arm the transient run-state bit consumed by this query.
|
||||
Write(a[0], _messageSkipServiceActive || _host.IsMessageSkipActive ? 1 : 0); return pc + 1;
|
||||
case "get-adv-read-skip-state": // 0x1cc: per-message read/click skip service state
|
||||
case "get-adv-service-state": // compatibility with pre-recovery generated tables
|
||||
|
||||
Reference in New Issue
Block a user