using UdonSharp; using UnityEngine; using VRC.SDK3.Components; using VRC.SDK3.Data; using VRC.SDK3.UdonNetworkCalling; using VRC.SDKBase; using VRC.Udon.Common.Interfaces; [UdonBehaviourSyncMode(BehaviourSyncMode.Manual)] public class FloorMapMarker : UdonSharpBehaviour { [UdonSynced, FieldChangeCallback(nameof(LocationFindingEnabled))] public bool _LocationFindingEnabled = false; [UdonSynced, FieldChangeCallback(nameof(IsGrabbed))] private bool _IsGrabbed = false; [SerializeField] private GameManagerRound3 _GameManager; [SerializeField] private Material _LitLampMaterial; private DataList _CollidingLocations = new DataList(); [UdonSynced] private int _CollisionCheckCounter = 0; [UdonSynced] private int _NoCollisionCounter = 0; private const int MAX_REPEAT_COLLISION_CHECKS = 3; private const int MAX_TIME_WITH_NO_COLLISIONS = 8; private const float TIME_BETWEEN_REPEAT_COLLISION_CHECKS = 0.15f; public void OnTriggerEnter(Collider OtherCollider) { FloorMapLocation Location = OtherCollider.GetComponent(); if (Location != null) { _CollidingLocations.Add(Location); _CollisionCheckCounter = 0; _NoCollisionCounter = 0; if (!IsGrabbed) CheckCollisions(); } } public void OnTriggerExit(Collider OtherCollider) { FloorMapLocation Location = OtherCollider.GetComponent(); if (Location != null) { _CollidingLocations.Remove(Location); _CollisionCheckCounter = 0; _NoCollisionCounter = 0; } } public override void OnPickup() { Rigidbody Body; if (Body = GetComponent()) { Body.constraints = RigidbodyConstraints.None; } IsGrabbed = true; _NoCollisionCounter = 0; _CollidingLocations.Clear(); base.OnPickup(); } public override void OnDrop() { IsGrabbed = false; VRCPlayerApi Owner = Networking.GetOwner(gameObject); if (!Owner.IsUserInVR()) { transform.eulerAngles = new Vector3(0.0f, transform.eulerAngles.y, 0.0f); } _NoCollisionCounter = 0; CheckCollisions(); base.OnDrop(); } public void CheckCollisions() { if (!LocationFindingEnabled || IsGrabbed) return; if (_CollidingLocations.Count > 0 && IsUpright()) { _NoCollisionCounter = 0; 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) { NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)this, NetworkEventTarget.All, nameof(SendCorrectResponse), Location.transform.position); 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 { NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)this, NetworkEventTarget.All, nameof(SendIncorrectResponse)); } _CollisionCheckCounter++; } else { _NoCollisionCounter++; if (_NoCollisionCounter >= MAX_TIME_WITH_NO_COLLISIONS) { NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)this, NetworkEventTarget.All, nameof(SendIncorrectResponse)); } 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; } [NetworkCallable] public void SendCorrectResponse(Vector3 CorrectLocation) { DisableMovementCompletely(CorrectLocation); MeshRenderer MarkerMesh; if (MarkerMesh = GetComponent()) { Material[] Materials = MarkerMesh.materials; Materials[2] = _LitLampMaterial; MarkerMesh.materials = Materials; } _GameManager.CorrectResponse(); } [NetworkCallable] public void SendIncorrectResponse() { DisableMovementCompletely(); _GameManager.IncorrectResponse(); _CollisionCheckCounter = 0; _CollidingLocations.Clear(); } public void EnablePickup(bool Enable) { VRCPickup Pickup; if (Pickup = GetComponent()) { Pickup.pickupable = Enable; } } public void DisableMovementCompletely(Vector3 CorrectLocation = new Vector3()) { Rigidbody Body; if (Body = GetComponent()) { Body.constraints = RigidbodyConstraints.FreezeAll; } transform.eulerAngles = new Vector3(0.0f, transform.eulerAngles.y, 0.0f); if (CorrectLocation != Vector3.zero) { transform.position = CorrectLocation; } } private bool IsUpright() { return (Vector3.Dot(transform.up, Vector3.up) >= 0.85f); } public bool LocationFindingEnabled { set { _LocationFindingEnabled = value; } get => _LocationFindingEnabled; } public bool IsGrabbed { set { _IsGrabbed = value; } get => _IsGrabbed; } }