플레이어 공격범위 수정
This commit is contained in:
parent
357c5da693
commit
4164e01d6a
|
|
@ -146843,7 +146843,7 @@ MonoBehaviour:
|
||||||
m_Script: {fileID: 11500000, guid: d4397a1006477aa418ff1693bdc232a1, type: 3}
|
m_Script: {fileID: 11500000, guid: d4397a1006477aa418ff1693bdc232a1, type: 3}
|
||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
baseMaxHealth: 100
|
baseMaxHealth: 1000
|
||||||
baseMoveSpeed: 5
|
baseMoveSpeed: 5
|
||||||
baseStrength: 10
|
baseStrength: 10
|
||||||
baseAttackDamage: 10
|
baseAttackDamage: 10
|
||||||
|
|
@ -217052,15 +217052,15 @@ PrefabInstance:
|
||||||
m_Modifications:
|
m_Modifications:
|
||||||
- target: {fileID: 450992007138140667, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
|
- target: {fileID: 450992007138140667, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
|
||||||
propertyPath: m_LocalPosition.x
|
propertyPath: m_LocalPosition.x
|
||||||
value: 20.181
|
value: 20.274
|
||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
- target: {fileID: 450992007138140667, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
|
- target: {fileID: 450992007138140667, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
|
||||||
propertyPath: m_LocalPosition.y
|
propertyPath: m_LocalPosition.y
|
||||||
value: 9.0006
|
value: 9.322
|
||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
- target: {fileID: 450992007138140667, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
|
- target: {fileID: 450992007138140667, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
|
||||||
propertyPath: m_LocalPosition.z
|
propertyPath: m_LocalPosition.z
|
||||||
value: 13.749
|
value: 13.741
|
||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
- target: {fileID: 450992007138140667, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
|
- target: {fileID: 450992007138140667, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
|
||||||
propertyPath: m_LocalRotation.w
|
propertyPath: m_LocalRotation.w
|
||||||
|
|
@ -217090,6 +217090,18 @@ PrefabInstance:
|
||||||
propertyPath: m_LocalEulerAnglesHint.z
|
propertyPath: m_LocalEulerAnglesHint.z
|
||||||
value: 172.153
|
value: 172.153
|
||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 4085536598674672635, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
|
||||||
|
propertyPath: m_Size.x
|
||||||
|
value: 0.003
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 4085536598674672635, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
|
||||||
|
propertyPath: m_Size.y
|
||||||
|
value: 0.008
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 6875888761843048781, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
|
||||||
|
propertyPath: m_Enabled
|
||||||
|
value: 1
|
||||||
|
objectReference: {fileID: 0}
|
||||||
- target: {fileID: 8071134912250732547, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
|
- target: {fileID: 8071134912250732547, guid: 9f51c4433e5c81644807e9e547b7826c, type: 3}
|
||||||
propertyPath: m_Name
|
propertyPath: m_Name
|
||||||
value: "\uCE7C (4)"
|
value: "\uCE7C (4)"
|
||||||
|
|
@ -217163,6 +217175,10 @@ PrefabInstance:
|
||||||
propertyPath: m_LocalEulerAnglesHint.y
|
propertyPath: m_LocalEulerAnglesHint.y
|
||||||
value: 0
|
value: 0
|
||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 2191869281094090394, guid: 6f13ab79d8b0c90469799a3505f07c8b, type: 3}
|
||||||
|
propertyPath: maxHP
|
||||||
|
value: 100
|
||||||
|
objectReference: {fileID: 0}
|
||||||
- target: {fileID: 3587750552762439828, guid: 6f13ab79d8b0c90469799a3505f07c8b, type: 3}
|
- target: {fileID: 3587750552762439828, guid: 6f13ab79d8b0c90469799a3505f07c8b, type: 3}
|
||||||
propertyPath: m_Name
|
propertyPath: m_Name
|
||||||
value: Monster
|
value: Monster
|
||||||
|
|
|
||||||
|
|
@ -8,21 +8,19 @@ public class PlayerAttack : MonoBehaviour
|
||||||
[SerializeField] private Stats stats;
|
[SerializeField] private Stats stats;
|
||||||
[SerializeField] private PlayerAnimator pAnim;
|
[SerializeField] private PlayerAnimator pAnim;
|
||||||
[SerializeField] private PlayerHealth playerHealth;
|
[SerializeField] private PlayerHealth playerHealth;
|
||||||
[SerializeField] private WeaponHitBox weaponHitBox;
|
[SerializeField] private WeaponHitBox weaponHitBox; // ⚔️ 낫에 붙은 히트박스
|
||||||
|
|
||||||
[Header("--- 설정 ---")]
|
[Header("--- 설정 ---")]
|
||||||
[SerializeField] private float attackCooldown = 0.4f;
|
[SerializeField] private float attackCooldown = 0.4f;
|
||||||
[SerializeField] private float fullChargeTime = 2f;
|
[SerializeField] private float fullChargeTime = 2f;
|
||||||
[SerializeField] private float postComboDelay = 1.2f; // 막타 후 딜레이 (n초)
|
[SerializeField] private float postComboDelay = 1.2f;
|
||||||
|
|
||||||
private float _lastAttackTime, _chargeTimer;
|
private float _lastAttackTime, _chargeTimer;
|
||||||
private bool _isCharging, _canAttack = true, _isAttacking = false;
|
private bool _isCharging, _canAttack = true, _isAttacking = false;
|
||||||
private int _comboCount = 0; // 콤보 카운트
|
private int _comboCount = 0;
|
||||||
|
|
||||||
public float ChargeProgress => Mathf.Clamp01(_chargeTimer / fullChargeTime);
|
public float ChargeProgress => Mathf.Clamp01(_chargeTimer / fullChargeTime);
|
||||||
public bool IsCharging => _isCharging;
|
public bool IsCharging => _isCharging;
|
||||||
|
|
||||||
// ⭐ 이동 스크립트에서 공격 중에 멈추게 할 때 사용하세요!
|
|
||||||
public bool IsAttacking => _isAttacking;
|
public bool IsAttacking => _isAttacking;
|
||||||
|
|
||||||
private void Update()
|
private void Update()
|
||||||
|
|
@ -40,54 +38,69 @@ public class PlayerAttack : MonoBehaviour
|
||||||
if (interaction.CurrentWeapon == null || pAnim == null) return;
|
if (interaction.CurrentWeapon == null || pAnim == null) return;
|
||||||
if (Time.time < _lastAttackTime + attackCooldown) return;
|
if (Time.time < _lastAttackTime + attackCooldown) return;
|
||||||
|
|
||||||
_isAttacking = true; // 🚫 공격 중 이동 제한 시작
|
_isAttacking = true;
|
||||||
_comboCount = (_comboCount % 3) + 1; // 1 -> 2 -> 3타 순환
|
_comboCount = (_comboCount % 3) + 1;
|
||||||
|
|
||||||
pAnim.TriggerAttack();
|
pAnim.TriggerAttack();
|
||||||
_lastAttackTime = Time.time;
|
_lastAttackTime = Time.time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ⭐ [수정] 휘두를 때 데미지를 실어서 판정을 켭니다.
|
||||||
|
public void StartWeaponCollision()
|
||||||
|
{
|
||||||
|
if (weaponHitBox != null)
|
||||||
|
{
|
||||||
|
Debug.Log("<color=yellow>[Attack]</color> 낫 공격 판정 ON!");
|
||||||
|
// stats에 설정된 공격력을 가져와서 전달하면 더 좋습니다.
|
||||||
|
weaponHitBox.EnableHitBox(20f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ⭐ [수정] 휘두르기가 끝나면 확실하게 판정을 끕니다.
|
||||||
|
public void StopWeaponCollision()
|
||||||
|
{
|
||||||
|
if (weaponHitBox != null)
|
||||||
|
{
|
||||||
|
Debug.Log("<color=yellow>[Attack]</color> 낫 공격 판정 OFF!");
|
||||||
|
weaponHitBox.DisableHitBox();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void OnAttackShake()
|
public void OnAttackShake()
|
||||||
{
|
{
|
||||||
if (CinemachineShake.Instance == null) return;
|
if (CinemachineShake.Instance == null) return;
|
||||||
|
|
||||||
if (_comboCount == 3) // 🔥 인왕 스타일 3타 막타 연출!
|
if (_comboCount == 3)
|
||||||
{
|
{
|
||||||
CinemachineShake.Instance.HitSlow(0.2f, 0.05f); // 묵직한 슬로우
|
CinemachineShake.Instance.HitSlow(0.2f, 0.05f);
|
||||||
CinemachineShake.Instance.CameraKick(10f); // 화끈한 카메라 킥
|
CinemachineShake.Instance.CameraKick(10f);
|
||||||
CinemachineShake.Instance.ShakeAttack();
|
CinemachineShake.Instance.ShakeAttack();
|
||||||
}
|
}
|
||||||
else // 일반 1, 2타
|
else
|
||||||
{
|
{
|
||||||
CinemachineShake.Instance.HitSlow(0.1f, 0.2f);
|
CinemachineShake.Instance.HitSlow(0.1f, 0.2f);
|
||||||
CinemachineShake.Instance.ShakeAttack();
|
CinemachineShake.Instance.ShakeAttack();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ⭐ 공격 애니메이션 마지막 프레임에 꼭 넣으세요!
|
|
||||||
public void OnAttackEnd()
|
public void OnAttackEnd()
|
||||||
{
|
{
|
||||||
if (_comboCount == 3) // 막타가 끝났다면 후딜레이 시작
|
StopWeaponCollision(); // 🚫 안전장치: 공격이 끝나면 무조건 판정을 끕니다.
|
||||||
{
|
if (_comboCount == 3) { StartCoroutine(PostComboRecovery()); }
|
||||||
StartCoroutine(PostComboRecovery());
|
else { _isAttacking = false; }
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_isAttacking = false; // 1, 2타는 즉시 이동 가능
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerator PostComboRecovery()
|
private IEnumerator PostComboRecovery()
|
||||||
{
|
{
|
||||||
_canAttack = false;
|
_canAttack = false;
|
||||||
_isAttacking = true; // 딜레이 중에도 이동 제한
|
_isAttacking = true;
|
||||||
yield return new WaitForSeconds(postComboDelay);
|
yield return new WaitForSeconds(postComboDelay);
|
||||||
_canAttack = true;
|
_canAttack = true;
|
||||||
_isAttacking = false; // 이제 움직이기 가능
|
_isAttacking = false;
|
||||||
_comboCount = 0; // 콤보 리셋
|
_comboCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CancelCharging() // 🛠️ 에러 해결: 확실하게 포함됨!
|
public void CancelCharging()
|
||||||
{
|
{
|
||||||
_isCharging = false;
|
_isCharging = false;
|
||||||
_chargeTimer = 0f;
|
_chargeTimer = 0f;
|
||||||
|
|
@ -98,10 +111,34 @@ public class PlayerAttack : MonoBehaviour
|
||||||
public void ReleaseAttack()
|
public void ReleaseAttack()
|
||||||
{
|
{
|
||||||
if (!_isCharging || interaction.CurrentWeapon == null) return;
|
if (!_isCharging || interaction.CurrentWeapon == null) return;
|
||||||
|
|
||||||
pAnim.TriggerThrow();
|
pAnim.TriggerThrow();
|
||||||
pAnim.SetCharging(false);
|
pAnim.SetCharging(false);
|
||||||
|
|
||||||
// 던지기 물리 로직 생략 (기존 것 유지)
|
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
|
||||||
|
Plane groundPlane = new Plane(Vector3.up, transform.position);
|
||||||
|
float rayDistance;
|
||||||
|
Vector3 targetDirection = transform.forward;
|
||||||
|
|
||||||
|
if (groundPlane.Raycast(ray, out rayDistance))
|
||||||
|
{
|
||||||
|
Vector3 pointOnGround = ray.GetPoint(rayDistance);
|
||||||
|
targetDirection = (pointOnGround - transform.position).normalized;
|
||||||
|
targetDirection.y = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetDirection != Vector3.zero) transform.rotation = Quaternion.LookRotation(targetDirection);
|
||||||
|
|
||||||
|
// 🛠️ 무기 독립 로직 (자식에서 떼어내기)
|
||||||
|
GameObject weaponObj = interaction.CurrentWeapon.gameObject;
|
||||||
|
weaponObj.transform.SetParent(null);
|
||||||
|
|
||||||
|
int lv = _chargeTimer >= 2f ? 3 : (_chargeTimer >= 1f ? 2 : 1);
|
||||||
|
float throwForce = interaction.CurrentWeapon.Config.GetForce(lv);
|
||||||
|
float currentSpread = interaction.CurrentWeapon.Config.GetSpread(lv);
|
||||||
|
Vector3 finalThrowDir = Quaternion.Euler(0, Random.Range(-currentSpread, currentSpread), 0) * targetDirection;
|
||||||
|
|
||||||
|
interaction.CurrentWeapon.OnThrown(finalThrowDir, throwForce, lv, stats);
|
||||||
|
|
||||||
if (CinemachineShake.Instance != null)
|
if (CinemachineShake.Instance != null)
|
||||||
{
|
{
|
||||||
|
|
@ -125,7 +162,13 @@ public class PlayerAttack : MonoBehaviour
|
||||||
pAnim.SetCharging(true);
|
pAnim.SetCharging(true);
|
||||||
if (CinemachineShake.Instance != null) CinemachineShake.Instance.SetZoom(true);
|
if (CinemachineShake.Instance != null) CinemachineShake.Instance.SetZoom(true);
|
||||||
}
|
}
|
||||||
|
private void OnDrawGizmos()
|
||||||
public void StartWeaponCollision() { /* ... */ }
|
{
|
||||||
public void StopWeaponCollision() { /* ... */ }
|
Gizmos.color = Color.red; // 공격 범위는 빨간색으로 표시
|
||||||
|
if (TryGetComponent<BoxCollider>(out var box))
|
||||||
|
{
|
||||||
|
Gizmos.matrix = transform.localToWorldMatrix;
|
||||||
|
Gizmos.DrawWireCube(box.center, box.size);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,36 +1,45 @@
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
public class WeaponHitBox : MonoBehaviour
|
public class WeaponHitBox : MonoBehaviour
|
||||||
{
|
{
|
||||||
private float _damage;
|
private float _damage;
|
||||||
private bool _isActive;
|
private bool _isActive = false; // ⭐ 기본은 꺼져 있어야 합니다!
|
||||||
private List<IDamageable> _hitTargets = new List<IDamageable>();
|
private List<IDamageable> _hitTargets = new List<IDamageable>();
|
||||||
|
|
||||||
public void EnableHitBox(float damage)
|
public void EnableHitBox(float damage)
|
||||||
{
|
{
|
||||||
_damage = damage;
|
_damage = damage;
|
||||||
_isActive = true;
|
_isActive = true; // 이제부터 공격 가능
|
||||||
_hitTargets.Clear(); // 휘두를 때마다 초기화하여 중복 타격 방지
|
_hitTargets.Clear();
|
||||||
|
gameObject.SetActive(true); // 오브젝트도 함께 켜줍니다.
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DisableHitBox()
|
public void DisableHitBox()
|
||||||
{
|
{
|
||||||
_isActive = false;
|
_isActive = false; // 공격 불가능
|
||||||
|
gameObject.SetActive(false); // 오브젝트도 꺼줍니다.
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnTriggerEnter(Collider other)
|
private void OnTriggerEnter(Collider other)
|
||||||
{
|
{
|
||||||
|
// 1. 공격 활성화 상태가 아니면 무시 (근접 킬 방지)
|
||||||
if (!_isActive) return;
|
if (!_isActive) return;
|
||||||
|
|
||||||
// 적에게 데미지 입히기
|
// 2. ⭐ [자해 방지] 부딪힌 대상이 나(Player)라면 무시합니다!
|
||||||
|
if (other.CompareTag("Player")) return;
|
||||||
|
|
||||||
|
// 3. 적(IDamageable)에게 데미지 입히기
|
||||||
if (other.TryGetComponent<IDamageable>(out var target))
|
if (other.TryGetComponent<IDamageable>(out var target))
|
||||||
{
|
{
|
||||||
if (!_hitTargets.Contains(target)) // 한 번 휘두를 때 한 명당 한 번만 맞게
|
if (!_hitTargets.Contains(target))
|
||||||
{
|
{
|
||||||
target.TakeDamage(_damage);
|
target.TakeDamage(_damage);
|
||||||
_hitTargets.Add(target);
|
_hitTargets.Add(target);
|
||||||
Debug.Log($"{other.name}에게 {_damage}의 물리 데미지!");
|
Debug.Log($"<color=green>[Hit]</color> {other.name}에게 {_damage} 데미지!");
|
||||||
|
|
||||||
|
// 타격 시 효과 (카메라 쉐이크 등 호출)
|
||||||
|
SendMessageUpwards("OnAttackShake", SendMessageOptions.DontRequireReceiver);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,31 @@
|
||||||
%YAML 1.1
|
%YAML 1.1
|
||||||
%TAG !u! tag:unity3d.com,2011:
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!1102 &-1543731576706283773
|
||||||
|
AnimatorState:
|
||||||
|
serializedVersion: 6
|
||||||
|
m_ObjectHideFlags: 1
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_Name: Speed
|
||||||
|
m_Speed: 1
|
||||||
|
m_CycleOffset: 0
|
||||||
|
m_Transitions: []
|
||||||
|
m_StateMachineBehaviours: []
|
||||||
|
m_Position: {x: 50, y: 50, z: 0}
|
||||||
|
m_IKOnFeet: 0
|
||||||
|
m_WriteDefaultValues: 1
|
||||||
|
m_Mirror: 0
|
||||||
|
m_SpeedParameterActive: 0
|
||||||
|
m_MirrorParameterActive: 0
|
||||||
|
m_CycleOffsetParameterActive: 0
|
||||||
|
m_TimeParameterActive: 0
|
||||||
|
m_Motion: {fileID: 7400000, guid: 01afba47ff0a5471596377d541fcfd45, type: 2}
|
||||||
|
m_Tag:
|
||||||
|
m_SpeedParameter:
|
||||||
|
m_MirrorParameter:
|
||||||
|
m_CycleOffsetParameter:
|
||||||
|
m_TimeParameter:
|
||||||
--- !u!91 &9100000
|
--- !u!91 &9100000
|
||||||
AnimatorController:
|
AnimatorController:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
|
@ -27,6 +53,12 @@ AnimatorController:
|
||||||
m_DefaultInt: 0
|
m_DefaultInt: 0
|
||||||
m_DefaultBool: 0
|
m_DefaultBool: 0
|
||||||
m_Controller: {fileID: 9100000}
|
m_Controller: {fileID: 9100000}
|
||||||
|
- m_Name: Speed
|
||||||
|
m_Type: 1
|
||||||
|
m_DefaultFloat: 0
|
||||||
|
m_DefaultInt: 0
|
||||||
|
m_DefaultBool: 0
|
||||||
|
m_Controller: {fileID: 9100000}
|
||||||
m_AnimatorLayers:
|
m_AnimatorLayers:
|
||||||
- serializedVersion: 5
|
- serializedVersion: 5
|
||||||
m_Name: Base Layer
|
m_Name: Base Layer
|
||||||
|
|
@ -171,6 +203,9 @@ AnimatorStateMachine:
|
||||||
- serializedVersion: 1
|
- serializedVersion: 1
|
||||||
m_State: {fileID: 3240602218424255273}
|
m_State: {fileID: 3240602218424255273}
|
||||||
m_Position: {x: 410, y: -320, z: 0}
|
m_Position: {x: 410, y: -320, z: 0}
|
||||||
|
- serializedVersion: 1
|
||||||
|
m_State: {fileID: -1543731576706283773}
|
||||||
|
m_Position: {x: 130, y: 210, z: 0}
|
||||||
m_ChildStateMachines: []
|
m_ChildStateMachines: []
|
||||||
m_AnyStateTransitions: []
|
m_AnyStateTransitions: []
|
||||||
m_EntryTransitions: []
|
m_EntryTransitions: []
|
||||||
|
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
fileFormatVersion: 2
|
|
||||||
guid: 194ffb9f0c5b86f4aaa6ac1ef3ade1ed
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
fileFormatVersion: 2
|
|
||||||
guid: 713ea1b84c2a9fc4d8c7f695ca916c8b
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
fileFormatVersion: 2
|
|
||||||
guid: ac56f8aebac30674489c8b5741b0489a
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
fileFormatVersion: 2
|
|
||||||
guid: 68d9417a84829c6459075121b8ac78bd
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
Loading…
Reference in New Issue
Block a user