Skip to content
Snippets Groups Projects
StageStatic.cs 16.9 KiB
Newer Older
  • Learn to ignore specific revisions
  • MaZiFAU's avatar
    MaZiFAU committed
    using System;
    
    using System.Collections;
    using System.Collections.Generic;
    
    MaZiFAU's avatar
    MaZiFAU committed
    using System.IO;
    
    using static CommunicationEvents;
    
    Marco Zimmer's avatar
    Marco Zimmer committed
    /// <summary>
    /// Keeps track of all available and current <see cref="Stage"/>
    /// </summary>
    
    Marco Zimmer's avatar
    Marco Zimmer committed
        /// <summary>
        /// - <c>Key</c>: stage name
        /// - <c>Value</c>: stages created by KWARC
        /// </summary>
    
        public static IReadOnlyDictionary<string, Stage> StageOfficial => StageChapters[0];
    
    Marco Zimmer's avatar
    Marco Zimmer committed
    
        /// <summary>
        /// - <c>Key</c>: stage name
        /// - <c>Value</c>: stages created by local user
        /// </summary>
    
        public static IReadOnlyDictionary<string, Stage> StageLocal => StageChapters[1];
    
    
    MaZiFAU's avatar
    MaZiFAU committed
        private static readonly List<Dictionary<string, Stage>> StageChapters = new() { new(), new() };
    
    Marco Zimmer's avatar
    Marco Zimmer committed
    
        /// <summary>
    
    Stefan Richter's avatar
    Stefan Richter committed
        /// Used to map <see cref="StageOfficial"/> <see cref="Stage.category">categories</see> into a ordered list for the StageMenu.
    
    Marco Zimmer's avatar
    Marco Zimmer committed
        /// </summary>
    
        public static Dictionary<string, int> Category = new Dictionary<string, int> {
            { "", -1 },
            { "Demo Category", 0 },
        };
    
    Marco Zimmer's avatar
    Marco Zimmer committed
        /// <summary>
        /// <see cref="Stage.name"/> of current <see cref="stage"/> or one to be loaded.
        /// <seealso cref="LoadInitStage(bool, GameObject)"/>
        /// </summary>
    
    Marco Zimmer's avatar
    Marco Zimmer committed
    
        /// <summary>
        /// !<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;
    
    Marco Zimmer's avatar
    Marco Zimmer committed
    
        /// <summary>
        /// Current <see cref="Mode"/>
        /// </summary>
    
    Marco Zimmer's avatar
    Marco Zimmer committed
        /// <summary>
        /// Loadable world scenes
        /// </summary>
        public static readonly List<string> Worlds = GenerateWorldList();
    
    Marco Zimmer's avatar
    Marco Zimmer committed
        /// <summary>
        /// Current <see cref="Stage"/>
        /// </summary>
    
        public static Stage stage
        {
            get
            {
                return (local_stage ? StageLocal : StageOfficial)?[current_name];
    
                current_name = value.name;
                local_stage = !value.use_install_folder;
    
    
                StageChapters[local_stage ? 1 : 0].Remove(current_name);
                StageChapters[local_stage ? 1 : 0].Add(current_name, value);
    
        /// \copydoc PlayerRecord.seconds
        public static double stage_time
            => ContainsKey(current_name)
            ? stage.player_record.seconds + Time.timeSinceLevelLoadAsDouble
            : double.NaN;
    
    
    Marco Zimmer's avatar
    Marco Zimmer committed
        /// <summary>
        /// TODO: set when encountering an error
        /// </summary>
    
        public static StageErrorStruct last_error
        {
    
        // TODO! generate at buildtime
    
    Marco Zimmer's avatar
    Marco Zimmer committed
        /// <summary>
        /// Extracts all loadable scenes for <see cref="Worlds"/>.
        /// </summary>
        /// <returns><see cref="Worlds"/></returns>
    
        private static List<string> GenerateWorldList()
        {
    
    Marco Zimmer's avatar
    Marco Zimmer committed
            List<string> _Worlds = new List<string>();
    
    
            string world = "World";
            string ending = ".unity";
            foreach (UnityEditor.EditorBuildSettingsScene scene in UnityEditor.EditorBuildSettings.scenes)
            {
                if (scene.enabled)
                {
                    string name = new System.IO.FileInfo(scene.path).Name;
                    name = name.Substring(0, name.Length - ending.Length);
    
                    if (0 == string.Compare(name, name.Length - world.Length, world, 0, world.Length))
                    {
                        _Worlds.Add(name);
                    }
                }
    
    Marco Zimmer's avatar
    Marco Zimmer committed
            List<string> _Worlds = new List<string> {"TreeWorld", "RiverWorld"};
    
            Debug.Log("WorldList might be incomplete or incorrect!");
    #endif
    
    
            return _Worlds;
    
    Marco Zimmer's avatar
    Marco Zimmer committed
        /// <summary>
        /// Available Modes a <see cref="Stage"/> to be selected and/ or loaded in.
        /// </summary>
    
    Marco Zimmer's avatar
    Marco Zimmer committed
        /// <summary>
        /// Created when an error (may) occures while a <see cref="Stage"/> is being created, because of incompatible variables.
        /// </summary>
    
    Marco Zimmer's avatar
    Marco Zimmer committed
            /// <summary> set iff <see cref="Stage.category"/> is incompatible </summary>
    
            public bool category { get { return state[0]; } set { state[0] = value; } }
    
    Marco Zimmer's avatar
    Marco Zimmer committed
    
            /// <summary> set iff <see cref="Stage.number"/> is incompatible </summary>
    
            public bool id { get { return state[1]; } set { state[1] = value; } }
    
    Marco Zimmer's avatar
    Marco Zimmer committed
    
            /// <summary> set iff <see cref="Stage.name"/> is incompatible </summary>
    
            public bool name { get { return state[2]; } set { state[2] = value; } }
    
    Marco Zimmer's avatar
    Marco Zimmer committed
    
            /// <summary> set iff <see cref="Stage.description"/> is incompatible </summary>
    
            public bool description { get { return state[3]; } set { state[3] = value; } }
    
    Marco Zimmer's avatar
    Marco Zimmer committed
    
            /// <summary> set iff <see cref="Stage.scene"/> is incompatible </summary>
    
            public bool scene { get { return state[4]; } set { state[4] = value; } }
    
    Marco Zimmer's avatar
    Marco Zimmer committed
    
            /// <summary> set iff !<see cref="Stage.use_install_folder"/> is incompatible </summary>
    
            public bool local { get { return state[5]; } set { state[5] = value; } }
    
    Marco Zimmer's avatar
    Marco Zimmer committed
    
            /// <summary> set iff <see cref="Stage.path"/> was not found </summary>
    
            public bool load { get { return state[6]; } set { state[6] = value; } }
    
    Marco Zimmer's avatar
    Marco Zimmer committed
    
            /// <summary>
            /// stores all boolish members, to iterate over
            /// </summary>
    
    MaZiFAU's avatar
    MaZiFAU committed
            private readonly bool[] state;
    
    Marco Zimmer's avatar
    Marco Zimmer committed
            /// <summary>
            /// <see langword="true"/> iff no error occures.
            /// </summary>
    
            public bool pass
            {
                get { return state.Aggregate(true, (last, next) => last && !next); }
            }
    
            public readonly static StageErrorStruct
                InvalidFolder = new StageErrorStruct(false, false, false, false, false, true, false),
    
                NotLoadable = new StageErrorStruct(false, false, false, false, false, false, true);
    
    Marco Zimmer's avatar
    Marco Zimmer committed
            /// <summary>
            /// Initiator <br/>
            /// canonical
            /// </summary>
    
            public StageErrorStruct(bool category, bool id, bool name, bool description, bool scene, bool local, bool load)
            {
                state = new bool[7];
    
                this.category = category;
                this.id = id;
                this.name = name;
                this.description = description;
                this.scene = scene;
                this.local = local;
                this.load = load;
            }
        }
    
    
    Marco Zimmer's avatar
    Marco Zimmer committed
        /// <summary>
        /// sets <see cref="mode"/> and en-/ disables children of <paramref name="gameObject"/> with certain Tags, only available in certain <see cref="Mode">Modes</see> (e.g. in Def_Stage)
        /// </summary>
        /// <param name="mode"><see cref="Mode"/> to set</param>
        /// <param name="gameObject"> which children will be checked</param>
    
        public static void SetMode(Mode mode, GameObject gameObject = null)
        {
    
            if (gameObject != null)
            {
    
                {
                    case Mode.Play:
                        gameObject.SetActiveByTagRecursive("CreatorMode", false);
                        break;
                    case Mode.Create:
                        gameObject.SetActiveByTagRecursive("CreatorMode", true);
                        break;
                }
    
            }
    
            // handle stage mode
            switch (mode)
            {
                case Mode.Play:
                case Mode.Create:
    
    Marco Zimmer's avatar
    Marco Zimmer committed
                    if (ContainsKey(current_name, local_stage))
                        stage.SetMode(mode == Mode.Create);
    
        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),
    
                name.Length == 0 || ContainsKey(name, false) || ContainsKey(name, true),
    
    MaZiFAU's avatar
    MaZiFAU committed
        public static StageErrorStruct LoadNewStage(string category, int id, string name, string description, string scene, bool local = true, bool forcelocal = false)
    
    MaZiFAU's avatar
    MaZiFAU committed
            StageErrorStruct ret = Validate(category, id, name, description, scene, forcelocal ? true : local);
    
                return ret;
    
            stage = new Stage(category, id, name, description, scene, local);
    
            LoadCreate();
            return ret;
        }
    
    Marco Zimmer's avatar
    Marco Zimmer committed
        /// <summary>
        /// Load current <see cref="stage"/> in <see cref="Mode.Create"/>
        /// </summary>
    
        public static void LoadCreate()
        {
    
    Marco Zimmer's avatar
    Marco Zimmer committed
            SetMode(Mode.Create);
    
            Loader.LoadScene(stage.scene);
    
    Marco Zimmer's avatar
    Marco Zimmer committed
        /// <summary>
        /// Finds first unused <see cref="Stage.number"/> in a certain <paramref name="category"/>.
        /// </summary>
        /// <param name="local">which kind of stage we are looking at</param>
        /// <param name="category">the category in question</param>
        /// <returns>first unused <see cref="Stage.number"/> in a certain <paramref name="category"/></returns>
        public static int NextNumber(bool local, string category)
    
    Marco Zimmer's avatar
    Marco Zimmer committed
            var numbers = (local ? StageLocal : StageOfficial).Values.Where(s => s.category == category).Select(s => s.number).ToList();
    
    
            if (0 == numbers.Count)
                return 1;
    
            numbers.Sort();
            int last = numbers[0];
            foreach (int i in numbers)
            {
                if (i > last && i != last + 1)
                    return last + 1;
                last = i;
            }
    
            return last + 1;
        }
    
    
    Marco Zimmer's avatar
    Marco Zimmer committed
        /// <summary>
        /// Looks wether an <see cref="Stage.number"/> <paramref name="i"/> exists within a certain <see cref="Stage.category"/> <paramref name="category"/> in local saves (<paramref name="local"/> == <see langword="true"/>) or install path.
        /// </summary>
        /// <param name="category">to look in</param>
        /// <param name="i">to look for</param>
        /// <param name="local">where to look</param>
        /// <returns></returns>
    
        public static bool ContainsNumber(string category, int i, bool local)
    
            return (local ? StageLocal : StageOfficial).Values
                .Where(s => s.category == category)
                .Select(s => s.number)
                .Contains(i);
    
    MaZiFAU's avatar
    MaZiFAU committed
        private static readonly int MaxTriesOfShallowLoadStages = 2;
    
        private static int TriesOfShallowLoadStages = 0;
    
    
    Marco Zimmer's avatar
    Marco Zimmer committed
        /// <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"/>.
    
    Marco Zimmer's avatar
    Marco Zimmer committed
        /// </summary>
    
    MaZiFAU's avatar
    MaZiFAU committed
        public static void ShallowLoadStages(bool force = false)
    
            if (MaxTriesOfShallowLoadStages <= TriesOfShallowLoadStages++
             && !force)
                return;
    
    
            //GlobalBehaviour.InitiateContext.FastForward(); //active wait
    
    
            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();
    
            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 + "\n" +
                            "See Log below!");
    
                        Debug.LogException(ex);
                    }
                }
    
    
    MaZiFAU's avatar
    MaZiFAU committed
            if (!GlobalBehaviour.ContextLoaded) // active wait at start instead?
    
                GlobalBehaviour.Instance.StartCoroutine(_WaitForContext());
    
            return;
    
            static IEnumerator _WaitForContext()
            {
    
    MaZiFAU's avatar
    MaZiFAU committed
                while (!GlobalBehaviour.ContextLoaded)
    
    MaZiFAU's avatar
    MaZiFAU committed
                    yield return null;
    
    
                ShallowLoadStages(true);
            }
    
    Marco Zimmer's avatar
    Marco Zimmer committed
        /// <summary>
        /// Sets parameters, defining what to load in <see cref="LoadInitStage(bool, GameObject)"/> and <see cref="LoadInitStage(string, bool, bool, GameObject)"/>.
        /// </summary>
        /// <param name="name">sets <see cref="current_name"/></param>
        /// <param name="local">sets <see cref="local_stage"/></param>
    
        public static void SetStage(string name, bool local)
    
    Marco Zimmer's avatar
    Marco Zimmer committed
        /// <summary>
        /// Returns a <see cref="Stage"/> or throws <see cref="Exception"/> if not found.
        /// </summary>
        /// <param name="name"><see cref="Stage.name"/></param>
        /// <param name="local">where to look</param>
        /// <returns><c>(local ? StageLocal : StageOfficial)[name];</c></returns>
    
        public static Stage GetStage(string name, bool local)
        {
            return (local ? StageLocal : StageOfficial)[name];
        }
    
    
    Marco Zimmer's avatar
    Marco Zimmer committed
        /// <summary>
        /// Deletes a <see cref="Stage"/> and all its associated files (including save games).
    
    Marco Zimmer's avatar
    Marco Zimmer committed
        /// </summary>
        /// <param name="stage">to be deleted</param>
    
        public static void Delete(Stage stage)
        {
    
            GetStage(stage.name, !stage.use_install_folder).delete();
    
            StageChapters[stage.use_install_folder ? 0 : 1].Remove(stage.name);
    
    Marco Zimmer's avatar
    Marco Zimmer committed
        /// <summary>
        /// Wrapps <see cref="LoadInitStage(bool, GameObject)"/> with extra parameters.
        /// Loads and initiates <see cref="Stage"/> defined by <paramref name="name"/> and <paramref name="local"/>.
        /// </summary>
        /// <param name="name">sets <see cref="current_name"/> iff succeedes</param>
        /// <param name="local">sets <see cref="current_name"/> iff succeedes</param>
        /// <param name="restore_session">wether to restore last (loaded) player session (<see langword="true"/>) or start from scratch (<see langword="false"/>).</param>
        /// <param name="gameObject">(e.g. UI/ Def_Stage) toggles recursively children with tag "DevelopingMode" to <see cref="mode"/> == <see cref="Mode.Create"/>.</param>
        /// <returns><see langword="false"/> iff <see cref="Stage"/> defined by <paramref name="name"/> and <paramref name="local"/> could not be *found* or *loaded*.</returns>
    
        public static bool LoadInitStage(string name, bool local = false, bool restore_session = true, GameObject gameObject = null)
        {
            bool old_l = local_stage;
            string old_n = current_name;
            SetStage(name, local);
    
            if (!LoadInitStage(restore_session, gameObject))
            {
                local_stage = old_l;
                current_name = old_n;
                return false;
            }
    
            return true;
        }
    
    
    Marco Zimmer's avatar
    Marco Zimmer committed
        /// <summary>
        /// Loads and initiates <see cref="Stage"/> defined by <see cref="current_name"/> and <see cref="local_stage"/>.
        /// </summary>
        /// <param name="restore_session">wether to restore last (loaded) player session (<see langword="true"/>) or start from scratch (<see langword="false"/>).</param>
        /// <param name="gameObject">(e.g. UI/ Def_Stage) toggles recursively children with tag "DevelopingMode" to <see cref="mode"/> == <see cref="Mode.Create"/>.</param>
        /// <returns><see langword="false"/> iff <see cref="Stage"/> defined by <see cref="current_name"/> and <see cref="local_stage"/> could not be *found* or *loaded*.</returns>
    
        public static bool LoadInitStage(bool restore_session, GameObject gameObject = null)
    
                return false;
    
            if (restore_session)
            {
                stage.factState.invoke = true;
                stage.factState.Draw();
            }
            else
    
                //if(mode == Mode.Create) // block saving "player" progress
                //    stage.player_record.seconds = -1;
    
            if (gameObject != null)
    
                gameObject.SetActiveByTagRecursive("DevelopingMode", mode == Mode.Create);
    
    Marco Zimmer's avatar
    Marco Zimmer committed
        /// <summary>
        /// Wrapps <see cref="ContainsKey(string, bool)"/>; defaulting local to <see cref="local_stage"/>
        /// </summary>
    
        public static bool ContainsKey(string key)
        {
            return ContainsKey(key, local_stage);
        }
    
    Marco Zimmer's avatar
    Marco Zimmer committed
    
        /// <summary>
        /// Looks for a <see cref="Stage"/> <paramref name="key"/> in <see cref="StageLocal"/> (<paramref name="local"/>==<see langword="true"/>) or <see cref="StageOfficial"/> (<paramref name="local"/>==<see langword="false"/>).
        /// </summary>
        /// <returns><c>(local ? StageLocal : StageOfficial).ContainsKey(key)</c></returns>
    
    Marco Zimmer's avatar
    Marco Zimmer committed
        public static bool ContainsKey(string key, bool local)
    
            return (local ? StageLocal : StageOfficial)?.ContainsKey(key) ?? false;