Skip to content
Snippets Groups Projects
ScrollDetails.cs 15.1 KiB
Newer Older
  • Learn to ignore specific revisions
  • MaZiFAU's avatar
    MaZiFAU committed
    using Newtonsoft.Json;
    using REST_JSON_API;
    using System.Collections;
    
    using System.Collections.Generic;
    
    MaZiFAU's avatar
    MaZiFAU committed
    using System.Linq;
    
    using TMPro;
    
    MaZiFAU's avatar
    MaZiFAU committed
    using UnityEngine;
    
    using UnityEngine.Networking;
    
    MaZiFAU's avatar
    MaZiFAU committed
    using static CommunicationEvents;
    
    
    public class ScrollDetails : MonoBehaviour
    {
    
    MaZiFAU's avatar
    MaZiFAU committed
        public static ScrollDetails Instance
        {
            get => _Instance;
            set
            {
    
                if (_Instance != value)
    
    MaZiFAU's avatar
    MaZiFAU committed
                    Destroy(_Instance);
    
    MaZiFAU's avatar
    MaZiFAU committed
                _Instance = value;
    
    MaZiFAU's avatar
    MaZiFAU committed
            }
        }
        private static ScrollDetails _Instance;
    
    
    Richard Marcus's avatar
    Richard Marcus committed
        public WorldCursor cursor;
    
        public GameObject parameterDisplayPrefab;
    
        public static Scroll ActiveScroll { get; private set; }
    
        public GameObject mmtAnswerPopUp;
    
    MaZiFAU's avatar
    MaZiFAU committed
        private PopupBehavior Popup;
    
        public static List<RenderedScrollFact> ParameterDisplays { get; private set; }
    
        private static List<ScrollAssignment> LatestBackwartsCompletions;
    
        private static List<Fact> LatestRenderedHints;
    
    MaZiFAU's avatar
    MaZiFAU committed
        public bool DynamicScrollDescriptionsActive = true;
        public bool AutomaticHintGenerationActive = true;
    
    
    MaZiFAU's avatar
    MaZiFAU committed
        private bool DynamicScrollInQue = false;
    
    MaZiFAU's avatar
    MaZiFAU committed
        private readonly IReadOnlyList<string> NoDynamicScroll = new List<string>()
        {
    
    MaZiFAU's avatar
    MaZiFAU committed
            // Insert ScrollURIS that are poorly optimized
    
    MaZiFAU's avatar
    MaZiFAU committed
        void Awake()
    
    MaZiFAU's avatar
    MaZiFAU committed
            Instance = this;
    
    
    MaZiFAU's avatar
    MaZiFAU committed
            if (cursor == null)
                cursor = FindObjectOfType<WorldCursor>();
    
    
    MaZiFAU's avatar
    MaZiFAU committed
            Popup = mmtAnswerPopUp.GetComponent<PopupBehavior>();
            Popup.gameObject.SetActive(true); // force Awake
    
    Richard Marcus's avatar
    Richard Marcus committed
    
    
        private void OnEnable()
        {
    
            ScrollFactHintEvent.AddListener(animateHint);
    
    MaZiFAU's avatar
    MaZiFAU committed
            NewAssignmentEvent.AddListener(NewAssignmentTrigger);
    
        private void OnDisable()
        {
            ScrollFactHintEvent.RemoveListener(animateHint);
    
    MaZiFAU's avatar
    MaZiFAU committed
            NewAssignmentEvent.RemoveListener(NewAssignmentTrigger);
    
    MaZiFAU's avatar
    MaZiFAU committed
        private void OnDestroy()
        {
            _Instance = null;
        }
    
    
    MaZiFAU's avatar
    MaZiFAU committed
        public void SetScroll(Scroll scroll_to_set)
    
    BenniHome's avatar
    BenniHome committed
        {
    
    MaZiFAU's avatar
    MaZiFAU committed
            ActiveScroll = scroll_to_set;
    
            Transform originalScroll = gameObject.transform.GetChild(1);
    
            Transform originalScrollView = originalScroll.GetChild(1);
            Transform originalViewport = originalScrollView.GetChild(0);
    
    
            //Clear all current ScrollFacts
    
            originalViewport.GetChild(0).gameObject.DestroyAllChildren();
    
    MaZiFAU's avatar
    MaZiFAU committed
            originalScroll.GetChild(0).GetComponent<TextMeshProUGUI>().text = ActiveScroll.description;
    
            //ParameterDisplays.ForEach(gameObj => Destroy(gameObj));
            ParameterDisplays = new();
            for (int i = 0; i < ActiveScroll.requiredFacts.Count; i++)
    
    BenniHome's avatar
    BenniHome committed
            {
    
    MaZiFAU's avatar
    MaZiFAU committed
                GameObject originalObj =
                    Instantiate(parameterDisplayPrefab, originalViewport.GetChild(0));
    
    MaZiFAU's avatar
    MaZiFAU committed
                RenderedScrollFact originalRSF =
                    originalObj.GetComponentInChildren<RenderedScrollFact>();
    
    MaZiFAU's avatar
    MaZiFAU committed
                ParameterDisplays.Add(originalRSF);
    
    
                originalRSF.Populate(ActiveScroll, ActiveScroll.requiredFacts[i].@ref.uri);
    
    MaZiFAU's avatar
    MaZiFAU committed
            if (StageStatic.stage.solution.ScrollOverwrites
    
                    .TryGetValue(ActiveScroll.ScrollReference, out (string, int, bool)[] population)
             && population.Length > 0)
            {
                DynamicScrollInQue = true; // block update on population
    
    
    MaZiFAU's avatar
    MaZiFAU committed
                foreach ((string Id, int index, bool show) in population)
                {
                    ParameterDisplays[index].URI = Id;
                    ParameterDisplays[index].transform.parent.gameObject.SetActive(show);
                }
    
    
                DynamicScrollInQue = false; // unblock
            }
    
    
            NewAssignmentEvent.Invoke(); // init display
    
    MaZiFAU's avatar
    MaZiFAU committed
        public bool SetNextEmptyTo(FactObjectUI activator)
        {
            RenderedScrollFact check = ParameterDisplays
                .Find(RSF => RSF != null
                          && RSF.Payload != null
    
    MaZiFAU's avatar
    MaZiFAU committed
                          && RSF.Payload.Equals(activator));
    
    MaZiFAU's avatar
    MaZiFAU committed
    
            if (check != null)
            {
                check.URI = null;
                return false;
            }
    
            RenderedScrollFact empty = ParameterDisplays
                .Find(RSF => !RSF.IsSet);
    
            if (empty == null)
                return false;
    
            empty.SetByFactObject(activator);
            return true;
        }
    
    
    MaZiFAU's avatar
    MaZiFAU committed
        public void MagicButtonTrigger()
    
    MaZiFAU's avatar
    MaZiFAU committed
            StartCoroutine(_MagicButton());
    
    MaZiFAU's avatar
    MaZiFAU committed
            IEnumerator _MagicButton()
    
    BenniHome's avatar
    BenniHome committed
            {
    
                if (MagicInQue)
                    yield break;  // only need next in que to finish
    
                MagicInQue = true;
                while (!SendingViewDone || DynamicScrollInQue)
    
    MaZiFAU's avatar
    MaZiFAU committed
                    yield return null; // Wait for last assignment
    
    MaZiFAU's avatar
    MaZiFAU committed
                yield return SendView("/scroll/apply");
    
    
                if (currentMmtAnswer == null)
                {
    
    MaZiFAU's avatar
    MaZiFAU committed
                    Debug.LogError("Magic FAILED");
    
    MaZiFAU's avatar
    MaZiFAU committed
                    ScrollApplicationCheckingErrorEvent.Invoke(null);
    
    MaZiFAU's avatar
    MaZiFAU committed
                    if (VerboseURI)
                        Debug.Log("Magic answers:\n" + currentMmtAnswer);
    
    
                    System.DateTime serializeTime = System.DateTime.UtcNow;
    
    MaZiFAU's avatar
    MaZiFAU committed
                    ScrollApplicationInfo pushout = JsonConvert.DeserializeObject<ScrollApplicationInfo>(currentMmtAnswer);
    
                    Debug.LogFormat($"Answerd serialized in : {(System.DateTime.UtcNow - serializeTime).TotalMilliseconds}ms");
    
    MaZiFAU's avatar
    MaZiFAU committed
    
    
    MaZiFAU's avatar
    MaZiFAU committed
                    if (pushout.acquiredFacts.Count == 0
                     || pushout.errors.Length > 0)
                    {
                        ScrollApplicationCheckingErrorEvent.Invoke(pushout.errors);
                        PushoutFactFailEvent.Invoke();
                    }
    
                    else
                        Popup.HidePopUp(); //close error Window
    
    MaZiFAU's avatar
    MaZiFAU committed
    
    
                    yield return __GeneratePushoutFacts(pushout.acquiredFacts);
    
    
            IEnumerator __GeneratePushoutFacts(List<MMTFact> pushoutFacts)
            {
                List<Fact> new_facts = new();
    
                Dictionary<string, string> old_to_new = new();
    
                System.DateTime parseTime = System.DateTime.UtcNow;
    
                bool samestep = false;
                for (int i = 0; i < pushoutFacts.Count; i++)
                {
    
                    List<Fact> new_list = Fact.MMTFactory(pushoutFacts[i].MapURIs(old_to_new));
    
                    if (new_list.Count == 0)
                    {
                        Debug.LogWarning("Parsing on pushout-fact returned empty List -> One of the dependent facts does not exist or parsing failed");
                        continue;
                    }
    
                    foreach (Fact new_fact in new_list)
                    {
                        Fact added = FactAdder.AddFactIfNotFound(new_fact, out bool exists, samestep, null, ActiveScroll.label);
                        if (!exists)
                        {
                            new_facts.Add(added);
                            AnimateExistingFactEvent.Invoke(added.Id, FactWrapper.FactMaterials.Solution);
                            samestep = true;
                        }
                        else
                        {
                            // AnimateExistingFactEvent.Invoke(_new, FactWrapper.FactMaterials.Hint); // Automaticly done in FactRecorder
    
                            old_to_new.Add(new_fact.Id, added.Id);
    
                }
    
                Debug.Log($"Facts parsed within {(System.DateTime.UtcNow - parseTime).TotalMilliseconds}ms");
                yield break;
            }
    
    John Schihada's avatar
    John Schihada committed
    
    
    MaZiFAU's avatar
    MaZiFAU committed
        public void NewAssignmentTrigger()
    
            //return; //if you read this, delete this line!
    
    
            if (ActiveScroll?.ScrollReference == null
             || NoDynamicScroll.Contains(ActiveScroll.ScrollReference))
                return;
    
    
    MaZiFAU's avatar
    MaZiFAU committed
            if (AutomaticHintGenerationActive || DynamicScrollDescriptionsActive)
                StartCoroutine(_NewAssignment());
    
    MaZiFAU's avatar
    MaZiFAU committed
            IEnumerator _NewAssignment()
    
                if (DynamicScrollInQue)
    
    MaZiFAU's avatar
    MaZiFAU committed
                    yield break; // only need next in que to finish
    
                DynamicScrollInQue = true;
    
    MaZiFAU's avatar
    MaZiFAU committed
                    yield return null; // if we dont wait => server will crash
    
    MaZiFAU's avatar
    MaZiFAU committed
                DynamicScrollInQue = false;
    
    MaZiFAU's avatar
    MaZiFAU committed
                yield return SendView("/scroll/dynamic");
    
    
                if (currentMmtAnswer == null)
                {
    
    MaZiFAU's avatar
    MaZiFAU committed
                    Debug.LogError("Dynamic Scroll FAILED");
    
    MaZiFAU's avatar
    MaZiFAU committed
                    ScrollDynamicInfo scrollDynamicInfo;
                    try
                    {
                        scrollDynamicInfo = JsonConvert.DeserializeObject<ScrollDynamicInfo>(currentMmtAnswer);
    
                        //scrollDynamicInfo = IJSONsavable<ScrollDynamicInfo>.postprocess(scrollDynamicInfo); // DON'T! will remove hints
    
    MaZiFAU's avatar
    MaZiFAU committed
                    }
                    catch (JsonSerializationException ex)
                    {
                        Debug.LogException(ex);
                        Debug.LogError("Could not Deserialize MMT aswer for /scroll/dynamic\n" + currentMmtAnswer);
                        yield break;
                    }
    
                    ScrollApplicationCheckingError[] errors = scrollDynamicInfo.errors
                        .Where(err => err.kind != "nonTotal") // expected
                        .ToArray();
    
                    if (errors.Length > 0)
                        ScrollApplicationCheckingErrorEvent.Invoke(errors);
    
    
                    processScrollDynamicInfo(scrollDynamicInfo);
                }
    
    MaZiFAU's avatar
    MaZiFAU committed
        private IEnumerator SendView(string endpoint)
    
    BenniHome's avatar
    BenniHome committed
        {
    
            while (ParameterDisplays == null) // Wait for server
    
    MaZiFAU's avatar
    MaZiFAU committed
                yield return null;
    
    
            string body = prepareScrollAssignments();
    
    BenniHome's avatar
    BenniHome committed
    
    
            using UnityWebRequest www = UnityWebRequest.Put(ServerAdress + endpoint, body);
    
    BenniHome's avatar
    BenniHome committed
            www.method = UnityWebRequest.kHttpVerbPOST;
    
            www.SetRequestHeader("Content-Type", "application/json");
    
    MaZiFAU's avatar
    MaZiFAU committed
            System.DateTime sendTime = System.DateTime.UtcNow;
            yield return www.SendWebRequest();
    
            //if (VerboseURI)
            Debug.LogFormat("Server answerd in : {0}ms"
                , (System.DateTime.UtcNow - sendTime).TotalMilliseconds);
    
    BenniHome's avatar
    BenniHome committed
    
    
            if (www.result == UnityWebRequest.Result.ConnectionError
    
             || www.result == UnityWebRequest.Result.ProtocolError)
    
    BenniHome's avatar
    BenniHome committed
            {
    
                Debug.LogWarning(www.error);
    
    Benjamin Bösl's avatar
    Benjamin Bösl committed
            }
    
                while (!www.downloadHandler.isDone)
    
                    yield return null;
    
                currentMmtAnswer = www.downloadHandler.text
                    .Replace("\"float\":null", "\"float\":0.0"); // cannot convert null to value type
    
    MaZiFAU's avatar
    MaZiFAU committed
            string prepareScrollAssignments()
            {
    
    MaZiFAU's avatar
    MaZiFAU committed
                List<ScrollAssignment> assignmentList = new();
    
    MaZiFAU's avatar
    MaZiFAU committed
                for (int i = 0; i < ParameterDisplays.Count; i++)
                {
                    Fact tempFact = ParameterDisplays[i].Fact;
                    if (tempFact != null)
    
    MaZiFAU's avatar
    MaZiFAU committed
                        assignmentList.Add(new ScrollAssignment(ActiveScroll.requiredFacts[i].@ref.uri, tempFact.Id));
    
    MaZiFAU's avatar
    MaZiFAU committed
                }
    
                return JsonConvert.SerializeObject(new ScrollApplication(ActiveScroll.ScrollReference, assignmentList));
    
    MaZiFAU's avatar
    MaZiFAU committed
        private void processScrollDynamicInfo(ScrollDynamicInfo scrollDynamicInfo)
    
            //TODO: more hints available in scrollDynamicInfo.rendered.requiredFacts
    
    
            LatestBackwartsCompletions = scrollDynamicInfo.backward_completions.Count > 0
                ? scrollDynamicInfo.backward_completions[0]
    
    MaZiFAU's avatar
    MaZiFAU committed
                : new List<ScrollAssignment>();
    
            List<string> hintUris = LatestBackwartsCompletions
    
    MaZiFAU's avatar
    MaZiFAU committed
                .Select(completion => completion.fact.uri)
                .ToList();
    
            //Update Scroll, process data for later hints and update Uri-List for which hints are available
    
    MaZiFAU's avatar
    MaZiFAU committed
            _processRenderedScroll(scrollDynamicInfo.rendered, hintUris);
    
    MaZiFAU's avatar
    MaZiFAU committed
            if (AutomaticHintGenerationActive)
    
                //Show that Hint is available for ScrollParameter
                HintAvailableEvent.Invoke(hintUris);
    
    MaZiFAU's avatar
    MaZiFAU committed
            return;
    
    MaZiFAU's avatar
    MaZiFAU committed
            void _processRenderedScroll(Scroll rendered, List<string> hintUris)
    
    MaZiFAU's avatar
    MaZiFAU committed
                if (DynamicScrollDescriptionsActive)
                { // Update scroll-description
                    Transform scroll = gameObject.transform.GetChild(1).transform;
                    scroll.GetChild(0).GetComponent<TextMeshProUGUI>().text = rendered.description;
    
    MaZiFAU's avatar
    MaZiFAU committed
                LatestRenderedHints = new();
                for (int i = 0; i < rendered.requiredFacts.Count; i++)
    
    MaZiFAU's avatar
    MaZiFAU committed
                    RenderedScrollFact RenderedScrollFact = ParameterDisplays
    
                        .Find(RSF => RSF.ScrollFactURI == rendered.requiredFacts[i].@ref.uri);
    
                    if (RenderedScrollFact == null)
    
                    { // e.g. FUNCs
                        //if(CommunicationEvents.VerboseScroll)
                        //    Debug.Log($"Descrapancy between requiredFacts and displayed facts:" +
                        //        $"Could not find display with ref: {rendered.requiredFacts[i].@ref.uri}");
    
    MaZiFAU's avatar
    MaZiFAU committed
                    if (DynamicScrollDescriptionsActive)
                        //Update ScrollParameter label
                        RenderedScrollFact.Scroll = rendered;
    
    MaZiFAU's avatar
    MaZiFAU committed
                    //If ScrollFact is assigned -> No Hint
    
    MaZiFAU's avatar
    MaZiFAU committed
                    if (!RenderedScrollFact.IsSet)
    
                        List<Fact> HintFactList = Fact.MMTFactory(rendered.requiredFacts[i]);
    
    MaZiFAU's avatar
    MaZiFAU committed
    
    
                        foreach (Fact HintFact in HintFactList)
    
                            hintUris.Add(HintFact.Id); // == rendered.requiredFacts[i].@ref.uri
    
    MaZiFAU's avatar
    MaZiFAU committed
                            LatestRenderedHints.Add(HintFact);
                        }
    
    MaZiFAU's avatar
    MaZiFAU committed
                return;
            }
    
    MaZiFAU's avatar
    MaZiFAU committed
        public void animateHint(string scrollParameterUri)
    
    MaZiFAU's avatar
    MaZiFAU committed
            if (FactRecorder.AllFacts.ContainsKey(scrollParameterUri))
    
                AnimateExistingFactEvent.Invoke(
                        scrollParameterUri,
                        FactWrapper.FactMaterials.Hint
                    );
    
    
            Fact hintFact = LatestRenderedHints.Find(x => x.Id == scrollParameterUri); // "Dictionary"
    
    MaZiFAU's avatar
    MaZiFAU committed
    
            ScrollAssignment suitableCompletion =
    
                LatestBackwartsCompletions.Find((ScrollAssignment x) => x.fact.uri == scrollParameterUri); // "Dictionary"
    
            if (suitableCompletion != null && suitableCompletion.assignment is OMS assignment)
    
    MaZiFAU's avatar
    MaZiFAU committed
                if (FactRecorder.AllFacts.ContainsKey(assignment.uri))
    
                    AnimateExistingFactEvent.Invoke(
    
                        assignment.uri,
    
                        FactWrapper.FactMaterials.Hint
                    );
    
    MaZiFAU's avatar
    MaZiFAU committed
            else if (hintFact != null)
    
    MaZiFAU's avatar
    MaZiFAU committed
                if (FactRecorder.FindEquivalent(StageStatic.stage.factState.MyFactSpace, hintFact, out string found_key, out Fact _, out bool _, false))
    
                    // existing fact -> Animate that
                    AnimateExistingFactEvent.Invoke(
    
    MaZiFAU's avatar
    MaZiFAU committed
                        found_key,
    
                        FactWrapper.FactMaterials.Hint
                    );
    
    MaZiFAU's avatar
    MaZiFAU committed
                {   // Generate new FactRepresentation and animate it
                    AnimateNonExistingFactEvent.Invoke(hintFact);
    
                    AnimateExistingFactEvent.Invoke(
                        scrollParameterUri,
                        FactWrapper.FactMaterials.Hint
                    );