From 38ce88757ad374bb2db54dcbd34d25bee7793488 Mon Sep 17 00:00:00 2001 From: 2riniar Date: Sun, 1 Dec 2024 03:19:56 +0900 Subject: [PATCH] =?UTF-8?q?Slot:=20=E3=82=B9=E3=83=AD=E3=83=83=E3=83=88?= =?UTF-8?q?=E3=82=92Manager=E3=81=8B=E3=82=89=E8=84=B1=E5=8D=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Common/Models/AppService.cs | 14 +++ Common/Models/{SlotManager.cs => Slot.cs} | 50 +++-------- Common/Models/User.cs | 6 +- Events/Admin/AdminMasterReloadPresenter.cs | 1 - Events/Slot/SlotConditionRefreshPresenter.cs | 8 +- Events/Slot/SlotExecutePresenter.cs | 3 +- .../20241130181742_CreateSlot.Designer.cs | 86 +++++++++++++++++++ Migrations/20241130181742_CreateSlot.cs | 34 ++++++++ Migrations/AppServiceModelSnapshot.cs | 15 ++++ Program.cs | 2 - 10 files changed, 173 insertions(+), 46 deletions(-) rename Common/Models/{SlotManager.cs => Slot.cs} (58%) create mode 100644 Migrations/20241130181742_CreateSlot.Designer.cs create mode 100644 Migrations/20241130181742_CreateSlot.cs diff --git a/Common/Models/AppService.cs b/Common/Models/AppService.cs index 39eda6f..30f5fe1 100644 --- a/Common/Models/AppService.cs +++ b/Common/Models/AppService.cs @@ -8,6 +8,7 @@ namespace Approvers.King.Common; public class AppService : DbContext { public DbSet AppStates { get; set; } + public DbSet Slots { get; set; } public DbSet Users { get; set; } public DbSet GachaProbabilities { get; set; } @@ -40,4 +41,17 @@ public async Task FindOrCreateUserAsync(ulong discordId) Add(user); return user; } + + public async Task GetDefaultSlotAsync() + { + var slot = await Slots.FirstOrDefaultAsync(); + if (slot != null) + { + return slot; + } + + slot = new Slot { Id = Guid.NewGuid() }; + Add(slot); + return slot; + } } diff --git a/Common/Models/SlotManager.cs b/Common/Models/Slot.cs similarity index 58% rename from Common/Models/SlotManager.cs rename to Common/Models/Slot.cs index 2d94dc0..721d82c 100644 --- a/Common/Models/SlotManager.cs +++ b/Common/Models/Slot.cs @@ -1,44 +1,19 @@ +using System.ComponentModel.DataAnnotations; + namespace Approvers.King.Common; -public class SlotManager : Singleton +public class Slot { - private readonly List _items = []; - - /// - /// 調子(千分率) - /// - private int _conditionOffsetPermillage; - private const int ReelCount = 3; - /// - /// マスタデータを読み込む - /// - public void LoadMaster() - { - _items.Clear(); - var items = MasterManager.SlotItemMaster.GetAll(); - _items.AddRange(items); - } + [Key] public Guid Id { get; set; } /// - /// 現在の状態を読み込む + /// 調子(千分率) /// - public async Task LoadAsync() - { - await using var app = AppService.CreateSession(); - _conditionOffsetPermillage = await app.AppStates.GetIntAsync(AppStateType.SlotConditionOffsetPermillage) ?? 0; - } + public int ConditionPermillage { get; set; } - /// - /// 現在の状態を保存する - /// - public async Task SaveAsync() - { - await using var app = AppService.CreateSession(); - await app.AppStates.SetIntAsync(AppStateType.SlotConditionOffsetPermillage, _conditionOffsetPermillage); - await app.SaveChangesAsync(); - } + public int ExecutePrice => MasterManager.SettingMaster.PricePerSlotOnce; /// /// 調子を再抽選する @@ -47,7 +22,7 @@ public void ShuffleCondition() { var max = MasterManager.SettingMaster.SlotMaxConditionOffsetPermillage; var min = MasterManager.SettingMaster.SlotMinConditionOffsetPermillage; - _conditionOffsetPermillage = RandomManager.GetRandomInt(min, max + 1); + ConditionPermillage = RandomManager.GetRandomInt(min, max + 1); } /// @@ -55,20 +30,21 @@ public void ShuffleCondition() /// public SlotExecuteResult Execute() { - var itemCount = _items.Count; + var items = MasterManager.SlotItemMaster.GetAll().ToList(); + var itemCount = items.Count; var reelItems = new SlotItem[ReelCount]; for (var i = 0; i < ReelCount; i++) { if (i == 0) { - reelItems[i] = _items[RandomManager.GetRandomInt(itemCount)]; + reelItems[i] = items[RandomManager.GetRandomInt(itemCount)]; continue; } // 一定確率で直前と同じ出目が出る // 確率はマスタデータの設定値に加え、調子により変動する - var repeatPermillage = Math.Clamp(reelItems[i - 1].RepeatPermillage + _conditionOffsetPermillage, 0, MasterManager.SettingMaster.SlotRepeatPermillageUpperBound); + var repeatPermillage = Math.Clamp(reelItems[i - 1].RepeatPermillage + ConditionPermillage, 0, MasterManager.SettingMaster.SlotRepeatPermillageUpperBound); var repeatProbability = NumberUtility.GetProbabilityFromPermillage(repeatPermillage); var isRepeat = RandomManager.IsHit(repeatProbability); if (isRepeat) @@ -77,7 +53,7 @@ public SlotExecuteResult Execute() continue; } - reelItems[i] = _items[RandomManager.GetRandomInt(itemCount)]; + reelItems[i] = items[RandomManager.GetRandomInt(itemCount)]; } var isWin = reelItems.Select(x => x.Id).Distinct().Count() == 1; diff --git a/Common/Models/User.cs b/Common/Models/User.cs index 2092f5b..100df88 100644 --- a/Common/Models/User.cs +++ b/Common/Models/User.cs @@ -57,15 +57,15 @@ public GachaProbability RollGachaOnceCertain() /// /// スロットを回す /// - public SlotExecuteResult ExecuteSlot() + public SlotExecuteResult ExecuteSlot(Slot slot) { if (TodaySlotExecuteCount >= MasterManager.SettingMaster.UserSlotExecuteLimitPerDay) { throw new AppException("今日はもう回せないぞカス"); } - var price = MasterManager.SettingMaster.PricePerSlotOnce; - var result = SlotManager.Instance.Execute(); + var price = slot.ExecutePrice; + var result = slot.Execute(); var reward = (int)(NumberUtility.GetPercentFromPermillage(result.ResultRatePermillage) * price); MonthlySlotProfitPrice += reward - price; TodaySlotExecuteCount++; diff --git a/Events/Admin/AdminMasterReloadPresenter.cs b/Events/Admin/AdminMasterReloadPresenter.cs index fd9909f..b8de11f 100644 --- a/Events/Admin/AdminMasterReloadPresenter.cs +++ b/Events/Admin/AdminMasterReloadPresenter.cs @@ -14,7 +14,6 @@ protected override async Task MainAsync() await MasterManager.FetchAsync(); await Message.ReplyAsync("マスターをリロードしたぞ"); - SlotManager.Instance.LoadMaster(); await UpdateGachaTableAsync(); } diff --git a/Events/Slot/SlotConditionRefreshPresenter.cs b/Events/Slot/SlotConditionRefreshPresenter.cs index fd27a12..65365b8 100644 --- a/Events/Slot/SlotConditionRefreshPresenter.cs +++ b/Events/Slot/SlotConditionRefreshPresenter.cs @@ -9,7 +9,11 @@ public class SlotConditionRefreshPresenter : SchedulerJobPresenterBase { protected override async Task MainAsync() { - SlotManager.Instance.ShuffleCondition(); - await SlotManager.Instance.SaveAsync(); + await using var app = AppService.CreateSession(); + + var slot = await app.GetDefaultSlotAsync(); + slot.ShuffleCondition(); + + await app.SaveChangesAsync(); } } diff --git a/Events/Slot/SlotExecutePresenter.cs b/Events/Slot/SlotExecutePresenter.cs index 303306c..85cf44a 100644 --- a/Events/Slot/SlotExecutePresenter.cs +++ b/Events/Slot/SlotExecutePresenter.cs @@ -14,7 +14,8 @@ protected override async Task MainAsync() await using var app = AppService.CreateSession(); var user = await app.FindOrCreateUserAsync(Message.Author.Id); - var result = user.ExecuteSlot(); + var slot = await app.GetDefaultSlotAsync(); + var result = user.ExecuteSlot(slot); await app.SaveChangesAsync(); diff --git a/Migrations/20241130181742_CreateSlot.Designer.cs b/Migrations/20241130181742_CreateSlot.Designer.cs new file mode 100644 index 0000000..9f4b7ef --- /dev/null +++ b/Migrations/20241130181742_CreateSlot.Designer.cs @@ -0,0 +1,86 @@ +// +using System; +using Approvers.King.Common; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Approvers.King.Migrations +{ + [DbContext(typeof(AppService))] + [Migration("20241130181742_CreateSlot")] + partial class CreateSlot + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.10"); + + modelBuilder.Entity("Approvers.King.Common.AppState", b => + { + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("Value") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Type"); + + b.ToTable("AppStates"); + }); + + modelBuilder.Entity("Approvers.King.Common.GachaProbability", b => + { + b.Property("RandomMessageId") + .HasColumnType("TEXT"); + + b.Property("Probability") + .HasColumnType("REAL"); + + b.HasKey("RandomMessageId"); + + b.ToTable("GachaProbabilities"); + }); + + modelBuilder.Entity("Approvers.King.Common.Slot", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("ConditionPermillage") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Slots"); + }); + + modelBuilder.Entity("Approvers.King.Common.User", b => + { + b.Property("DiscordId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("MonthlyGachaPurchasePrice") + .HasColumnType("INTEGER"); + + b.Property("MonthlySlotProfitPrice") + .HasColumnType("INTEGER"); + + b.Property("TodaySlotExecuteCount") + .HasColumnType("INTEGER"); + + b.HasKey("DiscordId"); + + b.ToTable("Users"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Migrations/20241130181742_CreateSlot.cs b/Migrations/20241130181742_CreateSlot.cs new file mode 100644 index 0000000..67891e9 --- /dev/null +++ b/Migrations/20241130181742_CreateSlot.cs @@ -0,0 +1,34 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Approvers.King.Migrations +{ + /// + public partial class CreateSlot : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Slots", + columns: table => new + { + Id = table.Column(type: "TEXT", nullable: false), + ConditionPermillage = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Slots", x => x.Id); + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Slots"); + } + } +} diff --git a/Migrations/AppServiceModelSnapshot.cs b/Migrations/AppServiceModelSnapshot.cs index f3eae2a..b27d054 100644 --- a/Migrations/AppServiceModelSnapshot.cs +++ b/Migrations/AppServiceModelSnapshot.cs @@ -1,4 +1,5 @@ // +using System; using Approvers.King.Common; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; @@ -43,6 +44,20 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("GachaProbabilities"); }); + modelBuilder.Entity("Approvers.King.Common.Slot", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("ConditionPermillage") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Slots"); + }); + modelBuilder.Entity("Approvers.King.Common.User", b => { b.Property("DiscordId") diff --git a/Program.cs b/Program.cs index 553381d..26a06d6 100644 --- a/Program.cs +++ b/Program.cs @@ -20,8 +20,6 @@ private static async Task BuildAsync(string[] args) TimeManager.Instance.Initialize(); await MasterManager.FetchAsync(); await GachaManager.Instance.LoadAsync(); - SlotManager.Instance.LoadMaster(); - await SlotManager.Instance.LoadAsync(); SchedulerManager.Initialize(); await DiscordManager.InitializeAsync();