282 lines
8.5 KiB
C#
282 lines
8.5 KiB
C#
|
|
using Rukhanka.Toolbox;
|
|
using Rukhanka.WaybackMachine;
|
|
using Unity;
|
|
using Unity.Burst;
|
|
using Unity.Collections;
|
|
using Unity.Collections.LowLevel.Unsafe;
|
|
using Unity.Entities;
|
|
using Unity.Mathematics;
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
namespace Rukhanka
|
|
{
|
|
[DisableAutoCreation]
|
|
public partial struct WaybackMachineRecordSystem: ISystem, ISystemStartStop
|
|
{
|
|
int frameCounter;
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
public void OnStartRunning(ref SystemState ss)
|
|
{
|
|
frameCounter = 0;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
public void OnStopRunning(ref SystemState ss)
|
|
{
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
[BurstCompile]
|
|
public void OnCreate(ref SystemState ss)
|
|
{
|
|
ss.RequireForUpdate<RecordComponent>();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void RecordAnimation(AnimationToProcessComponent atp, ref RecordComponent rc, int frameIndex)
|
|
{
|
|
var ahs = rc.wbData.Value.animHistory;
|
|
var curHistory = new AnimationHistoryData(atp, frameIndex);
|
|
|
|
// Search back for given animation in history
|
|
var foundIndex = -1;
|
|
for (var k = ahs.Length - 1; k >= 0; --k)
|
|
{
|
|
var ah = ahs[k];
|
|
if (ah.frameSpan.y + 1 != frameIndex)
|
|
continue;
|
|
|
|
if (ah.ComputeHash() == curHistory.ComputeHash())
|
|
{
|
|
foundIndex = k;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (foundIndex < 0)
|
|
{
|
|
foundIndex = ahs.Length;
|
|
curHistory.historyWeights = new (0xff, Allocator.Persistent);
|
|
curHistory.historyAnimTime = new (0xff, Allocator.Persistent);
|
|
ahs.Add(curHistory);
|
|
}
|
|
ref var historyElement = ref ahs.ElementAt(foundIndex);
|
|
historyElement.frameSpan.y = frameIndex;
|
|
|
|
var whv = new HistoryValue() { value = atp.weight, frameIndex = frameIndex };
|
|
historyElement.historyWeights.Add(whv);
|
|
var thv = new HistoryValue() { value = atp.time, frameIndex = frameIndex };
|
|
historyElement.historyAnimTime.Add(thv);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void RecordAnimationEvents(ref SystemState ss, Entity rce, ref RecordComponent rc)
|
|
{
|
|
if (!SystemAPI.HasBuffer<AnimationEventComponent>(rce))
|
|
return;
|
|
|
|
var animEvents = rc.wbData.Value.emittedAnimationEvents;
|
|
|
|
// Record animation events
|
|
for (var i = 0; i < animEvents.Length; ++i)
|
|
{
|
|
var aec = animEvents[i];
|
|
var ehd = new AnimationEventHistoryData(aec, frameCounter);
|
|
rc.wbData.Value.animationEventHistory.Add(ehd);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void RecordAnimations(ref SystemState ss, Entity rce, ref RecordComponent rc)
|
|
{
|
|
if (!SystemAPI.HasBuffer<AnimationToProcessComponent>(rce))
|
|
return;
|
|
|
|
var atps = SystemAPI.GetBuffer<AnimationToProcessComponent>(rce);
|
|
for (var i = 0; i < atps.Length; ++i)
|
|
{
|
|
var atp = atps[i];
|
|
RecordAnimation(atp, ref rc, frameCounter);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void RecordAnimatorTransition(in AnimatorControllerLayerComponent aclc, ref RecordComponent rc, int si, int di)
|
|
{
|
|
if (aclc.rtd.activeTransition.id < 0)
|
|
return;
|
|
|
|
ref var tb = ref aclc.controller.Value.layers[aclc.layerIndex].states[aclc.rtd.srcState.id].transitions[aclc.rtd.activeTransition.id];
|
|
var std = new AnimatorControllerTransitionHistoryData
|
|
{
|
|
frameSpan = new (frameCounter, frameCounter),
|
|
transitionId = aclc.rtd.activeTransition.id,
|
|
layerIndex = aclc.layerIndex,
|
|
dstStateId = aclc.rtd.dstState.id,
|
|
srcStateId = aclc.rtd.srcState.id,
|
|
weightRange = new float2(1) * aclc.rtd.activeTransition.normalizedDuration
|
|
};
|
|
|
|
var cth = rc.wbData.Value.controllerTransitionHistory;
|
|
|
|
// Search for existing entry in history
|
|
var i = cth.Length - 1;
|
|
for (; i >= 0; --i)
|
|
{
|
|
var ct = cth[i];
|
|
if (ct.srcStateId == std.srcStateId && ct.dstStateId == std.dstStateId && ct.frameSpan.y + 1 == frameCounter && std.layerIndex == ct.layerIndex)
|
|
break;
|
|
}
|
|
|
|
// If not found create new entry
|
|
if (i < 0)
|
|
{
|
|
i = cth.Length;
|
|
#if RUKHANKA_DEBUG_INFO
|
|
tb.name.CopyToWithTruncate(ref std.name);
|
|
#endif
|
|
cth.Add(std);
|
|
}
|
|
ref var csv = ref cth.ElementAt(i);
|
|
// If found update existing entry
|
|
csv.frameSpan.y = frameCounter;
|
|
csv.weightRange.y = aclc.rtd.activeTransition.normalizedDuration;
|
|
csv.srcStateDataIndex = si;
|
|
csv.dstStateDataIndex = di;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
int RecordAnimatorState(in AnimatorControllerLayerComponent aclc, int stateId, uint motionId, ref RecordComponent rc)
|
|
{
|
|
if (stateId < 0)
|
|
return -1;
|
|
|
|
var shd = new AnimatorControllerStateHistoryData(aclc, stateId, motionId, frameCounter);
|
|
var csh = rc.wbData.Value.controllerStateHistory;
|
|
|
|
// Search for existing entry in history
|
|
var i = csh.Length - 1;
|
|
for (; i >= 0; --i)
|
|
{
|
|
var cs = csh[i];
|
|
if (cs.stateId == shd.stateId &&
|
|
cs.frameSpan.y + 1 == frameCounter &&
|
|
cs.layerIndex == shd.layerIndex &&
|
|
cs.motionId == shd.motionId)
|
|
break;
|
|
}
|
|
|
|
// If not found create new entry
|
|
if (i < 0)
|
|
{
|
|
i = csh.Length;
|
|
csh.Add(shd);
|
|
}
|
|
ref var csv = ref csh.ElementAt(i);
|
|
// If found update existing entry
|
|
csv.frameSpan.y = frameCounter;
|
|
return i;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void RecordAnimatorStates(ref SystemState ss, Entity rce, ref RecordComponent rc)
|
|
{
|
|
if (!SystemAPI.HasBuffer<AnimatorControllerLayerComponent>(rce))
|
|
return;
|
|
|
|
var aclcs = SystemAPI.GetBuffer<AnimatorControllerLayerComponent>(rce);
|
|
for (var i = 0; i < aclcs.Length; ++i)
|
|
{
|
|
var aclc = aclcs[i];
|
|
var srcStateDataIndex = RecordAnimatorState(aclc, aclc.rtd.srcState.id, aclc.rtd.srcState.motionId, ref rc);
|
|
var dstStateDataIndex = RecordAnimatorState(aclc, aclc.rtd.dstState.id, aclc.rtd.dstState.motionId, ref rc);
|
|
RecordAnimatorTransition(aclc, ref rc, srcStateDataIndex, dstStateDataIndex);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void RecordAnimatorEvents(ref SystemState ss, Entity rce, ref RecordComponent rc)
|
|
{
|
|
if (!SystemAPI.HasBuffer<AnimatorControllerEventComponent>(rce))
|
|
return;
|
|
|
|
var acecs = rc.wbData.Value.emittedAnimatorEvents;
|
|
for (var i = 0; i < acecs.Length; ++i)
|
|
{
|
|
var acec = acecs[i];
|
|
var aehd = new AnimatorEventHistoryData(acec, frameCounter);
|
|
var k = -1;
|
|
// For every frame update events append it to the previous to make continuous span
|
|
if (aehd.eventType == AnimatorControllerEventComponent.EventType.StateUpdate)
|
|
{
|
|
k = rc.wbData.Value.animatorEventHistory.Length - 1;
|
|
for (; k >= 0; --k)
|
|
{
|
|
ref var hd = ref rc.wbData.Value.animatorEventHistory.ElementAt(k);
|
|
if (hd.stateId == aehd.stateId && hd.layerId == aehd.layerId && hd.eventType == AnimatorControllerEventComponent.EventType.StateUpdate)
|
|
{
|
|
hd.frameRange.y = frameCounter;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Find begin event for this event
|
|
if (aehd.eventType != AnimatorControllerEventComponent.EventType.StateEnter)
|
|
{
|
|
var l = rc.wbData.Value.animatorEventHistory.Length - 1;
|
|
for (; l >= 0; --l)
|
|
{
|
|
ref var hd = ref rc.wbData.Value.animatorEventHistory.ElementAt(l);
|
|
if (hd.stateId == aehd.stateId && hd.layerId == aehd.layerId && hd.eventType == AnimatorControllerEventComponent.EventType.StateEnter)
|
|
break;
|
|
}
|
|
|
|
if (l >= 0)
|
|
aehd.beginHistoryIndex = l;
|
|
}
|
|
|
|
// If previous update event was not found, or we are dealing with other event type - add new entry
|
|
if (k < 0)
|
|
{
|
|
rc.wbData.Value.animatorEventHistory.Add(aehd);
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
[BurstCompile]
|
|
public unsafe void OnUpdate(ref SystemState ss)
|
|
{
|
|
var rcd = SystemAPI.GetSingletonRW<RecordComponent>();
|
|
var rce = SystemAPI.GetSingletonEntity<RecordComponent>();
|
|
|
|
ref var rc = ref rcd.ValueRW;
|
|
var ptr = rc.wbData.GetUnsafePtr();
|
|
ptr->lastRecordedFrame = frameCounter;
|
|
|
|
RecordAnimatorStates(ref ss, rce, ref rc);
|
|
RecordAnimationEvents(ref ss, rce, ref rc);
|
|
RecordAnimatorEvents(ref ss, rce, ref rc);
|
|
RecordAnimations(ref ss, rce, ref rc);
|
|
|
|
frameCounter++;
|
|
rcd.ValueRW.wbData.Value.EndFrame();
|
|
}
|
|
}
|
|
}
|