#if UNITY_EDITOR /******************************************************************************* The content of this file includes portions of the proprietary AUDIOKINETIC Wwise Technology released in source code form as part of the game integration package. The content of this file may not be used without valid licenses to the AUDIOKINETIC Wwise Technology. Note that the use of the game engine is subject to the Unity(R) Terms of Service at https://unity3d.com/legal/terms-of-service License Usage Licensees holding valid licenses to the AUDIOKINETIC Wwise Technology may use this file in accordance with the end user license agreement provided with the software or, alternatively, in accordance with the terms contained in a written agreement between you and Audiokinetic Inc. Copyright (c) 2025 Audiokinetic Inc. *******************************************************************************/ using UnityEngine; [UnityEditor.InitializeOnLoad] public class AkPortalManager { private static AkPortalManager s_portalManager; public System.Collections.Generic.List EnvironmentList = new System.Collections.Generic.List(); public System.Collections.Generic.Dictionary>[] IntersectingEnvironments = { //All environments on the negative side of each portal(opposite to the direction of the chosen axis) new System.Collections.Generic.Dictionary>(), //All environments on the positive side of each portal(same direction as the chosen axis) new System.Collections.Generic.Dictionary>() }; private float m_timeStamp = UnityEngine.Time.realtimeSinceStartup; public System.Collections.Generic.List PortalList = new System.Collections.Generic.List(); static AkPortalManager() { if (UnityEditor.AssetDatabase.IsAssetImportWorkerProcess()) { return; } //This constructor is called before any game object is created when there is a compilation which makes the 'FindObjectsOfType' function return null. //So we register the init function to be called at hte first update. UnityEditor.EditorApplication.update += Init; } public static void Init() { //Do nothing if Manager exists if (s_portalManager == null) { s_portalManager = new AkPortalManager(); s_portalManager.Populate(); //Register the update function to be called at each frame UnityEditor.EditorApplication.update += s_portalManager.UpdateEnvironments; } //Unregister in case we were registered UnityEditor.EditorApplication.update -= Init; } public static AkPortalManager GetManager() { return s_portalManager; } public void Populate() { //Add all environments in the scene to the environment list #if UNITY_6000_0_OR_NEWER var akEnv = Object.FindObjectsByType(FindObjectsSortMode.None); #else var akEnv = Object.FindObjectsOfType(); #endif s_portalManager.EnvironmentList.Clear(); s_portalManager.EnvironmentList.AddRange(akEnv); //Add all portals in the scene to the portal list #if UNITY_6000_0_OR_NEWER var akPortals = Object.FindObjectsByType(FindObjectsSortMode.None); #else var akPortals = Object.FindObjectsOfType(); #endif s_portalManager.PortalList.Clear(); s_portalManager.PortalList.AddRange(akPortals); //check for portal-environment intersections and populate the IntersectingEnvironments dictionary for (var i = 0; i < s_portalManager.PortalList.Count; i++) s_portalManager.UpdatePortal(s_portalManager.PortalList[i]); } public void UpdatePortal(AkEnvironmentPortal in_portal) { var envList = new System.Collections.Generic.List[2]; for (var i = 0; i < 2; i++) { if (!IntersectingEnvironments[i].TryGetValue(in_portal.GetInstanceID(), out envList[i])) { envList[i] = new System.Collections.Generic.List(); IntersectingEnvironments[i][in_portal.GetInstanceID()] = envList[i]; } else envList[i].Clear(); } //We check if a portal intersects any environment //Iterate in reverse order for safe removal form list while iterating for (var i = EnvironmentList.Count - 1; i >= 0; i--) { if (EnvironmentList[i] != null) { //if there is an intersection if (in_portal.GetComponent().bounds .Intersects(EnvironmentList[i].GetComponent().bounds)) { if (UnityEngine.Vector3.Dot(in_portal.transform.rotation * in_portal.axis, EnvironmentList[i].transform.position - in_portal.transform.position) >= 0) envList[1].Add(EnvironmentList[i]); else envList[0].Add(EnvironmentList[i]); } } else EnvironmentList.RemoveAt(i); } } private void UpdateEnvironment(AkEnvironment in_env) { for (var i = PortalList.Count - 1; i >= 0; i--) //Iterate in reverse order for safe removal form list while iterating { if (PortalList[i] != null) { if (in_env.GetComponent().bounds .Intersects(PortalList[i].GetComponent().bounds)) { System.Collections.Generic.List envList = null; //Get index of the list that should contain this environment //Index = 0 means that the enviroment is on the negative side of the portal (opposite to the direction of the chosen axis) //Index = 1 means that the enviroment is on the positive side of the portal (same direction as the chosen axis) var index = UnityEngine.Vector3.Dot(PortalList[i].transform.rotation * PortalList[i].axis, in_env.transform.position - PortalList[i].transform.position) >= 0 ? 1 : 0; if (!IntersectingEnvironments[index].TryGetValue(PortalList[i].GetInstanceID(), out envList)) { envList = new System.Collections.Generic.List(); envList.Add(in_env); IntersectingEnvironments[index][PortalList[i].GetInstanceID()] = envList; } else if (!envList.Contains(in_env)) envList.Add(in_env); } } else PortalList.RemoveAt(i); } } public void UpdateEnvironments() { //Timer is reset when starting play mode and when coming back to editor mode if (UnityEngine.Time.realtimeSinceStartup < m_timeStamp) { m_timeStamp = UnityEngine.Time.realtimeSinceStartup; //The PortalManager object doesn't get destroyed but all game objects in our lists become null //So we populate Populate(); return; } //The update is done once every second if (UnityEngine.Time.realtimeSinceStartup - m_timeStamp < 1.0f) return; m_timeStamp = UnityEngine.Time.realtimeSinceStartup; var portals = UnityEditor.Selection.GetFiltered(typeof(AkEnvironmentPortal), UnityEditor.SelectionMode.Unfiltered); if (portals != null) { for (var i = 0; i < portals.Length; i++) { if (!PortalList.Contains((AkEnvironmentPortal) portals[i])) PortalList.Add((AkEnvironmentPortal) portals[i]); UpdatePortal((AkEnvironmentPortal) portals[i]); } } var envs = UnityEditor.Selection.GetFiltered(typeof(AkEnvironment), UnityEditor.SelectionMode.Unfiltered); if (envs != null) { for (var i = 0; i < envs.Length; i++) { if (!EnvironmentList.Contains((AkEnvironment) envs[i])) EnvironmentList.Add((AkEnvironment) envs[i]); UpdateEnvironment((AkEnvironment) envs[i]); } } } } #endif