Contains all the methods to save and load all of the elements of a level, the elements contained in the TileMap.
Esempio n. 1
0
 public LevelSave GetLevelSave(string levelName)
 {
     if (mLevelSaves.ContainsKey(levelName))
     {
         return(mLevelSaves[levelName]);
     }
     return(mLevelSaves[levelName] = new LevelSave());
 }
    public void SaveGame()
    {
        ShapeData[]   shapes        = FindObjectsOfType <ShapeData>();
        InventoryData inventoryData = FindObjectOfType <InventoryData>();

        LevelSave.SaveGameplay(shapes, inventoryData);
        SceneManager.LoadScene("MainMenu");
    }
Esempio n. 3
0
 void Awake()
 {
     data = SaveLoad.LoadGame();
     if (SceneManager.GetActiveScene().name != data.level)
     {
         Load();
     }
 }
Esempio n. 4
0
    public static void SaveGame(string _level)
    {
        FileStream fs = new FileStream(path, FileMode.Create);

        LevelSave data = new LevelSave(_level); //Получение данных

        formatter.Serialize(fs, data);          //Сериализация данных

        fs.Close();
    }
Esempio n. 5
0
    public static void SaveGame(int partida)
    {
        BinaryFormatter formatter = new BinaryFormatter();
        string          path      = Application.persistentDataPath + "/DatosGuardados " + partida + ".MMM";
        FileStream      stream    = new FileStream(path, FileMode.Create);

        LevelSave levelSave = new LevelSave();

        formatter.Serialize(stream, levelSave);
        stream.Close();
    }
        void SaveLevels(GameLevel[] levels)
        {
            foreach (var l in levels)
            {
                var ls = new LevelSave();

                ls.index  = l.Index;
                ls.rating = l.Rating;
                ls.status = l.Status;

                levelSave.Add(ls);
            }
        }
        private static MySqlCommand ToMySqlCommand(LevelSave save)
        {
            var command = new MySqlCommand(MySqlDbManagerQueries.InsertUpdateLevel);

            command.Parameters.AddWithValue("DateCreated", save.DateCreated);
            command.Parameters.AddWithValue("DateLastSave", save.DateLastSave);
            command.Parameters.AddWithValue("PlayTime", (int)save.PlayTime.TotalSeconds);
            command.Parameters.AddWithValue("LoginCount", save.LoginCount);
            command.Parameters.AddWithValue("UserId", save.UserId);
            command.Parameters.AddWithValue("ClanId", save.ClanId);
            command.Parameters.AddWithValue("LevelJson", save.LevelJson);
            command.Parameters.AddWithValue("Token", save.Token);
            command.Parameters.AddWithValue("Name", save.Name);
            command.Parameters.AddWithValue("IsNamed", save.IsNamed);
            command.Parameters.AddWithValue("Trophies", save.Trophies);
            command.Parameters.AddWithValue("League", save.League);
            command.Parameters.AddWithValue("ExpPoints", save.ExpPoints);
            command.Parameters.AddWithValue("ExpLevel", save.ExpLevels);
            command.Parameters.AddWithValue("Gems", save.Gems);
            command.Parameters.AddWithValue("FreeGems", save.FreeGems);
            command.Parameters.AddWithValue("AttacksWon", save.AttacksWon);
            command.Parameters.AddWithValue("AttacksLost", save.AttacksLost);
            command.Parameters.AddWithValue("DefensesWon", save.DefensesWon);
            command.Parameters.AddWithValue("DefensesLost", save.DefensesLost);

            var stream = new MemoryStream();

            using (var w = new MessageWriter(stream))
            {
                WriteSlots(w, save.ResourcesCapacity);
                WriteSlots(w, save.ResourcesAmount);
                WriteSlots(w, save.Units);
                WriteSlots(w, save.Spells);
                WriteSlots(w, save.UnitUpgrades);
                WriteSlots(w, save.SpellUpgrades);
                WriteSlots(w, save.HeroUpgrades);
                WriteSlots(w, save.HeroHealths);
                WriteSlots(w, save.HeroStates);
                WriteSlots(w, save.AllianceUnits);
                WriteSlots(w, save.TutorialProgress);
                WriteSlots(w, save.Achievements);
                WriteSlots(w, save.AchievementProgress);
                WriteSlots(w, save.NpcStars);
                WriteSlots(w, save.NpcGold);
                WriteSlots(w, save.NpcElixir);

                command.Parameters.AddWithValue("slots", stream.ToArray());
            }

            return(command);
        }
        private static void FromMySqlDataReader(LevelSave save, DbDataReader reader)
        {
            save.UserId = (long)reader["user_id"];
            save.ClanId = reader["clan_id"] is DBNull ? null : (long?)reader["clan_id"];

            save.DateCreated  = (DateTime)reader["create_date"];
            save.DateLastSave = (DateTime)reader["last_save_date"];
            save.PlayTime     = TimeSpan.FromSeconds((int)reader["play_time_seconds"]);
            save.LoginCount   = (int)reader["login_count"];

            save.LevelJson = (string)reader["level_json"];

            save.Token = (string)reader["token"];

            save.Name         = (string)reader["name"];
            save.IsNamed      = (bool)reader["is_named"];
            save.Trophies     = (int)reader["trophies"];
            save.League       = (int)reader["league"];
            save.ExpPoints    = (int)reader["exp_points"];
            save.ExpLevels    = (int)reader["exp_levels"];
            save.Gems         = (int)reader["gems"];
            save.FreeGems     = (int)reader["free_gems"];
            save.AttacksWon   = (int)reader["atk_won"];
            save.AttacksLost  = (int)reader["atk_lost"];
            save.DefensesWon  = (int)reader["def_won"];
            save.DefensesLost = (int)reader["def_lost"];

            // Deserialize the slots.
            var slots  = (byte[])reader["slots"];
            var stream = new MemoryStream(slots);

            using (var r = new MessageReader(stream))
            {
                save.ResourcesCapacity   = ReadSlots <ResourceCapacitySlot>(r);
                save.ResourcesAmount     = ReadSlots <ResourceAmountSlot>(r);
                save.Units               = ReadSlots <UnitSlot>(r);
                save.Spells              = ReadSlots <SpellSlot>(r);
                save.UnitUpgrades        = ReadSlots <UnitUpgradeSlot>(r);
                save.SpellUpgrades       = ReadSlots <SpellUpgradeSlot>(r);
                save.HeroUpgrades        = ReadSlots <HeroUpgradeSlot>(r);
                save.HeroHealths         = ReadSlots <HeroHealthSlot>(r);
                save.HeroStates          = ReadSlots <HeroStateSlot>(r);
                save.AllianceUnits       = ReadSlots <AllianceUnitSlot>(r);
                save.TutorialProgress    = ReadSlots <TutorialProgressSlot>(r);
                save.Achievements        = ReadSlots <AchievementSlot>(r);
                save.AchievementProgress = ReadSlots <AchievementProgessSlot>(r);
                save.NpcStars            = ReadSlots <NpcStarSlot>(r);
                save.NpcGold             = ReadSlots <NpcGoldSlot>(r);
                save.NpcElixir           = ReadSlots <NpcElixirSlot>(r);
            }
        }
Esempio n. 9
0
        public bool Generate()
        {
            Run.Level    = this;
            rooms        = null;
            ItemsToSpawn = new List <string>();
            Variant      = VariantRegistry.Generate(LevelSave.BiomeGenerated.Id);

            if (Variant == null)
            {
                Variant = new RegularLevelVariant();
            }

            if (Run.Depth > 0)
            {
                var c = Rnd.Int(1, Run.Depth);

                if (Run.Level.Biome is CaveBiome)
                {
                    c = Rnd.Int(5, 15);
                }

                for (var i = 0; i < c; i++)
                {
                    ItemsToSpawn.Add("bk:emerald");
                }
            }

            Build();

            if (!Paint())
            {
                return(false);
            }

            if (rooms == null)
            {
                return(false);
            }

            TileUp();
            CreateBody();
            CreateDestroyableBody();
            LoadPassable();

            LevelSave.ResetGen();
            Log.Info("Done!");

            return(true);
        }
Esempio n. 10
0
    public static LevelSave LoadGame() //Метод загрузки
    {
        if (File.Exists(path))
        {                                                            // Проверка существования файла сохранения
            FileStream fs = new FileStream(path, FileMode.Open);     // Открытие потока

            LevelSave data = formatter.Deserialize(fs) as LevelSave; // Получение данных

            fs.Close();                                              // Закрытие потока

            return(data);                                            // Возвращение данных
        }

        return(null); // Если файл не существует, будет возвращено null
    }
Esempio n. 11
0
    /*  public static List<string> Save(GameObject level)
     * {
     *
     *    List<string> result = new List<string>();
     *    int count = level.transform.childCount;
     *    StreamWriter writer = new StreamWriter(path, true);
     *    for (int i = 0; i < count; i++)
     *    {
     *        Transform obj = level.transform.GetChild(i);
     *        LevelSave save = new LevelSave();
     *        save.x = obj.localPosition.x;
     *        save.y = obj.localPosition.y;
     *        save.z = obj.localPosition.z;
     *        string json = JsonUtility.ToJson(save);
     *        writer.WriteLine(json);
     *        result.Add(json);
     *    }
     *    writer.Close();
     *    return result;
     * }
     * public static void Load(List<string> json)
     * {
     *    int length = json.Count;
     *    StreamReader reader = new StreamReader(path);
     *    string jsoni=reader.ReadToEnd();
     *
     *    for (int i = 0; i < 0; i++)
     *    {
     *        LevelSave obj = JsonUtility.FromJson<LevelSave>(json[0]+json[1]);
     *        GameObject pre= GameObject.CreatePrimitive(PrimitiveType.Cube);
     *        pre.transform.position = new Vector3(obj.x, obj.y, obj.z);
     *    }
     *
     *
     *
     *    reader.Close();
     * }
     */
    public static void saveGame(LevelSave level)
    {
        BinaryFormatter bf = new BinaryFormatter();

        string filePath = Application.dataPath + inputPath;

        Debug.Log(filePath);
        FileStream fs = new FileStream(filePath, FileMode.Create);



        bf.Serialize(fs, level);

        fs.Close();
    }
Esempio n. 12
0
    public static void loadGame()
    {
        string filePath = Application.dataPath + inputPath;

        Debug.Log(filePath);
        if (File.Exists(filePath))
        {
            BinaryFormatter bf = new BinaryFormatter();
            FileStream      fs = new FileStream(filePath, FileMode.Open);

            LevelSave saveGameData = bf.Deserialize(fs) as LevelSave;

            fs.Close();


            GameObject parent = GameObject.Find("Level");
            if (parent == null)
            {
                GameObject par = new GameObject();
                parent = GameObject.Instantiate(par, Vector3.zero, Quaternion.identity);
            }
            parent.name = "Level";
            if (!saveGameData.assetPath.Equals(""))
            {
                GameObject prefab = (GameObject)AssetDatabase.LoadAssetAtPath(saveGameData.assetPath, typeof(GameObject));
                int        count  = saveGameData.posX.Count;
                for (int i = 0; i < count; i++)
                {
                    GameObject created = Instantiate(prefab, parent.transform, true);
                    created.transform.localPosition = new Vector3(saveGameData.posX[i], saveGameData.posY[i], saveGameData.posZ[i]);
                    created.transform.localRotation = Quaternion.Euler(new Vector3(saveGameData.rotationX[i], saveGameData.rotationY[i], saveGameData.rotationZ[i]));
                    created.transform.localScale    = new Vector3(saveGameData.scaleX[i], saveGameData.scaleY[i], saveGameData.scaleZ[i]);
                }
            }
            else
            {
                int count = saveGameData.posX.Count;
                for (int i = 0; i < count; i++)
                {
                    GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
                    cube.transform.SetParent(parent.transform);
                    cube.transform.localPosition = new Vector3(saveGameData.posX[i], saveGameData.posY[i], saveGameData.posZ[i]);
                    cube.transform.localRotation = Quaternion.Euler(new Vector3(saveGameData.rotationX[i], saveGameData.rotationY[i], saveGameData.rotationZ[i]));
                    cube.transform.localScale    = new Vector3(saveGameData.scaleX[i], saveGameData.scaleY[i], saveGameData.scaleZ[i]);
                }
            }
        }
    }
        private async Task InternalSaveLevelAsync(LevelSave level, bool newLevel, CancellationToken cancellationToken)
        {
            using (var sql = new MySqlConnection(_connectionString))
            {
                await sql.OpenAsync(cancellationToken);

                // Don't forget to update the DateLastSave value.
                level.DateLastSave = DateTime.UtcNow;

                // Convert the LevelSave to a MySqlCommand with the correct parameters.
                using (var command = ToMySqlCommand(level))
                {
                    command.Connection = sql;

                    var numRows = await command.ExecuteNonQueryAsync(cancellationToken);

                    if (newLevel && numRows == 1)
                    {
                        var newId = command.LastInsertedId;
                        Debug.Assert(newId != -1, "Number of rows affected was 1, however last insert id was 0.");

                        level.UserId = command.LastInsertedId;
                    }
                    else
                    {
                        Debug.Assert(level.UserId != 0);

                        // If the level isn't in a clan, we make sure its not in the clans_members table.
                        if (level.ClanId == null)
                        {
                            using (var command2 = new MySqlCommand("DELETE FROM `clan_members` WHERE `user_id` = @UserId", sql))
                            {
                                command2.Parameters.AddWithValue("UserId", level.UserId);

                                var numRows2 = await command2.ExecuteNonQueryAsync(cancellationToken);

                                if (numRows2 == 1)
                                {
                                    Server.Logs.Info("Deleting entry from clans_members since level is not in clan.");
                                }
                            }
                        }
                    }
                }
            }
        }
Esempio n. 14
0
        void SaveLevel()
        {
            string path = "";

            if (source != null)
            {
                if (!AssetDatabase.Contains(source))
                {
                    Debug.LogError("Please use  prefabs to save the level");
                    return;
                }
                else
                {
                    path = AssetDatabase.GetAssetPath(source);
                }
            }
            _level = GameObject.Find("Level");

            LevelSave levelText = new LevelSave();

            levelText.assetPath = path;

            int count = _level.transform.childCount;

            for (int i = 1; i <= count; i++)
            {
                Transform childTransform = _level.transform.GetChild(count - i).transform;
                Vector3   pos            = childTransform.localPosition;
                Vector3   scale          = childTransform.localScale;
                Vector3   rotation       = childTransform.rotation.eulerAngles;
                levelText.posX.Add(pos.x);
                levelText.posY.Add(pos.y);
                levelText.posZ.Add(pos.z);

                levelText.scaleX.Add(scale.x);
                levelText.scaleY.Add(scale.y);
                levelText.scaleZ.Add(scale.z);

                levelText.rotationX.Add(rotation.x);
                levelText.rotationY.Add(rotation.y);
                levelText.rotationZ.Add(rotation.z);
            }
            SaveGame.saveGame(levelText);
        }
Esempio n. 15
0
    public static LevelSave LoadGame(int partida)
    {
        string path = Application.persistentDataPath + "/DatosGuardados " + partida + ".MMM";;

        if (File.Exists(path))
        {
            BinaryFormatter formatter = new BinaryFormatter();
            FileStream      stream    = new FileStream(path, FileMode.Open);

            LevelSave levelSave = formatter.Deserialize(stream) as LevelSave;

            stream.Close();
            return(levelSave);
        }
        else
        {
            Debug.LogError("El archivo con extension .MMM no existe en" + path + ", error al cargar");
            return(null);
        }
    }
 public void SaveNewLevel()
 {
     ShapeData[] shapes = FindObjectsOfType <ShapeData>();
     LevelSave.SaveLevel(shapes);
     SceneManager.LoadScene("MainMenu");
 }
Esempio n. 17
0
    /// <summary>
    /// Save all the data from the map editor to ajson file.
    /// </summary>
    /// <param name="t_fileName">The name of the file in which the data will be saved</param>
    /// <returns>Bool for if the file was save succesfully</returns>
    public bool SaveLevel(string t_fileName)
    {
        LevelSave.SaveLevel(m_map, t_fileName, m_tileSprites, m_mapObjects);

        return(true);
    }
Esempio n. 18
0
    /// <summary>
    /// Loads in the data from the a file who's name matches the passed in
    /// name. If the file fails to load false is returned otherwise the
    /// map editor data is populated. If the level editor is not null its
    /// UI data is populated. If the passed in bool is true then the real
    /// prefabs are instanciated within the scene instead of the map objects.
    /// </summary>
    /// <param name="t_fileName">The name of the file that is to be loaded</param>
    /// <param name="t_loadRealObjects">Bool for it the original prefabs should be placed or the fake ones</param>
    /// <returns>Bool for if the file was loaded succesfuly or not</returns>
    public bool LoadLevel(string t_fileName, bool t_loadRealObjects)
    {
        if (t_fileName != "")
        {
            LevelSaveData saveData = LevelSave.LoadLevel(t_fileName);

            if (saveData != null)
            {
                ClearAllData();
                CreateMap(saveData.m_mapWidth, saveData.m_mapHeight);

                foreach (string path in saveData.m_tileSpritePaths)
                {
                    LoadtTileSprite(path);

                    if (m_levelEditor != null)
                    {
                        m_levelEditor.CreateSpriteButton(path);
                    }
                }

                for (int x = 0; x < saveData.m_spriteNames.Count; x++)
                {
                    ColumnWrapper wrapperClass = saveData.m_spriteNames[x];

                    for (int y = 0; y < wrapperClass.m_spriteNames.Count; y++)
                    {
                        Sprite sprite = m_map.GetTile(new MapIndex(x, y)).GetSprite();

                        foreach (string path in m_tileSprites.Keys)
                        {
                            if (path.Contains(wrapperClass.m_spriteNames[y]))
                            {
                                sprite = m_tileSprites[path];
                                break;
                            }
                        }

                        m_map.GetTile(new MapIndex(x, y)).SetSprite(sprite);
                    }
                }

                for (int i = 0; i < saveData.m_objectsData.Count; i++)
                {
                    LoadMapObject(saveData.m_objectsData[i].m_name,
                                  saveData.m_objectsData[i].m_width,
                                  saveData.m_objectsData[i].m_height);

                    if (m_levelEditor != null)
                    {
                        m_levelEditor.CreateObjectButton(m_mapObjects[saveData.m_objectsData[i].m_name]);
                    }
                }

                for (int i = 0; i < saveData.m_placedObjects.Count; i++)
                {
                    if (m_mapObjects.ContainsKey(saveData.m_placedObjects[i].m_name))
                    {
                        MapObject mapObject = m_mapObjects[saveData.m_placedObjects[i].m_name];

                        Vector2 position = saveData.m_placedObjects[i].m_position;

                        position.x = position.x - ((mapObject.m_width - 1) * m_map.m_tileSize) / 2;
                        position.y = position.y - ((mapObject.m_height - 1) * m_map.m_tileSize) / 2;

                        MapIndex mapIndex = m_map.WorldPositionToMapIndex(position);

                        if (t_loadRealObjects)
                        {
                            InstantiateRealObject(mapIndex, mapObject);
                        }

                        else
                        {
                            InstantiateMapObject(mapIndex, mapObject);
                        }
                    }
                }

                return(true);
            }
        }

        return(false);
    }
    // Start is called before the first frame update
    void Awake()
    {
        LevelData levelData = LevelSave.loadLevel();

        if (levelData != null)
        {
            foreach (SaveShapeData shape in levelData.m_saveShapeDatas)
            {
                switch (shape.name)
                {
                case "Bush_01(Clone)":
                    GameObject Bush_01 = Instantiate <GameObject>(m_shapes[(int)Objects.Bush_01]);
                    Bush_01.transform.position = shape.objectPosition;
                    break;

                case "Bush_02(Clone)":
                    GameObject Bush_02 = Instantiate <GameObject>(m_shapes[(int)Objects.Bush_02]);
                    Bush_02.transform.position = shape.objectPosition;
                    break;

                case "Grass_01(Clone)":
                    GameObject Grass_01 = Instantiate <GameObject>(m_shapes[(int)Objects.Grass_01]);
                    Grass_01.transform.position = shape.objectPosition;
                    break;

                case "Grass_02(Clone)":
                    GameObject Grass_02 = Instantiate <GameObject>(m_shapes[(int)Objects.Grass_02]);
                    Grass_02.transform.position = shape.objectPosition;
                    break;

                case "Ground_01(Clone)":
                    GameObject Ground_01 = Instantiate <GameObject>(m_shapes[(int)Objects.Ground_01]);
                    Ground_01.transform.position = shape.objectPosition;
                    break;

                case "Ground_02(Clone)":
                    GameObject Ground_02 = Instantiate <GameObject>(m_shapes[(int)Objects.Ground_02]);
                    Ground_02.transform.position = shape.objectPosition;
                    break;

                case "Ground_03(Clone)":
                    GameObject Ground_03 = Instantiate <GameObject>(m_shapes[(int)Objects.Ground_03]);
                    Ground_03.transform.position = shape.objectPosition;
                    break;

                case "Mushroom1(Clone)":
                    GameObject Mushroom1 = Instantiate <GameObject>(m_shapes[(int)Objects.Mushroom1]);
                    Mushroom1.transform.position = shape.objectPosition;
                    break;

                case "Mushroom2(Clone)":
                    GameObject Mushroom2 = Instantiate <GameObject>(m_shapes[(int)Objects.Mushroom2]);
                    Mushroom2.transform.position = shape.objectPosition;
                    break;

                case "Rock_01(Clone)":
                    GameObject Rock_01 = Instantiate <GameObject>(m_shapes[(int)Objects.Rock_01]);
                    Rock_01.transform.position = shape.objectPosition;
                    break;

                case "Rock_03(Clone)":
                    GameObject Rock_03 = Instantiate <GameObject>(m_shapes[(int)Objects.Rock_03]);
                    Rock_03.transform.position = shape.objectPosition;
                    break;

                case "Rock_04(Clone)":
                    GameObject Rock_04 = Instantiate <GameObject>(m_shapes[(int)Objects.Rock_04]);
                    Rock_04.transform.position = shape.objectPosition;
                    break;

                case "Stump_01(Clone)":
                    GameObject Stump_01 = Instantiate <GameObject>(m_shapes[(int)Objects.Stump_01]);
                    Stump_01.transform.position = shape.objectPosition;
                    break;

                case "Tree_01(Clone)":
                    GameObject Tree_01 = Instantiate <GameObject>(m_shapes[(int)Objects.Tree_01]);
                    Tree_01.transform.position = shape.objectPosition;
                    break;

                case "Tree_02(Clone)":
                    GameObject Tree_02 = Instantiate <GameObject>(m_shapes[(int)Objects.Tree_02]);
                    Tree_02.transform.position = shape.objectPosition;
                    break;

                case "Tree_03(Clone)":
                    GameObject Tree_03 = Instantiate <GameObject>(m_shapes[(int)Objects.Tree_03]);
                    Tree_03.transform.position = shape.objectPosition;
                    break;

                case "Wood(Clone)":
                    GameObject Wood = Instantiate <GameObject>(m_shapes[(int)Objects.Wood]);
                    Wood.transform.position = shape.objectPosition;
                    break;

                case "EnemySpawner(Clone)":
                    GameObject Spawner = Instantiate <GameObject>(m_shapes[(int)Objects.Spawner]);
                    Spawner.transform.position = shape.objectPosition;
                    break;

                default:
                    break;
                }
            }
            foreach (collectables inventoryData in levelData.m_saveInventoryData.itemTypes)
            {
                switch (inventoryData)
                {
                case collectables.WOOD:
                    m_playerBackPack.GetComponent <InventoryScript>().inventory.Add(collectables.WOOD);
                    break;

                case collectables.STONE:
                    m_playerBackPack.GetComponent <InventoryScript>().inventory.Add(collectables.STONE);
                    break;

                case collectables.MUSHROOM1:
                    m_playerBackPack.GetComponent <InventoryScript>().inventory.Add(collectables.MUSHROOM1);
                    break;

                case collectables.MUSHROOM2:
                    m_playerBackPack.GetComponent <InventoryScript>().inventory.Add(collectables.MUSHROOM2);
                    break;

                default:
                    break;
                }
            }
            m_playerBackPack.GetComponent <InventoryScript>().SetupSavedInventory(levelData);
        }
    }
Esempio n. 20
0
 public void CustomMap()
 {
     LevelSave.SetCurrentLevel("Level1");
     SceneManager.LoadScene("Gameplay Scene");
     LevelSave.loadLevel();
 }
Esempio n. 21
0
 public void DefaultMap()
 {
     LevelSave.SetCurrentLevel("BOB");
     SceneManager.LoadScene("Gameplay Scene");
     LevelSave.loadLevel();
 }
Esempio n. 22
0
 public void ContinueGame()
 {
     SceneManager.LoadScene("Gameplay Scene");
     LevelSave.loadLevel();
 }
 public Task SaveLevelAsync(LevelSave level, CancellationToken token)
 => InternalSaveLevelAsync(level, false, token);