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