Skip to content

Commit

Permalink
Merge pull request #169 from AnnulusGames/fix-sequence-item
Browse files Browse the repository at this point in the history
Add check if motion is in sequence
  • Loading branch information
yn01-dev authored Dec 8, 2024
2 parents 432ed8b + 4247763 commit b483028
Show file tree
Hide file tree
Showing 16 changed files with 135 additions and 87 deletions.
4 changes: 2 additions & 2 deletions src/LitMotion/Assets/LitMotion/Editor/MotionDebuggerWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,8 @@ void RenderDetailsPanel()
var selected = treeView.state.selectedIDs;
if (selected.Count > 0 && treeView.CurrentBindingItems.FirstOrDefault(x => x.id == selected[0]) is MotionDebuggerViewItem item)
{
ref var unmanagedData = ref MotionManager.GetDataRef(item.Handle);
ref var managedData = ref MotionManager.GetManagedDataRef(item.Handle);
ref var unmanagedData = ref MotionManager.GetDataRef(item.Handle, MotionStoragePermission.Admin);
ref var managedData = ref MotionManager.GetManagedDataRef(item.Handle, MotionStoragePermission.Admin);
var debugInfo = MotionManager.GetDebugInfo(item.Handle);

using (new EditorGUILayout.VerticalScope(GUI.skin.box))
Expand Down
5 changes: 5 additions & 0 deletions src/LitMotion/Assets/LitMotion/Runtime/Internal/Error.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,10 @@ public static void MotionHasBeenCanceledOrCompleted()
{
throw new InvalidOperationException("Motion has already been canceled or completed.");
}

public static void MotionIsInSequence()
{
throw new InvalidOperationException("Cannot access the motion in sequence.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public struct MotionDataCore
public MotionStatus Status;
public MotionStatus PrevStatus;
public bool IsPreserved;
public bool SkipUpdate;
public bool IsInSequence;

public ushort ComplpetedLoops;
public ushort PrevCompletedLoops;
Expand Down
32 changes: 16 additions & 16 deletions src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,17 @@ public static void Register<TValue, TOptions, TAdapter>(MotionStorage<TValue, TO
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ref MotionDataCore GetDataRef(MotionHandle handle)
public static ref MotionDataCore GetDataRef(MotionHandle handle, MotionStoragePermission permission)
{
CheckTypeId(handle);
return ref list[handle.StorageId].GetDataRef(handle);
return ref list[handle.StorageId].GetDataRef(handle, permission);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ref ManagedMotionData GetManagedDataRef(MotionHandle handle)
public static ref ManagedMotionData GetManagedDataRef(MotionHandle handle, MotionStoragePermission permission)
{
CheckTypeId(handle);
return ref list[handle.StorageId].GetManagedDataRef(handle);
return ref list[handle.StorageId].GetManagedDataRef(handle, permission);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand All @@ -41,31 +41,31 @@ public static MotionDebugInfo GetDebugInfo(MotionHandle handle)
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Complete(MotionHandle handle)
public static void Complete(MotionHandle handle, MotionStoragePermission permission)
{
CheckTypeId(handle);
list[handle.StorageId].Complete(handle);
list[handle.StorageId].Complete(handle, permission);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryComplete(MotionHandle handle)
public static bool TryComplete(MotionHandle handle, MotionStoragePermission permission)
{
CheckTypeId(handle);
return list[handle.StorageId].TryComplete(handle);
return list[handle.StorageId].TryComplete(handle, permission);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Cancel(MotionHandle handle)
public static void Cancel(MotionHandle handle, MotionStoragePermission permission)
{
CheckTypeId(handle);
list[handle.StorageId].Cancel(handle);
list[handle.StorageId].Cancel(handle, permission);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryCancel(MotionHandle handle)
public static bool TryCancel(MotionHandle handle, MotionStoragePermission permission)
{
CheckTypeId(handle);
return list[handle.StorageId].TryCancel(handle);
return list[handle.StorageId].TryCancel(handle, permission);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand All @@ -76,17 +76,17 @@ public static bool IsActive(MotionHandle handle)
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void SetTime(MotionHandle handle, double time)
public static void SetTime(MotionHandle handle, double time, MotionStoragePermission permission)
{
CheckTypeId(handle);
list[handle.StorageId].SetTime(handle, time);
list[handle.StorageId].SetTime(handle, time, permission);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void AddToSequence(ref MotionHandle handle, out double motionDuration)
public static void AddToSequence(MotionHandle handle, out double motionDuration)
{
CheckTypeId(handle);
list[handle.StorageId].AddToSequence(ref handle, out motionDuration);
list[handle.StorageId].AddToSequence(handle, out motionDuration);
}

// For MotionTracker
Expand Down
112 changes: 72 additions & 40 deletions src/LitMotion/Assets/LitMotion/Runtime/Internal/MotionStorage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,32 @@ internal record MotionDebugInfo
public object Options;
}

/// <summary>
/// Represents the permissions for a motion in MotionStorage.
/// </summary>
internal enum MotionStoragePermission : byte
{
/// <summary>
/// Only root motions can be accessed, motions inside a sequence cannot be accessed.
/// </summary>
User,
/// <summary>
/// Allows access to motions within a sequence.
/// </summary>
Admin,
}

internal interface IMotionStorage
{
bool IsActive(MotionHandle handle);
bool TryCancel(MotionHandle handle);
bool TryComplete(MotionHandle handle);
void Cancel(MotionHandle handle);
void Complete(MotionHandle handle);
void SetTime(MotionHandle handle, double time);
void AddToSequence(ref MotionHandle handle, out double motionDuration);
ref MotionDataCore GetDataRef(MotionHandle handle);
ref ManagedMotionData GetManagedDataRef(MotionHandle handle);
bool TryCancel(MotionHandle handle, MotionStoragePermission permission);
bool TryComplete(MotionHandle handle, MotionStoragePermission permission);
void Cancel(MotionHandle handle, MotionStoragePermission permission);
void Complete(MotionHandle handle, MotionStoragePermission permission);
void SetTime(MotionHandle handle, double time, MotionStoragePermission permission);
ref MotionDataCore GetDataRef(MotionHandle handle, MotionStoragePermission permission);
ref ManagedMotionData GetManagedDataRef(MotionHandle handle, MotionStoragePermission permission);
void AddToSequence(MotionHandle handle, out double motionDuration);
MotionDebugInfo GetDebugInfo(MotionHandle handle);
void Reset();
}
Expand Down Expand Up @@ -220,25 +235,28 @@ public bool IsActive(MotionHandle handle)
(motion.Core.Status is MotionStatus.Completed && motion.Core.IsPreserved);
}

public bool TryCancel(MotionHandle handle)
public bool TryCancel(MotionHandle handle, MotionStoragePermission permission)
{
return TryCancelCore(handle) == 0;
return TryCancelCore(handle, permission) == 0;
}

public void Cancel(MotionHandle handle)
public void Cancel(MotionHandle handle, MotionStoragePermission permission)
{
switch (TryCancelCore(handle))
switch (TryCancelCore(handle, permission))
{
case 1:
Error.MotionNotExists();
return;
case 2:
Error.MotionHasBeenCanceledOrCompleted();
return;
case 3:
Error.MotionIsInSequence();
return;
}
}

int TryCancelCore(MotionHandle handle)
int TryCancelCore(MotionHandle handle, MotionStoragePermission permission)
{
ref var slot = ref sparseSetCore.GetSlotRefUnchecked(handle.Index);
var denseIndex = slot.DenseIndex;
Expand All @@ -259,6 +277,11 @@ int TryCancelCore(MotionHandle handle)
return 2;
}

if (permission < MotionStoragePermission.Admin && unmanagedData.Core.IsInSequence)
{
return 3;
}

unmanagedData.Core.Status = MotionStatus.Canceled;

ref var managedData = ref managedDataArray[denseIndex];
Expand All @@ -267,14 +290,14 @@ int TryCancelCore(MotionHandle handle)
return 0;
}

public bool TryComplete(MotionHandle handle)
public bool TryComplete(MotionHandle handle, MotionStoragePermission permission)
{
return TryCompleteCore(handle) == 0;
return TryCompleteCore(handle, permission) == 0;
}

public void Complete(MotionHandle handle)
public void Complete(MotionHandle handle, MotionStoragePermission permission)
{
switch (TryCompleteCore(handle))
switch (TryCompleteCore(handle, permission))
{
case 1:
Error.MotionNotExists();
Expand All @@ -283,11 +306,14 @@ public void Complete(MotionHandle handle)
Error.MotionHasBeenCanceledOrCompleted();
return;
case 3:
Error.MotionIsInSequence();
return;
case 4:
throw new InvalidOperationException("Complete was ignored because it is not possible to complete a motion that loops infinitely. If you want to end the motion, call Cancel() instead.");
}
}

int TryCompleteCore(MotionHandle handle)
int TryCompleteCore(MotionHandle handle, MotionStoragePermission permission)
{
ref var slot = ref sparseSetCore.GetSlotRefUnchecked(handle.Index);

Expand All @@ -309,11 +335,16 @@ int TryCompleteCore(MotionHandle handle)
return 2;
}

if (unmanagedData.Core.Loops < 0)
if (permission < MotionStoragePermission.Admin && unmanagedData.Core.IsInSequence)
{
return 3;
}

if (unmanagedData.Core.Loops < 0)
{
return 4;
}

ref var managedData = ref managedDataArray[slot.DenseIndex];

unmanagedData.Core.Status = MotionStatus.Completed;
Expand Down Expand Up @@ -364,19 +395,21 @@ int TryCompleteCore(MotionHandle handle)
return 0;
}

public unsafe void SetTime(MotionHandle handle, double time)
public unsafe void SetTime(MotionHandle handle, double time, MotionStoragePermission permission)
{
ref var slot = ref sparseSetCore.GetSlotRefUnchecked(handle.Index);

var denseIndex = slot.DenseIndex;
if (IsDenseIndexOutOfRange(denseIndex)) Error.MotionNotExists();

var version = slot.Version;
if (version <= 0 || version != handle.Version) Error.MotionNotExists();

fixed (MotionData<TValue, TOptions>* ptr = unmanagedDataArray)
{
var dataPtr = ptr + denseIndex;

var version = slot.Version;
if (version <= 0 || version != handle.Version) Error.MotionNotExists();
if (permission < MotionStoragePermission.Admin && dataPtr->Core.IsInSequence) Error.MotionIsInSequence();

MotionHelper.Update<TValue, TOptions, TAdapter>(dataPtr, time, out var result);

Expand Down Expand Up @@ -413,9 +446,9 @@ public unsafe void SetTime(MotionHandle handle, double time)
}
}

public void AddToSequence(ref MotionHandle handle, out double motionDuration)
public void AddToSequence(MotionHandle handle, out double motionDuration)
{
ref var slot = ref GetSlotWithVarify(handle);
ref var slot = ref GetSlotWithVarify(handle, MotionStoragePermission.Admin);
ref var dataRef = ref unmanagedDataArray[slot.DenseIndex];

if (dataRef.Core.Status is not MotionStatus.Scheduled)
Expand All @@ -430,31 +463,24 @@ public void AddToSequence(ref MotionHandle handle, out double motionDuration)
}

dataRef.Core.IsPreserved = true;
dataRef.Core.SkipUpdate = true;

// ref var managedDataRef = ref managedDataArray[slot.DenseIndex];
// managedDataRef.SkipValuesDuringDelay = true;

// increment version
slot.Version++;
handle.Version++;
dataRef.Core.IsInSequence = true;
}

public ref ManagedMotionData GetManagedDataRef(MotionHandle handle)
public ref ManagedMotionData GetManagedDataRef(MotionHandle handle, MotionStoragePermission permission)
{
ref var slot = ref GetSlotWithVarify(handle);
ref var slot = ref GetSlotWithVarify(handle, permission);
return ref managedDataArray[slot.DenseIndex];
}

public ref MotionDataCore GetDataRef(MotionHandle handle)
public ref MotionDataCore GetDataRef(MotionHandle handle, MotionStoragePermission permission)
{
ref var slot = ref GetSlotWithVarify(handle);
ref var slot = ref GetSlotWithVarify(handle, permission);
return ref UnsafeUtility.As<MotionData<TValue, TOptions>, MotionDataCore>(ref unmanagedDataArray[slot.DenseIndex]);
}

public MotionDebugInfo GetDebugInfo(MotionHandle handle)
{
ref var slot = ref GetSlotWithVarify(handle);
ref var slot = ref GetSlotWithVarify(handle, MotionStoragePermission.Admin);
ref var dataRef = ref unmanagedDataArray[slot.DenseIndex];

return new()
Expand All @@ -466,17 +492,23 @@ public MotionDebugInfo GetDebugInfo(MotionHandle handle)
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
ref SparseSetCore.Slot GetSlotWithVarify(MotionHandle handle)
ref SparseSetCore.Slot GetSlotWithVarify(MotionHandle handle, MotionStoragePermission permission)
{
ref var slot = ref sparseSetCore.GetSlotRefUnchecked(handle.Index);
if (IsDenseIndexOutOfRange(slot.DenseIndex)) Error.MotionNotExists();

if (IsInvalidVersion(slot.Version, handle) ||
unmanagedDataArray[slot.DenseIndex].Core.Status == MotionStatus.None)
ref var dataRef = ref unmanagedDataArray[slot.DenseIndex];

if (IsInvalidVersion(slot.Version, handle) || dataRef.Core.Status == MotionStatus.None)
{
Error.MotionNotExists();
}

if (permission < MotionStoragePermission.Admin && dataRef.Core.IsInSequence)
{
Error.MotionIsInSequence();
}

return ref slot;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ protected void Initialize(MotionHandle motionHandle, MotionCancelBehavior cancel
this.cancelAwaitOnMotionCanceled = cancelAwaitOnMotionCanceled;
this.cancellationToken = cancellationToken;

ref var managedData = ref MotionManager.GetManagedDataRef(motionHandle);
ref var managedData = ref MotionManager.GetManagedDataRef(motionHandle, MotionStoragePermission.Admin);
originalCancelAction = managedData.OnCancelAction;
originalCompleteAction = managedData.OnCompleteAction;
managedData.OnCancelAction = onCancelCallbackDelegate;
Expand Down Expand Up @@ -129,7 +129,7 @@ protected void RestoreOriginalCallback(bool checkIsActive = true)
{
if (checkIsActive && !motionHandle.IsActive()) return;

ref var managedData = ref MotionManager.GetManagedDataRef(motionHandle);
ref var managedData = ref MotionManager.GetManagedDataRef(motionHandle, MotionStoragePermission.Admin);
managedData.OnCancelAction = originalCancelAction;
managedData.OnCompleteAction = originalCompleteAction;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public unsafe void Update(double time, double unscaledTime, double realtime)
{
var currentDataPtr = dataPtr + i;

if (currentDataPtr->Core.SkipUpdate) continue;
if (currentDataPtr->Core.IsInSequence) continue;

var status = currentDataPtr->Core.Status;
ref var managedData = ref managedDataSpan[i];
Expand Down
2 changes: 1 addition & 1 deletion src/LitMotion/Assets/LitMotion/Runtime/MotionAwaiter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public void UnsafeOnCompleted(Action continuation)
{
if (continuation == null) return;

ref var managedData = ref MotionManager.GetManagedDataRef(handle);
ref var managedData = ref MotionManager.GetManagedDataRef(handle, MotionStoragePermission.Admin);
managedData.OnCompleteAction += continuation;
managedData.OnCancelAction += continuation;
}
Expand Down
Loading

0 comments on commit b483028

Please sign in to comment.