diff --git a/Maple2.Database/Model/Map/HomeLayoutCube.cs b/Maple2.Database/Model/Map/HomeLayoutCube.cs index 60af68add..024d98bf8 100644 --- a/Maple2.Database/Model/Map/HomeLayoutCube.cs +++ b/Maple2.Database/Model/Map/HomeLayoutCube.cs @@ -19,19 +19,24 @@ internal class HomeLayoutCube { public int ItemId { get; set; } public HousingCategory HousingCategory { get; set; } - public CubePortalSettings? CubePortalSettings { get; set; } public InteractCube? Interact { get; set; } public UgcItemLook? Template { get; set; } [return: NotNullIfNotNull(nameof(other))] public static implicit operator PlotCube?(HomeLayoutCube? other) { - return other == null ? null : new PlotCube(other.ItemId, other.Id, other.Template) { + if (other == null) return null; + + var plotCube = new PlotCube(other.ItemId, other.Id, other.Template) { Position = new Vector3B(other.X, other.Y, other.Z), Rotation = other.Rotation, HousingCategory = other.HousingCategory, - CubePortalSettings = other.CubePortalSettings, Interact = other.Interact, }; + + if (plotCube.Interact?.NoticeSettings is not null) { + plotCube.Interact.NoticeSettings.Position = plotCube.Position; + } + return plotCube; } [return: NotNullIfNotNull(nameof(other))] @@ -44,7 +49,6 @@ internal class HomeLayoutCube { ItemId = other.ItemId, Template = other.Template, HousingCategory = other.HousingCategory, - CubePortalSettings = other.CubePortalSettings, Interact = other.Interact, }; } @@ -58,7 +62,6 @@ public static void Configure(EntityTypeBuilder builder) { .HasForeignKey(cube => cube.HomeLayoutId); builder.Property(cube => cube.Template).HasJsonConversion(); - builder.Property(cube => cube.CubePortalSettings).HasJsonConversion(); builder.Property(cube => cube.Interact).HasJsonConversion(); } } diff --git a/Maple2.Database/Model/Map/CubePortalSettings.cs b/Maple2.Database/Model/Map/InteractCube.cs similarity index 60% rename from Maple2.Database/Model/Map/CubePortalSettings.cs rename to Maple2.Database/Model/Map/InteractCube.cs index 4f0d03328..dd6c88e82 100644 --- a/Maple2.Database/Model/Map/CubePortalSettings.cs +++ b/Maple2.Database/Model/Map/InteractCube.cs @@ -1,10 +1,28 @@ using System.Diagnostics.CodeAnalysis; -using System.Text.Json.Serialization; using Maple2.Model.Enum; -using Maple2.Model.Game; namespace Maple2.Database.Model; +internal record InteractCube( + string Id, + InteractCubeState DefaultState, + CubePortalSettings? PortalSettings, + CubeNoticeSettings? NoticeSettings) { + + [return: NotNullIfNotNull(nameof(other))] + public static implicit operator InteractCube?(Maple2.Model.Game.InteractCube? other) { + return other == null ? null : new InteractCube( + other.Id, + other.DefaultState, + other.PortalSettings, + other.NoticeSettings); + } + + [return: NotNullIfNotNull(nameof(other))] + public static implicit operator Maple2.Model.Game.InteractCube?(InteractCube? other) { + return other == null ? null : new Maple2.Model.Game.InteractCube(other.Id, other.DefaultState, other.PortalSettings, other.NoticeSettings); + } +} internal record CubePortalSettings( string PortalName, @@ -32,19 +50,22 @@ internal record CubePortalSettings( } } -internal record InteractCube( - string Id, - InteractCubeState DefaultState) { +internal record CubeNoticeSettings( + string Notice, + byte Distance) { [return: NotNullIfNotNull(nameof(other))] - public static implicit operator InteractCube?(Maple2.Model.Game.InteractCube? other) { - return other == null ? null : new InteractCube( - other.Id, - other.DefaultState); + public static implicit operator CubeNoticeSettings?(Maple2.Model.Game.CubeNoticeSettings? other) { + return other == null ? null : new CubeNoticeSettings( + other.Notice, + other.Distance); } [return: NotNullIfNotNull(nameof(other))] - public static implicit operator Maple2.Model.Game.InteractCube?(InteractCube? other) { - return other == null ? null : new Maple2.Model.Game.InteractCube(other.Id, other.DefaultState); + public static implicit operator Maple2.Model.Game.CubeNoticeSettings?(CubeNoticeSettings? other) { + return other == null ? null : new Maple2.Model.Game.CubeNoticeSettings { + Notice = other.Notice, + Distance = other.Distance, + }; } } diff --git a/Maple2.Database/Model/Map/UgcMapCube.cs b/Maple2.Database/Model/Map/UgcMapCube.cs index 030e1768f..75fbbd13f 100644 --- a/Maple2.Database/Model/Map/UgcMapCube.cs +++ b/Maple2.Database/Model/Map/UgcMapCube.cs @@ -20,20 +20,25 @@ internal class UgcMapCube { public int ItemId { get; set; } public HousingCategory HousingCategory { get; set; } - public CubePortalSettings? CubePortalSettings { get; set; } public InteractCube? Interact { get; set; } public UgcItemLook? Template { get; set; } [return: NotNullIfNotNull(nameof(other))] public static implicit operator PlotCube?(UgcMapCube? other) { - return other == null ? null : new PlotCube(other.ItemId, other.Id, other.Template) { + if (other == null) return null; + + var plotCube = new PlotCube(other.ItemId, other.Id, other.Template) { Position = new Vector3B(other.X, other.Y, other.Z), Rotation = other.Rotation, HousingCategory = other.HousingCategory, - CubePortalSettings = other.CubePortalSettings, Interact = other.Interact, }; + + if (plotCube.Interact?.NoticeSettings is not null) { + plotCube.Interact.NoticeSettings.Position = plotCube.Position; + } + return plotCube; } [return: NotNullIfNotNull(nameof(other))] @@ -47,7 +52,6 @@ internal class UgcMapCube { ItemId = other.ItemId, Template = other.Template, HousingCategory = other.HousingCategory, - CubePortalSettings = other.CubePortalSettings, Interact = other.Interact, }; } @@ -61,7 +65,6 @@ public static void Configure(EntityTypeBuilder builder) { .HasForeignKey(cube => cube.UgcMapId); builder.Property(cube => cube.Template).HasJsonConversion(); - builder.Property(cube => cube.CubePortalSettings).HasJsonConversion(); builder.Property(cube => cube.Interact).HasJsonConversion(); } } diff --git a/Maple2.File.Ingest/Maple2.File.Ingest.csproj b/Maple2.File.Ingest/Maple2.File.Ingest.csproj index 0be812633..33307ea61 100644 --- a/Maple2.File.Ingest/Maple2.File.Ingest.csproj +++ b/Maple2.File.Ingest/Maple2.File.Ingest.csproj @@ -19,7 +19,7 @@ - + diff --git a/Maple2.File.Ingest/Mapper/FunctionCubeMapper.cs b/Maple2.File.Ingest/Mapper/FunctionCubeMapper.cs index 85b75a72a..299e043d6 100644 --- a/Maple2.File.Ingest/Mapper/FunctionCubeMapper.cs +++ b/Maple2.File.Ingest/Mapper/FunctionCubeMapper.cs @@ -16,10 +16,13 @@ public FunctionCubeMapper(M2dReader xmlReader) { } protected override IEnumerable Map() { - foreach ((int id, FunctionCube functionCube) in parser.Parse()) { + foreach ((int id, FunctionCubeRoot functionCubeRoot) in parser.Parse()) { + FunctionCube functionCube = functionCubeRoot.FunctionCube; + ConfigurableCube? configurableCube = functionCubeRoot.ConfigurableCube; yield return new FunctionCubeMetadata( Id: id, RecipeId: functionCube.receipeID, + ConfigurableCubeType: configurableCube is not null ? (ConfigurableCubeType) configurableCube.id : ConfigurableCubeType.None, DefaultState: (InteractCubeState) functionCube.DefaultState, AutoStateChange: functionCube.AutoStateChange, AutoStateChangeTime: functionCube.AutoStateChangeTime, diff --git a/Maple2.Model/Enum/ConfigurableCubeType.cs b/Maple2.Model/Enum/ConfigurableCubeType.cs new file mode 100644 index 000000000..2b4a22526 --- /dev/null +++ b/Maple2.Model/Enum/ConfigurableCubeType.cs @@ -0,0 +1,8 @@ +namespace Maple2.Model.Enum; +// ReSharper disable InconsistentNaming + +public enum ConfigurableCubeType { + None = 0, + UGCNotice = 1, + UGCPortal = 2, +} diff --git a/Maple2.Model/Game/Cube/CubePortalSettings.cs b/Maple2.Model/Game/Cube/ConfigurableCube.cs similarity index 52% rename from Maple2.Model/Game/Cube/CubePortalSettings.cs rename to Maple2.Model/Game/Cube/ConfigurableCube.cs index 0c84c1ef7..7a30cbc0c 100644 --- a/Maple2.Model/Game/Cube/CubePortalSettings.cs +++ b/Maple2.Model/Game/Cube/ConfigurableCube.cs @@ -1,41 +1,55 @@ using Maple2.Model.Common; using Maple2.Model.Enum; +using Maple2.Model.Metadata; using Maple2.PacketLib.Tools; using Maple2.Tools; namespace Maple2.Model.Game; -public class CubeSettings : IByteSerializable { - public virtual CubeSettings Clone() { - return (CubeSettings) MemberwiseClone(); - } - public virtual void WriteTo(IByteWriter writer) { } -} - -public sealed class CubePortalSettings : CubeSettings { +public class CubePortalSettings : IByteSerializable { public string PortalName { get; set; } public PortalActionType Method { get; set; } public CubePortalDestination Destination { get; set; } public string DestinationTarget { get; set; } public int PortalObjectId { get; set; } - public override CubeSettings Clone() { - return (CubePortalSettings) MemberwiseClone(); - } - public CubePortalSettings() { PortalName = string.Empty; DestinationTarget = string.Empty; } - public override void WriteTo(IByteWriter writer) { + public CubePortalSettings(Vector3B position) { + PortalName = $"Portal_{Math.Abs(position.X):D2}.{Math.Abs(position.Y):D2}.{Math.Abs(position.Z):D2}"; + DestinationTarget = string.Empty; + } + + public void WriteTo(IByteWriter writer) { writer.WriteUnicodeString(PortalName); writer.WriteByte((byte) Method); writer.Write(Destination); writer.WriteUnicodeString(DestinationTarget); } +} - public void SetName(Vector3B position) { - PortalName = $"Portal_{Math.Abs(position.X):D2}.{Math.Abs(position.Y):D2}.{Math.Abs(position.Z):D2}"; +public class CubeNoticeSettings : IByteSerializable { + public string Notice { get; set; } + public byte Distance { get; set; } + + public Vector3B Position { get; set; } + + public CubeNoticeSettings() { + Notice = string.Empty; + } + + public CubeNoticeSettings(Vector3B position) { + Notice = string.Empty; + Distance = 1; + Position = position; + } + + public void WriteTo(IByteWriter writer) { + writer.Write(Position); + writer.WriteUnicodeString(Notice); + writer.WriteByte(Distance); } } diff --git a/Maple2.Model/Game/Cube/InteractCube.cs b/Maple2.Model/Game/Cube/InteractCube.cs new file mode 100644 index 000000000..06bea05c6 --- /dev/null +++ b/Maple2.Model/Game/Cube/InteractCube.cs @@ -0,0 +1,53 @@ +using Maple2.Model.Common; +using Maple2.Model.Enum; +using Maple2.Model.Metadata; +using Maple2.PacketLib.Tools; +using Maple2.Tools; +using Maple2.Tools.Extensions; + +namespace Maple2.Model.Game; + +public class InteractCube : IByteSerializable { + public string Id { get; set; } + public InteractCubeState State { get; set; } + + public readonly InteractCubeState DefaultState; + + public Nurturing? Nurturing { get; set; } + public CubePortalSettings? PortalSettings { get; set; } + public CubeNoticeSettings? NoticeSettings { get; set; } + + public long InteractingCharacterId { get; set; } + + public InteractCube(Vector3B position, FunctionCubeMetadata metadata) { + Id = $"4_{position.ConvertToInt()}"; + DefaultState = metadata.DefaultState; + State = metadata.DefaultState; + + if (metadata.Nurturing is not null) { + Nurturing = new Nurturing(metadata.Nurturing); + } + + if (metadata.ConfigurableCubeType is ConfigurableCubeType.UGCPortal) { + PortalSettings = new CubePortalSettings(position); + } else if (metadata.ConfigurableCubeType is ConfigurableCubeType.UGCNotice) { + NoticeSettings = new CubeNoticeSettings(position); + } + } + + public InteractCube(string id, InteractCubeState defaultState, CubePortalSettings? portalSettings, CubeNoticeSettings? noticeSettings) { + Id = id; + DefaultState = defaultState; + State = defaultState; + PortalSettings = portalSettings; + NoticeSettings = noticeSettings; + } + + public void WriteTo(IByteWriter writer) { + writer.WriteUnicodeString(Id); + writer.Write(State); + if (Nurturing is not null) { + writer.WriteClass(Nurturing); + } + } +} diff --git a/Maple2.Model/Game/Cube/Nurturing.cs b/Maple2.Model/Game/Cube/Nurturing.cs new file mode 100644 index 000000000..faad1e1e5 --- /dev/null +++ b/Maple2.Model/Game/Cube/Nurturing.cs @@ -0,0 +1,85 @@ +using Maple2.Model.Metadata; +using Maple2.PacketLib.Tools; +using Maple2.Tools; + +namespace Maple2.Model.Game; + +public class Nurturing : IByteSerializable { + public long Exp { get; set; } + public DateTimeOffset LastFeedTime { get; set; } + + public short Stage { get; private set; } + public short ClaimedGiftForStage { get; set; } + public List PlayedBy { get; set; } + private DateTimeOffset CreationTime { get; set; } + + public readonly FunctionCubeMetadata.NurturingData NurturingMetadata; + + public Nurturing(FunctionCubeMetadata.NurturingData metadata) { + CreationTime = DateTimeOffset.Now; + NurturingMetadata = metadata; + Stage = 1; + ClaimedGiftForStage = 1; + PlayedBy = []; + } + + public Nurturing(long exp, short claimedGiftForStage, long[] playedBy, DateTimeOffset creationTime, DateTimeOffset lastFeedTime, FunctionCubeMetadata.NurturingData? metadata) { + NurturingMetadata = metadata ?? throw new ArgumentException("FunctionCubeMetadata does not have a Nurturing metadata."); + + Exp = exp; + Stage = 1; + ClaimedGiftForStage = claimedGiftForStage; + PlayedBy = playedBy.ToList(); + CreationTime = creationTime; + LastFeedTime = lastFeedTime; + + FunctionCubeMetadata.NurturingData.Growth[] requiredGrowth = metadata.RequiredGrowth; + if (exp >= requiredGrowth.Last().Exp) { + Stage = requiredGrowth.Last().Stage; + return; + } + + for (short i = 0; i < requiredGrowth.Length; i++) { + FunctionCubeMetadata.NurturingData.Growth growth = requiredGrowth[i]; + if (exp < growth.Exp) { + Stage = (short) (i + 1); + break; + } + } + } + + public void Feed() { + if (Exp >= NurturingMetadata.RequiredGrowth.Last().Exp) { + return; + } + + Exp += Constant.NurturingEatGrowth; + if (Exp >= NurturingMetadata.RequiredGrowth.First(x => x.Stage == Stage).Exp) { + Stage++; + } + LastFeedTime = DateTimeOffset.Now; + } + + public bool Play(long accountId) { + if (PlayedBy.Count >= Constant.NurturingPlayMaxCount) { + return false; + } + + if (PlayedBy.Contains(accountId)) { + return false; + } + + PlayedBy.Add(accountId); + Feed(); + return true; + } + + public void WriteTo(IByteWriter writer) { + writer.WriteLong(CreationTime.ToUnixTimeSeconds()); + writer.WriteLong(Exp); + writer.WriteShort(Stage); + writer.WriteShort(ClaimedGiftForStage); + writer.WriteShort(); // Unknown + writer.WriteLong(LastFeedTime.ToUnixTimeSeconds()); + } +} diff --git a/Maple2.Model/Game/Cube/PlotCube.cs b/Maple2.Model/Game/Cube/PlotCube.cs index 58fe9408e..63565dfca 100644 --- a/Maple2.Model/Game/Cube/PlotCube.cs +++ b/Maple2.Model/Game/Cube/PlotCube.cs @@ -1,9 +1,5 @@ using Maple2.Model.Common; using Maple2.Model.Enum; -using Maple2.Model.Metadata; -using Maple2.PacketLib.Tools; -using Maple2.Tools; -using Maple2.Tools.Extensions; namespace Maple2.Model.Game; @@ -18,7 +14,6 @@ public enum CubeType { Default, Construction, Liftable }; public HousingCategory HousingCategory { get; set; } - public CubePortalSettings? CubePortalSettings { get; set; } public InteractCube? Interact { get; set; } public PlotCube(int itemId, long id = 0, UgcItemLook? template = null) { @@ -26,124 +21,5 @@ public PlotCube(int itemId, long id = 0, UgcItemLook? template = null) { ItemType = new ItemType(itemId); Id = id; Template = template; - - if (itemId is Constant.InteriorPortalCubeId) { - CubePortalSettings = new CubePortalSettings(); - } - } -} - -public class InteractCube : IByteSerializable { - public string Id { get; set; } - public InteractCubeState State { get; set; } - - public readonly InteractCubeState DefaultState; - - public Nurturing? Nurturing { get; set; } - - public long InteractingCharacterId { get; set; } - - public InteractCube(Vector3B position, FunctionCubeMetadata metadata) { - Id = $"4_{position.ConvertToInt()}"; - DefaultState = metadata.DefaultState; - State = metadata.DefaultState; - - if (metadata.Nurturing is not null) { - Nurturing = new Nurturing(metadata.Nurturing); - } - } - - public InteractCube(string id, InteractCubeState defaultState) { - Id = id; - DefaultState = defaultState; - State = defaultState; - } - - public void WriteTo(IByteWriter writer) { - writer.WriteUnicodeString(Id); - writer.Write(State); - if (Nurturing is not null) { - writer.WriteClass(Nurturing); - } - } -} - -public class Nurturing : IByteSerializable { - public long Exp { get; set; } - public DateTimeOffset LastFeedTime { get; set; } - - public short Stage { get; private set; } - public short ClaimedGiftForStage { get; set; } - public List PlayedBy { get; set; } - private DateTimeOffset CreationTime { get; set; } - - public readonly FunctionCubeMetadata.NurturingData NurturingMetadata; - - public Nurturing(FunctionCubeMetadata.NurturingData metadata) { - CreationTime = DateTimeOffset.Now; - NurturingMetadata = metadata; - Stage = 1; - ClaimedGiftForStage = 1; - PlayedBy = []; - } - - public Nurturing(long exp, short claimedGiftForStage, long[] playedBy, DateTimeOffset creationTime, DateTimeOffset lastFeedTime, FunctionCubeMetadata.NurturingData? metadata) { - NurturingMetadata = metadata ?? throw new ArgumentException("FunctionCubeMetadata does not have a Nurturing metadata."); - - Exp = exp; - Stage = 1; - ClaimedGiftForStage = claimedGiftForStage; - PlayedBy = playedBy.ToList(); - CreationTime = creationTime; - LastFeedTime = lastFeedTime; - - FunctionCubeMetadata.NurturingData.Growth[] requiredGrowth = metadata.RequiredGrowth; - if (exp >= requiredGrowth.Last().Exp) { - Stage = requiredGrowth.Last().Stage; - return; - } - - for (short i = 0; i < requiredGrowth.Length; i++) { - FunctionCubeMetadata.NurturingData.Growth growth = requiredGrowth[i]; - if (exp < growth.Exp) { - Stage = (short) (i + 1); - break; - } - } - } - - public void Feed() { - if (Exp >= NurturingMetadata.RequiredGrowth.Last().Exp) { - return; - } - - Exp += Constant.NurturingEatGrowth; - if (Exp >= NurturingMetadata.RequiredGrowth.First(x => x.Stage == Stage).Exp) { - Stage++; - } - LastFeedTime = DateTimeOffset.Now; - } - - public bool Play(long accountId) { - if (PlayedBy.Count >= Constant.NurturingPlayMaxCount) { - return false; - } - - if (PlayedBy.Contains(accountId)) { - return false; - } - - PlayedBy.Add(accountId); - Feed(); - return true; - } - - public void WriteTo(IByteWriter writer) { - writer.WriteLong(CreationTime.ToUnixTimeSeconds()); - writer.WriteLong(Exp); - writer.WriteShort(Stage); - writer.WriteShort(ClaimedGiftForStage); - writer.WriteShort(); // Unknown - writer.WriteLong(LastFeedTime.ToUnixTimeSeconds()); } } diff --git a/Maple2.Model/Metadata/FunctionCubeMetadata.cs b/Maple2.Model/Metadata/FunctionCubeMetadata.cs index 1936734fa..695340323 100644 --- a/Maple2.Model/Metadata/FunctionCubeMetadata.cs +++ b/Maple2.Model/Metadata/FunctionCubeMetadata.cs @@ -6,6 +6,7 @@ namespace Maple2.Model.Metadata; public record FunctionCubeMetadata( int Id, int RecipeId, + ConfigurableCubeType ConfigurableCubeType, InteractCubeState DefaultState, int[] AutoStateChange, int AutoStateChangeTime, diff --git a/Maple2.Server.Game/Manager/Field/FieldManager.State.cs b/Maple2.Server.Game/Manager/Field/FieldManager.State.cs index 05eee5e44..0750da91a 100644 --- a/Maple2.Server.Game/Manager/Field/FieldManager.State.cs +++ b/Maple2.Server.Game/Manager/Field/FieldManager.State.cs @@ -167,27 +167,32 @@ public FieldPortal SpawnPortal(Portal portal, int instanceId, Vector3 position = return fieldPortal; } - public FieldPortal SpawnCubePortal(PlotCube plotCube) { + public FieldPortal? SpawnCubePortal(PlotCube plotCube) { int targetMapId = MapId; long targetHomeAccountId = 0; - if (!string.IsNullOrEmpty(plotCube.CubePortalSettings!.DestinationTarget)) { - switch (plotCube.CubePortalSettings.Destination) { + CubePortalSettings? cubePortalSettings = plotCube.Interact?.PortalSettings; + if (cubePortalSettings is null) { + return null; + } + + if (!string.IsNullOrEmpty(cubePortalSettings.DestinationTarget)) { + switch (cubePortalSettings.Destination) { case CubePortalDestination.PortalInHome: targetMapId = Constant.DefaultHomeMapId; break; case CubePortalDestination.SelectedMap: - targetMapId = int.Parse(plotCube.CubePortalSettings.DestinationTarget); + targetMapId = int.Parse(cubePortalSettings.DestinationTarget); break; case CubePortalDestination.FriendHome: targetMapId = Constant.DefaultHomeMapId; - targetHomeAccountId = long.Parse(plotCube.CubePortalSettings.DestinationTarget); + targetHomeAccountId = long.Parse(cubePortalSettings.DestinationTarget); break; } } - var portal = new Portal(NextLocalId(), targetMapId, -1, PortalType.InHome, plotCube.CubePortalSettings.Method, plotCube.Position, new Vector3(0, 0, plotCube.Rotation), new Vector3(200, 200, 250), 0, 0, Visible: true, MinimapVisible: false, Enable: true); + var portal = new Portal(NextLocalId(), targetMapId, -1, PortalType.InHome, cubePortalSettings.Method, plotCube.Position, new Vector3(0, 0, plotCube.Rotation), new Vector3(200, 200, 250), 0, 0, Visible: true, MinimapVisible: false, Enable: true); FieldPortal fieldPortal = SpawnPortal(portal); fieldPortal.HomeId = targetHomeAccountId; - plotCube.CubePortalSettings.PortalObjectId = fieldPortal.ObjectId; + cubePortalSettings.PortalObjectId = fieldPortal.ObjectId; return fieldPortal; } @@ -678,6 +683,15 @@ public void OnAddPlayer(FieldPlayer added) { result.AddRange(lifeSkillsCubes); added.Session.Send(FunctionCubePacket.SendCubes(result)); } + + foreach (Plot plot in Plots.Values) { + foreach (PlotCube plotCube in plot.Cubes.Values) { + if (plotCube.Interact?.NoticeSettings is not null) { + added.Session.Send(HomeActionPacket.SendCubeNoticeSettings(plotCube)); + } + } + } + foreach (FieldPlayer fieldPlayer in Players.Values) { added.Session.Send(FieldPacket.AddPlayer(fieldPlayer.Session)); if (fieldPlayer.Session.GuideObject != null) { diff --git a/Maple2.Server.Game/Manager/Field/FieldManager.cs b/Maple2.Server.Game/Manager/Field/FieldManager.cs index b35fc9f08..3abaf2338 100644 --- a/Maple2.Server.Game/Manager/Field/FieldManager.cs +++ b/Maple2.Server.Game/Manager/Field/FieldManager.cs @@ -136,7 +136,7 @@ private void Init() { if (MapId is Constant.DefaultHomeMapId) { List cubePortals = Plots.FirstOrDefault().Value.Cubes.Values - .Where(x => x.ItemId is Constant.InteriorPortalCubeId && x.CubePortalSettings is not null) + .Where(x => x.Interact?.PortalSettings is not null) .ToList(); foreach (PlotCube cubePortal in cubePortals) { @@ -411,14 +411,14 @@ public bool UsePortal(GameSession session, int portalId, string password) { // MoveByPortal (same map) Portal srcPortal = fieldPortal; if (srcPortal.Type is PortalType.InHome) { - PlotCube? cubePortal = Plots.First().Value.Cubes.Values.FirstOrDefault(x => x.CubePortalSettings is not null && x.CubePortalSettings.PortalObjectId == fieldPortal.ObjectId); + PlotCube? cubePortal = Plots.First().Value.Cubes.Values.FirstOrDefault(x => x.Interact?.PortalSettings is not null && x.Interact.PortalSettings.PortalObjectId == fieldPortal.ObjectId); if (cubePortal is null) { return false; } - switch (cubePortal.CubePortalSettings!.Destination) { + switch (cubePortal.Interact!.PortalSettings!.Destination) { case CubePortalDestination.PortalInHome: - PlotCube? destinationCube = Plots.First().Value.Cubes.Values.FirstOrDefault(x => x.CubePortalSettings is not null && x.CubePortalSettings.PortalName == cubePortal.CubePortalSettings.DestinationTarget); + PlotCube? destinationCube = Plots.First().Value.Cubes.Values.FirstOrDefault(x => x.Interact?.PortalSettings is not null && x.Interact.PortalSettings.PortalName == cubePortal.Interact.PortalSettings.DestinationTarget); if (destinationCube is null) { return false; } diff --git a/Maple2.Server.Game/Manager/HousingManager.cs b/Maple2.Server.Game/Manager/HousingManager.cs index 7cf591e31..968c468fb 100644 --- a/Maple2.Server.Game/Manager/HousingManager.cs +++ b/Maple2.Server.Game/Manager/HousingManager.cs @@ -521,7 +521,6 @@ public bool TryPlaceCube(HeldCube cube, Plot plot, in Vector3B position, float r HousingCategory = itemMetadata.Housing.HousingCategory, }; - result.CubePortalSettings?.SetName(position); if (result.ItemType.IsInteractFurnishing && functionCubeMetadata is not null) { result.Interact = new InteractCube(position, functionCubeMetadata); } @@ -558,7 +557,6 @@ public bool TryPlaceCube(HeldCube cube, Plot plot, in Vector3B position, float r result.Position = position; result.Rotation = rotation; result.HousingCategory = itemMetadata.Housing.HousingCategory; - result.CubePortalSettings?.SetName(position); if (result.ItemType.IsInteractFurnishing && functionCubeMetadata is not null) { result.Interact = new InteractCube(position, functionCubeMetadata); @@ -576,8 +574,8 @@ public bool TryRemoveCube(Plot plot, in Vector3B position, [NotNullWhen(true)] o return false; } - if (cube.ItemId is Constant.InteriorPortalCubeId && cube.CubePortalSettings is not null) { - session.Field.RemovePortal(cube.CubePortalSettings.PortalObjectId); + if (cube.Interact?.PortalSettings is not null) { + session.Field.RemovePortal(cube.Interact.PortalSettings.PortalObjectId); } if (cube.HousingCategory is HousingCategory.Farming or HousingCategory.Ranching && cube.Interact is not null) { @@ -699,22 +697,25 @@ public void ApplyLayout(Plot plot, HomeLayout layout, bool isBlueprint = false) } if (plotCube.ItemType.IsInteractFurnishing && plotCube.Interact is not null) { + if (cube.Interact?.PortalSettings is not null) { + plotCube.Interact.PortalSettings = cube.Interact.PortalSettings; + } session.Field.Broadcast(FunctionCubePacket.AddFunctionCube(plotCube.Interact)); } - if (cube.CubePortalSettings is not null) { - plotCube.CubePortalSettings = cube.CubePortalSettings; - } session.Field.Broadcast(sendPacket); } List cubePortals = plot.Cubes.Values - .Where(x => x.ItemId is Constant.InteriorPortalCubeId && x.CubePortalSettings is not null) + .Where(x => x.ItemId is Constant.InteriorPortalCubeId && x.Interact?.PortalSettings is not null) .ToList(); foreach (PlotCube cubePortal in cubePortals) { - FieldPortal fieldPortal = session.Field.SpawnCubePortal(cubePortal); + FieldPortal? fieldPortal = session.Field.SpawnCubePortal(cubePortal); + if (fieldPortal is null) { + continue; + } session.Field.Broadcast(PortalPacket.Add(fieldPortal)); } diff --git a/Maple2.Server.Game/PacketHandlers/HomeActionHandler.cs b/Maple2.Server.Game/PacketHandlers/HomeActionHandler.cs index cb7b55934..588cf0f0f 100644 --- a/Maple2.Server.Game/PacketHandlers/HomeActionHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/HomeActionHandler.cs @@ -21,7 +21,8 @@ private enum Command : byte { Survey = 5, ChangePortalSettings = 6, UpdateBallCoord = 7, - SendPortalSettings = 13, + ChangeNoticeSettings = 12, + SendConfigurableSettings = 13, } public override void Handle(GameSession session, IByteReader packet) { @@ -36,8 +37,11 @@ public override void Handle(GameSession session, IByteReader packet) { case Command.ChangePortalSettings: HandleChangePortalSettings(session, packet); break; - case Command.SendPortalSettings: - HandleSendPortalSettings(session, packet); + case Command.ChangeNoticeSettings: + HandleChangeNoticeSettings(session, packet); + break; + case Command.SendConfigurableSettings: + HandleConfigurableSettings(session, packet); break; } } @@ -123,39 +127,38 @@ private void HandleChangePortalSettings(GameSession session, IByteReader packet) return; } - if (cube.ItemId is not Constant.InteriorPortalCubeId) { - Logger.Warning("Cube is not a portal cube at {0}", coord); - return; - } - - if (cube.CubePortalSettings is null) { + if (cube.Interact?.PortalSettings is null) { Logger.Warning("Cube does not have portal settings at {0}", coord); return; } - cube.CubePortalSettings.PortalName = packet.ReadUnicodeString(); - cube.CubePortalSettings.Method = (PortalActionType) packet.ReadByte(); - cube.CubePortalSettings.Destination = (CubePortalDestination) packet.ReadByte(); - cube.CubePortalSettings.DestinationTarget = packet.ReadUnicodeString(); + cube.Interact.PortalSettings.PortalName = packet.ReadUnicodeString(); + cube.Interact.PortalSettings.Method = (PortalActionType) packet.ReadByte(); + cube.Interact.PortalSettings.Destination = (CubePortalDestination) packet.ReadByte(); + cube.Interact.PortalSettings.DestinationTarget = packet.ReadUnicodeString(); foreach (FieldPortal portal in session.Field.GetPortals()) { session.Field.RemovePortal(portal.ObjectId); } List cubePortals = plot.Cubes.Values - .Where(x => x.ItemId is Constant.InteriorPortalCubeId && x.CubePortalSettings is not null) + .Where(x => x.ItemId is Constant.InteriorPortalCubeId && x.Interact?.PortalSettings is not null) .ToList(); foreach (PlotCube cubePortal in cubePortals) { - FieldPortal fieldPortal = session.Field.SpawnCubePortal(cubePortal); + FieldPortal? fieldPortal = session.Field.SpawnCubePortal(cubePortal); + if (fieldPortal == null) { + continue; + } session.Field.Broadcast(PortalPacket.Add(fieldPortal)); } session.Housing.SaveHome(); } - private void HandleSendPortalSettings(GameSession session, IByteReader packet) { - var coord = packet.Read(); + private void HandleChangeNoticeSettings(GameSession session, IByteReader packet) { + bool editing = packet.ReadBool(); + Vector3B coord = packet.Read(); Plot? plot = session.Housing.GetFieldPlot(); if (plot == null) { @@ -167,16 +170,42 @@ private void HandleSendPortalSettings(GameSession session, IByteReader packet) { return; } - if (cube.ItemId is not Constant.InteriorPortalCubeId) { - Logger.Warning("Cube is not a portal cube at {0}", coord); + if (cube.Interact?.NoticeSettings is null) { + Logger.Warning("Cube does not have notice settings at {0}", coord); return; } - List otherPortalsNames = plot.Cubes.Values - .Where(x => x.ItemId is Constant.InteriorPortalCubeId && x.Id != cube.Id) - .Select(x => x.CubePortalSettings?.PortalName ?? string.Empty) - .ToList(); + cube.Interact.NoticeSettings.Notice = packet.ReadUnicodeString(); + cube.Interact.NoticeSettings.Distance = packet.ReadByte(); + + session.Field.Broadcast(HomeActionPacket.SendCubeNoticeSettings(cube, editing: false)); + session.Housing.SaveHome(); + } + + private void HandleConfigurableSettings(GameSession session, IByteReader packet) { + var coord = packet.Read(); - session.Send(HomeActionPacket.SendCubePortalSettings(cube, otherPortalsNames)); + Plot? plot = session.Housing.GetFieldPlot(); + if (plot == null) { + return; + } + + if (!plot.Cubes.TryGetValue(coord, out PlotCube? cube)) { + Logger.Warning("Cube not found at {0}", coord); + return; + } + + if (cube.Interact?.PortalSettings is not null) { + List otherPortalsNames = plot.Cubes.Values + .Where(x => x.ItemId is Constant.InteriorPortalCubeId && x.Id != cube.Id) + .Select(x => x.Interact!.PortalSettings?.PortalName ?? string.Empty) + .ToList(); + + session.Send(HomeActionPacket.SendCubePortalSettings(cube, otherPortalsNames)); + } else if (cube.Interact?.NoticeSettings is not null) { + session.Send(HomeActionPacket.SendCubeNoticeSettings(cube, editing: true)); + } else { + Logger.Warning("Cube is not configurable at {0}", coord); + } } } diff --git a/Maple2.Server.Game/Packets/HomeActionPacket.cs b/Maple2.Server.Game/Packets/HomeActionPacket.cs index e10b698a3..f2222ce2f 100644 --- a/Maple2.Server.Game/Packets/HomeActionPacket.cs +++ b/Maple2.Server.Game/Packets/HomeActionPacket.cs @@ -18,6 +18,7 @@ private enum HomeActionCommand : byte { PortalCube = 6, Ball = 7, Roll = 11, + NoticeCube = 12, } private enum SurveyCommand : byte { @@ -37,13 +38,13 @@ private enum BallCommand : byte { } public static ByteWriter SendCubePortalSettings(PlotCube cube, List otherPortalsNames) { - Debug.Assert(cube.CubePortalSettings != null, nameof(cube.CubePortalSettings) + " != null"); + Debug.Assert(cube.Interact?.PortalSettings != null, nameof(cube.Interact.PortalSettings) + " != null"); var pWriter = Packet.Of(SendOp.HomeAction); pWriter.Write(HomeActionCommand.PortalCube); pWriter.WriteByte(); pWriter.Write(cube.Position); - pWriter.WriteClass(cube.CubePortalSettings); + pWriter.WriteClass(cube.Interact.PortalSettings); pWriter.WriteInt(otherPortalsNames.Count); foreach (string portalName in otherPortalsNames) { pWriter.WriteUnicodeString(portalName); @@ -52,6 +53,17 @@ public static ByteWriter SendCubePortalSettings(PlotCube cube, List othe return pWriter; } + public static ByteWriter SendCubeNoticeSettings(PlotCube cube, bool editing = false) { + Debug.Assert(cube.Interact?.NoticeSettings != null, nameof(cube.Interact.NoticeSettings) + " != null"); + + var pWriter = Packet.Of(SendOp.HomeAction); + pWriter.Write(HomeActionCommand.NoticeCube); + pWriter.WriteBool(editing); + pWriter.WriteClass(cube.Interact.NoticeSettings); + + return pWriter; + } + public static ByteWriter HostAlarm(string message) { var pWriter = Packet.Of(SendOp.HomeAction); pWriter.Write(HomeActionCommand.Alarm); diff --git a/Maple2.Server.World/Migrations/20250219083923_ReworkInteractCube.Designer.cs b/Maple2.Server.World/Migrations/20250219083923_ReworkInteractCube.Designer.cs new file mode 100644 index 000000000..29979e901 --- /dev/null +++ b/Maple2.Server.World/Migrations/20250219083923_ReworkInteractCube.Designer.cs @@ -0,0 +1,1849 @@ +// +using System; +using Maple2.Database.Context; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Maple2.Server.World.Migrations +{ + [DbContext(typeof(Ms2Context))] + [Migration("20250219083923_ReworkInteractCube")] + partial class ReworkInteractCube + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("Maple2.Database.Model.Account", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("ActiveGoldPass") + .HasColumnType("tinyint(1)"); + + b.Property("CreationTime") + .ValueGeneratedOnAdd() + .HasColumnType("datetime(6)"); + + b.Property("Currency") + .IsRequired() + .HasColumnType("json"); + + b.Property("LastModified") + .IsConcurrencyToken() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("datetime(6)"); + + b.Property("MachineId") + .HasColumnType("binary(16)"); + + b.Property("MarketLimits") + .IsRequired() + .HasColumnType("json"); + + b.Property("MaxCharacters") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(4); + + b.Property("Online") + .HasColumnType("tinyint(1)"); + + b.Property("Password") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("PremiumRewardsClaimed") + .IsRequired() + .HasColumnType("json"); + + b.Property("PremiumTime") + .HasColumnType("bigint"); + + b.Property("PrestigeCurrentExp") + .HasColumnType("bigint"); + + b.Property("PrestigeExp") + .HasColumnType("bigint"); + + b.Property("PrestigeLevel") + .HasColumnType("int"); + + b.Property("PrestigeLevelsGained") + .HasColumnType("int"); + + b.Property("PrestigeMissions") + .IsRequired() + .HasColumnType("json"); + + b.Property("PrestigeRewardsClaimed") + .IsRequired() + .HasColumnType("json"); + + b.Property("SurvivalExp") + .HasColumnType("bigint"); + + b.Property("SurvivalGoldLevelRewardClaimed") + .HasColumnType("int"); + + b.Property("SurvivalLevel") + .HasColumnType("int"); + + b.Property("SurvivalSilverLevelRewardClaimed") + .HasColumnType("int"); + + b.Property("Username") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("account", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.Achievement", b => + { + b.Property("OwnerId") + .HasColumnType("bigint"); + + b.Property("Id") + .HasColumnType("int"); + + b.Property("Category") + .HasColumnType("int"); + + b.Property("CompletedCount") + .HasColumnType("int"); + + b.Property("Counter") + .HasColumnType("bigint"); + + b.Property("CurrentGrade") + .HasColumnType("int"); + + b.Property("Favorite") + .HasColumnType("tinyint(1)"); + + b.Property("Grades") + .IsRequired() + .HasColumnType("json"); + + b.Property("RewardGrade") + .HasColumnType("int"); + + b.HasKey("OwnerId", "Id"); + + b.ToTable("achievement", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.BannerSlot", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("ActivateTime") + .HasColumnType("datetime(6)"); + + b.Property("BannerId") + .HasColumnType("bigint"); + + b.Property("Template") + .HasColumnType("json"); + + b.HasKey("Id"); + + b.HasIndex("BannerId"); + + b.ToTable("ugc-banner-slot", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.BlackMarketListing", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("CharacterId") + .HasColumnType("bigint"); + + b.Property("CreationTime") + .ValueGeneratedOnAdd() + .HasColumnType("datetime(6)"); + + b.Property("Deposit") + .HasColumnType("bigint"); + + b.Property("ExpiryTime") + .HasColumnType("datetime(6)"); + + b.Property("ItemUid") + .HasColumnType("bigint"); + + b.Property("Price") + .HasColumnType("bigint"); + + b.Property("Quantity") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("black-market-listing", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.Buddy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("BuddyId") + .HasColumnType("bigint"); + + b.Property("LastModified") + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("datetime(6)"); + + b.Property("Message") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("OwnerId") + .HasColumnType("bigint"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.HasKey("Id"); + + b.HasIndex("BuddyId"); + + b.HasIndex("OwnerId"); + + b.ToTable("buddy", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.Character", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("Channel") + .HasColumnType("smallint"); + + b.Property("Cooldown") + .IsRequired() + .HasColumnType("json"); + + b.Property("CreationTime") + .ValueGeneratedOnAdd() + .HasColumnType("datetime(6)"); + + b.Property("Currency") + .IsRequired() + .HasColumnType("json"); + + b.Property("DeleteTime") + .HasColumnType("datetime(6)"); + + b.Property("Experience") + .IsRequired() + .HasColumnType("json"); + + b.Property("Gender") + .HasColumnType("tinyint unsigned"); + + b.Property("Job") + .HasColumnType("int"); + + b.Property("LastModified") + .IsConcurrencyToken() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("datetime(6)"); + + b.Property("Level") + .ValueGeneratedOnAdd() + .HasColumnType("smallint") + .HasDefaultValue((short)1); + + b.Property("MapId") + .HasColumnType("int"); + + b.Property("Mastery") + .IsRequired() + .HasColumnType("json"); + + b.Property("Name") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.Property("Profile") + .IsRequired() + .HasColumnType("json"); + + b.Property("ReturnMapId") + .HasColumnType("int"); + + b.Property("SkinColor") + .IsRequired() + .HasColumnType("json"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("character", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.CharacterConfig", b => + { + b.Property("CharacterId") + .HasColumnType("bigint"); + + b.Property("DeathCount") + .HasColumnType("int"); + + b.Property("DeathTick") + .HasColumnType("bigint"); + + b.Property("ExplorationProgress") + .HasColumnType("int"); + + b.Property("FavoriteDesigners") + .HasColumnType("json"); + + b.Property("FavoriteStickers") + .HasColumnType("json"); + + b.Property("GatheringCounts") + .HasColumnType("json"); + + b.Property("GuideRecords") + .HasColumnType("json"); + + b.Property("HotBars") + .HasColumnType("json"); + + b.Property("KeyBinds") + .HasColumnType("json"); + + b.Property("Lapenshards") + .HasColumnType("json"); + + b.Property("LastModified") + .IsConcurrencyToken() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("datetime(6)"); + + b.Property("SkillCooldowns") + .HasColumnType("json"); + + b.Property("SkillMacros") + .HasColumnType("json"); + + b.Property("SkillPoint") + .HasColumnType("json"); + + b.Property("StatAllocation") + .HasColumnType("json"); + + b.Property("StatPoints") + .HasColumnType("json"); + + b.Property("Wardrobes") + .HasColumnType("json"); + + b.HasKey("CharacterId"); + + b.ToTable("character-config", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.CharacterUnlock", b => + { + b.Property("CharacterId") + .HasColumnType("bigint"); + + b.Property("CollectedItems") + .IsRequired() + .HasColumnType("json"); + + b.Property("Emotes") + .IsRequired() + .HasColumnType("json"); + + b.Property("Expand") + .IsRequired() + .HasColumnType("json"); + + b.Property("FishAlbum") + .IsRequired() + .HasColumnType("json"); + + b.Property("HairSlotExpand") + .HasColumnType("smallint"); + + b.Property("InteractedObjects") + .IsRequired() + .HasColumnType("json"); + + b.Property("LastModified") + .IsConcurrencyToken() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("datetime(6)"); + + b.Property("Maps") + .IsRequired() + .HasColumnType("json"); + + b.Property("MasteryRewardsClaimed") + .IsRequired() + .HasColumnType("json"); + + b.Property("Pets") + .IsRequired() + .HasColumnType("json"); + + b.Property("StickerSets") + .IsRequired() + .HasColumnType("json"); + + b.Property("Taxis") + .IsRequired() + .HasColumnType("json"); + + b.Property("Titles") + .IsRequired() + .HasColumnType("json"); + + b.HasKey("CharacterId"); + + b.ToTable("character-unlock", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.Club", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("BuffId") + .HasColumnType("int"); + + b.Property("CreationTime") + .ValueGeneratedOnAdd() + .HasColumnType("datetime(6)"); + + b.Property("LeaderId") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.Property("NameChangeCooldown") + .HasColumnType("datetime(6)"); + + b.Property("State") + .HasColumnType("tinyint unsigned"); + + b.HasKey("Id"); + + b.HasIndex("LeaderId"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("club", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.ClubMember", b => + { + b.Property("ClubId") + .HasColumnType("bigint"); + + b.Property("CharacterId") + .HasColumnType("bigint"); + + b.Property("CreationTime") + .ValueGeneratedOnAdd() + .HasColumnType("datetime(6)"); + + b.HasKey("ClubId", "CharacterId"); + + b.HasIndex("CharacterId"); + + b.ToTable("club-member", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.GameEventUserValue", b => + { + b.Property("CharacterId") + .HasColumnType("bigint"); + + b.Property("EventId") + .HasColumnType("int"); + + b.Property("Type") + .HasColumnType("int"); + + b.Property("ExpirationTime") + .HasColumnType("bigint"); + + b.Property("Value") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("CharacterId", "EventId", "Type"); + + b.ToTable("game-event-user-value", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.Guild", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("Buffs") + .IsRequired() + .HasColumnType("json"); + + b.Property("CreationTime") + .ValueGeneratedOnAdd() + .HasColumnType("datetime(6)"); + + b.Property("Emblem") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Experience") + .HasColumnType("int"); + + b.Property("Focus") + .HasColumnType("int"); + + b.Property("Funds") + .HasColumnType("int"); + + b.Property("HouseRank") + .HasColumnType("int"); + + b.Property("HouseTheme") + .HasColumnType("int"); + + b.Property("LeaderId") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Notice") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Npcs") + .IsRequired() + .HasColumnType("json"); + + b.Property("Posters") + .IsRequired() + .HasColumnType("json"); + + b.Property("Ranks") + .IsRequired() + .HasColumnType("json"); + + b.HasKey("Id"); + + b.HasIndex("LeaderId") + .IsUnique(); + + b.ToTable("guild", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.GuildApplication", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("ApplicantId") + .HasColumnType("bigint"); + + b.Property("CreationTime") + .ValueGeneratedOnAdd() + .HasColumnType("datetime(6)"); + + b.Property("GuildId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ApplicantId"); + + b.HasIndex("GuildId"); + + b.ToTable("guild-application", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.GuildMember", b => + { + b.Property("GuildId") + .HasColumnType("bigint"); + + b.Property("CharacterId") + .HasColumnType("bigint"); + + b.Property("CheckinTime") + .HasColumnType("datetime(6)"); + + b.Property("CreationTime") + .ValueGeneratedOnAdd() + .HasColumnType("datetime(6)"); + + b.Property("DailyDonationCount") + .HasColumnType("int"); + + b.Property("DonationTime") + .HasColumnType("datetime(6)"); + + b.Property("Message") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Rank") + .HasColumnType("tinyint unsigned"); + + b.Property("TotalContribution") + .HasColumnType("int"); + + b.Property("WeeklyContribution") + .HasColumnType("int"); + + b.HasKey("GuildId", "CharacterId"); + + b.HasIndex("CharacterId") + .IsUnique(); + + b.ToTable("guild-member", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.Home", b => + { + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("ArchitectScore") + .HasColumnType("int"); + + b.Property("Area") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint unsigned") + .HasDefaultValue((byte)4); + + b.Property("Background") + .HasColumnType("tinyint unsigned"); + + b.Property("Blueprints") + .IsRequired() + .HasColumnType("json"); + + b.Property("Camera") + .HasColumnType("tinyint unsigned"); + + b.Property("CurrentArchitectScore") + .HasColumnType("int"); + + b.Property("DecorationExp") + .HasColumnType("bigint"); + + b.Property("DecorationLevel") + .HasColumnType("bigint"); + + b.Property("DecorationRewardTimestamp") + .HasColumnType("bigint"); + + b.Property("Height") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint unsigned") + .HasDefaultValue((byte)3); + + b.Property("InteriorRewardsClaimed") + .IsRequired() + .HasColumnType("json"); + + b.Property("LastModified") + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("datetime(6)"); + + b.Property("Layouts") + .IsRequired() + .HasColumnType("json"); + + b.Property("Lighting") + .HasColumnType("tinyint unsigned"); + + b.Property("Message") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Passcode") + .HasColumnType("longtext"); + + b.Property("Permissions") + .IsRequired() + .HasColumnType("json"); + + b.HasKey("AccountId"); + + b.ToTable("home", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.HomeLayout", b => + { + b.Property("Uid") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("Area") + .HasColumnType("tinyint unsigned"); + + b.Property("Background") + .HasColumnType("tinyint unsigned"); + + b.Property("Camera") + .HasColumnType("tinyint unsigned"); + + b.Property("Height") + .HasColumnType("tinyint unsigned"); + + b.Property("Id") + .HasColumnType("int"); + + b.Property("Lighting") + .HasColumnType("tinyint unsigned"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Timestamp") + .HasColumnType("datetime(6)"); + + b.HasKey("Uid"); + + b.ToTable("home-layout", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.HomeLayoutCube", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("HomeLayoutId") + .HasColumnType("bigint"); + + b.Property("HousingCategory") + .HasColumnType("int"); + + b.Property("Interact") + .HasColumnType("json"); + + b.Property("ItemId") + .HasColumnType("int"); + + b.Property("Rotation") + .HasColumnType("float"); + + b.Property("Template") + .HasColumnType("json"); + + b.Property("X") + .HasColumnType("tinyint"); + + b.Property("Y") + .HasColumnType("tinyint"); + + b.Property("Z") + .HasColumnType("tinyint"); + + b.HasKey("Id"); + + b.HasIndex("HomeLayoutId"); + + b.ToTable("home-layout-cube", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.Item", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("Amount") + .HasColumnType("int"); + + b.Property("Appearance") + .IsRequired() + .HasColumnType("json"); + + b.Property("Binding") + .HasColumnType("json"); + + b.Property("CoupleInfo") + .HasColumnType("json"); + + b.Property("CreationTime") + .ValueGeneratedOnAdd() + .HasColumnType("datetime(6)"); + + b.Property("Enchant") + .HasColumnType("json"); + + b.Property("ExpiryTime") + .HasColumnType("datetime(6)"); + + b.Property("GachaDismantleId") + .HasColumnType("int"); + + b.Property("GlamorForges") + .HasColumnType("smallint"); + + b.Property("Group") + .HasColumnType("tinyint unsigned"); + + b.Property("IsLocked") + .HasColumnType("tinyint(1)"); + + b.Property("ItemId") + .HasColumnType("int"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("datetime(6)"); + + b.Property("LimitBreak") + .HasColumnType("json"); + + b.Property("OwnerId") + .HasColumnType("bigint"); + + b.Property("Rarity") + .HasColumnType("int"); + + b.Property("RemainUses") + .HasColumnType("int"); + + b.Property("Slot") + .HasColumnType("smallint"); + + b.Property("Socket") + .HasColumnType("json"); + + b.Property("Stats") + .HasColumnType("json"); + + b.Property("SubType") + .HasColumnType("json"); + + b.Property("TimeChangedOption") + .HasColumnType("int"); + + b.Property("Transfer") + .HasColumnType("json"); + + b.Property("UnlockTime") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("item", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.ItemStorage", b => + { + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("Expand") + .HasColumnType("smallint"); + + b.Property("Meso") + .HasColumnType("bigint"); + + b.HasKey("AccountId"); + + b.ToTable("item-storage", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.Mail", b => + { + b.Property("ReceiverId") + .HasColumnType("bigint"); + + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("Content") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ContentArgs") + .IsRequired() + .HasColumnType("json"); + + b.Property("Currency") + .IsRequired() + .HasColumnType("json"); + + b.Property("ExpiryTime") + .HasColumnType("datetime(6)"); + + b.Property("ReadTime") + .HasColumnType("datetime(6)"); + + b.Property("SendTime") + .ValueGeneratedOnAdd() + .HasColumnType("datetime(6)"); + + b.Property("SenderId") + .HasColumnType("bigint"); + + b.Property("SenderName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Title") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TitleArgs") + .IsRequired() + .HasColumnType("json"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("WeddingInvite") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("ReceiverId", "Id"); + + b.ToTable("mail", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.Marriage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CreationTime") + .ValueGeneratedOnAdd() + .HasColumnType("datetime(6)"); + + b.Property("ExpHistory") + .IsRequired() + .HasColumnType("json"); + + b.Property("Partner1Id") + .HasColumnType("bigint"); + + b.Property("Partner1Message") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Partner2Id") + .HasColumnType("bigint"); + + b.Property("Partner2Message") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Profile") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("Partner1Id"); + + b.HasIndex("Partner2Id"); + + b.ToTable("marriage", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.Medal", b => + { + b.Property("OwnerId") + .HasColumnType("bigint"); + + b.Property("Id") + .HasColumnType("int"); + + b.Property("ExpiryTime") + .HasColumnType("datetime(6)"); + + b.Property("Slot") + .HasColumnType("smallint"); + + b.HasKey("OwnerId", "Id"); + + b.ToTable("medal", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.MesoListing", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("Amount") + .HasColumnType("bigint"); + + b.Property("CharacterId") + .HasColumnType("bigint"); + + b.Property("CreationTime") + .ValueGeneratedOnAdd() + .HasColumnType("datetime(6)"); + + b.Property("ExpiryTime") + .HasColumnType("datetime(6)"); + + b.Property("LastModified") + .IsConcurrencyToken() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("datetime(6)"); + + b.Property("Price") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("CharacterId"); + + b.ToTable("meso-market", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.Nurturing", b => + { + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("ItemId") + .HasColumnType("int"); + + b.Property("ClaimedGiftForStage") + .HasColumnType("smallint"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("Exp") + .HasColumnType("bigint"); + + b.Property("LastFeedTime") + .HasColumnType("datetime(6)"); + + b.Property("PlayedBy") + .IsRequired() + .HasColumnType("json"); + + b.HasKey("AccountId", "ItemId"); + + b.ToTable("nurturing", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.PetConfig", b => + { + b.Property("ItemUid") + .HasColumnType("bigint"); + + b.Property("LootConfig") + .IsRequired() + .HasColumnType("json"); + + b.Property("PotionConfigs") + .IsRequired() + .HasColumnType("json"); + + b.HasKey("ItemUid"); + + b.ToTable("pet-config", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.Quest", b => + { + b.Property("OwnerId") + .HasColumnType("bigint"); + + b.Property("Id") + .HasColumnType("int"); + + b.Property("CompletionCount") + .HasColumnType("int"); + + b.Property("Conditions") + .IsRequired() + .HasColumnType("json"); + + b.Property("EndTime") + .HasColumnType("bigint"); + + b.Property("StartTime") + .HasColumnType("bigint"); + + b.Property("State") + .HasColumnType("int"); + + b.Property("Track") + .HasColumnType("tinyint(1)"); + + b.HasKey("OwnerId", "Id"); + + b.ToTable("quest", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.ServerInfo", b => + { + b.Property("Key") + .HasColumnType("varchar(255)"); + + b.Property("LastModified") + .HasColumnType("datetime(6)"); + + b.HasKey("Key"); + + b.ToTable("server-info", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.Shop.CharacterShopData", b => + { + b.Property("ShopId") + .HasColumnType("int"); + + b.Property("OwnerId") + .HasColumnType("bigint"); + + b.Property("Interval") + .HasColumnType("tinyint unsigned"); + + b.Property("RestockCount") + .HasColumnType("int"); + + b.Property("RestockTime") + .HasColumnType("datetime(6)"); + + b.HasKey("ShopId", "OwnerId"); + + b.ToTable("character-shop-data", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.Shop.CharacterShopItemData", b => + { + b.Property("ShopItemId") + .HasColumnType("int"); + + b.Property("ShopId") + .HasColumnType("int"); + + b.Property("OwnerId") + .HasColumnType("bigint"); + + b.Property("Item") + .IsRequired() + .HasColumnType("json"); + + b.Property("StockPurchased") + .HasColumnType("int"); + + b.HasKey("ShopItemId", "ShopId", "OwnerId"); + + b.ToTable("character-shop-item-data", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.SkillTab", b => + { + b.Property("CharacterId") + .HasColumnType("bigint"); + + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("CreationTime") + .ValueGeneratedOnAdd() + .HasColumnType("datetime(6)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Skills") + .IsRequired() + .HasColumnType("json"); + + b.HasKey("CharacterId", "Id"); + + b.HasIndex("CharacterId"); + + b.ToTable("skill-tab", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.SoldMeretMarketItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CharacterId") + .HasColumnType("bigint"); + + b.Property("MarketId") + .HasColumnType("bigint"); + + b.Property("Price") + .HasColumnType("bigint"); + + b.Property("SoldTime") + .ValueGeneratedOnAdd() + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.ToTable("meret-market-sold", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.SoldMesoListing", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("Amount") + .HasColumnType("bigint"); + + b.Property("CharacterId") + .HasColumnType("bigint"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("datetime(6)"); + + b.Property("ListedTime") + .HasColumnType("datetime(6)"); + + b.Property("Price") + .HasColumnType("bigint"); + + b.Property("SoldTime") + .ValueGeneratedOnAdd() + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.ToTable("meso-market-sold", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.SoldUgcMarketItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Price") + .HasColumnType("bigint"); + + b.Property("Profit") + .HasColumnType("bigint"); + + b.Property("SoldTime") + .ValueGeneratedOnAdd() + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.ToTable("ugc-market-item-sold", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.SystemBanner", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("BeginTime") + .HasColumnType("datetime(6)"); + + b.Property("EndTime") + .HasColumnType("datetime(6)"); + + b.Property("Function") + .HasColumnType("int"); + + b.Property("FunctionParameter") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Language") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Type") + .HasColumnType("int"); + + b.Property("Url") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("system-banner", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.UgcMap", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("ApartmentNumber") + .HasColumnType("int"); + + b.Property("ExpiryTime") + .HasColumnType("datetime(6)"); + + b.Property("Indoor") + .HasColumnType("tinyint(1)"); + + b.Property("LastModified") + .IsConcurrencyToken() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("datetime(6)"); + + b.Property("MapId") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Number") + .HasColumnType("int"); + + b.Property("OwnerId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("MapId"); + + b.HasIndex("OwnerId"); + + b.ToTable("ugcmap", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.UgcMapCube", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("HousingCategory") + .HasColumnType("int"); + + b.Property("Interact") + .HasColumnType("json"); + + b.Property("ItemId") + .HasColumnType("int"); + + b.Property("Rotation") + .HasColumnType("float"); + + b.Property("Template") + .HasColumnType("json"); + + b.Property("UgcMapId") + .HasColumnType("bigint"); + + b.Property("X") + .HasColumnType("tinyint"); + + b.Property("Y") + .HasColumnType("tinyint"); + + b.Property("Z") + .HasColumnType("tinyint"); + + b.HasKey("Id"); + + b.HasIndex("UgcMapId"); + + b.ToTable("ugcmap-cube", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.UgcMarketItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("Blueprint") + .IsRequired() + .HasColumnType("json"); + + b.Property("CharacterId") + .HasColumnType("bigint"); + + b.Property("CharacterName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("CreationTime") + .ValueGeneratedOnAdd() + .HasColumnType("datetime(6)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ItemId") + .HasColumnType("int"); + + b.Property("ListingEndTime") + .HasColumnType("datetime(6)"); + + b.Property("Look") + .IsRequired() + .HasColumnType("json"); + + b.Property("Price") + .HasColumnType("bigint"); + + b.Property("PromotionEndTime") + .HasColumnType("datetime(6)"); + + b.Property("SalesCount") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("tinyint unsigned"); + + b.Property("TabId") + .HasColumnType("int"); + + b.Property("Tags") + .IsRequired() + .HasColumnType("json"); + + b.HasKey("Id"); + + b.ToTable("ugc-market-item", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.UgcResource", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("LastModified") + .IsConcurrencyToken() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("datetime(6)"); + + b.Property("OwnerId") + .HasColumnType("bigint"); + + b.Property("Path") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.HasKey("Id"); + + b.HasIndex("OwnerId"); + + b.ToTable("ugcresource", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.WeddingHall", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CeremonyTime") + .HasColumnType("datetime(6)"); + + b.Property("CreationTime") + .ValueGeneratedOnAdd() + .HasColumnType("datetime(6)"); + + b.Property("GuestList") + .IsRequired() + .HasColumnType("json"); + + b.Property("MarriageId") + .HasColumnType("bigint"); + + b.Property("OwnerId") + .HasColumnType("bigint"); + + b.Property("PackageHallId") + .HasColumnType("int"); + + b.Property("PackageId") + .HasColumnType("int"); + + b.Property("Public") + .HasColumnType("tinyint(1)"); + + b.HasKey("Id"); + + b.HasIndex("MarriageId") + .IsUnique(); + + b.ToTable("wedding-hall", (string)null); + }); + + modelBuilder.Entity("Maple2.Database.Model.Buddy", b => + { + b.HasOne("Maple2.Database.Model.Character", "BuddyCharacter") + .WithMany() + .HasForeignKey("BuddyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Maple2.Database.Model.Character", null) + .WithMany() + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("BuddyCharacter"); + }); + + modelBuilder.Entity("Maple2.Database.Model.Character", b => + { + b.HasOne("Maple2.Database.Model.Account", null) + .WithMany("Characters") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Maple2.Database.Model.CharacterConfig", b => + { + b.HasOne("Maple2.Database.Model.Character", null) + .WithOne() + .HasForeignKey("Maple2.Database.Model.CharacterConfig", "CharacterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.OwnsOne("Maple2.Database.Model.SkillBook", "SkillBook", b1 => + { + b1.Property("CharacterConfigCharacterId") + .HasColumnType("bigint"); + + b1.Property("ActiveSkillTabId") + .HasColumnType("bigint"); + + b1.Property("MaxSkillTabs") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(1); + + b1.HasKey("CharacterConfigCharacterId"); + + b1.HasIndex("ActiveSkillTabId") + .IsUnique(); + + b1.ToTable("character-config"); + + b1.HasOne("Maple2.Database.Model.SkillTab", null) + .WithOne() + .HasForeignKey("Maple2.Database.Model.CharacterConfig.SkillBook#Maple2.Database.Model.SkillBook", "ActiveSkillTabId") + .HasPrincipalKey("Maple2.Database.Model.SkillTab", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b1.WithOwner() + .HasForeignKey("CharacterConfigCharacterId"); + }); + + b.Navigation("SkillBook"); + }); + + modelBuilder.Entity("Maple2.Database.Model.CharacterUnlock", b => + { + b.HasOne("Maple2.Database.Model.Character", null) + .WithOne() + .HasForeignKey("Maple2.Database.Model.CharacterUnlock", "CharacterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Maple2.Database.Model.Club", b => + { + b.HasOne("Maple2.Database.Model.Character", null) + .WithMany() + .HasForeignKey("LeaderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Maple2.Database.Model.ClubMember", b => + { + b.HasOne("Maple2.Database.Model.Character", "Character") + .WithMany() + .HasForeignKey("CharacterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Maple2.Database.Model.Club", null) + .WithMany("Members") + .HasForeignKey("ClubId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Character"); + }); + + modelBuilder.Entity("Maple2.Database.Model.GameEventUserValue", b => + { + b.HasOne("Maple2.Database.Model.Character", null) + .WithMany() + .HasForeignKey("CharacterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Maple2.Database.Model.Guild", b => + { + b.HasOne("Maple2.Database.Model.Character", null) + .WithOne() + .HasForeignKey("Maple2.Database.Model.Guild", "LeaderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Maple2.Database.Model.GuildApplication", b => + { + b.HasOne("Maple2.Database.Model.Character", null) + .WithMany() + .HasForeignKey("ApplicantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Maple2.Database.Model.Guild", null) + .WithMany() + .HasForeignKey("GuildId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Maple2.Database.Model.GuildMember", b => + { + b.HasOne("Maple2.Database.Model.Character", "Character") + .WithOne() + .HasForeignKey("Maple2.Database.Model.GuildMember", "CharacterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Maple2.Database.Model.Guild", null) + .WithMany("Members") + .HasForeignKey("GuildId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Character"); + }); + + modelBuilder.Entity("Maple2.Database.Model.Home", b => + { + b.HasOne("Maple2.Database.Model.Account", null) + .WithOne() + .HasForeignKey("Maple2.Database.Model.Home", "AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Maple2.Database.Model.HomeLayoutCube", b => + { + b.HasOne("Maple2.Database.Model.HomeLayout", null) + .WithMany("Cubes") + .HasForeignKey("HomeLayoutId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Maple2.Database.Model.ItemStorage", b => + { + b.HasOne("Maple2.Database.Model.Account", null) + .WithOne() + .HasForeignKey("Maple2.Database.Model.ItemStorage", "AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Maple2.Database.Model.Marriage", b => + { + b.HasOne("Maple2.Database.Model.Character", null) + .WithMany() + .HasForeignKey("Partner1Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Maple2.Database.Model.Character", null) + .WithMany() + .HasForeignKey("Partner2Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Maple2.Database.Model.MesoListing", b => + { + b.HasOne("Maple2.Database.Model.Account", null) + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Maple2.Database.Model.Character", null) + .WithMany() + .HasForeignKey("CharacterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Maple2.Database.Model.PetConfig", b => + { + b.HasOne("Maple2.Database.Model.Item", null) + .WithOne() + .HasForeignKey("Maple2.Database.Model.PetConfig", "ItemUid") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Maple2.Database.Model.SkillTab", b => + { + b.HasOne("Maple2.Database.Model.Character", null) + .WithMany() + .HasForeignKey("CharacterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Maple2.Database.Model.SoldUgcMarketItem", b => + { + b.HasOne("Maple2.Database.Model.Account", null) + .WithMany() + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Maple2.Database.Model.UgcMapCube", b => + { + b.HasOne("Maple2.Database.Model.UgcMap", null) + .WithMany("Cubes") + .HasForeignKey("UgcMapId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Maple2.Database.Model.WeddingHall", b => + { + b.HasOne("Maple2.Database.Model.Marriage", null) + .WithOne() + .HasForeignKey("Maple2.Database.Model.WeddingHall", "MarriageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Maple2.Database.Model.Account", b => + { + b.Navigation("Characters"); + }); + + modelBuilder.Entity("Maple2.Database.Model.Club", b => + { + b.Navigation("Members"); + }); + + modelBuilder.Entity("Maple2.Database.Model.Guild", b => + { + b.Navigation("Members"); + }); + + modelBuilder.Entity("Maple2.Database.Model.HomeLayout", b => + { + b.Navigation("Cubes"); + }); + + modelBuilder.Entity("Maple2.Database.Model.UgcMap", b => + { + b.Navigation("Cubes"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Maple2.Server.World/Migrations/20250219083923_ReworkInteractCube.cs b/Maple2.Server.World/Migrations/20250219083923_ReworkInteractCube.cs new file mode 100644 index 000000000..eb85d2fe2 --- /dev/null +++ b/Maple2.Server.World/Migrations/20250219083923_ReworkInteractCube.cs @@ -0,0 +1,40 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Maple2.Server.World.Migrations +{ + /// + public partial class ReworkInteractCube : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "CubePortalSettings", + table: "ugcmap-cube"); + + migrationBuilder.DropColumn( + name: "CubePortalSettings", + table: "home-layout-cube"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "CubePortalSettings", + table: "ugcmap-cube", + type: "json", + nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AddColumn( + name: "CubePortalSettings", + table: "home-layout-cube", + type: "json", + nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"); + } + } +} diff --git a/Maple2.Server.World/Migrations/Ms2ContextModelSnapshot.cs b/Maple2.Server.World/Migrations/Ms2ContextModelSnapshot.cs index 14212658f..2b04827f7 100644 --- a/Maple2.Server.World/Migrations/Ms2ContextModelSnapshot.cs +++ b/Maple2.Server.World/Migrations/Ms2ContextModelSnapshot.cs @@ -763,9 +763,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) .ValueGeneratedOnAdd() .HasColumnType("bigint"); - b.Property("CubePortalSettings") - .HasColumnType("json"); - b.Property("HomeLayoutId") .HasColumnType("bigint"); @@ -1400,9 +1397,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) .ValueGeneratedOnAdd() .HasColumnType("bigint"); - b.Property("CubePortalSettings") - .HasColumnType("json"); - b.Property("HousingCategory") .HasColumnType("int");