Refactored camera direction
This commit is contained in:
parent
43c3d02f0a
commit
c90b733a3d
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -244,7 +244,7 @@ void UOLSBaseLayerAnimInstance::NativeThreadSafeUpdateVelocityData(const float d
|
||||
const bool wasMovingLastUpdate = !LocalVelocity2D.IsNearlyZero(1.e-4f);
|
||||
if (wasMovingLastUpdate)
|
||||
{
|
||||
StopLocalVelocityCardinalDirection = LocalVelocityDirection;
|
||||
StopLocalVelocityDirection = LocalVelocityDirection;
|
||||
}
|
||||
|
||||
WorldVelocity = OwningPawnVelocity;
|
||||
@ -254,17 +254,14 @@ void UOLSBaseLayerAnimInstance::NativeThreadSafeUpdateVelocityData(const float d
|
||||
|
||||
LocalVelocityDirectionAngle = UKismetAnimationLibrary::CalculateDirection(worldVelocity2D, WorldRotation);
|
||||
LocalVelocityDirectionAngleWithOffset = LocalVelocityDirectionAngle - RootYawOffset;
|
||||
|
||||
LocalVelocityDirection = UOLSLocomotionBPLibrary::SelectCardinalDirectionFromAngle(LocalVelocityDirectionAngleWithOffset,
|
||||
CardinalDirectionDeadZone,
|
||||
LocalVelocityDirection,
|
||||
wasMovingLastUpdate);
|
||||
|
||||
LocalVelocityDirectionNoOffset = UOLSLocomotionBPLibrary::SelectCardinalDirectionFromAngle(
|
||||
LocalVelocityDirectionAngle,
|
||||
CardinalDirectionDeadZone,
|
||||
LocalVelocityDirection,
|
||||
wasMovingLastUpdate);
|
||||
GetMovementDirectionThresholds(LocalVelocityDirection, MovementDirectionThresholds);
|
||||
|
||||
LocalVelocityDirection = UOLSLocomotionBPLibrary::SelectMovementDirectionFromAngle(
|
||||
LocalVelocityDirectionAngleWithOffset, RotationMode, Gait, MovementDirectionBias, MovementDirectionThresholds);
|
||||
|
||||
LocalVelocityDirectionNoOffset = UOLSLocomotionBPLibrary::SelectMovementDirectionFromAngle(
|
||||
LocalVelocityDirectionAngle, RotationMode, Gait, MovementDirectionBias, MovementDirectionThresholds);
|
||||
|
||||
bHasVelocity = (LocalVelocity2D.SizeSquared2D() > KINDA_SMALL_NUMBER);
|
||||
|
||||
@ -281,14 +278,21 @@ void UOLSBaseLayerAnimInstance::NativeThreadSafeUpdateAccelerationData(const flo
|
||||
bHasAcceleration = (LocalAcceleration2D.SizeSquared2D() > KINDA_SMALL_NUMBER);
|
||||
|
||||
PivotDirection2D =
|
||||
UKismetMathLibrary::Normal(UKismetMathLibrary::VLerp(PivotDirection2D, UKismetMathLibrary::Normal(worldAcceleration2D), .5f));
|
||||
|
||||
UKismetMathLibrary::Normal(
|
||||
UKismetMathLibrary::VLerp(PivotDirection2D, UKismetMathLibrary::Normal(worldAcceleration2D), .5f));
|
||||
|
||||
GetMovementDirectionThresholds(CardinalDirectionFromAcceleration, MovementDirectionThresholds);
|
||||
|
||||
CardinalDirectionFromAcceleration = (IsLookingOrAimingDirection()
|
||||
? UOLSLocomotionBPLibrary::GetOppositeCardinalDirectional(
|
||||
UOLSLocomotionBPLibrary::SelectCardinalDirectionFromAngle(
|
||||
UKismetAnimationLibrary::CalculateDirection(PivotDirection2D, WorldRotation),
|
||||
CardinalDirectionDeadZone, EOLSCardinalDirection::EForward))
|
||||
: EOLSCardinalDirection::EBackward);
|
||||
? UOLSLocomotionBPLibrary::GetOppositeMovementDirection(
|
||||
UOLSLocomotionBPLibrary::SelectMovementDirectionFromAngle(
|
||||
UKismetAnimationLibrary::CalculateDirection(
|
||||
PivotDirection2D, WorldRotation),
|
||||
RotationMode, Gait,
|
||||
MovementDirectionBias,
|
||||
MovementDirectionThresholds),
|
||||
MovementDirectionBias)
|
||||
: EOLSMovementDirection::EBackward);
|
||||
|
||||
if (HasAcceleration())
|
||||
{
|
||||
@ -498,10 +502,16 @@ bool UOLSBaseLayerAnimInstance::ShouldDistanceMatchStop() const
|
||||
|
||||
bool UOLSBaseLayerAnimInstance::IsMovingPerpendicularToInitialPivot() const
|
||||
{
|
||||
const bool isPivotFwdOrBwd = (PivotInitialDirection == EOLSCardinalDirection::EForward || PivotInitialDirection == EOLSCardinalDirection::EBackward);
|
||||
const bool isVelocityFwdOrBwd = (LocalVelocityDirection == EOLSCardinalDirection::EForward || LocalVelocityDirection == EOLSCardinalDirection::EBackward);
|
||||
const bool isPivotLeftOrRight = (PivotInitialDirection == EOLSCardinalDirection::ELeft || PivotInitialDirection == EOLSCardinalDirection::ERight);
|
||||
const bool isVelocityLeftOrRight = (LocalVelocityDirection == EOLSCardinalDirection::ELeft || LocalVelocityDirection == EOLSCardinalDirection::ERight);
|
||||
const bool isPivotFwdOrBwd = (PivotInitialDirection == EOLSMovementDirection::EForward || PivotInitialDirection ==
|
||||
EOLSMovementDirection::EBackward);
|
||||
const bool isVelocityFwdOrBwd = (LocalVelocityDirection == EOLSMovementDirection::EForward || LocalVelocityDirection
|
||||
== EOLSMovementDirection::EBackward);
|
||||
const bool isPivotLeftOrRight = (PivotInitialDirection == EOLSMovementDirection::ELeftLeft || PivotInitialDirection
|
||||
== EOLSMovementDirection::ELeftRight || PivotInitialDirection == EOLSMovementDirection::ERightLeft ||
|
||||
PivotInitialDirection == EOLSMovementDirection::ERightRight);
|
||||
const bool isVelocityLeftOrRight = (LocalVelocityDirection == EOLSMovementDirection::ELeftLeft ||
|
||||
LocalVelocityDirection == EOLSMovementDirection::ELeftRight || LocalVelocityDirection ==
|
||||
EOLSMovementDirection::ERightLeft || LocalVelocityDirection == EOLSMovementDirection::ERightRight);
|
||||
return (isPivotFwdOrBwd && !isVelocityFwdOrBwd) || (isPivotLeftOrRight && !isVelocityLeftOrRight);
|
||||
}
|
||||
|
||||
@ -611,3 +621,45 @@ UOLSLocomotionComponent* UOLSBaseLayerAnimInstance::ThreadSafeGetLocomotionCompo
|
||||
{
|
||||
return LocomotionComponent;
|
||||
}
|
||||
|
||||
void UOLSBaseLayerAnimInstance::GetMovementDirectionThresholds(const EOLSMovementDirection& movementDirection, FOLSMovementDirectionThresholds& outMovementThresholds)
|
||||
{
|
||||
if (movementDirection == EOLSMovementDirection::EForward || movementDirection == EOLSMovementDirection::EBackward)
|
||||
{
|
||||
outMovementThresholds.FL = -60.f;
|
||||
outMovementThresholds.FR = 60.f;
|
||||
outMovementThresholds.BL = -120.f;
|
||||
outMovementThresholds.BR = 120.f;
|
||||
return;
|
||||
}
|
||||
|
||||
if (movementDirection == EOLSMovementDirection::ELeftLeft || movementDirection ==
|
||||
EOLSMovementDirection::ELeftRight || movementDirection == EOLSMovementDirection::ERightLeft ||
|
||||
movementDirection == EOLSMovementDirection::ERightRight)
|
||||
{
|
||||
if (bIsPivoting)
|
||||
{
|
||||
outMovementThresholds.FL = -60.f;
|
||||
outMovementThresholds.FR = 60.f;
|
||||
outMovementThresholds.BL = -120.f;
|
||||
outMovementThresholds.BR = 120.f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bIsLooping && IsAimingDirection())
|
||||
{
|
||||
outMovementThresholds.FL = -60.f;
|
||||
outMovementThresholds.FR = 60.f;
|
||||
outMovementThresholds.BL = -140.f;
|
||||
outMovementThresholds.BR = 140.f;
|
||||
}
|
||||
else
|
||||
{
|
||||
outMovementThresholds.FL = -40.f;
|
||||
outMovementThresholds.FR = 40.f;
|
||||
outMovementThresholds.BL = -120.f;
|
||||
outMovementThresholds.BR = 120.f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -131,13 +131,12 @@ UAnimSequence* UOLSBaseLinkedLayerAnimInstance::SelectTurnInPlaceAnimation(
|
||||
UAnimSequence* UOLSBaseLinkedLayerAnimInstance::SelectStartCycleAnimation(const bool isCrouching,
|
||||
const bool isAiming,
|
||||
const EOLSGait gait,
|
||||
const EOLSCardinalDirection velocityDirection,
|
||||
const EOLSHipDirection hipDirection,
|
||||
const EOLSMovementDirection velocityDirection,
|
||||
const float angle) const
|
||||
{
|
||||
if (isAiming)
|
||||
{
|
||||
return GetGaitAnimSets(isCrouching, gait).GaitAnimSet_CameraFacing.GetStartCycleFromHipDirection(hipDirection).
|
||||
return GetGaitAnimSets(isCrouching, gait).GaitAnimSet_CameraFacing.StartCycle.
|
||||
GetMovementAnimByCardinalDirection(
|
||||
velocityDirection, FeetPositionData.IsRightFootIsFront());
|
||||
}
|
||||
@ -150,14 +149,12 @@ UAnimSequence* UOLSBaseLinkedLayerAnimInstance::SelectStartCycleAnimation(const
|
||||
UAnimSequence* UOLSBaseLinkedLayerAnimInstance::SelectCycleAnimation(const bool isCrouching,
|
||||
const bool isAiming,
|
||||
const EOLSGait gait,
|
||||
const EOLSCardinalDirection velocityDirection,
|
||||
const EOLSHipDirection hipDirection) const
|
||||
const EOLSMovementDirection velocityDirection) const
|
||||
{
|
||||
if (isAiming)
|
||||
{
|
||||
return GetGaitAnimSets(isCrouching, gait).GaitAnimSet_CameraFacing.GetCycleFromHipDirection(hipDirection).
|
||||
GetMovementAnimByCardinalDirection(
|
||||
velocityDirection, FeetPositionData.IsRightFootIsFront());
|
||||
return GetGaitAnimSets(isCrouching, gait).GaitAnimSet_CameraFacing.Cycle.GetMovementAnimByCardinalDirection(
|
||||
velocityDirection);
|
||||
}
|
||||
|
||||
return GetGaitAnimSets(isCrouching, gait).GaitAnimSet_ForwardFacing.Cycle;
|
||||
@ -166,15 +163,13 @@ UAnimSequence* UOLSBaseLinkedLayerAnimInstance::SelectCycleAnimation(const bool
|
||||
UAnimSequence* UOLSBaseLinkedLayerAnimInstance::SelectPivotAnimation(const bool isCrouching,
|
||||
const bool isAiming,
|
||||
const EOLSGait gait,
|
||||
const EOLSCardinalDirection velocityDirection,
|
||||
const EOLSHipDirection hipDirection,
|
||||
const EOLSMovementDirection velocityDirection,
|
||||
const float angle) const
|
||||
{
|
||||
if (isAiming)
|
||||
{
|
||||
return GetGaitAnimSets(isCrouching, gait).GaitAnimSet_CameraFacing.GetPivotFromHipDirection(hipDirection).
|
||||
GetMovementAnimByCardinalDirection(
|
||||
velocityDirection, FeetPositionData.IsRightFootIsFront());
|
||||
return GetGaitAnimSets(isCrouching, gait).GaitAnimSet_CameraFacing.Pivot.GetMovementAnimByCardinalDirection(
|
||||
velocityDirection, FeetPositionData.IsRightFootIsFront());
|
||||
}
|
||||
|
||||
return GetGaitAnimSets(isCrouching, gait).GaitAnimSet_ForwardFacing.Pivot.GetLeftOrRightByAngle(
|
||||
@ -184,13 +179,12 @@ UAnimSequence* UOLSBaseLinkedLayerAnimInstance::SelectPivotAnimation(const bool
|
||||
UAnimSequence* UOLSBaseLinkedLayerAnimInstance::SelectStopCycleAnimation(const bool isCrouching,
|
||||
const bool isAiming,
|
||||
const EOLSGait gait,
|
||||
const EOLSCardinalDirection velocityDirection,
|
||||
const EOLSHipDirection hipDirection) const
|
||||
const EOLSMovementDirection velocityDirection) const
|
||||
{
|
||||
if (isAiming)
|
||||
{
|
||||
return GetGaitAnimSets(isCrouching, gait).
|
||||
GaitAnimSet_CameraFacing.GetStopCycleFromHipDirection(hipDirection).GetMovementAnimByCardinalDirection(
|
||||
GaitAnimSet_CameraFacing.StopCycle.GetMovementAnimByCardinalDirection(
|
||||
velocityDirection, FeetPositionData.IsRightFootIsFront());
|
||||
}
|
||||
|
||||
|
||||
@ -92,22 +92,24 @@ UAnimSequence* FOLSMovementAnimSet_ForwardFacing_StartCycle::GetForward180LeftOr
|
||||
}
|
||||
|
||||
class UAnimSequence* FOLSMovementAnimSet_ForwardFacing_StartCycle::GetMovementAnimationByAngle(
|
||||
const EOLSCardinalDirection direction, const float angle, const bool isRightFootFarFromTarget) const
|
||||
const EOLSMovementDirection direction, const float angle, const bool isRightFootFarFromTarget) const
|
||||
{
|
||||
TObjectPtr<UAnimSequence> result = nullptr;
|
||||
|
||||
switch (direction)
|
||||
{
|
||||
case EOLSCardinalDirection::EForward:
|
||||
case EOLSMovementDirection::EForward:
|
||||
result = GetForwardLeftOrRightFoot(isRightFootFarFromTarget);
|
||||
break;
|
||||
case EOLSCardinalDirection::ELeft:
|
||||
case EOLSMovementDirection::ELeftLeft:
|
||||
case EOLSMovementDirection::ELeftRight:
|
||||
result = Forward90L;
|
||||
break;
|
||||
case EOLSCardinalDirection::ERight:
|
||||
case EOLSMovementDirection::ERightLeft:
|
||||
case EOLSMovementDirection::ERightRight:
|
||||
result = Forward90R;
|
||||
break;
|
||||
case EOLSCardinalDirection::EBackward:
|
||||
case EOLSMovementDirection::EBackward:
|
||||
result = GetForward180LeftOrRightByAngle(angle);
|
||||
break;
|
||||
}
|
||||
@ -128,6 +130,35 @@ UAnimSequence* FOLSMovementAnimSet_ForwardFacing_StopCycle::GetLeftOrRightAnim(c
|
||||
return Stop.GetForwardLeftOrRightFoot(isRightFootPlanted);
|
||||
}
|
||||
|
||||
class UAnimSequence* FOLSMovementAnimSet_CameraFacing_Directional_Cycle::GetMovementAnimByCardinalDirection(
|
||||
const EOLSMovementDirection& direction) const
|
||||
{
|
||||
TObjectPtr<UAnimSequence> result = nullptr;
|
||||
switch (direction)
|
||||
{
|
||||
case EOLSMovementDirection::EForward:
|
||||
result = Forward;
|
||||
break;
|
||||
case EOLSMovementDirection::EBackward:
|
||||
result = Backward;
|
||||
break;
|
||||
case EOLSMovementDirection::ELeftLeft:
|
||||
result = LeftLeft;
|
||||
break;
|
||||
case EOLSMovementDirection::ELeftRight:
|
||||
result = LeftRight;
|
||||
break;
|
||||
case EOLSMovementDirection::ERightRight:
|
||||
result = RightRight;
|
||||
break;
|
||||
case EOLSMovementDirection::ERightLeft:
|
||||
result = RightLeft;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void FOLSGaitAnimSet::GetPlayRateByLocomotionState(const EOLSLocomotionStatePlayRate& state, FVector2D& outPlayRate) const
|
||||
{
|
||||
switch (state)
|
||||
@ -144,28 +175,36 @@ void FOLSGaitAnimSet::GetPlayRateByLocomotionState(const EOLSLocomotionStatePlay
|
||||
}
|
||||
}
|
||||
|
||||
void FOLSMovementAnimSet_CameraFacing_Directional::GetMovementAnimSetByCardinalDirection(const EOLSCardinalDirection& direction,
|
||||
FOLSMovementAnimSet_FeetPosition& outAnimSet) const
|
||||
void FOLSMovementAnimSet_CameraFacing_Directional::GetMovementAnimSetByCardinalDirection(
|
||||
const EOLSMovementDirection& direction,
|
||||
FOLSMovementAnimSet_FeetPosition& outAnimSet) const
|
||||
{
|
||||
switch (direction)
|
||||
{
|
||||
case EOLSCardinalDirection::EForward:
|
||||
case EOLSMovementDirection::EForward:
|
||||
outAnimSet = Forward;
|
||||
break;
|
||||
case EOLSCardinalDirection::EBackward:
|
||||
case EOLSMovementDirection::EBackward:
|
||||
outAnimSet = Backward;
|
||||
break;
|
||||
case EOLSCardinalDirection::ERight:
|
||||
outAnimSet = Right;
|
||||
case EOLSMovementDirection::ELeftLeft:
|
||||
outAnimSet = LeftLeft;
|
||||
break;
|
||||
case EOLSCardinalDirection::ELeft:
|
||||
outAnimSet = Left;
|
||||
case EOLSMovementDirection::ELeftRight:
|
||||
outAnimSet = LeftRight;
|
||||
break;
|
||||
case EOLSMovementDirection::ERightRight:
|
||||
outAnimSet = RightRight;
|
||||
break;
|
||||
case EOLSMovementDirection::ERightLeft:
|
||||
outAnimSet = RightLeft;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
UAnimSequence* FOLSMovementAnimSet_CameraFacing_Directional::GetMovementAnimByCardinalDirection(const EOLSCardinalDirection& direction,
|
||||
const bool isRightFootFarFromTarget) const
|
||||
UAnimSequence* FOLSMovementAnimSet_CameraFacing_Directional::GetMovementAnimByCardinalDirection(
|
||||
const EOLSMovementDirection& direction,
|
||||
const bool isRightFootFarFromTarget) const
|
||||
{
|
||||
FOLSMovementAnimSet_FeetPosition animSet;
|
||||
GetMovementAnimSetByCardinalDirection(direction, animSet);
|
||||
@ -173,26 +212,6 @@ UAnimSequence* FOLSMovementAnimSet_CameraFacing_Directional::GetMovementAnimByCa
|
||||
return animSet.GetForwardLeftOrRightFoot(isRightFootFarFromTarget);
|
||||
}
|
||||
|
||||
const FOLSMovementAnimSet_CameraFacing_Directional& FOLSGaitAnimSet_CameraFacing::GetStartCycleFromHipDirection(const EOLSHipDirection hipDirection) const
|
||||
{
|
||||
return (hipDirection == EOLSHipDirection::EForward) ? StartCycle_HipForward : StartCycle_HipBackward;
|
||||
}
|
||||
|
||||
const FOLSMovementAnimSet_CameraFacing_Directional& FOLSGaitAnimSet_CameraFacing::GetCycleFromHipDirection(const EOLSHipDirection hipDirection) const
|
||||
{
|
||||
return (hipDirection == EOLSHipDirection::EForward) ? Cycle_HipForward : Cycle_HipBackward;
|
||||
}
|
||||
|
||||
const FOLSMovementAnimSet_CameraFacing_Directional& FOLSGaitAnimSet_CameraFacing::GetPivotFromHipDirection(const EOLSHipDirection hipDirection) const
|
||||
{
|
||||
return (hipDirection == EOLSHipDirection::EForward) ? Pivot_HipForward : Pivot_HipBackward;
|
||||
}
|
||||
|
||||
const FOLSMovementAnimSet_CameraFacing_Directional& FOLSGaitAnimSet_CameraFacing::GetStopCycleFromHipDirection(const EOLSHipDirection hipDirection) const
|
||||
{
|
||||
return (hipDirection == EOLSHipDirection::EForward) ? StopCycle_HipForward : StopCycle_HipBackward;
|
||||
}
|
||||
|
||||
UAnimSequence* FOLSStanceAnimSets::GetIdleAnimation() const
|
||||
{
|
||||
return IdleAndTurnInPlaceAnimSet.GetIdleAnimation();
|
||||
|
||||
@ -5,60 +5,103 @@
|
||||
|
||||
DEFINE_LOG_CATEGORY_STATIC(LogOLSLocomotionLibrary, Verbose, All);
|
||||
|
||||
EOLSCardinalDirection UOLSLocomotionBPLibrary::SelectCardinalDirectionFromAngle(float angle,
|
||||
float deadZone,
|
||||
EOLSCardinalDirection currentDirection,
|
||||
bool useCurrentDirection /* = false */)
|
||||
EOLSMovementDirection UOLSLocomotionBPLibrary::SelectMovementDirectionFromAngle(float angle,
|
||||
const EOLSRotationMode& rotationMode,
|
||||
const EOLSGait& gait,
|
||||
const EOLSMovementDirectionBias& movementDirectionBias,
|
||||
const FOLSMovementDirectionThresholds& movementDirectionThreshold)
|
||||
{
|
||||
|
||||
const float absAngle = FMath::Abs(angle);
|
||||
float fwdDeadZone = deadZone;
|
||||
float bwdDeadZone = deadZone;
|
||||
|
||||
if (useCurrentDirection)
|
||||
EOLSMovementDirection result = EOLSMovementDirection::EForward;
|
||||
if (rotationMode == EOLSRotationMode::EVelocityDirection || gait == EOLSGait::ESprint)
|
||||
{
|
||||
if (currentDirection == EOLSCardinalDirection::EForward)
|
||||
return result;
|
||||
}
|
||||
|
||||
const bool isAngleForwardDirection = FMath::IsWithinInclusive(angle,
|
||||
movementDirectionThreshold.FL,
|
||||
movementDirectionThreshold.FR);
|
||||
const bool isAngleLeftDirection = FMath::IsWithinInclusive(angle,
|
||||
movementDirectionThreshold.BL,
|
||||
movementDirectionThreshold.FL);
|
||||
const bool isAngleRightDirection = FMath::IsWithinInclusive(angle,
|
||||
movementDirectionThreshold.FR,
|
||||
movementDirectionThreshold.BR);
|
||||
|
||||
if (isAngleForwardDirection)
|
||||
{
|
||||
result = EOLSMovementDirection::EForward;
|
||||
}
|
||||
else if (isAngleLeftDirection)
|
||||
{
|
||||
switch (movementDirectionBias)
|
||||
{
|
||||
fwdDeadZone *= 2.f;
|
||||
}
|
||||
else if (currentDirection == EOLSCardinalDirection::EBackward)
|
||||
{
|
||||
bwdDeadZone *= 2.f;
|
||||
case EOLSMovementDirectionBias::ELeftFoot_F:
|
||||
result = EOLSMovementDirection::ELeftLeft;
|
||||
break;
|
||||
case EOLSMovementDirectionBias::ERightFoot_F:
|
||||
result = EOLSMovementDirection::ELeftRight;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(absAngle <= (45 + fwdDeadZone))
|
||||
else if (isAngleRightDirection)
|
||||
{
|
||||
return EOLSCardinalDirection::EForward;
|
||||
switch (movementDirectionBias)
|
||||
{
|
||||
case EOLSMovementDirectionBias::ELeftFoot_F:
|
||||
result = EOLSMovementDirection::ERightLeft;
|
||||
break;
|
||||
case EOLSMovementDirectionBias::ERightFoot_F:
|
||||
result = EOLSMovementDirection::ERightRight;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (absAngle >= (135 - bwdDeadZone))
|
||||
else
|
||||
{
|
||||
return EOLSCardinalDirection::EBackward;
|
||||
}
|
||||
else if (angle > 0)
|
||||
{
|
||||
return EOLSCardinalDirection::ERight;
|
||||
result = EOLSMovementDirection::EBackward;
|
||||
}
|
||||
|
||||
return EOLSCardinalDirection::ELeft;
|
||||
return result;
|
||||
}
|
||||
|
||||
EOLSCardinalDirection UOLSLocomotionBPLibrary::GetOppositeCardinalDirectional(EOLSCardinalDirection currentDirection)
|
||||
EOLSMovementDirection UOLSLocomotionBPLibrary::GetOppositeMovementDirection(
|
||||
const EOLSMovementDirection& currentDirection,
|
||||
const EOLSMovementDirectionBias& movementDirectionBias)
|
||||
{
|
||||
switch (currentDirection)
|
||||
EOLSMovementDirection result = EOLSMovementDirection::EForward;
|
||||
if (currentDirection == EOLSMovementDirection::EForward)
|
||||
{
|
||||
case EOLSCardinalDirection::EForward: {return EOLSCardinalDirection::EBackward;}
|
||||
case EOLSCardinalDirection::EBackward: {return EOLSCardinalDirection::EForward;}
|
||||
case EOLSCardinalDirection::ELeft: {return EOLSCardinalDirection::ERight;}
|
||||
case EOLSCardinalDirection::ERight: {return EOLSCardinalDirection::ELeft;}
|
||||
result = EOLSMovementDirection::EBackward;
|
||||
}
|
||||
|
||||
return EOLSCardinalDirection::EForward;
|
||||
}
|
||||
|
||||
EOLSHipDirection UOLSLocomotionBPLibrary::GetOppositeHipDirection(EOLSHipDirection currentHipDirection)
|
||||
{
|
||||
return (currentHipDirection == EOLSHipDirection::EForward ? EOLSHipDirection::EBackward : EOLSHipDirection::EForward);
|
||||
else if (currentDirection == EOLSMovementDirection::ELeftLeft || currentDirection == EOLSMovementDirection::ELeftRight)
|
||||
{
|
||||
switch (movementDirectionBias)
|
||||
{
|
||||
case EOLSMovementDirectionBias::ELeftFoot_F:
|
||||
result = EOLSMovementDirection::ERightLeft;
|
||||
break;
|
||||
case EOLSMovementDirectionBias::ERightFoot_F:
|
||||
result = EOLSMovementDirection::ERightRight;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (currentDirection == EOLSMovementDirection::ERightLeft || currentDirection == EOLSMovementDirection::ERightRight)
|
||||
{
|
||||
switch (movementDirectionBias)
|
||||
{
|
||||
case EOLSMovementDirectionBias::ELeftFoot_F:
|
||||
result = EOLSMovementDirection::ELeftLeft;
|
||||
break;
|
||||
case EOLSMovementDirectionBias::ERightFoot_F:
|
||||
result = EOLSMovementDirection::ELeftRight;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = EOLSMovementDirection::EBackward;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void UOLSLocomotionBPLibrary::TryLinkAnimLayer(USkeletalMeshComponent* mesh,
|
||||
|
||||
@ -159,6 +159,11 @@ protected:
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Components", meta = (BlueprintThreadSafe))
|
||||
class UOLSLocomotionComponent* ThreadSafeGetLocomotionComponent() const;
|
||||
|
||||
protected:
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Movement Direciton", meta = (BlueprintThreadSafe))
|
||||
void GetMovementDirectionThresholds(const EOLSMovementDirection& movementDirection, FOLSMovementDirectionThresholds& outMovementThresholds);
|
||||
|
||||
protected:
|
||||
|
||||
@ -235,10 +240,10 @@ protected:
|
||||
float LocalVelocityDirectionAngleWithOffset = 0.f;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "ThreadSafe|VelocityData")
|
||||
EOLSCardinalDirection LocalVelocityDirection = EOLSCardinalDirection::EForward;
|
||||
EOLSMovementDirection LocalVelocityDirection = EOLSMovementDirection::EForward;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "ThreadSafe|VelocityData")
|
||||
EOLSCardinalDirection LocalVelocityDirectionNoOffset = EOLSCardinalDirection::EForward;
|
||||
EOLSMovementDirection LocalVelocityDirectionNoOffset = EOLSMovementDirection::EForward;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "ThreadSafe|VelocityData")
|
||||
uint8 bHasVelocity : 1;
|
||||
@ -261,7 +266,7 @@ protected:
|
||||
float LocalAccelerationDirection = 0.f;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "ThreadSafe|AccelerationData")
|
||||
EOLSCardinalDirection CardinalDirectionFromAcceleration = EOLSCardinalDirection::EForward;
|
||||
EOLSMovementDirection CardinalDirectionFromAcceleration = EOLSMovementDirection::EForward;
|
||||
|
||||
protected:
|
||||
|
||||
@ -345,23 +350,29 @@ protected:
|
||||
|
||||
protected:
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, Category = "ThreadSafe|LocomotionSMData")
|
||||
uint8 bIsPivoting : 1 = false;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, Category = "ThreadSafe|LocomotionSMData")
|
||||
uint8 bIsLooping : 1 = false;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, Category = "ThreadSafe|LocomotionSMData")
|
||||
float PivotInitialVelocityDirection = 0.f;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, Category = "ThreadSafe|LocomotionSMData")
|
||||
EOLSCardinalDirection PivotInitialDirection = EOLSCardinalDirection::EForward;
|
||||
EOLSMovementDirection PivotInitialDirection = EOLSMovementDirection::EForward;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, Category = "ThreadSafe|LocomotionSMData")
|
||||
float LastPivotTime = 0.f;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, Category = "ThreadSafe|LocomotionSMData")
|
||||
EOLSCardinalDirection StartDirection = EOLSCardinalDirection::EForward;
|
||||
EOLSMovementDirection StartDirection = EOLSMovementDirection::EForward;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, Category = "ThreadSafe|LocomotionSMData")
|
||||
EOLSGait StopInitialGait = EOLSGait::EWalk;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, Category = "ThreadSafe|LocomotionSMData")
|
||||
EOLSCardinalDirection StopLocalVelocityCardinalDirection = EOLSCardinalDirection::EForward;
|
||||
EOLSMovementDirection StopLocalVelocityDirection = EOLSMovementDirection::EForward;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, Category = "ThreadSafe|LocomotionSMData")
|
||||
uint8 bHasGaitChanged : 1 = false;
|
||||
@ -377,6 +388,9 @@ protected:
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, Category = "ThreadSafe|LocomotionSMData")
|
||||
EOLSRotationMode LastRotationMode = EOLSRotationMode::EVelocityDirection;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, Category = "ThreadSafe|LocomotionSMData")
|
||||
FOLSMovementDirectionThresholds MovementDirectionThresholds;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, Category = "ThreadSafe|LocomotionSMData")
|
||||
TObjectPtr<class UAnimInstance> LastLinkedLayer = nullptr;
|
||||
@ -423,6 +437,9 @@ protected:
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Settings|VelocityData")
|
||||
float CardinalDirectionDeadZone = 10.f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Settings|MovementDirection")
|
||||
EOLSMovementDirectionBias MovementDirectionBias = EOLSMovementDirectionBias::ELeftFoot_F;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Settings|GameplayTagBindings")
|
||||
FGameplayTag ADSGameplayTag = FGameplayTag::EmptyTag;
|
||||
|
||||
|
||||
@ -65,31 +65,27 @@ protected:
|
||||
class UAnimSequence* SelectStartCycleAnimation(const bool isCrouching,
|
||||
const bool isAiming,
|
||||
const EOLSGait gait,
|
||||
const EOLSCardinalDirection velocityDirection,
|
||||
const EOLSHipDirection hipDirection,
|
||||
const EOLSMovementDirection velocityDirection,
|
||||
const float angle) const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, meta = (BlueprintThreadSafe), Category = "ThreadSafe|Selectors")
|
||||
class UAnimSequence* SelectCycleAnimation(const bool isCrouching,
|
||||
const bool isAiming,
|
||||
const EOLSGait gait,
|
||||
const EOLSCardinalDirection velocityDirection,
|
||||
const EOLSHipDirection hipDirection) const;
|
||||
const EOLSMovementDirection velocityDirection) const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, meta = (BlueprintThreadSafe), Category = "ThreadSafe|Selectors")
|
||||
class UAnimSequence* SelectPivotAnimation(const bool isCrouching,
|
||||
const bool isAiming,
|
||||
const EOLSGait gait,
|
||||
const EOLSCardinalDirection velocityDirection,
|
||||
const EOLSHipDirection hipDirection,
|
||||
const EOLSMovementDirection velocityDirection,
|
||||
const float angle) const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, meta = (BlueprintThreadSafe), Category = "ThreadSafe|Selectors")
|
||||
class UAnimSequence* SelectStopCycleAnimation(const bool isCrouching,
|
||||
const bool isAiming,
|
||||
const EOLSGait gait,
|
||||
const EOLSCardinalDirection velocityDirection,
|
||||
const EOLSHipDirection hipDirection) const;
|
||||
const EOLSMovementDirection velocityDirection) const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, meta = (BlueprintThreadSafe), Category = "ThreadSafe|Selectors")
|
||||
FVector2D SelectPlayRateByLocomotionState(const bool isCrouching, const bool isAiming, const EOLSGait gait,
|
||||
|
||||
@ -9,6 +9,44 @@
|
||||
#include "UObject/Object.h"
|
||||
#include "OLSAnimationData.generated.h"
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EOLSMovementDirection : uint8
|
||||
{
|
||||
EForward UMETA(DisplayName = "F"),
|
||||
EBackward UMETA(DisplayName = "B"),
|
||||
ELeftLeft UMETA(DisplayName = "LL"),
|
||||
ELeftRight UMETA(DisplayName = "LR"),
|
||||
ERightLeft UMETA(DisplayName = "RL"),
|
||||
ERightRight UMETA(DisplayName = "RR")
|
||||
};
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EOLSMovementDirectionBias : uint8
|
||||
{
|
||||
ELeftFoot_F UMETA(DisplayName = "Left Foot Forward"),
|
||||
ERightFoot_F UMETA(DisplayName = "Right Foot Forward"),
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FOLSMovementDirectionThresholds
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
float FL = -60.f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
float FR = 60.f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
float BL = -120.f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
float BR = 120.f;
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FOLSFeetPositionSettings
|
||||
{
|
||||
@ -150,7 +188,7 @@ public:
|
||||
|
||||
class UAnimSequence* GetForwardLeftOrRightFoot(const bool isRightFootFarFromTarget) const;
|
||||
class UAnimSequence* GetForward180LeftOrRightByAngle(const float angle) const;
|
||||
class UAnimSequence* GetMovementAnimationByAngle(const EOLSCardinalDirection direction,
|
||||
class UAnimSequence* GetMovementAnimationByAngle(const EOLSMovementDirection direction,
|
||||
const float angle,
|
||||
const bool isRightFootFarFromTarget) const;
|
||||
|
||||
@ -207,6 +245,36 @@ public:
|
||||
};
|
||||
#pragma endregion
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FOLSMovementAnimSet_CameraFacing_Directional_Cycle
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
class UAnimSequence* GetMovementAnimByCardinalDirection(const EOLSMovementDirection& direction) const;
|
||||
|
||||
public:
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, meta = (DisplayName = "F"))
|
||||
TObjectPtr<class UAnimSequence> Forward;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, meta = (DisplayName = "B"))
|
||||
TObjectPtr<class UAnimSequence> Backward;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, meta = (DisplayName = "LL"))
|
||||
TObjectPtr<class UAnimSequence> LeftLeft;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, meta = (DisplayName = "LR"))
|
||||
TObjectPtr<class UAnimSequence> LeftRight;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, meta = (DisplayName = "RL"))
|
||||
TObjectPtr<class UAnimSequence> RightLeft;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, meta = (DisplayName = "RR"))
|
||||
TObjectPtr<class UAnimSequence> RightRight;
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FOLSMovementAnimSet_CameraFacing_Directional
|
||||
{
|
||||
@ -214,25 +282,31 @@ struct FOLSMovementAnimSet_CameraFacing_Directional
|
||||
|
||||
protected:
|
||||
|
||||
void GetMovementAnimSetByCardinalDirection(const EOLSCardinalDirection& direction, FOLSMovementAnimSet_FeetPosition& outAnimSet) const;
|
||||
void GetMovementAnimSetByCardinalDirection(const EOLSMovementDirection& direction, FOLSMovementAnimSet_FeetPosition& outAnimSet) const;
|
||||
|
||||
public:
|
||||
|
||||
class UAnimSequence* GetMovementAnimByCardinalDirection(const EOLSCardinalDirection& direction, const bool isRightFootFarFromTarget) const;
|
||||
class UAnimSequence* GetMovementAnimByCardinalDirection(const EOLSMovementDirection& direction, const bool isRightFootFarFromTarget) const;
|
||||
|
||||
public:
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly)
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, meta = (DisplayName = "F"))
|
||||
FOLSMovementAnimSet_FeetPosition Forward;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly)
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, meta = (DisplayName = "B"))
|
||||
FOLSMovementAnimSet_FeetPosition Backward;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly)
|
||||
FOLSMovementAnimSet_FeetPosition Right;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly)
|
||||
FOLSMovementAnimSet_FeetPosition Left;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, meta = (DisplayName = "LL"))
|
||||
FOLSMovementAnimSet_FeetPosition LeftLeft;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, meta = (DisplayName = "LR"))
|
||||
FOLSMovementAnimSet_FeetPosition LeftRight;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, meta = (DisplayName = "RL"))
|
||||
FOLSMovementAnimSet_FeetPosition RightLeft;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, meta = (DisplayName = "RR"))
|
||||
FOLSMovementAnimSet_FeetPosition RightRight;
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
@ -292,38 +366,19 @@ struct FOLSGaitAnimSet_CameraFacing : public FOLSGaitAnimSet
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
const FOLSMovementAnimSet_CameraFacing_Directional& GetStartCycleFromHipDirection(const EOLSHipDirection hipDirection) const;
|
||||
const FOLSMovementAnimSet_CameraFacing_Directional& GetCycleFromHipDirection(const EOLSHipDirection hipDirection) const;
|
||||
const FOLSMovementAnimSet_CameraFacing_Directional& GetPivotFromHipDirection(const EOLSHipDirection hipDirection) const;
|
||||
const FOLSMovementAnimSet_CameraFacing_Directional& GetStopCycleFromHipDirection(const EOLSHipDirection hipDirection) const;
|
||||
|
||||
public:
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Gait Anim Set | Hip Forward")
|
||||
FOLSMovementAnimSet_CameraFacing_Directional StartCycle_HipForward;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Gait Anim Set | Hip Forward")
|
||||
FOLSMovementAnimSet_CameraFacing_Directional Cycle_HipForward;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Gait Anim Set")
|
||||
FOLSMovementAnimSet_CameraFacing_Directional StartCycle;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Gait Anim Set | Hip Forward")
|
||||
FOLSMovementAnimSet_CameraFacing_Directional Pivot_HipForward;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Gait Anim Set | Hip Forward")
|
||||
FOLSMovementAnimSet_CameraFacing_Directional StopCycle_HipForward;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Gait Anim Set")
|
||||
FOLSMovementAnimSet_CameraFacing_Directional_Cycle Cycle;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Gait Anim Set | Hip Backward")
|
||||
FOLSMovementAnimSet_CameraFacing_Directional StartCycle_HipBackward;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Gait Anim Set | Hip Backward")
|
||||
FOLSMovementAnimSet_CameraFacing_Directional Cycle_HipBackward;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Gait Anim Set")
|
||||
FOLSMovementAnimSet_CameraFacing_Directional Pivot;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Gait Anim Set | Hip Backward")
|
||||
FOLSMovementAnimSet_CameraFacing_Directional Pivot_HipBackward;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Gait Anim Set | Hip Backward")
|
||||
FOLSMovementAnimSet_CameraFacing_Directional StopCycle_HipBackward;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Gait Anim Set")
|
||||
FOLSMovementAnimSet_CameraFacing_Directional StopCycle;
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
@ -379,9 +434,6 @@ public:
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Stance Anim Sets")
|
||||
FOLSGaitAnimSets WalkAnimSets;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Stance Anim Sets")
|
||||
uint8 bUseFeetPosition : 1 = false;
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
|
||||
@ -25,15 +25,6 @@ enum class EOLSHipDirection : uint8
|
||||
EBackward UMETA(DisplayName = "Backward")
|
||||
};
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EOLSCardinalDirection : uint8
|
||||
{
|
||||
EForward UMETA(DisplayName = "Forward"),
|
||||
EBackward UMETA(DisplayName = "Backward"),
|
||||
ELeft UMETA(DisplayName = "Left"),
|
||||
ERight UMETA(DisplayName = "Right")
|
||||
};
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EOLSLocomotionStatePlayRate : uint8
|
||||
{
|
||||
|
||||
@ -20,13 +20,14 @@ class OLSANIMATION_API UOLSLocomotionBPLibrary : public UBlueprintFunctionLibrar
|
||||
public:
|
||||
|
||||
UFUNCTION(BlueprintCallable,BlueprintPure,Category = "OLS|Function Library",meta=(BlueprintThreadSafe))
|
||||
static EOLSCardinalDirection SelectCardinalDirectionFromAngle(float angle, float deadZone, EOLSCardinalDirection currentDirection, bool useCurrentDirection = false);
|
||||
static EOLSMovementDirection SelectMovementDirectionFromAngle(float angle,
|
||||
const EOLSRotationMode& rotationMode,
|
||||
const EOLSGait& gait,
|
||||
const EOLSMovementDirectionBias& movementDirectionBias,
|
||||
const FOLSMovementDirectionThresholds& movementDirectionThreshold);
|
||||
|
||||
UFUNCTION(BlueprintCallable,BlueprintPure,Category = "OLS|Function Library",meta=(BlueprintThreadSafe))
|
||||
static EOLSCardinalDirection GetOppositeCardinalDirectional(EOLSCardinalDirection currentDirection);
|
||||
|
||||
UFUNCTION(BlueprintCallable,BlueprintPure,Category = "OLS|Function Library",meta=(BlueprintThreadSafe))
|
||||
static EOLSHipDirection GetOppositeHipDirection(EOLSHipDirection currentHipDirection);
|
||||
static EOLSMovementDirection GetOppositeMovementDirection(const EOLSMovementDirection& currentDirection, const EOLSMovementDirectionBias& movementDirectionBias);
|
||||
|
||||
public:
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user