/// <summary> /// Handles end of conflict events if user chooses to do so. /// </summary> private void handleEndConflicts(ConflictEndMode mode, TrackedObjectStates tos) { switch (mode) { case ConflictEndMode.OnIndividualConflictEnded: //find conflicts that have partially or completely ended and inform agents monitoring int numStates = tos.ParentIDLeavers.Length; for (int endParentID = 0; endParentID < numStates; endParentID++) { int parentID = tos.ParentIDLeavers[endParentID]; TrackedObjectData TOData; // = TrackedObjectDataRef[parentID]; if (TrackedObjectDataRef.TryGetValue(parentID, out TOData)) { int numConflicts = tos.LeavingIDs[endParentID].Length; // allocate arrays for conflict data GameObject[] leavers = new GameObject[numConflicts]; string[] conflictorAffiliations = new string[numConflicts]; // fill conflict data for (int i = 0; i < numConflicts; i++) { int m = TrackedObjectStates.LeavingIDs[endParentID][i]; leavers[i] = gameObjectReference[m]; conflictorAffiliations[i] = TrackedObjectAffiliations[m]; } //inform the agents monitoring this object foreach (WorldMonitors wm in TOData.ObjectOwners) { wm.RaiseConflictLeavers(TOData.Object, leavers, conflictorAffiliations); } } } break; case ConflictEndMode.OnAllConflictsEnded: //find conflicts that have completely ended and inform the agents monitoring foreach (int endParentID in TrackedObjectStates.PriorConflictingIDs) { TrackedObjectData TOData; if (TrackedObjectDataRef.TryGetValue(endParentID, out TOData)) // preserve the ability to have non-owned tracked objects { if (TOData.ObjectOwners.Count > 0) { foreach (WorldMonitors wm in TOData.ObjectOwners) { wm.EndConflicts(gameObjectReference[endParentID]); } } } } break; } }
/// <summary> /// Call this method to begin the threaded Octree operations. /// </summary> /// <param name="otp"<see cref="OctreeThreadParameters"/></param> public void ThreadOctreeInit(OctreeThreadParameters otp, bool restrictToMainThread) { if (restrictToMainThread) { TrackedObjectStates = evaluateOctree(otp); return; } ThreadRunning = true; IsDone = false; base.StartOctree(otp); }
public void Start() { usingTriggers = TrackingMode == TrackingMode.UnityTriggers; agentMonitors = GameObject.FindObjectsOfType <WorldMonitors>(); /* * Start procedure is O(i*j*k) and a faster solution may exist */ for (int i = 0; i < agentMonitors.Length; i++) { for (int j = 0; j < agentMonitors[i].TrackedObjects.Count; j++) { for (int k = 0; k < agentMonitors[i].TrackedObjects[j].TrackedObjects.Count; k++) { // double threshold size if user wishes for point octree to mimic trigger interaction distances float threshold = (OctreeMimicTriggerInteraction && TrackingMode == TrackingMode.Octree) ? agentMonitors[i].ThresholdSet[j] * 3 / 2 : agentMonitors[i].ThresholdSet[j]; GameObject go = agentMonitors[i].TrackedObjects[j].TrackedObjects[k]; if (go) // allows user to leave empty gameobject slots in tracked object inspector { int id; if (GameObjectIDReference.TryGetValue(go, out id)) { TrackedObjectData TOData; TrackedObjectDataRef.TryGetValue(id, out TOData); TOData.ObjectOwners.Add(agentMonitors[i]); TrackedObjectDataRef[id] = TOData; if (usingTriggers) { // WorldMonitors will declare ownership in its Start() method if (!go.GetComponent <TrackedObjectTriggers>()) { go.AddComponent <TrackedObjectTriggers>(); } go.GetComponent <TrackedObjectTriggers>().Initialize(); } } else { GameObjectIDReference.Add(go, TotalTrackedObjects); //object ID = current number of tracked objects gameObjectReference.Add(TotalTrackedObjects, go); //using IDs necessary to run aux thread TrackedObjectData TOData = new TrackedObjectData { Object = go, Threshold = threshold, ObjectOwners = new List <WorldMonitors>() }; TOData.ObjectOwners.Add(agentMonitors[i]); TrackedObjectDataRef.Add(TotalTrackedObjects, TOData); TrackedObjectAffiliations.Add(TotalTrackedObjects, OTIEditorBase._AlphabetAssembler(j)); if (usingTriggers) { if (!go.GetComponent <TrackedObjectTriggers>()) { go.AddComponent <TrackedObjectTriggers>(); } go.GetComponent <TrackedObjectTriggers>().Initialize(); } TotalTrackedObjects++; } } } } } AllocationSpace = TotalTrackedObjects; FreeSpace = MaximumObjectsAllowed - AllocationSpace >= 0; if (usingTriggers || ExhaustiveMethod) { return; // no more set up required; switching between modes is not allowed at runtime. } Octree = new Octree(); //configure tracked object states at start for (int i = 0; i < TotalTrackedObjects; i++) { List <int> locals = new List <int>(); if (Octree.MasterList.ContainsKey(i)) { Octree.MasterList[i] = locals; } else { Octree.MasterList.Add(i, locals); } } OctreeThreadParameters otp = new OctreeThreadParameters { ObjectIDs = new List <int>(TrackedObjectDataRef.Keys), TotalTrackedObjects = TotalTrackedObjects, Coordinates = getUpdatedPositions(new List <int>(TrackedObjectDataRef.Keys)), DynamicObjects = TrackedObjectAffiliations }; //construct initial octree Octree.Initialize(InitialWorldSize, WorldOrigin, MinimumObjectSize); Octree.IsDone = true; //allows an initial pass into job start Octree.ThreadOctreeInit(otp, RestrictToMainThread); while (!Octree.UpdateOctree()) { } //wait until conflict states are established TrackedObjectStates = Octree.TrackedObjectStates; // wipe initial results so conflicts existing before start register for (int i = 0; i < Octree.MasterList.Count; i++) { Octree.MasterList[i] = new List <int>(); } }
void Update() { if (ExhaustiveMethod || usingTriggers) // if you are not using these features you can remove this if statement { if (ExhaustiveMethod) { exhaustiveCalculation(); } return; } if (Octree.UpdateOctree()) // job has concluded { passedFrames = 0; // in sync with update TrackedObjectStates = Octree.TrackedObjectStates; OctreeThreadParameters otp = refreshThreadingParameters(); int numStates = TrackedObjectStates.ParentIDEnterers.Length; for (int tos = 0; tos < numStates; tos++) { int parentID = TrackedObjectStates.ParentIDEnterers[tos]; TrackedObjectData TOData; if (TrackedObjectDataRef.TryGetValue(parentID, out TOData)) { int numConflicts = TrackedObjectStates.EnteringIDs[tos].Length; GameObject[] conflictors = new GameObject[numConflicts]; // allocate arrays for conflict data string[] conflictorAffiliations = new string[numConflicts]; // fill conflict data for (int i = 0; i < numConflicts; i++) { int m = TrackedObjectStates.EnteringIDs[tos][i]; conflictors[i] = gameObjectReference[m]; conflictorAffiliations[i] = TrackedObjectAffiliations[m]; } foreach (WorldMonitors wm in TOData.ObjectOwners) //inform the agents monitoring this object} { wm.RaiseConflictEnterers(TOData.Object, conflictors, conflictorAffiliations); } } } // if user wishes for no end conflict events to be raised, the update has concluded. if (ConflictEndMode == ConflictEndMode.NoConflictEndEvents) { Octree.ThreadOctreeInit(otp, RestrictToMainThread); return; } handleEndConflicts(ConflictEndMode, TrackedObjectStates); Octree.ThreadOctreeInit(otp, RestrictToMainThread); } else { passedFrames++; } }
protected override void ThreadOctree(OctreeThreadParameters otp) { TrackedObjectStates = evaluateOctree(otp); IsDone = true; // TrackedObjectStates are defined - - eliminating race conditions }