From db93c8f49d885e4a86385da0057694fadb475b16 Mon Sep 17 00:00:00 2001 From: rfi Date: Thu, 22 Feb 2024 16:11:23 +0700 Subject: [PATCH] this took soo long, but here you are wells --- BLHX.Server.Common/BLHX.Server.Common.csproj | 3 + BLHX.Server.Common/Data/Data.cs | 53 +++- BLHX.Server.Common/Data/JSON.cs | 17 +- .../Data/Model/ResourceFieldTemplate.cs | 28 ++ BLHX.Server.Common/Database/DBManager.cs | 7 + BLHX.Server.Common/Database/Player.cs | 136 +++++++++- .../20240222030542_ResourceFields.Designer.cs | 249 +++++++++++++++++ .../Player/20240222030542_ResourceFields.cs | 47 ++++ ...4540_ResourceFieldsUpgradeTime.Designer.cs | 252 ++++++++++++++++++ ...0240222064540_ResourceFieldsUpgradeTime.cs | 30 +++ .../Player/PlayerContextModelSnapshot.cs | 37 +++ .../Resources/ShareCfg/oilfield_template.json | 160 +++++++++++ .../ShareCfg/tradingport_template.json | 160 +++++++++++ .../Utils/DateTimeExtensions.cs | 5 + BLHX.Server.Game/Connection.cs | 16 +- BLHX.Server.Game/Handlers/P10.cs | 2 + BLHX.Server.Game/Handlers/P11.cs | 21 ++ BLHX.Server.Game/Handlers/P22.cs | 4 +- 18 files changed, 1210 insertions(+), 17 deletions(-) create mode 100644 BLHX.Server.Common/Data/Model/ResourceFieldTemplate.cs create mode 100644 BLHX.Server.Common/Migrations/Player/20240222030542_ResourceFields.Designer.cs create mode 100644 BLHX.Server.Common/Migrations/Player/20240222030542_ResourceFields.cs create mode 100644 BLHX.Server.Common/Migrations/Player/20240222064540_ResourceFieldsUpgradeTime.Designer.cs create mode 100644 BLHX.Server.Common/Migrations/Player/20240222064540_ResourceFieldsUpgradeTime.cs create mode 100644 BLHX.Server.Common/Resources/ShareCfg/oilfield_template.json create mode 100644 BLHX.Server.Common/Resources/ShareCfg/tradingport_template.json diff --git a/BLHX.Server.Common/BLHX.Server.Common.csproj b/BLHX.Server.Common/BLHX.Server.Common.csproj index 74d2068..1185dc3 100644 --- a/BLHX.Server.Common/BLHX.Server.Common.csproj +++ b/BLHX.Server.Common/BLHX.Server.Common.csproj @@ -21,6 +21,9 @@ PreserveNewest + + PreserveNewest + diff --git a/BLHX.Server.Common/Data/Data.cs b/BLHX.Server.Common/Data/Data.cs index cf7a00c..89339fb 100644 --- a/BLHX.Server.Common/Data/Data.cs +++ b/BLHX.Server.Common/Data/Data.cs @@ -1,4 +1,6 @@ using BLHX.Server.Common.Utils; +using System.Reflection; +using System.Text.RegularExpressions; namespace BLHX.Server.Common.Data; @@ -6,17 +8,37 @@ public static class Data { static readonly Logger c = new(nameof(Data), ConsoleColor.Yellow); - public static Dictionary ChapterTemplate = []; - public static Dictionary ShipDataStatistics = []; - public static Dictionary ShipDataTemplate = []; - public static Dictionary TaskDataTemplate = []; + [LoadData("oilfield_template.json", LoadDataType.ShareCfg)] + public static Dictionary OilFieldTemplate { get; private set; } = null!; + + [LoadData("tradingport_template.json", LoadDataType.ShareCfg)] + public static Dictionary GoldFieldTemplate { get; private set; } = null!; + + [LoadData("chapter_template.json", LoadDataType.ShareCfgData)] + public static Dictionary ChapterTemplate { get; private set; } = null!; + + [LoadData("ship_data_statistics.json", LoadDataType.ShareCfgData)] + public static Dictionary ShipDataStatistics { get; private set; } = null!; + + [LoadData("ship_data_template.json", LoadDataType.ShareCfgData)] + public static Dictionary ShipDataTemplate { get; private set; } = null!; + + [LoadData("task_data_template.json", LoadDataType.ShareCfgData)] + public static Dictionary TaskDataTemplate { get; private set; } = null!; public static void Load() { - LoadData(ref ChapterTemplate, "chapter_template.json", nameof(ChapterTemplate)); - LoadData(ref ShipDataStatistics, "ship_data_statistics.json", nameof(ShipDataStatistics)); - LoadData(ref ShipDataTemplate, "ship_data_template.json", nameof(ShipDataTemplate)); - LoadData(ref TaskDataTemplate, "task_data_template.json", nameof(TaskDataTemplate)); + foreach (var prop in typeof(Data).GetProperties().Where(x => x.GetCustomAttribute() is not null)) + { + var attr = prop.GetCustomAttribute()!; + prop.SetValue(null, typeof(JSON).GetMethod("Load")!.MakeGenericMethod(prop.PropertyType).Invoke(null, [Path.Combine(attr.DataType switch + { + LoadDataType.ShareCfg => JSON.ShareCfgPath, + LoadDataType.ShareCfgData => JSON.ShareCfgDataPath, + _ => "" + }, attr.FileName), false])); + c.Warn($"Loaded {prop.Name}"); + } c.Log("All data tables loaded"); } @@ -25,7 +47,7 @@ public static class Data { try { - data = JSON.Load>(Path.Combine(JSON.ShareConfigPath, fileName)); + data = JSON.Load>(Path.Combine(JSON.ShareCfgDataPath, fileName)); c.Warn($"Loaded {data.Count} {dataName}"); } catch (Exception e) @@ -34,3 +56,16 @@ public static class Data } } } + +public enum LoadDataType +{ + ShareCfg, + ShareCfgData +} + +[AttributeUsage(AttributeTargets.Property)] +public class LoadDataAttribute(string fileName, LoadDataType dataType) : Attribute +{ + public LoadDataType DataType = dataType; + public string FileName = fileName; +} \ No newline at end of file diff --git a/BLHX.Server.Common/Data/JSON.cs b/BLHX.Server.Common/Data/JSON.cs index 35ef17c..fbbcbeb 100644 --- a/BLHX.Server.Common/Data/JSON.cs +++ b/BLHX.Server.Common/Data/JSON.cs @@ -1,12 +1,14 @@ using System.Text.Json; +using System.Text.RegularExpressions; namespace BLHX.Server.Common.Data; -public static class JSON +public static partial class JSON { public static JsonSerializerOptions serializerOptions = new() { IncludeFields = true, WriteIndented = true }; public static string ConfigPath => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json"); - public static string ShareConfigPath => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Resources\\sharecfgdata\\"); + public static string ShareCfgDataPath => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Resources/sharecfgdata/"); + public static string ShareCfgPath => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Resources/ShareCfg/"); public static T Load(string path, bool create = true) where T : new() { @@ -16,7 +18,13 @@ public static class JSON Save(path, obj); } - return JsonSerializer.Deserialize(File.ReadAllText(path), serializerOptions) ?? new T(); + string text = File.ReadAllText(path); + if (typeof(T).IsGenericType && typeof(T).GetGenericTypeDefinition() == typeof(Dictionary<,>) && typeof(T).GetGenericArguments()[0] == typeof(int)) + { + text = DictKeyAll().Replace(text, ""); + } + + return JsonSerializer.Deserialize(text, serializerOptions) ?? new T(); } public static void Save(string path, T obj) @@ -28,4 +36,7 @@ public static class JSON { return JsonSerializer.Serialize(obj, serializerOptions); } + + [GeneratedRegex(@",[\n\s\t]+?""all"":[\s\S]+?]", RegexOptions.Multiline)] + public static partial Regex DictKeyAll(); } diff --git a/BLHX.Server.Common/Data/Model/ResourceFieldTemplate.cs b/BLHX.Server.Common/Data/Model/ResourceFieldTemplate.cs new file mode 100644 index 0000000..1524ecd --- /dev/null +++ b/BLHX.Server.Common/Data/Model/ResourceFieldTemplate.cs @@ -0,0 +1,28 @@ +using System.Text.Json.Serialization; + +namespace BLHX.Server.Common.Data +{ + public class ResourceFieldTemplate : Model + { + [JsonPropertyName("hour_time")] + public uint HourTime { get; set; } + + [JsonPropertyName("level")] + public uint Level { get; set; } + + [JsonPropertyName("production")] + public uint Production { get; set; } + + [JsonPropertyName("store")] + public uint Store { get; set; } + + [JsonPropertyName("time")] + public uint Time { get; set; } + + [JsonPropertyName("use")] + public List Use { get; set; } = []; + + [JsonPropertyName("user_level")] + public uint UserLevel { get; set; } + } +} diff --git a/BLHX.Server.Common/Database/DBManager.cs b/BLHX.Server.Common/Database/DBManager.cs index 0a57bd0..e0c153b 100644 --- a/BLHX.Server.Common/Database/DBManager.cs +++ b/BLHX.Server.Common/Database/DBManager.cs @@ -28,6 +28,13 @@ namespace BLHX.Server.Common.Database } } + enum SavingState + { + None, + Saving, + Attempting + } + public interface IBLHXDBContext { public static abstract string DbPath { get; } diff --git a/BLHX.Server.Common/Database/Player.cs b/BLHX.Server.Common/Database/Player.cs index ed61484..1136f51 100644 --- a/BLHX.Server.Common/Database/Player.cs +++ b/BLHX.Server.Common/Database/Player.cs @@ -1,22 +1,45 @@ using BLHX.Server.Common.Proto.common; using BLHX.Server.Common.Proto.p12; +using BLHX.Server.Common.Utils; using Microsoft.EntityFrameworkCore; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using System.Numerics; namespace BLHX.Server.Common.Database { public sealed class PlayerContext : DbContext, IBLHXDBContext { + SavingState savingState; public static string DbPath => "Databases/players.db"; public DbSet Players { get; set; } public DbSet Resources { get; set; } + public DbSet ResourceFields { get; set; } public DbSet Ships { get; set; } public PlayerContext() { if (Database.GetPendingMigrations().Any()) Database.Migrate(); + + SavingChanges += (_, _) => savingState = SavingState.Saving; + SavedChanges += (_, _) => savingState = SavingState.None; + SaveChangesFailed += (_, _) => savingState = SavingState.None; + } + + // Thread-safe method pls + public void Save() + { + if (savingState == SavingState.Attempting) + return; + + while (savingState != SavingState.None) + { + savingState = SavingState.Attempting; + Task.Delay(1).Wait(); + } + + SaveChanges(); } public Player Init(string token, uint shipId, string name) @@ -24,7 +47,7 @@ namespace BLHX.Server.Common.Database var player = new Player(token, new Displayinfo() { Icon = shipId }, name); Players.Add(player); - SaveChanges(); + Save(); // Initial resousrces player.DoResource(8, 4000); @@ -37,11 +60,21 @@ namespace BLHX.Server.Common.Database player.AddShip(shipId); player.AddShip(106011); - SaveChanges(); + PlayerRoutine(player); return player; } + public void PlayerRoutine(Player player) + { + if (!ResourceFields.Any(x => x.Type == ResourceFieldType.Gold)) + ResourceFields.Add(new() { Type = ResourceFieldType.Gold, PlayerUid = player.Uid }); + if (!ResourceFields.Any(x => x.Type == ResourceFieldType.Oil)) + ResourceFields.Add(new() { Type = ResourceFieldType.Oil, PlayerUid = player.Uid }); + + Save(); + } + protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); @@ -63,6 +96,10 @@ namespace BLHX.Server.Common.Database .WithOne(e => e.Player) .HasForeignKey(e => e.PlayerUid) .IsRequired(); + e.HasMany(b => b.ResourceFields) + .WithOne(e => e.Player) + .HasForeignKey(e => e.PlayerUid) + .IsRequired(); e.HasMany(b => b.Ships) .WithOne(e => e.Player) .HasForeignKey(e => e.PlayerUid) @@ -114,6 +151,7 @@ namespace BLHX.Server.Common.Database public List Fleets { get; set; } = null!; public virtual ICollection Resources { get; set; } = []; + public virtual ICollection ResourceFields { get; set; } = []; public virtual ICollection Ships { get; set; } = []; public Player(string token, Displayinfo displayInfo, string name) @@ -167,6 +205,28 @@ namespace BLHX.Server.Common.Database DBManager.PlayerContext.Ships.Add(ship); } + + public void HarvestResourceField(ResourceFieldType type) + { + foreach (var resourceField in ResourceFields) + { + if (resourceField.Type == type) + { + var amount = resourceField.Flush(); + switch (type) + { + case ResourceFieldType.Gold: + DoResource(1, (int)amount); + break; + case ResourceFieldType.Oil: + DoResource(2, (int)amount); + break; + } + + resourceField.CalculateYield(); + } + } + } } [PrimaryKey(nameof(Id), nameof(PlayerUid))] @@ -247,4 +307,76 @@ namespace BLHX.Server.Common.Database }; } } + + public enum ResourceFieldType + { + Gold = 1, + Oil = 2 + } + + [PrimaryKey(nameof(Type), nameof(PlayerUid))] + public class ResourceField + { + [Key] + public ResourceFieldType Type { get; set; } + public uint Level { get; set; } = 1; + public DateTime LastHarvestTime { get; set; } = DateTime.Now; + public DateTime UpgradeTime { get; set; } = DateTime.Now; + + [Key] + public uint PlayerUid { get; set; } + public virtual Player Player { get; set; } = null!; + + public void CalculateYield() + { + // TODO: Take UpgradeTime into acccount of the reward + switch (Type) + { + case ResourceFieldType.Gold: + if (Data.Data.GoldFieldTemplate.TryGetValue((int)Level, out var goldTemplate)) + { + var num = (goldTemplate.HourTime * goldTemplate.Production) / 3600f * LastHarvestTime.GetSecondsPassed(); + Player.DoResource(7, (int)Math.Min((uint)Math.Floor(num), goldTemplate.Store)); + } + break; + case ResourceFieldType.Oil: + if (Data.Data.OilFieldTemplate.TryGetValue((int)Level, out var oilTemplate)) + { + var num = (oilTemplate.HourTime * oilTemplate.Production) / 3600f * LastHarvestTime.GetSecondsPassed(); + Player.DoResource(5, (int)Math.Min((uint)Math.Floor(num), oilTemplate.Store)); + } + break; + } + } + + public uint Flush() + { + uint amount = 0; + // TODO: Take UpgradeTime into acccount of the reward + switch (Type) + { + case ResourceFieldType.Gold: + if (Data.Data.GoldFieldTemplate.TryGetValue((int)Level, out var goldTemplate)) + { + var goldField = Player.Resources.First(x => x.Id == 7); + amount = goldField.Num; + + goldField.Num = 0; + } + break; + case ResourceFieldType.Oil: + if (Data.Data.OilFieldTemplate.TryGetValue((int)Level, out var oilTemplate)) + { + var oilField = Player.Resources.First(x => x.Id == 5); + amount = oilField.Num; + + oilField.Num = 0; + } + break; + } + LastHarvestTime = DateTime.Now; + + return amount; + } + } } diff --git a/BLHX.Server.Common/Migrations/Player/20240222030542_ResourceFields.Designer.cs b/BLHX.Server.Common/Migrations/Player/20240222030542_ResourceFields.Designer.cs new file mode 100644 index 0000000..7a916ea --- /dev/null +++ b/BLHX.Server.Common/Migrations/Player/20240222030542_ResourceFields.Designer.cs @@ -0,0 +1,249 @@ +// +using System; +using BLHX.Server.Common.Database; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace BLHX.Server.Common.Migrations.Player +{ + [DbContext(typeof(PlayerContext))] + [Migration("20240222030542_ResourceFields")] + partial class ResourceFields + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.2") + .HasAnnotation("Proxies:ChangeTracking", false) + .HasAnnotation("Proxies:CheckEquality", false) + .HasAnnotation("Proxies:LazyLoading", true); + + modelBuilder.Entity("BLHX.Server.Common.Database.Player", b => + { + b.Property("Uid") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Adv") + .IsRequired() + .ValueGeneratedOnAdd() + .HasColumnType("TEXT") + .HasDefaultValue(""); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("DisplayInfo") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("Exp") + .HasColumnType("INTEGER"); + + b.Property("Fleets") + .IsRequired() + .ValueGeneratedOnAdd() + .HasColumnType("jsonb") + .HasDefaultValue("[{\"Id\":1,\"Name\":null,\"ShipLists\":[1,2],\"Commanders\":[]},{\"Id\":2,\"Name\":null,\"ShipLists\":[],\"Commanders\":[]},{\"Id\":11,\"Name\":null,\"ShipLists\":[],\"Commanders\":[]},{\"Id\":12,\"Name\":null,\"ShipLists\":[],\"Commanders\":[]}]"); + + b.Property("Level") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Token") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Uid"); + + b.HasIndex("Token") + .IsUnique(); + + b.ToTable("Players"); + }); + + modelBuilder.Entity("BLHX.Server.Common.Database.PlayerResource", b => + { + b.Property("Id") + .HasColumnType("INTEGER"); + + b.Property("PlayerUid") + .HasColumnType("INTEGER"); + + b.Property("Num") + .HasColumnType("INTEGER"); + + b.HasKey("Id", "PlayerUid"); + + b.HasIndex("PlayerUid"); + + b.ToTable("Resources"); + }); + + modelBuilder.Entity("BLHX.Server.Common.Database.PlayerShip", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ActivityNpc") + .HasColumnType("INTEGER"); + + b.Property("BluePrintFlag") + .HasColumnType("INTEGER"); + + b.Property("CommanderId") + .HasColumnType("INTEGER"); + + b.Property("CommonFlag") + .HasColumnType("INTEGER"); + + b.Property("CoreLists") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("Energy") + .HasColumnType("INTEGER"); + + b.Property("EquipInfoLists") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("Exp") + .HasColumnType("INTEGER"); + + b.Property("Intimacy") + .HasColumnType("INTEGER"); + + b.Property("IsLocked") + .HasColumnType("INTEGER"); + + b.Property("LastChangeName") + .HasColumnType("TEXT"); + + b.Property("Level") + .HasColumnType("INTEGER"); + + b.Property("MetaRepairLists") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("PlayerUid") + .HasColumnType("INTEGER"); + + b.Property("Proficiency") + .HasColumnType("INTEGER"); + + b.Property("Propose") + .HasColumnType("INTEGER"); + + b.Property("SkillIdLists") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("SkinId") + .HasColumnType("INTEGER"); + + b.Property("State") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("StrengthLists") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("TemplateId") + .HasColumnType("INTEGER"); + + b.Property("TransformLists") + .IsRequired() + .HasColumnType("jsonb"); + + b.HasKey("Id"); + + b.HasIndex("PlayerUid"); + + b.ToTable("Ships"); + }); + + modelBuilder.Entity("BLHX.Server.Common.Database.ResourceField", b => + { + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("PlayerUid") + .HasColumnType("INTEGER"); + + b.Property("LastHarvestTime") + .HasColumnType("TEXT"); + + b.Property("Level") + .HasColumnType("INTEGER"); + + b.HasKey("Type", "PlayerUid"); + + b.HasIndex("PlayerUid"); + + b.ToTable("ResourceFields"); + }); + + modelBuilder.Entity("BLHX.Server.Common.Database.PlayerResource", b => + { + b.HasOne("BLHX.Server.Common.Database.Player", "Player") + .WithMany("Resources") + .HasForeignKey("PlayerUid") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Player"); + }); + + modelBuilder.Entity("BLHX.Server.Common.Database.PlayerShip", b => + { + b.HasOne("BLHX.Server.Common.Database.Player", "Player") + .WithMany("Ships") + .HasForeignKey("PlayerUid") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Player"); + }); + + modelBuilder.Entity("BLHX.Server.Common.Database.ResourceField", b => + { + b.HasOne("BLHX.Server.Common.Database.Player", "Player") + .WithMany("ResourceFields") + .HasForeignKey("PlayerUid") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Player"); + }); + + modelBuilder.Entity("BLHX.Server.Common.Database.Player", b => + { + b.Navigation("ResourceFields"); + + b.Navigation("Resources"); + + b.Navigation("Ships"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/BLHX.Server.Common/Migrations/Player/20240222030542_ResourceFields.cs b/BLHX.Server.Common/Migrations/Player/20240222030542_ResourceFields.cs new file mode 100644 index 0000000..d506e5c --- /dev/null +++ b/BLHX.Server.Common/Migrations/Player/20240222030542_ResourceFields.cs @@ -0,0 +1,47 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace BLHX.Server.Common.Migrations.Player +{ + /// + public partial class ResourceFields : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "ResourceFields", + columns: table => new + { + Type = table.Column(type: "INTEGER", nullable: false), + PlayerUid = table.Column(type: "INTEGER", nullable: false), + LastHarvestTime = table.Column(type: "TEXT", nullable: false), + Level = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ResourceFields", x => new { x.Type, x.PlayerUid }); + table.ForeignKey( + name: "FK_ResourceFields_Players_PlayerUid", + column: x => x.PlayerUid, + principalTable: "Players", + principalColumn: "Uid", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_ResourceFields_PlayerUid", + table: "ResourceFields", + column: "PlayerUid"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "ResourceFields"); + } + } +} diff --git a/BLHX.Server.Common/Migrations/Player/20240222064540_ResourceFieldsUpgradeTime.Designer.cs b/BLHX.Server.Common/Migrations/Player/20240222064540_ResourceFieldsUpgradeTime.Designer.cs new file mode 100644 index 0000000..cf359a4 --- /dev/null +++ b/BLHX.Server.Common/Migrations/Player/20240222064540_ResourceFieldsUpgradeTime.Designer.cs @@ -0,0 +1,252 @@ +// +using System; +using BLHX.Server.Common.Database; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace BLHX.Server.Common.Migrations.Player +{ + [DbContext(typeof(PlayerContext))] + [Migration("20240222064540_ResourceFieldsUpgradeTime")] + partial class ResourceFieldsUpgradeTime + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.2") + .HasAnnotation("Proxies:ChangeTracking", false) + .HasAnnotation("Proxies:CheckEquality", false) + .HasAnnotation("Proxies:LazyLoading", true); + + modelBuilder.Entity("BLHX.Server.Common.Database.Player", b => + { + b.Property("Uid") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Adv") + .IsRequired() + .ValueGeneratedOnAdd() + .HasColumnType("TEXT") + .HasDefaultValue(""); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("DisplayInfo") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("Exp") + .HasColumnType("INTEGER"); + + b.Property("Fleets") + .IsRequired() + .ValueGeneratedOnAdd() + .HasColumnType("jsonb") + .HasDefaultValue("[{\"Id\":1,\"Name\":null,\"ShipLists\":[1,2],\"Commanders\":[]},{\"Id\":2,\"Name\":null,\"ShipLists\":[],\"Commanders\":[]},{\"Id\":11,\"Name\":null,\"ShipLists\":[],\"Commanders\":[]},{\"Id\":12,\"Name\":null,\"ShipLists\":[],\"Commanders\":[]}]"); + + b.Property("Level") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Token") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Uid"); + + b.HasIndex("Token") + .IsUnique(); + + b.ToTable("Players"); + }); + + modelBuilder.Entity("BLHX.Server.Common.Database.PlayerResource", b => + { + b.Property("Id") + .HasColumnType("INTEGER"); + + b.Property("PlayerUid") + .HasColumnType("INTEGER"); + + b.Property("Num") + .HasColumnType("INTEGER"); + + b.HasKey("Id", "PlayerUid"); + + b.HasIndex("PlayerUid"); + + b.ToTable("Resources"); + }); + + modelBuilder.Entity("BLHX.Server.Common.Database.PlayerShip", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ActivityNpc") + .HasColumnType("INTEGER"); + + b.Property("BluePrintFlag") + .HasColumnType("INTEGER"); + + b.Property("CommanderId") + .HasColumnType("INTEGER"); + + b.Property("CommonFlag") + .HasColumnType("INTEGER"); + + b.Property("CoreLists") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("Energy") + .HasColumnType("INTEGER"); + + b.Property("EquipInfoLists") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("Exp") + .HasColumnType("INTEGER"); + + b.Property("Intimacy") + .HasColumnType("INTEGER"); + + b.Property("IsLocked") + .HasColumnType("INTEGER"); + + b.Property("LastChangeName") + .HasColumnType("TEXT"); + + b.Property("Level") + .HasColumnType("INTEGER"); + + b.Property("MetaRepairLists") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("PlayerUid") + .HasColumnType("INTEGER"); + + b.Property("Proficiency") + .HasColumnType("INTEGER"); + + b.Property("Propose") + .HasColumnType("INTEGER"); + + b.Property("SkillIdLists") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("SkinId") + .HasColumnType("INTEGER"); + + b.Property("State") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("StrengthLists") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("TemplateId") + .HasColumnType("INTEGER"); + + b.Property("TransformLists") + .IsRequired() + .HasColumnType("jsonb"); + + b.HasKey("Id"); + + b.HasIndex("PlayerUid"); + + b.ToTable("Ships"); + }); + + modelBuilder.Entity("BLHX.Server.Common.Database.ResourceField", b => + { + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("PlayerUid") + .HasColumnType("INTEGER"); + + b.Property("LastHarvestTime") + .HasColumnType("TEXT"); + + b.Property("Level") + .HasColumnType("INTEGER"); + + b.Property("UpgradeTime") + .HasColumnType("TEXT"); + + b.HasKey("Type", "PlayerUid"); + + b.HasIndex("PlayerUid"); + + b.ToTable("ResourceFields"); + }); + + modelBuilder.Entity("BLHX.Server.Common.Database.PlayerResource", b => + { + b.HasOne("BLHX.Server.Common.Database.Player", "Player") + .WithMany("Resources") + .HasForeignKey("PlayerUid") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Player"); + }); + + modelBuilder.Entity("BLHX.Server.Common.Database.PlayerShip", b => + { + b.HasOne("BLHX.Server.Common.Database.Player", "Player") + .WithMany("Ships") + .HasForeignKey("PlayerUid") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Player"); + }); + + modelBuilder.Entity("BLHX.Server.Common.Database.ResourceField", b => + { + b.HasOne("BLHX.Server.Common.Database.Player", "Player") + .WithMany("ResourceFields") + .HasForeignKey("PlayerUid") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Player"); + }); + + modelBuilder.Entity("BLHX.Server.Common.Database.Player", b => + { + b.Navigation("ResourceFields"); + + b.Navigation("Resources"); + + b.Navigation("Ships"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/BLHX.Server.Common/Migrations/Player/20240222064540_ResourceFieldsUpgradeTime.cs b/BLHX.Server.Common/Migrations/Player/20240222064540_ResourceFieldsUpgradeTime.cs new file mode 100644 index 0000000..d626301 --- /dev/null +++ b/BLHX.Server.Common/Migrations/Player/20240222064540_ResourceFieldsUpgradeTime.cs @@ -0,0 +1,30 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace BLHX.Server.Common.Migrations.Player +{ + /// + public partial class ResourceFieldsUpgradeTime : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "UpgradeTime", + table: "ResourceFields", + type: "TEXT", + nullable: false, + defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "UpgradeTime", + table: "ResourceFields"); + } + } +} diff --git a/BLHX.Server.Common/Migrations/Player/PlayerContextModelSnapshot.cs b/BLHX.Server.Common/Migrations/Player/PlayerContextModelSnapshot.cs index c1c1774..c9cbf58 100644 --- a/BLHX.Server.Common/Migrations/Player/PlayerContextModelSnapshot.cs +++ b/BLHX.Server.Common/Migrations/Player/PlayerContextModelSnapshot.cs @@ -178,6 +178,30 @@ namespace BLHX.Server.Common.Migrations.Player b.ToTable("Ships"); }); + modelBuilder.Entity("BLHX.Server.Common.Database.ResourceField", b => + { + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("PlayerUid") + .HasColumnType("INTEGER"); + + b.Property("LastHarvestTime") + .HasColumnType("TEXT"); + + b.Property("Level") + .HasColumnType("INTEGER"); + + b.Property("UpgradeTime") + .HasColumnType("TEXT"); + + b.HasKey("Type", "PlayerUid"); + + b.HasIndex("PlayerUid"); + + b.ToTable("ResourceFields"); + }); + modelBuilder.Entity("BLHX.Server.Common.Database.PlayerResource", b => { b.HasOne("BLHX.Server.Common.Database.Player", "Player") @@ -200,8 +224,21 @@ namespace BLHX.Server.Common.Migrations.Player b.Navigation("Player"); }); + modelBuilder.Entity("BLHX.Server.Common.Database.ResourceField", b => + { + b.HasOne("BLHX.Server.Common.Database.Player", "Player") + .WithMany("ResourceFields") + .HasForeignKey("PlayerUid") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Player"); + }); + modelBuilder.Entity("BLHX.Server.Common.Database.Player", b => { + b.Navigation("ResourceFields"); + b.Navigation("Resources"); b.Navigation("Ships"); diff --git a/BLHX.Server.Common/Resources/ShareCfg/oilfield_template.json b/BLHX.Server.Common/Resources/ShareCfg/oilfield_template.json new file mode 100644 index 0000000..4f17dd4 --- /dev/null +++ b/BLHX.Server.Common/Resources/ShareCfg/oilfield_template.json @@ -0,0 +1,160 @@ +{ + "1": { + "hour_time": 3, + "level": 1, + "production": 20, + "store": 300, + "time": 10, + "use": [ + 1, + 60 + ], + "user_level": 1 + }, + "2": { + "hour_time": 3, + "level": 2, + "production": 21, + "store": 600, + "time": 900, + "use": [ + 1, + 300 + ], + "user_level": 10 + }, + "3": { + "hour_time": 3, + "level": 3, + "production": 22, + "store": 900, + "time": 3600, + "use": [ + 1, + 600 + ], + "user_level": 20 + }, + "4": { + "hour_time": 3, + "level": 4, + "production": 23, + "store": 1200, + "time": 7200, + "use": [ + 1, + 1500 + ], + "user_level": 30 + }, + "5": { + "hour_time": 3, + "level": 5, + "production": 24, + "store": 1500, + "time": 14400, + "use": [ + 1, + 3000 + ], + "user_level": 40 + }, + "6": { + "hour_time": 3, + "level": 6, + "production": 25, + "store": 1800, + "time": 28800, + "use": [ + 1, + 4500 + ], + "user_level": 50 + }, + "7": { + "hour_time": 3, + "level": 7, + "production": 26, + "store": 2100, + "time": 43200, + "use": [ + 1, + 6000 + ], + "user_level": 60 + }, + "8": { + "hour_time": 3, + "level": 8, + "production": 27, + "store": 2400, + "time": 64800, + "use": [ + 1, + 7500 + ], + "user_level": 70 + }, + "9": { + "hour_time": 3, + "level": 9, + "production": 28, + "store": 2700, + "time": 86400, + "use": [ + 1, + 15000 + ], + "user_level": 80 + }, + "10": { + "hour_time": 3, + "level": 10, + "production": 30, + "store": 3000, + "time": 7200, + "use": [ + 1, + 9000 + ], + "user_level": 90 + }, + "11": { + "hour_time": 3, + "level": 11, + "production": 31, + "store": 3300, + "time": 7200, + "use": [ + 1, + 10500 + ], + "user_level": 100 + }, + "12": { + "hour_time": 3, + "level": 12, + "production": 32, + "store": 3600, + "time": 0, + "use": [ + 1, + 12000 + ], + "user_level": 110 + }, + "all": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12 + ] +} \ No newline at end of file diff --git a/BLHX.Server.Common/Resources/ShareCfg/tradingport_template.json b/BLHX.Server.Common/Resources/ShareCfg/tradingport_template.json new file mode 100644 index 0000000..bb1ac5e --- /dev/null +++ b/BLHX.Server.Common/Resources/ShareCfg/tradingport_template.json @@ -0,0 +1,160 @@ +{ + "1": { + "hour_time": 3, + "level": 1, + "production": 60, + "store": 900, + "time": 10, + "use": [ + 1, + 60 + ], + "user_level": 1 + }, + "2": { + "hour_time": 3, + "level": 2, + "production": 64, + "store": 1800, + "time": 900, + "use": [ + 1, + 300 + ], + "user_level": 10 + }, + "3": { + "hour_time": 3, + "level": 3, + "production": 68, + "store": 2800, + "time": 3600, + "use": [ + 1, + 600 + ], + "user_level": 20 + }, + "4": { + "hour_time": 3, + "level": 4, + "production": 72, + "store": 3800, + "time": 7200, + "use": [ + 1, + 1500 + ], + "user_level": 30 + }, + "5": { + "hour_time": 3, + "level": 5, + "production": 76, + "store": 4800, + "time": 14400, + "use": [ + 1, + 3000 + ], + "user_level": 40 + }, + "6": { + "hour_time": 3, + "level": 6, + "production": 80, + "store": 5800, + "time": 28800, + "use": [ + 1, + 4500 + ], + "user_level": 50 + }, + "7": { + "hour_time": 3, + "level": 7, + "production": 84, + "store": 6800, + "time": 43200, + "use": [ + 1, + 6000 + ], + "user_level": 60 + }, + "8": { + "hour_time": 3, + "level": 8, + "production": 88, + "store": 7900, + "time": 64800, + "use": [ + 1, + 7500 + ], + "user_level": 70 + }, + "9": { + "hour_time": 3, + "level": 9, + "production": 92, + "store": 8900, + "time": 86400, + "use": [ + 1, + 15000 + ], + "user_level": 80 + }, + "10": { + "hour_time": 3, + "level": 10, + "production": 100, + "store": 10000, + "time": 7200, + "use": [ + 1, + 9000 + ], + "user_level": 90 + }, + "11": { + "hour_time": 3, + "level": 11, + "production": 104, + "store": 11000, + "time": 7200, + "use": [ + 1, + 10500 + ], + "user_level": 100 + }, + "12": { + "hour_time": 3, + "level": 12, + "production": 108, + "store": 12000, + "time": 0, + "use": [ + 1, + 12000 + ], + "user_level": 110 + }, + "all": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12 + ] +} \ No newline at end of file diff --git a/BLHX.Server.Common/Utils/DateTimeExtensions.cs b/BLHX.Server.Common/Utils/DateTimeExtensions.cs index 8c085be..75cb24d 100644 --- a/BLHX.Server.Common/Utils/DateTimeExtensions.cs +++ b/BLHX.Server.Common/Utils/DateTimeExtensions.cs @@ -10,5 +10,10 @@ int offset = (dayOfMonth + (int)firstDayOfWeek - 1) / 7; return offset + 1; } + + public static double GetSecondsPassed(this DateTime date) + { + return (DateTime.Now - date).TotalSeconds; + } } } diff --git a/BLHX.Server.Game/Connection.cs b/BLHX.Server.Game/Connection.cs index 19ced46..80542a0 100644 --- a/BLHX.Server.Game/Connection.cs +++ b/BLHX.Server.Game/Connection.cs @@ -76,7 +76,7 @@ namespace BLHX.Server.Game if (!attr.IsNotifyHandler) packetIdx++; if (!attr.SaveDataAfterRun) - DBManager.PlayerContext.SaveChanges(); + DBManager.PlayerContext.Save(); } else { @@ -138,6 +138,20 @@ namespace BLHX.Server.Game ns.Write(sendBuf); } + public void Tick() + { + foreach (var resourceField in player.ResourceFields) + { + resourceField.CalculateYield(); + } + + DBManager.PlayerContext.Save(); + this.NotifyResourceList(); +#if DEBUG + c.Log($"Tick"); +#endif + } + public void InitClientData() { this.NotifyPlayerData(); diff --git a/BLHX.Server.Game/Handlers/P10.cs b/BLHX.Server.Game/Handlers/P10.cs index c2f2d65..05790ba 100644 --- a/BLHX.Server.Game/Handlers/P10.cs +++ b/BLHX.Server.Game/Handlers/P10.cs @@ -89,6 +89,7 @@ namespace BLHX.Server.Game.Handlers return; } + DBManager.PlayerContext.PlayerRoutine(player); connection.player = player; rsp.UserId = player.Uid; connection.Send(rsp); @@ -116,6 +117,7 @@ namespace BLHX.Server.Game.Handlers static void HeartbeatHandler(Connection connection, Packet packet) { connection.Send(new Sc10101() { State = 1 }); + connection.Tick(); } } } diff --git a/BLHX.Server.Game/Handlers/P11.cs b/BLHX.Server.Game/Handlers/P11.cs index b6cf15a..fc6351d 100644 --- a/BLHX.Server.Game/Handlers/P11.cs +++ b/BLHX.Server.Game/Handlers/P11.cs @@ -16,6 +16,7 @@ namespace BLHX.Server.Game.Handlers Monday0oclockTimestamp = Connection.Monday0oclockTimestamp, ShipCount = connection.player is null ? 0 : (uint)connection.player.Ships.Count }); + connection.Tick(); } [PacketHandler(Command.Cs11009, SaveDataAfterRun = true)] @@ -27,6 +28,15 @@ namespace BLHX.Server.Game.Handlers connection.Send(new Sc11010()); } + [PacketHandler(Command.Cs11013, SaveDataAfterRun = true)] + static void HarvestResourceHandler(Connection connection, Packet packet) + { + var req = packet.Decode(); + connection.player.HarvestResourceField((ResourceFieldType)req.Type); + + connection.Send(new Sc11014()); + } + [PacketHandler(Command.Cs11601)] static void GetEmojiInfoHandler(Connection connection, Packet packet) { @@ -60,6 +70,17 @@ namespace BLHX.Server.Game.Handlers static class P11ConnectionNotifyExtensions { + public static void NotifyResourceList(this Connection connection) + { + if (connection.player is not null) + { + connection.Send(new Sc11004() + { + ResourceLists = connection.player.Resources.Select(x => new Resource() { Num = x.Num, Type = x.Id }).ToList() + }); + } + } + public static void NotifyPlayerData(this Connection connection) { if (connection.player is not null) diff --git a/BLHX.Server.Game/Handlers/P22.cs b/BLHX.Server.Game/Handlers/P22.cs index a008aec..1efd436 100644 --- a/BLHX.Server.Game/Handlers/P22.cs +++ b/BLHX.Server.Game/Handlers/P22.cs @@ -24,8 +24,8 @@ namespace BLHX.Server.Game.Handlers { connection.Send(new Sc22001() { - OilWellLevel = 1, - GoldWellLevel = 1, + OilWellLevel = connection.player.ResourceFields.FirstOrDefault(x => x.Type == Common.Database.ResourceFieldType.Oil)?.Level ?? 1, + GoldWellLevel = connection.player.ResourceFields.FirstOrDefault(x => x.Type == Common.Database.ResourceFieldType.Gold)?.Level ?? 1, ClassLv = 1, Class = new(), SkillClassNum = 2