mirror of
https://github.com/maxartz15/VertexAnimation.git
synced 2025-02-20 13:19:32 +01:00
Rewrote Animator to ISystem
This commit is contained in:
parent
9f8a7fb7d8
commit
9dca839eaf
@ -17,7 +17,7 @@ namespace TAO.VertexAnimation
|
|||||||
public uint Seed;
|
public uint Seed;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal struct SkinnedMeshEntity : IBufferElementData
|
public struct SkinnedMeshEntity : IBufferElementData
|
||||||
{
|
{
|
||||||
public Entity Value;
|
public Entity Value;
|
||||||
}
|
}
|
||||||
@ -75,7 +75,7 @@ public class AnimationLibraryComponentBaker : Baker < AnimationLibraryComponentA
|
|||||||
Random random = new Random( authoring.Seed != 0 ? authoring.Seed : 42 );
|
Random random = new Random( authoring.Seed != 0 ? authoring.Seed : 42 );
|
||||||
int index = random.NextInt( 20 );
|
int index = random.NextInt( 20 );
|
||||||
// Add animator to 'parent'.
|
// Add animator to 'parent'.
|
||||||
VA_AnimatorComponent animatorComponent = new VA_AnimatorComponent
|
AnimatorComponent animatorComponent = new AnimatorComponent
|
||||||
{
|
{
|
||||||
Enabled = true,
|
Enabled = true,
|
||||||
AnimationName = animationsRef.animations[index].name,
|
AnimationName = animationsRef.animations[index].name,
|
||||||
@ -87,7 +87,7 @@ public class AnimationLibraryComponentBaker : Baker < AnimationLibraryComponentA
|
|||||||
AddComponent(animatorComponent);
|
AddComponent(animatorComponent);
|
||||||
|
|
||||||
|
|
||||||
VA_AnimatorBlendStateComponent animatorStateComponent = new VA_AnimatorBlendStateComponent
|
AnimatorBlendStateComponent animatorStateComponent = new AnimatorBlendStateComponent
|
||||||
{
|
{
|
||||||
BlendingEnabled = true,
|
BlendingEnabled = true,
|
||||||
AnimationIndex = 1,
|
AnimationIndex = 1,
|
||||||
@ -110,21 +110,24 @@ public class AnimationLibraryComponentBaker : Baker < AnimationLibraryComponentA
|
|||||||
}
|
}
|
||||||
|
|
||||||
//[GenerateAuthoringComponent]
|
//[GenerateAuthoringComponent]
|
||||||
public struct VA_AnimatorComponent : IComponentData
|
public struct AnimatorComponent : IComponentData
|
||||||
{
|
{
|
||||||
public bool Enabled;
|
public bool Enabled;
|
||||||
public FixedString64Bytes AnimationName;
|
public FixedString64Bytes AnimationName;
|
||||||
public int AnimationIndex;
|
public int AnimationIndex;
|
||||||
public int AnimationIndexNext;
|
public int AnimationIndexNext;
|
||||||
public float AnimationTime;
|
public float AnimationTime;
|
||||||
|
public float AnimationTimeNext;
|
||||||
public BlobAssetReference<VA_AnimationLibraryData> AnimationLibrary;
|
public BlobAssetReference<VA_AnimationLibraryData> AnimationLibrary;
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct VA_AnimatorBlendStateComponent : IComponentData
|
public struct AnimatorBlendStateComponent : IComponentData
|
||||||
{
|
{
|
||||||
public bool BlendingEnabled;
|
public bool BlendingEnabled;
|
||||||
public int AnimationIndex;
|
public int AnimationIndex;
|
||||||
public int AnimationIndexNext;
|
public int AnimationIndexNext;
|
||||||
public float AnimationTime;
|
public float AnimationTime;
|
||||||
|
public float AnimationTimeNext;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,152 +4,6 @@ using Unity.Mathematics;
|
|||||||
namespace TAO.VertexAnimation
|
namespace TAO.VertexAnimation
|
||||||
{
|
{
|
||||||
|
|
||||||
public readonly partial struct AnimatorAspect : IAspect
|
|
||||||
{
|
|
||||||
private readonly RefRW < VA_AnimatorComponent > m_Animator;
|
|
||||||
private readonly RefRW < VA_AnimatorBlendStateComponent > m_AnimatorBlendState;
|
|
||||||
private readonly DynamicBuffer < SkinnedMeshEntity > m_SkinnedMeshEntities;
|
|
||||||
|
|
||||||
public void UpdateAnimator(float deltaTime, EntityCommandBuffer.ParallelWriter ecb, ref int startIndex)
|
|
||||||
{
|
|
||||||
if ( m_Animator.ValueRO.Enabled )
|
|
||||||
{
|
|
||||||
// Get the animation lib data.
|
|
||||||
ref VA_AnimationLibraryData animationsRef = ref m_Animator.ValueRO.AnimationLibrary.Value;
|
|
||||||
|
|
||||||
//if ( m_Animator.ValueRO.AnimationName != vaAnimatorStateComponent.CurrentAnimationName )
|
|
||||||
//{
|
|
||||||
// // Set the animation index on the AnimatorComponent to play this animation.
|
|
||||||
// m_Animator.ValueRO.AnimationIndexNext = VA_AnimationLibraryUtils.GetAnimation(ref animationsRef, vaAnimatorStateComponent.CurrentAnimationName);
|
|
||||||
// m_Animator.ValueRO.AnimationName = vaAnimatorStateComponent.CurrentAnimationName;
|
|
||||||
//}
|
|
||||||
|
|
||||||
// 'Play' the actual animation.
|
|
||||||
m_Animator.ValueRW.AnimationTime += deltaTime * animationsRef.animations[m_Animator.ValueRO.AnimationIndex].frameTime;
|
|
||||||
|
|
||||||
if ( m_Animator.ValueRO.AnimationTime > animationsRef.animations[m_Animator.ValueRO.AnimationIndex].duration )
|
|
||||||
{
|
|
||||||
// Set time. Using the difference to smoothen out animations when looping.
|
|
||||||
m_Animator.ValueRW.AnimationTime -= animationsRef.animations[m_Animator.ValueRO.AnimationIndex].duration;
|
|
||||||
|
|
||||||
//m_Animator.ValueRW.animationIndexNext = vaAnimatorStateComponent.Rand.NextInt( 20 );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lerp animations.
|
|
||||||
// Set animation for lerp.
|
|
||||||
int animationIndexNext = m_Animator.ValueRO.AnimationIndexNext;
|
|
||||||
|
|
||||||
if ( animationIndexNext < 0 )
|
|
||||||
{
|
|
||||||
animationIndexNext = m_Animator.ValueRO.AnimationIndex;
|
|
||||||
|
|
||||||
//m_Animator.ValueRO.animationIndexNext = animationIndexNext + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate next frame time for lerp.
|
|
||||||
float animationTimeNext = m_Animator.ValueRO.AnimationTime +
|
|
||||||
( 1.0f / animationsRef.animations[animationIndexNext].maxFrames );
|
|
||||||
|
|
||||||
if ( animationTimeNext > animationsRef.animations[animationIndexNext].duration )
|
|
||||||
{
|
|
||||||
// Set time. Using the difference to smooth out animations when looping.
|
|
||||||
animationTimeNext -= m_Animator.ValueRO.AnimationTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
int animationIndexNextBlend = 0;
|
|
||||||
float animationTimeNextBlend = 0.0f;
|
|
||||||
|
|
||||||
if ( m_AnimatorBlendState.ValueRO.BlendingEnabled )
|
|
||||||
{
|
|
||||||
// 'Play' the actual animation.
|
|
||||||
m_AnimatorBlendState.ValueRW.AnimationTime += deltaTime *
|
|
||||||
animationsRef.
|
|
||||||
animations[m_AnimatorBlendState.ValueRO.AnimationIndex].
|
|
||||||
frameTime;
|
|
||||||
|
|
||||||
if ( m_AnimatorBlendState.ValueRO.AnimationTime >
|
|
||||||
animationsRef.animations[m_AnimatorBlendState.ValueRO.AnimationIndex].duration )
|
|
||||||
{
|
|
||||||
// Set time. Using the difference to smoothen out animations when looping.
|
|
||||||
m_AnimatorBlendState.ValueRW.AnimationTime -=
|
|
||||||
animationsRef.animations[m_AnimatorBlendState.ValueRO.AnimationIndex].duration;
|
|
||||||
|
|
||||||
//m_Animator.ValueRO.animationIndexNext = vaAnimatorStateComponent.Rand.NextInt( 20 );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lerp animations.
|
|
||||||
// Set animation for lerp.
|
|
||||||
animationIndexNextBlend = m_AnimatorBlendState.ValueRO.AnimationIndexNext;
|
|
||||||
|
|
||||||
if ( animationIndexNextBlend < 0 )
|
|
||||||
{
|
|
||||||
animationIndexNextBlend = m_AnimatorBlendState.ValueRO.AnimationIndex;
|
|
||||||
|
|
||||||
//m_Animator.ValueRO.animationIndexNext = animationIndexNext + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate next frame time for lerp.
|
|
||||||
animationTimeNextBlend = m_AnimatorBlendState.ValueRO.AnimationTime +
|
|
||||||
( 1.0f / animationsRef.animations[animationIndexNextBlend].maxFrames );
|
|
||||||
|
|
||||||
if ( animationTimeNextBlend > animationsRef.animations[animationIndexNextBlend].duration )
|
|
||||||
{
|
|
||||||
// Set time. Using the difference to smooth out animations when looping.
|
|
||||||
animationTimeNextBlend -= m_AnimatorBlendState.ValueRO.AnimationTime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( int i = 0; i < m_SkinnedMeshEntities.Length; i++ )
|
|
||||||
{
|
|
||||||
FirstAnimationDataComponent animationDataComponent = new FirstAnimationDataComponent();
|
|
||||||
|
|
||||||
animationDataComponent.Value = new float4
|
|
||||||
{
|
|
||||||
x = m_Animator.ValueRO.AnimationTime,
|
|
||||||
y = VA_AnimationLibraryUtils.GetAnimationMapIndex(
|
|
||||||
ref animationsRef,
|
|
||||||
m_Animator.ValueRO.AnimationIndex ),
|
|
||||||
z = animationTimeNext,
|
|
||||||
w = VA_AnimationLibraryUtils.GetAnimationMapIndex( ref animationsRef, animationIndexNext )
|
|
||||||
};
|
|
||||||
|
|
||||||
ecb.SetComponent < FirstAnimationDataComponent >(startIndex,
|
|
||||||
m_SkinnedMeshEntities[i].Value,
|
|
||||||
animationDataComponent );
|
|
||||||
|
|
||||||
startIndex++;
|
|
||||||
|
|
||||||
if ( m_AnimatorBlendState.ValueRO.BlendingEnabled )
|
|
||||||
{
|
|
||||||
SecondAnimationDataComponent animationDataComponent2 = new SecondAnimationDataComponent();
|
|
||||||
|
|
||||||
animationDataComponent2.Value = new float4
|
|
||||||
{
|
|
||||||
x = m_AnimatorBlendState.ValueRO.AnimationTime,
|
|
||||||
y = VA_AnimationLibraryUtils.GetAnimationMapIndex(
|
|
||||||
ref animationsRef,
|
|
||||||
m_AnimatorBlendState.ValueRO.AnimationIndex ),
|
|
||||||
z = animationTimeNextBlend,
|
|
||||||
w = VA_AnimationLibraryUtils.GetAnimationMapIndex(
|
|
||||||
ref animationsRef,
|
|
||||||
animationIndexNextBlend )
|
|
||||||
};
|
|
||||||
|
|
||||||
ecb.SetComponent < SecondAnimationDataComponent >(startIndex,
|
|
||||||
m_SkinnedMeshEntities[i].Value,
|
|
||||||
animationDataComponent2 );
|
|
||||||
|
|
||||||
startIndex++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( m_Animator.ValueRO.AnimationIndexNext >= 0 )
|
|
||||||
{
|
|
||||||
m_Animator.ValueRW.AnimationIndex = animationIndexNext;
|
|
||||||
m_Animator.ValueRW.AnimationIndexNext = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,35 +1,208 @@
|
|||||||
using System.Collections.Generic;
|
using Unity.Burst;
|
||||||
using Unity.Collections;
|
using Unity.Collections;
|
||||||
using Unity.Entities;
|
using Unity.Entities;
|
||||||
using Unity.Transforms;
|
using Unity.Jobs;
|
||||||
using Unity.Mathematics;
|
using Unity.Mathematics;
|
||||||
|
|
||||||
namespace TAO.VertexAnimation
|
namespace TAO.VertexAnimation
|
||||||
{
|
{
|
||||||
|
|
||||||
// System to update all the animations.
|
// System to update all the animations.
|
||||||
|
|
||||||
|
[BurstCompile]
|
||||||
|
[UpdateInGroup( typeof( SimulationSystemGroup ) )]
|
||||||
|
[UpdateAfter( typeof( BeginSimulationEntityCommandBufferSystem ) )]
|
||||||
public partial struct AnimatorSystem : ISystem
|
public partial struct AnimatorSystem : ISystem
|
||||||
{
|
{
|
||||||
|
//private EntityQuery m_Group;
|
||||||
|
[BurstCompile]
|
||||||
public void OnCreate( ref SystemState state )
|
public void OnCreate( ref SystemState state )
|
||||||
{
|
{
|
||||||
|
//NativeArray < ComponentType > componentTypes = new NativeArray < ComponentType >( 2, Allocator.Persistent );
|
||||||
|
//componentTypes[0] = ComponentType.ReadWrite < AnimatorComponent >();
|
||||||
|
//componentTypes[1] = ComponentType.ReadWrite<AnimatorBlendStateComponent>();
|
||||||
|
//m_Group = state.GetEntityQuery(componentTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[BurstCompile]
|
||||||
public void OnDestroy( ref SystemState state )
|
public void OnDestroy( ref SystemState state )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[BurstCompile]
|
||||||
public void OnUpdate( ref SystemState state )
|
public void OnUpdate( ref SystemState state )
|
||||||
{
|
{
|
||||||
float deltaTime = SystemAPI.Time.DeltaTime;
|
float deltaTime = SystemAPI.Time.DeltaTime;
|
||||||
EntityCommandBuffer ecb = new EntityCommandBuffer( Allocator.Temp );
|
|
||||||
int i = 0;
|
|
||||||
foreach ( var animatorAspect in SystemAPI.
|
|
||||||
Query < AnimatorAspect >() )
|
|
||||||
{
|
|
||||||
animatorAspect.UpdateAnimator( deltaTime, ecb.AsParallelWriter(), ref i );
|
|
||||||
}
|
|
||||||
|
|
||||||
ecb.Playback( state.EntityManager );
|
EntityCommandBuffer ecb = SystemAPI.GetSingleton < BeginSimulationEntityCommandBufferSystem.Singleton >().
|
||||||
|
CreateCommandBuffer( state.WorldUnmanaged );
|
||||||
|
|
||||||
|
UpdateAnimatorJob job =
|
||||||
|
new UpdateAnimatorJob { DeltaTime = deltaTime, StartIndex = 0, Ecb = ecb.AsParallelWriter() };
|
||||||
|
|
||||||
|
job.Run();
|
||||||
|
|
||||||
|
//handle.Complete();
|
||||||
|
// state.Dependency = JobHandle.CombineDependencies( ecb., state.Dependency );
|
||||||
|
//state.Dependency.Complete();
|
||||||
|
|
||||||
|
// int i = 0;
|
||||||
|
// for ( int j = 0; j < jobHandles.Length; j++ )
|
||||||
|
// {
|
||||||
|
// jobHandles2.Add(new UpdateAnimatedMeshMaterialParametersJob { Ecb = ecb.AsParallelWriter(), StartIndex = i }.ScheduleParallel(jobHandles[j] ));
|
||||||
|
// i += 2;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// for ( int j = 0; j < jobHandles2.Length; j++ )
|
||||||
|
// {
|
||||||
|
// jobHandles2[j].Complete();
|
||||||
|
// }
|
||||||
|
// //ecb.Playback( state.EntityManager );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[BurstCompile]
|
||||||
|
public partial struct UpdateAnimatorJob : IJobEntity
|
||||||
|
{
|
||||||
|
public float DeltaTime;
|
||||||
|
public int StartIndex;
|
||||||
|
public EntityCommandBuffer.ParallelWriter Ecb;
|
||||||
|
|
||||||
|
[BurstCompile]
|
||||||
|
public void Execute(
|
||||||
|
ref AnimatorComponent animator,
|
||||||
|
ref AnimatorBlendStateComponent animatorBlendState,
|
||||||
|
in DynamicBuffer < SkinnedMeshEntity > buffer )
|
||||||
|
{
|
||||||
|
if ( animator.Enabled )
|
||||||
|
{
|
||||||
|
// Get the animation lib data.
|
||||||
|
ref VA_AnimationLibraryData animationsRef = ref animator.AnimationLibrary.Value;
|
||||||
|
|
||||||
|
//if ( animator.AnimationName != vaAnimatorStateComponent.CurrentAnimationName )
|
||||||
|
//{
|
||||||
|
// // Set the animation index on the AnimatorComponent to play this animation.
|
||||||
|
// animator.AnimationIndexNext = VA_AnimationLibraryUtils.GetAnimation(ref animationsRef, vaAnimatorStateComponent.CurrentAnimationName);
|
||||||
|
// animator.AnimationName = vaAnimatorStateComponent.CurrentAnimationName;
|
||||||
|
//}
|
||||||
|
|
||||||
|
// 'Play' the actual animation.
|
||||||
|
animator.AnimationTime += DeltaTime * animationsRef.animations[animator.AnimationIndex].frameTime;
|
||||||
|
|
||||||
|
if ( animator.AnimationTime > animationsRef.animations[animator.AnimationIndex].duration )
|
||||||
|
{
|
||||||
|
// Set time. Using the difference to smoothen out animations when looping.
|
||||||
|
animator.AnimationTime -= animationsRef.animations[animator.AnimationIndex].duration;
|
||||||
|
|
||||||
|
//animator.animationIndexNext = vaAnimatorStateComponent.Rand.NextInt( 20 );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lerp animations.
|
||||||
|
// Set animation for lerp.
|
||||||
|
int animationIndexNext = animator.AnimationIndexNext;
|
||||||
|
|
||||||
|
if ( animationIndexNext < 0 )
|
||||||
|
{
|
||||||
|
animationIndexNext = animator.AnimationIndex;
|
||||||
|
|
||||||
|
//animator.animationIndexNext = animationIndexNext + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate next frame time for lerp.
|
||||||
|
float animationTimeNext = animator.AnimationTime +
|
||||||
|
( 1.0f / animationsRef.animations[animationIndexNext].maxFrames );
|
||||||
|
|
||||||
|
if ( animationTimeNext > animationsRef.animations[animationIndexNext].duration )
|
||||||
|
{
|
||||||
|
// Set time. Using the difference to smooth out animations when looping.
|
||||||
|
animationTimeNext -= animator.AnimationTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
int animationIndexNextBlend = 0;
|
||||||
|
float animationTimeNextBlend = 0.0f;
|
||||||
|
|
||||||
|
if ( animatorBlendState.BlendingEnabled )
|
||||||
|
{
|
||||||
|
// 'Play' the actual animation.
|
||||||
|
animatorBlendState.AnimationTime += DeltaTime *
|
||||||
|
animationsRef.
|
||||||
|
animations[animatorBlendState.AnimationIndex].
|
||||||
|
frameTime;
|
||||||
|
|
||||||
|
if ( animatorBlendState.AnimationTime >
|
||||||
|
animationsRef.animations[animatorBlendState.AnimationIndex].duration )
|
||||||
|
{
|
||||||
|
// Set time. Using the difference to smoothen out animations when looping.
|
||||||
|
animatorBlendState.AnimationTime -=
|
||||||
|
animationsRef.animations[animatorBlendState.AnimationIndex].duration;
|
||||||
|
|
||||||
|
//animator.animationIndexNext = vaAnimatorStateComponent.Rand.NextInt( 20 );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lerp animations.
|
||||||
|
// Set animation for lerp.
|
||||||
|
animationIndexNextBlend = animatorBlendState.AnimationIndexNext;
|
||||||
|
|
||||||
|
if ( animationIndexNextBlend < 0 )
|
||||||
|
{
|
||||||
|
animationIndexNextBlend = animatorBlendState.AnimationIndex;
|
||||||
|
|
||||||
|
//animator.animationIndexNext = animationIndexNext + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate next frame time for lerp.
|
||||||
|
animationTimeNextBlend = animatorBlendState.AnimationTime +
|
||||||
|
( 1.0f / animationsRef.animations[animationIndexNextBlend].maxFrames );
|
||||||
|
|
||||||
|
if ( animationTimeNextBlend > animationsRef.animations[animationIndexNextBlend].duration )
|
||||||
|
{
|
||||||
|
// Set time. Using the difference to smooth out animations when looping.
|
||||||
|
animationTimeNextBlend -= animatorBlendState.AnimationTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( int i = 0; i < buffer.Length; i++ )
|
||||||
|
{
|
||||||
|
FirstAnimationDataComponent vaAnimationDataComponent = new FirstAnimationDataComponent();
|
||||||
|
|
||||||
|
vaAnimationDataComponent.Value = new float4
|
||||||
|
{
|
||||||
|
x = animator.AnimationTime,
|
||||||
|
y = VA_AnimationLibraryUtils.GetAnimationMapIndex( ref animationsRef, animator.AnimationIndex ),
|
||||||
|
z = animationTimeNext,
|
||||||
|
w = VA_AnimationLibraryUtils.GetAnimationMapIndex( ref animationsRef, animationIndexNext )
|
||||||
|
};
|
||||||
|
|
||||||
|
SystemAPI.SetComponent < FirstAnimationDataComponent >( buffer[i].Value, vaAnimationDataComponent );
|
||||||
|
|
||||||
|
if ( animatorBlendState.BlendingEnabled )
|
||||||
|
{
|
||||||
|
SecondAnimationDataComponent vaAnimationDataComponent2 = new SecondAnimationDataComponent();
|
||||||
|
|
||||||
|
vaAnimationDataComponent2.Value = new float4
|
||||||
|
{
|
||||||
|
x = animatorBlendState.AnimationTime,
|
||||||
|
y = VA_AnimationLibraryUtils.GetAnimationMapIndex(
|
||||||
|
ref animationsRef,
|
||||||
|
animatorBlendState.AnimationIndex ),
|
||||||
|
z = animationTimeNextBlend,
|
||||||
|
w = VA_AnimationLibraryUtils.GetAnimationMapIndex(
|
||||||
|
ref animationsRef,
|
||||||
|
animationIndexNextBlend )
|
||||||
|
};
|
||||||
|
|
||||||
|
SystemAPI.SetComponent < SecondAnimationDataComponent >(
|
||||||
|
buffer[i].Value,
|
||||||
|
vaAnimationDataComponent2 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( animator.AnimationIndexNext >= 0 )
|
||||||
|
{
|
||||||
|
animator.AnimationIndex = animationIndexNext;
|
||||||
|
animator.AnimationIndexNext = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user