using System.Collections; using System.Collections.Generic; using UnityEngine; using Photon.Realtime; using Photon.Pun; public class JobManager : MonoBehaviour, IInRoomCallbacks { [Header("Data:")] [SerializeField] private List jobTemplates = new List(); [SerializeField] private List zones = new List(); [Header("Events:")] [SerializeField] private GameEvent onAvailableJobsUpdated; [SerializeField] private GameEvent_JobInstance onJobStarted; [SerializeField] private GameEvent_JobInstance onJobCompleted; [Header("Listeners:")] [SerializeField] private GameEventListener_JobInstance onJobSelectedLocally; [SerializeField] private GameEventListener onLoadLevelStarting; [SerializeField] private GameEventListener_ZoneData onGameSceneLoaded; [SerializeField] private GameEventListener onDifficultyChanged; [SerializeField] private GameEventListener onJoinedRoom; [SerializeField] private GameEventListener onBossDead; [Header("Runtime Data:")] public bool JobActive = false; public JobInstance currentlySelectedJob; [SerializeField] public List availableJobs = new List(); private string availableJobsJson; #region Singleton private static JobManager _instance; // Public reference to the singleton instance public static JobManager Instance { get { // If the instance doesn't exist, try to find it in the scene if (_instance == null) { _instance = FindObjectOfType(); // If it's still null, create a new GameObject and add the component if (_instance == null) { GameObject singletonObject = new GameObject(typeof(JobManager).Name); _instance = singletonObject.AddComponent(); } } return _instance; } } #endregion protected void Awake() { // Ensure there's only one instance if (_instance != null && _instance != this) { Destroy(gameObject); return; } // If this is the first instance, set it as the singleton _instance = this; DontDestroyOnLoad(gameObject); SetupEvents(); } private void SetupEvents() { onJobSelectedLocally.Response.AddListener(UpdateJobSelection); onLoadLevelStarting.Response.AddListener(UpdateActiveJobState); onGameSceneLoaded.Response.AddListener(HandleGameSceneChanged); onDifficultyChanged.Response.AddListener(UpdateAvailableJobsRewardsOnDifficultyChanged); onJoinedRoom.Response.AddListener(GenerateJobs); onBossDead.Response.AddListener(CompleteCurrentJob); } public void UpdateJobSelection(JobInstance jobInstance) { currentlySelectedJob = jobInstance; } private void UpdateActiveJobState() { if (currentlySelectedJob.isHostileZone) JobActive = true; } private void HandleGameSceneChanged(ZoneData zoneData) { if (JobActive) onJobStarted.Raise(currentlySelectedJob); } public void CompleteCurrentJob() { if (!JobActive) return; if (!currentlySelectedJob.isHostileZone) return; onJobCompleted.Raise(currentlySelectedJob); JobActive = false; currentlySelectedJob.completed = true; if (!PhotonNetwork.IsMasterClient) return; UpdatePropertiesWithJobs(); onAvailableJobsUpdated.Raise(); } public JobInstance GenerateJobInstance(ZoneData respectiveZone) { List possibleTemplates = jobTemplates.FindAll(job => job.zoneName == respectiveZone.zoneName); JobTemplate usedTemplate = possibleTemplates[Random.Range(0, possibleTemplates.Count)]; JobInstance generatedJob = new JobInstance(usedTemplate); generatedJob.templateIndex = jobTemplates.IndexOf(usedTemplate); generatedJob.UpdateRewardsBasedOnTemplateAndDifficulty(usedTemplate); return generatedJob; } private void UpdateAvailableJobsRewardsOnDifficultyChanged() { foreach (JobInstance job in availableJobs) { job.UpdateRewardsBasedOnTemplateAndDifficulty(jobTemplates[job.templateIndex]); } } public void GenerateJobs() { if (!PhotonNetwork.IsMasterClient) { TryGetAvailableJobsFromRoomProperties(); return; } for (int i = 0; i < zones.Count; i++) { availableJobs.Add(GenerateJobInstance(zones[i])); } UpdatePropertiesWithJobs(); onAvailableJobsUpdated.Raise(); } private void UpdatePropertiesWithJobs() { if (availableJobs.TrueForAll(job => (job.isHostileZone && job.completed) || !job.isHostileZone)) { availableJobs.Clear(); Debug.Log("Jobs: Refreshing job state on all completed"); GenerateJobs(); } AvailableJobs jobs = new AvailableJobs(); jobs.availableJobs = availableJobs; availableJobsJson = JsonUtility.ToJson(jobs); Debug.Log("Room Property jobs: " + availableJobsJson); ExitGames.Client.Photon.Hashtable ht = new ExitGames.Client.Photon.Hashtable { { GameConstants.NetworkPropertyKeys.AvailableJobsKey, availableJobsJson } }; PhotonNetwork.CurrentRoom.SetCustomProperties(ht); } private void TryGetAvailableJobsFromRoomProperties() { ExitGames.Client.Photon.Hashtable roomProperties = PhotonNetwork.CurrentRoom.CustomProperties; if (roomProperties.ContainsKey(GameConstants.NetworkPropertyKeys.AvailableJobsKey)) { availableJobsJson = (string)roomProperties[GameConstants.NetworkPropertyKeys.AvailableJobsKey]; Debug.Log("Room Property Jobs: " + availableJobsJson); AvailableJobs jobs = JsonUtility.FromJson(availableJobsJson); availableJobs = jobs.availableJobs; onAvailableJobsUpdated.Raise(); } } public void OnRoomPropertiesUpdate(ExitGames.Client.Photon.Hashtable propertiesThatChanged) { if (PhotonNetwork.IsMasterClient) return; TryGetAvailableJobsFromRoomProperties(); } public void OnPlayerEnteredRoom(Player newPlayer) { } public void OnPlayerLeftRoom(Player otherPlayer) { } public void OnPlayerPropertiesUpdate(Player targetPlayer, ExitGames.Client.Photon.Hashtable changedProps) { } public void OnMasterClientSwitched(Player newMasterClient) { } } [System.Serializable] public class AvailableJobs { public List availableJobs = new List(); }