using Rukhanka.WaybackMachine; using Unity.Burst; using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; using Unity.Entities; using Unity.Jobs; ///////////////////////////////////////////////////////////////////////////////////////////////////// namespace Rukhanka { [DisableAutoCreation] [BurstCompile] [UpdateAfter(typeof(AnimatorControllerSystem))] public partial struct FillAnimationsFromControllerSystem: ISystem { EntityQuery fillAnimationsBufferQuery; ///////////////////////////////////////////////////////////////////////////////////////////////////// [BurstCompile] public void OnCreate(ref SystemState ss) { fillAnimationsBufferQuery = SystemAPI.QueryBuilder() .WithAll() .Build(); ss.RequireForUpdate(fillAnimationsBufferQuery); } ///////////////////////////////////////////////////////////////////////////////////////////////////// [BurstCompile] public void OnDestroy(ref SystemState ss) { if (SystemAPI.TryGetSingletonRW(out var internalDataSingleton)) internalDataSingleton.ValueRW.Dispose(); } ///////////////////////////////////////////////////////////////////////////////////////////////////// [BurstCompile] public void OnUpdate(ref SystemState ss) { var entityTypeHandle = SystemAPI.GetEntityTypeHandle(); var controllerLayersBufferHandleRO = SystemAPI.GetBufferTypeHandle(true); var controllerParametersBufferHandleRO = SystemAPI.GetBufferTypeHandle(true); var animatorOverrideAnimationsLookup = SystemAPI.GetComponentLookup(true); var animationToProcessBufferHandle = SystemAPI.GetBufferTypeHandle(); var animDBSingleton = SystemAPI.GetSingleton(); var internalDataSingletonQuery = SystemAPI.QueryBuilder().WithAllRW().Build(); var internalAnimatorData = GetInternalDataSingleton(internalDataSingletonQuery, ref ss); var fillAnimationsBufferJob = new FillAnimationsBufferJob() { controllerLayersBufferHandle = controllerLayersBufferHandleRO, controllerParametersBufferHandle = controllerParametersBufferHandleRO, animationToProcessBufferHandle = animationToProcessBufferHandle, animatorOverrideAnimationLookup = animatorOverrideAnimationsLookup, entityTypeHandle = entityTypeHandle, animationDatabase = animDBSingleton.animations, avatarMaskDatabase = animDBSingleton.avatarMasks, animatorOverrideAnimationsMap = internalAnimatorData.animatorOverrideAnimationsMap.AsParallelWriter() }; ss.Dependency = fillAnimationsBufferJob.ScheduleParallel(fillAnimationsBufferQuery, ss.Dependency); ss.Dependency = CopyEventsForWaybackMachineDuringRecording(ref ss, ss.Dependency); } ///////////////////////////////////////////////////////////////////////////////////////////////////// internal static InternalAnimatorDataSingleton GetInternalDataSingleton(EntityQuery singletonQuery, ref SystemState ss) { if (singletonQuery.TryGetSingletonRW(out var internalAnimatorData)) return internalAnimatorData.ValueRW; var iads = InternalAnimatorDataSingleton.MakeDefault(); ss.EntityManager.CreateSingleton(iads, "Rukhanka.InternalAnimatorDataSingleton"); return iads; } ///////////////////////////////////////////////////////////////////////////////////////////////////// internal static unsafe BlobAssetReference GetControllerAnimationsBlob ( Entity e, ComponentLookup animatorOverrideAnimationLookup, BlobAssetReference cab, NativeParallelHashMap>.ParallelWriter animatorOverrideAnimationsMap ) { if (animatorOverrideAnimationLookup.TryGetComponent(e, out var animationOverrides) && animatorOverrideAnimationLookup.IsComponentEnabled(e)) { // Try cache first var combinedHash = animationOverrides.value.GetHashCode() ^ cab.GetHashCode(); if (UnsafeParallelHashMapBase> .TryGetFirstValueAtomic(animatorOverrideAnimationsMap.m_Writer.m_Buffer, combinedHash, out var rv, out _)) return rv; // Merge controller animations and override animations var bb = new BlobBuilder(Allocator.Temp); ref var mergedBlobAsset = ref bb.ConstructRoot(); var animsArr = bb.Allocate(ref mergedBlobAsset.animations, cab.Value.animations.Length); for (var i = 0; i < animsArr.Length; ++i) { var overrideAnim = animationOverrides.value.Value.animations[i]; animsArr[i] = overrideAnim.IsValid ? overrideAnim : cab.Value.animations[i]; } rv = bb.CreateBlobAssetReference(Allocator.Persistent); animatorOverrideAnimationsMap.TryAdd(combinedHash, rv); return rv; } return cab; } ///////////////////////////////////////////////////////////////////////////////////////////////////// JobHandle CopyEventsForWaybackMachineDuringRecording(ref SystemState ss, JobHandle dependsOn) { if (!SystemAPI.TryGetSingletonRW(out var rcd)) return dependsOn; var copyEventsToWaybackMachineJob = new CopyAnimatorEventsToWaybackMachineRecordingJob() { outEvents = rcd.ValueRW.wbData.Value.emittedAnimatorEvents }; var jh = copyEventsToWaybackMachineJob.Schedule(dependsOn); return jh; } } }