190 lines
7.0 KiB
C#
190 lines
7.0 KiB
C#
using UnityEngine;
|
|
using VRC.SDKBase;
|
|
using System.Reflection;
|
|
using UnityEngine.Rendering.PostProcessing;
|
|
|
|
namespace VRC.SDK3.ClientSim
|
|
{
|
|
/// <summary>
|
|
/// Wrapper for the VRC_SceneDescriptor.
|
|
/// </summary>
|
|
public class ClientSimSceneManager : IClientSimSceneManager
|
|
{
|
|
// Using a variable here to allow for testability when not on android platform.
|
|
private bool _isAndroid =
|
|
#if UNITY_ANDROID
|
|
true;
|
|
#else
|
|
false;
|
|
#endif
|
|
|
|
// Only used for tests to verify android path in copy camera.
|
|
internal static ClientSimSceneManager CreateTestInstance(bool isAndroid)
|
|
{
|
|
return new ClientSimSceneManager { _isAndroid = isAndroid };
|
|
}
|
|
|
|
|
|
private int _spawnOrder = 0;
|
|
private VRC_SceneDescriptor _descriptor => VRC_SceneDescriptor.Instance;
|
|
|
|
|
|
public bool HasSceneDescriptor()
|
|
{
|
|
return _descriptor != null;
|
|
}
|
|
|
|
public void SetupCamera(Camera camera)
|
|
{
|
|
if (!HasSceneDescriptor())
|
|
{
|
|
throw new ClientSimException("Cannot get reference camera when there is no scene descriptor.");
|
|
}
|
|
|
|
Camera refCamera = null;
|
|
if (_descriptor.ReferenceCamera != null)
|
|
{
|
|
refCamera = _descriptor.ReferenceCamera.GetComponent<Camera>();
|
|
}
|
|
|
|
if (refCamera != null)
|
|
{
|
|
CopyCameraValues(refCamera, camera);
|
|
}
|
|
else
|
|
{
|
|
this.LogWarning("Reference camera is not set in the SceneDescriptor!");
|
|
|
|
// Force camera near settings
|
|
camera.nearClipPlane = Mathf.Clamp(camera.nearClipPlane, 0.01f, 0.05f);
|
|
}
|
|
}
|
|
|
|
public float GetRespawnHeight()
|
|
{
|
|
if (!HasSceneDescriptor())
|
|
{
|
|
throw new ClientSimException("Cannot get respawn height when there is no scene descriptor.");
|
|
}
|
|
|
|
return _descriptor.RespawnHeightY;
|
|
}
|
|
|
|
public bool ShouldObjectsDestroyAtRespawnHeight()
|
|
{
|
|
if (!HasSceneDescriptor())
|
|
{
|
|
throw new ClientSimException("Cannot get respawn height setting when there is no scene descriptor.");
|
|
}
|
|
|
|
return _descriptor.ObjectBehaviourAtRespawnHeight == VRC_SceneDescriptor.RespawnHeightBehaviour.Destroy;
|
|
}
|
|
|
|
public void ResetSpawnOrder()
|
|
{
|
|
_spawnOrder = 0;
|
|
}
|
|
|
|
public Transform GetSpawnPoint(bool remote = false)
|
|
{
|
|
if (!HasSceneDescriptor())
|
|
{
|
|
throw new ClientSimException("Trying to get a Spawn Point but there is no Scene Descriptor. Add a SceneDescriptor or the VRCWorldPrefab to your scene.");
|
|
}
|
|
|
|
if (_descriptor.spawns.Length == 0 || _descriptor.spawns[0] == null)
|
|
{
|
|
throw new ClientSimException("Trying to get a Spawn Point but the Scene Descriptor doesn't have one. Add a Transform to the 'Spawns' array in the VRC Scene Descriptor component.");
|
|
}
|
|
|
|
// Remote players always restart the list, so for now, only first spawn
|
|
if (_descriptor.spawnOrder == VRC_SceneDescriptor.SpawnOrder.First ||
|
|
_descriptor.spawnOrder == VRC_SceneDescriptor.SpawnOrder.Demo ||
|
|
remote)
|
|
{
|
|
return _descriptor.spawns[0];
|
|
}
|
|
if (_descriptor.spawnOrder == VRC_SceneDescriptor.SpawnOrder.Random)
|
|
{
|
|
int spawn = Random.Range(0, _descriptor.spawns.Length);
|
|
return _descriptor.spawns[spawn];
|
|
}
|
|
if (_descriptor.spawnOrder == VRC_SceneDescriptor.SpawnOrder.Sequential)
|
|
{
|
|
Transform spawn = _descriptor.spawns[_spawnOrder];
|
|
_spawnOrder = (_spawnOrder + 1) % _descriptor.spawns.Length;
|
|
return spawn;
|
|
}
|
|
|
|
// Fallback to first spawn point
|
|
return _descriptor.spawns[0];
|
|
}
|
|
|
|
public Transform GetSpawnPoint(int index)
|
|
{
|
|
if (!HasSceneDescriptor())
|
|
{
|
|
throw new ClientSimException("Cannot get spawn point when there is no scene descriptor.");
|
|
}
|
|
|
|
if (index < 0 || index >= _descriptor.spawns.Length || _descriptor.spawns[index] == null)
|
|
{
|
|
this.LogWarning($"Using spawn point 0 instead of {index}, which is invalid.");
|
|
index = 0;
|
|
}
|
|
|
|
// Fallback to first spawn point
|
|
return _descriptor.spawns[index];
|
|
}
|
|
|
|
public float GetSpawnRadius()
|
|
{
|
|
if (!HasSceneDescriptor())
|
|
{
|
|
throw new ClientSimException("Cannot get spawn radius when there is no scene descriptor.");
|
|
}
|
|
|
|
return _descriptor.spawnRadius;
|
|
}
|
|
|
|
private void CopyCameraValues(Camera refCamera, Camera camera)
|
|
{
|
|
if (refCamera == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
camera.farClipPlane = refCamera.farClipPlane;
|
|
camera.nearClipPlane = Mathf.Clamp(refCamera.nearClipPlane, 0.01f, 0.05f);
|
|
camera.clearFlags = refCamera.clearFlags;
|
|
camera.backgroundColor = refCamera.backgroundColor;
|
|
camera.allowHDR = refCamera.allowHDR;
|
|
|
|
PostProcessLayer refPostProcessLayer = refCamera.GetComponent<PostProcessLayer>();
|
|
if (refPostProcessLayer != null)
|
|
{
|
|
if (_isAndroid)
|
|
{
|
|
Debug.LogWarning("Post processing is not supported on Android");
|
|
}
|
|
else
|
|
{
|
|
// VRChatBug: VRChat ignores if the PostProcessingLayer is disabled on the reference camera and always
|
|
// enables it for the player's camera.
|
|
PostProcessLayer postProcessLayer = camera.gameObject.AddComponent<PostProcessLayer>();
|
|
postProcessLayer.volumeLayer = refPostProcessLayer.volumeLayer;
|
|
|
|
postProcessLayer.volumeTrigger = refPostProcessLayer.volumeTrigger != refPostProcessLayer.transform
|
|
? refPostProcessLayer.volumeTrigger
|
|
: camera.transform;
|
|
|
|
// Use reflection to copy over resources : https://github.com/Unity-Technologies/PostProcessing/issues/467
|
|
FieldInfo resourcesInfo = typeof(PostProcessLayer).GetField("m_Resources", BindingFlags.NonPublic | BindingFlags.Instance);
|
|
PostProcessResources postProcessResources = resourcesInfo.GetValue(refPostProcessLayer) as PostProcessResources;
|
|
postProcessLayer.Init(postProcessResources);
|
|
}
|
|
}
|
|
refCamera.gameObject.SetActive(false);
|
|
}
|
|
}
|
|
} |