using UdonSharp; using UnityEngine; using VRC.SDK3.Image; using VRC.SDK3.Video.Components.Base; using VRC.SDKBase; using VRC.Udon.Common.Interfaces; public enum ClueScreenType { Blank, Video, Map } [UdonBehaviourSyncMode(BehaviourSyncMode.Manual)] public class CaseVideoSyncPlayer : UdonSharpBehaviour { [SerializeField] private GameManagerRound1 _GameManager; [UdonSynced, FieldChangeCallback(nameof(SubMapIndex))] private int _SubMapIndex = 0; [FieldChangeCallback(nameof(FlashCorrectAnswer))] private bool _FlashCorrectAnswer = false; [SerializeField] private BaseVRCVideoPlayer _VideoPlayer; [UdonSynced, FieldChangeCallback(nameof(VideoURL))] private VRCUrl _VideoURL; [UdonSynced, FieldChangeCallback(nameof(TimeAndOffset))] private Vector2 _TimeAndOffset; public float SyncFrequency = 5.0f; [SerializeField] private MeshRenderer _BlankScreenMesh; [SerializeField] private MeshRenderer _VideoScreenMesh; [SerializeField] private MeshRenderer _MapScreenMesh; private VRCImageDownloader _MapDownloader; void Start() { _MapDownloader = new VRCImageDownloader(); } void OnDestroy() { _MapDownloader.Dispose(); } public void LoadMap(int MapIndex) { ShowScreen(ClueScreenType.Blank); TextureInfo AdditionalTextureInfo = new TextureInfo(); AdditionalTextureInfo.WrapModeU = TextureWrapMode.Clamp; AdditionalTextureInfo.WrapModeV = TextureWrapMode.Clamp; AdditionalTextureInfo.GenerateMipMaps = false; AdditionalTextureInfo.MaterialProperty = "_EmissionMap"; _MapDownloader.DownloadImage( _GameManager.GetMapURL(MapIndex), _MapScreenMesh.sharedMaterial, (IUdonEventReceiver)this, AdditionalTextureInfo); } public override void OnImageLoadSuccess(IVRCImageDownload result) { base.OnImageLoadSuccess(result); } public override void OnImageLoadError(IVRCImageDownload result) { base.OnImageLoadError(result); } public void InitialiseMapScreen() { _VideoPlayer.Stop(); SubMapIndex = 0; ShowScreen(ClueScreenType.Map); } public void IncrementMap() { SubMapIndex++; } public void NextCorrectAnswerFrame() { if (FlashCorrectAnswer) { SubMapIndex = (SubMapIndex == 4) ? 3 : 4; Debug.LogError("Switching to frame " + SubMapIndex + "..."); SendCustomEventDelayedSeconds(nameof(NextCorrectAnswerFrame), 0.25f); } } private void UpdateMap() { switch (SubMapIndex) { case 0: _MapScreenMesh.sharedMaterial.SetVector("_MainTex_ST", new Vector4(0.5f, 0.33333333f, 0.0f, 0.66666666f)); break; case 1: _MapScreenMesh.sharedMaterial.SetVector("_MainTex_ST", new Vector4(0.5f, 0.33333333f, 0.5f, 0.66666666f)); break; case 2: _MapScreenMesh.sharedMaterial.SetVector("_MainTex_ST", new Vector4(0.5f, 0.33333333f, 0.0f, 0.33333333f)); break; case 3: _MapScreenMesh.sharedMaterial.SetVector("_MainTex_ST", new Vector4(0.5f, 0.33333333f, 0.5f, 0.33333333f)); break; case 4: _MapScreenMesh.sharedMaterial.SetVector("_MainTex_ST", new Vector4(0.5f, 0.33333333f, 0.0f, 0.0f)); break; case 5: _MapScreenMesh.sharedMaterial.SetVector("_MainTex_ST", new Vector4(0.5f, 0.33333333f, 0.5f, 0.0f)); break; } } public void PlayVideo() { _VideoPlayer.PlayURL(VideoURL); RequestSerialization(); } public override void OnVideoStart() { Debug.LogError("Displaying video material..."); ShowScreen(ClueScreenType.Video); UpdateTimeAndOffset(); base.OnVideoStart(); } private void UpdateTimeAndOffset() { if (Networking.IsOwner(gameObject)) { TimeAndOffset = new Vector2(_VideoPlayer.GetTime(), (float)Networking.GetServerTimeInSeconds()); RequestSerialization(); if (SyncFrequency > 0.0f) { SendCustomEventDelayedSeconds(nameof(UpdateTimeAndOffset), SyncFrequency); } } else { SendCustomEvent(nameof(Resync)); } } public void Resync() { _VideoPlayer.SetTime(TimeAndOffset.x + ((float)Networking.GetServerTimeInSeconds() - TimeAndOffset.y)); } public void ClearScreen() { ShowScreen(ClueScreenType.Blank); FlashCorrectAnswer = false; } private void ShowScreen(ClueScreenType Screen) { switch (Screen) { case ClueScreenType.Blank: { _BlankScreenMesh.gameObject.SetActive(true); _VideoScreenMesh.gameObject.SetActive(false); _MapScreenMesh.gameObject.SetActive(false); break; } case ClueScreenType.Video: { _BlankScreenMesh.gameObject.SetActive(false); _VideoScreenMesh.gameObject.SetActive(true); _MapScreenMesh.gameObject.SetActive(false); break; } case ClueScreenType.Map: { _BlankScreenMesh.gameObject.SetActive(false); _VideoScreenMesh.gameObject.SetActive(false); _MapScreenMesh.gameObject.SetActive(true); break; } } } public int SubMapIndex { set { _SubMapIndex = value; UpdateMap(); } get => _SubMapIndex; } public bool FlashCorrectAnswer { set { _FlashCorrectAnswer = value; NextCorrectAnswerFrame(); } get => _FlashCorrectAnswer; } public VRCUrl VideoURL { set { if (_VideoURL != value) { _VideoURL = value; PlayVideo(); } } get => _VideoURL; } public Vector2 TimeAndOffset { set { _TimeAndOffset = value; if (!Networking.IsOwner(gameObject)) { SendCustomEvent(nameof(Resync)); } } get => _TimeAndOffset; } }