From 47feb1f419cc39677111a56c65aa9972c7e5f09f Mon Sep 17 00:00:00 2001
From: MaZiFAU <63099053+MaZiFAU@users.noreply.github.com>
Date: Sun, 24 Sep 2023 14:38:55 +0200
Subject: [PATCH] Known Bugs; BugFixes; Facts; Misc;

Known Bugs;
+ Saving/Loading [Experimental]

BugFixes;
+ Server caching may pose the need for postponed Stage loading
+ Server cheches wrong label -> send fact with new one.
+ New Facts may have Definisions()==null -> null.ToString() for ID
+-> MMTFact.ToString() as Fallback

Facts;
+ Further decoupled from FactRecorder
+-> labeling done JIT by FactRecorder
+ Caching: object CompiledValue && Expression CompileBase

Misc;
+ added SOMDoc(from)Object(object)
+ StageStatic.ShallowLoadStages(bool): streamlined loading in case of failure due to unloaded dependecies (e.g.: ContextRecorder)
---
 Assets/Scripts/GenerateDemoFiles.cs           |  47 ++------
 Assets/Scripts/GlobalBehaviour.cs             |   3 +-
 .../FactHandling/FactRecorder.cs              |   8 +-
 .../FactWrapper/RenderedScrollFact.cs         |   2 +
 .../FactHandling/Facts/AbstractLineFact.cs    |   4 +
 .../FactHandling/Facts/Fact.cs                |  57 ++++++++-
 .../FactHandling/Facts/FunctionFact.cs        |  15 ++-
 .../FactHandling/Facts/MMTTypes.cs            |  52 ++++++---
 .../FactHandling/Facts/UnsortedFact.cs        |  81 ++++++-------
 Assets/Scripts/Loading/Stage.cs               |  34 +-----
 .../CommunicationProtocoll/Endpoints.cs       |   8 ++
 .../SOMDocToLambdaExpression.cs               |  56 +++++----
 .../CommunicationProtocoll/SOMDocs.cs         |  65 +++++++++++
 Assets/Scripts/StageStatic.cs                 | 108 +++++++++++++-----
 .../UI/MainMenue/PageLoader/StageLoader.cs    |   2 +-
 Assets/misc.meta                              |   8 ++
 16 files changed, 345 insertions(+), 205 deletions(-)
 create mode 100644 Assets/misc.meta

diff --git a/Assets/Scripts/GenerateDemoFiles.cs b/Assets/Scripts/GenerateDemoFiles.cs
index b0827c99..d335a60f 100644
--- a/Assets/Scripts/GenerateDemoFiles.cs
+++ b/Assets/Scripts/GenerateDemoFiles.cs
@@ -37,9 +37,6 @@ public static void GenerateAll()
                 Debug.LogError("Exception while executing " + action.Method.Name);
                 Debug.LogException(ex);
             }
-
-        StageStatic.StageOfficial = null;
-        StageStatic.StageLocal = null;
     }
 
     public static void GenerateTreeStage()
@@ -48,9 +45,9 @@ public static void GenerateTreeStage()
         float minimalSolutionHight = 6;
 
         // Generate Stage
-        Stage demo = new Stage
+        StageStatic.LoadNewStage
         (
-            number: 1,
+            id: 1,
             category: "Demo Category",
             name: "TechDemo A",
             scene: "RiverWorld",
@@ -58,13 +55,6 @@ public static void GenerateTreeStage()
             local: false
         );
 
-        // needed to generate facts
-        StageStatic.StageOfficial = new Dictionary<string, Stage>
-        {
-            { demo.name, demo },
-        };
-        StageStatic.SetStage(demo.name, false);
-
         // Populate Solution
         PointFact
             buttom = new PointFact(Vector3.zero, Vector3.up),
@@ -96,9 +86,9 @@ public static void GenerateRiverStage()
         float minimalSolutionHight = 6;
 
         // Generate Stage
-        Stage demo = new Stage
+        StageStatic.LoadNewStage
         (
-            number: 2,
+            id: 2,
             category: "Demo Category",
             name: "TechDemo B",
             scene: "RiverWorld",
@@ -106,13 +96,6 @@ public static void GenerateRiverStage()
             local: false
         );
 
-        // needed to generate facts
-        StageStatic.StageOfficial = new Dictionary<string, Stage>
-        {
-            { demo.name, demo },
-        };
-        StageStatic.SetStage(demo.name, false);
-
         // Populate Solution
         PointFact
             buttom = new PointFact(Vector3.zero, Vector3.up),
@@ -212,9 +195,9 @@ public static void GenerateCanonBallStage2D()
         }
 
         // Generate Stage
-        Stage demo = new Stage
+        StageStatic.LoadNewStage
         (
-            number: 1,
+            id: 1,
             category: "CanonBall",
             name: "CanonBall 2D",
             scene: "RiverWorld",
@@ -222,13 +205,6 @@ public static void GenerateCanonBallStage2D()
             local: false
         );
 
-        // needed to generate facts
-        StageStatic.StageOfficial = new Dictionary<string, Stage>
-        {
-            { demo.name, demo },
-        };
-        StageStatic.SetStage(demo.name, false);
-
         // Populate Solution
 
         string BallURI = StageStatic.stage.solution.Add(
@@ -435,9 +411,9 @@ public static void GenerateCanonBallStage3D()
                     Wall_parameter[i, j, k] = (float)(PythonWalls[i, j, k] * Py_factor);
 
         // Generate Stage
-        Stage demo = new Stage
+        StageStatic.LoadNewStage
         (
-            number: 2,
+            id: 2,
             category: "CanonBall",
             name: "CanonBall 3D",
             scene: "RiverWorld",
@@ -445,13 +421,6 @@ public static void GenerateCanonBallStage3D()
             local: false
         );
 
-        // needed to generate facts
-        StageStatic.StageOfficial = new Dictionary<string, Stage>
-        {
-            { demo.name, demo },
-        };
-        StageStatic.SetStage(demo.name, false);
-
         // Populate Solution
 
         string BallURI = StageStatic.stage.solution.Add(
diff --git a/Assets/Scripts/GlobalBehaviour.cs b/Assets/Scripts/GlobalBehaviour.cs
index 9c28beaa..05a0495f 100644
--- a/Assets/Scripts/GlobalBehaviour.cs
+++ b/Assets/Scripts/GlobalBehaviour.cs
@@ -136,10 +136,11 @@ IEnumerator _GetScrollsfromServer()
     }
 
     public static FactRecorder Context = new();
+    public static IEnumerator InitiateContext = IEnumeratorExtensions.yield_break;
 
     private void GetContextfromServer()
     {
-        StartCoroutine(_GetContextfromServer());
+        StartCoroutine(InitiateContext = _GetContextfromServer());
 
         IEnumerator _GetContextfromServer()
         {
diff --git a/Assets/Scripts/InteractionEngine/FactHandling/FactRecorder.cs b/Assets/Scripts/InteractionEngine/FactHandling/FactRecorder.cs
index d57c7221..f4e3263b 100644
--- a/Assets/Scripts/InteractionEngine/FactHandling/FactRecorder.cs
+++ b/Assets/Scripts/InteractionEngine/FactHandling/FactRecorder.cs
@@ -578,9 +578,13 @@ public string Add(Fact value, out bool exists, bool samestep, Gadget gadget, str
             //if (exists = GlobalFactDictionary.FindEquivalent(AllFacts, value, out key, out Fact found, out bool _, true, false))
             if (AllFacts.TryGetValue(value.Id, out Fact found))
                 value = found;
-            else
-                if (!value.HasServerTwin)
+            //else
+            if (value._LastLabel != value.GetLabel(this) // Dirty Fix for Server caching wrong label
+             || !value.HasServerTwin)
+            {
+                value.GetLabel(this); // initialize label
                 value.SendToMMT();
+            }
 
             key = value.Id;
 
diff --git a/Assets/Scripts/InteractionEngine/FactHandling/FactWrapper/RenderedScrollFact.cs b/Assets/Scripts/InteractionEngine/FactHandling/FactWrapper/RenderedScrollFact.cs
index 64adcc77..7fbdda75 100644
--- a/Assets/Scripts/InteractionEngine/FactHandling/FactWrapper/RenderedScrollFact.cs
+++ b/Assets/Scripts/InteractionEngine/FactHandling/FactWrapper/RenderedScrollFact.cs
@@ -54,6 +54,8 @@ protected override void FactUpdated()
 
         if (VerboseURI)
             Debug.Log(nameof(RenderedScrollFact) + " recieved Fact: " + URI);
+
+        base.FactUpdated();
     }
 
     protected override void _DeleteFactEvent(Fact fact)
diff --git a/Assets/Scripts/InteractionEngine/FactHandling/Facts/AbstractLineFact.cs b/Assets/Scripts/InteractionEngine/FactHandling/Facts/AbstractLineFact.cs
index 9ca1bac2..8bcab1b2 100644
--- a/Assets/Scripts/InteractionEngine/FactHandling/Facts/AbstractLineFact.cs
+++ b/Assets/Scripts/InteractionEngine/FactHandling/Facts/AbstractLineFact.cs
@@ -1,5 +1,6 @@
 using Newtonsoft.Json;
 using REST_JSON_API;
+using System;
 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
@@ -10,6 +11,9 @@
 /// </summary>
 public abstract class AbstractLineFact : FactWrappedCRTP<AbstractLineFact>
 {
+    //protected override object GetCompiledValue() 
+    //    => new Tuple<Vector3, Vector3>(Point1.Point, Point2.Point);
+
     /// @{ <summary>
     /// One <see cref="Fact.Id">Id</see> of two <see cref="PointFact"/> defining <see cref="Dir"/>.
     /// </summary>
diff --git a/Assets/Scripts/InteractionEngine/FactHandling/Facts/Fact.cs b/Assets/Scripts/InteractionEngine/FactHandling/Facts/Fact.cs
index f9fe86b7..ce4e25ba 100644
--- a/Assets/Scripts/InteractionEngine/FactHandling/Facts/Fact.cs
+++ b/Assets/Scripts/InteractionEngine/FactHandling/Facts/Fact.cs
@@ -8,6 +8,7 @@
 using REST_JSON_API;
 using System.Drawing;
 using System.Collections;
+using System.Linq.Expressions;
 
 public static class ParsingDictionary
 {
@@ -110,6 +111,45 @@ public static class ParsingDictionary
 [JsonSubtypes.KnownSubType(typeof(RealLitFact), nameof(RealLitFact))]
 public abstract class Fact
 {
+    [JsonIgnore]
+    public Expression CompileBase
+    {
+        get
+        {
+            if (_CompileBase == null)
+                CompileValue();
+            return _CompileBase;
+        }
+
+        protected set => _CompileBase = value;
+    }
+    private Expression _CompileBase;
+
+    [JsonIgnore]
+    public object CompiledValue
+    {
+        get => _CompiledValue ??= GetCompiledValue();
+        protected set => _CompiledValue = value;
+    }
+    private object _CompiledValue;
+    protected virtual object GetCompiledValue() => CompileValue(); // put to abstract, once we know what to do with every Fact
+
+    protected object CompileValue()
+    {
+        Func<object[], object[]> builder =
+            (HasServerTwin // otherwise: self-referencing
+            ? Defines()
+            : ServerDefinition)
+            .PartialInvokeCastingLambdaExpression(out _CompileBase, out Type[] Signature);
+
+        if (Signature.Length != 1)
+            throw new InvalidCastException($"{nameof(ServerDefinition)} does not compile to constant!");
+
+        return _CompiledValue = Signature[0] == typeof(object[])
+            ? builder(new object[0])
+            : builder(new object[0])[0];
+    }
+
     /// <summary>
     /// Reference to <c>GameObject</c> that represents this Fact in the GameWorld.
     /// </summary>
@@ -152,12 +192,13 @@ public string Id
         get
         {
             //while (FetchURICoroutine.MoveNext()) ; //active wait for server
-            return ServerDefinition.ToString();
+            return ServerDefinition?.ToString() ?? ScalaFact.ToString();
         }
     }
     //private IEnumerator FetchURICoroutine = IEnumeratorExtensions.yield_break;
 
     /// <summary>AST which the Server understands. e.g.: OMS(MMT URI)</summary>
+    [JsonIgnore]
     public SOMDoc ServerDefinition
     {
         get => _ServerDefinition ??= Defines();
@@ -165,6 +206,14 @@ public SOMDoc ServerDefinition
     }
     private SOMDoc _ServerDefinition = null;
 
+    [JsonIgnore]
+    public MMTFact ScalaFact
+    {
+        get => _ScalaFact ??= MakeMMTDeclaration();
+        protected set => _ScalaFact = value;
+    }
+    private MMTFact _ScalaFact = null;
+
     //public MMTFact MMTFact => _MMTFact ??= MakeMMTDeclaration();
     //private MMTFact _MMTFact = null;
 
@@ -184,7 +233,7 @@ public string GetLabel(FactRecorder name_space)
             : generateLabel(name_space));
     }
     protected internal string _LastLabel = "NaN";
-    
+
     public bool SetLabel(string value, FactRecorder name_space)
     {
         if (name_space == null) // JsonSerialization toggle)
@@ -526,7 +575,9 @@ public static void MakeFact(List<Fact> ret, object payload, SOMDoc ServerDefinit
         Type type = payload.GetType();
 
         if (BypassServer) bypasscc++;
-        SOMDoc BypassURI = new OMLIT<uint>(bypasscc);
+        SOMDoc BypassURI = BypassServer
+            ? new OMLIT<uint>(bypasscc)
+            : null;
 
         if (payload is Fact fact)
             ret.Add(fact);
diff --git a/Assets/Scripts/InteractionEngine/FactHandling/Facts/FunctionFact.cs b/Assets/Scripts/InteractionEngine/FactHandling/Facts/FunctionFact.cs
index dd3ac363..e00a6a99 100644
--- a/Assets/Scripts/InteractionEngine/FactHandling/Facts/FunctionFact.cs
+++ b/Assets/Scripts/InteractionEngine/FactHandling/Facts/FunctionFact.cs
@@ -9,6 +9,8 @@
 
 public class FunctionCallFact : FactWrappedCRTP<FunctionCallFact>
 {
+    protected override object GetCompiledValue() 
+        => Tuple.Create(Domain, Function_args.CompiledValue, Function.CompiledValue);
 
     public string func_id
     {
@@ -148,6 +150,9 @@ protected override Fact _ReInitializeMe(Dictionary<string, string> old_to_new)
 
 public class FunctionFact : FactWrappedCRTP<FunctionFact>
 {
+    protected override object GetCompiledValue() 
+        => Expression.Lambda(CompileBase).Compile().DynamicInvoke();
+
     public SOMDoc Function_SOMDoc;
 
     [JsonIgnore]
@@ -156,9 +161,6 @@ public class FunctionFact : FactWrappedCRTP<FunctionFact>
     [JsonIgnore]
     public Func<object[], object[]> Function;
 
-    [JsonIgnore]
-    public Expression LambdaExpression;
-
     /// <summary> \copydoc Fact.Fact </summary>
     public FunctionFact() : base() { }
 
@@ -170,7 +172,8 @@ public FunctionFact() : base() { }
     public FunctionFact(SOMDoc Function_SOMDoc) : base()
     {
         this.Function_SOMDoc = Function_SOMDoc;
-        this.Function = this.Function_SOMDoc.PartialInvokeCastingLambdaExpression(out LambdaExpression, out Signature);
+        this.Function = this.Function_SOMDoc.PartialInvokeCastingLambdaExpression(out Expression CompileBase, out Signature);
+        this.CompileBase = CompileBase;
     }
 
     /// <summary>
@@ -181,8 +184,8 @@ public FunctionFact(SOMDoc Function_SOMDoc) : base()
     public FunctionFact(SOMDoc Function_SOMDoc, SOMDoc _ServerDefinition) : base()
     {
         this.Function_SOMDoc = Function_SOMDoc;
-        this.Function = Function_SOMDoc.PartialInvokeCastingLambdaExpression(out LambdaExpression, out Signature);
-
+        this.Function = Function_SOMDoc.PartialInvokeCastingLambdaExpression(out Expression CompileBase, out Signature);
+        this.CompileBase = CompileBase;
         this.ServerDefinition = _ServerDefinition;
     }
 
diff --git a/Assets/Scripts/InteractionEngine/FactHandling/Facts/MMTTypes.cs b/Assets/Scripts/InteractionEngine/FactHandling/Facts/MMTTypes.cs
index 71206c16..9b3fdc9d 100644
--- a/Assets/Scripts/InteractionEngine/FactHandling/Facts/MMTTypes.cs
+++ b/Assets/Scripts/InteractionEngine/FactHandling/Facts/MMTTypes.cs
@@ -8,7 +8,6 @@
 using Newtonsoft.Json;
 using System.Collections;
 using System.Linq.Expressions;
-using Newtonsoft.Json.Linq;
 
 /// <summary>
 /// 
@@ -17,6 +16,8 @@
 /// <remarks>Needed to refere to lists serverside</remarks>
 public class ListFact : FactWrappedCRTP<ListFact>
 {
+    protected override object GetCompiledValue() => CompileValue();
+
     public string[] lids = new string[0];
 
     public SOMDoc[] payload = new SOMDoc[0];
@@ -167,6 +168,8 @@ protected override bool EquivalentWrapped(ListFact f1, ListFact f2)
 
 public class DynamicListFact : FactWrappedCRTP<DynamicListFact>, IUnpackable
 {
+    protected override object GetCompiledValue() => CompileValue();
+
     [JsonIgnore]
     public List<object> payload;
 
@@ -176,12 +179,12 @@ public class DynamicListFact : FactWrappedCRTP<DynamicListFact>, IUnpackable
 
     public DynamicListFact() : base() { }
 
-    public DynamicListFact(List<object> payload, SOMDoc indirect_payload, SOMDoc ListType) : base()
-    {
-        this.payload = payload;
-        this.indirect_payload = indirect_payload;
-        this.ListType = ListType;
-    }
+    //public DynamicListFact(List<object> payload, SOMDoc indirect_payload, SOMDoc ListType) : base()
+    //{
+    //    this.payload = payload;
+    //    this.indirect_payload = indirect_payload;
+    //    this.ListType = ListType;
+    //}
 
     public static List<Fact> MMTFactory(List<dynamic> payload, SOMDoc indirect_payload, SOMDoc ListType, SOMDoc _ServerDefinition = null)
     {
@@ -189,20 +192,25 @@ public static List<Fact> MMTFactory(List<dynamic> payload, SOMDoc indirect_paylo
          && indirect_payload == null)
             return new();
 
+        Expression CompileBase = null;
+        object CompiledValue = payload;
         if (payload == null)
         {
             Func<object[], object[]> builder =
-                indirect_payload.PartialInvokeCastingLambdaExpression(out _, out Type[] signature);
+                indirect_payload.PartialInvokeCastingLambdaExpression(out CompileBase, out Type[] signature);
 
             if (signature.Length != 1)
                 return new();
 
-            object result = builder(new object[0])[0];
+            CompiledValue = builder(new object[0])[0];
 
-            if (result is IEnumerable<dynamic> enum_result)
+            if (CompiledValue is List<dynamic> list_result)
+                payload = list_result;
+            else
+            if (CompiledValue is IEnumerable<dynamic> enum_result)
                 payload = enum_result.ToList();
             else
-            if (result is IEnumerable<float> enum_float) // special case for boxed/struct values
+            if (CompiledValue is IEnumerable<float> enum_float) // special case for boxed/struct values
                 payload = enum_float.Select(f => (dynamic)f).ToList();
             else
             if (signature[0].IsArray)
@@ -211,18 +219,21 @@ public static List<Fact> MMTFactory(List<dynamic> payload, SOMDoc indirect_paylo
                 return new();
         }
 
-        //TODO? indirect_payload ??= SOMDoc.FromObject(payload);
-        ListType ??= SOMDoc.SOMDocType(payload.GetType());
+        indirect_payload ??= SOMDoc.SOMDocObject(payload);
+        ListType ??= SOMDoc.SOMDocType(CompiledValue?.GetType() ?? payload.GetType());
 
         List<Fact> ret = new() {
             new DynamicListFact()
         {
+            CompiledValue = CompiledValue,
             payload = payload.Select(e => (object) e).ToList(),
             indirect_payload = indirect_payload,
             ListType = ListType,
-            //ServerDefinition = _ServerDefinition,
         }};
 
+        if(CompileBase != null)
+            (ret[0] as DynamicListFact).CompileBase = CompileBase;
+
         if (_ServerDefinition != null)
             (ret[0] as DynamicListFact).ServerDefinition = _ServerDefinition;
 
@@ -273,7 +284,8 @@ protected override string[] GetDependentFactIds()
     protected override void RecalculateTransform() { }
 
     protected override Fact _ReInitializeMe(Dictionary<string, string> old_to_new)
-        => new DynamicListFact(payload, indirect_payload?.MapURIs(old_to_new), ListType);
+        => MMTFactory(payload, indirect_payload?.MapURIs(old_to_new), ListType, ServerDefinition)
+            .FirstOrDefault();
 
     public IEnumerator UnpackMe(List<Fact> ret, bool BypassServer)
     {
@@ -292,6 +304,8 @@ public IEnumerator UnpackMe(List<Fact> ret, bool BypassServer)
 /// <remarks>Needed to refere to tupels serverside</remarks>
 public class TupleFact : FactWrappedCRTP<TupleFact>
 {
+    protected override object GetCompiledValue() => CompileValue();
+
     public string[] lids = new string[0];
 
     public SOMDoc[] payload = new SOMDoc[0];
@@ -377,6 +391,8 @@ protected override bool EquivalentWrapped(TupleFact f1, TupleFact f2)
 
 public class DynamicTupleFact : FactWrappedCRTP<DynamicTupleFact>, IUnpackable
 {
+    protected override object GetCompiledValue() => payload;
+
     [JsonIgnore]
     object payload;
 
@@ -384,6 +400,7 @@ public class DynamicTupleFact : FactWrappedCRTP<DynamicTupleFact>, IUnpackable
 
     [JsonIgnore]
     public Type[] Signature => _Signature ??= payload.GetType().GetGenericArguments();
+
     private Type[] _Signature;
 
     public SOMDoc indirect_payload;
@@ -550,6 +567,8 @@ public IEnumerator UnpackMe(List<Fact> ret, bool BypassServer)
 
 public class RealLitFact : FactWrappedCRTP<RealLitFact>
 {
+    protected override object GetCompiledValue() => value;
+
     public float value;
 
     public RealLitFact() : base() { }
@@ -557,7 +576,6 @@ public RealLitFact() : base() { }
     public RealLitFact(float value) : base()
     {
         this.value = value;
-        SendToMMT();
     }
 
     public RealLitFact(float value, SOMDoc _ServerDefinition) : base()
@@ -597,6 +615,8 @@ protected override Fact _ReInitializeMe(Dictionary<string, string> old_to_new)
 
 public class GeneralFact : FactWrappedCRTP<GeneralFact>
 {
+    protected override object GetCompiledValue() => CompileValue();
+
     public MMTFact Raw { get; private set; }
 
     //[JsonIgnore]
diff --git a/Assets/Scripts/InteractionEngine/FactHandling/Facts/UnsortedFact.cs b/Assets/Scripts/InteractionEngine/FactHandling/Facts/UnsortedFact.cs
index 323b2964..45ef1397 100644
--- a/Assets/Scripts/InteractionEngine/FactHandling/Facts/UnsortedFact.cs
+++ b/Assets/Scripts/InteractionEngine/FactHandling/Facts/UnsortedFact.cs
@@ -18,48 +18,30 @@ public class PointFact : FactWrappedCRTP<PointFact>
     [JsonProperty]
     private Vector3 Normal;
 
-    /// <summary> \copydoc Fact.Fact </summary>
-    public PointFact() : base()
-    {
-        this.Point = Vector3.zero;
-        this.Normal = Vector3.up;
-    }
-
     /// <summary>
     /// Standard Constructor:
     /// Initiates <see cref="Point"/>, <see cref="Normal"/>, <see cref="Fact._URI"/> and creates MMT %Fact Server-Side
     /// </summary>
-    /// <param name="P">sets <see cref="Point"/></param>
-    /// <param name="N">sets <see cref="Normal"/></param>
-    public PointFact(Vector3 P, Vector3 N) : base()
+    /// <param name="Point">sets <see cref="Point"/></param>
+    /// <param name="Normal">sets <see cref="Normal"/></param>
+    [JsonConstructor]
+    public PointFact(Vector3 Point, Vector3 Normal) : base()
     {
-        this.Point = P;
-        this.Normal = N;
-    }
-
-    protected override void RecalculateTransform()
-    {
-        Position = Point;
-        { // Rotation
-            Vector3 notNormal = Vector3.forward != Normal ? Vector3.forward : Vector3.up;
-            Rotation = Quaternion.LookRotation(
-                Vector3.Cross(Normal, notNormal),
-                Normal
-            );
-        }
+        this.Point = Point;
+        this.Normal = Normal;
     }
 
     /// <summary>
     /// Bypasses initialization of new MMT %Fact by using existend URI, _which is not checked for existence_.
     /// <see cref="Normal"/> set to <c>Vector3.up</c>
     /// </summary>
-    /// <param name="point">sets <see cref="Point"/></param>
-    /// <param name="uri">MMT URI</param>
-    public PointFact(Vector3 point, SOMDoc _ServerDefinition) : base()
+    /// <param name="Point">sets <see cref="Point"/></param>
+    /// <param name="ServerDefinition">MMT URI as OMS</param>
+    public PointFact(Vector3 Point, SOMDoc ServerDefinition) : base()
     {
-        this.Point = point;
+        this.Point = Point;
         this.Normal = Vector3.up;
-        this.ServerDefinition = _ServerDefinition;
+        this.ServerDefinition = ServerDefinition;
     }
 
     /// \copydoc Fact.parseFact(ScrollFact)
@@ -69,8 +51,19 @@ public PointFact(Vector3 point, SOMDoc _ServerDefinition) : base()
             yield break;
         ParsingDictionary.parseTermsToId.TryAdd(defines.ToString(), fact.@ref.uri);
 
-        Vector3 point = SOMDoc.MakeVector3(defines);
-        ret.Add(new PointFact(point, fact.@ref));
+        ret.Add(new PointFact(SOMDoc.MakeVector3(defines), fact.@ref));
+    }
+
+    protected override void RecalculateTransform()
+    {
+        Position = Point;
+        { // Rotation
+            Vector3 notNormal = Vector3.forward != Normal ? Vector3.forward : Vector3.up;
+            Rotation = Quaternion.LookRotation(
+                Vector3.Cross(Normal, notNormal),
+                Normal
+            );
+        }
     }
 
     /// \copydoc Fact.hasDependentFacts
@@ -520,24 +513,18 @@ private void Init(Vector3[] Verticies)
         throw new NotImplementedException();
     }
 
-    public override MMTFact MakeMMTDeclaration()
-    {
-        SOMDoc tp = new OMS(MMTConstants.Triangle);
-
-        return new MMTGeneralFact(_LastLabel, tp, Defines());
-    }
+    public override MMTFact MakeMMTDeclaration() 
+        => new MMTGeneralFact(_LastLabel, GetMMTType(), Defines());
 
     public override SOMDoc Defines()
-    //=> new OMA(
-    //        new OMS(MMTConstants.MakeType),
-    //        new[] {
-    //            new OML_Member("point1", null, SOMDoc.MakeVector3(point1)),
-    //        }
-    //    );
-    => new OMA(
-            new OMS(MMTConstants.CreateTriangle),
-            Verticies.Select(vert => SOMDoc.MakeVector3(vert)).ToArray()
-        );
+        //=> SOMDoc.SOMDocObject(
+        //        ((FunctionFact)FactRecorder.AllFacts[MMTConstants.CreateTriangle]).Function
+        //            (Verticies.Cast<object>().ToArray())[0]
+        //    );
+        => new OMA(
+                new OMS(MMTConstants.CreateTriangle),
+                Verticies.Select(vert => SOMDoc.MakeVector3(vert)).ToArray()
+            );
 
     protected override bool EquivalentWrapped(TriangleFact f1, TriangleFact f2)
     {
diff --git a/Assets/Scripts/Loading/Stage.cs b/Assets/Scripts/Loading/Stage.cs
index 1cb87299..6c81cf64 100644
--- a/Assets/Scripts/Loading/Stage.cs
+++ b/Assets/Scripts/Loading/Stage.cs
@@ -5,6 +5,7 @@
 using Newtonsoft.Json;
 using System;
 using static CommunicationEvents;
+using System.Collections;
 
 public class Stage : IJSONsavable<Stage>
 {
@@ -397,39 +398,6 @@ public bool LoadSavegames()
         return ret;
     }
 
-    /// <summary>
-    /// Looks for saved <see cref="Stage">Stages</see> in parametised directories and calls on them <see cref="ShallowLoad(out Stage, string)"/>.
-    /// </summary>
-    /// <param name="hierarchie">see <see cref="hierarchie"/> //TODO? Interface</param>
-    /// <param name="use_install_folder">see <see cref="use_install_folder"/></param>
-    /// <returns>contians all <see cref="Stage">Stages</see> found given parameters.</returns>
-    public static Dictionary<string, Stage> Grup(List<Directories> hierarchie = null, bool use_install_folder = false)
-    {
-        Dictionary<string, Stage> ret = new();
-
-        var new_hierarchie = IJSONsavable<Stage>.Instance._IJGetHierarchie(hierarchie);
-        string path = CreatePathToFile(out _, "", "", new_hierarchie, use_install_folder);
-
-        foreach (var file in new DirectoryInfo(path).GetFiles())
-        {
-            if (file.Extension != ".JSON")
-                continue;
-
-            try
-            {
-                if (ShallowLoad(out Stage tmp, file.FullName))
-                    ret.Add(tmp.name, tmp);
-            }
-            catch (Exception ex)
-            {
-                Debug.LogError("Could not load StageFile: " + file.FullName);
-                Debug.LogException(ex);
-            }
-        }
-
-        return ret;
-    }
-
     /// <summary>
     /// Calls <see cref="ClearPlay"/> and <see cref="store(bool)">store(true)</see>.
     /// </summary>
diff --git a/Assets/Scripts/MMTServer/CommunicationProtocoll/Endpoints.cs b/Assets/Scripts/MMTServer/CommunicationProtocoll/Endpoints.cs
index 6320f0f8..0b8ee4d6 100644
--- a/Assets/Scripts/MMTServer/CommunicationProtocoll/Endpoints.cs
+++ b/Assets/Scripts/MMTServer/CommunicationProtocoll/Endpoints.cs
@@ -105,6 +105,8 @@ public bool Equivalent(MMTFact f2)
         protected abstract bool EquivalentWrapped(MMTFact f1, MMTFact f2);
 
         public abstract SOMDoc GetMMTType();
+
+        public new abstract string ToString();
     }
 
     /// <summary>Class for facts without values, e.g. Points</summary>
@@ -185,6 +187,9 @@ protected override bool EquivalentWrapped(MMTFact f1, MMTFact f2)
 
         public override SOMDoc GetMMTType()
             => type;
+
+        public override string ToString()
+            => $"[{type}]: {defines}";
     }
 
     /// <summary>Class for facts with values, e.g. Distances or Angles</summary>
@@ -269,6 +274,9 @@ public override SOMDoc GetMMTType()
         {
             throw new System.NotImplementedException();
         }
+
+        public override string ToString()
+            => $"<{lhs}> == <{value}>";
     }
 
     public class Scroll
diff --git a/Assets/Scripts/MMTServer/CommunicationProtocoll/SOMDocToLambdaExpression.cs b/Assets/Scripts/MMTServer/CommunicationProtocoll/SOMDocToLambdaExpression.cs
index 2d1422a1..88e2f338 100644
--- a/Assets/Scripts/MMTServer/CommunicationProtocoll/SOMDocToLambdaExpression.cs
+++ b/Assets/Scripts/MMTServer/CommunicationProtocoll/SOMDocToLambdaExpression.cs
@@ -294,34 +294,6 @@ void ThrowArgumentException(ExpressionType expression_cast, int expected)
                     .Where(p => lambda_params.Contains(p))
                     .ToArray();
 
-                if (FactRecorder.AllFacts.TryGetValue(URI, out Fact fact))
-                {
-                    Expression lambda_orig;
-                    if (fact is not FunctionFact ffact)
-                    {
-                        LambdaExpression flambda_fact = fact
-                            .MakeMMTDeclaration()
-                            .GetDefines()
-                            .GetLambdaExpression();
-
-                        if (lambda_applicant.Length == 0)
-                            return flambda_fact;
-
-                        lambda_orig = flambda_fact;
-                    }
-                    else
-                    {
-                        if (lambda_applicant.Length == 0)
-                            return Expression.Lambda(
-                                    ffact.LambdaExpression,
-                                    found_bound_params
-                                );
-
-                        lambda_orig = ffact.LambdaExpression;
-                    }
-                    return _PartialInvoke(lambda_orig, lambda_applicant, found_bound_params);
-                }
-                else
                 if (MMTtoUnaryExpressionType.TryGetValue(URI, out var unnary_type))
                 {
                     if (lambda_applicant.Count() < 1)
@@ -349,6 +321,32 @@ void ThrowArgumentException(ExpressionType expression_cast, int expected)
                 {
                     return Expression.Lambda(Expression.Default(type), null);
                 }
+                else // Last entree to avoid stack-overflow:
+                if (FactRecorder.AllFacts.TryGetValue(URI, out Fact fact))
+                {
+                    type = fact.CompiledValue.GetType();
+                    Expression lambda_orig =
+                        Expression.Constant(fact.CompiledValue, type);
+
+                    if (FuncExtensions.IsFuncType(type, out int signature_count))
+                    { // has to be LambdaExpression!
+                        ParameterExpression[] invoke_params = type
+                            .GetGenericArguments()
+                            .Take(signature_count - 1)
+                            .Select(t => Expression.Parameter(t))
+                            .ToArray();
+
+                        lambda_orig = Expression.Lambda(
+                                Expression.Invoke(lambda_orig, invoke_params),
+                                invoke_params
+                            );
+                    }
+
+                    if (lambda_applicant.Length == 0)
+                        return Expression.Lambda(lambda_orig, null);
+                    else
+                        return _PartialInvoke(lambda_orig, lambda_applicant, found_bound_params);
+                }
 
                 throw new NotImplementedException("Could not map URI: \"" + URI + "\"");
             }
@@ -363,7 +361,7 @@ public static LambdaExpression _PartialInvoke(Expression func, LambdaExpression[
 
                 int params_count = signature_count - 1;
                 IEnumerable<Type> params_type = func.Type.GetGenericArguments().Take(params_count);
-                
+
                 int free_params = params_count - lambda_arguments.Length;
                 if (free_params <= 0)
                     return Expression.Lambda(
diff --git a/Assets/Scripts/MMTServer/CommunicationProtocoll/SOMDocs.cs b/Assets/Scripts/MMTServer/CommunicationProtocoll/SOMDocs.cs
index f224fd7f..9381af65 100644
--- a/Assets/Scripts/MMTServer/CommunicationProtocoll/SOMDocs.cs
+++ b/Assets/Scripts/MMTServer/CommunicationProtocoll/SOMDocs.cs
@@ -6,6 +6,8 @@
 using System;
 using UnityEngine;
 using MoreLinq;
+using System.Runtime.CompilerServices;
+using System.Collections;
 
 namespace REST_JSON_API
 {
@@ -112,6 +114,69 @@ public static SOMDoc SOMDocType(Type type)
             throw new NotImplementedException($"For Type {type}");
         }
 
+        public static SOMDoc SOMDocObject(object obj)
+        {
+            Type type = obj.GetType();
+
+            if (type == typeof(Vector3)) // Isomoprhismus
+                return MakeVector3((Vector3)obj);
+
+            if (obj is ITuple tuple) //TupleExtensions.IsTupleType(type, out int tuple_count)
+            {
+                SOMDoc[] payload = new SOMDoc[tuple.Length];
+                for (int i = 0; i < tuple.Length; i++)
+                    payload[i] = SOMDocObject(tuple[i]);
+
+                return MakeTupel(payload);
+            }
+
+            if (type.HasElementType) // pretend its a List
+                type = typeof(List<>);
+
+            if (type.IsGenericType) // Dictionary does not like Assembled Generics
+                type = type.GetGenericTypeDefinition();
+
+            if (type == typeof(List<>))
+            {
+                List<SOMDoc> payload = new();
+                foreach (object o in (IEnumerable)obj)
+                    payload.Add(SOMDocObject(o));
+
+                return MakeShallowList(payload.ToArray());
+            }
+
+            if (type.IsAnonymousType())
+                return new OMA(
+                    new OMS(MMTConstants.MakeType),
+                    type.GetFields()
+                        .Select(mem =>
+                            new OML_Member(
+                                mem.Name,
+                                null, //SOMDocType(mem.FieldType), 
+                                SOMDocObject(mem.GetValue(obj))
+                            )
+                        ).ToArray()
+                );
+
+            if (MMTConstants.TYPE_TO_OMS.TryGetValue(type, out string uri))
+                switch (obj)
+                {
+                    case bool b: return new OMLIT<bool>(b, uri);
+                    case int i: return new OMLIT<int>(i, uri);
+                    case float f: return new OMLIT<float>(f, uri);
+                    case double d: return new OMLIT<double>(d, uri);
+                    case char c: return new OMLIT<char>(c, uri);
+                    case string s: return new OMLIT<string>(s, uri);
+                    case Fact f: return f.Defines();
+                    default: goto Error;
+                }
+
+            if (FuncExtensions.IsFuncType(type, out _))
+                throw new NotSupportedException("Cannot reconstruct SOMDoc from Func<>!");
+            Error:
+            throw new NotImplementedException($"For Type {type}");
+        }
+
         // change to SOMDoc[] args?
         protected internal abstract Type ToType(Type[] args, (string name, Type type)[] bound_params);
         public Type ToType()
diff --git a/Assets/Scripts/StageStatic.cs b/Assets/Scripts/StageStatic.cs
index 7da9af0f..5c157f5a 100644
--- a/Assets/Scripts/StageStatic.cs
+++ b/Assets/Scripts/StageStatic.cs
@@ -3,6 +3,8 @@
 using System.Linq;
 using System;
 using UnityEngine;
+using static CommunicationEvents;
+using System.IO;
 
 /// <summary>
 /// Keeps track of all available and current <see cref="Stage"/>
@@ -13,13 +15,15 @@ public static class StageStatic
     /// - <c>Key</c>: stage name
     /// - <c>Value</c>: stages created by KWARC
     /// </summary>
-    public static Dictionary<string, Stage> StageOfficial;
+    public static IReadOnlyDictionary<string, Stage> StageOfficial => StageChapters[0];
 
     /// <summary>
     /// - <c>Key</c>: stage name
     /// - <c>Value</c>: stages created by local user
     /// </summary>
-    public static Dictionary<string, Stage> StageLocal;
+    public static IReadOnlyDictionary<string, Stage> StageLocal => StageChapters[1];
+
+    private static List<Dictionary<string, Stage>> StageChapters = new() { new(), new() };
 
     /// <summary>
     /// Used to map <see cref="StageOfficial"/> <see cref="Stage.category">categories</see> into a ordered list for the StageMenue.
@@ -39,7 +43,7 @@ public static class StageStatic
     /// !<see cref="Stage.use_install_folder"/> of current <see cref="stage"/> or one to be loaded.
     /// <seealso cref="LoadInitStage(bool, GameObject)"/>
     /// </summary>
-    public  static bool local_stage;
+    public static bool local_stage;
 
     /// <summary>
     /// Current <see cref="Mode"/>
@@ -54,16 +58,19 @@ public static class StageStatic
     /// <summary>
     /// Current <see cref="Stage"/>
     /// </summary>
-    public static Stage stage {
-        get {
-            return (local_stage ? StageLocal : StageOfficial)?[current_name];    
+    public static Stage stage
+    {
+        get
+        {
+            return (local_stage ? StageLocal : StageOfficial)?[current_name];
         }
-        set {
+        set
+        {
             current_name = value.name;
             local_stage = !value.use_install_folder;
 
-            (local_stage ? StageLocal : StageOfficial).Remove(current_name);
-            (local_stage ? StageLocal : StageOfficial).Add(current_name, value);
+            StageChapters[local_stage ? 1 : 0].Remove(current_name);
+            StageChapters[local_stage ? 1 : 0].Add(current_name, value);
         }
     }
 
@@ -76,7 +83,8 @@ public static double stage_time
     /// <summary>
     /// TODO: set when encountering an error
     /// </summary>
-    public static StageErrorStruct last_error {
+    public static StageErrorStruct last_error
+    {
         get;
         private set;
     }
@@ -131,25 +139,25 @@ public enum Mode
     public struct StageErrorStruct
     {
         /// <summary> set iff <see cref="Stage.category"/> is incompatible </summary>
-        public bool category    { get { return state[0]; } set { state[0] = value; } }
+        public bool category { get { return state[0]; } set { state[0] = value; } }
 
         /// <summary> set iff <see cref="Stage.number"/> is incompatible </summary>
-        public bool id          { get { return state[1]; } set { state[1] = value; } }
+        public bool id { get { return state[1]; } set { state[1] = value; } }
 
         /// <summary> set iff <see cref="Stage.name"/> is incompatible </summary>
-        public bool name        { get { return state[2]; } set { state[2] = value; } }
+        public bool name { get { return state[2]; } set { state[2] = value; } }
 
         /// <summary> set iff <see cref="Stage.description"/> is incompatible </summary>
         public bool description { get { return state[3]; } set { state[3] = value; } }
 
         /// <summary> set iff <see cref="Stage.scene"/> is incompatible </summary>
-        public bool scene       { get { return state[4]; } set { state[4] = value; } }
+        public bool scene { get { return state[4]; } set { state[4] = value; } }
 
         /// <summary> set iff !<see cref="Stage.use_install_folder"/> is incompatible </summary>
-        public bool local       { get { return state[5]; } set { state[5] = value; } }
+        public bool local { get { return state[5]; } set { state[5] = value; } }
 
         /// <summary> set iff <see cref="Stage.path"/> was not found </summary>
-        public bool load        { get { return state[6]; } set { state[6] = value; } }
+        public bool load { get { return state[6]; } set { state[6] = value; } }
 
 
         /// <summary>
@@ -167,7 +175,7 @@ public bool pass
 
         public readonly static StageErrorStruct
             InvalidFolder = new StageErrorStruct(false, false, false, false, false, true, false),
-            NotLoadable   = new StageErrorStruct(false, false, false, false, false, false, true);
+            NotLoadable = new StageErrorStruct(false, false, false, false, false, false, true);
 
         /// <summary>
         /// Initiator <br/>
@@ -198,7 +206,8 @@ public static void SetMode(Mode mode, GameObject gameObject = null)
         StageStatic.mode = mode;
 
         // handle StageStatic.mode
-        if (gameObject != null) {
+        if (gameObject != null)
+        {
             switch (mode)
             {
                 case Mode.Play:
@@ -223,7 +232,7 @@ public static void SetMode(Mode mode, GameObject gameObject = null)
     }
 
     public static StageErrorStruct Validate(string category, int id, string name, string description, string scene, bool local = true)
-    {   
+    {
         return new StageErrorStruct(
             category.Length == 0,
             ContainsNumber(category, id, true),
@@ -235,13 +244,13 @@ public static StageErrorStruct Validate(string category, int id, string name, st
             );
     }
 
-    public static StageErrorStruct LoadNewStage(string category, int id, string name, string description, string scene)
+    public static StageErrorStruct LoadNewStage(string category, int id, string name, string description, string scene, bool local = true)
     {
-        StageErrorStruct ret = Validate(category, id, name, description, scene, true);
+        StageErrorStruct ret = Validate(category, id, name, description, scene, local);
         if (!ret.pass)
             return ret;
 
-        stage = new Stage(category, id, name, description, scene, true);
+        stage = new Stage(category, id, name, description, scene, local);
         stage.store(force_stage_file: true);
 
         LoadCreate();
@@ -297,16 +306,59 @@ public static bool ContainsNumber(string category, int i, bool local)
             .Contains(i);
     }
 
+    private static int MaxTriesOfShallowLoadStages = 2;
+    private static int TriesOfShallowLoadStages = 0;
+
     /// <summary>
     /// Looks for and initial loads (see <see cref="Stage.ShallowLoad(out Stage, string)"/>) <see cref="Stage">Stages</see> in <see cref="local_stage"/> and !<see cref="local_stage"/>.
     /// </summary>
     public static void ShallowLoadStages(bool force = false)
     {
-        if(force)
-            StageOfficial = StageLocal = null;
+        if (MaxTriesOfShallowLoadStages <= TriesOfShallowLoadStages++
+         && !force)
+            return;
+
+        List<FileInfo>[] crawler = new List<FileInfo>[StageChapters.Count];
+
+        _ = new Stage(); // Init static members
+        var new_hierarchie = IJSONsavable<Stage>.Instance._IJGetHierarchie(null);
+
+        string
+        path = CreatePathToFile(out _, "", "", new_hierarchie, true);
+        crawler[0] = new DirectoryInfo(path).GetFiles().ToList();
+
+        path = CreatePathToFile(out _, "", "", new_hierarchie, false);
+        crawler[1] = new DirectoryInfo(path).GetFiles().ToList();
 
-        StageOfficial ??= Stage.Grup(null, true);
-        StageLocal ??= Stage.Grup(null, false);
+        for (int i = 0; i < StageChapters.Count; i++)
+            foreach (FileInfo file in crawler[i])
+            {
+                if (file.Extension != ".JSON"
+                 || StageChapters[i].ContainsKey(Path.GetFileNameWithoutExtension(file.Name)))
+                    continue;
+
+                try
+                {
+                    if (Stage.ShallowLoad(out Stage tmp, file.FullName))
+                        StageChapters[i].Add(tmp.name, tmp);
+                }
+                catch (Exception ex)
+                {
+                    Debug.LogError("Could not load StageFile: " + file.FullName);
+                    Debug.LogException(ex);
+                }
+            }
+
+        if (!force && GlobalBehaviour.InitiateContext.MoveNext()) // active wait at start instead?
+            GlobalBehaviour.Instance.StartCoroutine(_WaitForContext());
+
+        return;
+
+        static IEnumerator _WaitForContext()
+        {
+            yield return GlobalBehaviour.InitiateContext;
+            ShallowLoadStages(true);
+        }
     }
 
     /// <summary>
@@ -339,7 +391,7 @@ public static Stage GetStage(string name, bool local)
     public static void Delete(Stage stage)
     {
         GetStage(stage.name, !stage.use_install_folder).delete();
-        (!stage.use_install_folder ? StageLocal : StageOfficial).Remove(stage.name);
+        StageChapters[stage.use_install_folder ? 0 : 1].Remove(stage.name);
     }
 
     /// <summary>
@@ -392,7 +444,7 @@ public static bool LoadInitStage(bool restore_session, GameObject gameObject = n
             //    stage.player_record.seconds = -1;
         }
 
-        if(gameObject != null)
+        if (gameObject != null)
             gameObject.SetActiveByTagRecursive("DevelopingMode", mode == Mode.Create);
         SetMode(mode);
         return true;
diff --git a/Assets/Scripts/UI/MainMenue/PageLoader/StageLoader.cs b/Assets/Scripts/UI/MainMenue/PageLoader/StageLoader.cs
index 1fa12747..2660ab07 100644
--- a/Assets/Scripts/UI/MainMenue/PageLoader/StageLoader.cs
+++ b/Assets/Scripts/UI/MainMenue/PageLoader/StageLoader.cs
@@ -24,7 +24,7 @@ public override void Init()
         StageStatic.SetStage("", local);
         StageStatic.ShallowLoadStages();
 
-        Dictionary<string, Stage> dict = local ? 
+        IReadOnlyDictionary<string, Stage> dict = local ?
             StageStatic.StageLocal : StageStatic.StageOfficial;
 
         var ord = local ? 
diff --git a/Assets/misc.meta b/Assets/misc.meta
new file mode 100644
index 00000000..da5d7287
--- /dev/null
+++ b/Assets/misc.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 8e7e945081c0fb74c9af3afb160e602f
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
-- 
GitLab