static void Prefix(StandardLevelDetailView __instance, IBeatmapLevel level, BeatmapDifficulty defaultDifficulty, BeatmapCharacteristicSO defaultBeatmapCharacteristic, PlayerData playerData)
        {
            List <BeatmapCharacteristicSO> toGenerate = new List <BeatmapCharacteristicSO>();

            if (Config.Instance.ShowGenerated360)
            {
                toGenerate.Add(GameModeHelper.GetGenerated360GameMode());
            }
            if (Config.Instance.ShowGenerated90)
            {
                toGenerate.Add(GameModeHelper.GetGenerated90GameMode());
            }

            List <IDifficultyBeatmapSet> sets = new List <IDifficultyBeatmapSet>(level.beatmapLevelData.difficultyBeatmapSets);

            // Generate each custom gamemode
            foreach (BeatmapCharacteristicSO customGameMode in toGenerate)
            {
                if (level.beatmapLevelData.difficultyBeatmapSets.Any((e) => e.beatmapCharacteristic.serializedName == GameModeHelper.GENERATED_360DEGREE_MODE))
                {
                    // Already added the generated gamemode
                    continue;
                }

                IDifficultyBeatmapSet basedOnGameMode = level.beatmapLevelData.difficultyBeatmapSets.FirstOrDefault((e) => e.beatmapCharacteristic.serializedName == Config.Instance.BasedOn);
                if (basedOnGameMode == null)
                {
                    // Level does not have a standard mode to base its 360 mode on
                    continue;
                }

                CustomDifficultyBeatmapSet customSet    = new CustomDifficultyBeatmapSet(customGameMode);
                CustomDifficultyBeatmap[]  difficulties = basedOnGameMode.difficultyBeatmaps.Select((e) => new CustomDifficultyBeatmap(e.level, customSet, e.difficulty, e.difficultyRank, e.noteJumpMovementSpeed, e.noteJumpStartBeatOffset, e.beatmapData.GetCopy())).ToArray();
                customSet.SetCustomDifficultyBeatmaps(difficulties);
                sets.Add(customSet);
            }

            // Update difficultyBeatmapSets
            if (level.beatmapLevelData is BeatmapLevelData data)
            {
                if (!FieldHelper.Set(data, "_difficultyBeatmapSets", sets.ToArray()))
                {
                    Plugin.Log.Warn("Could not set new difficulty sets");
                    return;
                }
            }
            else
            {
                Plugin.Log.Info("Unsupported beatmapLevelData: " + (level.beatmapLevelData?.GetType().FullName ?? "null"));
            }
        }
        public void Init(IBeatmapLevel rootBeatmap)
        {
            // LevelsList のデータ構成
            // 0,1,2,3,4|0,1,2,3,4|0,1,2,3,4|0,1,2,3,4

            // {index} : {data}
            // 0 : モードと難易度を組み合わせたフラグ
            // 1 : ノーツ数
            // 2 : ボム数
            // 3 : ウォール数
            // 4 : NJS

            //Logger.Debug(LevelsList);
            DifficultyBeatmapSets = LevelsList.Split('|')
                                    .Select(level => level.Split(','))
                                    .GroupBy(data => int.Parse(data[0]) & FLAGS_LEVELS_ALLMODE) // モードごとに処理
                                    .Select <IGrouping <int, string[]>, IDifficultyBeatmapSet>(grouping =>
            {
                var charateristic = GetBeatmapCharacteristicCollectionFromSO(ToSerializedName(grouping.Key));

                if (charateristic == null)
                {
                    if (CharacteristicSOsDictionary.ContainsKey(grouping.Key))
                    {
                        charateristic = CharacteristicSOsDictionary[grouping.Key];
                    }
                    else
                    {
                        charateristic = new SimpleBeatmapCharacteristicSO(
                            serializedName: ToSerializedName(grouping.Key),
                            compoundIdPartName: ToCompoundIdPartName(grouping.Key),
                            characteristicNameLocalizationKey: ToCharacteristicNameLocalizationKey(grouping.Key),
                            descriptionLocalizationKey: ToDescriptionLocalizationKey(grouping.Key),
                            sortingOrder: grouping.Key,
                            containsRotationEvents: ToContainsRotationEvents(grouping.Key),
                            requires360Movement: ToRequires360Movement(grouping.Key))
                        {
                            hideFlags = HideFlags.DontSave | HideFlags.NotEditable,
                        };
                        CharacteristicSOsDictionary.Add(grouping.Key, charateristic);
                    }
                }

                var difficultyBeatmapSet = new CustomDifficultyBeatmapSet(charateristic);
                difficultyBeatmapSet.SetCustomDifficultyBeatmaps(
                    grouping.Select(data => new CustomDifficultyBeatmap(
                                        rootBeatmap,                                  // level
                                        difficultyBeatmapSet,                         // parent difficulty set
                                        ToBeatmapDifficulty(int.Parse(data[0])),      // difficulty
                                        (int)ToBeatmapDifficulty(int.Parse(data[0])), // difficulty rank
                                        float.Parse(data[4]),                         // note jump speed
                                        0,                                            // start offset
                                        SimpleBeatmapData.Create(
                                            notesCount: int.Parse(data[1]),
                                            bombsCount: int.Parse(data[2]),
                                            obstaclesCount: int.Parse(data[3]),
                                            spawnRotationEventsCount: 0)
                                        )).OrderBy(x => x.difficultyRank).ToArray());
                return(difficultyBeatmapSet);
            })
                                    .ToArray();


            PreviewDifficultyBeatmapSets = LevelsList.Split('|')
                                           .Select(level => level.Split(','))
                                           .GroupBy(data => int.Parse(data[0]) & FLAGS_LEVELS_ALLMODE) // モードごとに処理
                                           .SelectMany(group =>
                                                       group.Select(data => new PreviewDifficultyBeatmapSet(
                                                                        GetBeatmapCharacteristicCollectionFromSO(ToSerializedName(group.Key)) ?? CharacteristicSOsDictionary[group.Key],
                                                                        group
                                                                        .Select(d => ToBeatmapDifficulty(int.Parse(d[0])))
                                                                        .OrderBy(x => (int)x)
                                                                        .ToArray()
                                                                        )).ToArray())
                                           .ToArray();
        }