//public void NewStoryLine(string _name) //{ // // Creates a new LOCAL storypointer and adds it to the pointerstack. // new StoryPointer(_name, SCOPE.LOCAL); // constructor adds pointer to GENERAL.allpointers //} public void EvaluatePointers() { // Create a stack of pointers for processing. pointerStack = new List <StoryPointer>(); for (int p = GENERAL.ALLPOINTERS.Count - 1; p >= 0; p--) { StoryPointer sp = GENERAL.ALLPOINTERS[p]; // For consistency of network logic, local pointers that were killed are disposed here. // Global pointers are disposed by the AD, after updating clients about them. if (sp.scope == SCOPE.LOCAL && sp.GetStatus() == POINTERSTATUS.KILLED) { Log("Removing pointer: " + sp.currentPoint.StoryLine); GENERAL.ALLPOINTERS.RemoveAt(p); } if (sp.GetStatus() == POINTERSTATUS.EVALUATE || sp.GetStatus() == POINTERSTATUS.TASKUPDATED) { // pointer needs evaluating. but we only do this if pointer is local OR if pointer is global and we are the server if ((sp.scope == SCOPE.GLOBAL && GENERAL.AUTHORITY == AUTHORITY.GLOBAL) || (sp.scope == SCOPE.LOCAL)) { pointerStack.Add(sp); } } } if (pointerStack.Count > 0) { Log("Evaluating " + pointerStack.Count + " of " + GENERAL.ALLPOINTERS.Count + " storypointers."); } while (pointerStack.Count > 0) { // Keep processing items on the stack untill empty. StoryPointer pointer; string targetPointerName, targetValue; StoryPointer newPointer, targetPointer; StoryPoint targetPoint; pointer = pointerStack[0]; Log("Evaluating pointer: " + pointer.currentPoint.StoryLine); pointer.LoadPersistantData(); switch (pointer.currentPoint.taskType) { case TASKTYPE.ROUTING: string type = pointer.currentPoint.Instructions[0]; switch (type) { case "hold": // Put this pointer on hold. Remove from stack. Log("Pausing pointer."); pointer.SetStatus(POINTERSTATUS.PAUSED); pointerStack.RemoveAt(0); break; case "tell": // Control another pointer. Finds a/the(!) pointer on the given storyline and moves it to the given storypoint, marking the pointer for evaluation. // Progress this pointer, keeping it on the stack targetPointerName = pointer.currentPoint.Instructions[1]; targetValue = pointer.currentPoint.Instructions[2]; targetPointer = GENERAL.GetPointerForStoryline(targetPointerName); if (targetPointer != null) { targetPoint = GENERAL.GetStoryPointByID(targetValue); if (targetPoint != null) { targetPointer.currentPoint = targetPoint; } else { Warning("Tell was unable to find the indicated storypoint."); } targetPointer.SetStatus(POINTERSTATUS.EVALUATE); Log("Telling pointer on storyline " + targetPointerName + " to move to point " + targetValue); } else { Warning("Tell was unable to find the indicated storypointer."); } moveToNextPoint(pointer); break; case "goto": // Moves this pointer to another point anywhere in the script. Mark for evaluation, keep on stack. targetValue = pointer.currentPoint.Instructions[1]; targetPoint = GENERAL.GetStoryPointByID(targetValue); if (targetPoint != null) { pointer.currentPoint = targetPoint; Log("Go to point " + targetValue); } else { Warning("Goto point not found."); } pointer.SetStatus(POINTERSTATUS.EVALUATE); break; case "start": // Start a new pointer on the given storypoint. // Create a new pointer, add it to the list of pointers and add it to the stack. // Progress the current pointer, keeping it on the stack. targetPointerName = pointer.currentPoint.Instructions[1]; if (GENERAL.GetPointerForStoryline(targetPointerName) == null) { Log("Starting new pointer for storypoint: " + targetPointerName); newPointer = new StoryPointer(targetPointerName, pointer.scope); pointerStack.Add(newPointer); } else { Log("Storyline already active for storypoint " + targetPointerName); } moveToNextPoint(pointer); break; case "stop": // Stop another storypointer by storyline name, or all other storylines with 'all'. targetPointerName = pointer.currentPoint.Instructions[1]; if (targetPointerName == "all") { foreach (StoryPointer stp in GENERAL.ALLPOINTERS) { if (stp != pointer) { Log("Stopping pointer " + stp.currentPoint.StoryLine); stp.Kill(); if (GENERAL.ALLTASKS.Remove(stp.currentTask)) { Log("Removing task " + stp.currentTask.Instruction); } else { Warning("Failed removing task " + stp.currentTask.Instruction); } } } // Remove all pointers from stack, re-adding the one we're on. pointerStack.Clear(); pointerStack.Add(pointer); } else { // Stop a single storypointer on given storyline. targetPointer = GENERAL.GetPointerForStoryline(targetPointerName); if (targetPointer != null) { Log("Stopping pointer " + targetPointer.currentPoint.StoryLine); pointerStack.Remove(targetPointer); targetPointer.Kill(); if (GENERAL.ALLTASKS.Remove(targetPointer.currentTask)) { Log("Removing task " + targetPointer.currentTask.Instruction); } else { Warning("Failed removing task " + targetPointer.currentTask.Instruction); } } else { Log("No pointer found for " + targetPointerName); } } moveToNextPoint(pointer); break; default: break; } break; //case TASKTYPE.END: // // End of a storyline. // checkForCallBack(pointer); // if (pointer.currentTask != null && pointer.currentTask.getStatus() != TASKSTATUS.COMPLETE) // { // Warning("Encountered end of storyline, but current task didn't complete?"); // } // pointer.SetStatus(POINTERSTATUS.NEWTASK); // // pointer.Kill(); // pointerStack.RemoveAt(0); // break; case TASKTYPE.BASIC: // case TASKTYPE.END: if (pointer.GetStatus() == POINTERSTATUS.EVALUATE) { // A normal task to be executed. Assistant director will generate task. Log("Task to be executed: " + pointer.currentPoint.Instructions[0]); pointer.SetStatus(POINTERSTATUS.NEWTASK); pointerStack.RemoveAt(0); } if (pointer.GetStatus() == POINTERSTATUS.TASKUPDATED) { // Something has happened in the task that we need to evaluate. if (pointer.currentTask.getStatus() == TASKSTATUS.COMPLETE) { // Task was completed. Check if there's a callback before moving on. checkForCallBack(pointer); // Task was completed, progress to the next point. Log("task completed: " + pointer.currentTask.Instruction); pointer.SetStatus(POINTERSTATUS.EVALUATE); moveToNextPoint(pointer); } if (pointer.currentTask.getStatus() == TASKSTATUS.ACTIVE) { // See if there's a callback. checkForCallBack(pointer); // Return pointerstatus to paused and stop evaluating it for now. // Debug.LogWarning (me + "Pointerstatus says taskupdated, but taskstatus for task " + pointer.currentTask.description + " is active."); pointer.SetStatus(POINTERSTATUS.PAUSED); pointerStack.RemoveAt(0); } } break; default: // This shouldn't occur. Warning("Error: unkown storypoint type. "); pointerStack.RemoveAt(0); break; } } }
void LateUpdate() { StoryUpdate storyUpdate = new StoryUpdate(); // Contains a collection of task and pointer updates. // Check our loadbalance. If we're sending too many updates we'll randomly drop frames. // All changes will be sent but if values are updated in the meantime the previous value will never be sent. // This is ok for running values but not ok for status values etc. int QueueSize = 0; if (GENERAL.AUTHORITY == AUTHORITY.GLOBAL && NetworkServer.active) { // We're an active server. byte error; QueueSize = NetworkTransport.GetOutgoingMessageQueueSize(NetworkServer.serverHostId, out error); // debugValue.text = "queued out server: " + QueueSize; if ((NetworkError)error != NetworkError.Ok) { Error("Networktransport error: " + (NetworkError)error); } } if (GENERAL.AUTHORITY == AUTHORITY.LOCAL && networkManager != null && networkManager.client != null) { // We're an active client. byte error = (byte)NetworkError.Ok; if (networkManager.client.connection != null) { QueueSize = NetworkTransport.GetOutgoingMessageQueueSize(networkManager.client.connection.hostId, out error); } else { Warning("Can't get queue size (yet)"); } // debugValue.text = "queued out client: " + QueueSize; if ((NetworkError)error != NetworkError.Ok) { Error("Networktransport error: " + (NetworkError)error); } } switch (QueueSize) { case 0: BufferStatusOut = 0; break; case 1: case 2: BufferStatusOut = 1; break; default: BufferStatusOut = 2; break; } // forcing always send. // this means that a storyupdate is sent for every frame and they all arrive in order. // they get executed in order as well, but they may be batched together. // so multiple tasks might get executed in a single frame. they will be executed in the correct order. if (QueueSize < 3 || true) { // Iterate over all pointers to see if any were killed. Clients do not kill pointers themselves. // For consistency of network logic, local pointers that were killed are disposed by the director. // Global pointers are disposed here, after updating clients about them. for (int p = GENERAL.ALLPOINTERS.Count - 1; p >= 0; p--) { StoryPointer pointer = GENERAL.ALLPOINTERS[p]; if (GENERAL.AUTHORITY == AUTHORITY.GLOBAL && pointer.scope == SCOPE.GLOBAL && pointer.GetStatus() == POINTERSTATUS.KILLED) //if (GENERAL.AUTHORITY == AUTHORITY.GLOBAL && pointer.scope == SCOPE.GLOBAL && pointer.modified && pointer.GetStatus() == POINTERSTATUS.KILLED) { Log("Sending pointer kill update to clients: " + pointer.currentPoint.StoryLine); storyUpdate.AddStoryPointerUpdate(pointer.GetUpdate()); // bundled //pointer.modified = false; Log("Removing pointer " + pointer.currentPoint.StoryLine); GENERAL.ALLPOINTERS.Remove(pointer); } } // Iterate over all tasks. for (int i = GENERAL.ALLTASKS.Count - 1; i >= 0; i--) { StoryTask task = GENERAL.ALLTASKS[i]; // Cleanup completed tasks. if (task.getStatus() == TASKSTATUS.COMPLETE) { GENERAL.ALLTASKS.RemoveAt(i); Verbose("Task " + task.Instruction + " on storyline " + task.Pointer.currentPoint.StoryLine + " completed, removed from alltasks. "); } if (task.modified) { // Debugging: if a pointer is in the process of being killed, we may want to not send task updates // as they might result in the task being recreated clientside. if (task.Pointer.GetStatus() == POINTERSTATUS.KILLED) { Warning("Supressing sending task update for task with pointer that is dying. " + task.Instruction); } else { // Check if we need to send network updates. switch (GENERAL.AUTHORITY) { case AUTHORITY.LOCAL: if (task.scope == SCOPE.GLOBAL) { Verbose("Global task " + task.Instruction + " changed, adding to update for server."); storyUpdate.AddTaskUpdate(task.GetUpdateBundled()); // bundled } break; case AUTHORITY.GLOBAL: if (task.scope == SCOPE.GLOBAL) { Verbose("Global task " + task.Instruction + " changed, adding to update for clients."); storyUpdate.AddTaskUpdate(task.GetUpdateBundled()); // bundled } break; default: break; } task.modified = false; } } } // If anything to send, send. if (storyUpdate.AnythingToSend()) { switch (GENERAL.AUTHORITY) { case AUTHORITY.LOCAL: SendStoryUpdateToServer(storyUpdate); //Debug.Log("Sending story update to server. \n" + storyUpdate.DebugLog); break; case AUTHORITY.GLOBAL: SendStoryUpdateToClients(storyUpdate); //Debug.Log("Sending story update to clients. \n" + storyUpdate.DebugLog); //Debug.Log(storyUpdate.ToString()); break; default: break; } } } else { Warning("Dropping update."); } }
/* * private async void LoadScript() * { * if (scriptAddressable != null && scriptAddressable != "") * { * theDirector.status = DIRECTORSTATUS.PAUSED; * AsyncOperationHandle<TextAsset> handle = Addressables.LoadAssetAsync<TextAsset>(scriptAddressable); * await handle.Task; * * if (handle.Status==) * if (handle.Result == null) * { * Error("Addressable script asset failed: " + obj.OperationException.Message); * * } * else * { * * theDirector.loadScriptAsset(obj.Result); * Log("Script loaded, from addressable asset."); * * * } * * } * * * * * * // The task is complete. Be sure to check the Status is successful before storing the Result. * * } * */ #region SENDUPDATES void LateUpdate() { // Check if any data changed during this frame, and send updates across network. StoryUpdate storyUpdate = new StoryUpdate(); // Contains a collection of task and pointer updates. // Is there a networkhandler. if (NetworkHandler.Instance != null) { int Queue = NetworkHandler.Instance.GetQueueSize(); if (Queue == -1) { // Verbose("no network active"); } else { switch (Queue) { case 0: BufferStatusOut = 0; break; case 1: case 2: BufferStatusOut = 1; break; default: BufferStatusOut = 2; break; } // forcing always send. // this means that a storyupdate is sent for every frame and they all arrive in order. // they get executed in order as well, but they may be batched together. // so multiple tasks might get executed in a single frame. they will be executed in the correct order. if (Queue < 3 || true) { // Iterate over all pointers to see if any were killed. Clients do not kill pointers themselves. // For consistency of network logic, local pointers that were killed are disposed by the director. // Global pointers are disposed here, after updating clients about them. for (int p = GENERAL.ALLPOINTERS.Count - 1; p >= 0; p--) { StoryPointer pointer = GENERAL.ALLPOINTERS[p]; if (GENERAL.AUTHORITY == AUTHORITY.GLOBAL && pointer.scope == SCOPE.GLOBAL && pointer.GetStatus() == POINTERSTATUS.KILLED) //if (GENERAL.AUTHORITY == AUTHORITY.GLOBAL && pointer.scope == SCOPE.GLOBAL && pointer.modified && pointer.GetStatus() == POINTERSTATUS.KILLED) { Log("Sending pointer kill update to clients: " + pointer.currentPoint.StoryLine); storyUpdate.AddStoryPointerUpdate(pointer.GetUpdate()); // bundled //pointer.modified = false; Log("Removing pointer " + pointer.currentPoint.StoryLine); GENERAL.ALLPOINTERS.Remove(pointer); } } // Iterate over all tasks. for (int i = GENERAL.ALLTASKS.Count - 1; i >= 0; i--) { StoryTask task = GENERAL.ALLTASKS[i]; // Cleanup completed tasks. if (task.getStatus() == TASKSTATUS.COMPLETE) { GENERAL.ALLTASKS.RemoveAt(i); Verbose("Task " + task.Instruction + " on storyline " + task.Pointer.currentPoint.StoryLine + " completed, removed from alltasks. "); } if (task.modified) { // Debugging: if a pointer is in the process of being killed, we may want to not send task updates // as they might result in the task being recreated clientside. if (task.Pointer.GetStatus() == POINTERSTATUS.KILLED) { Warning("Supressing sending task update for task with pointer that is dying. " + task.Instruction); } else { // Check if we need to send network updates. switch (GENERAL.AUTHORITY) { case AUTHORITY.LOCAL: if (task.scope == SCOPE.GLOBAL) { Verbose("Global task " + task.Instruction + " with id " + task.PointID + " changed, adding to update for server."); storyUpdate.AddTaskUpdate(task.GetUpdate()); // bundled } break; case AUTHORITY.GLOBAL: if (task.scope == SCOPE.GLOBAL) { Verbose("Global task " + task.Instruction + " with id " + task.PointID + " changed, adding to update for clients."); storyUpdate.AddTaskUpdate(task.GetUpdate()); // bundled } break; default: break; } task.modified = false; } } } // If anything to send, send. if (storyUpdate.AnythingToSend()) { switch (GENERAL.AUTHORITY) { case AUTHORITY.LOCAL: if (NetworkHandler.Instance != null) { NetworkHandler.Instance.SendStoryUpdateToServer(storyUpdate); } Log("Sending story update to server. \n" + storyUpdate.DebugLog); break; case AUTHORITY.GLOBAL: if (NetworkHandler.Instance != null) { NetworkHandler.Instance.SendStoryUpdateToClients(storyUpdate); } Log("Sending story update to clients. \n" + storyUpdate.DebugLog); //Debug.Log(storyUpdate.ToString()); break; default: break; } } } } /* * * * * if (NetworkHandler.Instance.IsClient()) * { * StoryUpdate storyUpdate = new StoryUpdate(); // Contains a collection of dataupdates. * * // Iterate over all data. * * for (int i = GENERAL.ALLTASKS.Count - 1; i >= 0; i--) * { * StoryTask data = GENERAL.ALLTASKS[i]; * * if (data.modified) * { * // Data was modified locally, if global, compile an update for the server. * * if (data.scope == SCOPE.GLOBAL) * { * Verbose("Data was modified locally as client, creating update for server for " + data.ID); * storyUpdate.AddDataUpdate(data.GetDataUpdate()); // bundled * } * * data.modified = false; * } * } * * // If anything to send, send. * * if (storyUpdate.AnythingToSend()) * * { * * NetworkHandler.Instance.SendStoryUpdateToServer(storyUpdate); * * Verbose("Sending story update to server. \n" + storyUpdate.DebugLog); * * * * } * * * * } * * * * * // If server, messages may differ for clients. * * * if (NetworkHandler.Instance.IsServer()) * { * * string[] clients = NetworkHandler.Instance.TrackedConnectedAddresses().ToArray(); * * for (int c = 0; c < clients.Length; c++) * { * * StoryUpdate storyUpdate = new StoryUpdate(); // Contains a collection of dataupdates. * * // Iterate over all data. * * for (int i = GENERAL.ALLTASKS.Count - 1; i >= 0; i--) * { * StoryTask data = GENERAL.ALLTASKS[i]; * * if (data.modified) * { * // Data was modified locally, if global, compile an update for the server. * * if (data.scope == SCOPE.GLOBAL) * { * Verbose("Data was modified locally as client, creating update for server for " + data.ID); * storyUpdate.AddDataUpdate(data.GetDataUpdateFor(clients[c])); // bundled * } * * data.modified = false; * } * } * * // If anything to send, send. * * if (storyUpdate.AnythingToSend()) * * { * NetworkHandler.Instance.SendStoryUpdateToClient(storyUpdate, clients[c]); * * Verbose("Sending story update to client. \n" + storyUpdate.DebugLog); * * * * } * * * } * * * * * } * * */ } }
void Update() { #if !SOLO // Handle story updates, aiming for 1 per frame, assuming we're tyring to run in sync. // Lowest numbers are oldest. int UpdateCount = StoryUpdateStack.Count; switch (UpdateCount) { case 0: BufferStatusIn = 0; break; case 1: // exactly one, so apply. ApplyStoryUpdate(StoryUpdateStack[0]); StoryUpdateStack.RemoveAt(0); BufferStatusIn = 1; break; case 2: // Two, normally for different frames that happened to arrive in the same frame on this end. // Apply the oldest one, keep the other because we exact 0 updates during our next frame. ApplyStoryUpdate(StoryUpdateStack[0]); StoryUpdateStack.RemoveAt(0); BufferStatusIn = 1; break; default: // More than 2. Apply all the older ones in order of arrival, keep latest one. Warning("Update buffer >2"); BufferStatusIn = 2; while (StoryUpdateStack.Count > 1) { ApplyStoryUpdate(StoryUpdateStack[0]); StoryUpdateStack.RemoveAt(0); } break; } #endif switch (theDirector.status) { case DIRECTORSTATUS.ACTIVE: // Verbose("Director active ."); foreach (StoryTask task in GENERAL.ALLTASKS) { if (task.getCallBack() != "") { // if a callback was set (somewhere on the network) we act on it only if we are the server or if the task is local. if (GENERAL.AUTHORITY == AUTHORITY.GLOBAL || task.scope == SCOPE.LOCAL) { task.Pointer.SetStatus(POINTERSTATUS.TASKUPDATED); } } } theDirector.EvaluatePointers(); List <StoryTask> newTasks = new List <StoryTask>(); for (int p = 0; p < GENERAL.ALLPOINTERS.Count; p++) { StoryPointer pointer = GENERAL.ALLPOINTERS[p]; switch (pointer.scope) { case SCOPE.GLOBAL: // If pointer scope is global, we add a task if our own scope is global as well. (If our scope is local, we'll be receiving the task over the network) if (GENERAL.AUTHORITY == AUTHORITY.GLOBAL) { if (pointer.GetStatus() == POINTERSTATUS.NEWTASK) { pointer.SetStatus(POINTERSTATUS.PAUSED); StoryTask task = new StoryTask(pointer, SCOPE.GLOBAL); task.LoadPersistantData(pointer); newTasks.Add(task); task.modified = true; Verbose("Created global task " + task.Instruction + " for pointer " + pointer.currentPoint.StoryLine); } } break; case SCOPE.LOCAL: default: // If pointer scope is local, check if new tasks have to be generated. if (pointer.GetStatus() == POINTERSTATUS.NEWTASK) { pointer.SetStatus(POINTERSTATUS.PAUSED); StoryTask task = new StoryTask(pointer, SCOPE.LOCAL); task.LoadPersistantData(pointer); newTasks.Add(task); Verbose("Created local task " + task.Instruction + " for pointer " + pointer.currentPoint.StoryLine); } break; } } if (newTasks.Count > 0) { DistributeTasks(new TaskArgs(newTasks)); // if any new tasks call an event, passing on the list of tasks to any handlers listening } break; case DIRECTORSTATUS.READY: GENERAL.SIGNOFFS = eventHandlerCount(); if (GENERAL.SIGNOFFS == 0) { Error("No handlers registred. Pausing director."); theDirector.status = DIRECTORSTATUS.PAUSED; } else { Verbose("" + GENERAL.SIGNOFFS + " handlers registred."); Log("Starting storyline " + launchStoryline); theDirector.NewStoryLine(launchStoryline); theDirector.status = DIRECTORSTATUS.ACTIVE; } break; case DIRECTORSTATUS.NOTREADY: if (script != null) { theDirector.loadScript(script); break; } //if (scriptName != "") //{ // Warning("Please use the TextAsset field for your script."); // theDirector.loadScript(scriptName); // break; //} Error("No script reference found."); break; default: break; } }
void Update() { SetDebugLevels(); #region APPLYUPDATES if (NetworkHandler.Instance != null) { // Handle story updates, aiming for 1 per frame, assuming we're tyring to run in sync. // Lowest numbers are oldest. int UpdateCount = NetworkHandler.Instance.StoryUpdateStack.Count; switch (UpdateCount) { case 0: BufferStatusIn = 0; break; case 1: // exactly one, so apply. ApplyStoryUpdate(NetworkHandler.Instance.StoryUpdateStack[0]); NetworkHandler.Instance.StoryUpdateStack.RemoveAt(0); BufferStatusIn = 1; break; case 2: // Two, normally for different frames that happened to arrive in the same frame on this end. // Apply the oldest one, keep the other because we expect to get 0 updates during our next frame // (If we're on similar fps) ApplyStoryUpdate(NetworkHandler.Instance.StoryUpdateStack[0]); NetworkHandler.Instance.StoryUpdateStack.RemoveAt(0); BufferStatusIn = 1; break; default: // More than 2. Apply all the older ones in order of arrival, keep latest one because we may get 0 next frame. Warning("Update buffer >2"); BufferStatusIn = 2; while (NetworkHandler.Instance.StoryUpdateStack.Count > 1) { ApplyStoryUpdate(NetworkHandler.Instance.StoryUpdateStack[0]); NetworkHandler.Instance.StoryUpdateStack.RemoveAt(0); } break; } } #endregion #region DIRECTOR switch (theDirector.status) { case DIRECTORSTATUS.ACTIVE: // Verbose("Director active ."); foreach (StoryTask task in GENERAL.ALLTASKS) { if (task.getCallBack() != "") { // if a callback was set (somewhere on the network) we act on it only if we are the server or if the task is local. if (GENERAL.AUTHORITY == AUTHORITY.GLOBAL || task.scope == SCOPE.LOCAL) // if (true || task.scope == SCOPE.LOCAL) { task.Pointer.SetStatus(POINTERSTATUS.TASKUPDATED); } } } theDirector.EvaluatePointers(); List <StoryTask> newTasks = new List <StoryTask>(); for (int p = 0; p < GENERAL.ALLPOINTERS.Count; p++) { StoryPointer pointer = GENERAL.ALLPOINTERS[p]; switch (pointer.scope) { case SCOPE.GLOBAL: // If pointer scope is global, we add a task if our own scope is global as well. (If our scope is local, we'll be receiving the task over the network) if (GENERAL.AUTHORITY == AUTHORITY.GLOBAL) // if (true) { if (pointer.GetStatus() == POINTERSTATUS.NEWTASK) { pointer.SetStatus(POINTERSTATUS.PAUSED); StoryTask task = pointer.SpawnTask(); // StoryTask task = new StoryTask(pointer, SCOPE.GLOBAL); task.LoadPersistantData(pointer); newTasks.Add(task); task.modified = true; Verbose("Created global task " + task.Instruction + " with pointid " + task.PointID + " for pointer " + pointer.currentPoint.StoryLine); } } break; case SCOPE.LOCAL: default: // If pointer scope is local, check if new tasks have to be generated. if (pointer.GetStatus() == POINTERSTATUS.NEWTASK) { pointer.SetStatus(POINTERSTATUS.PAUSED); StoryTask task = pointer.SpawnTask(); //StoryTask task = new StoryTask(pointer, SCOPE.LOCAL); task.LoadPersistantData(pointer); newTasks.Add(task); Verbose("Created local task " + task.Instruction + " with pointid " + task.PointID + " for pointer " + pointer.currentPoint.StoryLine); } break; } } if (newTasks.Count > 0) { if (newTasksEventUnity != null) { newTasksEventUnity.Invoke(newTasks); } // if (newTasksEvent != null) newTasksEvent(this, new TaskArgs(newTasks)); // trigger the event, if there are any listeners // DistributeTasks(new TaskArgs(newTasks)); // if any new tasks call an event, passing on the list of tasks to any handlers listening } break; case DIRECTORSTATUS.READY: int SIGNOFFS = eventHandlerCount(); if (SIGNOFFS == 0) { Error("No handlers registred. Pausing director."); theDirector.status = DIRECTORSTATUS.PAUSED; } else { Verbose("" + SIGNOFFS + " handlers registred at this time."); Verbose("Starting storyline " + launchStoryline); theDirector.NewStoryLine(launchStoryline); theDirector.status = DIRECTORSTATUS.ACTIVE; } break; case DIRECTORSTATUS.NOTREADY: // try addressable script first. //if (scriptAddressable != null && scriptAddressable != "") //{ // // pause while loading // theDirector.status = DIRECTORSTATUS.PAUSED; // Addressables.LoadAssetAsync<TextAsset>(scriptAddressable).Completed += obj => // { // if (obj.Result == null) // { // Error("Addressable script asset failed: " + obj.OperationException.Message); // } // else // { // theDirector.loadScriptAsset(obj.Result); // Log("Script loaded, from addressable asset."); // } // }; //} if (scriptFile != null && scriptFile != "") { // we have a reference to a local script file, so we'll attempt to load it (synchronous). we try to load it from a folder with the current version string script = Transport.FileToText(Application.persistentDataPath + "/scripts/" + App.GetMinor() + "/" + scriptFile); if (script == "") { Log("No script on disk for version: " + App.GetMinor()); } else { theDirector.loadScriptText(script); Log("Script loaded, from local file."); break; } } if (scriptAsset != null) { theDirector.loadScriptAsset(scriptAsset); Log("Script loaded, from asset."); break; } Error("No script reference found, pausing director."); theDirector.status = DIRECTORSTATUS.PAUSED; break; default: break; } #endregion }