From c6b19076c0c9673a91d49f4828479021e3415305 Mon Sep 17 00:00:00 2001
From: MaZiFAU <marco.alexander.zimmer@fau.de>
Date: Wed, 31 Aug 2022 21:56:48 +0200
Subject: [PATCH] + Added AllowedGadgets in Stage; + Redone Gadget Logging;

---
 Assets/Scripts/GenerateDemoFiles.cs           |   8 +-
 Assets/Scripts/GlobalBehaviour.cs             |   9 +-
 .../InteractionEngine/FactHandling/Fact.cs    |   2 +-
 .../FactHandling/FactManager.cs               |  16 +-
 .../FactHandling/FactOrganizer.cs             | 145 +++++++++---------
 .../InteractionEngine/Gadgets/AngleTool.cs    |   7 +-
 .../InteractionEngine/Gadgets/Gadget.cs       |  91 ++++++++---
 .../Gadgets/GadgetManager.cs                  |  18 ++-
 .../InteractionEngine/Gadgets/LineTool.cs     |   7 +-
 .../InteractionEngine/Gadgets/LotTool.cs      |   7 +-
 .../InteractionEngine/Gadgets/Pendulum.cs     |   4 +
 .../InteractionEngine/Gadgets/Pointer.cs      |   4 +
 .../InteractionEngine/Gadgets/PoleTool.cs     |   4 +
 .../InteractionEngine/Gadgets/Remover.cs      |   6 +-
 .../Scripts/InteractionEngine/Gadgets/Tape.cs |   4 +
 Assets/Scripts/Loading/Stage.cs               |  31 ++--
 Assets/Stages/TechDemo A.JSON                 |   2 +-
 Assets/Stages/TechDemo B.JSON                 |   2 +-
 18 files changed, 235 insertions(+), 132 deletions(-)

diff --git a/Assets/Scripts/GenerateDemoFiles.cs b/Assets/Scripts/GenerateDemoFiles.cs
index 6203e440..cf03341e 100644
--- a/Assets/Scripts/GenerateDemoFiles.cs
+++ b/Assets/Scripts/GenerateDemoFiles.cs
@@ -1,4 +1,4 @@
-using System.Collections;
+using System.Linq;
 using System.Collections.Generic;
 using UnityEngine;
 using static CommunicationEvents;
@@ -57,6 +57,9 @@ public static void GenerateDemoA()
             new List<SolutionOrganizer.SubSolution>
             { new SolutionOrganizer.SubSolution(new HashSet<string> { target_Id }, null, null, new LineFactHightDirectionComparer()) };
 
+        // Set Gadgets
+        StageStatic.stage.AllowedGadgets = null;
+
         // Save
         StageStatic.SetMode(StageStatic.Mode.Create);
         StageStatic.stage.store();
@@ -106,6 +109,9 @@ public static void GenerateDemoB()
                 new SolutionOrganizer.SubSolution(null, new List<int> { 1 }, new List<int> { 0 }, new LineFactHightComparer()),
             };
 
+        // Set Gadgets
+        StageStatic.stage.AllowedGadgets = new() { new Pointer(), new Tape(), new AngleTool(), new LineTool(), new LotTool(), new Pendulum(), new Remover() };
+
         // Save
         StageStatic.SetMode(StageStatic.Mode.Create);
         StageStatic.stage.store();
diff --git a/Assets/Scripts/GlobalBehaviour.cs b/Assets/Scripts/GlobalBehaviour.cs
index e60f48d7..b99b7145 100644
--- a/Assets/Scripts/GlobalBehaviour.cs
+++ b/Assets/Scripts/GlobalBehaviour.cs
@@ -36,9 +36,6 @@ public class GlobalBehaviour : MonoBehaviour
 
     void Awake()
     {
-
-        // GenerateDemoFiles.GenerateAll();
-
         hintAnimationStartColor = _hintAnimationStartColor;
         hintAnimationEndColor = _hintAnimationEndColor;
         hintAnimationDuration = _hintAnimationDuration;
@@ -50,8 +47,12 @@ void Awake()
         GadgetLaserDistance = _GadgetLaserDistance;
         GadgetPhysicalDistance = _GadgetPhysicalDistance;
 
+        //DontDestroyOnLoad(gameObject);
+    }
 
+    private void Start()
+    {
+        //GenerateDemoFiles.GenerateAll();
         StageStatic.ShallowLoadStages();
-        //DontDestroyOnLoad(gameObject);
     }
 }
diff --git a/Assets/Scripts/InteractionEngine/FactHandling/Fact.cs b/Assets/Scripts/InteractionEngine/FactHandling/Fact.cs
index 4b9ef857..347c8c6c 100644
--- a/Assets/Scripts/InteractionEngine/FactHandling/Fact.cs
+++ b/Assets/Scripts/InteractionEngine/FactHandling/Fact.cs
@@ -125,7 +125,7 @@ public string Id {
     /// </value>
     public string Label {
         get { // in case of renamed dependables
-            return (_Facts.FactDict.Count == 0 && this is not PointFact) // JsonSerialization toggle && allow first (Point)Fact to be created
+            return (_Facts.GetNumberOfFacts() == 0 && this is not PointFact) // JsonSerialization toggle && allow first (Point)Fact to be created
                 || (hasCustomLabel && _CustomLabel != null) 
                 ? _CustomLabel
                 : generateLabel();
diff --git a/Assets/Scripts/InteractionEngine/FactHandling/FactManager.cs b/Assets/Scripts/InteractionEngine/FactHandling/FactManager.cs
index f299c9a5..dec8045d 100644
--- a/Assets/Scripts/InteractionEngine/FactHandling/FactManager.cs
+++ b/Assets/Scripts/InteractionEngine/FactHandling/FactManager.cs
@@ -16,12 +16,12 @@ public static class FactManager
     /// <param name="fact">to be added</param>
     /// <param name="exists"><c>true</c> iff <paramref name="fact"/> already has a equivalent counterpart in <paramref name="fact._Facts"/></param>
     /// \copydetails FactManager
-    public static Fact AddFactIfNotFound(Fact fact, out bool exists, bool samestep, Type gadget, string scroll_label)
+    public static Fact AddFactIfNotFound(Fact fact, out bool exists, bool samestep, Gadget gadget, string scroll_label)
     {
         return StageStatic.stage.factState[
             StageStatic.stage.factState.Add(
                 fact, out exists, samestep
-                , gadget ?? (scroll_label == null ? GadgetManager.ActiveGadgetInd.GetType() : null)
+                , gadget ?? (scroll_label == null ? GadgetManager.ActiveGadget : null)
                 , scroll_label
             )];
     }
@@ -29,7 +29,7 @@ public static Fact AddFactIfNotFound(Fact fact, out bool exists, bool samestep,
     /// \copybrief FactManager <summary></summary>
     /// <param name="hit"><c>RaycastHit</c> where and how (orientation) to spawn <see cref="PointFact"/></param>
     /// \copydetails FactManager
-    public static PointFact AddPointFact(RaycastHit hit, bool samestep = false, Type gadget = null, string scroll_label = null)
+    public static PointFact AddPointFact(RaycastHit hit, bool samestep = false, Gadget gadget = null, string scroll_label = null)
     {
         return (PointFact) AddFactIfNotFound(
             new PointFact(hit.point, hit.normal, StageStatic.stage.factState)
@@ -40,7 +40,7 @@ public static PointFact AddPointFact(RaycastHit hit, bool samestep = false, Type
     /// <param name="point">where to spawn <see cref="PointFact"/></param>
     /// <param name="normal">how (orientation) to spawn <see cref="PointFact"/></param>
     /// \copydetails FactManager
-    public static PointFact AddPointFact(Vector3 point, Vector3 normal, bool samestep = false, Type gadget = null, string scroll_label = null)
+    public static PointFact AddPointFact(Vector3 point, Vector3 normal, bool samestep = false, Gadget gadget = null, string scroll_label = null)
     {
         return (PointFact) AddFactIfNotFound(
             new PointFact(point, normal, StageStatic.stage.factState)
@@ -51,7 +51,7 @@ public static PointFact AddPointFact(Vector3 point, Vector3 normal, bool sameste
     /// <param name="pid"><see cref="Fact.Id"/> of <see cref="PointFact"/> which lies on <paramref name="lid"/></param>
     /// <param name="lid"><see cref="Fact.Id"/> of <see cref="LineFact"/> on which <paramref name="pid"/> lies</param>
     /// \copydetails FactManager
-    public static OnLineFact AddOnLineFact(string pid, string lid, bool samestep = false, Type gadget = null, string scroll_label = null)
+    public static OnLineFact AddOnLineFact(string pid, string lid, bool samestep = false, Gadget gadget = null, string scroll_label = null)
     {
         return (OnLineFact)AddFactIfNotFound(
             new OnLineFact(pid, lid, StageStatic.stage.factState)
@@ -62,7 +62,7 @@ public static OnLineFact AddOnLineFact(string pid, string lid, bool samestep = f
     /// <param name="pid1"><see cref="Fact.Id"/> of first <see cref="PointFact"/> defining a <see cref="LineFact"/></param>
     /// <param name="pid2"><see cref="Fact.Id"/> of second <see cref="PointFact"/> defining a <see cref="LineFact"/></param>
     /// \copydetails FactManager
-    public static LineFact AddLineFact(string pid1, string pid2, bool samestep = false, Type gadget = null, string scroll_label = null)
+    public static LineFact AddLineFact(string pid1, string pid2, bool samestep = false, Gadget gadget = null, string scroll_label = null)
     {
         return (LineFact)AddFactIfNotFound(
             new LineFact(pid1, pid2, StageStatic.stage.factState)
@@ -76,7 +76,7 @@ public static LineFact AddLineFact(string pid1, string pid2, bool samestep = fal
     /// <param name="pid1"><see cref="Fact.Id"/> of first <see cref="PointFact"/> defining a <see cref="RayFact"/></param>
     /// <param name="pid2"><see cref="Fact.Id"/> of second <see cref="PointFact"/> defining a <see cref="RayFact"/></param>
     /// \copydetails FactManager
-    public static RayFact AddRayFact(string pid1, string pid2, bool samestep = false, Type gadget = null, string scroll_label = null)
+    public static RayFact AddRayFact(string pid1, string pid2, bool samestep = false, Gadget gadget = null, string scroll_label = null)
     {
         RayFact rayFact = (RayFact)AddFactIfNotFound(
             new RayFact(pid1, pid2, StageStatic.stage.factState)
@@ -119,7 +119,7 @@ void AddHitIfOnLine(RaycastHit hit)
     /// <param name="pid2"><see cref="Fact.Id"/> of second <see cref="PointFact"/> defining a <see cref="AngleFact"/></param>
     /// <param name="pid3"><see cref="Fact.Id"/> of third <see cref="PointFact"/> defining a <see cref="AngleFact"/></param>
     /// \copydetails FactManager
-    public static AngleFact AddAngleFact(string pid1, string pid2, string pid3, bool samestep = false, Type gadget = null, string scroll_label = null)
+    public static AngleFact AddAngleFact(string pid1, string pid2, string pid3, bool samestep = false, Gadget gadget = null, string scroll_label = null)
     {
         return (AngleFact)AddFactIfNotFound(
             new AngleFact(pid1, pid2, pid3, StageStatic.stage.factState)
diff --git a/Assets/Scripts/InteractionEngine/FactHandling/FactOrganizer.cs b/Assets/Scripts/InteractionEngine/FactHandling/FactOrganizer.cs
index db02c11b..8307c441 100644
--- a/Assets/Scripts/InteractionEngine/FactHandling/FactOrganizer.cs
+++ b/Assets/Scripts/InteractionEngine/FactHandling/FactOrganizer.cs
@@ -20,31 +20,43 @@
 /// </summary>
 public class FactOrganizer : IJSONsavable<FactOrganizer>
 {
+    /// <summary>
+    /// - <c>Key</c>: <see cref="Gadget"/> Used Gadget
+    /// - <c>Value</c>: <see cref="int"/> First occurence of gadget in Workflow
+    /// </summary>
+    protected Dictionary<Gadget, int> GadgetWorkflowDict = new();
+    /// <summary>
+    /// - <c>Key</c>: <see cref="int"/> First occurence of gadget in Workflow
+    /// - <c>Value</c>: <see cref="Gadget"/> Used Gadget
+    /// </summary>
+    [JsonProperty]
+    protected Dictionary<int, Gadget> WorkflowGadgetDict = new() { {-1, null } };
+
     /// <summary>
     /// - <c>Key</c>: <see cref="Fact.Id"/>
     /// - <c>Value</c>: <see cref="Fact"/>
     /// </summary>
     [JsonProperty]
-    protected internal Dictionary<string, Fact> FactDict;
+    protected Dictionary<string, Fact> FactDict;
 
     /// <summary>
     /// - <c>Key</c>: <see cref="Fact.Id"/>
     /// - <c>Value</c>: <see cref="meta"/>
     /// </summary>
     [JsonProperty]
-    protected internal Dictionary<string, meta> MetaInf = new();
+    protected Dictionary<string, meta> MetaInf = new();
 
     /// <summary>
     /// Keeps track of insertion/ deletion/ etc. operations for <see cref="undo"/> and <see cref="redo"/>
     /// </summary>
     [JsonProperty]
-    protected internal List<stepnote> Workflow = new();
+    protected List<stepnote> Workflow = new();
 
     /// <summary>
     /// Notes position in <see cref="Workflow"/> for <see cref="undo"/> and <see cref="redo"/>; the pointed to element is non-acitve
     /// </summary>
     [JsonProperty]
-    protected internal int marker = 0;
+    protected int marker = 0;
 
     /// <summary>
     /// Backlock logic redundant - for convinience.
@@ -53,7 +65,7 @@ public class FactOrganizer : IJSONsavable<FactOrganizer>
     /// <seealso cref="stepnote"/>
     /// </summary>
     [JsonProperty]
-    protected internal int worksteps = 0;
+    protected int worksteps = 0;
     /// <summary>
     /// Backlock logic redundant - for convinience.
     /// Keeps track of number of steps in <see cref="Workflow"/>, which are not set active.
@@ -61,13 +73,13 @@ public class FactOrganizer : IJSONsavable<FactOrganizer>
     /// <seealso cref="stepnote"/>
     /// </summary>
     [JsonProperty]
-    protected internal int backlog = 0;
+    protected int backlog = 0;
 
     /// <summary>
     /// Set to <c>true</c> if recently been resetted.
     /// </summary>
     [JsonProperty]
-    protected internal bool soft_resetted = false;
+    protected bool soft_resetted = false;
 
     /// <summary>
     /// If set to <c>true</c>, <see cref="Remove(string, bool)"/> and <see cref="Add(Fact, out bool, bool)"/> will invoke <see cref="CommunicationEvents.RemoveFactEvent"/> and <see cref="CommunicationEvents.AddFactEvent"/> respectively.
@@ -126,6 +138,18 @@ protected internal struct stepnote
         /// <summary> distincts creation and deletion </summary>
         public bool creation;
 
+        /// <summary>
+        /// keeps track with wich <see cref="Gadget"/> the <see cref="Fact"/> is created
+        /// <c>-1</c> iff its not the case
+        /// </summary>
+        public int gadget_rank;
+
+        /// <summary>
+        /// keeps track with wich <see cref="Scroll"/> the <see cref="Fact"/> is created
+        /// <c>null</c> iff its not the case
+        /// </summary>
+        public string scroll_label;
+
 
         /// <summary>
         /// Initiator
@@ -134,11 +158,12 @@ protected internal struct stepnote
         /// <param name="samestep">sets <see cref="samestep"/></param>
         /// <param name="creation">sets <see cref="creation"/></param>
         /// <param name="that"><see cref="FactOrganizer"/> of which <c>this</c> will be added in its <see cref="FactOrganizer.Workflow"/></param>
-        public stepnote(string Id, bool samestep, bool creation, FactOrganizer that)
+        public stepnote(FactOrganizer that, string Id, bool samestep, bool creation, Gadget gadget, string scroll_label)
         {
             this.Id = Id;
             this.samestep = samestep;
             this.creation = creation;
+            this.scroll_label = scroll_label;
 
             if (samestep)
             // steplink = !first_steptail ? previous.steplink : steproot
@@ -150,6 +175,15 @@ public stepnote(string Id, bool samestep, bool creation, FactOrganizer that)
                 // steproot sets steplink after itself (end of steptail)
                 this.steplink = that.marker + 1;
 
+            if (gadget == null)
+                this.gadget_rank = -1;
+            else {
+                if (!that.GadgetWorkflowDict.ContainsKey(gadget)) {
+                    that.GadgetWorkflowDict.Add(gadget, that.MetaInf[Id].workflow_id);
+                    that.WorkflowGadgetDict.Add(that.MetaInf[Id].workflow_id, gadget);
+                }
+                this.gadget_rank = that.GadgetWorkflowDict[gadget];
+            }
         }
     }
 
@@ -171,37 +205,15 @@ protected internal struct meta
         /// </summary>
         public bool active;
 
-        /// <summary>
-        /// keeps track with wich <see cref="Gadget"/> the <see cref="Fact"/> is created
-        /// <c>null</c> iff its not the case
-        /// </summary>
-        public Type gadget {
-            get => _gadget;
-            set => _gadget = 
-                value == null ? null : 
-                Gadget.GadgetTypes.Contains(value) ? value : 
-                typeof(Gadget.UndefinedGadget);
-        }
-        private Type _gadget;
-
-        /// <summary>
-        /// keeps track with wich <see cref="Scroll"/> the <see cref="Fact"/> is created
-        /// <c>null</c> iff its not the case
-        /// </summary>
-        public string scroll_label;
-
         /// <summary>
         /// Initiator
         /// </summary>
         /// <param name="workflow_id">sets <see cref="workflow_id"/></param>
         /// <param name="active">sets <see cref="active"/></param>
-        public meta(int workflow_id, bool active, Type gadget, string scroll_label)
+        public meta(int workflow_id, bool active)
         {
             this.workflow_id = workflow_id;
             this.active = active;
-            this.scroll_label = scroll_label;
-            _gadget = null; //Compiler Restriction
-            this.gadget = gadget;
         }
     }
 
@@ -276,13 +288,13 @@ public static T ReInitializeFactOrganizer<T>
                     old_to_new.Add(sn.Id, add.Id);
                 }
 
-                target.Add(add, out _, sn.samestep, source.MetaInf[sn.Id].gadget, source.MetaInf[sn.Id].scroll_label);
+                target.Add(add, out _, sn.samestep, source.WorkflowGadgetDict[sn.gadget_rank], sn.scroll_label);
             }
             else if (old_to_new.ContainsKey(sn.Id))
             // Remove
             {
                 Fact remove = target.FactDict[old_to_new[sn.Id]];
-                target.Remove(remove, sn.samestep);
+                target.Remove(remove, sn.samestep, source.WorkflowGadgetDict[sn.gadget_rank]);
             }
         }
 
@@ -301,20 +313,14 @@ public static T ReInitializeFactOrganizer<T>
     /// </summary>
     /// <param name="id">a <see cref="Fact.Id"/> in <see cref="FactDict"/></param>
     /// <returns><c><see cref="FactDict"/>[<paramref name="id"/>]</c></returns>
-    public Fact this[string id]
-    {
-        get { return FactDict[id]; }
-    }
+    public Fact this[string id] { get => FactDict[id]; }
 
     /// <summary>
     /// wrappes <c><see cref="FactDict"/>.ContainsKey(<paramref name="id"/>)</c>
     /// </summary>
     /// <param name="id">a <see cref="Fact.Id"/></param>
     /// <returns><c><see cref="FactDict"/>.ContainsKey(<paramref name="id"/>)</c></returns>
-    public bool ContainsKey(string id)
-    {
-        return FactDict.ContainsKey(id);
-    }
+    public bool ContainsKey(string id) => FactDict.ContainsKey(id);
 
     /// <summary>
     /// Looks up if there is a <paramref name="label"/> <see cref="Fact.Label"/> in <see cref="FactDict"/>.Values
@@ -366,7 +372,7 @@ private bool FindEquivalent(Fact search, out string found, out bool exact)
     /// <param name="note">to be added</param>
     private void WorkflowAdd(stepnote note)
     {
-        PruneWorkflow();
+        PruneWorkflow(note);
 
         if (note.samestep)
         // update steplink of steproot
@@ -388,7 +394,7 @@ private void WorkflowAdd(stepnote note)
     /// set current (displayed) state in stone, a.k.a. <see cref="Fact.delete(bool)">delete</see> non <see cref="meta.active"/> <see cref="Fact">Facts</see> for good;
     /// resets <see cref="undo">un</see>-<see cref="redo"/> parameters
     /// </summary>
-    private void PruneWorkflow()
+    private void PruneWorkflow(stepnote not_me)
     {
         /*if (soft_resetted)
             this.hardreset(false); // musn't clear
@@ -404,7 +410,14 @@ private void PruneWorkflow()
             {
                 stepnote last = Workflow[i];
 
-                if (last.creation // may be zombie
+                if (last.gadget_rank == MetaInf[last.Id].workflow_id
+                 && last.gadget_rank != not_me.gadget_rank) 
+                {   // Remove Gadget, if its the first time it's beeing used
+                    GadgetWorkflowDict.Remove(WorkflowGadgetDict[last.gadget_rank]);
+                    WorkflowGadgetDict.Remove(last.gadget_rank);
+                }
+
+                if (last.Id != not_me.Id // may be zombie
                  && MetaInf[last.Id].workflow_id == i)
                 // remove for good, if original creation gets pruned
                 {
@@ -428,7 +441,7 @@ private void PruneWorkflow()
     /// <param name="samestep">set <c>true</c> if <see cref="Fact"/> creation happens as a subsequent/ consequent step of multiple <see cref="Fact"/> creations and/or deletions, 
     /// and you whish that these are affected by a single <see cref="undo"/>/ <see cref="redo"/> step</param>
     /// <returns><see cref="Fact.Id"/> of <paramref name="value"/> or <see cref="FindEquivalent(Fact, out string, out bool)">found</see> <see cref="Fact"/> iff <paramref name="exists"/>==<c>true</c></returns>
-    public string Add(Fact value, out bool exists, bool samestep, Type gadget, string scroll_label)
+    public string Add(Fact value, out bool exists, bool samestep, Gadget gadget, string scroll_label)
     {
         soft_resetted = false;
 #pragma warning disable IDE0018 // Inlinevariablendeklaration
@@ -445,16 +458,9 @@ public string Add(Fact value, out bool exists, bool samestep, Type gadget, strin
                 // desired outcome already achieved
                 return key;
 
-            if (MetaInf[key].workflow_id >= marker)
-            // check for zombie-status: everything >= marker will be pruned
-            {
-                // protect zombie from beeing pruned
-                stepnote zombie = Workflow[MetaInf[key].workflow_id];
-                zombie.creation = false; // this stepnote entry will be deleted, but will not trigger deletion
-                Workflow[MetaInf[key].workflow_id] = zombie;
-                // set new init location
-                MetaInf[key] = new meta(marker, true, gadget, scroll_label);
-            }
+            if (MetaInf[key].workflow_id > marker)
+                // update meta data: everything >= marker will be pruned (except this Fact)
+                MetaInf[key] = new meta(marker, true);
 
         }
         else
@@ -462,10 +468,10 @@ public string Add(Fact value, out bool exists, bool samestep, Type gadget, strin
         {
             key = value.Id;
             FactDict.Add(key, value);
-            MetaInf.Add(key, new meta(marker, true, gadget, scroll_label));
+            MetaInf.Add(key, new meta(marker, true));
         }
 
-        WorkflowAdd(new stepnote(key, samestep, true, this));
+        WorkflowAdd(new stepnote(this, key, samestep, true, gadget, scroll_label));
         return key;
     }
 
@@ -478,8 +484,8 @@ public string Add(Fact value, out bool exists, bool samestep, Type gadget, strin
     /// <param name="samestep">set <c>true</c> if <see cref="Fact"/> deletion happens as a subsequent/ consequent step of multiple <see cref="Fact"/> creations and/or deletions, 
     /// and you whish that these are affected by a single <see cref="undo"/>/ <see cref="redo"/> step</param>
     /// <returns><c>true</c> iff <paramref name="value"/><see cref="Fact.Id">.Id</see> was found.</returns>
-    public bool Remove(Fact value, bool samestep = false)
-        => this.Remove(value.Id, samestep);
+    public bool Remove(Fact value, bool samestep, Gadget gadget)
+        => this.Remove(value.Id, samestep, gadget);
 
     /// \copybrief Remove(Fact, bool)
     /// <remarks>this will not <see cref="Fact.delete(bool)">delete</see> a <see cref="Fact"/>, but sets it <see cref="meta.active">inactive</see> for later <see cref="Fact.delete(bool)">deletion</see> when <see cref="PruneWorkflow">pruned</see>.</remarks>
@@ -487,7 +493,7 @@ public bool Remove(Fact value, bool samestep = false)
     /// <param name="samestep">set <c>true</c> if <see cref="Fact"/> deletion happens as a subsequent/ consequent step of multiple <see cref="Fact"/> creations and/or deletions, 
     /// and you whish that these are affected by a single <see cref="undo"/>/ <see cref="redo"/> step</param>
     /// <returns><c>true</c> iff <paramref name="value"/> was found.</returns>
-    public bool Remove(string key, bool samestep = false)
+    public bool Remove(string key, bool samestep, Gadget gadget)
     //no reset check needed (impossible state)
     {
         if (!FactDict.ContainsKey(key))
@@ -503,7 +509,7 @@ public bool Remove(string key, bool samestep = false)
 
         if (deletethis.Count > 0)
         {
-            yeetusdeletus(deletethis, samestep);
+            yeetusdeletus(deletethis, samestep, gadget);
         }
 
         return true;
@@ -551,11 +557,11 @@ public bool safe_dependencies(string key, out List<string> dependencies)
     /// </summary>
     /// <param name="deletereverse">to be <see cref="Remove(string, bool)">removed</see>, but without checking for (recursive) dependencies</param>
     /// <param name="samestep">see <see cref="Remove(string, bool).samestep"/>. Only applies to last (first iteration) element of <paramref name="deletereverse"/>; for everything else <paramref name="samestep"/> will be set to <c>true</c>.</param>
-    private void yeetusdeletus(List<string> deletereverse, bool samestep = false)
+    private void yeetusdeletus(List<string> deletereverse, bool samestep, Gadget gadget)
     {
         for (int i = deletereverse.Count - 1; i >= 0; i--, samestep = true)
         {
-            WorkflowAdd(new stepnote(deletereverse[i], samestep, false, this));
+            WorkflowAdd(new stepnote(this, deletereverse[i], samestep, false, gadget, null));
         }
     }
 
@@ -577,9 +583,9 @@ private void reversestep(int pos, bool samestep = false)
             i >= stop; i--, samestep = true)
         {
             if (Workflow[i].creation)
-                Remove(Workflow[i].Id, samestep);
+                Remove(Workflow[i].Id, samestep, null);
             else if (!MetaInf[Workflow[i].Id].active)
-                WorkflowAdd(new stepnote(Workflow[i].Id, samestep, true, this));
+                WorkflowAdd(new stepnote(this, Workflow[i].Id, samestep, true, null, null));
         }
     }
 
@@ -832,14 +838,15 @@ public bool DynamiclySolved(
         return MissingElementsCount == 0;
     }
 
-    public IEnumerable<Type> GetUsedGadgets()
-        => MetaInf.Values.Where(inf => inf.active & inf.gadget != null).Select(inf => inf.gadget).Distinct();
+    public IEnumerable<Gadget> GetUsedGadgets() => GadgetWorkflowDict.Keys;
 
-    public int GetNumberOfGadgets() => GetUsedGadgets().Count();
+    public int GetNumberOfGadgets() => GadgetWorkflowDict.Count;
     
     public IEnumerable<string> GetUsedScrolls()
-        => MetaInf.Values.Where(inf => inf.active && inf.scroll_label != null).Select(inf => inf.scroll_label).Distinct();
+        => Workflow.Where(sn => MetaInf[sn.Id].active && sn.scroll_label != null).Select(sn => sn.scroll_label).Distinct();
 
     public int GetNumberOfScrolls() => GetUsedScrolls().Count();
 
+    public int GetNumberOfFacts() => FactDict.Count;
+
 }
\ No newline at end of file
diff --git a/Assets/Scripts/InteractionEngine/Gadgets/AngleTool.cs b/Assets/Scripts/InteractionEngine/Gadgets/AngleTool.cs
index ec80cebd..330f60ee 100644
--- a/Assets/Scripts/InteractionEngine/Gadgets/AngleTool.cs
+++ b/Assets/Scripts/InteractionEngine/Gadgets/AngleTool.cs
@@ -1,7 +1,12 @@
-using UnityEngine;
+using Newtonsoft.Json;
+using UnityEngine;
 
 public class AngleTool : Gadget
 {
+    /// \copydoc Gadget.s_type
+    [JsonProperty]
+    protected static new string s_type = "AngleTool";
+
     //Variables for AngleMode distinction
     private int PointNr = 0;
     private readonly PointFact[] AnglePoints = new PointFact[3];
diff --git a/Assets/Scripts/InteractionEngine/Gadgets/Gadget.cs b/Assets/Scripts/InteractionEngine/Gadgets/Gadget.cs
index 7e3beb99..ae69b469 100644
--- a/Assets/Scripts/InteractionEngine/Gadgets/Gadget.cs
+++ b/Assets/Scripts/InteractionEngine/Gadgets/Gadget.cs
@@ -1,4 +1,5 @@
-using Newtonsoft.Json;
+using JsonSubTypes;
+using Newtonsoft.Json;
 using System;
 using System.Collections.Generic;
 using System.Linq;
@@ -9,8 +10,26 @@
 /// Base class for all Gadgets to derive from.
 /// A Gadget is a tool for the player (and level editor) to interact with the GameWorld.
 /// </summary>
+[JsonConverter(typeof(JsonSubtypes), "s_type")]
+[JsonSubtypes.KnownSubType(typeof(Pointer), "Pointer")]
+[JsonSubtypes.KnownSubType(typeof(Tape), "Tape")]
+[JsonSubtypes.KnownSubType(typeof(LineTool), "LineTool")]
+[JsonSubtypes.KnownSubType(typeof(LotTool), "LotTool")]
+[JsonSubtypes.KnownSubType(typeof(AngleTool), "AngleTool")]
+[JsonSubtypes.KnownSubType(typeof(Pendulum), "Pendulum")]
+[JsonSubtypes.KnownSubType(typeof(PoleTool), "PoleTool")]
+[JsonSubtypes.KnownSubType(typeof(Remover), "Remover")]
+[JsonSubtypes.FallBackSubType(typeof(UndefinedGadget))]
 public abstract class Gadget
 {
+    /// <value>
+    /// [ClassName] for JSON de-/serialization.
+    /// Set in every non-abstract subclass of Gadget.
+    /// Also add JsonSubtypes.KnownSubType attribute for deserialization to Gadget!
+    /// </value>
+    [JsonProperty]
+    protected static /*new*/ string s_type = "ERROR: set s_type in T:Gadget"; // In the subtype! NOT here!
+
     /// <summary>Used to map to a T:Gadget </summary>
     /// <remarks>Do NOT rename elements! Do NOT change values! Deserialization relies on it!</remarks>
     public enum GadgetIDs
@@ -40,24 +59,24 @@ public enum GadgetIDs
 
     /// <summary> Position in tool belt. </summary>
     /// <remarks>Set in Inspector or <see cref="Awake"/></remarks>
-    public int Rank;
+    public int Rank = int.MinValue;
     /// <summary> Tool Name </summary>
     /// <remarks>Set in Inspector or <see cref="Awake"/></remarks>
-    public string UiName;
+    public string UiName = null;
     /// <summary> Maximum range for this Tool. For consistency use GadgetDistances in <see cref="GlobalBehaviour"/>.</summary>
     /// <remarks>Set in Inspector or <see cref="Awake"/></remarks>
-    public float MaxRange;
-    public float MaxHeight;
+    public float MaxRange = float.NegativeInfinity;
+    public float MaxHeight = float.NegativeInfinity;
 
     /// <summary>Which sprite to use</summary>
-    public int ButtonIndx;
-    public int MaterialIndx;
+    public int ButtonIndx = -1;
+    public int MaterialIndx = -1;
     /// <summary>Layers to ignore for this gadget by default.</summary>
     /// <remarks>Set in Inspector</remarks>
-    public LayerMask IgnoreLayerMask;
-    public LayerMask SecondaryLayerMask;
+    public LayerMask IgnoreLayerMask = -1;
+    public LayerMask SecondaryLayerMask = -1;
 
-    //protected List<Vector3> LinePositions = new();
+    private bool init_success = false;
 
     /// <summary>
     /// Collection of <c>Type</c>s of *all* available <see cref="Gadget"/>s to choose from.
@@ -67,33 +86,59 @@ public enum GadgetIDs
 
     public Gadget()
     {
+        Init(true);
+    }
+
+    public void Init(bool overrite)
+    {
+        if ( init_success
+          || GadgetManager.DataContainerGadgetDict == null)
+            return;
+
         Type this_type = this.GetType();
-        if (!GadgetTypeToIDs.ContainsKey(this_type)) {
+        if (!GadgetTypeToIDs.ContainsKey(this_type))
+        {
             Debug.LogError("No " + this_type.ToString() + "in Dictionary<Type, GadgetIDs> GadgetTypeToIDs!");
             return;
         }
         var GadgetID = GadgetTypeToIDs[this_type];
 
-        if (!GadgetManager.DataContainerGadgetDict.ContainsKey(GadgetID)) {
-            Debug.LogError("No " + GadgetID.ToString() + "in assigned "+ typeof(DataContainerGadgetCollection).Name +"!");
+        if (!GadgetManager.DataContainerGadgetDict.ContainsKey(GadgetID))
+        {
+            Debug.LogError("No " + GadgetID.ToString() + "in assigned " + typeof(DataContainerGadgetCollection).Name + "!");
             return;
         }
         var data_cache = GadgetManager.DataContainerGadgetDict[GadgetID];
 
-        Rank = data_cache.Rank;
-        UiName = data_cache.UiName;
-        MaxRange = data_cache.MaxRange;
-        MaxHeight = data_cache.MaxHeight;
-        IgnoreLayerMask = data_cache.IgnoreLayerMask;
-        SecondaryLayerMask = data_cache.SecondaryLayerMask;
-        ButtonIndx = data_cache.ButtonIndx < GadgetManager.ButtonSprites.Length
-            ? data_cache.ButtonIndx : 0;
-        MaterialIndx = data_cache.MaterialIndx < GadgetManager.Materials.Length
-            ? data_cache.MaterialIndx : 0;
+        if (overrite || Rank == int.MinValue)
+            Rank = data_cache.Rank;
+        if (overrite || UiName == null)
+            UiName = data_cache.UiName;
+        if (overrite || MaxRange == float.NegativeInfinity)
+            MaxRange = data_cache.MaxRange;
+        if (overrite || MaxHeight == float.NegativeInfinity)
+            MaxHeight = data_cache.MaxHeight;
+        if (overrite || IgnoreLayerMask == -1)
+            IgnoreLayerMask = data_cache.IgnoreLayerMask;
+        if (overrite || SecondaryLayerMask == -1)
+            SecondaryLayerMask = data_cache.SecondaryLayerMask;
+        if (overrite || ButtonIndx < 0)
+            ButtonIndx = 
+                data_cache.ButtonIndx < GadgetManager.ButtonSprites.Length
+             && data_cache.ButtonIndx >= 0
+                ? data_cache.ButtonIndx : 0;
+        if (overrite || MaterialIndx < 0)
+            MaterialIndx = 
+                data_cache.MaterialIndx < GadgetManager.Materials.Length 
+             && data_cache.MaterialIndx >= 0
+                ? data_cache.MaterialIndx : 0;
+
+        init_success = true;
     }
 
     public void Awake()
     {
+        Init(false);
         _Awake();
     }
 
diff --git a/Assets/Scripts/InteractionEngine/Gadgets/GadgetManager.cs b/Assets/Scripts/InteractionEngine/Gadgets/GadgetManager.cs
index 2882016c..04dd41f3 100644
--- a/Assets/Scripts/InteractionEngine/Gadgets/GadgetManager.cs
+++ b/Assets/Scripts/InteractionEngine/Gadgets/GadgetManager.cs
@@ -84,20 +84,28 @@ private void Awake()
             activeGadgetScaleFactor = 1.5f;
         else if (UIconfig.FrameITUIversion == 2)
             activeGadgetScaleFactor = 2.1f;
+    }
 
+    void Start()
+    {
+        gadgets = (
+            StageStatic.stage.AllowedGadgets == null
+            || StageStatic.stage.AllowedGadgets.Count == 0
+            ? Gadget.GadgetTypes
+                .Where(t => t != typeof(Gadget.UndefinedGadget))
+                .Select(t => (Gadget)Activator.CreateInstance(t))
+            : StageStatic.stage.AllowedGadgets
+            ).OrderBy(g => g.Rank).ToArray();
 
-        gadgets = Gadget.GadgetTypes.Select(t => (Gadget) Activator.CreateInstance(t)).OrderBy(g => g.Rank).ToArray();
         buttons = new Button[gadgets.Length];
 
-        for (int i = 0; i < gadgets.Length; i++) {
+        for (int i = 0; i < gadgets.Length; i++)
+        {
             gadgets[i].Awake();
             //gadgets[i].Start();
             CreateButton(i);
         }
-    }
 
-    void Start()
-    {
         ActiveGadgetInd = 0;
         buttons[0].transform.localScale *= activeGadgetScaleFactor;
         OnHit = gadgets[0].Hit;
diff --git a/Assets/Scripts/InteractionEngine/Gadgets/LineTool.cs b/Assets/Scripts/InteractionEngine/Gadgets/LineTool.cs
index a8026a93..d5e8aa44 100644
--- a/Assets/Scripts/InteractionEngine/Gadgets/LineTool.cs
+++ b/Assets/Scripts/InteractionEngine/Gadgets/LineTool.cs
@@ -1,10 +1,15 @@
-using System.Collections;
+using Newtonsoft.Json;
+using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 using static CommunicationEvents;
 
 public class LineTool : Gadget
 {
+    /// \copydoc Gadget.s_type
+    [JsonProperty]
+    protected static new string s_type = "LineTool";
+
     //Variables for LineMode distinction
     private bool LineModeIsFirstPointSelected = false;
     private Fact LineModeFirstPointSelected = null;
diff --git a/Assets/Scripts/InteractionEngine/Gadgets/LotTool.cs b/Assets/Scripts/InteractionEngine/Gadgets/LotTool.cs
index 4c4e0fc0..0727a40f 100644
--- a/Assets/Scripts/InteractionEngine/Gadgets/LotTool.cs
+++ b/Assets/Scripts/InteractionEngine/Gadgets/LotTool.cs
@@ -1,4 +1,5 @@
-using System.Collections;
+using Newtonsoft.Json;
+using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 using static CommunicationEvents;
@@ -6,6 +7,10 @@
 public class LotTool : Gadget
 //constructs a Perpendicular between a Line and a Point
 {
+    /// \copydoc Gadget.s_type
+    [JsonProperty]
+    protected static new string s_type = "LotTool";
+
     //Variables for LineMode distinction
     private bool LotModeIsPointSelected = false;
     private bool LotModeIsLineSelected = false;
diff --git a/Assets/Scripts/InteractionEngine/Gadgets/Pendulum.cs b/Assets/Scripts/InteractionEngine/Gadgets/Pendulum.cs
index a7bd1946..1d1f6e3e 100644
--- a/Assets/Scripts/InteractionEngine/Gadgets/Pendulum.cs
+++ b/Assets/Scripts/InteractionEngine/Gadgets/Pendulum.cs
@@ -6,6 +6,10 @@
 public class Pendulum : Gadget
 //Acts as a Pendulum starting at a Point
 {
+    /// \copydoc Gadget.s_type
+    [Newtonsoft.Json.JsonProperty]
+    protected static new string s_type = "Pendulum";
+
     public override void _Enable()
     {
         ActivateLineDrawing();
diff --git a/Assets/Scripts/InteractionEngine/Gadgets/Pointer.cs b/Assets/Scripts/InteractionEngine/Gadgets/Pointer.cs
index 757cac17..8db5bc07 100644
--- a/Assets/Scripts/InteractionEngine/Gadgets/Pointer.cs
+++ b/Assets/Scripts/InteractionEngine/Gadgets/Pointer.cs
@@ -5,6 +5,10 @@
 
 public class Pointer : Gadget
 {
+    /// \copydoc Gadget.s_type
+    [Newtonsoft.Json.JsonProperty]
+    protected static new string s_type = "Pointer";
+
     public override void _Hit(RaycastHit hit)
     {
         string pid = FactManager.AddPointFact(hit).Id;
diff --git a/Assets/Scripts/InteractionEngine/Gadgets/PoleTool.cs b/Assets/Scripts/InteractionEngine/Gadgets/PoleTool.cs
index 72c5e705..ef8c8686 100644
--- a/Assets/Scripts/InteractionEngine/Gadgets/PoleTool.cs
+++ b/Assets/Scripts/InteractionEngine/Gadgets/PoleTool.cs
@@ -6,6 +6,10 @@
 public class PoleTool : Gadget
 //Acts as a Pendulum starting at a Point
 {
+    /// \copydoc Gadget.s_type
+    [Newtonsoft.Json.JsonProperty]
+    protected static new string s_type = "PoleTool";
+
     public float poleHeight = 1f;
 
     public override void _Enable()
diff --git a/Assets/Scripts/InteractionEngine/Gadgets/Remover.cs b/Assets/Scripts/InteractionEngine/Gadgets/Remover.cs
index b596545f..02b06706 100644
--- a/Assets/Scripts/InteractionEngine/Gadgets/Remover.cs
+++ b/Assets/Scripts/InteractionEngine/Gadgets/Remover.cs
@@ -5,9 +5,13 @@
 
 public class Remover : Gadget
 {
+    /// \copydoc Gadget.s_type
+    [Newtonsoft.Json.JsonProperty]
+    protected static new string s_type = "Remover";
+
     public override void _Hit(RaycastHit hit)
     {
         var hid = hit.transform.GetComponent<FactObject>()?.URI;
-        StageStatic.stage.factState.Remove(hid);
+        StageStatic.stage.factState.Remove(hid, false, this);
     }
 }
diff --git a/Assets/Scripts/InteractionEngine/Gadgets/Tape.cs b/Assets/Scripts/InteractionEngine/Gadgets/Tape.cs
index 41b99c25..44dfccb8 100644
--- a/Assets/Scripts/InteractionEngine/Gadgets/Tape.cs
+++ b/Assets/Scripts/InteractionEngine/Gadgets/Tape.cs
@@ -5,6 +5,10 @@
 
 public class Tape : Gadget
 {
+    /// \copydoc Gadget.s_type
+    [Newtonsoft.Json.JsonProperty]
+    protected static new string s_type = "Tape";
+
     //Variables for TapeMode distinction
     private bool TapeModeIsFirstPointSelected = false;
     private Fact TapeModeFirstPointSelected = null;
diff --git a/Assets/Scripts/Loading/Stage.cs b/Assets/Scripts/Loading/Stage.cs
index d8e59ac7..8891c205 100644
--- a/Assets/Scripts/Loading/Stage.cs
+++ b/Assets/Scripts/Loading/Stage.cs
@@ -42,12 +42,16 @@ public class Stage: IJSONsavable<Stage>
     [JSONsavable.JsonAutoPreProcess, JSONsavable.JsonAutoPostProcess]
     public SolutionOrganizer solution = null;
 
+    /// <summary>
+    /// A single class containing all savegame-data.
+    /// Stored seperately.
+    /// </summary>
     [JsonIgnore, JSONsavable.JsonSeparate]
     public SaveGame savegame = null;
 
     public List<PlayerRecord> solution_approches = new();
     public List<string> AllowedScrolls = new();
-    public List<Type> AllowedGadgets = new();
+    public List<Gadget> AllowedGadgets = new();
 
     #region makros/shortcuts
 
@@ -61,7 +65,7 @@ public class Stage: IJSONsavable<Stage>
     /// <summary> Current Stage progress.</summary>
     [JsonIgnore]
     public PlayerRecord player_record { 
-        get => savegame?.player_record;
+        get => savegame.player_record ??= new(record_name);
         set => (savegame ??= new())
             .player_record = value;
     }
@@ -94,7 +98,7 @@ public FactOrganizer factState {
     #endregion makros/shortcuts
 
     /// <summary> Returns a name for <see cref="player_record.name"/> which needs to be uniquified once put into <see cref="player_record_list"/> (e.g. by <see cref="push_record(double, bool) adding '_i'"/>).</summary>
-    private string record_name { get { return name + "_save"; } }
+    private string record_name { get => name + "_save"; }
 
     /// <summary> Wether <see cref="player_record.factState"/> (<see langword="false"/>) or <see cref="solution"/> (<see langword="true"/>) is exposed and drawn.</summary>
     [JsonIgnore]
@@ -453,7 +457,7 @@ public class SaveGame : IJSONsavable<SaveGame>
     public string path { get; set; }
 
     [JSONsavable.JsonAutoPreProcess, JSONsavable.JsonAutoPostProcess]
-    public PlayerRecord player_record = new();
+    public PlayerRecord player_record = null;
 
     public Dictionary<string, PlayerRecord> player_record_list = new(); //entries are "PostProcess"ed when accessed/Cloned
 
@@ -464,6 +468,12 @@ static SaveGame()
     public SaveGame() { }
 
     string IJSONsavable<SaveGame>._IJGetName(string name) => name + "_save";
+    SaveGame IJSONsavable<SaveGame>._IJPostProcess(SaveGame payload)
+    {
+        if ((payload.player_record_list ??= new()).Count == 0)
+            payload.player_record = null;
+        return payload;
+    }
 }
 
 
@@ -502,7 +512,7 @@ public PlayerRecord() { }
     /// <param name="name">sets <see cref="name"/></param>
     public PlayerRecord(string name) {
         this.name = name;
-        factState = new FactOrganizer();
+        factState = new FactOrganizer() { invoke = true };
     }
 
     /// <summary>
@@ -517,17 +527,8 @@ public PlayerRecord Clone()
             solved = this.solved,
             seconds = this.seconds
         };
-        ret.factState = FactOrganizer.ReInitializeFactOrganizer<FactOrganizer>(this.factState, false, out _);
+        ret.factState = IJSONsavable<FactOrganizer>.postprocess(this.factState);
 
         return ret;
     }
-}
-
-
-public class SolutionApproach: IJSONsavable<SolutionApproach>
-{
-    public string name { get; set; } = null;
-    public string path { get; set; } = null;
-
-    //public PlayerRecord
 }
\ No newline at end of file
diff --git a/Assets/Stages/TechDemo A.JSON b/Assets/Stages/TechDemo A.JSON
index 7756b07e..066220d7 100644
--- a/Assets/Stages/TechDemo A.JSON	
+++ b/Assets/Stages/TechDemo A.JSON	
@@ -1 +1 @@
-{"category":"Demo Category","number":1,"description":"Tree Stage","scene":"RiverWorld","use_install_folder":true,"solution":{"ValidationSet":[{"MasterIDs":["http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact649"],"SolutionIndex":[],"RelationIndex":[],"ComparerString":"LineFactHightDirectionComparer"}],"FactDict":{"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact647":{"s_type":"PointFact","Point":{"x":0.0,"y":0.0,"z":0.0,"magnitude":0.0,"sqrMagnitude":0.0},"Normal":{"x":0.0,"y":1.0,"z":0.0,"magnitude":1.0,"sqrMagnitude":1.0},"Id":"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact647","Label":"A","hasCustomLabel":false,"LabelId":1},"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact648":{"s_type":"PointFact","Point":{"x":0.0,"y":6.0,"z":0.0,"normalized":{"x":0.0,"y":1.0,"z":0.0,"magnitude":1.0,"sqrMagnitude":1.0},"magnitude":6.0,"sqrMagnitude":36.0},"Normal":{"x":0.0,"y":1.0,"z":0.0,"magnitude":1.0,"sqrMagnitude":1.0},"Id":"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact648","Label":"B","hasCustomLabel":false,"LabelId":2},"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact649":{"s_type":"LineFact","Distance":6.0,"Pid1":"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact647","Pid2":"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact648","Dir":{"x":0.0,"y":1.0,"z":0.0,"magnitude":1.0,"sqrMagnitude":1.0},"Id":"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact649","Label":"[AB]","hasCustomLabel":false,"LabelId":0}},"MetaInf":{"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact647":{"workflow_id":0,"active":true},"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact648":{"workflow_id":1,"active":true},"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact649":{"workflow_id":2,"active":true}},"Workflow":[{"Id":"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact647","samestep":false,"steplink":3,"creation":true},{"Id":"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact648","samestep":true,"steplink":0,"creation":true},{"Id":"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact649","samestep":true,"steplink":0,"creation":true}],"marker":3,"worksteps":1,"backlog":0,"soft_resetted":false,"invoke":true,"MaxLabelId":2,"UnusedLabelIds":[],"name":null,"path":null},"name":"TechDemo A","path":null}
\ No newline at end of file
+{"category":"Demo Category","number":1,"description":"Tree Stage","scene":"RiverWorld","use_install_folder":true,"solution":{"ValidationSet":[{"MasterIDs":["http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact1320"],"SolutionIndex":[],"RelationIndex":[],"ComparerString":"LineFactHightDirectionComparer"}],"WorkflowGadgetDict":{"-1":null},"FactDict":{"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact1318":{"s_type":"PointFact","Point":{"x":0.0,"y":0.0,"z":0.0,"magnitude":0.0,"sqrMagnitude":0.0},"Normal":{"x":0.0,"y":1.0,"z":0.0,"magnitude":1.0,"sqrMagnitude":1.0},"Id":"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact1318","Label":"A","hasCustomLabel":false,"LabelId":1},"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact1319":{"s_type":"PointFact","Point":{"x":0.0,"y":6.0,"z":0.0,"normalized":{"x":0.0,"y":1.0,"z":0.0,"magnitude":1.0,"sqrMagnitude":1.0},"magnitude":6.0,"sqrMagnitude":36.0},"Normal":{"x":0.0,"y":1.0,"z":0.0,"magnitude":1.0,"sqrMagnitude":1.0},"Id":"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact1319","Label":"B","hasCustomLabel":false,"LabelId":2},"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact1320":{"s_type":"LineFact","Distance":6.0,"Pid1":"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact1318","Pid2":"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact1319","Dir":{"x":0.0,"y":1.0,"z":0.0,"magnitude":1.0,"sqrMagnitude":1.0},"Id":"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact1320","Label":"[AB]","hasCustomLabel":false,"LabelId":0}},"MetaInf":{"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact1318":{"workflow_id":0,"active":true},"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact1319":{"workflow_id":1,"active":true},"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact1320":{"workflow_id":2,"active":true}},"Workflow":[{"Id":"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact1318","samestep":false,"steplink":3,"creation":true,"gadget_rank":-1,"scroll_label":null},{"Id":"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact1319","samestep":true,"steplink":0,"creation":true,"gadget_rank":-1,"scroll_label":null},{"Id":"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact1320","samestep":true,"steplink":0,"creation":true,"gadget_rank":-1,"scroll_label":null}],"marker":3,"worksteps":1,"backlog":0,"soft_resetted":false,"invoke":true,"MaxLabelId":2,"UnusedLabelIds":[],"name":null,"path":null},"solution_approches":[],"AllowedScrolls":[],"AllowedGadgets":null,"name":"TechDemo A","path":null}
\ No newline at end of file
diff --git a/Assets/Stages/TechDemo B.JSON b/Assets/Stages/TechDemo B.JSON
index 63d816df..e6206127 100644
--- a/Assets/Stages/TechDemo B.JSON	
+++ b/Assets/Stages/TechDemo B.JSON	
@@ -1 +1 @@
-{"category":"Demo Category","number":2,"description":"River Stage","scene":"RiverWorld","use_install_folder":true,"solution":{"ValidationSet":[{"MasterIDs":["http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact652"],"SolutionIndex":[],"RelationIndex":[],"ComparerString":"LineFactHightDirectionComparer"},{"MasterIDs":["http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact652"],"SolutionIndex":[],"RelationIndex":[],"ComparerString":"LineSpanningOverRiverWorldComparer"},{"MasterIDs":[],"SolutionIndex":[1],"RelationIndex":[0],"ComparerString":"LineFactHightComparer"}],"FactDict":{"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact650":{"s_type":"PointFact","Point":{"x":0.0,"y":0.0,"z":0.0,"magnitude":0.0,"sqrMagnitude":0.0},"Normal":{"x":0.0,"y":1.0,"z":0.0,"magnitude":1.0,"sqrMagnitude":1.0},"Id":"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact650","Label":"A","hasCustomLabel":false,"LabelId":1},"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact651":{"s_type":"PointFact","Point":{"x":0.0,"y":6.0,"z":0.0,"normalized":{"x":0.0,"y":1.0,"z":0.0,"magnitude":1.0,"sqrMagnitude":1.0},"magnitude":6.0,"sqrMagnitude":36.0},"Normal":{"x":0.0,"y":1.0,"z":0.0,"magnitude":1.0,"sqrMagnitude":1.0},"Id":"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact651","Label":"B","hasCustomLabel":false,"LabelId":2},"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact652":{"s_type":"LineFact","Distance":6.0,"Pid1":"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact650","Pid2":"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact651","Dir":{"x":0.0,"y":1.0,"z":0.0,"magnitude":1.0,"sqrMagnitude":1.0},"Id":"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact652","Label":"[AB]","hasCustomLabel":false,"LabelId":0}},"MetaInf":{"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact650":{"workflow_id":0,"active":true},"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact651":{"workflow_id":1,"active":true},"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact652":{"workflow_id":2,"active":true}},"Workflow":[{"Id":"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact650","samestep":false,"steplink":3,"creation":true},{"Id":"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact651","samestep":true,"steplink":0,"creation":true},{"Id":"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact652","samestep":true,"steplink":0,"creation":true}],"marker":3,"worksteps":1,"backlog":0,"soft_resetted":false,"invoke":true,"MaxLabelId":2,"UnusedLabelIds":[],"name":null,"path":null},"name":"TechDemo B","path":null}
\ No newline at end of file
+{"category":"Demo Category","number":2,"description":"River Stage","scene":"RiverWorld","use_install_folder":true,"solution":{"ValidationSet":[{"MasterIDs":["http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact1323"],"SolutionIndex":[],"RelationIndex":[],"ComparerString":"LineFactHightDirectionComparer"},{"MasterIDs":["http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact1323"],"SolutionIndex":[],"RelationIndex":[],"ComparerString":"LineSpanningOverRiverWorldComparer"},{"MasterIDs":[],"SolutionIndex":[1],"RelationIndex":[0],"ComparerString":"LineFactHightComparer"}],"WorkflowGadgetDict":{"-1":null},"FactDict":{"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact1321":{"s_type":"PointFact","Point":{"x":0.0,"y":0.0,"z":0.0,"magnitude":0.0,"sqrMagnitude":0.0},"Normal":{"x":0.0,"y":1.0,"z":0.0,"magnitude":1.0,"sqrMagnitude":1.0},"Id":"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact1321","Label":"A","hasCustomLabel":false,"LabelId":1},"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact1322":{"s_type":"PointFact","Point":{"x":0.0,"y":6.0,"z":0.0,"normalized":{"x":0.0,"y":1.0,"z":0.0,"magnitude":1.0,"sqrMagnitude":1.0},"magnitude":6.0,"sqrMagnitude":36.0},"Normal":{"x":0.0,"y":1.0,"z":0.0,"magnitude":1.0,"sqrMagnitude":1.0},"Id":"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact1322","Label":"B","hasCustomLabel":false,"LabelId":2},"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact1323":{"s_type":"LineFact","Distance":6.0,"Pid1":"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact1321","Pid2":"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact1322","Dir":{"x":0.0,"y":1.0,"z":0.0,"magnitude":1.0,"sqrMagnitude":1.0},"Id":"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact1323","Label":"[AB]","hasCustomLabel":false,"LabelId":0}},"MetaInf":{"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact1321":{"workflow_id":0,"active":true},"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact1322":{"workflow_id":1,"active":true},"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact1323":{"workflow_id":2,"active":true}},"Workflow":[{"Id":"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact1321","samestep":false,"steplink":3,"creation":true,"gadget_rank":-1,"scroll_label":null},{"Id":"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact1322","samestep":true,"steplink":0,"creation":true,"gadget_rank":-1,"scroll_label":null},{"Id":"http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact1323","samestep":true,"steplink":0,"creation":true,"gadget_rank":-1,"scroll_label":null}],"marker":3,"worksteps":1,"backlog":0,"soft_resetted":false,"invoke":true,"MaxLabelId":2,"UnusedLabelIds":[],"name":null,"path":null},"solution_approches":[],"AllowedScrolls":[],"AllowedGadgets":[{"s_type":"Pointer","Rank":1,"UiName":"Pointer","MaxRange":"Infinity","MaxHeight":"Infinity","ButtonIndx":1,"MaterialIndx":0,"IgnoreLayerMask":{"value":24066},"SecondaryLayerMask":{"value":0}},{"s_type":"Tape","Rank":2,"UiName":"Tape","MaxRange":2.5,"MaxHeight":2.5,"ButtonIndx":2,"MaterialIndx":0,"IgnoreLayerMask":{"value":96770},"SecondaryLayerMask":{"value":0}},{"s_type":"AngleTool","Rank":3,"UiName":"Angle Tool","MaxRange":"Infinity","MaxHeight":"Infinity","ButtonIndx":3,"MaterialIndx":1,"IgnoreLayerMask":{"value":96770},"SecondaryLayerMask":{"value":0}},{"s_type":"LineTool","Rank":4,"UiName":"Line Tool","MaxRange":"Infinity","MaxHeight":"Infinity","ButtonIndx":4,"MaterialIndx":0,"IgnoreLayerMask":{"value":96770},"SecondaryLayerMask":{"value":0}},{"s_type":"LotTool","Rank":5,"UiName":"Lot Tool","MaxRange":"Infinity","MaxHeight":"Infinity","ButtonIndx":5,"MaterialIndx":0,"IgnoreLayerMask":{"value":86530},"SecondaryLayerMask":{"value":0}},{"s_type":"Pendulum","Rank":6,"UiName":"Pendulum","MaxRange":"Infinity","MaxHeight":"Infinity","ButtonIndx":6,"MaterialIndx":0,"IgnoreLayerMask":{"value":96770},"SecondaryLayerMask":{"value":1}},{"s_type":"Remover","Rank":8,"UiName":"Delete Fact","MaxRange":"Infinity","MaxHeight":"Infinity","ButtonIndx":8,"MaterialIndx":0,"IgnoreLayerMask":{"value":115219},"SecondaryLayerMask":{"value":0}}],"name":"TechDemo B","path":null}
\ No newline at end of file
-- 
GitLab