using UdonSharp; using UnityEngine; using VRC.SDK3.Components; using VRC.SDK3.Data; using static UnityEditor.FilePathAttribute; [UdonBehaviourSyncMode(BehaviourSyncMode.Manual)] public class FloorMapMarker : UdonSharpBehaviour { [UdonSynced, SerializeField, FieldChangeCallback(nameof(Enabled))] private bool _Enabled = false; [UdonSynced, FieldChangeCallback(nameof(IsGrabbed))] private bool _IsGrabbed = false; [SerializeField] private GameManagerRound3 _GameManager; [SerializeField] private AudioManager _AudioManager; private DataList _CollidingLocations = new DataList(); private int _CollisionCheckCounter = 0; private int _FailureCounter = 0; private const int MAX_REPEAT_COLLISION_CHECKS = 3; private const float TIME_BETWEEN_REPEAT_COLLISION_CHECKS = 0.15f; private const int MAX_FAILURE_COUNT = 2; public void OnTriggerEnter(Collider OtherCollider) { FloorMapLocation Location = OtherCollider.GetComponent(); if (Location != null) { _CollidingLocations.Add(Location); _CollisionCheckCounter = 0; if (!IsGrabbed) CheckCollisions(); } } public void OnTriggerExit(Collider OtherCollider) { FloorMapLocation Location = OtherCollider.GetComponent(); if (Location != null) { _CollidingLocations.Remove(Location); _CollisionCheckCounter = 0; } } public override void OnPickup() { Rigidbody Body; if (Body = GetComponent()) { Body.constraints = RigidbodyConstraints.None; } Enabled = true; IsGrabbed = true; _CollidingLocations.Clear(); base.OnPickup(); } public override void OnDrop() { IsGrabbed = false; CheckCollisions(); base.OnDrop(); } public void CheckCollisions() { if (!Enabled) return; if (_CollidingLocations.Count > 0 && IsUpright() && !IsGrabbed) { for (int i = 0; i < _CollidingLocations.Count; i++) { FloorMapLocation Location = (FloorMapLocation)_CollidingLocations[i].Reference; if (Location != null) { bool FoundCorrectResponse = ConfirmChoice(Location.Country, Location.City); if (FoundCorrectResponse) { _AudioManager.PlaySFX(SFXEventType.MapCorrect); Rigidbody Body; if (Body = GetComponent()) { Body.constraints = RigidbodyConstraints.FreezeAll; } transform.position = Location.transform.position; StandUpright(); Enabled = false; EnablePickup(false); return; } } } // We should make sure to only reach here if we don't get a correct // response from the previous loop. if (_CollisionCheckCounter < MAX_REPEAT_COLLISION_CHECKS) { SendCustomEventDelayedSeconds(nameof(CheckCollisions), TIME_BETWEEN_REPEAT_COLLISION_CHECKS); } else { _AudioManager.PlaySFX(SFXEventType.MapIncorrect); Rigidbody Body; if (Body = GetComponent()) { Body.constraints = RigidbodyConstraints.FreezeAll; } StandUpright(); _CollisionCheckCounter = 0; _CollidingLocations.Clear(); // Stop checking for new collisions here, and if this results // in too many fails, don't allow new pickups. Enabled = false; _FailureCounter++; if (_FailureCounter >= MAX_FAILURE_COUNT) { EnablePickup(false); } } _CollisionCheckCounter++; } else { // If the marker isn't sitting mostly upright and is not grabbed, // don't check collisions until later, in case it becomes upright. SendCustomEventDelayedSeconds(nameof(CheckCollisions), TIME_BETWEEN_REPEAT_COLLISION_CHECKS); } } public bool ConfirmChoice(string Country, string City) { if (Country == _GameManager.GetCurrentCountry() && City == _GameManager.GetCurrentCity()) { return true; } return false; } private void EnablePickup(bool Enable) { VRCPickup Pickup; if (Pickup = GetComponent()) { Pickup.pickupable = Enable; } } private void StandUpright() { transform.eulerAngles = new Vector3(0.0f, transform.eulerAngles.y, 0.0f); } private bool IsUpright() { return (Vector3.Dot(transform.up, Vector3.up) >= 0.85f); } public bool Enabled { set { _Enabled = value; } get => _Enabled; } public bool IsGrabbed { set { _IsGrabbed = value; } get => _IsGrabbed; } }