public static void RemoveCameras(GameObject currentAvatar, bool localPlayer, bool friend) { if (!localPlayer && currentAvatar != null) { foreach (Camera camera in currentAvatar.GetComponentsInChildren <Camera>(true)) { if (camera == null || camera.gameObject == null) { continue; } Debug.LogWarning("Removing camera from " + camera.gameObject.name); if (friend && camera.targetTexture != null) { camera.enabled = false; } else { camera.enabled = false; if (camera.targetTexture != null) { camera.targetTexture = new RenderTexture(16, 16, 24); } ValidationUtils.RemoveComponent(camera); } } } }
public static void RemoveExtraAnimationComponents(GameObject currentAvatar) { if (currentAvatar == null) { return; } // remove Animator comps { Animator mainAnimator = currentAvatar.GetComponent <Animator>(); bool removeMainAnimator = false; if (mainAnimator != null) { if (!mainAnimator.isHuman || mainAnimator.avatar == null || !mainAnimator.avatar.isValid) { removeMainAnimator = true; } } foreach (Animator anim in currentAvatar.GetComponentsInChildren <Animator>(true)) { if (anim == null || anim.gameObject == null) { continue; } // exclude the main avatar animator if (anim == mainAnimator) { if (!removeMainAnimator) { continue; } } Debug.LogWarning("Removing Animator comp from " + anim.gameObject.name); anim.enabled = false; ValidationUtils.RemoveComponent(anim); } } ValidationUtils.RemoveComponentsOfType <Animation>(currentAvatar); }
public static Dictionary <ParticleSystem, int> EnforceParticleSystemLimits(GameObject currentAvatar) { Dictionary <ParticleSystem, int> particleSystems = new Dictionary <ParticleSystem, int>(); foreach (ParticleSystem ps in currentAvatar.transform.GetComponentsInChildren <ParticleSystem>(true)) { int realtime_max = ps_max_particles; // always limit collision force var collision = ps.collision; if (collision.colliderForce > ps_max_particle_force) { collision.colliderForce = ps_max_particle_force; Debug.LogError("Collision force is restricted on avatars, particle system named " + ps.gameObject.name + " collision force restricted to " + ps_max_particle_force); } if (ps_limiter_enabled) { if (particleSystems.Count > ps_max_systems) { Debug.LogError("Too many particle systems, #" + particleSystems.Count + " named " + ps.gameObject.name + " deleted"); ValidationUtils.RemoveComponent(ps); continue; } else { var main = ps.main; var emission = ps.emission; ParticleSystemRenderer renderer = ps.GetComponent <ParticleSystemRenderer>(); if (renderer != null) { if (renderer.renderMode == ParticleSystemRenderMode.Mesh) { Mesh[] meshes = new Mesh[0]; int highestPoly = 0; renderer.GetMeshes(meshes); if (meshes.Length == 0 && renderer.mesh != null) { meshes = new Mesh[] { renderer.mesh }; } // Debug.Log(meshes.Length + " meshes possible emmited meshes from " + ps.gameObject.name); foreach (Mesh m in meshes) { if (m.isReadable) { if (m.triangles.Length / 3 > highestPoly) { highestPoly = m.triangles.Length / 3; } } else { if (1000 > highestPoly) { highestPoly = int.MaxValue; } } } if (highestPoly > 0) { highestPoly = Mathf.Clamp(highestPoly / ps_mesh_particle_divider, 1, highestPoly); realtime_max = Mathf.FloorToInt((float)realtime_max / highestPoly); if (highestPoly > ps_mesh_particle_poly_limit) { Debug.LogError("Particle system named " + ps.gameObject.name + " breached polygon limits, it has been deleted"); ValidationUtils.RemoveComponent(ps); continue; } } } } ParticleSystem.MinMaxCurve rate = emission.rateOverTime; if (rate.mode == ParticleSystemCurveMode.Constant) { rate.constant = Mathf.Clamp(rate.constant, 0, ps_max_emission); } else if (rate.mode == ParticleSystemCurveMode.TwoConstants) { rate.constantMax = Mathf.Clamp(rate.constantMax, 0, ps_max_emission); } else { rate.curveMultiplier = Mathf.Clamp(rate.curveMultiplier, 0, ps_max_emission); } emission.rateOverTime = rate; rate = emission.rateOverDistance; if (rate.mode == ParticleSystemCurveMode.Constant) { rate.constant = Mathf.Clamp(rate.constant, 0, ps_max_emission); } else if (rate.mode == ParticleSystemCurveMode.TwoConstants) { rate.constantMax = Mathf.Clamp(rate.constantMax, 0, ps_max_emission); } else { rate.curveMultiplier = Mathf.Clamp(rate.curveMultiplier, 0, ps_max_emission); } emission.rateOverDistance = rate; //Disable collision with PlayerLocal layer collision.collidesWith &= ~(1 << 10); } } particleSystems.Add(ps, realtime_max); } EnforceRealtimeParticleSystemLimits(particleSystems, true, false); return(particleSystems); }
public static IEnumerator EnforceAvatarStationLimitsEnumerator(GameObject currentAvatar, System.Action <VRC_Station> onFound) { Queue <GameObject> children = new Queue <GameObject>(); children.Enqueue(currentAvatar.gameObject); int stationCount = 0; uint objectsProcessedThisFrame = 0; while (children.Count > 0) { if (Time.frameCount > _enforceAvatarStationsFrameNumber) { _enforceAvatarStationsFrameNumber = Time.frameCount; _enforceAvatarStationsProcessedThisFrame = 0; } if (_enforceAvatarStationsProcessedThisFrame > ENFORCE_STATIONS_GAMEOBJECTS_PER_FRAME) { yield return(null); } Profiler.BeginSample("EnforceAvatarStationLimitsEnumerator"); _enforceAvatarStationsProcessedThisFrame++; GameObject child = children.Dequeue(); if (child == null) { Profiler.EndSample(); continue; } int childCount = child.transform.childCount; for (int idx = 0; idx < childCount; ++idx) { children.Enqueue(child.transform.GetChild(idx).gameObject); } VRC_Station[] stations = child.transform.GetComponents <VRC_Station>(); if (stations != null && stations.Length > 0) { foreach (VRC_Station station in stations) { if (station == null) { Profiler.EndSample(); continue; } #if VRC_CLIENT VRC_StationInternal stationInternal = station.transform.GetComponent <VRC_StationInternal>(); #endif if (stationCount < MAX_STATIONS_PER_AVATAR) { bool markedForDestruction = false; // keep this station, but limit it if (station.disableStationExit) { Debug.LogError("[" + currentAvatar.name + "]==> Stations on avatars cannot disable station exit. Re-enabled."); station.disableStationExit = false; } if (station.stationEnterPlayerLocation != null) { if (Vector3.Distance(station.stationEnterPlayerLocation.position, station.transform.position) > MAX_STATION_LOCATION_DISTANCE) { #if VRC_CLIENT markedForDestruction = true; Debug.LogError("[" + currentAvatar.name + "]==> Station enter location is too far from station (max dist=" + MAX_STATION_LOCATION_DISTANCE + "). Station disabled."); #else Debug.LogError("Station enter location is too far from station (max dist=" + MAX_STATION_LOCATION_DISTANCE + "). Station will be disabled at runtime."); #endif } if (Vector3.Distance(station.stationExitPlayerLocation.position, station.transform.position) > MAX_STATION_LOCATION_DISTANCE) { #if VRC_CLIENT markedForDestruction = true; Debug.LogError("[" + currentAvatar.name + "]==> Station exit location is too far from station (max dist=" + MAX_STATION_LOCATION_DISTANCE + "). Station disabled."); #else Debug.LogError("Station exit location is too far from station (max dist=" + MAX_STATION_LOCATION_DISTANCE + "). Station will be disabled at runtime."); #endif } if (markedForDestruction) { #if VRC_CLIENT ValidationUtils.RemoveComponent(station); if (stationInternal != null) { ValidationUtils.RemoveComponent(stationInternal); } #endif } else { if (onFound != null) { onFound(station); } } } } else { #if VRC_CLIENT Debug.LogError("[" + currentAvatar.name + "]==> Removing station over limit of " + MAX_STATIONS_PER_AVATAR); ValidationUtils.RemoveComponent(station); if (stationInternal != null) { ValidationUtils.RemoveComponent(stationInternal); } #else Debug.LogError("Too many stations on avatar(" + currentAvatar.name + "). Maximum allowed=" + MAX_STATIONS_PER_AVATAR + ". Extra stations will be removed at runtime."); #endif } stationCount++; } } Profiler.EndSample(); if (objectsProcessedThisFrame < ENFORCE_STATIONS_GAMEOBJECTS_PER_FRAME) { continue; } objectsProcessedThisFrame = 0; yield return(null); } }
public static IEnumerator EnforceAudioSourceLimitsEnumerator(GameObject currentAvatar, System.Action <AudioSource> onFound) { if (currentAvatar == null) { yield break; } Queue <GameObject> children = new Queue <GameObject>(); if (currentAvatar != null) { children.Enqueue(currentAvatar.gameObject); } while (children.Count > 0) { if (Time.frameCount > _enforceAudioSourcesFrameNumber) { _enforceAudioSourcesFrameNumber = Time.frameCount; _enforceAudioSourcesProcessedThisFrame = 0; } if (_enforceAudioSourcesProcessedThisFrame > ENFORCE_AUDIO_SOURCE_GAMEOBJECTS_PER_FRAME) { yield return(null); } Profiler.BeginSample("EnforceAudioSourceLimitsEnumerator"); _enforceAudioSourcesProcessedThisFrame++; GameObject child = children.Dequeue(); if (child == null) { Profiler.EndSample(); continue; } int childCount = child.transform.childCount; for (int idx = 0; idx < childCount; ++idx) { children.Enqueue(child.transform.GetChild(idx).gameObject); } #if VRC_CLIENT if (child.GetComponent <USpeaker>() != null) { Profiler.EndSample(); continue; } #endif AudioSource[] sources = child.transform.GetComponents <AudioSource>(); if (sources != null && sources.Length > 0) { AudioSource audioSource = sources[0]; if (audioSource == null) { Profiler.EndSample(); continue; } VRC_SpatialAudioSource vrcSpatialAudioSource = audioSource.gameObject.GetComponent <VRC_SpatialAudioSource>(); #if VRC_CLIENT audioSource.outputAudioMixerGroup = VRCAudioManager.GetAvatarGroup(); audioSource.priority = Mathf.Clamp(audioSource.priority, 200, 255); if (vrcSpatialAudioSource != null) { // copy the values into the onsp component var onspAudioSource = audioSource.gameObject.GetOrAddComponent <ONSPAudioSource>(); onspAudioSource.Gain = vrcSpatialAudioSource.Gain; onspAudioSource.Near = vrcSpatialAudioSource.Near; onspAudioSource.Far = vrcSpatialAudioSource.Far; onspAudioSource.VolumetricRadius = vrcSpatialAudioSource.VolumetricRadius; onspAudioSource.EnableSpatialization = vrcSpatialAudioSource.EnableSpatialization; onspAudioSource.UseInvSqr = !vrcSpatialAudioSource.UseAudioSourceVolumeCurve; if (!vrcSpatialAudioSource.EnableSpatialization) { audioSource.spatialize = false; } } #else // these are SDK only, we rely on AvatarAudioSourceLimiter to enforce // values at runtime #if SUPPORT_DEPRECATED_ONSP ONSPAudioSource[] allOnsp = audioSource.gameObject.GetComponents <ONSPAudioSource>(); if (allOnsp != null && allOnsp.Length > 0) { ONSPAudioSource onsp = allOnsp[0]; if (vrcSpatialAudioSource == null) { vrcSpatialAudioSource = audioSource.gameObject.AddComponent <VRC_SpatialAudioSource>(); } vrcSpatialAudioSource.Gain = Mathf.Min(onsp.Gain, VRCSDK2.AudioManagerSettings.AvatarAudioMaxGain); vrcSpatialAudioSource.Far = Mathf.Min(onsp.Far, VRCSDK2.AudioManagerSettings.AvatarAudioMaxRange); vrcSpatialAudioSource.VolumetricRadius = Mathf.Min(onsp.Far, VRCSDK2.AudioManagerSettings.AvatarAudioMaxRange); vrcSpatialAudioSource.Near = Mathf.Min(onsp.Near, onsp.Far); vrcSpatialAudioSource.EnableSpatialization = onsp.EnableSpatialization; vrcSpatialAudioSource.UseAudioSourceVolumeCurve = !onsp.UseInvSqr; Debug.LogWarningFormat("ONSPAudioSource found on {0}. converted to VRC_SpatialAudioSource.", child.name); foreach (var o in allOnsp) { Object.DestroyImmediate(o, true); } } #endif if (vrcSpatialAudioSource == null) { // user has not yet added VRC_SpatialAudioSource (or ONSP) // so set up some defaults vrcSpatialAudioSource = audioSource.gameObject.AddComponent <VRC_SpatialAudioSource>(); vrcSpatialAudioSource.Gain = AudioManagerSettings.AvatarAudioMaxGain; vrcSpatialAudioSource.Far = AudioManagerSettings.AvatarAudioMaxRange; vrcSpatialAudioSource.Near = 0f; vrcSpatialAudioSource.VolumetricRadius = 0f; vrcSpatialAudioSource.EnableSpatialization = true; vrcSpatialAudioSource.enabled = true; audioSource.spatialize = true; audioSource.priority = Mathf.Clamp(audioSource.priority, 200, 255); audioSource.bypassEffects = false; audioSource.bypassListenerEffects = false; audioSource.spatialBlend = 1f; audioSource.spread = 0; // user is allowed to change, but for now put a safe default audioSource.maxDistance = AudioManagerSettings.AvatarAudioMaxRange; audioSource.minDistance = audioSource.maxDistance / 500f; audioSource.rolloffMode = AudioRolloffMode.Logarithmic; } #endif //!VRC_CLIENT onFound(audioSource); if (sources.Length > 1) { Debug.LogError("Disabling extra AudioSources on GameObject(" + child.name + "). Only one is allowed per GameObject."); for (int i = 1; i < sources.Length; i++) { if (sources[i] == null) { Profiler.EndSample(); continue; } #if VRC_CLIENT sources[i].enabled = false; sources[i].clip = null; #else ValidationUtils.RemoveComponent(sources[i]); #endif //!VRC_CLIENT } } } Profiler.EndSample(); } }
private static IEnumerator EnforceAudioSourceLimitsEnumerator(GameObject currentAvatar, System.Action <AudioSource> onFound) { if (currentAvatar == null) { yield break; } Queue <GameObject> children = new Queue <GameObject>(); if (currentAvatar != null) { children.Enqueue(currentAvatar.gameObject); } while (children.Count > 0) { if (Time.frameCount > _enforceAudioSourcesFrameNumber) { _enforceAudioSourcesFrameNumber = Time.frameCount; _enforceAudioSourcesProcessedThisFrame = 0; } if (_enforceAudioSourcesProcessedThisFrame > ENFORCE_AUDIO_SOURCE_GAMEOBJECTS_PER_FRAME) { yield return(null); } Profiler.BeginSample("EnforceAudioSourceLimitsEnumerator"); _enforceAudioSourcesProcessedThisFrame++; GameObject child = children.Dequeue(); if (child == null) { Profiler.EndSample(); continue; } int childCount = child.transform.childCount; for (int idx = 0; idx < childCount; ++idx) { children.Enqueue(child.transform.GetChild(idx).gameObject); } #if VRC_CLIENT if (child.GetComponent <USpeaker>() != null) { Profiler.EndSample(); continue; } #endif AudioSource[] sources = child.transform.GetComponents <AudioSource>(); if (sources != null && sources.Length > 0) { AudioSource audioSource = sources[0]; if (audioSource == null) { Profiler.EndSample(); continue; } #if VRC_CLIENT audioSource.outputAudioMixerGroup = VRCAudioManager.GetAvatarGroup(); audioSource.priority = Mathf.Clamp(audioSource.priority, 200, 255); #else ProcessSpatialAudioSources(audioSource); #endif //!VRC_CLIENT onFound(audioSource); if (sources.Length > 1) { Debug.LogError("Disabling extra AudioSources on GameObject(" + child.name + "). Only one is allowed per GameObject."); for (int i = 1; i < sources.Length; i++) { if (sources[i] == null) { Profiler.EndSample(); continue; } #if VRC_CLIENT sources[i].enabled = false; sources[i].clip = null; #else ValidationUtils.RemoveComponent(sources[i]); #endif //!VRC_CLIENT } } } Profiler.EndSample(); } }
public static void EnforceAvatarStationLimits(GameObject currentAvatar) { using (_enforceAvatarStationLimitsProfilerMarker.Auto()) { int stationCount = 0; foreach (VRC.SDKBase.VRCStation station in currentAvatar.gameObject.GetComponentsInChildren <VRC.SDKBase.VRCStation>(true)) { if (station == null) { continue; } #if VRC_CLIENT VRC_StationInternal stationInternal = station.transform.GetComponent <VRC_StationInternal>(); #endif if (stationCount < MAX_STATIONS_PER_AVATAR) { #if VRC_CLIENT bool markedForDestruction = false; #endif // keep this station, but limit it if (station.disableStationExit) { Debug.LogError("[" + currentAvatar.name + "]==> Stations on avatars cannot disable station exit. Re-enabled."); station.disableStationExit = false; } if (station.stationEnterPlayerLocation != null) { if (Vector3.Distance(station.stationEnterPlayerLocation.position, station.transform.position) > MAX_STATION_LOCATION_DISTANCE) { #if VRC_CLIENT markedForDestruction = true; Debug.LogError( "[" + currentAvatar.name + "]==> Station enter location is too far from station (max dist=" + MAX_STATION_LOCATION_DISTANCE + "). Station disabled."); #else Debug.LogError("Station enter location is too far from station (max dist=" + MAX_STATION_LOCATION_DISTANCE + "). Station will be disabled at runtime."); #endif } if (Vector3.Distance(station.stationExitPlayerLocation.position, station.transform.position) > MAX_STATION_LOCATION_DISTANCE) { #if VRC_CLIENT markedForDestruction = true; Debug.LogError( "[" + currentAvatar.name + "]==> Station exit location is too far from station (max dist=" + MAX_STATION_LOCATION_DISTANCE + "). Station disabled."); #else Debug.LogError("Station exit location is too far from station (max dist=" + MAX_STATION_LOCATION_DISTANCE + "). Station will be disabled at runtime."); #endif } #if VRC_CLIENT if (markedForDestruction) { ValidationUtils.RemoveComponent(station); if (stationInternal != null) { ValidationUtils.RemoveComponent(stationInternal); } } #endif } } else { #if VRC_CLIENT Debug.LogError("[" + currentAvatar.name + "]==> Removing station over limit of " + MAX_STATIONS_PER_AVATAR); ValidationUtils.RemoveComponent(station); if (stationInternal != null) { ValidationUtils.RemoveComponent(stationInternal); } #else Debug.LogError("Too many stations on avatar(" + currentAvatar.name + "). Maximum allowed=" + MAX_STATIONS_PER_AVATAR + ". Extra stations will be removed at runtime."); #endif } stationCount++; } } }
public static void EnforceAudioSourceLimits(GameObject currentAvatar) { using (_enforceAudioSourceLimitsProfilerMarker.Auto()) { if (currentAvatar == null) { return; } Queue <GameObject> children = new Queue <GameObject>(); if (currentAvatar != null) { children.Enqueue(currentAvatar.gameObject); } while (children.Count > 0) { GameObject child = children.Dequeue(); if (child == null) { continue; } int childCount = child.transform.childCount; for (int idx = 0; idx < childCount; ++idx) { children.Enqueue(child.transform.GetChild(idx).gameObject); } #if VRC_CLIENT if (child.GetComponent <USpeaker>() != null) { continue; } #endif AudioSource[] sources = child.transform.GetComponents <AudioSource>(); if (sources == null || sources.Length <= 0) { continue; } AudioSource audioSource = sources[0]; if (audioSource == null) { continue; } #if VRC_CLIENT audioSource.outputAudioMixerGroup = VRCAudioManager.GetAvatarGroup(); audioSource.priority = Mathf.Clamp(audioSource.priority, 200, 255); #else ProcessSpatialAudioSources(audioSource); #endif //!VRC_CLIENT if (sources.Length <= 1) { continue; } Debug.LogError("Disabling extra AudioSources on GameObject(" + child.name + "). Only one is allowed per GameObject."); for (int i = 1; i < sources.Length; i++) { if (sources[i] == null) { Profiler.EndSample(); continue; } #if VRC_CLIENT sources[i].enabled = false; sources[i].clip = null; #else ValidationUtils.RemoveComponent(sources[i]); #endif //!VRC_CLIENT } } } }