예제 #1
0
        public BeatmapLevelDataObject DeserializeFromJson(string songPath, string overrideLevelID)
        {
            try
            {
                var jsonSettings = new JsonSerializerSettings()
                {
                    ContractResolver = new MetadataResolver(_assetsFile)
                };

                string infoFile = Path.Combine(songPath, "Info.dat");

                BeatmapLevelDataObject bml = null;

                using (var sr = new StreamReader(_config.SongFileProvider.GetReadStream(infoFile)))
                {
                    bml = JsonConvert.DeserializeObject <BeatmapLevelDataObject>(sr.ReadToEnd(), jsonSettings);
                }

                if (!string.IsNullOrWhiteSpace(overrideLevelID))
                {
                    bml.LevelID = overrideLevelID;
                }
                return(bml);
            }
            catch (Exception ex)
            {
                Log.LogErr("Exception deserializing level", ex);
                return(null);
            }
        }
예제 #2
0
        //todo: not sure if this is always safe to assume the folder where the ogg is has the info.dat, but I hope it is
        public string GetCoverImageFilename(BeatmapLevelDataObject levelData)
        {
            var path = levelData?.AudioClip?.Object?.Resource?.Source;

            if (path == null)
            {
                Log.LogErr("Trying to get the cover image file, audio clip resource object was null!");
                return(null);
            }
            if (!path.StartsWith(_config.SongsPath))
            {
                Log.LogErr($"The audio clip path for level ID {levelData.LevelID} of '{path}' doesn't match with the configured songs path of '{_config.SongsPath}'.  Can't get cover art image location!");
                return(null);
            }

            //path = path.Substring(_config.SongsPath.Length).TrimStart('/');
            int idx = path.LastIndexOf("/");

            path = path.Substring(0, idx);

            var infodatfile = path.CombineFwdSlash("info.dat");

            if (!_config.SongFileProvider.FileExists(infodatfile))
            {
                Log.LogErr($"Could not find {infodatfile} for level ID {levelData.LevelID}");
                return(null);
            }

            //I hope this is a faster way than deserializing the entire object and worth the double code paths for parsing the same serialized type
            string imageFilename = null;

            try
            {
                using (var jr = new JsonTextReader(new StreamReader(_config.SongFileProvider.GetReadStream(infodatfile))))
                {
                    while (jr.Read())
                    {
                        if (jr.TokenType == JsonToken.PropertyName && jr.Value?.ToString() == "_coverImageFilename")
                        {
                            if (jr.Read() && jr.TokenType == JsonToken.String)
                            {
                                imageFilename = jr.Value?.ToString();
                                break;
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Log.LogErr($"Exception trying to read info.dat to get _coverImageFilename for level ID {levelData.LevelID} from '{infodatfile}'.", ex);
                return(null);
            }
            return(imageFilename);
        }
예제 #3
0
        public AudioClipObject LoadSongAudioAsset(string songPath, BeatmapLevelDataObject levelData)
        {
            string audioClipFile = songPath.CombineFwdSlash(levelData.SongFilename);
            //string outputFileName = levelData.LevelID + ".ogg";
            int    channels;
            int    frequency;
            Single length;

            byte[] oggBytes = _config.SongFileProvider.Read(audioClipFile);
            unsafe
            {
                GCHandle pinnedArray = GCHandle.Alloc(oggBytes, GCHandleType.Pinned);
                try
                {
                    IntPtr pointer = pinnedArray.AddrOfPinnedObject();
                    int    error;
                    StbSharp.StbVorbis.stb_vorbis_alloc alloc;
                    StbSharp.StbVorbis.stb_vorbis       v = StbSharp.StbVorbis.stb_vorbis_open_memory((byte *)pointer.ToPointer(), oggBytes.Length, &error, &alloc);
                    channels  = v.channels;
                    frequency = (int)v.sample_rate;
                    length    = StbSharp.StbVorbis.stb_vorbis_stream_length_in_seconds(v);
                    StbSharp.StbVorbis.stb_vorbis_close(v);
                }
                catch (Exception ex)
                {
                    Log.LogErr($"Exception parsing ogg file {audioClipFile}", ex);
                    return(null);
                }
                finally
                {
                    pinnedArray.Free();
                }
            }
            var audioClip = new AudioClipObject(_assetsFile)
            {
                Name              = levelData.LevelID,
                LoadType          = 1,
                IsTrackerFormat   = false,
                Ambisonic         = false,
                SubsoundIndex     = 0,
                PreloadAudioData  = false,
                LoadInBackground  = true,
                Legacy3D          = true,
                CompressionFormat = 1,
                BitsPerSample     = 16,
                Channels          = channels,
                Frequency         = frequency,
                Length            = (Single)length,
                Resource          = new StreamedResource(audioClipFile, 0, Convert.ToUInt64(_config.SongFileProvider.GetFileSize(audioClipFile)))
            };

            return(audioClip);
        }
예제 #4
0
        public Texture2DObject LoadSongCover(string songPath, BeatmapLevelDataObject levelData)
        {
            if (!string.IsNullOrWhiteSpace(levelData.CoverImageFilename) && _config.SongFileProvider.FileExists(songPath.CombineFwdSlash(levelData.CoverImageFilename)))
            {
                try
                {
                    string coverFile = songPath.CombineFwdSlash(levelData.CoverImageFilename);

                    var coverAsset = new Texture2DObject(_assetsFile)
                    {
                        Name = levelData.LevelID + "Cover"
                    };
                    byte[] imageBytes = _config.SongFileProvider.Read(coverFile);
                    ImageUtils.Instance.AssignImageToTexture(imageBytes, coverAsset, 256, 256);
                    return(coverAsset);
                }
                catch (Exception ex)
                {
                    Log.LogErr("Error loading cover art asset", ex);
                }
            }
            return(null);
        }
예제 #5
0
        public Texture2DObject LoadSongCover(string songPath, BeatmapLevelDataObject levelData)
        {
            if (!string.IsNullOrWhiteSpace(levelData.CoverImageFilename) && File.Exists(Path.Combine(songPath, levelData.CoverImageFilename)))
            {
                try
                {
                    string coverFile  = Path.Combine(songPath, levelData.CoverImageFilename);
                    Bitmap coverImage = (Bitmap)Bitmap.FromFile(coverFile);

                    var coverAsset = new Texture2DObject(_assetsFile)
                    {
                        Name = levelData.LevelID + "Cover"
                    };

                    ImageUtils.AssignImageToTexture(coverImage, coverAsset, 256, 256);
                    return(coverAsset);
                }
                catch (Exception ex)
                {
                    Log.LogErr("Error loading cover art asset", ex);
                }
            }
            return(null);
        }
예제 #6
0
        public BeatmapLevelDataObject LoadSongToAsset(BeatmapLevelDataObject beatmapLevel, string songPath, bool includeCovers = true)
        {
            try
            {
                beatmapLevel.Name = $"{beatmapLevel.LevelID}Level";

                //cover art
                Texture2DObject coverImage = null;
                if (includeCovers)
                {
                    coverImage = LoadSongCover(songPath, beatmapLevel);
                }

                //audio
                var audioAsset = LoadSongAudioAsset(songPath, beatmapLevel);
                if (audioAsset == null)
                {
                    Log.LogErr($"failed to get audio for song at path {songPath}");
                    return(null);
                }

                var toRemoveSet = new List <DifficultyBeatmapSet>();
                foreach (var difficultySet in beatmapLevel.DifficultyBeatmapSets)
                {
                    var characteristic = GetCharacteristicAsset(difficultySet.BeatmapCharacteristicName)?.PtrFrom(beatmapLevel);
                    if (characteristic == null)
                    {
                        Log.LogErr($"Characteristic {difficultySet.BeatmapCharacteristicName} couldn't be found.  Set will be removed.");
                        toRemoveSet.Add(difficultySet);
                        continue;
                    }
                    difficultySet.BeatmapCharacteristic = characteristic;
                    List <DifficultyBeatmap> toRemove = new List <DifficultyBeatmap>();
                    foreach (var difficultyBeatmap in difficultySet.DifficultyBeatmaps)
                    {
                        string dataFile = null;
                        if (!string.IsNullOrWhiteSpace(difficultyBeatmap.BeatmapFilename))
                        {
                            dataFile = songPath.CombineFwdSlash(difficultyBeatmap.BeatmapFilename);
                            if (!_config.SongFileProvider.FileExists(dataFile))
                            {
                                Log.LogErr($"BeatmapFilename was set to {dataFile} but the file didn't exist, will try to fall back to difficulty name.");
                                dataFile = null;
                            }
                        }
                        if (dataFile == null)
                        {
                            dataFile = songPath.CombineFwdSlash($"{difficultyBeatmap.Difficulty.ToString()}.dat");
                        }

                        if (!_config.SongFileProvider.FileExists(dataFile))
                        {
                            Log.LogErr(dataFile + " is missing, skipping this difficulty");
                            toRemove.Add(difficultyBeatmap);
                            continue;
                        }
                        string jsonData = _config.SongFileProvider.ReadToString(dataFile);
                        if (_assetsFile != null)
                        {
                            difficultyBeatmap.BeatmapData = new BeatmapDataObject(_assetsFile);
                        }

                        difficultyBeatmap.BeatmapData.Name           = beatmapLevel.LevelID + ((difficultySet.BeatmapCharacteristicName == Characteristic.Standard) ? "" : difficultySet.BeatmapCharacteristicName.ToString()) + difficultyBeatmap.Difficulty.ToString() + "BeatmapData";
                        difficultyBeatmap.BeatmapData.BeatsPerMinute = beatmapLevel.BeatsPerMinute;
                        difficultyBeatmap.BeatmapData.Shuffle        = beatmapLevel.Shuffle;
                        difficultyBeatmap.BeatmapData.ShufflePeriod  = beatmapLevel.ShufflePeriod;
                        difficultyBeatmap.BeatmapData.JsonData       = jsonData;

                        _assetsFile.AddObject(difficultyBeatmap.BeatmapData, true);
                        difficultyBeatmap.BeatmapDataPtr = difficultyBeatmap.BeatmapData.PtrFrom(beatmapLevel);
                    }
                    toRemove.ForEach(x => difficultySet.DifficultyBeatmaps.Remove(x));
                    if (difficultySet.DifficultyBeatmaps.Count < 1)
                    {
                        Log.LogErr($"Song at path {songPath} has no valid beatmaps for any difficulty on set {difficultySet.BeatmapCharacteristicName}, removing it");
                        toRemoveSet.Add(difficultySet);
                        continue;
                    }
                }
                toRemoveSet.ForEach(x => beatmapLevel.DifficultyBeatmapSets.Remove(x));
                if (beatmapLevel.DifficultyBeatmapSets.Count < 1)
                {
                    Log.LogErr($"Song at path {songPath} has no valid characterstics, it will not be imported");
                    return(null);
                }
                _assetsFile.AddObject(audioAsset, true);
                if (coverImage != null)
                {
                    _assetsFile.AddObject(coverImage);
                }

                beatmapLevel.AudioClip = audioAsset.PtrFrom(beatmapLevel);
                if (coverImage == null)
                {
                    var bsCover = _assetsFile.FindAsset <Texture2DObject>(x => x.Object.Name == "BeatSaberCover");
                    if (bsCover == null)
                    {
                        Log.LogErr("Unable to find BeatSaberCover in assets!  How is that gone?");
                        throw new Exception("Could not find beat saber cover in assets!  That should never be missing.");
                    }
                    var cover = bsCover.Clone();

                    _assetsFile.AddObject(cover, true);
                    beatmapLevel.CoverImageTexture2D = cover.PtrFrom(beatmapLevel);
                }
                else
                {
                    beatmapLevel.CoverImageTexture2D = coverImage.PtrFrom(beatmapLevel);
                }
                var environment = GetEnvironment(beatmapLevel.EnvironmentName);
                if (environment == null)
                {
                    Log.LogMsg($"Unknown environment name '{beatmapLevel.EnvironmentName}' on '{beatmapLevel.SongName}', falling back to default.");
                    environment = GetEnvironment("DefaultEnvironment");
                    if (environment == null)
                    {
                        throw new Exception("Unable to find the default environment!");
                    }
                }

                beatmapLevel.EnvironmentInfo = environment.PtrFrom(beatmapLevel);
                _assetsFile.AddObject(beatmapLevel, true);
                return(beatmapLevel);
            }
            catch (Exception ex)
            {
                Log.LogErr($"Error loading song from path {songPath}", ex);
                return(null);
            }
        }
예제 #7
0
        public BeatmapLevelDataObject LoadSongToAsset(BeatmapLevelDataObject beatmapLevel, string songPath, out string oggFileName, bool includeCovers = true)
        {
            oggFileName = null;
            try
            {
                beatmapLevel.Name = $"{beatmapLevel.LevelID}Level";

                //cover art
                Texture2DObject coverImage = null;
                if (includeCovers)
                {
                    coverImage = LoadSongCover(songPath, beatmapLevel);
                }

                //audio
                var audioAsset = LoadSongAudioAsset(songPath, beatmapLevel);
                if (audioAsset == null)
                {
                    Log.LogErr($"failed to get audio for song at path {songPath}");
                    return(null);
                }
                oggFileName = Path.Combine(songPath, beatmapLevel.SongFilename);;

                foreach (var difficultySet in beatmapLevel.DifficultyBeatmapSets)
                {
                    difficultySet.BeatmapCharacteristic = GetCharacteristicAsset(difficultySet.BeatmapCharacteristicName).PtrFrom(beatmapLevel);
                    List <DifficultyBeatmap> toRemove = new List <DifficultyBeatmap>();
                    foreach (var difficultyBeatmap in difficultySet.DifficultyBeatmaps)
                    {
                        var dataFile = Path.Combine(songPath, $"{difficultyBeatmap.Difficulty.ToString()}.dat");
                        if (!File.Exists(dataFile))
                        {
                            Log.LogErr(dataFile + " is missing, skipping this difficulty");
                            toRemove.Add(difficultyBeatmap);
                            continue;
                        }
                        string jsonData;
                        using (var sr = new StreamReader(dataFile))
                        {
                            jsonData = sr.ReadToEnd();
                        }
                        if (_assetsFile != null)
                        {
                            difficultyBeatmap.BeatmapData = new BeatmapDataObject(_assetsFile);
                        }

                        difficultyBeatmap.BeatmapData.Name           = beatmapLevel.LevelID + ((difficultySet.BeatmapCharacteristicName == Characteristic.Standard) ? "" : difficultySet.BeatmapCharacteristicName.ToString()) + difficultyBeatmap.Difficulty.ToString() + "BeatmapData";
                        difficultyBeatmap.BeatmapData.BeatsPerMinute = beatmapLevel.BeatsPerMinute;
                        difficultyBeatmap.BeatmapData.Shuffle        = beatmapLevel.Shuffle;
                        difficultyBeatmap.BeatmapData.ShufflePeriod  = beatmapLevel.ShufflePeriod;
                        difficultyBeatmap.BeatmapData.JsonData       = jsonData;
                        difficultyBeatmap.BeatmapData.TransformToProjectedData();
                        difficultyBeatmap.BeatmapData.JsonData = null;

                        _assetsFile.AddObject(difficultyBeatmap.BeatmapData, true);
                        difficultyBeatmap.BeatmapDataPtr = difficultyBeatmap.BeatmapData.PtrFrom(beatmapLevel);
                    }
                    toRemove.ForEach(x => difficultySet.DifficultyBeatmaps.Remove(x));
                    if (difficultySet.DifficultyBeatmaps.Count < 1)
                    {
                        Log.LogErr($"Song at path {songPath} has no valid beatmaps for any difficulty, skipping song");
                        return(null);
                    }
                }

                _assetsFile.AddObject(audioAsset, true);
                if (coverImage != null)
                {
                    _assetsFile.AddObject(coverImage);
                }

                beatmapLevel.AudioClip = audioAsset.PtrFrom(beatmapLevel);
                if (coverImage == null)
                {
                    beatmapLevel.CoverImageTexture2D = _assetsFile.FindAsset <Texture2DObject>(x => x.Object.Name == "BeatSaberCover").PtrFrom(beatmapLevel);
                }
                else
                {
                    beatmapLevel.CoverImageTexture2D = coverImage.PtrFrom(beatmapLevel);
                }
                var environment = _assetsFile.Manager.MassFirstOrDefaultAsset <MonoBehaviourObject>(x => x.Object.Name == $"{beatmapLevel.EnvironmentName}SceneInfo");
                if (environment == null)
                {
                    Log.LogMsg($"Unknown environment name '{beatmapLevel.EnvironmentName}' on '{beatmapLevel.SongName}', falling back to default.");
                    environment = _assetsFile.Manager.MassFirstAsset <MonoBehaviourObject>(x => x.Object.Name == "DefaultEnvironmentSceneInfo");
                }

                beatmapLevel.EnvironmentSceneInfo = environment.PtrFrom(beatmapLevel);
                _assetsFile.AddObject(beatmapLevel, true);
                return(beatmapLevel);
            }
            catch (Exception ex)
            {
                Log.LogErr($"Error loading song from path {songPath}", ex);
                return(null);
            }
        }