diff --git a/GameDatabase/Entities/UserDatum.cs b/GameDatabase/Entities/UserDatum.cs index 8dd3bb8..4bcd5ca 100644 --- a/GameDatabase/Entities/UserDatum.cs +++ b/GameDatabase/Entities/UserDatum.cs @@ -51,6 +51,7 @@ namespace GameDatabase.Entities public int AiWinCount { get; set; } public List Tokens { get; set; } = new(); public List UnlockedSongIdList { get; set; } = []; + public List UnlockedUraSongIdList { get; set; } = []; public bool IsAdmin { get; set; } } } \ No newline at end of file diff --git a/GameDatabase/Migrations/20241106173142_AddUnlockedUraSongIdListToUserDatum.Designer.cs b/GameDatabase/Migrations/20241106173142_AddUnlockedUraSongIdListToUserDatum.Designer.cs new file mode 100644 index 0000000..0afa9d7 --- /dev/null +++ b/GameDatabase/Migrations/20241106173142_AddUnlockedUraSongIdListToUserDatum.Designer.cs @@ -0,0 +1,576 @@ +// +using System; +using GameDatabase.Context; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace GameDatabase.Migrations +{ + [DbContext(typeof(TaikoDbContext))] + [Migration("20241106173142_AddUnlockedUraSongIdListToUserDatum")] + partial class AddUnlockedUraSongIdListToUserDatum + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.3"); + + modelBuilder.Entity("GameDatabase.Entities.AiScoreDatum", b => + { + b.Property("Baid") + .HasColumnType("INTEGER"); + + b.Property("SongId") + .HasColumnType("INTEGER"); + + b.Property("Difficulty") + .HasColumnType("INTEGER"); + + b.Property("IsWin") + .HasColumnType("INTEGER"); + + b.HasKey("Baid", "SongId", "Difficulty"); + + b.ToTable("AiScoreData"); + }); + + modelBuilder.Entity("GameDatabase.Entities.AiSectionScoreDatum", b => + { + b.Property("Baid") + .HasColumnType("INTEGER"); + + b.Property("SongId") + .HasColumnType("INTEGER"); + + b.Property("Difficulty") + .HasColumnType("INTEGER"); + + b.Property("SectionIndex") + .HasColumnType("INTEGER"); + + b.Property("Crown") + .HasColumnType("INTEGER"); + + b.Property("DrumrollCount") + .HasColumnType("INTEGER"); + + b.Property("GoodCount") + .HasColumnType("INTEGER"); + + b.Property("IsWin") + .HasColumnType("INTEGER"); + + b.Property("MissCount") + .HasColumnType("INTEGER"); + + b.Property("OkCount") + .HasColumnType("INTEGER"); + + b.Property("Score") + .HasColumnType("INTEGER"); + + b.HasKey("Baid", "SongId", "Difficulty", "SectionIndex"); + + b.ToTable("AiSectionScoreData"); + }); + + modelBuilder.Entity("GameDatabase.Entities.Card", b => + { + b.Property("AccessCode") + .HasColumnType("TEXT"); + + b.Property("Baid") + .HasColumnType("INTEGER"); + + b.HasKey("AccessCode"); + + b.HasIndex("Baid"); + + b.ToTable("Card", (string)null); + }); + + modelBuilder.Entity("GameDatabase.Entities.Credential", b => + { + b.Property("Baid") + .HasColumnType("INTEGER"); + + b.Property("Password") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Salt") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Baid"); + + b.ToTable("Credential", (string)null); + }); + + modelBuilder.Entity("GameDatabase.Entities.DanScoreDatum", b => + { + b.Property("Baid") + .HasColumnType("INTEGER"); + + b.Property("DanId") + .HasColumnType("INTEGER"); + + b.Property("DanType") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(1); + + b.Property("ArrivalSongCount") + .HasColumnType("INTEGER"); + + b.Property("ClearState") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(0u); + + b.Property("ComboCountTotal") + .HasColumnType("INTEGER"); + + b.Property("SoulGaugeTotal") + .HasColumnType("INTEGER"); + + b.HasKey("Baid", "DanId", "DanType"); + + b.ToTable("DanScoreData"); + }); + + modelBuilder.Entity("GameDatabase.Entities.DanStageScoreDatum", b => + { + b.Property("Baid") + .HasColumnType("INTEGER"); + + b.Property("DanId") + .HasColumnType("INTEGER"); + + b.Property("DanType") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(1); + + b.Property("SongNumber") + .HasColumnType("INTEGER"); + + b.Property("BadCount") + .HasColumnType("INTEGER"); + + b.Property("ComboCount") + .HasColumnType("INTEGER"); + + b.Property("DrumrollCount") + .HasColumnType("INTEGER"); + + b.Property("GoodCount") + .HasColumnType("INTEGER"); + + b.Property("HighScore") + .HasColumnType("INTEGER"); + + b.Property("OkCount") + .HasColumnType("INTEGER"); + + b.Property("PlayScore") + .HasColumnType("INTEGER"); + + b.Property("TotalHitCount") + .HasColumnType("INTEGER"); + + b.HasKey("Baid", "DanId", "DanType", "SongNumber"); + + b.ToTable("DanStageScoreData"); + }); + + modelBuilder.Entity("GameDatabase.Entities.SongBestDatum", b => + { + b.Property("Baid") + .HasColumnType("INTEGER"); + + b.Property("SongId") + .HasColumnType("INTEGER"); + + b.Property("Difficulty") + .HasColumnType("INTEGER"); + + b.Property("BestCrown") + .HasColumnType("INTEGER"); + + b.Property("BestRate") + .HasColumnType("INTEGER"); + + b.Property("BestScore") + .HasColumnType("INTEGER"); + + b.Property("BestScoreRank") + .HasColumnType("INTEGER"); + + b.HasKey("Baid", "SongId", "Difficulty"); + + b.ToTable("SongBestData"); + }); + + modelBuilder.Entity("GameDatabase.Entities.SongPlayDatum", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Baid") + .HasColumnType("INTEGER"); + + b.Property("ComboCount") + .HasColumnType("INTEGER"); + + b.Property("Crown") + .HasColumnType("INTEGER"); + + b.Property("Difficulty") + .HasColumnType("INTEGER"); + + b.Property("DrumrollCount") + .HasColumnType("INTEGER"); + + b.Property("GoodCount") + .HasColumnType("INTEGER"); + + b.Property("HitCount") + .HasColumnType("INTEGER"); + + b.Property("MissCount") + .HasColumnType("INTEGER"); + + b.Property("OkCount") + .HasColumnType("INTEGER"); + + b.Property("PlayTime") + .HasColumnType("datetime"); + + b.Property("Score") + .HasColumnType("INTEGER"); + + b.Property("ScoreRank") + .HasColumnType("INTEGER"); + + b.Property("ScoreRate") + .HasColumnType("INTEGER"); + + b.Property("Skipped") + .HasColumnType("INTEGER"); + + b.Property("SongId") + .HasColumnType("INTEGER"); + + b.Property("SongNumber") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("Baid"); + + b.ToTable("SongPlayData"); + }); + + modelBuilder.Entity("GameDatabase.Entities.Token", b => + { + b.Property("Baid") + .HasColumnType("INTEGER"); + + b.Property("Id") + .HasColumnType("INTEGER"); + + b.Property("Count") + .HasColumnType("INTEGER"); + + b.HasKey("Baid", "Id"); + + b.ToTable("Tokens"); + }); + + modelBuilder.Entity("GameDatabase.Entities.UserDatum", b => + { + b.Property("Baid") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AchievementDisplayDifficulty") + .HasColumnType("INTEGER"); + + b.Property("AiWinCount") + .HasColumnType("INTEGER"); + + b.Property("ColorBody") + .HasColumnType("INTEGER"); + + b.Property("ColorFace") + .HasColumnType("INTEGER"); + + b.Property("ColorLimb") + .HasColumnType("INTEGER"); + + b.Property("CostumeData") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("CostumeFlgArray") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("CurrentBody") + .HasColumnType("INTEGER"); + + b.Property("CurrentFace") + .HasColumnType("INTEGER"); + + b.Property("CurrentHead") + .HasColumnType("INTEGER"); + + b.Property("CurrentKigurumi") + .HasColumnType("INTEGER"); + + b.Property("CurrentPuchi") + .HasColumnType("INTEGER"); + + b.Property("DifficultyPlayedArray") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DifficultyPlayedCourse") + .HasColumnType("INTEGER"); + + b.Property("DifficultyPlayedSort") + .HasColumnType("INTEGER"); + + b.Property("DifficultyPlayedStar") + .HasColumnType("INTEGER"); + + b.Property("DifficultySettingArray") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DifficultySettingCourse") + .HasColumnType("INTEGER"); + + b.Property("DifficultySettingSort") + .HasColumnType("INTEGER"); + + b.Property("DifficultySettingStar") + .HasColumnType("INTEGER"); + + b.Property("DisplayAchievement") + .HasColumnType("INTEGER"); + + b.Property("DisplayDan") + .HasColumnType("INTEGER"); + + b.Property("FavoriteSongsArray") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("GenericInfoFlgArray") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("IsAdmin") + .HasColumnType("INTEGER"); + + b.Property("IsSkipOn") + .HasColumnType("INTEGER"); + + b.Property("IsVoiceOn") + .HasColumnType("INTEGER"); + + b.Property("LastPlayDatetime") + .HasColumnType("datetime"); + + b.Property("LastPlayMode") + .HasColumnType("INTEGER"); + + b.Property("MyDonName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("MyDonNameLanguage") + .HasColumnType("INTEGER"); + + b.Property("NotesPosition") + .HasColumnType("INTEGER"); + + b.Property("OptionSetting") + .HasColumnType("INTEGER"); + + b.Property("SelectedToneId") + .HasColumnType("INTEGER"); + + b.Property("Title") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("TitleFlgArray") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("TitlePlateId") + .HasColumnType("INTEGER"); + + b.Property("ToneFlgArray") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UnlockedBody") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UnlockedFace") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UnlockedHead") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UnlockedKigurumi") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UnlockedPuchi") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UnlockedSongIdList") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UnlockedUraSongIdList") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Baid"); + + b.ToTable("UserData"); + }); + + modelBuilder.Entity("GameDatabase.Entities.AiScoreDatum", b => + { + b.HasOne("GameDatabase.Entities.UserDatum", "Ba") + .WithMany() + .HasForeignKey("Baid") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Ba"); + }); + + modelBuilder.Entity("GameDatabase.Entities.AiSectionScoreDatum", b => + { + b.HasOne("GameDatabase.Entities.AiScoreDatum", "Parent") + .WithMany("AiSectionScoreData") + .HasForeignKey("Baid", "SongId", "Difficulty") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("GameDatabase.Entities.Card", b => + { + b.HasOne("GameDatabase.Entities.UserDatum", "Ba") + .WithMany() + .HasForeignKey("Baid") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Ba"); + }); + + modelBuilder.Entity("GameDatabase.Entities.Credential", b => + { + b.HasOne("GameDatabase.Entities.UserDatum", "Ba") + .WithMany() + .HasForeignKey("Baid") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Ba"); + }); + + modelBuilder.Entity("GameDatabase.Entities.DanScoreDatum", b => + { + b.HasOne("GameDatabase.Entities.UserDatum", "Ba") + .WithMany() + .HasForeignKey("Baid") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Ba"); + }); + + modelBuilder.Entity("GameDatabase.Entities.DanStageScoreDatum", b => + { + b.HasOne("GameDatabase.Entities.DanScoreDatum", "Parent") + .WithMany("DanStageScoreData") + .HasForeignKey("Baid", "DanId", "DanType") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("GameDatabase.Entities.SongBestDatum", b => + { + b.HasOne("GameDatabase.Entities.UserDatum", "Ba") + .WithMany() + .HasForeignKey("Baid") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Ba"); + }); + + modelBuilder.Entity("GameDatabase.Entities.SongPlayDatum", b => + { + b.HasOne("GameDatabase.Entities.UserDatum", "Ba") + .WithMany() + .HasForeignKey("Baid") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Ba"); + }); + + modelBuilder.Entity("GameDatabase.Entities.Token", b => + { + b.HasOne("GameDatabase.Entities.UserDatum", "Datum") + .WithMany("Tokens") + .HasForeignKey("Baid") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Datum"); + }); + + modelBuilder.Entity("GameDatabase.Entities.AiScoreDatum", b => + { + b.Navigation("AiSectionScoreData"); + }); + + modelBuilder.Entity("GameDatabase.Entities.DanScoreDatum", b => + { + b.Navigation("DanStageScoreData"); + }); + + modelBuilder.Entity("GameDatabase.Entities.UserDatum", b => + { + b.Navigation("Tokens"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/GameDatabase/Migrations/20241106173142_AddUnlockedUraSongIdListToUserDatum.cs b/GameDatabase/Migrations/20241106173142_AddUnlockedUraSongIdListToUserDatum.cs new file mode 100644 index 0000000..2e4c8a3 --- /dev/null +++ b/GameDatabase/Migrations/20241106173142_AddUnlockedUraSongIdListToUserDatum.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace GameDatabase.Migrations +{ + /// + public partial class AddUnlockedUraSongIdListToUserDatum : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "UnlockedUraSongIdList", + table: "UserData", + type: "TEXT", + nullable: false, + defaultValue: ""); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "UnlockedUraSongIdList", + table: "UserData"); + } + } +} diff --git a/GameDatabase/Migrations/TaikoDbContextModelSnapshot.cs b/GameDatabase/Migrations/TaikoDbContextModelSnapshot.cs index 09bb967..4547fe1 100644 --- a/GameDatabase/Migrations/TaikoDbContextModelSnapshot.cs +++ b/GameDatabase/Migrations/TaikoDbContextModelSnapshot.cs @@ -15,7 +15,7 @@ namespace TaikoLocalServer.Migrations protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "8.0.4"); + modelBuilder.HasAnnotation("ProductVersion", "8.0.3"); modelBuilder.Entity("GameDatabase.Entities.AiScoreDatum", b => { @@ -445,6 +445,10 @@ namespace TaikoLocalServer.Migrations .IsRequired() .HasColumnType("TEXT"); + b.Property("UnlockedUraSongIdList") + .IsRequired() + .HasColumnType("TEXT"); + b.HasKey("Baid"); b.ToTable("UserData"); diff --git a/README.md b/README.md index 705ac77..c41b1cc 100644 --- a/README.md +++ b/README.md @@ -211,6 +211,9 @@ There are various data json files under wwwroot/data that can be customized. 100, 200, 300 + ], + "uraSongNo": [ + // Fill in the uniqueId of songs whose ura chart you wish to lock ] } ``` @@ -241,10 +244,12 @@ There are various data json files under wwwroot/data that can be customized. [ { "songNo": 100, // The uniqueId of the song + "type": 0, // 0 indicates the shop is selling the song itself "price": 20 // How many don coins buying this song costs, the type of don coin is specified by token_data.json }, { "songNo": 200, + "type": 1, // And 1 indicates the shop is selling the song's ura chart "price": 20 } ] diff --git a/SharedProject/Models/ShopFolderData.cs b/SharedProject/Models/ShopFolderData.cs index 715913c..d179b58 100644 --- a/SharedProject/Models/ShopFolderData.cs +++ b/SharedProject/Models/ShopFolderData.cs @@ -5,7 +5,8 @@ namespace SharedProject.Models; public class ShopFolderData { [JsonPropertyName("songNo")] public uint SongNo { get; set; } - - public uint Type { get; set; } + + [JsonPropertyName("type")] public uint Type { get; set; } + [JsonPropertyName("price")] public uint Price { get; set; } } \ No newline at end of file diff --git a/TaikoLocalServer/Handlers/GetInitialDataQuery.cs b/TaikoLocalServer/Handlers/GetInitialDataQuery.cs index 5825ab8..ac48631 100644 --- a/TaikoLocalServer/Handlers/GetInitialDataQuery.cs +++ b/TaikoLocalServer/Handlers/GetInitialDataQuery.cs @@ -21,6 +21,7 @@ public class GetInitialDataQueryHandler(IGameDataService gameDataService, var musicList = gameDataService.GetMusicList(); var lockedSongsList = gameDataService.GetLockedSongsList(); + var lockedUraSongsList = gameDataService.GetLockedUraSongsList(); var enabledArray = FlagCalculator.GetBitArrayFromIds(musicList, songIdMax, logger); @@ -29,7 +30,7 @@ public class GetInitialDataQueryHandler(IGameDataService gameDataService, var defaultSongFlg = FlagCalculator.GetBitArrayFromIds(defaultSongList, songIdMax, logger); - var defaultSongWithUraList = gameDataService.GetMusicWithUraList(); + var defaultSongWithUraList = gameDataService.GetMusicWithUraList().Except(lockedUraSongsList); var uraReleaseBit = FlagCalculator.GetBitArrayFromIds(defaultSongWithUraList, songIdMax, logger); diff --git a/TaikoLocalServer/Handlers/UserDataQuery.cs b/TaikoLocalServer/Handlers/UserDataQuery.cs index 79723f6..3471026 100644 --- a/TaikoLocalServer/Handlers/UserDataQuery.cs +++ b/TaikoLocalServer/Handlers/UserDataQuery.cs @@ -16,16 +16,17 @@ public class UserDataQueryHandler(TaikoDbContext context, IGameDataService gameD userData.ThrowIfNull($"User not found for Baid {request.Baid}!"); var unlockedSongIdList = userData.UnlockedSongIdList; + var unlockedUraSongIdList = userData.UnlockedUraSongIdList; var musicList = gameDataService.GetMusicList(); - var lockedSongsList = gameDataService.GetLockedSongsList(); - lockedSongsList = lockedSongsList.Except(unlockedSongIdList).ToList(); + var lockedSongsList = gameDataService.GetLockedSongsList().Except(unlockedSongIdList).ToList(); + var lockedUraSongsList = gameDataService.GetLockedUraSongsList().Except(unlockedUraSongIdList).ToList(); var enabledMusicList = musicList.Except(lockedSongsList); var releaseSongArray = FlagCalculator.GetBitArrayFromIds(enabledMusicList, Constants.MusicIdMax, logger); var defaultSongWithUraList = gameDataService.GetMusicWithUraList(); - var enabledUraMusicList = defaultSongWithUraList.Except(lockedSongsList); + var enabledUraMusicList = defaultSongWithUraList.Except(lockedUraSongsList); var uraSongArray = FlagCalculator.GetBitArrayFromIds(enabledUraMusicList, Constants.MusicIdMax, logger); diff --git a/TaikoLocalServer/Services/GameDataService.cs b/TaikoLocalServer/Services/GameDataService.cs index 06b2b10..86a6c84 100644 --- a/TaikoLocalServer/Services/GameDataService.cs +++ b/TaikoLocalServer/Services/GameDataService.cs @@ -40,6 +40,8 @@ public class GameDataService(IOptions dataSettings) : IGameDataSer private List musicWithUraUniqueIdList = []; private List lockedSongsList = []; + + private List lockedUraSongsList = []; private readonly Dictionary musicDetailDictionary = new(); @@ -111,6 +113,11 @@ public class GameDataService(IOptions dataSettings) : IGameDataSer return lockedSongsList; } + public List GetLockedUraSongsList() + { + return lockedUraSongsList; + } + public Dictionary GetMusicDetailDictionary() { return musicDetailDictionary; @@ -376,6 +383,7 @@ public class GameDataService(IOptions dataSettings) : IGameDataSer { lockedSongsData.ThrowIfNull("Shouldn't happen!"); lockedSongsList = lockedSongsData["songNo"].ToList(); + lockedUraSongsList = lockedSongsData["uraSongNo"].ToList(); } private void InitializeMusicDetails(MusicInfos? musicInfoData, MusicOrder? musicOrderData, WordList? wordlistData) diff --git a/TaikoLocalServer/Services/Interfaces/IGameDataService.cs b/TaikoLocalServer/Services/Interfaces/IGameDataService.cs index de87d7f..e3d8088 100644 --- a/TaikoLocalServer/Services/Interfaces/IGameDataService.cs +++ b/TaikoLocalServer/Services/Interfaces/IGameDataService.cs @@ -27,6 +27,8 @@ public interface IGameDataService public List GetLockedSongsList(); + public List GetLockedUraSongsList(); + public Dictionary GetMusicDetailDictionary(); public List GetCostumeList(); diff --git a/TaikoLocalServer/wwwroot/data/locked_songs_data.json b/TaikoLocalServer/wwwroot/data/locked_songs_data.json index 86598ab..9d21a53 100644 --- a/TaikoLocalServer/wwwroot/data/locked_songs_data.json +++ b/TaikoLocalServer/wwwroot/data/locked_songs_data.json @@ -1,4 +1,8 @@ { "songNo": [ + + ], + "uraSongNo": [ + ] } \ No newline at end of file diff --git a/TaikoLocalServer/wwwroot/data/shop_folder_data.json b/TaikoLocalServer/wwwroot/data/shop_folder_data.json index a3c468e..cea2773 100644 --- a/TaikoLocalServer/wwwroot/data/shop_folder_data.json +++ b/TaikoLocalServer/wwwroot/data/shop_folder_data.json @@ -1,6 +1,12 @@ [ { - "songNo": 2, + "songNo": 1, + "type": 0, + "price": 0 + }, + { + "songNo": 9, + "type": 1, "price": 0 } ] \ No newline at end of file