using System.Collections.Generic; using System; using System.Linq; using UnityEngine; using DistantLands.Cozy.Data; #if LINK_NETCODE using Unity.Netcode; #endif #if LINK_PUN using Photon.Pun; using Photon.Realtime; #endif #if LINK_FISHNET using FishNet.Object; #endif #if LINK_MIRROR #endif #if LINK_PURRNET #endif #if UNITY_EDITOR using UnityEditor; #endif namespace DistantLands.Cozy { #if LINK_NETCODE [RequireComponent(typeof(NetcodeView))] [RequireComponent(typeof(NetworkObject))] #endif #if LINK_PUN [RequireComponent(typeof(PhotonView))] #endif // #if LINK_FISHNET // [RequireComponent(typeof(FishnetView))] // [RequireComponent(typeof(NetworkObject))] // #endif #if LINK_PURRNET [RequireComponent(typeof(PurrNetView))] #endif #if LINK_MIRROR #endif [ExecuteAlways] public class LinkModule : CozyModule { static readonly string[] Integrations = new string[6] { "None", "Netcode for Gameobjects", "PUN", "Mirror", "FishNetworking", "PurrNet" }; public static string SelectedIntegrationName => Integrations[SelectedIntegration]; public static int SelectedIntegration { get { #if LINK_NETCODE return 1; #elif LINK_PUN return 2; #elif LINK_MIRROR return 3; #elif LINK_FISHNET return 4; #elif LINK_PURRNET return 5; #else return 0; #endif } } public bool linkTime = true; public bool linkWeather = true; public bool linkAmbience = true; [Tooltip("Controls the amount of time (in seconds) before an RPC is sent to the server to sync the COZY systems.")] [Range(0, 6)] public float updateDelay = 0.5f; [Tooltip("Controls the amount of ticks away from the main server a client has to be before resyncing with the server. (Default: 0.05)")] [Range(0, 0.5f)] public float timeSettingSensitivity = 0.05f; float currentDelay; public Dictionary weatherHashes = new Dictionary(); public Dictionary ambienceHashes = new Dictionary(); public CozyAmbienceModule ambienceManager; #if LINK_NETCODE public bool isMaster { get { return netcodeView.NetworkManager.IsServer || netcodeView.NetworkManager.IsHost; } } //VARIABLES______________________________________________________________________________________________________ private NetcodeView nvCache; //FUNCTIONS_______________________________________________________________________________________________________ public void Update() { if (!Application.isPlaying) return; if (currentDelay <= 0) { if (isMaster) MasterCommunication(); else ClientCommunication(); currentDelay = updateDelay; } else currentDelay -= Time.deltaTime; } public NetcodeView netcodeView { get { if (nvCache) { return nvCache; } else { nvCache = GetComponent(); return nvCache; } } } public void SyncCozyTime() { if (Mathf.Abs(netcodeView.ticks.Value - weatherSphere.timeModule.currentTime) > timeSettingSensitivity) weatherSphere.timeModule.currentTime = netcodeView.ticks.Value; weatherSphere.timeModule.currentDay = netcodeView.day.Value; weatherSphere.timeModule.currentYear = netcodeView.year.Value; } public void SyncCozyAmbience() { ambienceManager.currentAmbienceProfile = ambienceManager.ambienceProfiles[netcodeView.ambience.Value]; } public void SyncCozyWeather() { List i = new List(); int l = 0; foreach (int j in netcodeView.weatherCache) { WeatherRelation k = new WeatherRelation(); k.profile = weatherSphere.weatherModule.ecosystem.forecastProfile.profilesToForecast[j]; k.weight = netcodeView.weatherValues[l]; i.Add(k); l++; } weatherSphere.weatherModule.ecosystem.weightedWeatherProfiles = i; } public void SyncCozyTimeMaster() { netcodeView.ticks.Value = weatherSphere.timeModule.currentTime; netcodeView.day.Value = weatherSphere.timeModule.currentDay; netcodeView.year.Value = weatherSphere.timeModule.currentYear; } public void SyncCozyAmbienceMaster() { netcodeView.ambience.Value = ambienceHashes[ambienceManager.currentAmbienceProfile]; } public void SyncCozyWeatherMaster() { netcodeView.weatherCache.Clear(); foreach (int i in GetWeatherIDs()) netcodeView.weatherCache.Add(i); netcodeView.weatherValues.Clear(); foreach (float i in GetWeatherIntensities()) netcodeView.weatherValues.Add(i); } private void MasterCommunication() { if (linkTime) SyncCozyTimeMaster(); if (linkAmbience) SyncCozyAmbienceMaster(); if (linkWeather) SyncCozyWeatherMaster(); } private void ClientCommunication() { if (linkTime) SyncCozyTime(); if (linkAmbience) SyncCozyAmbience(); if (linkWeather) SyncCozyWeather(); } public override void InitializeModule() { if (!Application.isPlaying) return; base.InitializeModule(); for (int i = 0; i < weatherSphere.weatherModule.ecosystem.forecastProfile.profilesToForecast.Count; i++) { weatherHashes.Add(weatherSphere.weatherModule.ecosystem.forecastProfile.profilesToForecast[i], i); } if (linkAmbience) { if (weatherSphere.GetModule() == null) { linkAmbience = false; } else { ambienceManager = weatherSphere.GetModule(); for (int i = 0; i < ambienceManager.ambienceProfiles.Length; i++) { ambienceHashes.Add(ambienceManager.ambienceProfiles[i], i); } } } } #endif #if LINK_PUN public bool isMaster => PhotonNetwork.IsConnected && PhotonNetwork.IsMasterClient; public enum LinkType { server, client } public LinkType linkType; private float m_Ticks; //VARIABLES______________________________________________________________________________________________________ private PhotonView pvCache; //FUNCTIONS_______________________________________________________________________________________________________ public void Update() { if (!Application.isPlaying) return; if (isMaster) { if (currentDelay <= 0) { MasterSendRPC(); currentDelay = updateDelay; } else currentDelay -= Time.deltaTime; } } public PhotonView photonView { get { if (pvCache) { return pvCache; } else { pvCache = GetComponent(); return pvCache; } } } [PunRPC] public void SyncCozyTime(float currentTicks, int currentDay, int currentYear) { if (Mathf.Abs(currentTicks - weatherSphere.timeModule.currentTime) > timeSettingSensitivity) weatherSphere.timeModule.currentTime = currentTicks; weatherSphere.timeModule.currentYear = currentYear; weatherSphere.timeModule.currentDay = currentDay; } [PunRPC] public void SyncCozyAmbience(int ambience) { ambienceManager.currentAmbienceProfile = ambienceManager.ambienceProfiles[ambience]; } [PunRPC] public void SyncCozyWeather(int[] cache, float[] values) { List i = new List(); int l = 0; foreach (int j in cache) { WeatherRelation k = new WeatherRelation(); k.profile = weatherSphere.weatherModule.ecosystem.forecastProfile.profilesToForecast[j]; k.weight = values[l]; i.Add(k); l++; } weatherSphere.weatherModule.ecosystem.weightedWeatherProfiles = i; } public int[] GetWeatherIDs() { List i = new List(); foreach (WeatherRelation j in weatherSphere.weatherModule.ecosystem.weightedWeatherProfiles) { i.Add(weatherHashes[j.profile]); } return i.ToArray(); } public float[] GetWeatherIntensities() { List i = new List(); foreach (WeatherRelation j in weatherSphere.weatherModule.ecosystem.weightedWeatherProfiles) { i.Add(j.weight); } return i.ToArray(); } private void MasterSendRPC() { if (linkTime) photonView.RPC(nameof(SyncCozyTime), RpcTarget.Others, (float)weatherSphere.timeModule.currentTime, weatherSphere.timeModule.currentDay, weatherSphere.timeModule.currentYear); if (linkAmbience) photonView.RPC(nameof(SyncCozyAmbience), RpcTarget.Others, ambienceHashes[ambienceManager.currentAmbienceProfile]); if (linkWeather) photonView.RPC(nameof(SyncCozyWeather), RpcTarget.Others, GetWeatherIDs(), GetWeatherIntensities()); } public override void InitializeModule() { if (!Application.isPlaying) return; base.InitializeModule(); weatherHashes.Clear(); for (int i = 0; i < weatherSphere.weatherModule.ecosystem.forecastProfile.profilesToForecast.Count; i++) { weatherHashes.Add(weatherSphere.weatherModule.ecosystem.forecastProfile.profilesToForecast[i], i); } if (linkAmbience) { if (weatherSphere.GetModule() == null) { linkAmbience = false; } else { ambienceManager = weatherSphere.GetModule(); for (int i = 0; i < ambienceManager.ambienceProfiles.Length; i++) { ambienceHashes.Add(ambienceManager.ambienceProfiles[i], i); } } } PhotonNetwork.AddCallbackTarget(this); photonView.AddCallbackTarget(this); } public void OnDisable() { PhotonNetwork.RemoveCallbackTarget(this); photonView.RemoveCallback(this); } #endif #if LINK_MIRROR public bool isMaster { get { return mirrorView.isMaster; } } //VARIABLES______________________________________________________________________________________________________ private MirrorView nvCache; //FUNCTIONS_______________________________________________________________________________________________________ public void Update() { if (!Application.isPlaying) return; if (currentDelay <= 0) { try { if (isMaster) MasterCommunication(); else ClientCommunication(); } catch { } currentDelay = updateDelay; } else currentDelay -= Time.deltaTime; } public MirrorView mirrorView { get { if (nvCache) { return nvCache; } else { nvCache = GetComponentInParent(); if (nvCache == null) { Debug.LogError("Make sure to add the Mirror View component to your weather sphere!"); return null; } return nvCache; } } } public void SyncCozyTime() { if (Mathf.Abs(mirrorView.time - weatherSphere.timeModule.currentTime) > timeSettingSensitivity) weatherSphere.timeModule.currentTime = mirrorView.time; weatherSphere.timeModule.currentDay = mirrorView.day; weatherSphere.timeModule.currentYear = mirrorView.year; } public void SyncCozyAmbience() { ambienceManager.currentAmbienceProfile = ambienceManager.ambienceProfiles[mirrorView.ambience]; } public void SyncCozyWeather() { weatherSphere.weatherModule.ecosystem.weightedWeatherProfiles.Clear(); int l = 0; int[] weatherCache = PollValues(mirrorView.weatherCacheString); foreach (int j in weatherCache) { WeatherRelation k = new WeatherRelation(); k.profile = weatherSphere.weatherModule.ecosystem.forecastProfile.profilesToForecast[j]; k.weight = PollWeightValues(mirrorView.weatherValuesString)[l]; weatherSphere.weatherModule.ecosystem.weightedWeatherProfiles.Add(k); l++; } } public void SyncCozyTimeMaster() { mirrorView.time = weatherSphere.timeModule.currentTime; mirrorView.day = weatherSphere.timeModule.currentDay; mirrorView.year = weatherSphere.timeModule.currentYear; } public void SyncCozyAmbienceMaster() { List ambiences = ambienceManager.ambienceProfiles.ToList(); mirrorView.ambience = ambiences.IndexOf(ambienceManager.currentAmbienceProfile); } public void SyncCozyWeatherMaster() { string weatherIDString = ""; foreach (int i in GetWeatherIDs()) weatherIDString = $"{weatherIDString}{i},"; mirrorView.weatherCacheString = weatherIDString; weatherIDString = ""; foreach (float i in GetWeatherIntensities()) weatherIDString = $"{weatherIDString}{i},"; mirrorView.weatherValuesString = weatherIDString; } private void MasterCommunication() { if (linkTime) SyncCozyTimeMaster(); if (linkAmbience) SyncCozyAmbienceMaster(); if (linkWeather) SyncCozyWeatherMaster(); } private void ClientCommunication() { if (linkTime) SyncCozyTime(); if (linkAmbience) SyncCozyAmbience(); if (linkWeather) SyncCozyWeather(); } public override void InitializeModule() { if (!Application.isPlaying) return; base.InitializeModule(); weatherHashes.Clear(); for (int i = 0; i < weatherSphere.weatherModule.ecosystem.forecastProfile.profilesToForecast.Count; i++) { if (!weatherHashes.ContainsKey(weatherSphere.weatherModule.ecosystem.forecastProfile.profilesToForecast[i])) weatherHashes.Add(weatherSphere.weatherModule.ecosystem.forecastProfile.profilesToForecast[i], i); } if (linkAmbience) { if (weatherSphere.GetModule() == null) { linkAmbience = false; } else { ambienceManager = weatherSphere.GetModule(); } } } #endif #if LINK_PURRNET public bool isMaster { get { return purrNetView.isMaster; } } private PurrNetView nvCache; public void Update() { if (!Application.isPlaying) return; if (currentDelay <= 0) { if (isMaster) MasterCommunication(); else ClientCommunication(); currentDelay = updateDelay; } else currentDelay -= Time.deltaTime; } public PurrNetView purrNetView { get { if (nvCache != null) { return nvCache; } else { nvCache = GetComponent(); return nvCache; } } } public void SyncCozyTime() { if (Mathf.Abs(purrNetView.time.value - weatherSphere.dayPercentage) > timeSettingSensitivity) weatherSphere.timeModule.currentTime = purrNetView.time.value; weatherSphere.timeModule.currentDay = purrNetView.day.value; weatherSphere.timeModule.currentYear = purrNetView.year.value; } public void SyncCozyAmbience() { ambienceManager.currentAmbienceProfile = ambienceManager.ambienceProfiles[purrNetView.ambience.value]; } public void SyncCozyWeather() { weatherSphere.weatherModule.ecosystem.weightedWeatherProfiles.Clear(); int l = 0; int[] weatherCache = PollValues(purrNetView.weatherCacheString.value); float[] weights = PollWeightValues(purrNetView.weatherValuesString.value); int count = Mathf.Min(weatherCache.Length, weights.Length); for (int i = 0; i < count; i++) { WeatherRelation relation = new WeatherRelation(); relation.profile = weatherSphere.weatherModule.ecosystem.forecastProfile.profilesToForecast[weatherCache[i]]; relation.weight = weights[i]; weatherSphere.weatherModule.ecosystem.weightedWeatherProfiles.Add(relation); } } public void SyncCozyTimeMaster() { purrNetView.time.value = weatherSphere.timeModule.currentTime; purrNetView.day.value = weatherSphere.timeModule.currentDay; purrNetView.year.value = weatherSphere.timeModule.currentYear; } public void SyncCozyAmbienceMaster() { List ambiences = ambienceManager.ambienceProfiles.ToList(); purrNetView.ambience.value = ambiences.IndexOf(ambienceManager.currentAmbienceProfile); } public void SyncCozyWeatherMaster() { string weatherIDString = ""; foreach (int i in GetWeatherIDs()) weatherIDString = $"{weatherIDString}{i},"; purrNetView.weatherCacheString.value = weatherIDString; weatherIDString = ""; foreach (float i in GetWeatherIntensities()) weatherIDString = $"{weatherIDString}{i},"; purrNetView.weatherValuesString.value = weatherIDString; } private void MasterCommunication() { if (weatherSphere == null) weatherSphere = CozyWeather.instance; if (linkTime) SyncCozyTimeMaster(); if (linkAmbience) SyncCozyAmbienceMaster(); if (linkWeather) SyncCozyWeatherMaster(); } private void ClientCommunication() { if (weatherSphere == null) weatherSphere = CozyWeather.instance; if (linkTime) SyncCozyTime(); if (linkAmbience) SyncCozyAmbience(); if (linkWeather) SyncCozyWeather(); } public override void InitializeModule() { if (!Application.isPlaying) return; base.InitializeModule(); weatherHashes.Clear(); for (int i = 0; i < weatherSphere.weatherModule.ecosystem.forecastProfile.profilesToForecast.Count; i++) { weatherHashes.Add(weatherSphere.weatherModule.ecosystem.forecastProfile.profilesToForecast[i], i); } if (linkAmbience) { if (weatherSphere.GetModule() == null) { linkAmbience = false; } else { ambienceManager = weatherSphere.GetModule(); ambienceHashes.Clear(); for (int i = 0; i < ambienceManager.ambienceProfiles.Length; i++) { if (!ambienceHashes.ContainsKey(ambienceManager.ambienceProfiles[i])) ambienceHashes.Add(ambienceManager.ambienceProfiles[i], i); } } } } #endif #if LINK_FISHNET public bool isMaster { get { return fishnetView.isMaster; } } //VARIABLES______________________________________________________________________________________________________ private FishnetView nvCache; //FUNCTIONS_______________________________________________________________________________________________________ public void Update() { if (!Application.isPlaying) return; if (currentDelay <= 0) { if (isMaster) MasterCommunication(); else ClientCommunication(); currentDelay = updateDelay; } else currentDelay -= Time.deltaTime; } public FishnetView fishnetView { get { if (nvCache != null) { return nvCache; } else { nvCache = GetComponentInParent(); return nvCache; } } } public void SyncCozyTime() { if (Mathf.Abs(fishnetView.time.Value - weatherSphere.dayPercentage) > timeSettingSensitivity) weatherSphere.timeModule.currentTime = fishnetView.time.Value; weatherSphere.timeModule.currentDay = fishnetView.day.Value; weatherSphere.timeModule.currentYear = fishnetView.year.Value; } public void SyncCozyAmbience() { ambienceManager.currentAmbienceProfile = ambienceManager.ambienceProfiles[fishnetView.ambience.Value]; } public void SyncCozyWeather() { weatherSphere.weatherModule.ecosystem.weightedWeatherProfiles.Clear(); int l = 0; int[] weatherCache = PollValues(fishnetView.weatherCacheString.Value); foreach (int j in weatherCache) { WeatherRelation k = new WeatherRelation(); k.profile = weatherSphere.weatherModule.ecosystem.forecastProfile.profilesToForecast[j]; k.weight = PollWeightValues(fishnetView.weatherValuesString.Value)[l]; weatherSphere.weatherModule.ecosystem.weightedWeatherProfiles.Add(k); l++; } } public void SyncCozyTimeMaster() { fishnetView.time.Value = weatherSphere.timeModule.currentTime; fishnetView.day.Value = weatherSphere.timeModule.currentDay; fishnetView.year.Value = weatherSphere.timeModule.currentYear; } public void SyncCozyAmbienceMaster() { List ambiences = ambienceManager.ambienceProfiles.ToList(); fishnetView.ambience.Value = ambiences.IndexOf(ambienceManager.currentAmbienceProfile); } public void SyncCozyWeatherMaster() { string weatherIDString = ""; foreach (int i in GetWeatherIDs()) weatherIDString = $"{weatherIDString}{i},"; fishnetView.weatherCacheString.Value = weatherIDString; weatherIDString = ""; foreach (float i in GetWeatherIntensities()) weatherIDString = $"{weatherIDString}{i},"; fishnetView.weatherValuesString.Value = weatherIDString; } private void MasterCommunication() { if (linkTime) SyncCozyTimeMaster(); if (linkAmbience) SyncCozyAmbienceMaster(); if (linkWeather) SyncCozyWeatherMaster(); } private void ClientCommunication() { if (linkTime) SyncCozyTime(); if (linkAmbience) SyncCozyAmbience(); if (linkWeather) SyncCozyWeather(); } public override void InitializeModule() { if (!weatherSphere.gameObject.GetComponent()) weatherSphere.gameObject.AddComponent(); if (!Application.isPlaying) return; base.InitializeModule(); if (linkAmbience) { if (weatherSphere.GetModule() == null) { linkAmbience = false; } else { ambienceManager = weatherSphere.GetModule(); } } weatherHashes.Clear(); for (int i = 0; i < weatherSphere.weatherModule.ecosystem.forecastProfile.profilesToForecast.Count; i++) { weatherHashes.Add(weatherSphere.weatherModule.ecosystem.forecastProfile.profilesToForecast[i], i); } } #endif public int[] GetWeatherIDs() { List i = new List(); foreach (WeatherRelation j in weatherSphere.weatherModule.ecosystem.weightedWeatherProfiles) { i.Add(weatherHashes[j.profile]); } return i.ToArray(); } public float[] GetWeatherIntensities() { List i = new List(); foreach (WeatherRelation j in weatherSphere.weatherModule.ecosystem.weightedWeatherProfiles) { i.Add(j.weight); } return i.ToArray(); } public int[] PollValues(string key) { char comma = ",".ToCharArray()[0]; string[] valuesInStringFormat = key.Split(comma); List i = new List(); foreach (string k in valuesInStringFormat) { if (k == "") continue; string trimmed = k.TrimEnd(comma); int parsed = int.Parse(trimmed); i.Add(parsed); } return i.ToArray(); } public float[] PollWeightValues(string key) { char comma = ",".ToCharArray()[0]; string[] valuesInStringFormat = key.Split(comma); List i = new List(); foreach (string k in valuesInStringFormat) { if (k == "") continue; i.Add(float.Parse(k.TrimEnd(comma))); } return i.ToArray(); } } }