CarmenSandiego/Assets/UdonSharp/CaseVideoSyncPlayer.cs

316 lines
7.8 KiB
C#

using UdonSharp;
using UnityEngine;
using VRC.SDK3.Image;
using VRC.SDK3.UdonNetworkCalling;
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;
[UdonSynced, FieldChangeCallback(nameof(ShowScreen))] private ClueScreenType _ShowScreen = ClueScreenType.Blank;
[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;
[SerializeField] private Texture2D _PlaceholderMapTexture;
private VRCImageDownloader _MapDownloader;
private Texture2D[] _MapImages;
private IUdonEventReceiver _UdonEventReceiverThis;
private int[] _CachedMapIndices = new int[0];
private int _MapDownloadIndex = 0;
private bool _MapDownloadsInProgress = false;
private const int IMAGES_PER_MAP_ATLAS = 6;
void Start()
{
_MapDownloader = new VRCImageDownloader();
_UdonEventReceiverThis = (IUdonEventReceiver)this;
}
void OnDestroy()
{
_MapDownloader.Dispose();
}
[NetworkCallable]
public void QueueMapDownloads(int[] MapIndices)
{
if (_MapDownloadsInProgress)
{
// Concatenate both caches into a new bigger cache and await new downloads as usual
int[] NewMapIndicesCache = new int[_CachedMapIndices.Length + MapIndices.Length];
Texture2D[] NewMapImages = new Texture2D[_CachedMapIndices.Length + MapIndices.Length];
for (int i = 0; i < _CachedMapIndices.Length; i++)
{
NewMapIndicesCache[i] = _CachedMapIndices[i];
NewMapImages[i] = _MapImages[i];
}
for (int i = 0; i < MapIndices.Length; i++)
{
NewMapIndicesCache[i + _CachedMapIndices.Length] = MapIndices[i];
NewMapImages[i + _CachedMapIndices.Length] = _PlaceholderMapTexture;
}
_CachedMapIndices = NewMapIndicesCache;
_MapImages = NewMapImages;
}
else
{
_MapDownloadsInProgress = true;
_CachedMapIndices = MapIndices;
_MapImages = new Texture2D[_CachedMapIndices.Length];
for (int i = 0; i < _MapImages.Length; i++)
{
_MapImages[i] = _PlaceholderMapTexture;
}
_SubMapIndex = 0;
_MapDownloadIndex = 0;
LoadMapFromIndex(_CachedMapIndices[_MapDownloadIndex]);
}
}
private void LoadMapFromIndex(int MapIndex)
{
VRCUrl MapURL = _GameManager.GetMapURL(MapIndex);
TextureInfo AdditionalTextureInfo = new TextureInfo();
AdditionalTextureInfo.WrapModeU = TextureWrapMode.Clamp;
AdditionalTextureInfo.WrapModeV = TextureWrapMode.Clamp;
AdditionalTextureInfo.GenerateMipMaps = true;
_MapDownloader.DownloadImage(MapURL, null, _UdonEventReceiverThis, AdditionalTextureInfo);
}
public override void OnImageLoadSuccess(IVRCImageDownload Result)
{
_MapImages[_MapDownloadIndex] = Result.Result;
int MapPage = SubMapIndex / IMAGES_PER_MAP_ATLAS;
if (MapPage == _MapDownloadIndex)
{
_MapScreenMesh.sharedMaterial.SetTexture("_EmissionMap", _MapImages[MapPage]);
}
_MapDownloadIndex++;
if (_MapDownloadIndex >= _CachedMapIndices.Length)
{
_MapDownloadsInProgress = false;
}
else
{
LoadMapFromIndex(_CachedMapIndices[_MapDownloadIndex]);
}
base.OnImageLoadSuccess(Result);
}
public override void OnImageLoadError(IVRCImageDownload Result)
{
_MapDownloadsInProgress = false;
base.OnImageLoadError(Result);
}
public void NextCorrectAnswerFrame()
{
if (FlashCorrectAnswer)
{
SubMapIndex = (SubMapIndex == 4) ? 3 : 4;
SendCustomEventDelayedSeconds(nameof(NextCorrectAnswerFrame), 0.2f);
}
else
{
_VideoPlayer.Stop();
SubMapIndex = 0;
ShowScreen = ClueScreenType.Blank;
}
}
private void UpdateMap()
{
int MapPage = SubMapIndex / IMAGES_PER_MAP_ATLAS;
int SubmapIndexWrapped = SubMapIndex % IMAGES_PER_MAP_ATLAS;
switch (SubmapIndexWrapped)
{
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;
}
_MapScreenMesh.sharedMaterial.SetTexture("_EmissionMap", _MapImages[MapPage]);
ShowScreen = ClueScreenType.Map;
RequestSerialization();
}
public void PlayVideo()
{
_VideoPlayer.PlayURL(VideoURL);
RequestSerialization();
}
public override void OnVideoStart()
{
ShowScreen = ClueScreenType.Video;
//UpdateTimeAndOffset();
base.OnVideoStart();
}
public override void OnVideoEnd()
{
ShowScreen = ClueScreenType.Blank;
base.OnVideoEnd();
}
private void UpdateTimeAndOffset()
{
if (Networking.IsOwner(gameObject))
{
TimeAndOffset = new Vector2(_VideoPlayer.GetTime(), (float)Networking.GetServerTimeInSeconds());
if (SyncFrequency > 0.0f)
{
SendCustomEventDelayedSeconds(nameof(UpdateTimeAndOffset), SyncFrequency);
}
}
else
{
Resync();
}
RequestSerialization();
}
public void Resync()
{
_VideoPlayer.SetTime(TimeAndOffset.x + ((float)Networking.GetServerTimeInSeconds() - TimeAndOffset.y));
}
public void ClearScreen()
{
ShowScreen = ClueScreenType.Blank;
FlashCorrectAnswer = false;
}
private void SwapToScreen(ClueScreenType Screen)
{
if (ShowScreen == Screen) return;
switch (Screen)
{
case ClueScreenType.Blank:
{
_BlankScreenMesh.transform.localPosition = new Vector3(0.0f, 0.0f, 0.0f);
_VideoScreenMesh.transform.localPosition = new Vector3(0.0f, -1000.0f, 0.0f);
_MapScreenMesh.transform.localPosition = new Vector3(0.0f, -1000.0f, 0.0f);
break;
}
case ClueScreenType.Video:
{
_BlankScreenMesh.transform.localPosition = new Vector3(0.0f, -1000.0f, 0.0f);
_VideoScreenMesh.transform.localPosition = new Vector3(0.0f, 0.0f, 0.0f);
_MapScreenMesh.transform.localPosition = new Vector3(0.0f, -1000.0f, 0.0f);
break;
}
case ClueScreenType.Map:
{
_BlankScreenMesh.transform.localPosition = new Vector3(0.0f, -1000.0f, 0.0f);
_VideoScreenMesh.transform.localPosition = new Vector3(0.0f, -1000.0f, 0.0f);
_MapScreenMesh.transform.localPosition = new Vector3(0.0f, 0.0f, 0.0f);
break;
}
}
RequestSerialization();
}
public int SubMapIndex
{
set
{
_SubMapIndex = value;
UpdateMap();
}
get => _SubMapIndex;
}
public ClueScreenType ShowScreen
{
set
{
SwapToScreen(value);
_ShowScreen = value;
}
get => _ShowScreen;
}
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))
{
Resync();
}
}
get => _TimeAndOffset;
}
}