/*! Creates a new storypointer, if the storyline doesn't exist, with a given scope and adds it to the pointerstack. */ public void NewStoryLineExclusive(string _name, SCOPE _scope = SCOPE.LOCAL) { if (_name == "") { Warning("New storyline name is empty."); return; } Log("new storyline " + _name); if (GENERAL.GetPointerForStoryline(_name) == null) { // StoryPointer pointer = new StoryPointer(_name, _scope); // constructor adds pointer to GENERAL.allpointers StoryPointer pointer = new StoryPointer(); // constructor adds pointer to GENERAL.allpointers pointer.SetScope(_scope); pointer.SetStoryPointByID(_name); } else { Log("Storyline already running, you called exclusive."); } //pointer.scope = _scope; }
void ApplyPointerUpdate(PointerUpdateBundled pointerUpdate) { // Right now the only update we send for pointers is when they are killed. StoryPointer pointer = GENERAL.GetPointerForStoryline(pointerUpdate.StoryLineName); Log("Server says kill pointer: " + pointerUpdate.StoryLineName); if (pointer != null) { // We remove it instantly. No need to mark it as deleted, nothing else to do with it. GENERAL.ALLPOINTERS.Remove(pointer); Log("Removing pointer: " + pointer.currentPoint.StoryLine); // Server passes tasks, so if it is faster, client may be processing more than one task for a storyline. (Even if the deus dash would show it) for (int i = GENERAL.ALLTASKS.Count - 1; i >= 0; i--) { StoryTask task = GENERAL.ALLTASKS[i]; if (task.Point != null && task.Point.StoryLine == pointerUpdate.StoryLineName) { Log("Removing task: " + task.Instruction); GENERAL.ALLTASKS.Remove(task); } } } }
public static void AddPointer(StoryPointer pointer) { if (pointer != null) { ALLPOINTERS.Add(pointer); } }
void ApplyTaskUpdate(StoryTaskUpdate taskUpdate) { // See if we already have a task on this storypoint. StoryTask updateTask = GENERAL.GetTaskForPoint(taskUpdate.pointID); if (updateTask == null) { // Are we client ? -> create the task // (If we're the server, we'll ignore updates for tasks we no longer know about) if (GENERAL.AUTHORITY == AUTHORITY.LOCAL) { // Do we already have a pointer for this storyline? StoryPointer updatePointer = GENERAL.GetStorylinePointerForPointID(taskUpdate.pointID); if (updatePointer == null) { // Create a new pointer updatePointer = new StoryPointer(); Log("Created a new pointer for point with ID " + taskUpdate.pointID); } updatePointer.SetStoryPointByID(taskUpdate.pointID); updatePointer.SetScope(SCOPE.GLOBAL);// global because we just got it updateTask = updatePointer.SpawnTask(); //updateTask = new StoryTask(taskUpdate.pointID,updatePointer); // global because we just got it Log("Created an instance of global task " + updateTask.Instruction + " id " + updateTask.PointID); //Log("Populated pointer " + updatePointer.currentPoint.StoryLine + " with task " + updateTask.Instruction); updateTask.ApplyUpdate(taskUpdate); // updatePointer.PopulateWithTask(updateTask); List <StoryTask> newTasks = new List <StoryTask>(); newTasks.Add(updateTask); if (newTasksEventUnity != null) { newTasksEventUnity.Invoke(newTasks); } } } else { updateTask.ApplyUpdate(taskUpdate); updateTask.scope = SCOPE.GLOBAL;// if a task was local it now becomes global Verbose("Applied update to existing task " + updateTask.Instruction); } }
void moveToNextPoint(StoryPointer thePointer) { if (!thePointer.ProgressToNextPoint()) { Warning("Error: killing pointer "); thePointer.SetStatus(POINTERSTATUS.KILLED); pointerStack.RemoveAt(0); } }
//int LastUpdateFrame = -1; //int UpdatesPerFrame = 0; //public int LastUpdatesPerFrame = 0; //public int MaxUpdatesPerFrame = 0; // ------------------------------------------------ #region CONSTRUCTOR // Tasks are create by calling spawntask on a pointer. public StoryTask(StoryPointer _fromPointer) : base("StoryTask", _fromPointer.scope) { // Create a task based on the current storypoint in the pointer. Pointer = _fromPointer; __point = _fromPointer.currentPoint; scope = _fromPointer.scope; setDefaults(); GENERAL.AddTask(this); }
// new StoryPointer(beginName, SCOPE.LOCAL); // constructor adds pointer to GENERAL.allpointers //public void beginStoryLine(string beginName) //{ // new StoryPointer(beginName, SCOPE.LOCAL); // constructor adds pointer to GENERAL.allpointers //} /*! Creates a new storypointer with a given scope and adds it to the pointerstack. */ public void NewStoryLine(string _name, SCOPE _scope = SCOPE.LOCAL) { if (_name == "") { Warning("New storyline name is empty."); return; } StoryPointer pointer = new StoryPointer(_name, _scope); // constructor adds pointer to GENERAL.allpointers //pointer.scope = _scope; }
public StoryTask(string _fromPointID, SCOPE _scope) { // Creating a task from a storypoint -> pointer to be created from this task. //pointID = storyPointID; __point = GENERAL.GetStoryPointByID(_fromPointID); //description = point.task[0]; scope = _scope; __pointer = null; setDefaults(); GENERAL.ALLTASKS.Add(this); }
void ApplyTaskUpdate(TaskUpdateBundled taskUpdate) { // See if we have a task on this storypoint. StoryTask updateTask = GENERAL.GetTaskForPoint(taskUpdate.pointID); if (updateTask == null) { // If not, and we're a client, we create the task. // If we're the server, we ignore updates for task we no longer know about. if (GENERAL.AUTHORITY == AUTHORITY.LOCAL) { updateTask = new StoryTask(taskUpdate.pointID, SCOPE.GLOBAL); updateTask.ApplyUpdateMessage(taskUpdate); Log("Created an instance of global task " + updateTask.Instruction + " id " + updateTask.PointID); if (taskUpdate.pointID != "GLOBALS") { // Now find a pointer. StoryPointer updatePointer = GENERAL.GetStorylinePointerForPointID(taskUpdate.pointID); if (updatePointer == null) { updatePointer = new StoryPointer(); Log("Created a new pointer for task " + updateTask.Instruction); } updatePointer.PopulateWithTask(updateTask); Log("Populated pointer " + updatePointer.currentPoint.StoryLine + " with task " + updateTask.Instruction); DistributeTasks(new TaskArgs(updateTask)); } } } else { updateTask.ApplyUpdateMessage(taskUpdate); updateTask.scope = SCOPE.GLOBAL;//?? Verbose("Applied update to existing task " + updateTask.Instruction); } }
bool checkForCallBack(StoryPointer pointer) { // checks and trigger callback on the current task for given pointer. does not touch the pointer itself. if (pointer.currentTask == null) { return(false); } string callBackValue = pointer.currentTask.getCallBack(); if (callBackValue == "") { return(false); } pointer.currentTask.clearCallBack(); // clear value // A callback is equivalent to 'start name', launching a new storypointer on the given point. if (GENERAL.GetPointerForStoryline(pointer.currentTask.getCallBack()) == null) { Log("New callback storyline: " + callBackValue); StoryPointer newStoryPointer = new StoryPointer(callBackValue, pointer.scope); if (newStoryPointer.currentPoint == null) { // callback value was invalid, no point was found, we don't add the pointer. GENERAL.ALLPOINTERS.Remove(newStoryPointer);// was auto-added in constructor, so must be removed Warning("Callback storyline doesn't exist: " + callBackValue); } else { //newStoryPointer.modified = true; pointerStack.Add(newStoryPointer); newStoryPointer.persistantData = pointer.persistantData; // inherit data, note that data network distribution is via task only. AD will load value into task. } } else { Log("Callback storyline already started: " + callBackValue); } return(true); }
public StoryTask(StoryPointer _fromPointer, SCOPE _scope) { // Create a task based on the current storypoint of the pointer. // Note that setting scope is explicit, but in effect the scope of the task is the same as the scope of the pointer. __pointer = _fromPointer; //description = pointer.currentPoint.task[0]; __point = __pointer.currentPoint; //pointID = pointer.currentPoint.ID; _fromPointer.currentTask = this; scope = _scope; setDefaults(); GENERAL.ALLTASKS.Add(this); }
void createNewPointerUi(StoryPointer targetPointer) { if (PointerBlock == null || DeusCanvas == null) { Warning("Can't make pointerblock, null reference."); return; } GameObject newPointerUi; newPointerUi = Instantiate(PointerBlock); newPointerUi.transform.SetParent(DeusCanvas.transform, false); targetPointer.pointerObject = newPointerUi; targetPointer.pointerTextObject = newPointerUi.transform.Find("textObject").gameObject; targetPointer.deusText = newPointerUi.transform.Find("textObject/Text").GetComponent <Text>(); targetPointer.deusTextSuper = newPointerUi.transform.Find("textObject/TextSuper").GetComponent <Text>(); // find empty spot int p = 0; while (p < PointerdisplayBuffer && pointerPositions[p] != null) { p++; } if (p == PointerdisplayBuffer) { Warning("Too many pointers to display."); p = 0; } pointerPositions[p] = targetPointer; targetPointer.position = p; // Place it on the canvas int row = p / PointerDisplayCols; int col = p % PointerDisplayCols; float scale = 1f / PointerDisplayCols; targetPointer.pointerObject.GetComponent <RectTransform>().localPosition = scale * new Vector3(PointerDisplayCols / 2f * -1024f + 512f + col * 1024f, PointerDisplayRows / 2f * 512f - 256f - row * 512f, 0); targetPointer.pointerObject.GetComponent <RectTransform>().localScale = new Vector3(scale, scale, scale); }
public static StoryPointer GetPointerForStoryline(string theStoryLine) { flagPointerOverflow(); StoryPointer r = null; foreach (StoryPointer p in GENERAL.ALLPOINTERS) { if (p.currentPoint.StoryLine == theStoryLine) { r = p; break; } } return(r); }
void updateTaskInfo(StoryPointer pointer) { StoryTask theTask = pointer.currentTask; if (theTask == null || theTask.Pointer.pointerObject == null) { return; } if (theTask.Instruction != "wait") { //string displayText; string displayText = theTask.scope == SCOPE.GLOBAL ? "G| " : "L| "; // if (theTask.scope == SCOPE.GLOBAL) //{ // displayText = "G | "; //} //else //{ // displayText = "L | "; //} displayText = displayText + theTask.Instruction + " | "; // If a task has a value for "debug" we display it along with task description. string debugText; if (theTask.GetStringValue("debug", out debugText)) { displayText = displayText + debugText; } theTask.Pointer.deusText.text = displayText; theTask.Pointer.deusTextSuper.text = theTask.Pointer.currentPoint.StoryLine + " " + GENERAL.ALLPOINTERS.Count; } else { theTask.Pointer.deusTextSuper.text = theTask.Pointer.currentPoint.StoryLine; } }
public static StoryPointer GetStorylinePointerForPointID(string pointID) { string storyline = GetStoryPointByID(pointID).StoryLine; flagPointerOverflow(); StoryPointer r = null; foreach (StoryPointer p in GENERAL.ALLPOINTERS) { if (p.currentPoint.StoryLine == storyline) { r = p; break; } } return(r); }
void updateTaskDisplays() { // Go over all pointers and plot them into our diplay foreach (StoryPointer pointer in GENERAL.ALLPOINTERS) { if (!pointerList.Contains(pointer)) { Verbose("Pointer is new, added display for storyline " + pointer.currentPoint.StoryLine); pointerList.Add(pointer); createNewPointerUi(pointer); } updateTaskInfo(pointer); } // Go over all display pointers and see if they're still alive. for (int i = pointerList.Count - 1; i >= 0; i--) { // foreach (StoryPointer pointer in pointerList) { StoryPointer pointer = pointerList[i]; if (!GENERAL.ALLPOINTERS.Contains(pointer)) { Verbose("Destroying ui for pointer for storyline " + pointer.currentPoint.StoryLine); // update first. some pointers reach end in a single go - we want those to be aligned. // updateTaskDisplay (task); pointerList.Remove(pointer); pointerPositions[pointer.position] = null; Destroy(pointer.pointerObject); } } }
public Item(StoryPointer sp, GameObject prefab) { // Debug.Log("creating item"); __type = TYPE.POINTER; __sp = sp; // __sd = null; // TimeOut = 0f; // remove = false; if (prefab != null) { displayObject = GameObject.Instantiate(prefab); } else { displayObject = null; } deusText = displayObject.transform.Find("textObject/Text").GetComponent <Text>(); deusTextSuper = displayObject.transform.Find("textObject/TextSuper").GetComponent <Text>(); }
//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."); } }
bool checkForCallBack(StoryPointer pointer) { // checks for callbacks on the pointer. returns true if the pointer itself was moved. if (pointer.currentTask == null) { return(false); } string callBackValue = pointer.currentTask.getCallBack(); if (callBackValue == "") { return(false); } pointer.currentTask.clearCallBack(); // clear value // a callback refers to a point. if it's a storyline, a new storypoint will launch on the given point. // if it's another point, it works as goto StoryPoint callBackPoint = GENERAL.GetStoryPointByID(callBackValue); if (callBackPoint == null) { return(false); } // check if this point is on our own storyline if (callBackPoint.StoryLine == pointer.currentPoint.StoryLine) { // point is on the storyline our pointer is on, so make our pointer move Log("Callback -> caller's own storyline: " + callBackPoint.StoryLine + " moved to point: " + callBackValue + " task: " + callBackPoint.Instructions[0]); pointer.currentPoint = callBackPoint; pointer.SetStatus(POINTERSTATUS.EVALUATE); return(true); } // check if a pointer exists on the callback point's storyline StoryPointer storyPointer = GENERAL.GetPointerForStoryline(callBackPoint.StoryLine); if (storyPointer == null) { // no pointer for the callback point's storyline exists, we'll create one Log("Callback -> new storyline: " + callBackPoint.StoryLine + " starting at point: " + callBackValue + " task: " + callBackPoint.Instructions[0]); StoryPointer newStoryPointer = new StoryPointer(); newStoryPointer.SetScope(pointer.scope); newStoryPointer.SetStoryPointByID(callBackValue); pointerStack.Add(newStoryPointer); newStoryPointer.persistantData = pointer.persistantData; // inherit data, note that data network distribution is via task only. AD will load value into task } else { // a pointer on the storyline exists, we'll move it Log("Callback -> existing storyline: " + callBackPoint.StoryLine + " moved to point: " + callBackValue + " task: " + callBackPoint.Instructions[0]); storyPointer.currentPoint = callBackPoint; storyPointer.SetStatus(POINTERSTATUS.EVALUATE); } return(false); }
public void LoadPersistantData(StoryPointer referencePointer) { SetStringValue("persistantData", referencePointer.persistantData); }
void updateTaskDisplays() { if (PointerBlock == null || DebugCanvas == null) { Warning("Set references for pointerblock and deuscanvas."); return; } // Go over all pointers and plot them into our diplay for (int i = 0; i < GENERAL.ALLPOINTERS.Count; i++) { StoryPointer pointer = GENERAL.ALLPOINTERS[i]; if (!itemList.Exists(x => x.StoryPointer == pointer)) { Item ni = new Item(pointer, PointerBlock); ni.displayObject.transform.SetParent(DebugCanvas.transform, false); itemList.Add(ni); } } // Log("datacount " + GENERAL.ALLDATA.Count); // Go over all data objects and plot them into our diplay /* * for (int i = 0; i < GENERAL.ALLDATA.Count; i++) * { * * StoryData data = GENERAL.ALLDATA[i]; * * if (!itemList.Exists(x => x.StoryData == data)) * { * // Log("addin gitem"); * Item ni = new Item(data, PointerBlock); * ni.displayObject.transform.SetParent(DeusCanvas.transform, false); * * itemList.Add(ni); * * } * * } */ // Go over all items backwards and remove any for (int i = itemList.Count - 1; i >= 0; i--) { if (itemList[i].TimeOut != 0 && itemList[i].TimeOut < Time.time) { Destroy(itemList[i].displayObject); itemList.RemoveAt(i); } } // Go over all display items and update them. for (int i = 0; i < itemList.Count; i++) { int row = i / PointerDisplayCols; int col = i % PointerDisplayCols; float scale = 1f / PointerDisplayCols; Item item = itemList[i]; // item.displayObject.GetComponent<RectTransform>().localPosition = scale * new Vector3(PointerDisplayCols / 2f * -1024f + 512f + col * 1024f, PointerDisplayRows / 2f * 512f - 256f - row * 512f, 0); item.displayObject.GetComponent <RectTransform>().localPosition = scale * new Vector3(PointerDisplayCols / 2f * -1024f + 512f + col * 1024f, PointerDisplayRows / 2f * 512f - 256f - row * 512f, 0); item.displayObject.GetComponent <RectTransform>().localScale = new Vector3(scale, scale, scale); switch (item.Type) { case Item.TYPE.POINTER: if (item.TimeOut == 0 && !GENERAL.ALLPOINTERS.Contains(item.StoryPointer)) { item.TimeOut = Time.time + 1f; } StoryTask theTask = item.StoryPointer.currentTask; if (theTask == null || item.displayObject == null) { return; } if (theTask.Instruction != "wait" && theTask.Instruction != "end") { // string displayText = theTask.scope == SCOPE.GLOBAL ? "G| " : "L| "; string displayText = theTask.Instruction; // If a task has a value for "debug" we display it along with task description. string debugText; if (theTask.GetStringValue("debug", out debugText)) { displayText = displayText + " | " + debugText; } item.deusText.text = displayText; item.deusTextSuper.text = theTask.Pointer.currentPoint.StoryLine + " " + GENERAL.ALLPOINTERS.Count + (theTask.scope == SCOPE.GLOBAL ? " G" : " L"); } else { item.deusTextSuper.text = theTask.Pointer.currentPoint.StoryLine; } break; case Item.TYPE.DATA: /* * item.deusText.text = item.StoryData.GetChangeLog(); * item.deusTextSuper.text = "data: " + item.StoryData.ID + GENERAL.ALLDATA.Count; */ break; default: break; } } }
/* * 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() { 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 }
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; } }