Guest User

Untitled

a guest
Oct 1st, 2020
32
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 7.41 KB | None | 0 0
  1. #region Gap Handling
  2. /// <summary>
  3. /// Called when a gap gate is successfully passed through. Typically called by the gate itself.
  4. /// </summary>
  5. /// <param name="performingBoard">the board that went through the gate</param>
  6. /// <param name="theGapGate">the gate they went through</param>
  7. static public void GapGatePassed(ISkateboardGateway performingBoard, GapGateZone theGapGate)
  8. {
  9.     if (singleton == null) { return; }
  10.            
  11.     SkateboardGapTracker ourTracker = null;
  12.     if (!singleton.completedGapLog.TryGetValue(performingBoard, out ourTracker))
  13.     {
  14.         ourTracker = new SkateboardGapTracker();
  15.  
  16.         singleton.completedGapLog.Add(performingBoard, ourTracker);
  17.     }
  18.  
  19.     ourTracker.Log(theGapGate, performingBoard);
  20. }
  21.        
  22. protected void EvaluateGaps()
  23. {
  24.     // We iterate over the gap logs first, because if we ever optimize this, the simplest to optimize is the defined gaps (with a Dictionary), whereas this will always be an in-order iteration
  25.     foreach (KeyValuePair<ISkateboardGateway, SkateboardGapTracker> skateboardGaps in completedGapLog)
  26.     {
  27.         LinkedListNode<CompletedGapGate> tempNode = skateboardGaps.Value.gapGateLog.First;
  28.         while (tempNode != null)
  29.         {
  30.             // Now, check this against the first entry in each defined gap gate sequence
  31.             // @TODO: If anyone ever wants to optimize this, you'd do it by stuffing the sequences into a Lookup class keyed on their first gate, probably up in Awake(), buuuut I'm too lazy for that
  32.             for (int index = 0; index < namedGaps.Length; index++)
  33.             {
  34.                 GapGateSequence namedGap = namedGaps[index];
  35.                 if (namedGap.gates == null) { continue; } // (REALLY? fuck it, let's error check, but... REALLY?!)
  36.  
  37.                 bool sequenceCompleted = CheckGap(tempNode, namedGap);
  38.                 if (!sequenceCompleted && namedGap.bothWays) { sequenceCompleted = CheckGap(tempNode, namedGap, reverseOrder:true); }
  39.                        
  40.                 // If we get this far and it's positive? YAY! We did a gap!
  41.                 if (sequenceCompleted)
  42.                 {
  43.                     // @FIXME: This is where the better handling will go later, but we're gonna do a quickie test for now
  44.                     Debug.Log("Gap completed: " + namedGap.gapNameLocID);
  45.  
  46.                     // Since we've just completed a gap, let's trigger a safety purge of this skateboard's logged gaps
  47.                     tempNode = null;
  48.                     break;
  49.                 }
  50.             }
  51.  
  52.             if (tempNode != null) { tempNode = tempNode.Next; }
  53.             else
  54.             {
  55.                 // This means we found a valid gap, and should purge this skateboard's gap log to avoid repeat-detection
  56.                 skateboardGaps.Value.gapGateLog.Clear();
  57.  
  58.                 // (and then we'll still be null on tempNode and thus drop nicely out of this on next loop)
  59.             }
  60.         }
  61.     }
  62. }
  63.  
  64. protected bool CheckGap(LinkedListNode<CompletedGapGate> loggedGateNode, GapGateSequence gapSequence, bool reverseOrder = false)
  65. {
  66.     // First, figure out which way we're evaluating this gap
  67.     int gateSeqIndex = 0;
  68.     int gateSeqStep = 1;
  69.  
  70.     if (reverseOrder)
  71.     {
  72.         gateSeqIndex = gapSequence.gates.Length - 1;
  73.         gateSeqStep = -1;
  74.     }
  75.  
  76.     // Then just step through the sequence
  77.     float lastGateTime = -1f;
  78.     float gateTimeAccum = 0f;
  79.     float lastGroundedTime = -1f;
  80.     float groundedTimeAccum = 0f;
  81.     bool sequenceCompleted = true;
  82.     LinkedListNode<CompletedGapGate> tempComparisonNode = loggedGateNode;
  83.     while (gateSeqIndex < gapSequence.gates.Length && gateSeqIndex >= 0)
  84.     {
  85.         // If we run out of logged gap gates before we run out of gates in the sequence, I guess we haven't hit the gap yet
  86.         if (tempComparisonNode == null)
  87.         {
  88.             sequenceCompleted = false;
  89.             break;
  90.         }
  91.  
  92.         // Step through our logged gates until we find one that matches the next in the gate sequence - or we run out of gates
  93.         while (tempComparisonNode != null && tempComparisonNode.Value.theGapGate != gapSequence.gates[gateSeqIndex])
  94.         {
  95.             // When we start skipping nodes that don't match, it means we need to reset our sequence check to the first one in the sequence again
  96.             gateSeqIndex = reverseOrder ? gapSequence.gates.Length - 1 : 0;
  97.             gateTimeAccum = groundedTimeAccum = 0f;
  98.             lastGateTime = lastGroundedTime = -1f;
  99.  
  100.             // (this lets us handle cases where gap detections overlap, and there's a totally unrelated gap gate in the space between the two gates that define the gap we're testing for)
  101.             tempComparisonNode = tempComparisonNode.Next;
  102.  
  103.             // (the fall-through case here wraps around and catches the null check above and falses us out, easy peasy)
  104.         }
  105.  
  106.         // Assuming we still have a node / we found a node...
  107.         if (tempComparisonNode != null)
  108.         {
  109.             // Handle accumulation of properties between states
  110.             if (lastGateTime >= 0f) { gateTimeAccum += Mathf.Max(tempComparisonNode.Value.timeGapCompleted - lastGateTime, 0f); }
  111.             lastGateTime = tempComparisonNode.Value.timeGapCompleted;
  112.  
  113.             if (lastGroundedTime >= 0f) { groundedTimeAccum += Mathf.Max(tempComparisonNode.Value.groundedTime - lastGroundedTime, 0f); }
  114.             lastGroundedTime = tempComparisonNode.Value.groundedTime;
  115.  
  116.             // Neeext
  117.             tempComparisonNode = tempComparisonNode.Next;
  118.         }
  119.         gateSeqIndex += gateSeqStep;
  120.  
  121.         // If we go past one of our (assigned to something valid) limiters, that's it, the gap doesn't count anyways
  122.         if (gapSequence.maxGrounded > 0f && groundedTimeAccum > gapSequence.maxGrounded)
  123.         {
  124.             sequenceCompleted = false;
  125.             break;
  126.         }
  127.  
  128.         if (gapSequence.timeLimit > 0f && groundedTimeAccum > gapSequence.timeLimit)
  129.         {
  130.             sequenceCompleted = false;
  131.             break;
  132.         }
  133.     }
  134.  
  135.     return sequenceCompleted;
  136. }
  137.  
  138. /// <summary>
  139. /// Sweeps through the gap gate logs and removes entries too old to matter anymore
  140. /// </summary>
  141. protected void PruneGapGateLogs()
  142. {
  143.     foreach(KeyValuePair<ISkateboardGateway, SkateboardGapTracker> skateboardGaps in completedGapLog)
  144.     {
  145.         LinkedListNode<CompletedGapGate> headNode = skateboardGaps.Value.gapGateLog.First;
  146.         while(headNode != null && Time.timeSinceLevelLoad - headNode.Value.timeGapCompleted >= GapCompletionTimeout)
  147.         {
  148.             skateboardGaps.Value.gapGateLog.RemoveFirst();
  149.             headNode = skateboardGaps.Value.gapGateLog.First;
  150.         }
  151.     }
  152. }
  153.  
  154. protected class SkateboardGapTracker
  155. {
  156.     public LinkedList<CompletedGapGate> gapGateLog = new LinkedList<CompletedGapGate>();
  157.            
  158.     public CompletedGapGate Log(GapGateZone theGapGate, ISkateboardGateway performingBoard)
  159.     {
  160.         CompletedGapGate newGapGate = null;
  161.  
  162.         // First, check the very last node. If it's for this gap gate (ie. a repeat trigger), we just update it
  163.         LinkedListNode<CompletedGapGate> logNode = gapGateLog.Last;
  164.         if (logNode != null && logNode.Value.theGapGate == theGapGate)
  165.         {
  166.             newGapGate = logNode.Value;
  167.         }
  168.         // Otherwise, we create a new one and add it to the end
  169.         else
  170.         {
  171.             newGapGate = new CompletedGapGate();
  172.             gapGateLog.AddLast(newGapGate);
  173.         }
  174.  
  175.         // Either way, update/set the args, and we're done!
  176.         newGapGate.theGapGate = theGapGate;
  177.         newGapGate.timeGapCompleted = Time.timeSinceLevelLoad;
  178.         newGapGate.groundedTime = performingBoard.Movement.TotalTimeGrounded;
  179.                
  180.         return newGapGate;
  181.     }
  182. }
  183.  
  184. protected class CompletedGapGate
  185. {
  186.     public GapGateZone theGapGate;
  187.     public float timeGapCompleted = -1f;
  188.     public float groundedTime = -1f;
  189. }
  190.  
  191. [System.Serializable]
  192. protected class GapGateSequence
  193. {
  194.     public string gapNameLocID;
  195.     public float score;
  196.     public bool bothWays = true;
  197.     public float timeLimit = -1f;
  198.     public float maxGrounded = -1f;
  199.     public GapGateZone[] gates;
  200. }
  201. #endregion
  202.  
  203. #region Console Command Defs
  204. [ConsoleCommand]
  205. static protected string SkipMission()
  206. {
  207.     singleton.skipThisMission = true;
  208.     return "Skipping current mission";
  209. }
  210. #endregion
Advertisement
Add Comment
Please, Sign In to add comment