From a0f52ab4b5ab754f08f6e7e37eb9f72e63be9d0a Mon Sep 17 00:00:00 2001 From: sven-n Date: Wed, 20 Mar 2024 18:40:25 +0100 Subject: [PATCH 01/29] Object references in custom plugin configurations --- src/ChatServer/ExDbConnector/Program.cs | 2 +- src/Network/Analyzer/MainForm.cs | 2 +- .../ByDataSourceReferenceHandler.cs | 34 ++++++++++++ .../ByDataSourceReferenceResolver.cs | 54 +++++++++++++++++++ .../Initialization/DataInitializationBase.cs | 15 +++--- src/PlugIns/PlugInConfigurationExtensions.cs | 34 +++++++++--- src/PlugIns/PlugInContainerBase.cs | 2 +- src/PlugIns/PlugInManager.cs | 10 +++- src/Startup/Program.cs | 36 ++++++++++--- .../EmbeddedFormFieldBuilder.cs | 5 +- .../Form/MemberOfAggregateField.razor | 4 +- .../PersistentObjectsLookupController.cs | 3 +- .../AdminPanel/Services/PlugInController.cs | 10 ++-- .../CustomPlugInContainerTest.cs | 16 +++--- .../PlugInManagerTest.cs | 42 +++++++-------- .../PlugInProxyTypeGeneratorTest.cs | 16 +++--- tests/MUnique.OpenMU.Tests/GuildActionTest.cs | 2 +- .../PacketHandlerPlugInContainerTest.cs | 12 ++--- tests/MUnique.OpenMU.Tests/PartyTest.cs | 2 +- tests/MUnique.OpenMU.Tests/TestHelper.cs | 2 +- tests/MUnique.OpenMU.Tests/TradeTest.cs | 2 +- .../ViewPlugInContainerTest.cs | 12 ++--- 22 files changed, 230 insertions(+), 87 deletions(-) create mode 100644 src/Persistence/ByDataSourceReferenceHandler.cs create mode 100644 src/Persistence/ByDataSourceReferenceResolver.cs diff --git a/src/ChatServer/ExDbConnector/Program.cs b/src/ChatServer/ExDbConnector/Program.cs index bf9c2e6fe..8853e88d7 100644 --- a/src/ChatServer/ExDbConnector/Program.cs +++ b/src/ChatServer/ExDbConnector/Program.cs @@ -56,7 +56,7 @@ internal static async Task Main(string[] args) // To make the chat server use our configured encryption key, we need to trick a bit. We add an endpoint with a special client version which is defined in the plugin. var configuration = new ChatServerSettings(); configuration.Endpoints.Add(new ChatServerEndpoint { ClientVersion = ConfigurableNetworkEncryptionPlugIn.Version, NetworkPort = chatServerListenerPort }); - var pluginManager = new PlugInManager(null, loggerFactory, serviceContainer); + var pluginManager = new PlugInManager(null, loggerFactory, serviceContainer, null); pluginManager.DiscoverAndRegisterPlugInsOf(); var chatServer = new ChatServer(addressResolver, loggerFactory, pluginManager); chatServer.Initialize(configuration); diff --git a/src/Network/Analyzer/MainForm.cs b/src/Network/Analyzer/MainForm.cs index 1d135fe01..e933f2dda 100644 --- a/src/Network/Analyzer/MainForm.cs +++ b/src/Network/Analyzer/MainForm.cs @@ -49,7 +49,7 @@ public MainForm() this.InitializeComponent(); var serviceContainer = new ServiceContainer(); serviceContainer.AddService(typeof(ILoggerFactory), new NullLoggerFactory()); - this._plugInManager = new PlugInManager(null, new NullLoggerFactory(), serviceContainer); + this._plugInManager = new PlugInManager(null, new NullLoggerFactory(), serviceContainer, null); this._plugInManager.DiscoverAndRegisterPlugIns(); this.clientBindingSource.DataSource = this._proxiedConnections; this.connectedClientsListBox.DisplayMember = nameof(ICapturedConnection.Name); diff --git a/src/Persistence/ByDataSourceReferenceHandler.cs b/src/Persistence/ByDataSourceReferenceHandler.cs new file mode 100644 index 000000000..42c7d70e3 --- /dev/null +++ b/src/Persistence/ByDataSourceReferenceHandler.cs @@ -0,0 +1,34 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace MUnique.OpenMU.Persistence; + +using System.Text.Json.Serialization; +using MUnique.OpenMU.DataModel.Configuration; + +/// +/// A reference handler which uses a to resolve references. +/// +public class ByDataSourceReferenceHandler : ReferenceHandler +{ + /// + /// The data source. + /// + private IDataSource _dataSource; + + /// + /// Initializes a new instance of the class. + /// + /// The data source. + public ByDataSourceReferenceHandler(IDataSource dataSource) + { + this._dataSource = dataSource; + } + + /// + public override ReferenceResolver CreateResolver() + { + return new ByDataSourceReferenceResolver(this._dataSource); + } +} \ No newline at end of file diff --git a/src/Persistence/ByDataSourceReferenceResolver.cs b/src/Persistence/ByDataSourceReferenceResolver.cs new file mode 100644 index 000000000..0e8a2b725 --- /dev/null +++ b/src/Persistence/ByDataSourceReferenceResolver.cs @@ -0,0 +1,54 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace MUnique.OpenMU.Persistence; + +using System.Text.Json.Serialization; +using MUnique.OpenMU.DataModel.Configuration; + +/// +/// A reference resolver which uses a to resolve references. +/// +public class ByDataSourceReferenceResolver : ReferenceResolver +{ + /// + /// The data source. + /// + private readonly IDataSource _dataSource; + + /// + /// Initializes a new instance of the class. + /// + /// The data source. + public ByDataSourceReferenceResolver(IDataSource dataSource) + { + this._dataSource = dataSource; + } + + /// + public override void AddReference(string referenceId, object value) + { + //throw new NotImplementedException(); + } + + /// + public override string GetReference(object value, out bool alreadyExists) + { + if (value is IIdentifiable identifiable) + { + alreadyExists = this._dataSource.Get(identifiable.Id) is { }; + return identifiable.Id.ToString(); + } + + alreadyExists = false; + return string.Empty; + } + + /// + public override object ResolveReference(string referenceId) + { + var id = Guid.Parse(referenceId); + return this._dataSource.Get(id) ?? throw new KeyNotFoundException($"Reference with id '{referenceId}' not found."); + } +} \ No newline at end of file diff --git a/src/Persistence/Initialization/DataInitializationBase.cs b/src/Persistence/Initialization/DataInitializationBase.cs index c7b229824..f29fe2390 100644 --- a/src/Persistence/Initialization/DataInitializationBase.cs +++ b/src/Persistence/Initialization/DataInitializationBase.cs @@ -120,9 +120,10 @@ public async Task CreateInitialDataAsync(byte numberOfGameServers, bool createTe // should never happen, but the access to the GameServer type is a trick to load the assembly into the current domain. } + var referenceHandler = new ByDataSourceReferenceHandler(new GameConfigurationDataSource(this._loggerFactory.CreateLogger(), this._persistenceContextProvider)); var serviceContainer = new ServiceContainer(); serviceContainer.AddService(typeof(IPersistenceContextProvider), this._persistenceContextProvider); - var plugInManager = new PlugInManager(null, this._loggerFactory, serviceContainer); + var plugInManager = new PlugInManager(null, this._loggerFactory, serviceContainer, referenceHandler); plugInManager.DiscoverAndRegisterPlugIns(); plugInManager.KnownPlugInTypes.ForEach(plugInType => { @@ -136,32 +137,32 @@ public async Task CreateInitialDataAsync(byte numberOfGameServers, bool createTe if (plugInType == typeof(ResetFeaturePlugIn)) { plugInConfiguration.IsActive = false; - plugInConfiguration.SetConfiguration(new ResetConfiguration()); + plugInConfiguration.SetConfiguration(new ResetConfiguration(), referenceHandler); } if (plugInType == typeof(ChaosCastleStartPlugIn)) { - plugInConfiguration.SetConfiguration(ChaosCastleStartConfiguration.Default); + plugInConfiguration.SetConfiguration(ChaosCastleStartConfiguration.Default, referenceHandler); } if (plugInType == typeof(GoldenInvasionPlugIn)) { - plugInConfiguration.SetConfiguration(PeriodicInvasionConfiguration.DefaultGoldenInvasion); + plugInConfiguration.SetConfiguration(PeriodicInvasionConfiguration.DefaultGoldenInvasion, referenceHandler); } if (plugInType == typeof(RedDragonInvasionPlugIn)) { - plugInConfiguration.SetConfiguration(PeriodicInvasionConfiguration.DefaultRedDragonInvasion); + plugInConfiguration.SetConfiguration(PeriodicInvasionConfiguration.DefaultRedDragonInvasion, referenceHandler); } if (plugInType == typeof(HappyHourPlugIn)) { - plugInConfiguration.SetConfiguration(HappyHourConfiguration.Default); + plugInConfiguration.SetConfiguration(HappyHourConfiguration.Default, referenceHandler); } if (plugInType == typeof(MuHelperFeaturePlugIn)) { - plugInConfiguration.SetConfiguration(new MuHelperConfiguration()); + plugInConfiguration.SetConfiguration(new MuHelperConfiguration(), referenceHandler); } // We don't move the player anymore by his request. This was usually requested after a player performed a skill. diff --git a/src/PlugIns/PlugInConfigurationExtensions.cs b/src/PlugIns/PlugInConfigurationExtensions.cs index 14220bdbf..0c7596829 100644 --- a/src/PlugIns/PlugInConfigurationExtensions.cs +++ b/src/PlugIns/PlugInConfigurationExtensions.cs @@ -5,6 +5,7 @@ namespace MUnique.OpenMU.PlugIns; using System.Text.Json; +using System.Text.Json.Serialization; /// /// Extension methods for the plugin configuration. @@ -16,10 +17,11 @@ public static class PlugInConfigurationExtensions /// /// The custom configuration type. /// The configuration. + /// The reference handler. /// /// The custom configuration as . /// - public static T? GetConfiguration(this PlugInConfiguration configuration) + public static T? GetConfiguration(this PlugInConfiguration configuration, ReferenceHandler? referenceHandler) where T : class { if (string.IsNullOrWhiteSpace(configuration.CustomConfiguration)) @@ -27,7 +29,12 @@ public static class PlugInConfigurationExtensions return default; } - return JsonSerializer.Deserialize(configuration.CustomConfiguration); + var options = new JsonSerializerOptions + { + ReferenceHandler = referenceHandler, + }; + + return JsonSerializer.Deserialize(configuration.CustomConfiguration, options); } /// @@ -35,17 +42,23 @@ public static class PlugInConfigurationExtensions /// /// The configuration. /// Type of the configuration. + /// The reference handler. /// /// The custom configuration as the given specified type. /// - public static object? GetConfiguration(this PlugInConfiguration configuration, Type configurationType) + public static object? GetConfiguration(this PlugInConfiguration configuration, Type configurationType, ReferenceHandler? referenceHandler) { if (string.IsNullOrWhiteSpace(configuration.CustomConfiguration)) { return default; } - return JsonSerializer.Deserialize(configuration.CustomConfiguration, configurationType); + var options = new JsonSerializerOptions + { + ReferenceHandler = referenceHandler, + }; + + return JsonSerializer.Deserialize(configuration.CustomConfiguration, configurationType, options); } /// @@ -54,9 +67,10 @@ public static class PlugInConfigurationExtensions /// The custom configuration type. /// The plug in configuration. /// The configuration. - public static void SetConfiguration(this PlugInConfiguration plugInConfiguration, T configuration) + /// The reference handler. + public static void SetConfiguration(this PlugInConfiguration plugInConfiguration, T configuration, ReferenceHandler? referenceHandler) { - plugInConfiguration.CustomConfiguration = JsonSerializer.Serialize(configuration, new JsonSerializerOptions { WriteIndented = true }); + plugInConfiguration.CustomConfiguration = JsonSerializer.Serialize(configuration, new JsonSerializerOptions { WriteIndented = true, ReferenceHandler = referenceHandler }); } /// @@ -64,8 +78,12 @@ public static void SetConfiguration(this PlugInConfiguration plugInConfigurat /// /// The plug in configuration. /// The configuration. - public static void SetConfiguration(this PlugInConfiguration plugInConfiguration, object configuration) + /// The reference handler. + public static void SetConfiguration(this PlugInConfiguration plugInConfiguration, object configuration, ReferenceHandler? referenceHandler) { - plugInConfiguration.CustomConfiguration = JsonSerializer.Serialize(configuration, configuration.GetType(), new JsonSerializerOptions { WriteIndented = true }); + plugInConfiguration.CustomConfiguration = JsonSerializer.Serialize( + configuration, + configuration.GetType(), + new JsonSerializerOptions { WriteIndented = true, ReferenceHandler = referenceHandler }); } } \ No newline at end of file diff --git a/src/PlugIns/PlugInContainerBase.cs b/src/PlugIns/PlugInContainerBase.cs index 78e9c20e4..bd7b40975 100644 --- a/src/PlugIns/PlugInContainerBase.cs +++ b/src/PlugIns/PlugInContainerBase.cs @@ -207,7 +207,7 @@ private void OnPlugInConfigurationChanged(object? sender, PlugInConfigurationCha is { } configSupportInterface) { var configType = configSupportInterface.GenericTypeArguments[0]; - var typedCustomConfiguration = e.Configuration.GetConfiguration(configType); + var typedCustomConfiguration = e.Configuration.GetConfiguration(configType, this.Manager.CustomConfigReferenceHandler); configSupportInterface .GetProperty(nameof(ISupportCustomConfiguration.Configuration)) ?.SetMethod diff --git a/src/PlugIns/PlugInManager.cs b/src/PlugIns/PlugInManager.cs index 7fd470c2c..8ab52519a 100644 --- a/src/PlugIns/PlugInManager.cs +++ b/src/PlugIns/PlugInManager.cs @@ -8,6 +8,7 @@ namespace MUnique.OpenMU.PlugIns; using System.ComponentModel.Design; using System.Reflection; using System.Runtime.InteropServices; +using System.Text.Json.Serialization; using Microsoft.CodeAnalysis.CSharp; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -32,7 +33,7 @@ public class PlugInManager /// The configurations. /// The logger factory. /// The service provider. - public PlugInManager(ICollection? configurations, ILoggerFactory loggerFactory, IServiceProvider? serviceProvider) + public PlugInManager(ICollection? configurations, ILoggerFactory loggerFactory, IServiceProvider? serviceProvider, ReferenceHandler? customConfigReferenceHandler) { _ = typeof(Nito.AsyncEx.AsyncReaderWriterLock); // Ensure Nito.AsyncEx.Coordination is loaded so it will be available in proxy generation. @@ -41,6 +42,8 @@ public PlugInManager(ICollection? configurations, ILoggerFa this._serviceContainer.AddService(typeof(PlugInManager), this); this._serviceContainer.AddService(typeof(ILoggerFactory), loggerFactory); + this.CustomConfigReferenceHandler = customConfigReferenceHandler; + if (configurations is not null) { this.DiscoverAndRegisterPlugIns(); @@ -75,6 +78,11 @@ public PlugInManager(ICollection? configurations, ILoggerFa /// public IEnumerable KnownPlugInTypes => this._knownPlugIns.Values; + /// + /// Gets the reference handler for references in custom plugin configurations. + /// + public ReferenceHandler? CustomConfigReferenceHandler { get; } + /// /// Discovers and registers all plug ins of all loaded assemblies. /// diff --git a/src/Startup/Program.cs b/src/Startup/Program.cs index 3f2a63d75..ee3447bae 100644 --- a/src/Startup/Program.cs +++ b/src/Startup/Program.cs @@ -4,9 +4,11 @@ namespace MUnique.OpenMU.Startup; +using System; using System.ComponentModel.Design; using System.Diagnostics; using System.IO; +using System.Text.Json.Serialization; using System.Threading; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Configuration; @@ -266,6 +268,18 @@ private async Task CreateHostAsync(string[] args) .AddSingleton() .AddSingleton() .AddSingleton>(this.PlugInConfigurationsFactory) + .AddTransient(provider => + { + var persistenceContextProvider = provider.GetService(); + var dataSource = new GameConfigurationDataSource( + provider.GetService>()!, + persistenceContextProvider!); + var configId = persistenceContextProvider!.CreateNewConfigurationContext().GetDefaultGameConfigurationIdAsync(default).GetAwaiter().GetResult(); + dataSource.GetOwnerAsync(configId!.Value).GetAwaiter().GetResult(); + var referenceHandler = new ByDataSourceReferenceHandler(dataSource); + return referenceHandler; + }) + .AddTransient, GameConfigurationDataSource>() .AddHostedService() .AddHostedService() .AddHostedService(provider => provider.GetService()!) @@ -310,8 +324,11 @@ private ICollection PlugInConfigurationsFactory(IServicePro var configs = context.GetAsync().AsTask().WaitAndUnwrapException().ToList(); + var referenceHandler = new ByDataSourceReferenceHandler( + new GameConfigurationDataSource(serviceProvider.GetService>()!, persistenceContextProvider)); + // We check if we miss any plugin configurations in the database. If we do, we try to add them. - var pluginManager = new PlugInManager(null, serviceProvider.GetService()!, serviceProvider); + var pluginManager = new PlugInManager(null, serviceProvider.GetService()!, serviceProvider, referenceHandler); pluginManager.DiscoverAndRegisterPlugIns(); var typesWithCustomConfig = pluginManager.KnownPlugInTypes.Where(t => t.GetInterfaces().Contains(typeof(ISupportDefaultCustomConfiguration))).ToDictionary(t => t.GUID, t => t); @@ -319,7 +336,7 @@ private ICollection PlugInConfigurationsFactory(IServicePro var typesWithMissingCustomConfigs = configs.Where(c => string.IsNullOrWhiteSpace(c.CustomConfiguration) && typesWithCustomConfig.ContainsKey(c.TypeId)).ToList(); if (typesWithMissingCustomConfigs.Any()) { - typesWithMissingCustomConfigs.ForEach(c => this.CreateDefaultPlugInConfiguration(typesWithCustomConfig[c.TypeId]!, c)); + typesWithMissingCustomConfigs.ForEach(c => this.CreateDefaultPlugInConfiguration(typesWithCustomConfig[c.TypeId]!, c, referenceHandler)); context.SaveChanges(); } @@ -329,11 +346,11 @@ private ICollection PlugInConfigurationsFactory(IServicePro return configs; } - configs.AddRange(this.CreateMissingPlugInConfigurations(typesWithMissingConfigs, persistenceContextProvider)); + configs.AddRange(this.CreateMissingPlugInConfigurations(typesWithMissingConfigs, persistenceContextProvider, referenceHandler)); return configs; } - private IEnumerable CreateMissingPlugInConfigurations(IEnumerable plugInTypes, IPersistenceContextProvider persistenceContextProvider) + private IEnumerable CreateMissingPlugInConfigurations(IEnumerable plugInTypes, IPersistenceContextProvider persistenceContextProvider, ReferenceHandler referenceHandler) { GameConfiguration gameConfiguration; @@ -352,7 +369,7 @@ private IEnumerable CreateMissingPlugInConfigurations(IEnum gameConfiguration.PlugInConfigurations.Add(plugInConfiguration); if (plugInType.GetInterfaces().Contains(typeof(ISupportDefaultCustomConfiguration))) { - this.CreateDefaultPlugInConfiguration(plugInType, plugInConfiguration); + this.CreateDefaultPlugInConfiguration(plugInType, plugInConfiguration, referenceHandler); } yield return plugInConfiguration; @@ -361,13 +378,13 @@ private IEnumerable CreateMissingPlugInConfigurations(IEnum saveContext.SaveChanges(); } - private void CreateDefaultPlugInConfiguration(Type plugInType, PlugInConfiguration plugInConfiguration) + private void CreateDefaultPlugInConfiguration(Type plugInType, PlugInConfiguration plugInConfiguration, ReferenceHandler referenceHandler) { try { var plugin = (ISupportDefaultCustomConfiguration)Activator.CreateInstance(plugInType)!; var defaultConfig = plugin.CreateDefaultConfig(); - plugInConfiguration.SetConfiguration(defaultConfig); + plugInConfiguration.SetConfiguration(defaultConfig, referenceHandler); } catch (Exception ex) { @@ -490,7 +507,10 @@ private async Task InitializeDataAsync(string version, ILoggerFactory loggerFact serviceContainer.AddService(typeof(ILoggerFactory), loggerFactory); serviceContainer.AddService(typeof(IPersistenceContextProvider), contextProvider); - var plugInManager = new PlugInManager(null, loggerFactory, serviceContainer); + var referenceHandler = new ByDataSourceReferenceHandler( + new GameConfigurationDataSource(serviceContainer.GetService>()!, contextProvider)); + + var plugInManager = new PlugInManager(null, loggerFactory, serviceContainer, referenceHandler); plugInManager.DiscoverAndRegisterPlugInsOf(); var initialization = plugInManager.GetStrategy(version) ?? throw new Exception("Data initialization plugin not found"); await initialization.CreateInitialDataAsync(3, true).ConfigureAwait(false); diff --git a/src/Web/AdminPanel/ComponentBuilders/EmbeddedFormFieldBuilder.cs b/src/Web/AdminPanel/ComponentBuilders/EmbeddedFormFieldBuilder.cs index 9070f72f9..90ade473e 100644 --- a/src/Web/AdminPanel/ComponentBuilders/EmbeddedFormFieldBuilder.cs +++ b/src/Web/AdminPanel/ComponentBuilders/EmbeddedFormFieldBuilder.cs @@ -16,7 +16,10 @@ namespace MUnique.OpenMU.Web.AdminPanel.ComponentBuilders; public class EmbeddedFormFieldBuilder : BaseComponentBuilder, IComponentBuilder { /// - public int BuildComponent(object model, PropertyInfo propertyInfo, RenderTreeBuilder builder, int currentIndex, IChangeNotificationService notificationService) => this.BuildGenericField(model, typeof(MemberOfAggregateField<>), builder, propertyInfo, currentIndex, notificationService); + public int BuildComponent(object model, PropertyInfo propertyInfo, RenderTreeBuilder builder, int currentIndex, IChangeNotificationService notificationService) + { + return this.BuildGenericField(model, typeof(MemberOfAggregateField<>), builder, propertyInfo, currentIndex, notificationService); + } /// public bool CanBuildComponent(PropertyInfo propertyInfo) => diff --git a/src/Web/AdminPanel/Components/Form/MemberOfAggregateField.razor b/src/Web/AdminPanel/Components/Form/MemberOfAggregateField.razor index cba84bb91..9c0dd54c4 100644 --- a/src/Web/AdminPanel/Components/Form/MemberOfAggregateField.razor +++ b/src/Web/AdminPanel/Components/Form/MemberOfAggregateField.razor @@ -9,7 +9,7 @@
- @if (this.Value is null) + @if (this.CurrentValue is null) { } @@ -46,6 +46,6 @@ private void OnCreateClick() { - this.Value = this.PersistentContext.CreateNew(); + this.CurrentValue = this.PersistentContext.CreateNew(); } } diff --git a/src/Web/AdminPanel/Services/PersistentObjectsLookupController.cs b/src/Web/AdminPanel/Services/PersistentObjectsLookupController.cs index 89e24016c..17995c4aa 100644 --- a/src/Web/AdminPanel/Services/PersistentObjectsLookupController.cs +++ b/src/Web/AdminPanel/Services/PersistentObjectsLookupController.cs @@ -47,6 +47,7 @@ public async Task> GetSuggestionsAsync(string? text, IContext? return Enumerable.Empty(); } + var owner = await this._gameConfigurationSource.GetOwnerAsync(); IEnumerable values; if (this._gameConfigurationSource.IsSupporting(typeof(T))) { @@ -55,7 +56,7 @@ public async Task> GetSuggestionsAsync(string? text, IContext? else { using var context = persistenceContext is null - ? this._contextProvider.CreateNewContext(await this._gameConfigurationSource.GetOwnerAsync(Guid.Empty)) + ? this._contextProvider.CreateNewContext(owner) : null; var effectiveContext = persistenceContext ?? context; if (effectiveContext is null) diff --git a/src/Web/AdminPanel/Services/PlugInController.cs b/src/Web/AdminPanel/Services/PlugInController.cs index 8999ca9da..6d63207d0 100644 --- a/src/Web/AdminPanel/Services/PlugInController.cs +++ b/src/Web/AdminPanel/Services/PlugInController.cs @@ -7,10 +7,10 @@ namespace MUnique.OpenMU.Web.AdminPanel.Services; using System.Reflection; using Blazored.Modal; using Blazored.Modal.Services; -using MUnique.OpenMU.Web.AdminPanel.Components.Form; using MUnique.OpenMU.DataModel.Configuration; using MUnique.OpenMU.Persistence; using MUnique.OpenMU.PlugIns; +using MUnique.OpenMU.Web.AdminPanel.Components.Form; using MUnique.OpenMU.Web.AdminPanel.Models; /// @@ -173,10 +173,13 @@ public async Task ShowPlugInConfigAsync(PlugInConfigurationViewItem item) throw new ArgumentException($"{nameof(item.ConfigurationType)} must not be null.", nameof(item)); } - var configuration = item.Configuration.GetConfiguration(item.ConfigurationType) + var referenceResolver = new ByDataSourceReferenceHandler(this._dataSource); + + var configuration = item.Configuration.GetConfiguration(item.ConfigurationType, referenceResolver) ?? Activator.CreateInstance(item.ConfigurationType); var parameters = new ModalParameters(); parameters.Add(nameof(ModalCreateNew.Item), configuration!); + parameters.Add(nameof(ModalCreateNew.PersistenceContext), await this._dataSource.GetContextAsync()); var options = new ModalOptions { DisableBackgroundCancel = true, @@ -187,10 +190,11 @@ public async Task ShowPlugInConfigAsync(PlugInConfigurationViewItem item) item.PlugInName ?? string.Empty, parameters, options); + var result = await modal.Result.ConfigureAwait(false); if (!result.Cancelled) { - item.Configuration.SetConfiguration(configuration!); + item.Configuration.SetConfiguration(configuration!, referenceResolver); await (await this._dataSource.GetContextAsync().ConfigureAwait(false)).SaveChangesAsync().ConfigureAwait(false); this.DataChanged?.Invoke(this, EventArgs.Empty); } diff --git a/tests/MUnique.OpenMU.PlugIns.Tests/CustomPlugInContainerTest.cs b/tests/MUnique.OpenMU.PlugIns.Tests/CustomPlugInContainerTest.cs index ab44160f7..029fb4850 100644 --- a/tests/MUnique.OpenMU.PlugIns.Tests/CustomPlugInContainerTest.cs +++ b/tests/MUnique.OpenMU.PlugIns.Tests/CustomPlugInContainerTest.cs @@ -20,7 +20,7 @@ public class CustomPlugInContainerTest [Test] public void CreatingContainerWithNonMarkedTypeThrowsException() { - var manager = new PlugInManager(null, new NullLoggerFactory(), null); + var manager = new PlugInManager(null, new NullLoggerFactory(), null, null); var mock = new Mock>(manager); var exception = Assert.Throws(() => { @@ -36,7 +36,7 @@ public void CreatingContainerWithNonMarkedTypeThrowsException() [Test] public void GetPlugInFromCustomContainerWithRegisteredPlugInAfterRegistration() { - var manager = new PlugInManager(null, new NullLoggerFactory(), null); + var manager = new PlugInManager(null, new NullLoggerFactory(), null, null); var container = new CustomTestPlugInContainer(manager); manager.RegisterPlugIn(); @@ -50,7 +50,7 @@ public void GetPlugInFromCustomContainerWithRegisteredPlugInAfterRegistration() [Test] public void GetPlugInFromCustomContainerWithInitiallyRegisteredPlugIn() { - var manager = new PlugInManager(null, new NullLoggerFactory(), null); + var manager = new PlugInManager(null, new NullLoggerFactory(), null, null); manager.RegisterPlugIn(); var container = new CustomTestPlugInContainer(manager); var plugIn = container.GetPlugIn(); @@ -63,7 +63,7 @@ public void GetPlugInFromCustomContainerWithInitiallyRegisteredPlugIn() [Test] public void DontGetPlugInFromCustomContainerAfterDeactivation() { - var manager = new PlugInManager(null, new NullLoggerFactory(), null); + var manager = new PlugInManager(null, new NullLoggerFactory(), null, null); manager.RegisterPlugIn(); var container = new CustomTestPlugInContainer(manager); manager.DeactivatePlugIn(); @@ -77,7 +77,7 @@ public void DontGetPlugInFromCustomContainerAfterDeactivation() [Test] public void DontGetPlugInFromCustomContainerIfItDoesntSuit() { - var manager = new PlugInManager(null, new NullLoggerFactory(), null); + var manager = new PlugInManager(null, new NullLoggerFactory(), null, null); var container = new CustomTestPlugInContainer(manager) { CreateNewPlugIns = false }; manager.RegisterPlugIn(); var plugIn = container.GetPlugIn(); @@ -90,7 +90,7 @@ public void DontGetPlugInFromCustomContainerIfItDoesntSuit() [Test] public void ReplacePlugInAtCustomContainer() { - var manager = new PlugInManager(null, new NullLoggerFactory(), null); + var manager = new PlugInManager(null, new NullLoggerFactory(), null, null); manager.RegisterPlugIn(); var container = new CustomTestPlugInContainer(manager); manager.RegisterPlugIn(); @@ -104,7 +104,7 @@ public void ReplacePlugInAtCustomContainer() [Test] public void ReactivatePlugInAtCustomContainer() { - var manager = new PlugInManager(null, new NullLoggerFactory(), null); + var manager = new PlugInManager(null, new NullLoggerFactory(), null, null); manager.RegisterPlugIn(); var container = new CustomTestPlugInContainer(manager); manager.RegisterPlugIn(); @@ -119,7 +119,7 @@ public void ReactivatePlugInAtCustomContainer() [Test] public void GetPlugInFromCustomContainerWithAllImplementedInterfaces() { - var manager = new PlugInManager(null, new NullLoggerFactory(), null); + var manager = new PlugInManager(null, new NullLoggerFactory(), null, null); var container = new CustomTestPlugInContainer(manager); container.AddPlugIn(new TestCustomPlugIn2(), true); Assert.That(container.GetPlugIn(), Is.Not.Null); diff --git a/tests/MUnique.OpenMU.PlugIns.Tests/PlugInManagerTest.cs b/tests/MUnique.OpenMU.PlugIns.Tests/PlugInManagerTest.cs index 68242b459..f736586aa 100644 --- a/tests/MUnique.OpenMU.PlugIns.Tests/PlugInManagerTest.cs +++ b/tests/MUnique.OpenMU.PlugIns.Tests/PlugInManagerTest.cs @@ -21,7 +21,7 @@ public class PlugInManagerTest [Test] public void RegisteringPlugInCreatesProxy() { - var manager = new PlugInManager(null, new NullLoggerFactory(), this.CreateServiceProvider()); + var manager = new PlugInManager(null, new NullLoggerFactory(), this.CreateServiceProvider(), null); manager.RegisterPlugIn(); var point = manager.GetPlugInPoint(); @@ -35,7 +35,7 @@ public void RegisteringPlugInCreatesProxy() [Test] public async ValueTask RegisteredPlugInsActiveByDefaultAsync() { - var manager = new PlugInManager(null, new NullLoggerFactory(), this.CreateServiceProvider()); + var manager = new PlugInManager(null, new NullLoggerFactory(), this.CreateServiceProvider(), null); var plugIn = new ExamplePlugIn(); manager.RegisterPlugInAtPlugInPoint(plugIn); @@ -54,7 +54,7 @@ public async ValueTask RegisteredPlugInsActiveByDefaultAsync() [Test] public async ValueTask DeactivatingPlugInsAsync() { - var manager = new PlugInManager(null, new NullLoggerFactory(), this.CreateServiceProvider()); + var manager = new PlugInManager(null, new NullLoggerFactory(), this.CreateServiceProvider(), null); var plugIn = new ExamplePlugIn(); manager.RegisterPlugInAtPlugInPoint(plugIn); manager.DeactivatePlugIn(); @@ -74,7 +74,7 @@ public async ValueTask DeactivatingPlugInsAsync() [Test] public async ValueTask DeactivatingDeactivatedPlugInAsync() { - var manager = new PlugInManager(null, new NullLoggerFactory(), this.CreateServiceProvider()); + var manager = new PlugInManager(null, new NullLoggerFactory(), this.CreateServiceProvider(), null); var plugIn = new ExamplePlugIn(); manager.RegisterPlugInAtPlugInPoint(plugIn); manager.DeactivatePlugIn(); @@ -95,7 +95,7 @@ public async ValueTask DeactivatingDeactivatedPlugInAsync() [Test] public async ValueTask ActivatingActivatedPlugInAsync() { - var manager = new PlugInManager(null, new NullLoggerFactory(), this.CreateServiceProvider()); + var manager = new PlugInManager(null, new NullLoggerFactory(), this.CreateServiceProvider(), null); var plugIn = new ExamplePlugIn(); manager.RegisterPlugInAtPlugInPoint(plugIn); manager.ActivatePlugIn(); @@ -116,7 +116,7 @@ public async ValueTask ActivatingActivatedPlugInAsync() [Test] public async ValueTask DeactivatingOnePlugInDoesntAffectOthersAsync() { - var manager = new PlugInManager(null, new NullLoggerFactory(), this.CreateServiceProvider()); + var manager = new PlugInManager(null, new NullLoggerFactory(), this.CreateServiceProvider(), null); var plugIn = new ExamplePlugIn(); manager.RegisterPlugInAtPlugInPoint(plugIn); manager.RegisterPlugIn(); @@ -146,7 +146,7 @@ public async ValueTask CreatedAndActiveByConfigurationAsync(bool active) TypeId = typeof(ExamplePlugIn).GUID, IsActive = active, }; - var manager = new PlugInManager(new List { configuration }, new NullLoggerFactory(), this.CreateServiceProvider()); + var manager = new PlugInManager(new List { configuration }, new NullLoggerFactory(), this.CreateServiceProvider(), null); var player = await TestHelper.CreatePlayerAsync().ConfigureAwait(false); var command = "test"; var args = new MyEventArgs(); @@ -191,7 +191,7 @@ public void DoStuff(Player player, string text, MyEventArgs args) } }", }; - var manager = new PlugInManager(new List { configuration }, new NullLoggerFactory(), this.CreateServiceProvider()); + var manager = new PlugInManager(new List { configuration }, new NullLoggerFactory(), this.CreateServiceProvider(), null); var player = await TestHelper.CreatePlayerAsync().ConfigureAwait(false); var command = "test"; var args = new MyEventArgs(); @@ -213,7 +213,7 @@ public void CustomPlugInByExternalAssemblyNotFoundDoesntThrowError() IsActive = true, ExternalAssemblyName = "DoesNotExist.dll", }; - _ = new PlugInManager(new List { configuration }, new NullLoggerFactory(), this.CreateServiceProvider()); + _ = new PlugInManager(new List { configuration }, new NullLoggerFactory(), this.CreateServiceProvider(), null); } /// @@ -227,7 +227,7 @@ public void UnknownPlugInByConfigurationDoesntThrowError() TypeId = new Guid("A9BDA3E2-4EB6-45C3-B234-37C1819C0CB6"), IsActive = true, }; - _ = new PlugInManager(new List { configuration }, new NullLoggerFactory(), this.CreateServiceProvider()); + _ = new PlugInManager(new List { configuration }, new NullLoggerFactory(), this.CreateServiceProvider(), null); } /// @@ -236,7 +236,7 @@ public void UnknownPlugInByConfigurationDoesntThrowError() [Test] public void ActivatingUnknownPlugInDoesNotThrowError() { - var manager = new PlugInManager(null, new NullLoggerFactory(), this.CreateServiceProvider()); + var manager = new PlugInManager(null, new NullLoggerFactory(), this.CreateServiceProvider(), null); manager.ActivatePlugIn(new Guid("4C38A813-F9BF-428A-8EA1-A6C90A87E583")); } @@ -246,7 +246,7 @@ public void ActivatingUnknownPlugInDoesNotThrowError() [Test] public void DeactivatingUnknownPlugInDoesNotThrowError() { - var manager = new PlugInManager(null, new NullLoggerFactory(), this.CreateServiceProvider()); + var manager = new PlugInManager(null, new NullLoggerFactory(), this.CreateServiceProvider(), null); manager.ActivatePlugIn(new Guid("4C38A813-F9BF-428A-8EA1-A6C90A87E583")); } @@ -256,7 +256,7 @@ public void DeactivatingUnknownPlugInDoesNotThrowError() [Test] public async ValueTask ActivatingPlugInsAsync() { - var manager = new PlugInManager(null, new NullLoggerFactory(), this.CreateServiceProvider()); + var manager = new PlugInManager(null, new NullLoggerFactory(), this.CreateServiceProvider(), null); var plugIn = new ExamplePlugIn(); manager.RegisterPlugInAtPlugInPoint(plugIn); manager.DeactivatePlugIn(); @@ -277,7 +277,7 @@ public async ValueTask ActivatingPlugInsAsync() [Test] public void AutoDiscovery() { - var manager = new PlugInManager(null, new NullLoggerFactory(), this.CreateServiceProvider()); + var manager = new PlugInManager(null, new NullLoggerFactory(), this.CreateServiceProvider(), null); manager.DiscoverAndRegisterPlugIns(); var examplePlugInPoint = manager.GetPlugInPoint(); Assert.That(examplePlugInPoint, Is.InstanceOf()); @@ -289,7 +289,7 @@ public void AutoDiscovery() [Test] public void RegisteringPlugInWithoutGuidThrowsError() { - var manager = new PlugInManager(null, new NullLoggerFactory(), this.CreateServiceProvider()); + var manager = new PlugInManager(null, new NullLoggerFactory(), this.CreateServiceProvider(), null); Assert.Throws(() => manager.RegisterPlugIn()); } @@ -299,7 +299,7 @@ public void RegisteringPlugInWithoutGuidThrowsError() [Test] public void StrategyProviderCreatedForRegisteredStrategyPlugIn() { - var manager = new PlugInManager(null, new NullLoggerFactory(), this.CreateServiceProvider()); + var manager = new PlugInManager(null, new NullLoggerFactory(), this.CreateServiceProvider(), null); manager.RegisterPlugIn(); var strategyProvider = manager.GetStrategyProvider(); @@ -312,7 +312,7 @@ public void StrategyProviderCreatedForRegisteredStrategyPlugIn() [Test] public void StrategyProviderNotCreatedWithoutRegisteredStrategyPlugIn() { - var manager = new PlugInManager(null, new NullLoggerFactory(), this.CreateServiceProvider()); + var manager = new PlugInManager(null, new NullLoggerFactory(), this.CreateServiceProvider(), null); var strategyProvider = manager.GetStrategyProvider(); Assert.That(strategyProvider, Is.Null); @@ -324,7 +324,7 @@ public void StrategyProviderNotCreatedWithoutRegisteredStrategyPlugIn() [Test] public void RegisteredStrategyPlugInAvailable() { - var manager = new PlugInManager(null, new NullLoggerFactory(), this.CreateServiceProvider()); + var manager = new PlugInManager(null, new NullLoggerFactory(), this.CreateServiceProvider(), null); manager.RegisterPlugIn(); var strategy = manager.GetStrategy(ExampleStrategyPlugIn.CommandKey); @@ -338,7 +338,7 @@ public void RegisteredStrategyPlugInAvailable() [Test] public void DeactivatedStrategyPlugInNotAvailable() { - var manager = new PlugInManager(null, new NullLoggerFactory(), this.CreateServiceProvider()); + var manager = new PlugInManager(null, new NullLoggerFactory(), this.CreateServiceProvider(), null); manager.RegisterPlugIn(); manager.DeactivatePlugIn(); var strategy = manager.GetStrategy(ExampleStrategyPlugIn.CommandKey); @@ -351,7 +351,7 @@ public void DeactivatedStrategyPlugInNotAvailable() [Test] public void RegisteringRegisteredStrategyPlugInDoesntThrowError() { - var manager = new PlugInManager(null, new NullLoggerFactory(), this.CreateServiceProvider()); + var manager = new PlugInManager(null, new NullLoggerFactory(), this.CreateServiceProvider(), null); manager.RegisterPlugIn(); manager.RegisterPlugIn(); } @@ -362,7 +362,7 @@ public void RegisteringRegisteredStrategyPlugInDoesntThrowError() [Test] public void NoPlugInPointForStrategyPlugIn() { - var manager = new PlugInManager(null, new NullLoggerFactory(), this.CreateServiceProvider()); + var manager = new PlugInManager(null, new NullLoggerFactory(), this.CreateServiceProvider(), null); manager.RegisterPlugIn(); Assert.That(manager.GetPlugInPoint(), Is.Null); } diff --git a/tests/MUnique.OpenMU.PlugIns.Tests/PlugInProxyTypeGeneratorTest.cs b/tests/MUnique.OpenMU.PlugIns.Tests/PlugInProxyTypeGeneratorTest.cs index 4783ef116..6f2515d5f 100644 --- a/tests/MUnique.OpenMU.PlugIns.Tests/PlugInProxyTypeGeneratorTest.cs +++ b/tests/MUnique.OpenMU.PlugIns.Tests/PlugInProxyTypeGeneratorTest.cs @@ -48,7 +48,7 @@ internal interface IUnsupportedPlugIn public void ProxyIsCreated() { var generator = new PlugInProxyTypeGenerator(); - var proxy = generator.GenerateProxy(new PlugInManager(null, new NullLoggerFactory(), null)); + var proxy = generator.GenerateProxy(new PlugInManager(null, new NullLoggerFactory(), null, null)); Assert.That(proxy, Is.Not.Null); } @@ -60,7 +60,7 @@ public void ProxyIsCreated() public async ValueTask MultiplePlugInsAreExecutedAsync() { var generator = new PlugInProxyTypeGenerator(); - var proxy = generator.GenerateProxy(new PlugInManager(null, NullLoggerFactory.Instance, null)); + var proxy = generator.GenerateProxy(new PlugInManager(null, NullLoggerFactory.Instance, null, null)); var player = await TestHelper.CreatePlayerAsync().ConfigureAwait(false); var command = "test"; @@ -86,7 +86,7 @@ public async ValueTask MultiplePlugInsAreExecutedAsync() public async ValueTask MultipleAsyncPlugInsAreExecutedAsync() { var generator = new PlugInProxyTypeGenerator(); - var proxy = generator.GenerateProxy(new PlugInManager(null, NullLoggerFactory.Instance, null)); + var proxy = generator.GenerateProxy(new PlugInManager(null, NullLoggerFactory.Instance, null, null)); // Forcing to load NitoEx _ = new AsyncReaderWriterLock(); @@ -113,7 +113,7 @@ public async ValueTask MultipleAsyncPlugInsAreExecutedAsync() public async ValueTask InactivePlugInsAreNotExecutedAsync() { var generator = new PlugInProxyTypeGenerator(); - var proxy = generator.GenerateProxy(new PlugInManager(null, NullLoggerFactory.Instance, null)); + var proxy = generator.GenerateProxy(new PlugInManager(null, NullLoggerFactory.Instance, null, null)); var player = await TestHelper.CreatePlayerAsync().ConfigureAwait(false); var command = "test"; @@ -140,7 +140,7 @@ public async ValueTask InactivePlugInsAreNotExecutedAsync() public async ValueTask CancelEventArgsAreRespectedAsync() { var generator = new PlugInProxyTypeGenerator(); - var proxy = generator.GenerateProxy(new PlugInManager(null, NullLoggerFactory.Instance, null)); + var proxy = generator.GenerateProxy(new PlugInManager(null, NullLoggerFactory.Instance, null, null)); var player = await TestHelper.CreatePlayerAsync().ConfigureAwait(false); var command = "test"; @@ -165,7 +165,7 @@ public async ValueTask CancelEventArgsAreRespectedAsync() public void ErrorForClasses() { var generator = new PlugInProxyTypeGenerator(); - Assert.Throws(() => generator.GenerateProxy(new PlugInManager(null, new NullLoggerFactory(), null))); + Assert.Throws(() => generator.GenerateProxy(new PlugInManager(null, new NullLoggerFactory(), null, null))); } /// @@ -175,7 +175,7 @@ public void ErrorForClasses() public void ErrorForInterfaceWithoutAttribute() { var generator = new PlugInProxyTypeGenerator(); - Assert.Throws(() => generator.GenerateProxy(new PlugInManager(null, new NullLoggerFactory(), null))); + Assert.Throws(() => generator.GenerateProxy(new PlugInManager(null, new NullLoggerFactory(), null, null))); } /// @@ -185,6 +185,6 @@ public void ErrorForInterfaceWithoutAttribute() public void ErrorForInterfaceWithUnsupportedMethodSignature() { var generator = new PlugInProxyTypeGenerator(); - Assert.Throws(() => generator.GenerateProxy(new PlugInManager(null, new NullLoggerFactory(), null))); + Assert.Throws(() => generator.GenerateProxy(new PlugInManager(null, new NullLoggerFactory(), null, null))); } } \ No newline at end of file diff --git a/tests/MUnique.OpenMU.Tests/GuildActionTest.cs b/tests/MUnique.OpenMU.Tests/GuildActionTest.cs index efcc767b6..40a4a78ba 100644 --- a/tests/MUnique.OpenMU.Tests/GuildActionTest.cs +++ b/tests/MUnique.OpenMU.Tests/GuildActionTest.cs @@ -164,7 +164,7 @@ private IGameServerContext CreateGameServer() new InMemoryPersistenceContextProvider(), mapInitializer, new NullLoggerFactory(), - new PlugInManager(new List(), new NullLoggerFactory(), null), + new PlugInManager(new List(), new NullLoggerFactory(), null, null), NullDropGenerator.Instance, new ConfigurationChangeMediator()); mapInitializer.PlugInManager = gameServer.PlugInManager; diff --git a/tests/MUnique.OpenMU.Tests/PacketHandlerPlugInContainerTest.cs b/tests/MUnique.OpenMU.Tests/PacketHandlerPlugInContainerTest.cs index 543817bb7..5afdc919f 100644 --- a/tests/MUnique.OpenMU.Tests/PacketHandlerPlugInContainerTest.cs +++ b/tests/MUnique.OpenMU.Tests/PacketHandlerPlugInContainerTest.cs @@ -30,7 +30,7 @@ public class PacketHandlerPlugInContainerTest [Test] public void SelectPlugInOfCorrectVersionWhenExactVersionIsAvailable() { - var manager = new PlugInManager(null, new NullLoggerFactory(), null); + var manager = new PlugInManager(null, new NullLoggerFactory(), null, null); manager.RegisterPlugIn(); manager.RegisterPlugIn(); manager.RegisterPlugIn(); @@ -48,7 +48,7 @@ public void SelectPlugInOfCorrectVersionWhenExactVersionIsAvailable() [Test] public void SelectPlugInOfCorrectVersionWhenLowerVersionsAreAvailable() { - var manager = new PlugInManager(null, new NullLoggerFactory(), null); + var manager = new PlugInManager(null, new NullLoggerFactory(), null, null); manager.RegisterPlugIn(); manager.RegisterPlugIn(); var clientVersionProvider = new Mock(); @@ -65,7 +65,7 @@ public void SelectPlugInOfCorrectVersionWhenLowerVersionsAreAvailable() [Test] public void SelectPlugInOfCorrectLanguage() { - var manager = new PlugInManager(null, new NullLoggerFactory(), null); + var manager = new PlugInManager(null, new NullLoggerFactory(), null, null); manager.RegisterPlugIn(); manager.RegisterPlugIn(); var clientVersionProvider = new Mock(); @@ -82,7 +82,7 @@ public void SelectPlugInOfCorrectLanguage() [Test] public void SelectInvariantPlugIn() { - var manager = new PlugInManager(null, new NullLoggerFactory(), null); + var manager = new PlugInManager(null, new NullLoggerFactory(), null, null); manager.RegisterPlugIn(); var clientVersionProvider = new Mock(); clientVersionProvider.Setup(p => p.ClientVersion).Returns(Season6E3English); @@ -98,7 +98,7 @@ public void SelectInvariantPlugIn() [Test] public void SelectPlugInAfterDeactivation() { - var manager = new PlugInManager(null, new NullLoggerFactory(), null); + var manager = new PlugInManager(null, new NullLoggerFactory(), null, null); manager.RegisterPlugIn(); manager.RegisterPlugIn(); var clientVersionProvider = new Mock(); @@ -118,7 +118,7 @@ public void SelectPlugInAfterDeactivation() [Test] public void SelectLanguageSpecificOverInvariant() { - var manager = new PlugInManager(null, new NullLoggerFactory(), null); + var manager = new PlugInManager(null, new NullLoggerFactory(), null, null); manager.RegisterPlugIn(); manager.RegisterPlugIn(); manager.RegisterPlugIn(); diff --git a/tests/MUnique.OpenMU.Tests/PartyTest.cs b/tests/MUnique.OpenMU.Tests/PartyTest.cs index b52cdc614..176d5ce2c 100644 --- a/tests/MUnique.OpenMU.Tests/PartyTest.cs +++ b/tests/MUnique.OpenMU.Tests/PartyTest.cs @@ -204,7 +204,7 @@ private IGameContext GetGameContext() gameConfig.Maps.Add(contextProvider.CreateNewContext().CreateNew()); var mapInitializer = new MapInitializer(gameConfig, new NullLogger(), NullDropGenerator.Instance, null); - var gameContext = new GameContext(gameConfig, contextProvider, mapInitializer, new NullLoggerFactory(), new PlugInManager(new List(), new NullLoggerFactory(), null), NullDropGenerator.Instance, new ConfigurationChangeMediator()); + var gameContext = new GameContext(gameConfig, contextProvider, mapInitializer, new NullLoggerFactory(), new PlugInManager(new List(), new NullLoggerFactory(), null, null), NullDropGenerator.Instance, new ConfigurationChangeMediator()); gameContext.Configuration.MaximumPartySize = 5; mapInitializer.PlugInManager = gameContext.PlugInManager; mapInitializer.PathFinderPool = gameContext.PathFinderPool; diff --git a/tests/MUnique.OpenMU.Tests/TestHelper.cs b/tests/MUnique.OpenMU.Tests/TestHelper.cs index 50b3ff415..b235eeccf 100644 --- a/tests/MUnique.OpenMU.Tests/TestHelper.cs +++ b/tests/MUnique.OpenMU.Tests/TestHelper.cs @@ -43,7 +43,7 @@ public static async ValueTask CreatePlayerAsync() gameConfig.Object.Maps.Add(map.Object); var mapInitializer = new MapInitializer(gameConfig.Object, new NullLogger(), NullDropGenerator.Instance, null); - var gameContext = new GameContext(gameConfig.Object, new InMemoryPersistenceContextProvider(), mapInitializer, new NullLoggerFactory(), new PlugInManager(null, new NullLoggerFactory(), null), NullDropGenerator.Instance, new ConfigurationChangeMediator()); + var gameContext = new GameContext(gameConfig.Object, new InMemoryPersistenceContextProvider(), mapInitializer, new NullLoggerFactory(), new PlugInManager(null, new NullLoggerFactory(), null, null), NullDropGenerator.Instance, new ConfigurationChangeMediator()); mapInitializer.PlugInManager = gameContext.PlugInManager; mapInitializer.PathFinderPool = gameContext.PathFinderPool; return await CreatePlayerAsync(gameContext).ConfigureAwait(false); diff --git a/tests/MUnique.OpenMU.Tests/TradeTest.cs b/tests/MUnique.OpenMU.Tests/TradeTest.cs index c6b361ba3..e5b38804d 100644 --- a/tests/MUnique.OpenMU.Tests/TradeTest.cs +++ b/tests/MUnique.OpenMU.Tests/TradeTest.cs @@ -90,7 +90,7 @@ public async ValueTask TradeFinishTestAsync() trader2.TradingPartner = trader1; var gameContext = new Mock(); - gameContext.Setup(c => c.PlugInManager).Returns(new PlugInManager(null, new NullLoggerFactory(), null)); + gameContext.Setup(c => c.PlugInManager).Returns(new PlugInManager(null, new NullLoggerFactory(), null, null)); gameContext.Setup(c => c.PersistenceContextProvider).Returns(new InMemoryPersistenceContextProvider()); Mock.Get(trader1).Setup(m => m.GameContext).Returns(gameContext.Object); diff --git a/tests/MUnique.OpenMU.Tests/ViewPlugInContainerTest.cs b/tests/MUnique.OpenMU.Tests/ViewPlugInContainerTest.cs index e2d84f25a..dfd3666b2 100644 --- a/tests/MUnique.OpenMU.Tests/ViewPlugInContainerTest.cs +++ b/tests/MUnique.OpenMU.Tests/ViewPlugInContainerTest.cs @@ -40,7 +40,7 @@ public interface ISomeViewPlugIn : IViewPlugIn [Test] public void SelectPlugInOfCorrectVersionWhenExactVersionIsAvailable() { - var manager = new PlugInManager(null, new NullLoggerFactory(), null); + var manager = new PlugInManager(null, new NullLoggerFactory(), null, null); manager.RegisterPlugIn(); manager.RegisterPlugIn(); manager.RegisterPlugIn(); @@ -54,7 +54,7 @@ public void SelectPlugInOfCorrectVersionWhenExactVersionIsAvailable() [Test] public void SelectPlugInOfCorrectVersionWhenLowerVersionsAreAvailable() { - var manager = new PlugInManager(null, new NullLoggerFactory(), null); + var manager = new PlugInManager(null, new NullLoggerFactory(), null, null); manager.RegisterPlugIn(); manager.RegisterPlugIn(); manager.RegisterPlugIn(); @@ -68,7 +68,7 @@ public void SelectPlugInOfCorrectVersionWhenLowerVersionsAreAvailable() [Test] public void SelectPlugInOfCorrectLanguage() { - var manager = new PlugInManager(null, new NullLoggerFactory(), null); + var manager = new PlugInManager(null, new NullLoggerFactory(), null, null); manager.RegisterPlugIn(); manager.RegisterPlugIn(); var containerForSeason6English = new ViewPlugInContainer(this.CreatePlayer(manager), Season6E3English, manager); @@ -81,7 +81,7 @@ public void SelectPlugInOfCorrectLanguage() [Test] public void SelectInvariantPlugIn() { - var manager = new PlugInManager(null, new NullLoggerFactory(), null); + var manager = new PlugInManager(null, new NullLoggerFactory(), null, null); manager.RegisterPlugIn(); var containerForSeason6English = new ViewPlugInContainer(this.CreatePlayer(manager), Season6E3English, manager); Assert.That(containerForSeason6English.GetPlugIn()!.GetType(), Is.EqualTo(typeof(InvariantSeasonPlugIn))); @@ -93,7 +93,7 @@ public void SelectInvariantPlugIn() [Test] public void SelectPlugInAfterDeactivation() { - var manager = new PlugInManager(null, new NullLoggerFactory(), null); + var manager = new PlugInManager(null, new NullLoggerFactory(), null, null); manager.RegisterPlugIn(); manager.RegisterPlugIn(); manager.RegisterPlugIn(); @@ -109,7 +109,7 @@ public void SelectPlugInAfterDeactivation() [Test] public void SelectLanguageSpecificOverInvariant() { - var manager = new PlugInManager(null, new NullLoggerFactory(), null); + var manager = new PlugInManager(null, new NullLoggerFactory(), null, null); manager.RegisterPlugIn(); manager.RegisterPlugIn(); var containerForSeason9 = new ViewPlugInContainer(this.CreatePlayer(manager), Season9E2English, manager); From 5e230831938d1fe6d26b86f2bfe979a887977604 Mon Sep 17 00:00:00 2001 From: sven-n Date: Wed, 20 Mar 2024 18:40:58 +0100 Subject: [PATCH 02/29] Added a plugin configuration for jewel of bless consumption --- .../BlessJewelConsumeHandlerPlugIn.cs | 15 ++++++++++++++- ...ssJewelConsumeHandlerPlugInConfiguration.cs | 18 ++++++++++++++++++ .../SoulJewelConsumeHandlerPlugIn.cs | 1 + 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 src/GameLogic/PlayerActions/ItemConsumeActions/BlessJewelConsumeHandlerPlugInConfiguration.cs diff --git a/src/GameLogic/PlayerActions/ItemConsumeActions/BlessJewelConsumeHandlerPlugIn.cs b/src/GameLogic/PlayerActions/ItemConsumeActions/BlessJewelConsumeHandlerPlugIn.cs index 65b5ae2f2..47e7d4b79 100644 --- a/src/GameLogic/PlayerActions/ItemConsumeActions/BlessJewelConsumeHandlerPlugIn.cs +++ b/src/GameLogic/PlayerActions/ItemConsumeActions/BlessJewelConsumeHandlerPlugIn.cs @@ -15,14 +15,26 @@ namespace MUnique.OpenMU.GameLogic.PlayerActions.ItemConsumeActions; /// [Guid("E95A0292-B3B4-4E8C-AC5A-7F3DB4F01A37")] [PlugIn(nameof(BlessJewelConsumeHandlerPlugIn), "Plugin which handles the jewel of bless consumption.")] -public class BlessJewelConsumeHandlerPlugIn : ItemModifyConsumeHandlerPlugIn +public class BlessJewelConsumeHandlerPlugIn : ItemModifyConsumeHandlerPlugIn, ISupportCustomConfiguration { /// public override ItemIdentifier Key => ItemConstants.JewelOfBless; + /// + /// Gets or sets the configuration. + /// + public BlessJewelConsumeHandlerPlugInConfiguration? Configuration { get; set; } + /// protected override bool ModifyItem(Item item, IContext persistenceContext) { + if (this.Configuration?.RepairTargetItems.Contains(item.Definition!) is true + && item.Durability < item.GetMaximumDurabilityOfOnePiece()) + { + item.Durability = item.GetMaximumDurabilityOfOnePiece(); + return true; + } + if (!item.CanLevelBeUpgraded()) { return false; @@ -37,6 +49,7 @@ protected override bool ModifyItem(Item item, IContext persistenceContext) level++; item.Level = level; + item.Durability = item.GetMaximumDurabilityOfOnePiece(); return true; } } \ No newline at end of file diff --git a/src/GameLogic/PlayerActions/ItemConsumeActions/BlessJewelConsumeHandlerPlugInConfiguration.cs b/src/GameLogic/PlayerActions/ItemConsumeActions/BlessJewelConsumeHandlerPlugInConfiguration.cs new file mode 100644 index 000000000..23994c22a --- /dev/null +++ b/src/GameLogic/PlayerActions/ItemConsumeActions/BlessJewelConsumeHandlerPlugInConfiguration.cs @@ -0,0 +1,18 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace MUnique.OpenMU.GameLogic.PlayerActions.ItemConsumeActions; + +using MUnique.OpenMU.DataModel.Configuration.Items; + +/// +/// The configuration for the . +/// +public class BlessJewelConsumeHandlerPlugInConfiguration +{ + /// + /// Gets or sets the items which can be repaired by consuming a bless on them. + /// + public ICollection RepairTargetItems { get; set; } = new List(); +} \ No newline at end of file diff --git a/src/GameLogic/PlayerActions/ItemConsumeActions/SoulJewelConsumeHandlerPlugIn.cs b/src/GameLogic/PlayerActions/ItemConsumeActions/SoulJewelConsumeHandlerPlugIn.cs index 0d9738147..561d372db 100644 --- a/src/GameLogic/PlayerActions/ItemConsumeActions/SoulJewelConsumeHandlerPlugIn.cs +++ b/src/GameLogic/PlayerActions/ItemConsumeActions/SoulJewelConsumeHandlerPlugIn.cs @@ -62,6 +62,7 @@ protected override bool ModifyItem(Item item, IContext persistenceContext) if (this._randomizer.NextRandomBool(percent)) { item.Level++; + item.Durability = item.GetMaximumDurabilityOfOnePiece(); return true; // true doesn't mean that it was successful, just that the consumption happened. } From f706941540b3181270772f93a03508c47e207af5 Mon Sep 17 00:00:00 2001 From: sven-n Date: Mon, 6 May 2024 20:12:28 +0200 Subject: [PATCH 03/29] Automatically add missing Stat Attributes of the character class when entering the game. --- src/GameLogic/Player.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/GameLogic/Player.cs b/src/GameLogic/Player.cs index f13e77363..3c8046437 100644 --- a/src/GameLogic/Player.cs +++ b/src/GameLogic/Player.cs @@ -4,6 +4,7 @@ namespace MUnique.OpenMU.GameLogic; +using System.Numerics; using System.Threading; using MUnique.OpenMU.AttributeSystem; using MUnique.OpenMU.DataModel.Attributes; @@ -1786,9 +1787,26 @@ private void RaisePlayerLeftMap(GameMap map) this.PlayerLeftMap?.Invoke(this, (this, map)); } + /// + /// Adds the missing stat attributes, e.g. after the character class has been changed outside of the game. + /// + private void AddMissingStatAttributes() + { + if (this.SelectedCharacter is not { CharacterClass: { } characterClass } character) + { + return; + } + + var missingStats = characterClass.StatAttributes.Where(a => this.SelectedCharacter.Attributes.All(c => c.Definition != a.Attribute)); + + var attributes = missingStats.Select(a => this.PersistenceContext.CreateNew(a.Attribute, a.BaseValue)).ToList(); + attributes.ForEach(character.Attributes.Add); + } + private async ValueTask OnPlayerEnteredWorldAsync() { this.Attributes = new ItemAwareAttributeSystem(this.Account!, this.SelectedCharacter!); + this.AddMissingStatAttributes(); this.Inventory = new InventoryStorage(this, this.GameContext); this.ShopStorage = new ShopStorage(this); this.TemporaryStorage = new Storage(InventoryConstants.TemporaryStorageSize, new TemporaryItemStorage()); From 9ba14b0e348ee05e9bbf8302ee6b893c6e5d95cf Mon Sep 17 00:00:00 2001 From: sven-n Date: Mon, 6 May 2024 20:14:50 +0200 Subject: [PATCH 04/29] Fixed initialization code for infinity arrow skill on quest completion --- .../Initialization/GameConfigurationInitializerBase.cs | 1 + .../Updates/InfinityArrowSkillOnQuestCompletionPlugIn.cs | 1 + src/Persistence/Initialization/Updates/UpdateVersion.cs | 2 +- src/Persistence/Initialization/VersionSeasonSix/Quests.cs | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Persistence/Initialization/GameConfigurationInitializerBase.cs b/src/Persistence/Initialization/GameConfigurationInitializerBase.cs index ff551f281..3b88d0342 100644 --- a/src/Persistence/Initialization/GameConfigurationInitializerBase.cs +++ b/src/Persistence/Initialization/GameConfigurationInitializerBase.cs @@ -39,6 +39,7 @@ public override void Initialize() { this.GameConfiguration.ExperienceRate = 1.0f; this.GameConfiguration.MaximumLevel = 400; + this.GameConfiguration.MaximumMasterLevel = 400; this.GameConfiguration.InfoRange = 12; this.GameConfiguration.AreaSkillHitsPlayer = false; this.GameConfiguration.MaximumInventoryMoney = int.MaxValue; diff --git a/src/Persistence/Initialization/Updates/InfinityArrowSkillOnQuestCompletionPlugIn.cs b/src/Persistence/Initialization/Updates/InfinityArrowSkillOnQuestCompletionPlugIn.cs index 09140246b..16de5c3f9 100644 --- a/src/Persistence/Initialization/Updates/InfinityArrowSkillOnQuestCompletionPlugIn.cs +++ b/src/Persistence/Initialization/Updates/InfinityArrowSkillOnQuestCompletionPlugIn.cs @@ -62,5 +62,6 @@ protected override async ValueTask ApplyAsync(IContext context, GameConfiguratio skillReward.Value = 1; skillReward.SkillReward = gameConfiguration.Skills.First(s => s.Number == (short)SkillNumber.InfinityArrow); skillReward.RewardType = QuestRewardType.Skill; + quest.Rewards.Add(skillReward); } } \ No newline at end of file diff --git a/src/Persistence/Initialization/Updates/UpdateVersion.cs b/src/Persistence/Initialization/Updates/UpdateVersion.cs index e5ec30f9e..cf9ee08d7 100644 --- a/src/Persistence/Initialization/Updates/UpdateVersion.cs +++ b/src/Persistence/Initialization/Updates/UpdateVersion.cs @@ -83,5 +83,5 @@ public enum UpdateVersion /// /// The version of the . /// - InfinityArrowSkillOnQuestCompletion = 14, + InfinityArrowSkillOnQuestCompletion = 15, } \ No newline at end of file diff --git a/src/Persistence/Initialization/VersionSeasonSix/Quests.cs b/src/Persistence/Initialization/VersionSeasonSix/Quests.cs index 537940b42..83799b3b6 100644 --- a/src/Persistence/Initialization/VersionSeasonSix/Quests.cs +++ b/src/Persistence/Initialization/VersionSeasonSix/Quests.cs @@ -249,6 +249,7 @@ private void GainHeroStatus(CharacterClassNumber characterClass) skillReward.Value = 1; skillReward.SkillReward = this.GameConfiguration.Skills.First(s => s.Number == (short)SkillNumber.InfinityArrow); skillReward.RewardType = QuestRewardType.Skill; + heroStatus.Rewards.Add(skillReward); } heroStatus.Rewards.Add(pointReward); From ecbf822027085b03f31082bc3da47f6cc55a3641 Mon Sep 17 00:00:00 2001 From: sven-n Date: Mon, 6 May 2024 20:25:42 +0200 Subject: [PATCH 05/29] code style fixes --- src/Persistence/ByDataSourceReferenceHandler.cs | 2 +- src/Persistence/ByDataSourceReferenceResolver.cs | 2 +- src/Startup/Program.cs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Persistence/ByDataSourceReferenceHandler.cs b/src/Persistence/ByDataSourceReferenceHandler.cs index 42c7d70e3..1e507f562 100644 --- a/src/Persistence/ByDataSourceReferenceHandler.cs +++ b/src/Persistence/ByDataSourceReferenceHandler.cs @@ -15,7 +15,7 @@ public class ByDataSourceReferenceHandler : ReferenceHandler /// /// The data source. /// - private IDataSource _dataSource; + private readonly IDataSource _dataSource; /// /// Initializes a new instance of the class. diff --git a/src/Persistence/ByDataSourceReferenceResolver.cs b/src/Persistence/ByDataSourceReferenceResolver.cs index 0e8a2b725..fedf7a1fa 100644 --- a/src/Persistence/ByDataSourceReferenceResolver.cs +++ b/src/Persistence/ByDataSourceReferenceResolver.cs @@ -29,7 +29,7 @@ public ByDataSourceReferenceResolver(IDataSource dataSource) /// public override void AddReference(string referenceId, object value) { - //throw new NotImplementedException(); + // do nothing here, because the data source is the source of truth. } /// diff --git a/src/Startup/Program.cs b/src/Startup/Program.cs index ee3447bae..11825454d 100644 --- a/src/Startup/Program.cs +++ b/src/Startup/Program.cs @@ -274,8 +274,8 @@ private async Task CreateHostAsync(string[] args) var dataSource = new GameConfigurationDataSource( provider.GetService>()!, persistenceContextProvider!); - var configId = persistenceContextProvider!.CreateNewConfigurationContext().GetDefaultGameConfigurationIdAsync(default).GetAwaiter().GetResult(); - dataSource.GetOwnerAsync(configId!.Value).GetAwaiter().GetResult(); + var configId = persistenceContextProvider!.CreateNewConfigurationContext().GetDefaultGameConfigurationIdAsync(default).AsTask().WaitAndUnwrapException(); + dataSource.GetOwnerAsync(configId!.Value).AsTask().WaitAndUnwrapException(); var referenceHandler = new ByDataSourceReferenceHandler(dataSource); return referenceHandler; }) From ad96299f402ab9d01a2a0f5c6b937047b09d96e1 Mon Sep 17 00:00:00 2001 From: sven-n Date: Mon, 6 May 2024 20:28:27 +0200 Subject: [PATCH 06/29] Update Player.cs --- src/GameLogic/Player.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/GameLogic/Player.cs b/src/GameLogic/Player.cs index 3c8046437..0a24ce652 100644 --- a/src/GameLogic/Player.cs +++ b/src/GameLogic/Player.cs @@ -4,7 +4,6 @@ namespace MUnique.OpenMU.GameLogic; -using System.Numerics; using System.Threading; using MUnique.OpenMU.AttributeSystem; using MUnique.OpenMU.DataModel.Attributes; @@ -2141,4 +2140,4 @@ public GMMagicEffectDefinition() this.PowerUpDefinitions = new List(0); } } -} \ No newline at end of file +} From d83c51eb6265939ae971216e7846b2753cf8defb Mon Sep 17 00:00:00 2001 From: sven-n Date: Mon, 6 May 2024 20:30:26 +0200 Subject: [PATCH 07/29] Version 0.8.3 --- src/SharedAssemblyInfo.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/SharedAssemblyInfo.cs b/src/SharedAssemblyInfo.cs index 9e9de0229..454b864e2 100644 --- a/src/SharedAssemblyInfo.cs +++ b/src/SharedAssemblyInfo.cs @@ -11,7 +11,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("MUnique")] [assembly: AssemblyProduct("OpenMU")] -[assembly: AssemblyCopyright("Copyright © MUnique 2023")] +[assembly: AssemblyCopyright("Copyright © MUnique 2024")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -29,5 +29,5 @@ // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("0.8.2.0")] -[assembly: AssemblyFileVersion("0.8.2.0")] +[assembly: AssemblyVersion("0.8.3.0")] +[assembly: AssemblyFileVersion("0.8.3.0")] From 111c27bfe31237bd254745dbc032b2ccd00fc26d Mon Sep 17 00:00:00 2001 From: sven-n Date: Wed, 8 May 2024 21:35:24 +0200 Subject: [PATCH 08/29] Fixed pet effects --- src/Persistence/Initialization/Version075/Items/Pets.cs | 2 +- src/Persistence/Initialization/Version095d/Items/Pets.cs | 4 ++-- src/Persistence/Initialization/VersionSeasonSix/Items/Pets.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Persistence/Initialization/Version075/Items/Pets.cs b/src/Persistence/Initialization/Version075/Items/Pets.cs index 0e0cb182d..e47fcc961 100644 --- a/src/Persistence/Initialization/Version075/Items/Pets.cs +++ b/src/Persistence/Initialization/Version075/Items/Pets.cs @@ -29,7 +29,7 @@ public Pets(IContext context, GameConfiguration gameConfiguration) /// public override void Initialize() { - this.CreatePet(0, "Guardian Angel", 23, (Stats.DamageReceiveDecrement, 0.2f), (Stats.MaximumHealth, 50f)); + this.CreatePet(0, "Guardian Angel", 23, (Stats.DamageReceiveDecrement, -0.2f), (Stats.MaximumHealth, 50f)); this.CreatePet(1, "Imp", 28, (Stats.AttackDamageIncrease, 0.3f)); this.CreatePet(2, "Horn of Uniria", 25); } diff --git a/src/Persistence/Initialization/Version095d/Items/Pets.cs b/src/Persistence/Initialization/Version095d/Items/Pets.cs index d20a5501c..efef4c035 100644 --- a/src/Persistence/Initialization/Version095d/Items/Pets.cs +++ b/src/Persistence/Initialization/Version095d/Items/Pets.cs @@ -30,11 +30,11 @@ public Pets(IContext context, GameConfiguration gameConfiguration) /// public override void Initialize() { - this.CreatePet(0, 0, "Guardian Angel", 23, true, (Stats.DamageReceiveDecrement, 0.2f), (Stats.MaximumHealth, 50f)); + this.CreatePet(0, 0, "Guardian Angel", 23, true, (Stats.DamageReceiveDecrement, -0.2f), (Stats.MaximumHealth, 50f)); this.CreatePet(1, 0, "Imp", 28, true, (Stats.AttackDamageIncrease, 0.3f)); this.CreatePet(2, 0, "Horn of Uniria", 25, true); - var dinorant = this.CreatePet(3, SkillNumber.FireBreath, "Horn of Dinorant", 110, false, (Stats.DamageReceiveDecrement, 0.1f), (Stats.AttackDamageIncrease, 0.15f), (Stats.CanFly, 1.0f)); + var dinorant = this.CreatePet(3, SkillNumber.FireBreath, "Horn of Dinorant", 110, false, (Stats.DamageReceiveDecrement, -0.1f), (Stats.AttackDamageIncrease, 0.15f), (Stats.CanFly, 1.0f)); this.AddDinorantOptions(dinorant); } diff --git a/src/Persistence/Initialization/VersionSeasonSix/Items/Pets.cs b/src/Persistence/Initialization/VersionSeasonSix/Items/Pets.cs index 9a1f22145..8d2aef73e 100644 --- a/src/Persistence/Initialization/VersionSeasonSix/Items/Pets.cs +++ b/src/Persistence/Initialization/VersionSeasonSix/Items/Pets.cs @@ -57,7 +57,7 @@ public override void Initialize() this.CreatePet(64, 0, 1, 1, "Demon", 1, false, true, (Stats.AttackDamageIncrease, 0.4f), (Stats.AttackSpeed, 10f)); this.CreatePet(65, 0, 1, 1, "Spirit of Guardian", 1, false, true, (Stats.DamageReceiveDecrement, 0.3f), (Stats.MaximumHealth, 50f)); this.CreatePet(67, 0, 1, 1, "Pet Rudolf", 28, false, true); - this.CreatePet(80, 0, 1, 1, "Pet Panda", 1, false, true, (Stats.MoneyAmountRate, 0.5f), (Stats.DefenseBase, 50f)); + this.CreatePet(80, 0, 1, 1, "Pet Panda", 1, false, true, (Stats.ExperienceRate, 0.5f), (Stats.MasterExperienceRate, 0.5f),(Stats.DefenseBase, 50f)); this.CreatePet(106, 0, 1, 1, "Pet Unicorn", 28, false, true, (Stats.MoneyAmountRate, 0.5f), (Stats.DefenseBase, 50f)); this.CreatePet(123, 0, 1, 1, "Pet Skeleton", 1, false, true, (Stats.AttackDamageIncrease, 0.2f), (Stats.AttackSpeed, 10f), (Stats.ExperienceRate, 0.3f)); From 89282c153d9c800ccdfddccc30d4ad4226a4070f Mon Sep 17 00:00:00 2001 From: sven-n Date: Wed, 8 May 2024 21:36:05 +0200 Subject: [PATCH 09/29] Mini Game Entrance: Added check for master classes --- src/GameLogic/PlayerActions/MiniGames/EnterMiniGameAction.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/GameLogic/PlayerActions/MiniGames/EnterMiniGameAction.cs b/src/GameLogic/PlayerActions/MiniGames/EnterMiniGameAction.cs index 484bc52d4..7d6aa58b2 100644 --- a/src/GameLogic/PlayerActions/MiniGames/EnterMiniGameAction.cs +++ b/src/GameLogic/PlayerActions/MiniGames/EnterMiniGameAction.cs @@ -44,7 +44,8 @@ public async ValueTask TryEnterMiniGameAsync(Player player, MiniGameType miniGam var characterLevel = player.Attributes![Stats.Level]; var minLevel = isSpecialCharacter ? miniGameDefinition.MinimumSpecialCharacterLevel : miniGameDefinition.MinimumCharacterLevel; var maxLevel = isSpecialCharacter ? miniGameDefinition.MaximumSpecialCharacterLevel : miniGameDefinition.MaximumCharacterLevel; - if (characterLevel < minLevel) + var requiresMasterLevel = miniGameDefinition.RequiresMasterClass; + if (characterLevel < minLevel || (requiresMasterLevel && player.SelectedCharacter?.CharacterClass?.IsMasterClass is not true)) { await player.InvokeViewPlugInAsync(p => p.ShowResultAsync(miniGameType, EnterResult.CharacterLevelTooLow)).ConfigureAwait(false); return; From e0ad5828465fa3255bc5b693164946d8ba7bae65 Mon Sep 17 00:00:00 2001 From: sven-n Date: Wed, 8 May 2024 21:37:17 +0200 Subject: [PATCH 10/29] Fixed spawn wave starting The spawn waves need to wait in parallel. They cannot be run sequential, because they may overlap. So we start one task per wave and wait for the spawn until the start time has been elapsed. --- src/GameLogic/MiniGames/MiniGameContext.cs | 48 ++++++++++++---------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/src/GameLogic/MiniGames/MiniGameContext.cs b/src/GameLogic/MiniGames/MiniGameContext.cs index 046444494..652d13af2 100644 --- a/src/GameLogic/MiniGames/MiniGameContext.cs +++ b/src/GameLogic/MiniGames/MiniGameContext.cs @@ -32,7 +32,7 @@ public class MiniGameContext : AsyncDisposable, IEventStateProvider private readonly CancellationTokenSource _gameEndedCts = new(); - private readonly HashSet _currentSpawnWaves = new(); + private readonly ConcurrentDictionary _currentSpawnWaves = new(); private readonly List _remainingEvents = new(); private Stopwatch? _elapsedTimeSinceStart; @@ -177,7 +177,7 @@ public async ValueTask TryEnterAsync(Player player) /// public bool IsSpawnWaveActive(byte waveNumber) { - return this._currentSpawnWaves.Contains(waveNumber); + return this._currentSpawnWaves.ContainsKey(waveNumber); } /// @@ -588,15 +588,13 @@ private async Task RunSpawnWavesAsync(CancellationToken cancellationToken) { try { - foreach (var spawnWave in this.Definition.SpawnWaves.OrderBy(wave => wave.WaveNumber)) - { - if (cancellationToken.IsCancellationRequested) - { - break; - } - - await this.RunSpawnWaveAsync(spawnWave, cancellationToken).ConfigureAwait(false); - } + // We already need to start all tasks, because they may overlap. + // So it's not okay to run them one after another. + var waveTasks = this.Definition.SpawnWaves + .OrderBy(wave => wave.WaveNumber) + .Select(wave => this.RunSpawnWaveAsync(wave, cancellationToken)) + .ToList(); + await Task.WhenAll(waveTasks).ConfigureAwait(false); } catch (OperationCanceledException) { @@ -608,19 +606,20 @@ private async Task RunSpawnWavesAsync(CancellationToken cancellationToken) } } - private async ValueTask RunSpawnWaveAsync(MiniGameSpawnWave spawnWave, CancellationToken cancellationToken) + private async Task RunSpawnWaveAsync(MiniGameSpawnWave spawnWave, CancellationToken cancellationToken) { try { - if (cancellationToken.IsCancellationRequested) - { - return; - } - - var requiredDelay = spawnWave.StartTime - this._elapsedTimeSinceStart?.Elapsed; - if (requiredDelay > TimeSpan.Zero) + while (spawnWave.StartTime > this._elapsedTimeSinceStart?.Elapsed) { - await Task.Delay(requiredDelay.Value, cancellationToken).ConfigureAwait(false); + cancellationToken.ThrowIfCancellationRequested(); + + // Wait at least a second (or half of the remaining time) to the next check + var timeUntilNextCheck = (spawnWave.StartTime - this._elapsedTimeSinceStart!.Elapsed) / 2; + var requiredDelay = timeUntilNextCheck > TimeSpan.FromSeconds(1) + ? timeUntilNextCheck + : TimeSpan.FromSeconds(1); + await Task.Delay(requiredDelay, cancellationToken).ConfigureAwait(false); } this.Logger.LogDebug("{context}: Starting next wave: {wave}", this, spawnWave.Description); @@ -629,7 +628,11 @@ private async ValueTask RunSpawnWaveAsync(MiniGameSpawnWave spawnWave, Cancellat await this.ShowMessageAsync(message).ConfigureAwait(false); } - this._currentSpawnWaves.Add(spawnWave.WaveNumber); + if (!this._currentSpawnWaves.TryAdd(spawnWave.WaveNumber, spawnWave)) + { + this.Logger.LogWarning("{context}: Duplicate spawn wave number in event: {wave}. Check your configuration, every spawn wave needs a distinct number.", this, spawnWave.Description); + } + await this._mapInitializer.InitializeNpcsOnWaveStartAsync(this.Map, this, spawnWave.WaveNumber).ConfigureAwait(false); await Task.Delay(spawnWave.EndTime - spawnWave.StartTime, cancellationToken).ConfigureAwait(false); this.Logger.LogDebug("{context}: Wave ended: {wave}", this, spawnWave.Description); @@ -637,6 +640,7 @@ private async ValueTask RunSpawnWaveAsync(MiniGameSpawnWave spawnWave, Cancellat catch (OperationCanceledException) { // do nothing, as it's expected when game ends ... + throw; } catch (Exception ex) { @@ -644,7 +648,7 @@ private async ValueTask RunSpawnWaveAsync(MiniGameSpawnWave spawnWave, Cancellat } finally { - this._currentSpawnWaves.Remove(spawnWave.WaveNumber); + this._currentSpawnWaves.Remove(spawnWave.WaveNumber, out _); } } From d52ece6f2df67005f49cdc9612d7507f04a865f7 Mon Sep 17 00:00:00 2001 From: sven-n Date: Thu, 9 May 2024 12:09:58 +0200 Subject: [PATCH 11/29] Add [POST] prefix and character name to the blue message --- src/GameLogic/PlugIns/ChatCommands/PostChatCommandPlugIn.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/GameLogic/PlugIns/ChatCommands/PostChatCommandPlugIn.cs b/src/GameLogic/PlugIns/ChatCommands/PostChatCommandPlugIn.cs index afde1e116..8393ebfc9 100644 --- a/src/GameLogic/PlugIns/ChatCommands/PostChatCommandPlugIn.cs +++ b/src/GameLogic/PlugIns/ChatCommands/PostChatCommandPlugIn.cs @@ -34,6 +34,7 @@ public async ValueTask HandleCommandAsync(Player player, string command) return; } + message = $"[POST] {player.SelectedCharacter?.Name}: {message}"; await player.GameContext.SendGlobalMessageAsync(message, Interfaces.MessageType.BlueNormal).ConfigureAwait(false); } } \ No newline at end of file From b2d414df7c1250b5ba2727cb58a8f9d5cda4f739 Mon Sep 17 00:00:00 2001 From: open-not-ai Date: Thu, 16 May 2024 15:47:40 +0800 Subject: [PATCH 12/29] Update QuickStart.md Admin Panel. sever port is 8080 --- QuickStart.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/QuickStart.md b/QuickStart.md index 90928bbc8..a31ad292d 100644 --- a/QuickStart.md +++ b/QuickStart.md @@ -30,7 +30,7 @@ If you just want to play around with the server, you can find the newest docker all-in-one image on the Docker Hub: To pull and run the latest docker image, run this command: -`docker run --name openmu -d -p 80:80 -p 44405:44405 -p 55901:55901 -p 55902:55902 -p 55903:55903 -p 55980:55980 munique/openmu:latest -demo` +`docker run --name openmu -d -p 80:8080 -p 44405:44405 -p 55901:55901 -p 55902:55902 -p 55903:55903 -p 55980:55980 munique/openmu:latest -demo` The last argument is there to start the server in demo mode, without a database. To use a postgres database, you can use docker-compose. From 242161152dd930634a30aa0972dcb10b589a3ae2 Mon Sep 17 00:00:00 2001 From: sven-n Date: Fri, 7 Jun 2024 20:36:28 +0200 Subject: [PATCH 13/29] Fixed a major design flaw in the data model. ItemSets now have a reference to a ItemOptionDefinition instead of a collection of options. This way, we have a clean way to define set options without many-to-many references to IncreasableItemOption. This also solves the multiple foreign keys in the IncreasableItemOption table and different options for the composition root. Had to introduce some sql at the ef migrations to fix existing data. --- .../Configuration/Items/ItemSetGroup.cs | 9 +- src/DataModel/GameConfigurationHelper.cs | 1 - src/GameLogic/DefaultDropGenerator.cs | 4 +- src/GameLogic/ItemPowerUpFactory.cs | 29 +- src/GameServer/RemoteView/IItemSerializer.cs | 2 +- .../BasicModel/ItemSetGroup.Generated.cs | 39 +- .../CachingRepositoryProvider.cs | 5 +- .../20240602060055_FixItemOptions.Designer.cs | 4878 +++++++++++++++++ .../20240602060055_FixItemOptions.cs | 106 + ...20240602085237_FixItemOptions2.Designer.cs | 4878 +++++++++++++++++ .../20240602085237_FixItemOptions2.cs | 117 + .../EntityDataContextModelSnapshot.cs | 25 +- .../Model/ExtendedTypeContext.Generated.cs | 1 - .../Model/ItemSetGroup.Generated.cs | 31 +- .../Items/ArmorInitializerBase.cs | 26 +- .../VersionSeasonSix/Items/AncientSets.cs | 6 +- .../SourceGenerator/EfCoreModelGenerator.cs | 8 +- .../PowerUpFactoryTest.cs | 15 +- 18 files changed, 10105 insertions(+), 75 deletions(-) create mode 100644 src/Persistence/EntityFramework/Migrations/20240602060055_FixItemOptions.Designer.cs create mode 100644 src/Persistence/EntityFramework/Migrations/20240602060055_FixItemOptions.cs create mode 100644 src/Persistence/EntityFramework/Migrations/20240602085237_FixItemOptions2.Designer.cs create mode 100644 src/Persistence/EntityFramework/Migrations/20240602085237_FixItemOptions2.cs diff --git a/src/DataModel/Configuration/Items/ItemSetGroup.cs b/src/DataModel/Configuration/Items/ItemSetGroup.cs index fc316b8ce..4e993f05a 100644 --- a/src/DataModel/Configuration/Items/ItemSetGroup.cs +++ b/src/DataModel/Configuration/Items/ItemSetGroup.cs @@ -5,6 +5,7 @@ namespace MUnique.OpenMU.DataModel.Configuration.Items; using MUnique.OpenMU.Annotations; +using MUnique.OpenMU.DataModel.Entities; /// /// Defines an item set group. With (partial) completion of the set, additional options are getting applied. @@ -28,8 +29,9 @@ public partial class ItemSetGroup public string Name { get; set; } = string.Empty; /// - /// Gets or sets a value indicating whether all of the options of this item set always apply. - /// If not, the minimum item count and the minimum set levels are respected. + /// Gets or sets a value indicating whether the options of this item set always apply to an item, + /// even if the group wasn't explicitly added to the . + /// The minimum item count and the minimum set levels are respected. /// public bool AlwaysApplies { get; set; } @@ -57,8 +59,7 @@ public partial class ItemSetGroup /// /// The order is defined by . /// - [MemberOfAggregate] - public virtual ICollection Options { get; protected set; } = null!; + public virtual ItemOptionDefinition? Options { get; set; } = null!; /// /// Gets or sets the items of this set. diff --git a/src/DataModel/GameConfigurationHelper.cs b/src/DataModel/GameConfigurationHelper.cs index 3cae81d5c..a3110f95d 100644 --- a/src/DataModel/GameConfigurationHelper.cs +++ b/src/DataModel/GameConfigurationHelper.cs @@ -34,7 +34,6 @@ public static class GameConfigurationHelper { typeof(ItemOptionDefinition), c => c.ItemOptions }, { typeof(IncreasableItemOption), c => c.ItemOptions.SelectMany(o => o.PossibleOptions) - .Concat(c.ItemSetGroups.SelectMany(o => o.Options)) }, { typeof(ItemSetGroup), c => c.ItemSetGroups }, { typeof(ItemOfItemSet), c => c.ItemSetGroups.SelectMany(o => o.Items) }, diff --git a/src/GameLogic/DefaultDropGenerator.cs b/src/GameLogic/DefaultDropGenerator.cs index a75b43e6a..bf49a129e 100644 --- a/src/GameLogic/DefaultDropGenerator.cs +++ b/src/GameLogic/DefaultDropGenerator.cs @@ -42,7 +42,7 @@ public DefaultDropGenerator(GameConfiguration config, IRandomizer randomizer) { this._randomizer = randomizer; this._droppableItems = config.Items.Where(i => i.DropsFromMonsters).ToList(); - this._ancientItems = this._droppableItems.Where(i => i.PossibleItemSetGroups.Any(o => o.Options.Any(o => o.OptionType == ItemOptionTypes.AncientOption))).ToList(); + this._ancientItems = this._droppableItems.Where(i => i.PossibleItemSetGroups.Any(o => o.Options?.PossibleOptions.Any(o => o.OptionType == ItemOptionTypes.AncientOption) ?? false)).ToList(); } /// @@ -327,7 +327,7 @@ private static bool IsGroupRelevant(MonsterDefinition monsterDefinition, DropIte private void ApplyRandomAncientOption(Item item) { - var ancientSet = item.Definition?.PossibleItemSetGroups.Where(g => g!.Options.Any(o => o.OptionType == ItemOptionTypes.AncientOption)).SelectRandom(this._randomizer); + var ancientSet = item.Definition?.PossibleItemSetGroups.Where(g => g!.Options?.PossibleOptions.Any(o => o.OptionType == ItemOptionTypes.AncientOption) ?? false).SelectRandom(this._randomizer); if (ancientSet is null) { return; diff --git a/src/GameLogic/ItemPowerUpFactory.cs b/src/GameLogic/ItemPowerUpFactory.cs index c136bfc83..a51d3b800 100644 --- a/src/GameLogic/ItemPowerUpFactory.cs +++ b/src/GameLogic/ItemPowerUpFactory.cs @@ -78,17 +78,14 @@ public IEnumerable GetSetPowerUps( .Distinct(); var result = Enumerable.Empty(); - foreach (var group in itemGroups) - { - if (group.AlwaysApplies) - { - result = result.Concat(group.Options.Select(o => o.PowerUpDefinition ?? throw Error.NotInitializedProperty(o, nameof(o.PowerUpDefinition)))); - - continue; - } + var alwaysGroups = activeItems.SelectMany(i => i.Definition!.PossibleItemSetGroups).Where(i => i.AlwaysApplies).Distinct(); - var itemsOfGroup = activeItems.Where(i => i.ItemSetGroups.Any(ios => ios.ItemSetGroup == group) - && (group.SetLevel == 0 || i.Level >= group.SetLevel)); + foreach (var group in alwaysGroups.Concat(itemGroups).Distinct()) + { + var itemsOfGroup = activeItems.Where(i => + ((group.AlwaysApplies && i.Definition!.PossibleItemSetGroups.Contains(group)) + || i.ItemSetGroups.Any(ios => ios.ItemSetGroup == group)) + && (group.SetLevel == 0 || i.Level >= group.SetLevel)); var setMustBeComplete = group.MinimumItemCount == group.Items.Count; if (group.SetLevel > 0 && setMustBeComplete && itemsOfGroup.All(i => i.Level > group.SetLevel)) { @@ -97,19 +94,27 @@ public IEnumerable GetSetPowerUps( continue; } + if (group.Options is not { } options) + { + this._logger.LogWarning("Options of set {group} is not initialized", group); + continue; + } + var itemCount = group.CountDistinct ? itemsOfGroup.Select(item => item.Definition).Distinct().Count() : itemsOfGroup.Count(); var setIsComplete = itemCount == group.Items.Count; if (setIsComplete) { // Take all options when the set is complete - result = result.Concat(group.Options.Select(o => o.PowerUpDefinition ?? throw Error.NotInitializedProperty(o, nameof(o.PowerUpDefinition)))); + result = result.Concat( + options.PossibleOptions + .Select(o => o.PowerUpDefinition ?? throw Error.NotInitializedProperty(o, nameof(o.PowerUpDefinition)))); continue; } if (itemCount >= group.MinimumItemCount) { // Take the first n-1 options - result = result.Concat(group.Options.OrderBy(o => o.Number) + result = result.Concat(options.PossibleOptions.OrderBy(o => o.Number) .Take(itemCount - 1) .Select(o => o.PowerUpDefinition ?? throw Error.NotInitializedProperty(o, nameof(o.PowerUpDefinition)))); } diff --git a/src/GameServer/RemoteView/IItemSerializer.cs b/src/GameServer/RemoteView/IItemSerializer.cs index f4843511d..251a6ed61 100644 --- a/src/GameServer/RemoteView/IItemSerializer.cs +++ b/src/GameServer/RemoteView/IItemSerializer.cs @@ -305,7 +305,7 @@ private static void ReadAncientOption(byte ancientByte, IContext persistenceCont var bonusLevel = (ancientByte & AncientBonusLevelMask) >> 2; var setDiscriminator = ancientByte & AncientDiscriminatorMask; var ancientSets = item.Definition!.PossibleItemSetGroups - .Where(set => set.Options.Any(o => o.OptionType == ItemOptionTypes.AncientOption)) + .Where(set => set.Options?.PossibleOptions.Any(o => o.OptionType == ItemOptionTypes.AncientOption) ?? false) .SelectMany(i => i.Items).Where(i => i.ItemDefinition == item.Definition) .Where(set => set.AncientSetDiscriminator == setDiscriminator).ToList(); if (ancientSets.Count > 1) diff --git a/src/Persistence/BasicModel/ItemSetGroup.Generated.cs b/src/Persistence/BasicModel/ItemSetGroup.Generated.cs index 700926f3b..305fe988a 100644 --- a/src/Persistence/BasicModel/ItemSetGroup.Generated.cs +++ b/src/Persistence/BasicModel/ItemSetGroup.Generated.cs @@ -25,27 +25,6 @@ public partial class ItemSetGroup : MUnique.OpenMU.DataModel.Configuration.Items /// public Guid Id { get; set; } - /// - /// Gets the raw collection of . - /// - [System.Text.Json.Serialization.JsonPropertyName("options")] - public ICollection RawOptions { get; } = new List(); - - /// - [System.Text.Json.Serialization.JsonIgnore] - public override ICollection Options - { - get => base.Options ??= new CollectionAdapter(this.RawOptions); - protected set - { - this.Options.Clear(); - foreach (var item in value) - { - this.Options.Add(item); - } - } - } - /// /// Gets the raw collection of . /// @@ -67,6 +46,24 @@ protected set } } + /// + /// Gets the raw object of . + /// + [System.Text.Json.Serialization.JsonPropertyName("options")] + public ItemOptionDefinition RawOptions + { + get => base.Options as ItemOptionDefinition; + set => base.Options = value; + } + + /// + [System.Text.Json.Serialization.JsonIgnore] + public override MUnique.OpenMU.DataModel.Configuration.Items.ItemOptionDefinition Options + { + get => base.Options; + set => base.Options = value; + } + /// public override MUnique.OpenMU.DataModel.Configuration.Items.ItemSetGroup Clone(MUnique.OpenMU.DataModel.Configuration.GameConfiguration gameConfiguration) { diff --git a/src/Persistence/EntityFramework/CachingRepositoryProvider.cs b/src/Persistence/EntityFramework/CachingRepositoryProvider.cs index 3af952867..46591978d 100644 --- a/src/Persistence/EntityFramework/CachingRepositoryProvider.cs +++ b/src/Persistence/EntityFramework/CachingRepositoryProvider.cs @@ -59,8 +59,9 @@ protected override void Initialize() this.RegisterRepository(new ConfigurationTypeRepository(this._parent, this.LoggerFactory, config => config.RawItemOptions)); this.RegisterRepository(new ConfigurationTypeRepository( - this._parent, this.LoggerFactory, - config => config.RawItemOptions.SelectMany(o => o.RawPossibleOptions).Concat(config.RawItemSetGroups.SelectMany(g => g.RawOptions)).Distinct().ToList())); + this._parent, + this.LoggerFactory, + config => config.RawItemOptions.SelectMany(o => o.RawPossibleOptions).Distinct().ToList())); this.RegisterRepository(new ConfigurationTypeRepository(this._parent, this.LoggerFactory, config => config.RawAttributes)); this.RegisterRepository(new ConfigurationTypeRepository(this._parent, this.LoggerFactory, config => config.RawDropItemGroups)); this.RegisterRepository(new ConfigurationTypeRepository(this._parent, this.LoggerFactory, config => config.RawCharacterClasses)); diff --git a/src/Persistence/EntityFramework/Migrations/20240602060055_FixItemOptions.Designer.cs b/src/Persistence/EntityFramework/Migrations/20240602060055_FixItemOptions.Designer.cs new file mode 100644 index 000000000..4c81d47ce --- /dev/null +++ b/src/Persistence/EntityFramework/Migrations/20240602060055_FixItemOptions.Designer.cs @@ -0,0 +1,4878 @@ +// +using System; +using MUnique.OpenMU.Persistence.EntityFramework; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace MUnique.OpenMU.Persistence.EntityFramework.Migrations +{ + [DbContext(typeof(EntityDataContext))] + [Migration("20240602060055_FixItemOptions")] + partial class FixItemOptions + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Account", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ChatBanUntil") + .HasColumnType("timestamp with time zone"); + + b.Property("EMail") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsVaultExtended") + .HasColumnType("boolean"); + + b.Property("LoginName") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("PasswordHash") + .IsRequired() + .HasColumnType("text"); + + b.Property("RegistrationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("SecurityCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("State") + .HasColumnType("integer"); + + b.Property("TimeZone") + .HasColumnType("smallint"); + + b.Property("VaultId") + .HasColumnType("uuid"); + + b.Property("VaultPassword") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("LoginName") + .IsUnique(); + + b.HasIndex("VaultId") + .IsUnique(); + + b.ToTable("Account", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AccountCharacterClass", b => + { + b.Property("AccountId") + .HasColumnType("uuid"); + + b.Property("CharacterClassId") + .HasColumnType("uuid"); + + b.HasKey("AccountId", "CharacterClassId"); + + b.HasIndex("CharacterClassId"); + + b.ToTable("AccountCharacterClass", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AppearanceData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CharacterClassId") + .HasColumnType("uuid"); + + b.Property("FullAncientSetEquipped") + .HasColumnType("boolean"); + + b.Property("Pose") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("CharacterClassId"); + + b.ToTable("AppearanceData", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("Designation") + .HasColumnType("text"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.ToTable("AttributeDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeRelationship", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CharacterClassId") + .HasColumnType("uuid"); + + b.Property("InputAttributeId") + .HasColumnType("uuid"); + + b.Property("InputOperand") + .HasColumnType("real"); + + b.Property("InputOperator") + .HasColumnType("integer"); + + b.Property("OperandAttributeId") + .HasColumnType("uuid"); + + b.Property("PowerUpDefinitionValueId") + .HasColumnType("uuid"); + + b.Property("TargetAttributeId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CharacterClassId"); + + b.HasIndex("InputAttributeId"); + + b.HasIndex("OperandAttributeId"); + + b.HasIndex("PowerUpDefinitionValueId"); + + b.HasIndex("TargetAttributeId"); + + b.ToTable("AttributeRelationship", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeRequirement", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AttributeId") + .HasColumnType("uuid"); + + b.Property("GameMapDefinitionId") + .HasColumnType("uuid"); + + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.Property("MinimumValue") + .HasColumnType("integer"); + + b.Property("SkillId") + .HasColumnType("uuid"); + + b.Property("SkillId1") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("AttributeId"); + + b.HasIndex("GameMapDefinitionId"); + + b.HasIndex("ItemDefinitionId"); + + b.HasIndex("SkillId"); + + b.HasIndex("SkillId1"); + + b.ToTable("AttributeRequirement", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.BattleZoneDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("GroundId") + .HasColumnType("uuid"); + + b.Property("LeftGoalId") + .HasColumnType("uuid"); + + b.Property("LeftTeamSpawnPointX") + .HasColumnType("smallint"); + + b.Property("LeftTeamSpawnPointY") + .HasColumnType("smallint"); + + b.Property("RightGoalId") + .HasColumnType("uuid"); + + b.Property("RightTeamSpawnPointX") + .HasColumnType("smallint"); + + b.Property("RightTeamSpawnPointY") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("GroundId") + .IsUnique(); + + b.HasIndex("LeftGoalId") + .IsUnique(); + + b.HasIndex("RightGoalId") + .IsUnique(); + + b.ToTable("BattleZoneDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Character", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountId") + .HasColumnType("uuid"); + + b.Property("CharacterClassId") + .IsRequired() + .HasColumnType("uuid"); + + b.Property("CharacterSlot") + .HasColumnType("smallint"); + + b.Property("CharacterStatus") + .HasColumnType("integer"); + + b.Property("CreateDate") + .HasColumnType("timestamp with time zone"); + + b.Property("CurrentMapId") + .HasColumnType("uuid"); + + b.Property("Experience") + .HasColumnType("bigint"); + + b.Property("InventoryExtensions") + .HasColumnType("integer"); + + b.Property("InventoryId") + .HasColumnType("uuid"); + + b.Property("KeyConfiguration") + .HasColumnType("bytea"); + + b.Property("LevelUpPoints") + .HasColumnType("integer"); + + b.Property("MasterExperience") + .HasColumnType("bigint"); + + b.Property("MasterLevelUpPoints") + .HasColumnType("integer"); + + b.Property("MuHelperConfiguration") + .HasColumnType("bytea"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("PlayerKillCount") + .HasColumnType("integer"); + + b.Property("Pose") + .HasColumnType("smallint"); + + b.Property("PositionX") + .HasColumnType("smallint"); + + b.Property("PositionY") + .HasColumnType("smallint"); + + b.Property("State") + .HasColumnType("integer"); + + b.Property("StateRemainingSeconds") + .HasColumnType("integer"); + + b.Property("UsedFruitPoints") + .HasColumnType("integer"); + + b.Property("UsedNegFruitPoints") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("CharacterClassId"); + + b.HasIndex("CurrentMapId"); + + b.HasIndex("InventoryId") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Character", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CanGetCreated") + .HasColumnType("boolean"); + + b.Property("ComboDefinitionId") + .HasColumnType("uuid"); + + b.Property("CreationAllowedFlag") + .HasColumnType("smallint"); + + b.Property("FruitCalculation") + .HasColumnType("integer"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("HomeMapId") + .HasColumnType("uuid"); + + b.Property("IsMasterClass") + .HasColumnType("boolean"); + + b.Property("LevelRequirementByCreation") + .HasColumnType("smallint"); + + b.Property("LevelWarpRequirementReductionPercent") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("NextGenerationClassId") + .HasColumnType("uuid"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("ComboDefinitionId") + .IsUnique(); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("HomeMapId"); + + b.HasIndex("NextGenerationClassId"); + + b.ToTable("CharacterClass", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterDropItemGroup", b => + { + b.Property("CharacterId") + .HasColumnType("uuid"); + + b.Property("DropItemGroupId") + .HasColumnType("uuid"); + + b.HasKey("CharacterId", "DropItemGroupId"); + + b.HasIndex("DropItemGroupId"); + + b.ToTable("CharacterDropItemGroup", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterQuestState", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ActiveQuestId") + .HasColumnType("uuid"); + + b.Property("CharacterId") + .HasColumnType("uuid"); + + b.Property("ClientActionPerformed") + .HasColumnType("boolean"); + + b.Property("Group") + .HasColumnType("smallint"); + + b.Property("LastFinishedQuestId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ActiveQuestId"); + + b.HasIndex("CharacterId"); + + b.HasIndex("LastFinishedQuestId"); + + b.ToTable("CharacterQuestState", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ChatServerDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ClientCleanUpInterval") + .HasColumnType("interval"); + + b.Property("ClientTimeout") + .HasColumnType("interval"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("MaximumConnections") + .HasColumnType("integer"); + + b.Property("RoomCleanUpInterval") + .HasColumnType("interval"); + + b.Property("ServerId") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.ToTable("ChatServerDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ChatServerEndpoint", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ChatServerDefinitionId") + .HasColumnType("uuid"); + + b.Property("ClientId") + .HasColumnType("uuid"); + + b.Property("NetworkPort") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ChatServerDefinitionId"); + + b.HasIndex("ClientId"); + + b.ToTable("ChatServerEndpoint", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.CombinationBonusRequirement", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ItemOptionCombinationBonusId") + .HasColumnType("uuid"); + + b.Property("MinimumCount") + .HasColumnType("integer"); + + b.Property("OptionTypeId") + .HasColumnType("uuid"); + + b.Property("SubOptionType") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ItemOptionCombinationBonusId"); + + b.HasIndex("OptionTypeId"); + + b.ToTable("CombinationBonusRequirement", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ConfigurationUpdate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("InstalledAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Version") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("ConfigurationUpdate", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ConfigurationUpdateState", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CurrentInstalledVersion") + .HasColumnType("integer"); + + b.Property("InitializationKey") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("ConfigurationUpdateState", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ConnectServerDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CheckMaxConnectionsPerAddress") + .HasColumnType("boolean"); + + b.Property("ClientId") + .HasColumnType("uuid"); + + b.Property("ClientListenerPort") + .HasColumnType("integer"); + + b.Property("CurrentPatchVersion") + .HasColumnType("bytea"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("DisconnectOnUnknownPacket") + .HasColumnType("boolean"); + + b.Property("ListenerBacklog") + .HasColumnType("integer"); + + b.Property("MaxConnections") + .HasColumnType("integer"); + + b.Property("MaxConnectionsPerAddress") + .HasColumnType("integer"); + + b.Property("MaxFtpRequests") + .HasColumnType("integer"); + + b.Property("MaxIpRequests") + .HasColumnType("integer"); + + b.Property("MaxServerListRequests") + .HasColumnType("integer"); + + b.Property("MaximumReceiveSize") + .HasColumnType("smallint"); + + b.Property("PatchAddress") + .IsRequired() + .HasColumnType("text"); + + b.Property("ServerId") + .HasColumnType("smallint"); + + b.Property("Timeout") + .HasColumnType("interval"); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ConnectServerDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ConstValueAttribute", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CharacterClassId") + .HasColumnType("uuid"); + + b.Property("DefinitionId") + .HasColumnType("uuid"); + + b.Property("Value") + .HasColumnType("real"); + + b.HasKey("Id"); + + b.HasIndex("CharacterClassId"); + + b.HasIndex("DefinitionId"); + + b.ToTable("ConstValueAttribute", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.DropItemGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Chance") + .HasColumnType("double precision"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("ItemLevel") + .HasColumnType("smallint"); + + b.Property("ItemType") + .HasColumnType("integer"); + + b.Property("MaximumMonsterLevel") + .HasColumnType("smallint"); + + b.Property("MinimumMonsterLevel") + .HasColumnType("smallint"); + + b.Property("MonsterId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("MonsterId"); + + b.ToTable("DropItemGroup", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.DropItemGroupItemDefinition", b => + { + b.Property("DropItemGroupId") + .HasColumnType("uuid"); + + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.HasKey("DropItemGroupId", "ItemDefinitionId"); + + b.HasIndex("ItemDefinitionId"); + + b.ToTable("DropItemGroupItemDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.EnterGate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("GameMapDefinitionId") + .HasColumnType("uuid"); + + b.Property("LevelRequirement") + .HasColumnType("smallint"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.Property("TargetGateId") + .HasColumnType("uuid"); + + b.Property("X1") + .HasColumnType("smallint"); + + b.Property("X2") + .HasColumnType("smallint"); + + b.Property("Y1") + .HasColumnType("smallint"); + + b.Property("Y2") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("GameMapDefinitionId"); + + b.HasIndex("TargetGateId"); + + b.ToTable("EnterGate", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ExitGate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Direction") + .HasColumnType("integer"); + + b.Property("IsSpawnGate") + .HasColumnType("boolean"); + + b.Property("MapId") + .HasColumnType("uuid"); + + b.Property("X1") + .HasColumnType("smallint"); + + b.Property("X2") + .HasColumnType("smallint"); + + b.Property("Y1") + .HasColumnType("smallint"); + + b.Property("Y2") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("MapId"); + + b.ToTable("ExitGate", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Friend", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Accepted") + .HasColumnType("boolean"); + + b.Property("CharacterId") + .HasColumnType("uuid"); + + b.Property("FriendId") + .HasColumnType("uuid"); + + b.Property("RequestOpen") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.HasAlternateKey("CharacterId", "FriendId"); + + b.ToTable("Friend", "friend"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameClientDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("Episode") + .HasColumnType("smallint"); + + b.Property("Language") + .HasColumnType("integer"); + + b.Property("Season") + .HasColumnType("smallint"); + + b.Property("Serial") + .HasColumnType("bytea"); + + b.Property("Version") + .HasColumnType("bytea"); + + b.HasKey("Id"); + + b.ToTable("GameClientDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AreaSkillHitsPlayer") + .HasColumnType("boolean"); + + b.Property("CharacterNameRegex") + .HasColumnType("text"); + + b.Property("DamagePerOneItemDurability") + .HasColumnType("double precision"); + + b.Property("DamagePerOnePetDurability") + .HasColumnType("double precision"); + + b.Property("ExperienceRate") + .HasColumnType("real"); + + b.Property("HitsPerOneItemDurability") + .HasColumnType("double precision"); + + b.Property("InfoRange") + .HasColumnType("smallint"); + + b.Property("ItemDropDuration") + .ValueGeneratedOnAdd() + .HasColumnType("interval") + .HasDefaultValue(new TimeSpan(0, 0, 1, 0, 0)); + + b.Property("LetterSendPrice") + .HasColumnType("integer"); + + b.Property("MaximumCharactersPerAccount") + .HasColumnType("smallint"); + + b.Property("MaximumInventoryMoney") + .HasColumnType("integer"); + + b.Property("MaximumLetters") + .HasColumnType("integer"); + + b.Property("MaximumLevel") + .HasColumnType("smallint"); + + b.Property("MaximumMasterLevel") + .HasColumnType("smallint"); + + b.Property("MaximumPartySize") + .HasColumnType("smallint"); + + b.Property("MaximumPasswordLength") + .HasColumnType("integer"); + + b.Property("MaximumVaultMoney") + .HasColumnType("integer"); + + b.Property("MinimumMonsterLevelForMasterExperience") + .HasColumnType("smallint"); + + b.Property("RecoveryInterval") + .HasColumnType("integer"); + + b.Property("ShouldDropMoney") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("GameConfiguration", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BattleZoneId") + .HasColumnType("uuid"); + + b.Property("Discriminator") + .HasColumnType("integer"); + + b.Property("ExpMultiplier") + .HasColumnType("double precision"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.Property("SafezoneMapId") + .HasColumnType("uuid"); + + b.Property("TerrainData") + .HasColumnType("bytea"); + + b.HasKey("Id"); + + b.HasIndex("BattleZoneId") + .IsUnique(); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("SafezoneMapId"); + + b.ToTable("GameMapDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinitionDropItemGroup", b => + { + b.Property("GameMapDefinitionId") + .HasColumnType("uuid"); + + b.Property("DropItemGroupId") + .HasColumnType("uuid"); + + b.HasKey("GameMapDefinitionId", "DropItemGroupId"); + + b.HasIndex("DropItemGroupId"); + + b.ToTable("GameMapDefinitionDropItemGroup", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("MaximumPlayers") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.ToTable("GameServerConfiguration", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerConfigurationGameMapDefinition", b => + { + b.Property("GameServerConfigurationId") + .HasColumnType("uuid"); + + b.Property("GameMapDefinitionId") + .HasColumnType("uuid"); + + b.HasKey("GameServerConfigurationId", "GameMapDefinitionId"); + + b.HasIndex("GameMapDefinitionId"); + + b.ToTable("GameServerConfigurationGameMapDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("ExperienceRate") + .HasColumnType("real"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("ServerConfigurationId") + .HasColumnType("uuid"); + + b.Property("ServerID") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("ServerConfigurationId"); + + b.ToTable("GameServerDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerEndpoint", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AlternativePublishedPort") + .HasColumnType("integer"); + + b.Property("ClientId") + .HasColumnType("uuid"); + + b.Property("GameServerDefinitionId") + .HasColumnType("uuid"); + + b.Property("NetworkPort") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.HasIndex("GameServerDefinitionId"); + + b.ToTable("GameServerEndpoint", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Guild", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AllianceGuildId") + .HasColumnType("uuid"); + + b.Property("HostilityId") + .HasColumnType("uuid"); + + b.Property("Logo") + .HasColumnType("bytea"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(8) + .HasColumnType("character varying(8)"); + + b.Property("Notice") + .HasColumnType("text"); + + b.Property("Score") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("AllianceGuildId"); + + b.HasIndex("HostilityId"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Guild", "guild"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GuildMember", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("GuildId") + .HasColumnType("uuid"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("GuildId"); + + b.ToTable("GuildMember", "guild"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.IncreasableItemOption", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ItemOptionDefinitionId") + .HasColumnType("uuid"); + + b.Property("ItemSetGroupId") + .HasColumnType("uuid"); + + b.Property("LevelType") + .HasColumnType("integer"); + + b.Property("Number") + .HasColumnType("integer"); + + b.Property("OptionTypeId") + .HasColumnType("uuid"); + + b.Property("PowerUpDefinitionId") + .HasColumnType("uuid"); + + b.Property("SubOptionType") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ItemOptionDefinitionId"); + + b.HasIndex("ItemSetGroupId"); + + b.HasIndex("OptionTypeId"); + + b.HasIndex("PowerUpDefinitionId") + .IsUnique(); + + b.ToTable("IncreasableItemOption", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Item", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DefinitionId") + .HasColumnType("uuid"); + + b.Property("Durability") + .HasColumnType("double precision"); + + b.Property("HasSkill") + .HasColumnType("boolean"); + + b.Property("ItemSlot") + .HasColumnType("smallint"); + + b.Property("ItemStorageId") + .HasColumnType("uuid"); + + b.Property("Level") + .HasColumnType("smallint"); + + b.Property("PetExperience") + .HasColumnType("integer"); + + b.Property("SocketCount") + .HasColumnType("integer"); + + b.Property("StorePrice") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("DefinitionId"); + + b.HasIndex("ItemStorageId"); + + b.ToTable("Item", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemAppearance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AppearanceDataId") + .HasColumnType("uuid"); + + b.Property("DefinitionId") + .HasColumnType("uuid"); + + b.Property("ItemSlot") + .HasColumnType("smallint"); + + b.Property("Level") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("AppearanceDataId"); + + b.HasIndex("DefinitionId"); + + b.ToTable("ItemAppearance", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemAppearanceItemOptionType", b => + { + b.Property("ItemAppearanceId") + .HasColumnType("uuid"); + + b.Property("ItemOptionTypeId") + .HasColumnType("uuid"); + + b.HasKey("ItemAppearanceId", "ItemOptionTypeId"); + + b.HasIndex("ItemOptionTypeId"); + + b.ToTable("ItemAppearanceItemOptionType", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemBasePowerUpDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BaseValue") + .HasColumnType("real"); + + b.Property("BonusPerLevelTableId") + .HasColumnType("uuid"); + + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.Property("TargetAttributeId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("BonusPerLevelTableId"); + + b.HasIndex("ItemDefinitionId"); + + b.HasIndex("TargetAttributeId"); + + b.ToTable("ItemBasePowerUpDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCrafting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ItemCraftingHandlerClassName") + .IsRequired() + .HasColumnType("text"); + + b.Property("MonsterDefinitionId") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.Property("SimpleCraftingSettingsId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("MonsterDefinitionId"); + + b.HasIndex("SimpleCraftingSettingsId") + .IsUnique(); + + b.ToTable("ItemCrafting", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingRequiredItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AddPercentage") + .HasColumnType("smallint"); + + b.Property("FailResult") + .HasColumnType("integer"); + + b.Property("MaximumAmount") + .HasColumnType("smallint"); + + b.Property("MaximumItemLevel") + .HasColumnType("smallint"); + + b.Property("MinimumAmount") + .HasColumnType("smallint"); + + b.Property("MinimumItemLevel") + .HasColumnType("smallint"); + + b.Property("NpcPriceDivisor") + .HasColumnType("integer"); + + b.Property("Reference") + .HasColumnType("smallint"); + + b.Property("SimpleCraftingSettingsId") + .HasColumnType("uuid"); + + b.Property("SuccessResult") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("SimpleCraftingSettingsId"); + + b.ToTable("ItemCraftingRequiredItem", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingRequiredItemItemDefinition", b => + { + b.Property("ItemCraftingRequiredItemId") + .HasColumnType("uuid"); + + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.HasKey("ItemCraftingRequiredItemId", "ItemDefinitionId"); + + b.HasIndex("ItemDefinitionId"); + + b.ToTable("ItemCraftingRequiredItemItemDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingRequiredItemItemOptionType", b => + { + b.Property("ItemCraftingRequiredItemId") + .HasColumnType("uuid"); + + b.Property("ItemOptionTypeId") + .HasColumnType("uuid"); + + b.HasKey("ItemCraftingRequiredItemId", "ItemOptionTypeId"); + + b.HasIndex("ItemOptionTypeId"); + + b.ToTable("ItemCraftingRequiredItemItemOptionType", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingResultItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AddLevel") + .HasColumnType("smallint"); + + b.Property("Durability") + .HasColumnType("smallint"); + + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.Property("RandomMaximumLevel") + .HasColumnType("smallint"); + + b.Property("RandomMinimumLevel") + .HasColumnType("smallint"); + + b.Property("Reference") + .HasColumnType("smallint"); + + b.Property("SimpleCraftingSettingsId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ItemDefinitionId"); + + b.HasIndex("SimpleCraftingSettingsId"); + + b.ToTable("ItemCraftingResultItem", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConsumeEffectId") + .HasColumnType("uuid"); + + b.Property("DropLevel") + .HasColumnType("smallint"); + + b.Property("DropsFromMonsters") + .HasColumnType("boolean"); + + b.Property("Durability") + .HasColumnType("smallint"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("Group") + .HasColumnType("smallint"); + + b.Property("Height") + .HasColumnType("smallint"); + + b.Property("IsAmmunition") + .HasColumnType("boolean"); + + b.Property("IsBoundToCharacter") + .HasColumnType("boolean"); + + b.Property("ItemSlotId") + .HasColumnType("uuid"); + + b.Property("MaximumItemLevel") + .HasColumnType("smallint"); + + b.Property("MaximumSockets") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.Property("PetExperienceFormula") + .HasColumnType("text"); + + b.Property("SkillId") + .HasColumnType("uuid"); + + b.Property("StorageLimitPerCharacter") + .HasColumnType("integer"); + + b.Property("Value") + .HasColumnType("integer"); + + b.Property("Width") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("ConsumeEffectId"); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("ItemSlotId"); + + b.HasIndex("SkillId"); + + b.ToTable("ItemDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinitionCharacterClass", b => + { + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.Property("CharacterClassId") + .HasColumnType("uuid"); + + b.HasKey("ItemDefinitionId", "CharacterClassId"); + + b.HasIndex("CharacterClassId"); + + b.ToTable("ItemDefinitionCharacterClass", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinitionItemOptionDefinition", b => + { + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.Property("ItemOptionDefinitionId") + .HasColumnType("uuid"); + + b.HasKey("ItemDefinitionId", "ItemOptionDefinitionId"); + + b.HasIndex("ItemOptionDefinitionId"); + + b.ToTable("ItemDefinitionItemOptionDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinitionItemSetGroup", b => + { + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.Property("ItemSetGroupId") + .HasColumnType("uuid"); + + b.HasKey("ItemDefinitionId", "ItemSetGroupId"); + + b.HasIndex("ItemSetGroupId"); + + b.ToTable("ItemDefinitionItemSetGroup", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDropItemGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Chance") + .HasColumnType("double precision"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("DropEffect") + .HasColumnType("integer"); + + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.Property("ItemLevel") + .HasColumnType("smallint"); + + b.Property("ItemType") + .HasColumnType("integer"); + + b.Property("MaximumLevel") + .HasColumnType("smallint"); + + b.Property("MaximumMonsterLevel") + .HasColumnType("smallint"); + + b.Property("MinimumLevel") + .HasColumnType("smallint"); + + b.Property("MinimumMonsterLevel") + .HasColumnType("smallint"); + + b.Property("MoneyAmount") + .HasColumnType("integer"); + + b.Property("MonsterId") + .HasColumnType("uuid"); + + b.Property("RequiredCharacterLevel") + .HasColumnType("smallint"); + + b.Property("SourceItemLevel") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("ItemDefinitionId"); + + b.HasIndex("MonsterId"); + + b.ToTable("ItemDropItemGroup", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDropItemGroupItemDefinition", b => + { + b.Property("ItemDropItemGroupId") + .HasColumnType("uuid"); + + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.HasKey("ItemDropItemGroupId", "ItemDefinitionId"); + + b.HasIndex("ItemDefinitionId"); + + b.ToTable("ItemDropItemGroupItemDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemItemOfItemSet", b => + { + b.Property("ItemId") + .HasColumnType("uuid"); + + b.Property("ItemOfItemSetId") + .HasColumnType("uuid"); + + b.HasKey("ItemId", "ItemOfItemSetId"); + + b.HasIndex("ItemOfItemSetId"); + + b.ToTable("ItemItemOfItemSet", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemLevelBonusTable", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.ToTable("ItemLevelBonusTable", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOfItemSet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AncientSetDiscriminator") + .HasColumnType("integer"); + + b.Property("BonusOptionId") + .HasColumnType("uuid"); + + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.Property("ItemSetGroupId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("BonusOptionId"); + + b.HasIndex("ItemDefinitionId"); + + b.HasIndex("ItemSetGroupId"); + + b.ToTable("ItemOfItemSet", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOption", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Number") + .HasColumnType("integer"); + + b.Property("OptionTypeId") + .HasColumnType("uuid"); + + b.Property("PowerUpDefinitionId") + .HasColumnType("uuid"); + + b.Property("SubOptionType") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("OptionTypeId"); + + b.HasIndex("PowerUpDefinitionId") + .IsUnique(); + + b.ToTable("ItemOption", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionCombinationBonus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AppliesMultipleTimes") + .HasColumnType("boolean"); + + b.Property("BonusId") + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("Number") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("BonusId") + .IsUnique(); + + b.HasIndex("GameConfigurationId"); + + b.ToTable("ItemOptionCombinationBonus", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AddChance") + .HasColumnType("real"); + + b.Property("AddsRandomly") + .HasColumnType("boolean"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("MaximumOptionsPerItem") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.ToTable("ItemOptionDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionLink", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Index") + .HasColumnType("integer"); + + b.Property("ItemId") + .HasColumnType("uuid"); + + b.Property("ItemOptionId") + .HasColumnType("uuid"); + + b.Property("Level") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ItemId"); + + b.HasIndex("ItemOptionId"); + + b.ToTable("ItemOptionLink", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionOfLevel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("IncreasableItemOptionId") + .HasColumnType("uuid"); + + b.Property("Level") + .HasColumnType("integer"); + + b.Property("PowerUpDefinitionId") + .HasColumnType("uuid"); + + b.Property("RequiredItemLevel") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("IncreasableItemOptionId"); + + b.HasIndex("PowerUpDefinitionId") + .IsUnique(); + + b.ToTable("ItemOptionOfLevel", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("IsVisible") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.ToTable("ItemOptionType", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemSetGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AlwaysApplies") + .HasColumnType("boolean"); + + b.Property("CountDistinct") + .HasColumnType("boolean"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("MinimumItemCount") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("SetLevel") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.ToTable("ItemSetGroup", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemSlotType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("RawItemSlots") + .HasColumnType("text") + .HasColumnName("ItemSlots") + .HasAnnotation("Relational:JsonPropertyName", "itemSlots"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.ToTable("ItemSlotType", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemStorage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Money") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("ItemStorage", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.JewelMix", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("MixedJewelId") + .HasColumnType("uuid"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.Property("SingleJewelId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("MixedJewelId"); + + b.HasIndex("SingleJewelId"); + + b.ToTable("JewelMix", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.LetterBody", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Animation") + .HasColumnType("smallint"); + + b.Property("HeaderId") + .HasColumnType("uuid"); + + b.Property("Message") + .IsRequired() + .HasColumnType("text"); + + b.Property("Rotation") + .HasColumnType("smallint"); + + b.Property("SenderAppearanceId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("HeaderId"); + + b.HasIndex("SenderAppearanceId") + .IsUnique(); + + b.ToTable("LetterBody", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.LetterHeader", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CharacterId") + .HasColumnType("uuid"); + + b.Property("LetterDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ReadFlag") + .HasColumnType("boolean"); + + b.Property("ReceiverId") + .HasColumnType("uuid"); + + b.Property("SenderName") + .HasColumnType("text"); + + b.Property("Subject") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ReceiverId"); + + b.ToTable("LetterHeader", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.LevelBonus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AdditionalValue") + .HasColumnType("real"); + + b.Property("ItemLevelBonusTableId") + .HasColumnType("uuid"); + + b.Property("Level") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ItemLevelBonusTableId"); + + b.ToTable("LevelBonus", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MagicEffectDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DurationId") + .HasColumnType("uuid"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("InformObservers") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.Property("SendDuration") + .HasColumnType("boolean"); + + b.Property("StopByDeath") + .HasColumnType("boolean"); + + b.Property("SubType") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("DurationId") + .IsUnique(); + + b.HasIndex("GameConfigurationId"); + + b.ToTable("MagicEffectDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MasterSkillDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Aggregation") + .HasColumnType("integer"); + + b.Property("DisplayValueFormula") + .IsRequired() + .HasColumnType("text"); + + b.Property("MaximumLevel") + .HasColumnType("smallint"); + + b.Property("MinimumLevel") + .HasColumnType("smallint"); + + b.Property("Rank") + .HasColumnType("smallint"); + + b.Property("ReplacedSkillId") + .HasColumnType("uuid"); + + b.Property("RootId") + .HasColumnType("uuid"); + + b.Property("TargetAttributeId") + .HasColumnType("uuid"); + + b.Property("ValueFormula") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ReplacedSkillId"); + + b.HasIndex("RootId"); + + b.HasIndex("TargetAttributeId"); + + b.ToTable("MasterSkillDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MasterSkillDefinitionSkill", b => + { + b.Property("MasterSkillDefinitionId") + .HasColumnType("uuid"); + + b.Property("SkillId") + .HasColumnType("uuid"); + + b.HasKey("MasterSkillDefinitionId", "SkillId"); + + b.HasIndex("SkillId"); + + b.ToTable("MasterSkillDefinitionSkill", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MasterSkillRoot", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.ToTable("MasterSkillRoot", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameChangeEvent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("Index") + .HasColumnType("integer"); + + b.Property("Message") + .HasColumnType("text"); + + b.Property("MiniGameDefinitionId") + .HasColumnType("uuid"); + + b.Property("MinimumTargetLevel") + .HasColumnType("smallint"); + + b.Property("MultiplyKillsByPlayers") + .HasColumnType("boolean"); + + b.Property("NumberOfKills") + .HasColumnType("smallint"); + + b.Property("SpawnAreaId") + .HasColumnType("uuid"); + + b.Property("Target") + .HasColumnType("integer"); + + b.Property("TargetDefinitionId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("MiniGameDefinitionId"); + + b.HasIndex("SpawnAreaId") + .IsUnique(); + + b.HasIndex("TargetDefinitionId"); + + b.ToTable("MiniGameChangeEvent", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AllowParty") + .HasColumnType("boolean"); + + b.Property("ArePlayerKillersAllowedToEnter") + .HasColumnType("boolean"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("EnterDuration") + .HasColumnType("interval"); + + b.Property("EntranceFee") + .HasColumnType("integer"); + + b.Property("EntranceId") + .HasColumnType("uuid"); + + b.Property("ExitDuration") + .HasColumnType("interval"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("GameDuration") + .HasColumnType("interval"); + + b.Property("GameLevel") + .HasColumnType("smallint"); + + b.Property("MapCreationPolicy") + .HasColumnType("integer"); + + b.Property("MaximumCharacterLevel") + .HasColumnType("integer"); + + b.Property("MaximumPlayerCount") + .HasColumnType("integer"); + + b.Property("MaximumSpecialCharacterLevel") + .HasColumnType("integer"); + + b.Property("MinimumCharacterLevel") + .HasColumnType("integer"); + + b.Property("MinimumSpecialCharacterLevel") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("RequiresMasterClass") + .HasColumnType("boolean"); + + b.Property("SaveRankingStatistics") + .HasColumnType("boolean"); + + b.Property("TicketItemId") + .HasColumnType("uuid"); + + b.Property("TicketItemLevel") + .HasColumnType("integer"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("EntranceId"); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("TicketItemId"); + + b.ToTable("MiniGameDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameRankingEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CharacterId") + .HasColumnType("uuid"); + + b.Property("GameInstanceId") + .HasColumnType("uuid"); + + b.Property("MiniGameId") + .HasColumnType("uuid"); + + b.Property("Rank") + .HasColumnType("integer"); + + b.Property("Score") + .HasColumnType("integer"); + + b.Property("Timestamp") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("CharacterId"); + + b.HasIndex("MiniGameId"); + + b.ToTable("MiniGameRankingEntry", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameReward", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ItemRewardId") + .HasColumnType("uuid"); + + b.Property("MiniGameDefinitionId") + .HasColumnType("uuid"); + + b.Property("Rank") + .HasColumnType("integer"); + + b.Property("RequiredKillId") + .HasColumnType("uuid"); + + b.Property("RequiredSuccess") + .HasColumnType("integer"); + + b.Property("RewardAmount") + .HasColumnType("integer"); + + b.Property("RewardType") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ItemRewardId"); + + b.HasIndex("MiniGameDefinitionId"); + + b.HasIndex("RequiredKillId"); + + b.ToTable("MiniGameReward", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameSpawnWave", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("EndTime") + .HasColumnType("interval"); + + b.Property("Message") + .HasColumnType("text"); + + b.Property("MiniGameDefinitionId") + .HasColumnType("uuid"); + + b.Property("StartTime") + .HasColumnType("interval"); + + b.Property("WaveNumber") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("MiniGameDefinitionId"); + + b.ToTable("MiniGameSpawnWave", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameTerrainChange", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("EndX") + .HasColumnType("smallint"); + + b.Property("EndY") + .HasColumnType("smallint"); + + b.Property("IsClientUpdateRequired") + .HasColumnType("boolean"); + + b.Property("MiniGameChangeEventId") + .HasColumnType("uuid"); + + b.Property("SetTerrainAttribute") + .HasColumnType("boolean"); + + b.Property("StartX") + .HasColumnType("smallint"); + + b.Property("StartY") + .HasColumnType("smallint"); + + b.Property("TerrainAttribute") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("MiniGameChangeEventId"); + + b.ToTable("MiniGameTerrainChange", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterAttribute", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AttributeDefinitionId") + .HasColumnType("uuid"); + + b.Property("MonsterDefinitionId") + .HasColumnType("uuid"); + + b.Property("Value") + .HasColumnType("real"); + + b.HasKey("Id"); + + b.HasIndex("AttributeDefinitionId"); + + b.HasIndex("MonsterDefinitionId"); + + b.ToTable("MonsterAttribute", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AttackDelay") + .HasColumnType("interval"); + + b.Property("AttackRange") + .HasColumnType("smallint"); + + b.Property("AttackSkillId") + .HasColumnType("uuid"); + + b.Property("Attribute") + .HasColumnType("smallint"); + + b.Property("Designation") + .IsRequired() + .HasColumnType("text"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("IntelligenceTypeName") + .HasColumnType("text"); + + b.Property("MerchantStoreId") + .HasColumnType("uuid"); + + b.Property("MoveDelay") + .HasColumnType("interval"); + + b.Property("MoveRange") + .HasColumnType("smallint"); + + b.Property("NpcWindow") + .HasColumnType("integer"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.Property("NumberOfMaximumItemDrops") + .HasColumnType("integer"); + + b.Property("ObjectKind") + .HasColumnType("integer"); + + b.Property("RespawnDelay") + .HasColumnType("interval"); + + b.Property("ViewRange") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("AttackSkillId"); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("MerchantStoreId") + .IsUnique(); + + b.ToTable("MonsterDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinitionDropItemGroup", b => + { + b.Property("MonsterDefinitionId") + .HasColumnType("uuid"); + + b.Property("DropItemGroupId") + .HasColumnType("uuid"); + + b.HasKey("MonsterDefinitionId", "DropItemGroupId"); + + b.HasIndex("DropItemGroupId"); + + b.ToTable("MonsterDefinitionDropItemGroup", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterSpawnArea", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Direction") + .HasColumnType("integer"); + + b.Property("GameMapDefinitionId") + .HasColumnType("uuid"); + + b.Property("GameMapId") + .HasColumnType("uuid"); + + b.Property("MaximumHealthOverride") + .HasColumnType("integer"); + + b.Property("MonsterDefinitionId") + .HasColumnType("uuid"); + + b.Property("Quantity") + .HasColumnType("smallint"); + + b.Property("SpawnTrigger") + .HasColumnType("integer"); + + b.Property("WaveNumber") + .HasColumnType("smallint"); + + b.Property("X1") + .HasColumnType("smallint"); + + b.Property("X2") + .HasColumnType("smallint"); + + b.Property("Y1") + .HasColumnType("smallint"); + + b.Property("Y2") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("GameMapDefinitionId"); + + b.HasIndex("GameMapId"); + + b.HasIndex("MonsterDefinitionId"); + + b.ToTable("MonsterSpawnArea", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.PlugInConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CustomConfiguration") + .HasColumnType("text"); + + b.Property("CustomPlugInSource") + .HasColumnType("text"); + + b.Property("ExternalAssemblyName") + .HasColumnType("text"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("TypeId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.ToTable("PlugInConfiguration", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BoostId") + .HasColumnType("uuid"); + + b.Property("GameMapDefinitionId") + .HasColumnType("uuid"); + + b.Property("MagicEffectDefinitionId") + .HasColumnType("uuid"); + + b.Property("TargetAttributeId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("BoostId") + .IsUnique(); + + b.HasIndex("GameMapDefinitionId"); + + b.HasIndex("MagicEffectDefinitionId"); + + b.HasIndex("TargetAttributeId"); + + b.ToTable("PowerUpDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinitionValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AggregateType") + .HasColumnType("integer"); + + b.Property("Value") + .HasColumnType("real"); + + b.HasKey("Id"); + + b.ToTable("PowerUpDefinitionValue", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Group") + .HasColumnType("smallint"); + + b.Property("MaximumCharacterLevel") + .HasColumnType("integer"); + + b.Property("MinimumCharacterLevel") + .HasColumnType("integer"); + + b.Property("MonsterDefinitionId") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.Property("QualifiedCharacterId") + .HasColumnType("uuid"); + + b.Property("QuestGiverId") + .HasColumnType("uuid"); + + b.Property("RefuseNumber") + .HasColumnType("smallint"); + + b.Property("Repeatable") + .HasColumnType("boolean"); + + b.Property("RequiredStartMoney") + .HasColumnType("integer"); + + b.Property("RequiresClientAction") + .HasColumnType("boolean"); + + b.Property("StartingNumber") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("MonsterDefinitionId"); + + b.HasIndex("QualifiedCharacterId"); + + b.HasIndex("QuestGiverId"); + + b.ToTable("QuestDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestItemRequirement", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DropItemGroupId") + .HasColumnType("uuid"); + + b.Property("ItemId") + .HasColumnType("uuid"); + + b.Property("MinimumNumber") + .HasColumnType("integer"); + + b.Property("QuestDefinitionId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("DropItemGroupId"); + + b.HasIndex("ItemId"); + + b.HasIndex("QuestDefinitionId"); + + b.ToTable("QuestItemRequirement", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestMonsterKillRequirement", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("MinimumNumber") + .HasColumnType("integer"); + + b.Property("MonsterId") + .HasColumnType("uuid"); + + b.Property("QuestDefinitionId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("MonsterId"); + + b.HasIndex("QuestDefinitionId"); + + b.ToTable("QuestMonsterKillRequirement", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestMonsterKillRequirementState", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CharacterQuestStateId") + .HasColumnType("uuid"); + + b.Property("KillCount") + .HasColumnType("integer"); + + b.Property("RequirementId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CharacterQuestStateId"); + + b.HasIndex("RequirementId"); + + b.ToTable("QuestMonsterKillRequirementState", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestReward", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AttributeRewardId") + .HasColumnType("uuid"); + + b.Property("ItemRewardId") + .HasColumnType("uuid"); + + b.Property("QuestDefinitionId") + .HasColumnType("uuid"); + + b.Property("RewardType") + .HasColumnType("integer"); + + b.Property("SkillRewardId") + .HasColumnType("uuid"); + + b.Property("Value") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("AttributeRewardId"); + + b.HasIndex("ItemRewardId") + .IsUnique(); + + b.HasIndex("QuestDefinitionId"); + + b.HasIndex("SkillRewardId"); + + b.ToTable("QuestReward", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Rectangle", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("X1") + .HasColumnType("smallint"); + + b.Property("X2") + .HasColumnType("smallint"); + + b.Property("Y1") + .HasColumnType("smallint"); + + b.Property("Y2") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.ToTable("Rectangle", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SimpleCraftingSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("MaximumSuccessPercent") + .HasColumnType("smallint"); + + b.Property("Money") + .HasColumnType("integer"); + + b.Property("MoneyPerFinalSuccessPercentage") + .HasColumnType("integer"); + + b.Property("MultipleAllowed") + .HasColumnType("boolean"); + + b.Property("ResultItemExcellentOptionChance") + .HasColumnType("smallint"); + + b.Property("ResultItemLuckOptionChance") + .HasColumnType("smallint"); + + b.Property("ResultItemMaxExcOptionCount") + .HasColumnType("smallint"); + + b.Property("ResultItemSelect") + .HasColumnType("integer"); + + b.Property("ResultItemSkillChance") + .HasColumnType("smallint"); + + b.Property("SuccessPercent") + .HasColumnType("smallint"); + + b.Property("SuccessPercentageAdditionForAncientItem") + .HasColumnType("integer"); + + b.Property("SuccessPercentageAdditionForExcellentItem") + .HasColumnType("integer"); + + b.Property("SuccessPercentageAdditionForLuck") + .HasColumnType("integer"); + + b.Property("SuccessPercentageAdditionForSocketItem") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("SimpleCraftingSettings", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AttackDamage") + .HasColumnType("integer"); + + b.Property("DamageType") + .HasColumnType("integer"); + + b.Property("ElementalModifierTargetId") + .HasColumnType("uuid"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("ImplicitTargetRange") + .HasColumnType("smallint"); + + b.Property("MagicEffectDefId") + .HasColumnType("uuid"); + + b.Property("MasterDefinitionId") + .HasColumnType("uuid"); + + b.Property("MovesTarget") + .HasColumnType("boolean"); + + b.Property("MovesToTarget") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.Property("Range") + .HasColumnType("smallint"); + + b.Property("SkillType") + .HasColumnType("integer"); + + b.Property("Target") + .HasColumnType("integer"); + + b.Property("TargetRestriction") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ElementalModifierTargetId"); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("MagicEffectDefId"); + + b.HasIndex("MasterDefinitionId") + .IsUnique(); + + b.ToTable("Skill", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillCharacterClass", b => + { + b.Property("SkillId") + .HasColumnType("uuid"); + + b.Property("CharacterClassId") + .HasColumnType("uuid"); + + b.HasKey("SkillId", "CharacterClassId"); + + b.HasIndex("CharacterClassId"); + + b.ToTable("SkillCharacterClass", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillComboDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("MaximumCompletionTime") + .HasColumnType("interval"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("SkillComboDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillComboStep", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("IsFinalStep") + .HasColumnType("boolean"); + + b.Property("Order") + .HasColumnType("integer"); + + b.Property("SkillComboDefinitionId") + .HasColumnType("uuid"); + + b.Property("SkillId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("SkillComboDefinitionId"); + + b.HasIndex("SkillId"); + + b.ToTable("SkillComboStep", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CharacterId") + .HasColumnType("uuid"); + + b.Property("Level") + .HasColumnType("integer"); + + b.Property("SkillId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CharacterId"); + + b.HasIndex("SkillId"); + + b.ToTable("SkillEntry", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.StatAttribute", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountId") + .HasColumnType("uuid"); + + b.Property("CharacterId") + .HasColumnType("uuid"); + + b.Property("DefinitionId") + .HasColumnType("uuid"); + + b.Property("Value") + .HasColumnType("real"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("CharacterId"); + + b.HasIndex("DefinitionId"); + + b.ToTable("StatAttribute", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.StatAttributeDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AttributeId") + .HasColumnType("uuid"); + + b.Property("BaseValue") + .HasColumnType("real"); + + b.Property("CharacterClassId") + .HasColumnType("uuid"); + + b.Property("IncreasableByPlayer") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.HasIndex("AttributeId"); + + b.HasIndex("CharacterClassId"); + + b.ToTable("StatAttributeDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SystemConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AutoStart") + .HasColumnType("boolean"); + + b.Property("AutoUpdateSchema") + .HasColumnType("boolean"); + + b.Property("IpResolver") + .HasColumnType("integer"); + + b.Property("IpResolverParameter") + .HasColumnType("text"); + + b.Property("ReadConsoleInput") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("SystemConfiguration", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.WarpInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Costs") + .HasColumnType("integer"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("GateId") + .HasColumnType("uuid"); + + b.Property("Index") + .HasColumnType("integer"); + + b.Property("LevelRequirement") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("GateId"); + + b.ToTable("WarpInfo", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Account", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemStorage", "RawVault") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.Account", "VaultId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawVault"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AccountCharacterClass", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Account", "Account") + .WithMany("JoinedUnlockedCharacterClasses") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", "CharacterClass") + .WithMany() + .HasForeignKey("CharacterClassId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("CharacterClass"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AppearanceData", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", "RawCharacterClass") + .WithMany() + .HasForeignKey("CharacterClassId"); + + b.Navigation("RawCharacterClass"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawAttributes") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeRelationship", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", null) + .WithMany("RawAttributeCombinations") + .HasForeignKey("CharacterClassId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawInputAttribute") + .WithMany() + .HasForeignKey("InputAttributeId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawOperandAttribute") + .WithMany() + .HasForeignKey("OperandAttributeId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinitionValue", null) + .WithMany("RawRelatedValues") + .HasForeignKey("PowerUpDefinitionValueId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawTargetAttribute") + .WithMany() + .HasForeignKey("TargetAttributeId"); + + b.Navigation("RawInputAttribute"); + + b.Navigation("RawOperandAttribute"); + + b.Navigation("RawTargetAttribute"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeRequirement", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawAttribute") + .WithMany() + .HasForeignKey("AttributeId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", null) + .WithMany("RawMapRequirements") + .HasForeignKey("GameMapDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", null) + .WithMany("RawRequirements") + .HasForeignKey("ItemDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", null) + .WithMany("RawConsumeRequirements") + .HasForeignKey("SkillId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", null) + .WithMany("RawRequirements") + .HasForeignKey("SkillId1") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawAttribute"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.BattleZoneDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Rectangle", "RawGround") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.BattleZoneDefinition", "GroundId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Rectangle", "RawLeftGoal") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.BattleZoneDefinition", "LeftGoalId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Rectangle", "RawRightGoal") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.BattleZoneDefinition", "RightGoalId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawGround"); + + b.Navigation("RawLeftGoal"); + + b.Navigation("RawRightGoal"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Character", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Account", null) + .WithMany("RawCharacters") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", "RawCharacterClass") + .WithMany() + .HasForeignKey("CharacterClassId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", "RawCurrentMap") + .WithMany() + .HasForeignKey("CurrentMapId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemStorage", "RawInventory") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.Character", "InventoryId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawCharacterClass"); + + b.Navigation("RawCurrentMap"); + + b.Navigation("RawInventory"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillComboDefinition", "RawComboDefinition") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", "ComboDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawCharacterClasses") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", "RawHomeMap") + .WithMany() + .HasForeignKey("HomeMapId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", "RawNextGenerationClass") + .WithMany() + .HasForeignKey("NextGenerationClassId"); + + b.Navigation("RawComboDefinition"); + + b.Navigation("RawHomeMap"); + + b.Navigation("RawNextGenerationClass"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterDropItemGroup", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Character", "Character") + .WithMany("JoinedDropItemGroups") + .HasForeignKey("CharacterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.DropItemGroup", "DropItemGroup") + .WithMany() + .HasForeignKey("DropItemGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Character"); + + b.Navigation("DropItemGroup"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterQuestState", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestDefinition", "RawActiveQuest") + .WithMany() + .HasForeignKey("ActiveQuestId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Character", null) + .WithMany("RawQuestStates") + .HasForeignKey("CharacterId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestDefinition", "RawLastFinishedQuest") + .WithMany() + .HasForeignKey("LastFinishedQuestId"); + + b.Navigation("RawActiveQuest"); + + b.Navigation("RawLastFinishedQuest"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ChatServerEndpoint", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ChatServerDefinition", null) + .WithMany("RawEndpoints") + .HasForeignKey("ChatServerDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameClientDefinition", "RawClient") + .WithMany() + .HasForeignKey("ClientId"); + + b.Navigation("RawClient"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.CombinationBonusRequirement", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionCombinationBonus", null) + .WithMany("RawRequirements") + .HasForeignKey("ItemOptionCombinationBonusId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionType", "RawOptionType") + .WithMany() + .HasForeignKey("OptionTypeId"); + + b.Navigation("RawOptionType"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ConnectServerDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameClientDefinition", "RawClient") + .WithMany() + .HasForeignKey("ClientId"); + + b.Navigation("RawClient"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ConstValueAttribute", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", "CharacterClass") + .WithMany("RawBaseAttributeValues") + .HasForeignKey("CharacterClassId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawDefinition") + .WithMany() + .HasForeignKey("DefinitionId"); + + b.Navigation("CharacterClass"); + + b.Navigation("RawDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.DropItemGroup", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawDropItemGroups") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", "RawMonster") + .WithMany() + .HasForeignKey("MonsterId"); + + b.Navigation("RawMonster"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.DropItemGroupItemDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.DropItemGroup", "DropItemGroup") + .WithMany("JoinedPossibleItems") + .HasForeignKey("DropItemGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "ItemDefinition") + .WithMany() + .HasForeignKey("ItemDefinitionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("DropItemGroup"); + + b.Navigation("ItemDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.EnterGate", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", null) + .WithMany("RawEnterGates") + .HasForeignKey("GameMapDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ExitGate", "RawTargetGate") + .WithMany() + .HasForeignKey("TargetGateId"); + + b.Navigation("RawTargetGate"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ExitGate", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", "RawMap") + .WithMany("RawExitGates") + .HasForeignKey("MapId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawMap"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.BattleZoneDefinition", "RawBattleZone") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", "BattleZoneId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawMaps") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", "RawSafezoneMap") + .WithMany() + .HasForeignKey("SafezoneMapId"); + + b.Navigation("RawBattleZone"); + + b.Navigation("RawSafezoneMap"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinitionDropItemGroup", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.DropItemGroup", "DropItemGroup") + .WithMany() + .HasForeignKey("DropItemGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", "GameMapDefinition") + .WithMany("JoinedDropItemGroups") + .HasForeignKey("GameMapDefinitionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("DropItemGroup"); + + b.Navigation("GameMapDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerConfigurationGameMapDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", "GameMapDefinition") + .WithMany() + .HasForeignKey("GameMapDefinitionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerConfiguration", "GameServerConfiguration") + .WithMany("JoinedMaps") + .HasForeignKey("GameServerConfigurationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("GameMapDefinition"); + + b.Navigation("GameServerConfiguration"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", "RawGameConfiguration") + .WithMany() + .HasForeignKey("GameConfigurationId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerConfiguration", "RawServerConfiguration") + .WithMany() + .HasForeignKey("ServerConfigurationId"); + + b.Navigation("RawGameConfiguration"); + + b.Navigation("RawServerConfiguration"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerEndpoint", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameClientDefinition", "RawClient") + .WithMany() + .HasForeignKey("ClientId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerDefinition", null) + .WithMany("RawEndpoints") + .HasForeignKey("GameServerDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawClient"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Guild", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Guild", "RawAllianceGuild") + .WithMany() + .HasForeignKey("AllianceGuildId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Guild", "RawHostility") + .WithMany() + .HasForeignKey("HostilityId"); + + b.Navigation("RawAllianceGuild"); + + b.Navigation("RawHostility"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GuildMember", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Guild", null) + .WithMany("RawMembers") + .HasForeignKey("GuildId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Character", "Character") + .WithMany() + .HasForeignKey("Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Character"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.IncreasableItemOption", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionDefinition", null) + .WithMany("RawPossibleOptions") + .HasForeignKey("ItemOptionDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemSetGroup", null) + .WithMany("RawOptions") + .HasForeignKey("ItemSetGroupId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionType", "RawOptionType") + .WithMany() + .HasForeignKey("OptionTypeId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinition", "RawPowerUpDefinition") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.IncreasableItemOption", "PowerUpDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawOptionType"); + + b.Navigation("RawPowerUpDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Item", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "RawDefinition") + .WithMany() + .HasForeignKey("DefinitionId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemStorage", "RawItemStorage") + .WithMany("RawItems") + .HasForeignKey("ItemStorageId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawDefinition"); + + b.Navigation("RawItemStorage"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemAppearance", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AppearanceData", null) + .WithMany("RawEquippedItems") + .HasForeignKey("AppearanceDataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "RawDefinition") + .WithMany() + .HasForeignKey("DefinitionId"); + + b.Navigation("RawDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemAppearanceItemOptionType", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemAppearance", "ItemAppearance") + .WithMany("JoinedVisibleOptions") + .HasForeignKey("ItemAppearanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionType", "ItemOptionType") + .WithMany() + .HasForeignKey("ItemOptionTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ItemAppearance"); + + b.Navigation("ItemOptionType"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemBasePowerUpDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemLevelBonusTable", "RawBonusPerLevelTable") + .WithMany() + .HasForeignKey("BonusPerLevelTableId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", null) + .WithMany("RawBasePowerUpAttributes") + .HasForeignKey("ItemDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawTargetAttribute") + .WithMany() + .HasForeignKey("TargetAttributeId"); + + b.Navigation("RawBonusPerLevelTable"); + + b.Navigation("RawTargetAttribute"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCrafting", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", null) + .WithMany("RawItemCraftings") + .HasForeignKey("MonsterDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.SimpleCraftingSettings", "RawSimpleCraftingSettings") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCrafting", "SimpleCraftingSettingsId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawSimpleCraftingSettings"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingRequiredItem", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.SimpleCraftingSettings", null) + .WithMany("RawRequiredItems") + .HasForeignKey("SimpleCraftingSettingsId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingRequiredItemItemDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingRequiredItem", "ItemCraftingRequiredItem") + .WithMany("JoinedPossibleItems") + .HasForeignKey("ItemCraftingRequiredItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "ItemDefinition") + .WithMany() + .HasForeignKey("ItemDefinitionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ItemCraftingRequiredItem"); + + b.Navigation("ItemDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingRequiredItemItemOptionType", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingRequiredItem", "ItemCraftingRequiredItem") + .WithMany("JoinedRequiredItemOptions") + .HasForeignKey("ItemCraftingRequiredItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionType", "ItemOptionType") + .WithMany() + .HasForeignKey("ItemOptionTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ItemCraftingRequiredItem"); + + b.Navigation("ItemOptionType"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingResultItem", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "RawItemDefinition") + .WithMany() + .HasForeignKey("ItemDefinitionId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.SimpleCraftingSettings", null) + .WithMany("RawResultItems") + .HasForeignKey("SimpleCraftingSettingsId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawItemDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MagicEffectDefinition", "RawConsumeEffect") + .WithMany() + .HasForeignKey("ConsumeEffectId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawItems") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemSlotType", "RawItemSlot") + .WithMany() + .HasForeignKey("ItemSlotId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", "RawSkill") + .WithMany() + .HasForeignKey("SkillId"); + + b.Navigation("RawConsumeEffect"); + + b.Navigation("RawItemSlot"); + + b.Navigation("RawSkill"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinitionCharacterClass", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", "CharacterClass") + .WithMany() + .HasForeignKey("CharacterClassId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "ItemDefinition") + .WithMany("JoinedQualifiedCharacters") + .HasForeignKey("ItemDefinitionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CharacterClass"); + + b.Navigation("ItemDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinitionItemOptionDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "ItemDefinition") + .WithMany("JoinedPossibleItemOptions") + .HasForeignKey("ItemDefinitionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionDefinition", "ItemOptionDefinition") + .WithMany() + .HasForeignKey("ItemOptionDefinitionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ItemDefinition"); + + b.Navigation("ItemOptionDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinitionItemSetGroup", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "ItemDefinition") + .WithMany("JoinedPossibleItemSetGroups") + .HasForeignKey("ItemDefinitionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemSetGroup", "ItemSetGroup") + .WithMany() + .HasForeignKey("ItemSetGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ItemDefinition"); + + b.Navigation("ItemSetGroup"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDropItemGroup", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", null) + .WithMany("RawDropItems") + .HasForeignKey("ItemDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", "RawMonster") + .WithMany() + .HasForeignKey("MonsterId"); + + b.Navigation("RawMonster"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDropItemGroupItemDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "ItemDefinition") + .WithMany() + .HasForeignKey("ItemDefinitionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDropItemGroup", "ItemDropItemGroup") + .WithMany("JoinedPossibleItems") + .HasForeignKey("ItemDropItemGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ItemDefinition"); + + b.Navigation("ItemDropItemGroup"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemItemOfItemSet", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Item", "Item") + .WithMany("JoinedItemSetGroups") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOfItemSet", "ItemOfItemSet") + .WithMany() + .HasForeignKey("ItemOfItemSetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("ItemOfItemSet"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemLevelBonusTable", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawItemLevelBonusTables") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOfItemSet", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.IncreasableItemOption", "RawBonusOption") + .WithMany() + .HasForeignKey("BonusOptionId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "RawItemDefinition") + .WithMany() + .HasForeignKey("ItemDefinitionId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemSetGroup", "RawItemSetGroup") + .WithMany("RawItems") + .HasForeignKey("ItemSetGroupId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawBonusOption"); + + b.Navigation("RawItemDefinition"); + + b.Navigation("RawItemSetGroup"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOption", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionType", "RawOptionType") + .WithMany() + .HasForeignKey("OptionTypeId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinition", "RawPowerUpDefinition") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOption", "PowerUpDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawOptionType"); + + b.Navigation("RawPowerUpDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionCombinationBonus", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinition", "RawBonus") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionCombinationBonus", "BonusId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawItemOptionCombinationBonuses") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawBonus"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawItemOptions") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionLink", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Item", null) + .WithMany("RawItemOptions") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.IncreasableItemOption", "RawItemOption") + .WithMany() + .HasForeignKey("ItemOptionId"); + + b.Navigation("RawItemOption"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionOfLevel", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.IncreasableItemOption", null) + .WithMany("RawLevelDependentOptions") + .HasForeignKey("IncreasableItemOptionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinition", "RawPowerUpDefinition") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionOfLevel", "PowerUpDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawPowerUpDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionType", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawItemOptionTypes") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemSetGroup", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawItemSetGroups") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemSlotType", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawItemSlotTypes") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.JewelMix", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawJewelMixes") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "RawMixedJewel") + .WithMany() + .HasForeignKey("MixedJewelId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "RawSingleJewel") + .WithMany() + .HasForeignKey("SingleJewelId"); + + b.Navigation("RawMixedJewel"); + + b.Navigation("RawSingleJewel"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.LetterBody", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.LetterHeader", "RawHeader") + .WithMany() + .HasForeignKey("HeaderId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AppearanceData", "RawSenderAppearance") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.LetterBody", "SenderAppearanceId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawHeader"); + + b.Navigation("RawSenderAppearance"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.LetterHeader", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Character", "Receiver") + .WithMany("RawLetters") + .HasForeignKey("ReceiverId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Receiver"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.LevelBonus", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemLevelBonusTable", null) + .WithMany("RawBonusPerLevel") + .HasForeignKey("ItemLevelBonusTableId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MagicEffectDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinitionValue", "RawDuration") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.MagicEffectDefinition", "DurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawMagicEffects") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawDuration"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MasterSkillDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", "RawReplacedSkill") + .WithMany() + .HasForeignKey("ReplacedSkillId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MasterSkillRoot", "RawRoot") + .WithMany() + .HasForeignKey("RootId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawTargetAttribute") + .WithMany() + .HasForeignKey("TargetAttributeId"); + + b.Navigation("RawReplacedSkill"); + + b.Navigation("RawRoot"); + + b.Navigation("RawTargetAttribute"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MasterSkillDefinitionSkill", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MasterSkillDefinition", "MasterSkillDefinition") + .WithMany("JoinedRequiredMasterSkills") + .HasForeignKey("MasterSkillDefinitionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", "Skill") + .WithMany() + .HasForeignKey("SkillId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MasterSkillDefinition"); + + b.Navigation("Skill"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MasterSkillRoot", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawMasterSkillRoots") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameChangeEvent", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameDefinition", null) + .WithMany("RawChangeEvents") + .HasForeignKey("MiniGameDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterSpawnArea", "RawSpawnArea") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameChangeEvent", "SpawnAreaId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", "RawTargetDefinition") + .WithMany() + .HasForeignKey("TargetDefinitionId"); + + b.Navigation("RawSpawnArea"); + + b.Navigation("RawTargetDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ExitGate", "RawEntrance") + .WithMany() + .HasForeignKey("EntranceId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawMiniGameDefinitions") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "RawTicketItem") + .WithMany() + .HasForeignKey("TicketItemId"); + + b.Navigation("RawEntrance"); + + b.Navigation("RawTicketItem"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameRankingEntry", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Character", "RawCharacter") + .WithMany() + .HasForeignKey("CharacterId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameDefinition", "RawMiniGame") + .WithMany() + .HasForeignKey("MiniGameId"); + + b.Navigation("RawCharacter"); + + b.Navigation("RawMiniGame"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameReward", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.DropItemGroup", "RawItemReward") + .WithMany() + .HasForeignKey("ItemRewardId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameDefinition", null) + .WithMany("RawRewards") + .HasForeignKey("MiniGameDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", "RawRequiredKill") + .WithMany() + .HasForeignKey("RequiredKillId"); + + b.Navigation("RawItemReward"); + + b.Navigation("RawRequiredKill"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameSpawnWave", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameDefinition", null) + .WithMany("RawSpawnWaves") + .HasForeignKey("MiniGameDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameTerrainChange", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameChangeEvent", null) + .WithMany("RawTerrainChanges") + .HasForeignKey("MiniGameChangeEventId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterAttribute", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawAttributeDefinition") + .WithMany() + .HasForeignKey("AttributeDefinitionId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", null) + .WithMany("RawAttributes") + .HasForeignKey("MonsterDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawAttributeDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", "RawAttackSkill") + .WithMany() + .HasForeignKey("AttackSkillId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawMonsters") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemStorage", "RawMerchantStore") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", "MerchantStoreId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawAttackSkill"); + + b.Navigation("RawMerchantStore"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinitionDropItemGroup", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.DropItemGroup", "DropItemGroup") + .WithMany() + .HasForeignKey("DropItemGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", "MonsterDefinition") + .WithMany("JoinedDropItemGroups") + .HasForeignKey("MonsterDefinitionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("DropItemGroup"); + + b.Navigation("MonsterDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterSpawnArea", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", null) + .WithMany("RawMonsterSpawns") + .HasForeignKey("GameMapDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", "RawGameMap") + .WithMany() + .HasForeignKey("GameMapId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", "RawMonsterDefinition") + .WithMany() + .HasForeignKey("MonsterDefinitionId"); + + b.Navigation("RawGameMap"); + + b.Navigation("RawMonsterDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.PlugInConfiguration", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawPlugInConfigurations") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinitionValue", "RawBoost") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinition", "BoostId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", null) + .WithMany("RawCharacterPowerUpDefinitions") + .HasForeignKey("GameMapDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MagicEffectDefinition", null) + .WithMany("RawPowerUpDefinitions") + .HasForeignKey("MagicEffectDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawTargetAttribute") + .WithMany() + .HasForeignKey("TargetAttributeId"); + + b.Navigation("RawBoost"); + + b.Navigation("RawTargetAttribute"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", null) + .WithMany("RawQuests") + .HasForeignKey("MonsterDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", "RawQualifiedCharacter") + .WithMany() + .HasForeignKey("QualifiedCharacterId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", "RawQuestGiver") + .WithMany() + .HasForeignKey("QuestGiverId"); + + b.Navigation("RawQualifiedCharacter"); + + b.Navigation("RawQuestGiver"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestItemRequirement", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.DropItemGroup", "RawDropItemGroup") + .WithMany() + .HasForeignKey("DropItemGroupId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "RawItem") + .WithMany() + .HasForeignKey("ItemId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestDefinition", null) + .WithMany("RawRequiredItems") + .HasForeignKey("QuestDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawDropItemGroup"); + + b.Navigation("RawItem"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestMonsterKillRequirement", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", "RawMonster") + .WithMany() + .HasForeignKey("MonsterId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestDefinition", null) + .WithMany("RawRequiredMonsterKills") + .HasForeignKey("QuestDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawMonster"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestMonsterKillRequirementState", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterQuestState", null) + .WithMany("RawRequirementStates") + .HasForeignKey("CharacterQuestStateId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestMonsterKillRequirement", "RawRequirement") + .WithMany() + .HasForeignKey("RequirementId"); + + b.Navigation("RawRequirement"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestReward", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawAttributeReward") + .WithMany() + .HasForeignKey("AttributeRewardId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Item", "RawItemReward") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestReward", "ItemRewardId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestDefinition", null) + .WithMany("RawRewards") + .HasForeignKey("QuestDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", "RawSkillReward") + .WithMany() + .HasForeignKey("SkillRewardId"); + + b.Navigation("RawAttributeReward"); + + b.Navigation("RawItemReward"); + + b.Navigation("RawSkillReward"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawElementalModifierTarget") + .WithMany() + .HasForeignKey("ElementalModifierTargetId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawSkills") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MagicEffectDefinition", "RawMagicEffectDef") + .WithMany() + .HasForeignKey("MagicEffectDefId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MasterSkillDefinition", "RawMasterDefinition") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", "MasterDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawElementalModifierTarget"); + + b.Navigation("RawMagicEffectDef"); + + b.Navigation("RawMasterDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillCharacterClass", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", "CharacterClass") + .WithMany() + .HasForeignKey("CharacterClassId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", "Skill") + .WithMany("JoinedQualifiedCharacters") + .HasForeignKey("SkillId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CharacterClass"); + + b.Navigation("Skill"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillComboStep", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillComboDefinition", null) + .WithMany("RawSteps") + .HasForeignKey("SkillComboDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", "RawSkill") + .WithMany() + .HasForeignKey("SkillId"); + + b.Navigation("RawSkill"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillEntry", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Character", null) + .WithMany("RawLearnedSkills") + .HasForeignKey("CharacterId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", "RawSkill") + .WithMany() + .HasForeignKey("SkillId"); + + b.Navigation("RawSkill"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.StatAttribute", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Account", null) + .WithMany("RawAttributes") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Character", null) + .WithMany("RawAttributes") + .HasForeignKey("CharacterId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawDefinition") + .WithMany() + .HasForeignKey("DefinitionId"); + + b.Navigation("RawDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.StatAttributeDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawAttribute") + .WithMany() + .HasForeignKey("AttributeId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", null) + .WithMany("RawStatAttributes") + .HasForeignKey("CharacterClassId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawAttribute"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.WarpInfo", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawWarpList") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ExitGate", "RawGate") + .WithMany() + .HasForeignKey("GateId"); + + b.Navigation("RawGate"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Account", b => + { + b.Navigation("JoinedUnlockedCharacterClasses"); + + b.Navigation("RawAttributes"); + + b.Navigation("RawCharacters"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AppearanceData", b => + { + b.Navigation("RawEquippedItems"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Character", b => + { + b.Navigation("JoinedDropItemGroups"); + + b.Navigation("RawAttributes"); + + b.Navigation("RawLearnedSkills"); + + b.Navigation("RawLetters"); + + b.Navigation("RawQuestStates"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", b => + { + b.Navigation("RawAttributeCombinations"); + + b.Navigation("RawBaseAttributeValues"); + + b.Navigation("RawStatAttributes"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterQuestState", b => + { + b.Navigation("RawRequirementStates"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ChatServerDefinition", b => + { + b.Navigation("RawEndpoints"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.DropItemGroup", b => + { + b.Navigation("JoinedPossibleItems"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", b => + { + b.Navigation("RawAttributes"); + + b.Navigation("RawCharacterClasses"); + + b.Navigation("RawDropItemGroups"); + + b.Navigation("RawItemLevelBonusTables"); + + b.Navigation("RawItemOptionCombinationBonuses"); + + b.Navigation("RawItemOptionTypes"); + + b.Navigation("RawItemOptions"); + + b.Navigation("RawItemSetGroups"); + + b.Navigation("RawItemSlotTypes"); + + b.Navigation("RawItems"); + + b.Navigation("RawJewelMixes"); + + b.Navigation("RawMagicEffects"); + + b.Navigation("RawMaps"); + + b.Navigation("RawMasterSkillRoots"); + + b.Navigation("RawMiniGameDefinitions"); + + b.Navigation("RawMonsters"); + + b.Navigation("RawPlugInConfigurations"); + + b.Navigation("RawSkills"); + + b.Navigation("RawWarpList"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", b => + { + b.Navigation("JoinedDropItemGroups"); + + b.Navigation("RawCharacterPowerUpDefinitions"); + + b.Navigation("RawEnterGates"); + + b.Navigation("RawExitGates"); + + b.Navigation("RawMapRequirements"); + + b.Navigation("RawMonsterSpawns"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerConfiguration", b => + { + b.Navigation("JoinedMaps"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerDefinition", b => + { + b.Navigation("RawEndpoints"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Guild", b => + { + b.Navigation("RawMembers"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.IncreasableItemOption", b => + { + b.Navigation("RawLevelDependentOptions"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Item", b => + { + b.Navigation("JoinedItemSetGroups"); + + b.Navigation("RawItemOptions"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemAppearance", b => + { + b.Navigation("JoinedVisibleOptions"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingRequiredItem", b => + { + b.Navigation("JoinedPossibleItems"); + + b.Navigation("JoinedRequiredItemOptions"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", b => + { + b.Navigation("JoinedPossibleItemOptions"); + + b.Navigation("JoinedPossibleItemSetGroups"); + + b.Navigation("JoinedQualifiedCharacters"); + + b.Navigation("RawBasePowerUpAttributes"); + + b.Navigation("RawDropItems"); + + b.Navigation("RawRequirements"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDropItemGroup", b => + { + b.Navigation("JoinedPossibleItems"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemLevelBonusTable", b => + { + b.Navigation("RawBonusPerLevel"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionCombinationBonus", b => + { + b.Navigation("RawRequirements"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionDefinition", b => + { + b.Navigation("RawPossibleOptions"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemSetGroup", b => + { + b.Navigation("RawItems"); + + b.Navigation("RawOptions"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemStorage", b => + { + b.Navigation("RawItems"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MagicEffectDefinition", b => + { + b.Navigation("RawPowerUpDefinitions"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MasterSkillDefinition", b => + { + b.Navigation("JoinedRequiredMasterSkills"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameChangeEvent", b => + { + b.Navigation("RawTerrainChanges"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameDefinition", b => + { + b.Navigation("RawChangeEvents"); + + b.Navigation("RawRewards"); + + b.Navigation("RawSpawnWaves"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", b => + { + b.Navigation("JoinedDropItemGroups"); + + b.Navigation("RawAttributes"); + + b.Navigation("RawItemCraftings"); + + b.Navigation("RawQuests"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinitionValue", b => + { + b.Navigation("RawRelatedValues"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestDefinition", b => + { + b.Navigation("RawRequiredItems"); + + b.Navigation("RawRequiredMonsterKills"); + + b.Navigation("RawRewards"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SimpleCraftingSettings", b => + { + b.Navigation("RawRequiredItems"); + + b.Navigation("RawResultItems"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", b => + { + b.Navigation("JoinedQualifiedCharacters"); + + b.Navigation("RawConsumeRequirements"); + + b.Navigation("RawRequirements"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillComboDefinition", b => + { + b.Navigation("RawSteps"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Persistence/EntityFramework/Migrations/20240602060055_FixItemOptions.cs b/src/Persistence/EntityFramework/Migrations/20240602060055_FixItemOptions.cs new file mode 100644 index 000000000..0b2110d10 --- /dev/null +++ b/src/Persistence/EntityFramework/Migrations/20240602060055_FixItemOptions.cs @@ -0,0 +1,106 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace MUnique.OpenMU.Persistence.EntityFramework.Migrations +{ + /// + public partial class FixItemOptions : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_IncreasableItemOption_ItemSetGroup_ItemSetGroupId", + schema: "config", + table: "IncreasableItemOption"); + + migrationBuilder.AddForeignKey( + name: "FK_IncreasableItemOption_ItemSetGroup_ItemSetGroupId", + schema: "config", + table: "IncreasableItemOption", + column: "ItemSetGroupId", + principalSchema: "config", + principalTable: "ItemSetGroup", + principalColumn: "Id"); + + // First, we need to create the new item option definitions for the ancient sets + migrationBuilder.Sql( + """ + INSERT INTO config."ItemOptionDefinition" ("Id", "GameConfigurationId", "Name", "AddsRandomly", "AddChance", "MaximumOptionsPerItem") + SELECT UUID(REPLACE(sets.setId, '00000092-','00000083-')), '00000001-0001-0000-0000-000000000000', sets.setName || ' (Ancient Set)', false, 0, 0 + FROM + ( + SELECT COUNT(o."Id") c, text(o."ItemSetGroupId") setId, g."Name" setName + FROM config."IncreasableItemOption" o, config."ItemSetGroup" g + WHERE "ItemSetGroupId" is not null + AND "ItemOptionDefinitionId" is null + AND g."Id" = o."ItemSetGroupId" + GROUP BY o."ItemSetGroupId", g."Name" + ORDER BY c + ) sets + WHERE sets.c > 1 + """); + + // Then we need to update the item option definitions of the ancient sets, + // so that they belong to the previously created item option defintions + migrationBuilder.Sql( + """ + UPDATE config."IncreasableItemOption" o + SET "ItemOptionDefinitionId" = UUID(REPLACE(TEXT(o."ItemSetGroupId"), '00000092-','00000083-')) + WHERE o."ItemSetGroupId" is not null + AND o."ItemOptionDefinitionId" is null + AND o."OptionTypeId" is not null + """); + + // Then what's left are the options for set completion of normal sets. + migrationBuilder.Sql( + """ + INSERT INTO config."ItemOptionDefinition" ("Id", "GameConfigurationId", "Name", "AddsRandomly", "AddChance", "MaximumOptionsPerItem") + SELECT UUID(REPLACE(sets.optionId, '00000088-','00000083-')), + '00000001-0001-0000-0000-000000000000', + CASE WHEN sets.setLevel=0 THEN 'Complete Set Bonus (any level)' + ELSE 'Complete Set Bonus (Level ' || sets.setLevel || ')' + END, + false, 0, 0 + FROM + ( + SELECT text(o."Id") optionId, text(o."ItemSetGroupId") setId, g."Name" setName, g."SetLevel" setLevel + FROM config."IncreasableItemOption" o, config."ItemSetGroup" g + WHERE "ItemSetGroupId" is not null + AND "ItemOptionDefinitionId" is null + AND g."Id" = o."ItemSetGroupId" + ORDER BY setLevel + ) sets + """); + + // Then we need to update the item option definitions of the normal sets + // so that they belong to the previously created item option defintions + migrationBuilder.Sql( + """ + UPDATE config."IncreasableItemOption" o + SET "ItemOptionDefinitionId" = UUID(REPLACE(TEXT(o."Id"), '00000088-','00000083-')) + WHERE o."ItemOptionDefinitionId" is null + """); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_IncreasableItemOption_ItemSetGroup_ItemSetGroupId", + schema: "config", + table: "IncreasableItemOption"); + + migrationBuilder.AddForeignKey( + name: "FK_IncreasableItemOption_ItemSetGroup_ItemSetGroupId", + schema: "config", + table: "IncreasableItemOption", + column: "ItemSetGroupId", + principalSchema: "config", + principalTable: "ItemSetGroup", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + } +} diff --git a/src/Persistence/EntityFramework/Migrations/20240602085237_FixItemOptions2.Designer.cs b/src/Persistence/EntityFramework/Migrations/20240602085237_FixItemOptions2.Designer.cs new file mode 100644 index 000000000..5e82a0d41 --- /dev/null +++ b/src/Persistence/EntityFramework/Migrations/20240602085237_FixItemOptions2.Designer.cs @@ -0,0 +1,4878 @@ +// +using System; +using MUnique.OpenMU.Persistence.EntityFramework; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace MUnique.OpenMU.Persistence.EntityFramework.Migrations +{ + [DbContext(typeof(EntityDataContext))] + [Migration("20240602085237_FixItemOptions2")] + partial class FixItemOptions2 + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Account", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ChatBanUntil") + .HasColumnType("timestamp with time zone"); + + b.Property("EMail") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsVaultExtended") + .HasColumnType("boolean"); + + b.Property("LoginName") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("PasswordHash") + .IsRequired() + .HasColumnType("text"); + + b.Property("RegistrationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("SecurityCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("State") + .HasColumnType("integer"); + + b.Property("TimeZone") + .HasColumnType("smallint"); + + b.Property("VaultId") + .HasColumnType("uuid"); + + b.Property("VaultPassword") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("LoginName") + .IsUnique(); + + b.HasIndex("VaultId") + .IsUnique(); + + b.ToTable("Account", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AccountCharacterClass", b => + { + b.Property("AccountId") + .HasColumnType("uuid"); + + b.Property("CharacterClassId") + .HasColumnType("uuid"); + + b.HasKey("AccountId", "CharacterClassId"); + + b.HasIndex("CharacterClassId"); + + b.ToTable("AccountCharacterClass", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AppearanceData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CharacterClassId") + .HasColumnType("uuid"); + + b.Property("FullAncientSetEquipped") + .HasColumnType("boolean"); + + b.Property("Pose") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("CharacterClassId"); + + b.ToTable("AppearanceData", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("Designation") + .HasColumnType("text"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.ToTable("AttributeDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeRelationship", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CharacterClassId") + .HasColumnType("uuid"); + + b.Property("InputAttributeId") + .HasColumnType("uuid"); + + b.Property("InputOperand") + .HasColumnType("real"); + + b.Property("InputOperator") + .HasColumnType("integer"); + + b.Property("OperandAttributeId") + .HasColumnType("uuid"); + + b.Property("PowerUpDefinitionValueId") + .HasColumnType("uuid"); + + b.Property("TargetAttributeId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CharacterClassId"); + + b.HasIndex("InputAttributeId"); + + b.HasIndex("OperandAttributeId"); + + b.HasIndex("PowerUpDefinitionValueId"); + + b.HasIndex("TargetAttributeId"); + + b.ToTable("AttributeRelationship", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeRequirement", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AttributeId") + .HasColumnType("uuid"); + + b.Property("GameMapDefinitionId") + .HasColumnType("uuid"); + + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.Property("MinimumValue") + .HasColumnType("integer"); + + b.Property("SkillId") + .HasColumnType("uuid"); + + b.Property("SkillId1") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("AttributeId"); + + b.HasIndex("GameMapDefinitionId"); + + b.HasIndex("ItemDefinitionId"); + + b.HasIndex("SkillId"); + + b.HasIndex("SkillId1"); + + b.ToTable("AttributeRequirement", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.BattleZoneDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("GroundId") + .HasColumnType("uuid"); + + b.Property("LeftGoalId") + .HasColumnType("uuid"); + + b.Property("LeftTeamSpawnPointX") + .HasColumnType("smallint"); + + b.Property("LeftTeamSpawnPointY") + .HasColumnType("smallint"); + + b.Property("RightGoalId") + .HasColumnType("uuid"); + + b.Property("RightTeamSpawnPointX") + .HasColumnType("smallint"); + + b.Property("RightTeamSpawnPointY") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("GroundId") + .IsUnique(); + + b.HasIndex("LeftGoalId") + .IsUnique(); + + b.HasIndex("RightGoalId") + .IsUnique(); + + b.ToTable("BattleZoneDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Character", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountId") + .HasColumnType("uuid"); + + b.Property("CharacterClassId") + .IsRequired() + .HasColumnType("uuid"); + + b.Property("CharacterSlot") + .HasColumnType("smallint"); + + b.Property("CharacterStatus") + .HasColumnType("integer"); + + b.Property("CreateDate") + .HasColumnType("timestamp with time zone"); + + b.Property("CurrentMapId") + .HasColumnType("uuid"); + + b.Property("Experience") + .HasColumnType("bigint"); + + b.Property("InventoryExtensions") + .HasColumnType("integer"); + + b.Property("InventoryId") + .HasColumnType("uuid"); + + b.Property("KeyConfiguration") + .HasColumnType("bytea"); + + b.Property("LevelUpPoints") + .HasColumnType("integer"); + + b.Property("MasterExperience") + .HasColumnType("bigint"); + + b.Property("MasterLevelUpPoints") + .HasColumnType("integer"); + + b.Property("MuHelperConfiguration") + .HasColumnType("bytea"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("PlayerKillCount") + .HasColumnType("integer"); + + b.Property("Pose") + .HasColumnType("smallint"); + + b.Property("PositionX") + .HasColumnType("smallint"); + + b.Property("PositionY") + .HasColumnType("smallint"); + + b.Property("State") + .HasColumnType("integer"); + + b.Property("StateRemainingSeconds") + .HasColumnType("integer"); + + b.Property("UsedFruitPoints") + .HasColumnType("integer"); + + b.Property("UsedNegFruitPoints") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("CharacterClassId"); + + b.HasIndex("CurrentMapId"); + + b.HasIndex("InventoryId") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Character", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CanGetCreated") + .HasColumnType("boolean"); + + b.Property("ComboDefinitionId") + .HasColumnType("uuid"); + + b.Property("CreationAllowedFlag") + .HasColumnType("smallint"); + + b.Property("FruitCalculation") + .HasColumnType("integer"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("HomeMapId") + .HasColumnType("uuid"); + + b.Property("IsMasterClass") + .HasColumnType("boolean"); + + b.Property("LevelRequirementByCreation") + .HasColumnType("smallint"); + + b.Property("LevelWarpRequirementReductionPercent") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("NextGenerationClassId") + .HasColumnType("uuid"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("ComboDefinitionId") + .IsUnique(); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("HomeMapId"); + + b.HasIndex("NextGenerationClassId"); + + b.ToTable("CharacterClass", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterDropItemGroup", b => + { + b.Property("CharacterId") + .HasColumnType("uuid"); + + b.Property("DropItemGroupId") + .HasColumnType("uuid"); + + b.HasKey("CharacterId", "DropItemGroupId"); + + b.HasIndex("DropItemGroupId"); + + b.ToTable("CharacterDropItemGroup", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterQuestState", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ActiveQuestId") + .HasColumnType("uuid"); + + b.Property("CharacterId") + .HasColumnType("uuid"); + + b.Property("ClientActionPerformed") + .HasColumnType("boolean"); + + b.Property("Group") + .HasColumnType("smallint"); + + b.Property("LastFinishedQuestId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ActiveQuestId"); + + b.HasIndex("CharacterId"); + + b.HasIndex("LastFinishedQuestId"); + + b.ToTable("CharacterQuestState", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ChatServerDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ClientCleanUpInterval") + .HasColumnType("interval"); + + b.Property("ClientTimeout") + .HasColumnType("interval"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("MaximumConnections") + .HasColumnType("integer"); + + b.Property("RoomCleanUpInterval") + .HasColumnType("interval"); + + b.Property("ServerId") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.ToTable("ChatServerDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ChatServerEndpoint", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ChatServerDefinitionId") + .HasColumnType("uuid"); + + b.Property("ClientId") + .HasColumnType("uuid"); + + b.Property("NetworkPort") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ChatServerDefinitionId"); + + b.HasIndex("ClientId"); + + b.ToTable("ChatServerEndpoint", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.CombinationBonusRequirement", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ItemOptionCombinationBonusId") + .HasColumnType("uuid"); + + b.Property("MinimumCount") + .HasColumnType("integer"); + + b.Property("OptionTypeId") + .HasColumnType("uuid"); + + b.Property("SubOptionType") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ItemOptionCombinationBonusId"); + + b.HasIndex("OptionTypeId"); + + b.ToTable("CombinationBonusRequirement", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ConfigurationUpdate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("InstalledAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Version") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("ConfigurationUpdate", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ConfigurationUpdateState", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CurrentInstalledVersion") + .HasColumnType("integer"); + + b.Property("InitializationKey") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("ConfigurationUpdateState", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ConnectServerDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CheckMaxConnectionsPerAddress") + .HasColumnType("boolean"); + + b.Property("ClientId") + .HasColumnType("uuid"); + + b.Property("ClientListenerPort") + .HasColumnType("integer"); + + b.Property("CurrentPatchVersion") + .HasColumnType("bytea"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("DisconnectOnUnknownPacket") + .HasColumnType("boolean"); + + b.Property("ListenerBacklog") + .HasColumnType("integer"); + + b.Property("MaxConnections") + .HasColumnType("integer"); + + b.Property("MaxConnectionsPerAddress") + .HasColumnType("integer"); + + b.Property("MaxFtpRequests") + .HasColumnType("integer"); + + b.Property("MaxIpRequests") + .HasColumnType("integer"); + + b.Property("MaxServerListRequests") + .HasColumnType("integer"); + + b.Property("MaximumReceiveSize") + .HasColumnType("smallint"); + + b.Property("PatchAddress") + .IsRequired() + .HasColumnType("text"); + + b.Property("ServerId") + .HasColumnType("smallint"); + + b.Property("Timeout") + .HasColumnType("interval"); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.ToTable("ConnectServerDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ConstValueAttribute", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CharacterClassId") + .HasColumnType("uuid"); + + b.Property("DefinitionId") + .HasColumnType("uuid"); + + b.Property("Value") + .HasColumnType("real"); + + b.HasKey("Id"); + + b.HasIndex("CharacterClassId"); + + b.HasIndex("DefinitionId"); + + b.ToTable("ConstValueAttribute", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.DropItemGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Chance") + .HasColumnType("double precision"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("ItemLevel") + .HasColumnType("smallint"); + + b.Property("ItemType") + .HasColumnType("integer"); + + b.Property("MaximumMonsterLevel") + .HasColumnType("smallint"); + + b.Property("MinimumMonsterLevel") + .HasColumnType("smallint"); + + b.Property("MonsterId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("MonsterId"); + + b.ToTable("DropItemGroup", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.DropItemGroupItemDefinition", b => + { + b.Property("DropItemGroupId") + .HasColumnType("uuid"); + + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.HasKey("DropItemGroupId", "ItemDefinitionId"); + + b.HasIndex("ItemDefinitionId"); + + b.ToTable("DropItemGroupItemDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.EnterGate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("GameMapDefinitionId") + .HasColumnType("uuid"); + + b.Property("LevelRequirement") + .HasColumnType("smallint"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.Property("TargetGateId") + .HasColumnType("uuid"); + + b.Property("X1") + .HasColumnType("smallint"); + + b.Property("X2") + .HasColumnType("smallint"); + + b.Property("Y1") + .HasColumnType("smallint"); + + b.Property("Y2") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("GameMapDefinitionId"); + + b.HasIndex("TargetGateId"); + + b.ToTable("EnterGate", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ExitGate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Direction") + .HasColumnType("integer"); + + b.Property("IsSpawnGate") + .HasColumnType("boolean"); + + b.Property("MapId") + .HasColumnType("uuid"); + + b.Property("X1") + .HasColumnType("smallint"); + + b.Property("X2") + .HasColumnType("smallint"); + + b.Property("Y1") + .HasColumnType("smallint"); + + b.Property("Y2") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("MapId"); + + b.ToTable("ExitGate", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Friend", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Accepted") + .HasColumnType("boolean"); + + b.Property("CharacterId") + .HasColumnType("uuid"); + + b.Property("FriendId") + .HasColumnType("uuid"); + + b.Property("RequestOpen") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.HasAlternateKey("CharacterId", "FriendId"); + + b.ToTable("Friend", "friend"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameClientDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("Episode") + .HasColumnType("smallint"); + + b.Property("Language") + .HasColumnType("integer"); + + b.Property("Season") + .HasColumnType("smallint"); + + b.Property("Serial") + .HasColumnType("bytea"); + + b.Property("Version") + .HasColumnType("bytea"); + + b.HasKey("Id"); + + b.ToTable("GameClientDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AreaSkillHitsPlayer") + .HasColumnType("boolean"); + + b.Property("CharacterNameRegex") + .HasColumnType("text"); + + b.Property("DamagePerOneItemDurability") + .HasColumnType("double precision"); + + b.Property("DamagePerOnePetDurability") + .HasColumnType("double precision"); + + b.Property("ExperienceRate") + .HasColumnType("real"); + + b.Property("HitsPerOneItemDurability") + .HasColumnType("double precision"); + + b.Property("InfoRange") + .HasColumnType("smallint"); + + b.Property("ItemDropDuration") + .ValueGeneratedOnAdd() + .HasColumnType("interval") + .HasDefaultValue(new TimeSpan(0, 0, 1, 0, 0)); + + b.Property("LetterSendPrice") + .HasColumnType("integer"); + + b.Property("MaximumCharactersPerAccount") + .HasColumnType("smallint"); + + b.Property("MaximumInventoryMoney") + .HasColumnType("integer"); + + b.Property("MaximumLetters") + .HasColumnType("integer"); + + b.Property("MaximumLevel") + .HasColumnType("smallint"); + + b.Property("MaximumMasterLevel") + .HasColumnType("smallint"); + + b.Property("MaximumPartySize") + .HasColumnType("smallint"); + + b.Property("MaximumPasswordLength") + .HasColumnType("integer"); + + b.Property("MaximumVaultMoney") + .HasColumnType("integer"); + + b.Property("MinimumMonsterLevelForMasterExperience") + .HasColumnType("smallint"); + + b.Property("RecoveryInterval") + .HasColumnType("integer"); + + b.Property("ShouldDropMoney") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("GameConfiguration", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BattleZoneId") + .HasColumnType("uuid"); + + b.Property("Discriminator") + .HasColumnType("integer"); + + b.Property("ExpMultiplier") + .HasColumnType("double precision"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.Property("SafezoneMapId") + .HasColumnType("uuid"); + + b.Property("TerrainData") + .HasColumnType("bytea"); + + b.HasKey("Id"); + + b.HasIndex("BattleZoneId") + .IsUnique(); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("SafezoneMapId"); + + b.ToTable("GameMapDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinitionDropItemGroup", b => + { + b.Property("GameMapDefinitionId") + .HasColumnType("uuid"); + + b.Property("DropItemGroupId") + .HasColumnType("uuid"); + + b.HasKey("GameMapDefinitionId", "DropItemGroupId"); + + b.HasIndex("DropItemGroupId"); + + b.ToTable("GameMapDefinitionDropItemGroup", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("MaximumPlayers") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.ToTable("GameServerConfiguration", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerConfigurationGameMapDefinition", b => + { + b.Property("GameServerConfigurationId") + .HasColumnType("uuid"); + + b.Property("GameMapDefinitionId") + .HasColumnType("uuid"); + + b.HasKey("GameServerConfigurationId", "GameMapDefinitionId"); + + b.HasIndex("GameMapDefinitionId"); + + b.ToTable("GameServerConfigurationGameMapDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("ExperienceRate") + .HasColumnType("real"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("ServerConfigurationId") + .HasColumnType("uuid"); + + b.Property("ServerID") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("ServerConfigurationId"); + + b.ToTable("GameServerDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerEndpoint", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AlternativePublishedPort") + .HasColumnType("integer"); + + b.Property("ClientId") + .HasColumnType("uuid"); + + b.Property("GameServerDefinitionId") + .HasColumnType("uuid"); + + b.Property("NetworkPort") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ClientId"); + + b.HasIndex("GameServerDefinitionId"); + + b.ToTable("GameServerEndpoint", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Guild", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AllianceGuildId") + .HasColumnType("uuid"); + + b.Property("HostilityId") + .HasColumnType("uuid"); + + b.Property("Logo") + .HasColumnType("bytea"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(8) + .HasColumnType("character varying(8)"); + + b.Property("Notice") + .HasColumnType("text"); + + b.Property("Score") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("AllianceGuildId"); + + b.HasIndex("HostilityId"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Guild", "guild"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GuildMember", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("GuildId") + .HasColumnType("uuid"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("GuildId"); + + b.ToTable("GuildMember", "guild"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.IncreasableItemOption", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ItemOptionDefinitionId") + .HasColumnType("uuid"); + + b.Property("LevelType") + .HasColumnType("integer"); + + b.Property("Number") + .HasColumnType("integer"); + + b.Property("OptionTypeId") + .HasColumnType("uuid"); + + b.Property("PowerUpDefinitionId") + .HasColumnType("uuid"); + + b.Property("SubOptionType") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ItemOptionDefinitionId"); + + b.HasIndex("OptionTypeId"); + + b.HasIndex("PowerUpDefinitionId") + .IsUnique(); + + b.ToTable("IncreasableItemOption", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Item", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DefinitionId") + .HasColumnType("uuid"); + + b.Property("Durability") + .HasColumnType("double precision"); + + b.Property("HasSkill") + .HasColumnType("boolean"); + + b.Property("ItemSlot") + .HasColumnType("smallint"); + + b.Property("ItemStorageId") + .HasColumnType("uuid"); + + b.Property("Level") + .HasColumnType("smallint"); + + b.Property("PetExperience") + .HasColumnType("integer"); + + b.Property("SocketCount") + .HasColumnType("integer"); + + b.Property("StorePrice") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("DefinitionId"); + + b.HasIndex("ItemStorageId"); + + b.ToTable("Item", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemAppearance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AppearanceDataId") + .HasColumnType("uuid"); + + b.Property("DefinitionId") + .HasColumnType("uuid"); + + b.Property("ItemSlot") + .HasColumnType("smallint"); + + b.Property("Level") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("AppearanceDataId"); + + b.HasIndex("DefinitionId"); + + b.ToTable("ItemAppearance", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemAppearanceItemOptionType", b => + { + b.Property("ItemAppearanceId") + .HasColumnType("uuid"); + + b.Property("ItemOptionTypeId") + .HasColumnType("uuid"); + + b.HasKey("ItemAppearanceId", "ItemOptionTypeId"); + + b.HasIndex("ItemOptionTypeId"); + + b.ToTable("ItemAppearanceItemOptionType", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemBasePowerUpDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BaseValue") + .HasColumnType("real"); + + b.Property("BonusPerLevelTableId") + .HasColumnType("uuid"); + + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.Property("TargetAttributeId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("BonusPerLevelTableId"); + + b.HasIndex("ItemDefinitionId"); + + b.HasIndex("TargetAttributeId"); + + b.ToTable("ItemBasePowerUpDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCrafting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ItemCraftingHandlerClassName") + .IsRequired() + .HasColumnType("text"); + + b.Property("MonsterDefinitionId") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.Property("SimpleCraftingSettingsId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("MonsterDefinitionId"); + + b.HasIndex("SimpleCraftingSettingsId") + .IsUnique(); + + b.ToTable("ItemCrafting", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingRequiredItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AddPercentage") + .HasColumnType("smallint"); + + b.Property("FailResult") + .HasColumnType("integer"); + + b.Property("MaximumAmount") + .HasColumnType("smallint"); + + b.Property("MaximumItemLevel") + .HasColumnType("smallint"); + + b.Property("MinimumAmount") + .HasColumnType("smallint"); + + b.Property("MinimumItemLevel") + .HasColumnType("smallint"); + + b.Property("NpcPriceDivisor") + .HasColumnType("integer"); + + b.Property("Reference") + .HasColumnType("smallint"); + + b.Property("SimpleCraftingSettingsId") + .HasColumnType("uuid"); + + b.Property("SuccessResult") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("SimpleCraftingSettingsId"); + + b.ToTable("ItemCraftingRequiredItem", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingRequiredItemItemDefinition", b => + { + b.Property("ItemCraftingRequiredItemId") + .HasColumnType("uuid"); + + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.HasKey("ItemCraftingRequiredItemId", "ItemDefinitionId"); + + b.HasIndex("ItemDefinitionId"); + + b.ToTable("ItemCraftingRequiredItemItemDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingRequiredItemItemOptionType", b => + { + b.Property("ItemCraftingRequiredItemId") + .HasColumnType("uuid"); + + b.Property("ItemOptionTypeId") + .HasColumnType("uuid"); + + b.HasKey("ItemCraftingRequiredItemId", "ItemOptionTypeId"); + + b.HasIndex("ItemOptionTypeId"); + + b.ToTable("ItemCraftingRequiredItemItemOptionType", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingResultItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AddLevel") + .HasColumnType("smallint"); + + b.Property("Durability") + .HasColumnType("smallint"); + + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.Property("RandomMaximumLevel") + .HasColumnType("smallint"); + + b.Property("RandomMinimumLevel") + .HasColumnType("smallint"); + + b.Property("Reference") + .HasColumnType("smallint"); + + b.Property("SimpleCraftingSettingsId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ItemDefinitionId"); + + b.HasIndex("SimpleCraftingSettingsId"); + + b.ToTable("ItemCraftingResultItem", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConsumeEffectId") + .HasColumnType("uuid"); + + b.Property("DropLevel") + .HasColumnType("smallint"); + + b.Property("DropsFromMonsters") + .HasColumnType("boolean"); + + b.Property("Durability") + .HasColumnType("smallint"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("Group") + .HasColumnType("smallint"); + + b.Property("Height") + .HasColumnType("smallint"); + + b.Property("IsAmmunition") + .HasColumnType("boolean"); + + b.Property("IsBoundToCharacter") + .HasColumnType("boolean"); + + b.Property("ItemSlotId") + .HasColumnType("uuid"); + + b.Property("MaximumItemLevel") + .HasColumnType("smallint"); + + b.Property("MaximumSockets") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.Property("PetExperienceFormula") + .HasColumnType("text"); + + b.Property("SkillId") + .HasColumnType("uuid"); + + b.Property("StorageLimitPerCharacter") + .HasColumnType("integer"); + + b.Property("Value") + .HasColumnType("integer"); + + b.Property("Width") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("ConsumeEffectId"); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("ItemSlotId"); + + b.HasIndex("SkillId"); + + b.ToTable("ItemDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinitionCharacterClass", b => + { + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.Property("CharacterClassId") + .HasColumnType("uuid"); + + b.HasKey("ItemDefinitionId", "CharacterClassId"); + + b.HasIndex("CharacterClassId"); + + b.ToTable("ItemDefinitionCharacterClass", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinitionItemOptionDefinition", b => + { + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.Property("ItemOptionDefinitionId") + .HasColumnType("uuid"); + + b.HasKey("ItemDefinitionId", "ItemOptionDefinitionId"); + + b.HasIndex("ItemOptionDefinitionId"); + + b.ToTable("ItemDefinitionItemOptionDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinitionItemSetGroup", b => + { + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.Property("ItemSetGroupId") + .HasColumnType("uuid"); + + b.HasKey("ItemDefinitionId", "ItemSetGroupId"); + + b.HasIndex("ItemSetGroupId"); + + b.ToTable("ItemDefinitionItemSetGroup", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDropItemGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Chance") + .HasColumnType("double precision"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("DropEffect") + .HasColumnType("integer"); + + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.Property("ItemLevel") + .HasColumnType("smallint"); + + b.Property("ItemType") + .HasColumnType("integer"); + + b.Property("MaximumLevel") + .HasColumnType("smallint"); + + b.Property("MaximumMonsterLevel") + .HasColumnType("smallint"); + + b.Property("MinimumLevel") + .HasColumnType("smallint"); + + b.Property("MinimumMonsterLevel") + .HasColumnType("smallint"); + + b.Property("MoneyAmount") + .HasColumnType("integer"); + + b.Property("MonsterId") + .HasColumnType("uuid"); + + b.Property("RequiredCharacterLevel") + .HasColumnType("smallint"); + + b.Property("SourceItemLevel") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("ItemDefinitionId"); + + b.HasIndex("MonsterId"); + + b.ToTable("ItemDropItemGroup", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDropItemGroupItemDefinition", b => + { + b.Property("ItemDropItemGroupId") + .HasColumnType("uuid"); + + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.HasKey("ItemDropItemGroupId", "ItemDefinitionId"); + + b.HasIndex("ItemDefinitionId"); + + b.ToTable("ItemDropItemGroupItemDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemItemOfItemSet", b => + { + b.Property("ItemId") + .HasColumnType("uuid"); + + b.Property("ItemOfItemSetId") + .HasColumnType("uuid"); + + b.HasKey("ItemId", "ItemOfItemSetId"); + + b.HasIndex("ItemOfItemSetId"); + + b.ToTable("ItemItemOfItemSet", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemLevelBonusTable", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.ToTable("ItemLevelBonusTable", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOfItemSet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AncientSetDiscriminator") + .HasColumnType("integer"); + + b.Property("BonusOptionId") + .HasColumnType("uuid"); + + b.Property("ItemDefinitionId") + .HasColumnType("uuid"); + + b.Property("ItemSetGroupId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("BonusOptionId"); + + b.HasIndex("ItemDefinitionId"); + + b.HasIndex("ItemSetGroupId"); + + b.ToTable("ItemOfItemSet", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOption", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Number") + .HasColumnType("integer"); + + b.Property("OptionTypeId") + .HasColumnType("uuid"); + + b.Property("PowerUpDefinitionId") + .HasColumnType("uuid"); + + b.Property("SubOptionType") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("OptionTypeId"); + + b.HasIndex("PowerUpDefinitionId") + .IsUnique(); + + b.ToTable("ItemOption", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionCombinationBonus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AppliesMultipleTimes") + .HasColumnType("boolean"); + + b.Property("BonusId") + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("Number") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("BonusId") + .IsUnique(); + + b.HasIndex("GameConfigurationId"); + + b.ToTable("ItemOptionCombinationBonus", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AddChance") + .HasColumnType("real"); + + b.Property("AddsRandomly") + .HasColumnType("boolean"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("MaximumOptionsPerItem") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.ToTable("ItemOptionDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionLink", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Index") + .HasColumnType("integer"); + + b.Property("ItemId") + .HasColumnType("uuid"); + + b.Property("ItemOptionId") + .HasColumnType("uuid"); + + b.Property("Level") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ItemId"); + + b.HasIndex("ItemOptionId"); + + b.ToTable("ItemOptionLink", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionOfLevel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("IncreasableItemOptionId") + .HasColumnType("uuid"); + + b.Property("Level") + .HasColumnType("integer"); + + b.Property("PowerUpDefinitionId") + .HasColumnType("uuid"); + + b.Property("RequiredItemLevel") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("IncreasableItemOptionId"); + + b.HasIndex("PowerUpDefinitionId") + .IsUnique(); + + b.ToTable("ItemOptionOfLevel", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("IsVisible") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.ToTable("ItemOptionType", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemSetGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AlwaysApplies") + .HasColumnType("boolean"); + + b.Property("CountDistinct") + .HasColumnType("boolean"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("MinimumItemCount") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OptionsId") + .HasColumnType("uuid"); + + b.Property("SetLevel") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("OptionsId"); + + b.ToTable("ItemSetGroup", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemSlotType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("RawItemSlots") + .HasColumnType("text") + .HasColumnName("ItemSlots") + .HasAnnotation("Relational:JsonPropertyName", "itemSlots"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.ToTable("ItemSlotType", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemStorage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Money") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("ItemStorage", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.JewelMix", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("MixedJewelId") + .HasColumnType("uuid"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.Property("SingleJewelId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("MixedJewelId"); + + b.HasIndex("SingleJewelId"); + + b.ToTable("JewelMix", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.LetterBody", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Animation") + .HasColumnType("smallint"); + + b.Property("HeaderId") + .HasColumnType("uuid"); + + b.Property("Message") + .IsRequired() + .HasColumnType("text"); + + b.Property("Rotation") + .HasColumnType("smallint"); + + b.Property("SenderAppearanceId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("HeaderId"); + + b.HasIndex("SenderAppearanceId") + .IsUnique(); + + b.ToTable("LetterBody", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.LetterHeader", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CharacterId") + .HasColumnType("uuid"); + + b.Property("LetterDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ReadFlag") + .HasColumnType("boolean"); + + b.Property("ReceiverId") + .HasColumnType("uuid"); + + b.Property("SenderName") + .HasColumnType("text"); + + b.Property("Subject") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ReceiverId"); + + b.ToTable("LetterHeader", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.LevelBonus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AdditionalValue") + .HasColumnType("real"); + + b.Property("ItemLevelBonusTableId") + .HasColumnType("uuid"); + + b.Property("Level") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ItemLevelBonusTableId"); + + b.ToTable("LevelBonus", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MagicEffectDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DurationId") + .HasColumnType("uuid"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("InformObservers") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.Property("SendDuration") + .HasColumnType("boolean"); + + b.Property("StopByDeath") + .HasColumnType("boolean"); + + b.Property("SubType") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("DurationId") + .IsUnique(); + + b.HasIndex("GameConfigurationId"); + + b.ToTable("MagicEffectDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MasterSkillDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Aggregation") + .HasColumnType("integer"); + + b.Property("DisplayValueFormula") + .IsRequired() + .HasColumnType("text"); + + b.Property("MaximumLevel") + .HasColumnType("smallint"); + + b.Property("MinimumLevel") + .HasColumnType("smallint"); + + b.Property("Rank") + .HasColumnType("smallint"); + + b.Property("ReplacedSkillId") + .HasColumnType("uuid"); + + b.Property("RootId") + .HasColumnType("uuid"); + + b.Property("TargetAttributeId") + .HasColumnType("uuid"); + + b.Property("ValueFormula") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ReplacedSkillId"); + + b.HasIndex("RootId"); + + b.HasIndex("TargetAttributeId"); + + b.ToTable("MasterSkillDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MasterSkillDefinitionSkill", b => + { + b.Property("MasterSkillDefinitionId") + .HasColumnType("uuid"); + + b.Property("SkillId") + .HasColumnType("uuid"); + + b.HasKey("MasterSkillDefinitionId", "SkillId"); + + b.HasIndex("SkillId"); + + b.ToTable("MasterSkillDefinitionSkill", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MasterSkillRoot", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.ToTable("MasterSkillRoot", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameChangeEvent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("Index") + .HasColumnType("integer"); + + b.Property("Message") + .HasColumnType("text"); + + b.Property("MiniGameDefinitionId") + .HasColumnType("uuid"); + + b.Property("MinimumTargetLevel") + .HasColumnType("smallint"); + + b.Property("MultiplyKillsByPlayers") + .HasColumnType("boolean"); + + b.Property("NumberOfKills") + .HasColumnType("smallint"); + + b.Property("SpawnAreaId") + .HasColumnType("uuid"); + + b.Property("Target") + .HasColumnType("integer"); + + b.Property("TargetDefinitionId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("MiniGameDefinitionId"); + + b.HasIndex("SpawnAreaId") + .IsUnique(); + + b.HasIndex("TargetDefinitionId"); + + b.ToTable("MiniGameChangeEvent", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AllowParty") + .HasColumnType("boolean"); + + b.Property("ArePlayerKillersAllowedToEnter") + .HasColumnType("boolean"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("EnterDuration") + .HasColumnType("interval"); + + b.Property("EntranceFee") + .HasColumnType("integer"); + + b.Property("EntranceId") + .HasColumnType("uuid"); + + b.Property("ExitDuration") + .HasColumnType("interval"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("GameDuration") + .HasColumnType("interval"); + + b.Property("GameLevel") + .HasColumnType("smallint"); + + b.Property("MapCreationPolicy") + .HasColumnType("integer"); + + b.Property("MaximumCharacterLevel") + .HasColumnType("integer"); + + b.Property("MaximumPlayerCount") + .HasColumnType("integer"); + + b.Property("MaximumSpecialCharacterLevel") + .HasColumnType("integer"); + + b.Property("MinimumCharacterLevel") + .HasColumnType("integer"); + + b.Property("MinimumSpecialCharacterLevel") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("RequiresMasterClass") + .HasColumnType("boolean"); + + b.Property("SaveRankingStatistics") + .HasColumnType("boolean"); + + b.Property("TicketItemId") + .HasColumnType("uuid"); + + b.Property("TicketItemLevel") + .HasColumnType("integer"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("EntranceId"); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("TicketItemId"); + + b.ToTable("MiniGameDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameRankingEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CharacterId") + .HasColumnType("uuid"); + + b.Property("GameInstanceId") + .HasColumnType("uuid"); + + b.Property("MiniGameId") + .HasColumnType("uuid"); + + b.Property("Rank") + .HasColumnType("integer"); + + b.Property("Score") + .HasColumnType("integer"); + + b.Property("Timestamp") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("CharacterId"); + + b.HasIndex("MiniGameId"); + + b.ToTable("MiniGameRankingEntry", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameReward", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ItemRewardId") + .HasColumnType("uuid"); + + b.Property("MiniGameDefinitionId") + .HasColumnType("uuid"); + + b.Property("Rank") + .HasColumnType("integer"); + + b.Property("RequiredKillId") + .HasColumnType("uuid"); + + b.Property("RequiredSuccess") + .HasColumnType("integer"); + + b.Property("RewardAmount") + .HasColumnType("integer"); + + b.Property("RewardType") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ItemRewardId"); + + b.HasIndex("MiniGameDefinitionId"); + + b.HasIndex("RequiredKillId"); + + b.ToTable("MiniGameReward", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameSpawnWave", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("EndTime") + .HasColumnType("interval"); + + b.Property("Message") + .HasColumnType("text"); + + b.Property("MiniGameDefinitionId") + .HasColumnType("uuid"); + + b.Property("StartTime") + .HasColumnType("interval"); + + b.Property("WaveNumber") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("MiniGameDefinitionId"); + + b.ToTable("MiniGameSpawnWave", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameTerrainChange", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("EndX") + .HasColumnType("smallint"); + + b.Property("EndY") + .HasColumnType("smallint"); + + b.Property("IsClientUpdateRequired") + .HasColumnType("boolean"); + + b.Property("MiniGameChangeEventId") + .HasColumnType("uuid"); + + b.Property("SetTerrainAttribute") + .HasColumnType("boolean"); + + b.Property("StartX") + .HasColumnType("smallint"); + + b.Property("StartY") + .HasColumnType("smallint"); + + b.Property("TerrainAttribute") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("MiniGameChangeEventId"); + + b.ToTable("MiniGameTerrainChange", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterAttribute", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AttributeDefinitionId") + .HasColumnType("uuid"); + + b.Property("MonsterDefinitionId") + .HasColumnType("uuid"); + + b.Property("Value") + .HasColumnType("real"); + + b.HasKey("Id"); + + b.HasIndex("AttributeDefinitionId"); + + b.HasIndex("MonsterDefinitionId"); + + b.ToTable("MonsterAttribute", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AttackDelay") + .HasColumnType("interval"); + + b.Property("AttackRange") + .HasColumnType("smallint"); + + b.Property("AttackSkillId") + .HasColumnType("uuid"); + + b.Property("Attribute") + .HasColumnType("smallint"); + + b.Property("Designation") + .IsRequired() + .HasColumnType("text"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("IntelligenceTypeName") + .HasColumnType("text"); + + b.Property("MerchantStoreId") + .HasColumnType("uuid"); + + b.Property("MoveDelay") + .HasColumnType("interval"); + + b.Property("MoveRange") + .HasColumnType("smallint"); + + b.Property("NpcWindow") + .HasColumnType("integer"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.Property("NumberOfMaximumItemDrops") + .HasColumnType("integer"); + + b.Property("ObjectKind") + .HasColumnType("integer"); + + b.Property("RespawnDelay") + .HasColumnType("interval"); + + b.Property("ViewRange") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("AttackSkillId"); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("MerchantStoreId") + .IsUnique(); + + b.ToTable("MonsterDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinitionDropItemGroup", b => + { + b.Property("MonsterDefinitionId") + .HasColumnType("uuid"); + + b.Property("DropItemGroupId") + .HasColumnType("uuid"); + + b.HasKey("MonsterDefinitionId", "DropItemGroupId"); + + b.HasIndex("DropItemGroupId"); + + b.ToTable("MonsterDefinitionDropItemGroup", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterSpawnArea", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Direction") + .HasColumnType("integer"); + + b.Property("GameMapDefinitionId") + .HasColumnType("uuid"); + + b.Property("GameMapId") + .HasColumnType("uuid"); + + b.Property("MaximumHealthOverride") + .HasColumnType("integer"); + + b.Property("MonsterDefinitionId") + .HasColumnType("uuid"); + + b.Property("Quantity") + .HasColumnType("smallint"); + + b.Property("SpawnTrigger") + .HasColumnType("integer"); + + b.Property("WaveNumber") + .HasColumnType("smallint"); + + b.Property("X1") + .HasColumnType("smallint"); + + b.Property("X2") + .HasColumnType("smallint"); + + b.Property("Y1") + .HasColumnType("smallint"); + + b.Property("Y2") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("GameMapDefinitionId"); + + b.HasIndex("GameMapId"); + + b.HasIndex("MonsterDefinitionId"); + + b.ToTable("MonsterSpawnArea", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.PlugInConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CustomConfiguration") + .HasColumnType("text"); + + b.Property("CustomPlugInSource") + .HasColumnType("text"); + + b.Property("ExternalAssemblyName") + .HasColumnType("text"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("TypeId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.ToTable("PlugInConfiguration", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BoostId") + .HasColumnType("uuid"); + + b.Property("GameMapDefinitionId") + .HasColumnType("uuid"); + + b.Property("MagicEffectDefinitionId") + .HasColumnType("uuid"); + + b.Property("TargetAttributeId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("BoostId") + .IsUnique(); + + b.HasIndex("GameMapDefinitionId"); + + b.HasIndex("MagicEffectDefinitionId"); + + b.HasIndex("TargetAttributeId"); + + b.ToTable("PowerUpDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinitionValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AggregateType") + .HasColumnType("integer"); + + b.Property("Value") + .HasColumnType("real"); + + b.HasKey("Id"); + + b.ToTable("PowerUpDefinitionValue", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Group") + .HasColumnType("smallint"); + + b.Property("MaximumCharacterLevel") + .HasColumnType("integer"); + + b.Property("MinimumCharacterLevel") + .HasColumnType("integer"); + + b.Property("MonsterDefinitionId") + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.Property("QualifiedCharacterId") + .HasColumnType("uuid"); + + b.Property("QuestGiverId") + .HasColumnType("uuid"); + + b.Property("RefuseNumber") + .HasColumnType("smallint"); + + b.Property("Repeatable") + .HasColumnType("boolean"); + + b.Property("RequiredStartMoney") + .HasColumnType("integer"); + + b.Property("RequiresClientAction") + .HasColumnType("boolean"); + + b.Property("StartingNumber") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("MonsterDefinitionId"); + + b.HasIndex("QualifiedCharacterId"); + + b.HasIndex("QuestGiverId"); + + b.ToTable("QuestDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestItemRequirement", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DropItemGroupId") + .HasColumnType("uuid"); + + b.Property("ItemId") + .HasColumnType("uuid"); + + b.Property("MinimumNumber") + .HasColumnType("integer"); + + b.Property("QuestDefinitionId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("DropItemGroupId"); + + b.HasIndex("ItemId"); + + b.HasIndex("QuestDefinitionId"); + + b.ToTable("QuestItemRequirement", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestMonsterKillRequirement", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("MinimumNumber") + .HasColumnType("integer"); + + b.Property("MonsterId") + .HasColumnType("uuid"); + + b.Property("QuestDefinitionId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("MonsterId"); + + b.HasIndex("QuestDefinitionId"); + + b.ToTable("QuestMonsterKillRequirement", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestMonsterKillRequirementState", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CharacterQuestStateId") + .HasColumnType("uuid"); + + b.Property("KillCount") + .HasColumnType("integer"); + + b.Property("RequirementId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CharacterQuestStateId"); + + b.HasIndex("RequirementId"); + + b.ToTable("QuestMonsterKillRequirementState", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestReward", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AttributeRewardId") + .HasColumnType("uuid"); + + b.Property("ItemRewardId") + .HasColumnType("uuid"); + + b.Property("QuestDefinitionId") + .HasColumnType("uuid"); + + b.Property("RewardType") + .HasColumnType("integer"); + + b.Property("SkillRewardId") + .HasColumnType("uuid"); + + b.Property("Value") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("AttributeRewardId"); + + b.HasIndex("ItemRewardId") + .IsUnique(); + + b.HasIndex("QuestDefinitionId"); + + b.HasIndex("SkillRewardId"); + + b.ToTable("QuestReward", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Rectangle", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("X1") + .HasColumnType("smallint"); + + b.Property("X2") + .HasColumnType("smallint"); + + b.Property("Y1") + .HasColumnType("smallint"); + + b.Property("Y2") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.ToTable("Rectangle", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SimpleCraftingSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("MaximumSuccessPercent") + .HasColumnType("smallint"); + + b.Property("Money") + .HasColumnType("integer"); + + b.Property("MoneyPerFinalSuccessPercentage") + .HasColumnType("integer"); + + b.Property("MultipleAllowed") + .HasColumnType("boolean"); + + b.Property("ResultItemExcellentOptionChance") + .HasColumnType("smallint"); + + b.Property("ResultItemLuckOptionChance") + .HasColumnType("smallint"); + + b.Property("ResultItemMaxExcOptionCount") + .HasColumnType("smallint"); + + b.Property("ResultItemSelect") + .HasColumnType("integer"); + + b.Property("ResultItemSkillChance") + .HasColumnType("smallint"); + + b.Property("SuccessPercent") + .HasColumnType("smallint"); + + b.Property("SuccessPercentageAdditionForAncientItem") + .HasColumnType("integer"); + + b.Property("SuccessPercentageAdditionForExcellentItem") + .HasColumnType("integer"); + + b.Property("SuccessPercentageAdditionForLuck") + .HasColumnType("integer"); + + b.Property("SuccessPercentageAdditionForSocketItem") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("SimpleCraftingSettings", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AttackDamage") + .HasColumnType("integer"); + + b.Property("DamageType") + .HasColumnType("integer"); + + b.Property("ElementalModifierTargetId") + .HasColumnType("uuid"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("ImplicitTargetRange") + .HasColumnType("smallint"); + + b.Property("MagicEffectDefId") + .HasColumnType("uuid"); + + b.Property("MasterDefinitionId") + .HasColumnType("uuid"); + + b.Property("MovesTarget") + .HasColumnType("boolean"); + + b.Property("MovesToTarget") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.Property("Range") + .HasColumnType("smallint"); + + b.Property("SkillType") + .HasColumnType("integer"); + + b.Property("Target") + .HasColumnType("integer"); + + b.Property("TargetRestriction") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ElementalModifierTargetId"); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("MagicEffectDefId"); + + b.HasIndex("MasterDefinitionId") + .IsUnique(); + + b.ToTable("Skill", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillCharacterClass", b => + { + b.Property("SkillId") + .HasColumnType("uuid"); + + b.Property("CharacterClassId") + .HasColumnType("uuid"); + + b.HasKey("SkillId", "CharacterClassId"); + + b.HasIndex("CharacterClassId"); + + b.ToTable("SkillCharacterClass", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillComboDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("MaximumCompletionTime") + .HasColumnType("interval"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("SkillComboDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillComboStep", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("IsFinalStep") + .HasColumnType("boolean"); + + b.Property("Order") + .HasColumnType("integer"); + + b.Property("SkillComboDefinitionId") + .HasColumnType("uuid"); + + b.Property("SkillId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("SkillComboDefinitionId"); + + b.HasIndex("SkillId"); + + b.ToTable("SkillComboStep", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CharacterId") + .HasColumnType("uuid"); + + b.Property("Level") + .HasColumnType("integer"); + + b.Property("SkillId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CharacterId"); + + b.HasIndex("SkillId"); + + b.ToTable("SkillEntry", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.StatAttribute", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountId") + .HasColumnType("uuid"); + + b.Property("CharacterId") + .HasColumnType("uuid"); + + b.Property("DefinitionId") + .HasColumnType("uuid"); + + b.Property("Value") + .HasColumnType("real"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("CharacterId"); + + b.HasIndex("DefinitionId"); + + b.ToTable("StatAttribute", "data"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.StatAttributeDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AttributeId") + .HasColumnType("uuid"); + + b.Property("BaseValue") + .HasColumnType("real"); + + b.Property("CharacterClassId") + .HasColumnType("uuid"); + + b.Property("IncreasableByPlayer") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.HasIndex("AttributeId"); + + b.HasIndex("CharacterClassId"); + + b.ToTable("StatAttributeDefinition", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SystemConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AutoStart") + .HasColumnType("boolean"); + + b.Property("AutoUpdateSchema") + .HasColumnType("boolean"); + + b.Property("IpResolver") + .HasColumnType("integer"); + + b.Property("IpResolverParameter") + .HasColumnType("text"); + + b.Property("ReadConsoleInput") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("SystemConfiguration", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.WarpInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Costs") + .HasColumnType("integer"); + + b.Property("GameConfigurationId") + .HasColumnType("uuid"); + + b.Property("GateId") + .HasColumnType("uuid"); + + b.Property("Index") + .HasColumnType("integer"); + + b.Property("LevelRequirement") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("GameConfigurationId"); + + b.HasIndex("GateId"); + + b.ToTable("WarpInfo", "config"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Account", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemStorage", "RawVault") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.Account", "VaultId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawVault"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AccountCharacterClass", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Account", "Account") + .WithMany("JoinedUnlockedCharacterClasses") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", "CharacterClass") + .WithMany() + .HasForeignKey("CharacterClassId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("CharacterClass"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AppearanceData", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", "RawCharacterClass") + .WithMany() + .HasForeignKey("CharacterClassId"); + + b.Navigation("RawCharacterClass"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawAttributes") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeRelationship", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", null) + .WithMany("RawAttributeCombinations") + .HasForeignKey("CharacterClassId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawInputAttribute") + .WithMany() + .HasForeignKey("InputAttributeId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawOperandAttribute") + .WithMany() + .HasForeignKey("OperandAttributeId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinitionValue", null) + .WithMany("RawRelatedValues") + .HasForeignKey("PowerUpDefinitionValueId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawTargetAttribute") + .WithMany() + .HasForeignKey("TargetAttributeId"); + + b.Navigation("RawInputAttribute"); + + b.Navigation("RawOperandAttribute"); + + b.Navigation("RawTargetAttribute"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeRequirement", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawAttribute") + .WithMany() + .HasForeignKey("AttributeId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", null) + .WithMany("RawMapRequirements") + .HasForeignKey("GameMapDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", null) + .WithMany("RawRequirements") + .HasForeignKey("ItemDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", null) + .WithMany("RawConsumeRequirements") + .HasForeignKey("SkillId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", null) + .WithMany("RawRequirements") + .HasForeignKey("SkillId1") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawAttribute"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.BattleZoneDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Rectangle", "RawGround") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.BattleZoneDefinition", "GroundId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Rectangle", "RawLeftGoal") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.BattleZoneDefinition", "LeftGoalId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Rectangle", "RawRightGoal") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.BattleZoneDefinition", "RightGoalId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawGround"); + + b.Navigation("RawLeftGoal"); + + b.Navigation("RawRightGoal"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Character", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Account", null) + .WithMany("RawCharacters") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", "RawCharacterClass") + .WithMany() + .HasForeignKey("CharacterClassId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", "RawCurrentMap") + .WithMany() + .HasForeignKey("CurrentMapId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemStorage", "RawInventory") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.Character", "InventoryId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawCharacterClass"); + + b.Navigation("RawCurrentMap"); + + b.Navigation("RawInventory"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillComboDefinition", "RawComboDefinition") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", "ComboDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawCharacterClasses") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", "RawHomeMap") + .WithMany() + .HasForeignKey("HomeMapId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", "RawNextGenerationClass") + .WithMany() + .HasForeignKey("NextGenerationClassId"); + + b.Navigation("RawComboDefinition"); + + b.Navigation("RawHomeMap"); + + b.Navigation("RawNextGenerationClass"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterDropItemGroup", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Character", "Character") + .WithMany("JoinedDropItemGroups") + .HasForeignKey("CharacterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.DropItemGroup", "DropItemGroup") + .WithMany() + .HasForeignKey("DropItemGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Character"); + + b.Navigation("DropItemGroup"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterQuestState", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestDefinition", "RawActiveQuest") + .WithMany() + .HasForeignKey("ActiveQuestId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Character", null) + .WithMany("RawQuestStates") + .HasForeignKey("CharacterId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestDefinition", "RawLastFinishedQuest") + .WithMany() + .HasForeignKey("LastFinishedQuestId"); + + b.Navigation("RawActiveQuest"); + + b.Navigation("RawLastFinishedQuest"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ChatServerEndpoint", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ChatServerDefinition", null) + .WithMany("RawEndpoints") + .HasForeignKey("ChatServerDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameClientDefinition", "RawClient") + .WithMany() + .HasForeignKey("ClientId"); + + b.Navigation("RawClient"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.CombinationBonusRequirement", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionCombinationBonus", null) + .WithMany("RawRequirements") + .HasForeignKey("ItemOptionCombinationBonusId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionType", "RawOptionType") + .WithMany() + .HasForeignKey("OptionTypeId"); + + b.Navigation("RawOptionType"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ConnectServerDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameClientDefinition", "RawClient") + .WithMany() + .HasForeignKey("ClientId"); + + b.Navigation("RawClient"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ConstValueAttribute", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", "CharacterClass") + .WithMany("RawBaseAttributeValues") + .HasForeignKey("CharacterClassId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawDefinition") + .WithMany() + .HasForeignKey("DefinitionId"); + + b.Navigation("CharacterClass"); + + b.Navigation("RawDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.DropItemGroup", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawDropItemGroups") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", "RawMonster") + .WithMany() + .HasForeignKey("MonsterId"); + + b.Navigation("RawMonster"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.DropItemGroupItemDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.DropItemGroup", "DropItemGroup") + .WithMany("JoinedPossibleItems") + .HasForeignKey("DropItemGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "ItemDefinition") + .WithMany() + .HasForeignKey("ItemDefinitionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("DropItemGroup"); + + b.Navigation("ItemDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.EnterGate", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", null) + .WithMany("RawEnterGates") + .HasForeignKey("GameMapDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ExitGate", "RawTargetGate") + .WithMany() + .HasForeignKey("TargetGateId"); + + b.Navigation("RawTargetGate"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ExitGate", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", "RawMap") + .WithMany("RawExitGates") + .HasForeignKey("MapId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawMap"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.BattleZoneDefinition", "RawBattleZone") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", "BattleZoneId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawMaps") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", "RawSafezoneMap") + .WithMany() + .HasForeignKey("SafezoneMapId"); + + b.Navigation("RawBattleZone"); + + b.Navigation("RawSafezoneMap"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinitionDropItemGroup", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.DropItemGroup", "DropItemGroup") + .WithMany() + .HasForeignKey("DropItemGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", "GameMapDefinition") + .WithMany("JoinedDropItemGroups") + .HasForeignKey("GameMapDefinitionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("DropItemGroup"); + + b.Navigation("GameMapDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerConfigurationGameMapDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", "GameMapDefinition") + .WithMany() + .HasForeignKey("GameMapDefinitionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerConfiguration", "GameServerConfiguration") + .WithMany("JoinedMaps") + .HasForeignKey("GameServerConfigurationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("GameMapDefinition"); + + b.Navigation("GameServerConfiguration"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", "RawGameConfiguration") + .WithMany() + .HasForeignKey("GameConfigurationId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerConfiguration", "RawServerConfiguration") + .WithMany() + .HasForeignKey("ServerConfigurationId"); + + b.Navigation("RawGameConfiguration"); + + b.Navigation("RawServerConfiguration"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerEndpoint", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameClientDefinition", "RawClient") + .WithMany() + .HasForeignKey("ClientId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerDefinition", null) + .WithMany("RawEndpoints") + .HasForeignKey("GameServerDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawClient"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Guild", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Guild", "RawAllianceGuild") + .WithMany() + .HasForeignKey("AllianceGuildId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Guild", "RawHostility") + .WithMany() + .HasForeignKey("HostilityId"); + + b.Navigation("RawAllianceGuild"); + + b.Navigation("RawHostility"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GuildMember", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Guild", null) + .WithMany("RawMembers") + .HasForeignKey("GuildId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Character", "Character") + .WithMany() + .HasForeignKey("Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Character"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.IncreasableItemOption", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionDefinition", null) + .WithMany("RawPossibleOptions") + .HasForeignKey("ItemOptionDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionType", "RawOptionType") + .WithMany() + .HasForeignKey("OptionTypeId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinition", "RawPowerUpDefinition") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.IncreasableItemOption", "PowerUpDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawOptionType"); + + b.Navigation("RawPowerUpDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Item", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "RawDefinition") + .WithMany() + .HasForeignKey("DefinitionId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemStorage", "RawItemStorage") + .WithMany("RawItems") + .HasForeignKey("ItemStorageId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawDefinition"); + + b.Navigation("RawItemStorage"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemAppearance", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AppearanceData", null) + .WithMany("RawEquippedItems") + .HasForeignKey("AppearanceDataId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "RawDefinition") + .WithMany() + .HasForeignKey("DefinitionId"); + + b.Navigation("RawDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemAppearanceItemOptionType", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemAppearance", "ItemAppearance") + .WithMany("JoinedVisibleOptions") + .HasForeignKey("ItemAppearanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionType", "ItemOptionType") + .WithMany() + .HasForeignKey("ItemOptionTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ItemAppearance"); + + b.Navigation("ItemOptionType"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemBasePowerUpDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemLevelBonusTable", "RawBonusPerLevelTable") + .WithMany() + .HasForeignKey("BonusPerLevelTableId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", null) + .WithMany("RawBasePowerUpAttributes") + .HasForeignKey("ItemDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawTargetAttribute") + .WithMany() + .HasForeignKey("TargetAttributeId"); + + b.Navigation("RawBonusPerLevelTable"); + + b.Navigation("RawTargetAttribute"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCrafting", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", null) + .WithMany("RawItemCraftings") + .HasForeignKey("MonsterDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.SimpleCraftingSettings", "RawSimpleCraftingSettings") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCrafting", "SimpleCraftingSettingsId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawSimpleCraftingSettings"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingRequiredItem", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.SimpleCraftingSettings", null) + .WithMany("RawRequiredItems") + .HasForeignKey("SimpleCraftingSettingsId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingRequiredItemItemDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingRequiredItem", "ItemCraftingRequiredItem") + .WithMany("JoinedPossibleItems") + .HasForeignKey("ItemCraftingRequiredItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "ItemDefinition") + .WithMany() + .HasForeignKey("ItemDefinitionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ItemCraftingRequiredItem"); + + b.Navigation("ItemDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingRequiredItemItemOptionType", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingRequiredItem", "ItemCraftingRequiredItem") + .WithMany("JoinedRequiredItemOptions") + .HasForeignKey("ItemCraftingRequiredItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionType", "ItemOptionType") + .WithMany() + .HasForeignKey("ItemOptionTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ItemCraftingRequiredItem"); + + b.Navigation("ItemOptionType"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingResultItem", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "RawItemDefinition") + .WithMany() + .HasForeignKey("ItemDefinitionId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.SimpleCraftingSettings", null) + .WithMany("RawResultItems") + .HasForeignKey("SimpleCraftingSettingsId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawItemDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MagicEffectDefinition", "RawConsumeEffect") + .WithMany() + .HasForeignKey("ConsumeEffectId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawItems") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemSlotType", "RawItemSlot") + .WithMany() + .HasForeignKey("ItemSlotId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", "RawSkill") + .WithMany() + .HasForeignKey("SkillId"); + + b.Navigation("RawConsumeEffect"); + + b.Navigation("RawItemSlot"); + + b.Navigation("RawSkill"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinitionCharacterClass", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", "CharacterClass") + .WithMany() + .HasForeignKey("CharacterClassId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "ItemDefinition") + .WithMany("JoinedQualifiedCharacters") + .HasForeignKey("ItemDefinitionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CharacterClass"); + + b.Navigation("ItemDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinitionItemOptionDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "ItemDefinition") + .WithMany("JoinedPossibleItemOptions") + .HasForeignKey("ItemDefinitionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionDefinition", "ItemOptionDefinition") + .WithMany() + .HasForeignKey("ItemOptionDefinitionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ItemDefinition"); + + b.Navigation("ItemOptionDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinitionItemSetGroup", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "ItemDefinition") + .WithMany("JoinedPossibleItemSetGroups") + .HasForeignKey("ItemDefinitionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemSetGroup", "ItemSetGroup") + .WithMany() + .HasForeignKey("ItemSetGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ItemDefinition"); + + b.Navigation("ItemSetGroup"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDropItemGroup", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", null) + .WithMany("RawDropItems") + .HasForeignKey("ItemDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", "RawMonster") + .WithMany() + .HasForeignKey("MonsterId"); + + b.Navigation("RawMonster"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDropItemGroupItemDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "ItemDefinition") + .WithMany() + .HasForeignKey("ItemDefinitionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDropItemGroup", "ItemDropItemGroup") + .WithMany("JoinedPossibleItems") + .HasForeignKey("ItemDropItemGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ItemDefinition"); + + b.Navigation("ItemDropItemGroup"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemItemOfItemSet", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Item", "Item") + .WithMany("JoinedItemSetGroups") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOfItemSet", "ItemOfItemSet") + .WithMany() + .HasForeignKey("ItemOfItemSetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Item"); + + b.Navigation("ItemOfItemSet"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemLevelBonusTable", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawItemLevelBonusTables") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOfItemSet", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.IncreasableItemOption", "RawBonusOption") + .WithMany() + .HasForeignKey("BonusOptionId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "RawItemDefinition") + .WithMany() + .HasForeignKey("ItemDefinitionId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemSetGroup", "RawItemSetGroup") + .WithMany("RawItems") + .HasForeignKey("ItemSetGroupId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawBonusOption"); + + b.Navigation("RawItemDefinition"); + + b.Navigation("RawItemSetGroup"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOption", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionType", "RawOptionType") + .WithMany() + .HasForeignKey("OptionTypeId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinition", "RawPowerUpDefinition") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOption", "PowerUpDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawOptionType"); + + b.Navigation("RawPowerUpDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionCombinationBonus", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinition", "RawBonus") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionCombinationBonus", "BonusId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawItemOptionCombinationBonuses") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawBonus"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawItemOptions") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionLink", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Item", null) + .WithMany("RawItemOptions") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.IncreasableItemOption", "RawItemOption") + .WithMany() + .HasForeignKey("ItemOptionId"); + + b.Navigation("RawItemOption"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionOfLevel", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.IncreasableItemOption", null) + .WithMany("RawLevelDependentOptions") + .HasForeignKey("IncreasableItemOptionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinition", "RawPowerUpDefinition") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionOfLevel", "PowerUpDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawPowerUpDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionType", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawItemOptionTypes") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemSetGroup", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawItemSetGroups") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionDefinition", "RawOptions") + .WithMany() + .HasForeignKey("OptionsId"); + + b.Navigation("RawOptions"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemSlotType", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawItemSlotTypes") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.JewelMix", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawJewelMixes") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "RawMixedJewel") + .WithMany() + .HasForeignKey("MixedJewelId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "RawSingleJewel") + .WithMany() + .HasForeignKey("SingleJewelId"); + + b.Navigation("RawMixedJewel"); + + b.Navigation("RawSingleJewel"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.LetterBody", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.LetterHeader", "RawHeader") + .WithMany() + .HasForeignKey("HeaderId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AppearanceData", "RawSenderAppearance") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.LetterBody", "SenderAppearanceId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawHeader"); + + b.Navigation("RawSenderAppearance"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.LetterHeader", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Character", "Receiver") + .WithMany("RawLetters") + .HasForeignKey("ReceiverId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Receiver"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.LevelBonus", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemLevelBonusTable", null) + .WithMany("RawBonusPerLevel") + .HasForeignKey("ItemLevelBonusTableId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MagicEffectDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinitionValue", "RawDuration") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.MagicEffectDefinition", "DurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawMagicEffects") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawDuration"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MasterSkillDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", "RawReplacedSkill") + .WithMany() + .HasForeignKey("ReplacedSkillId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MasterSkillRoot", "RawRoot") + .WithMany() + .HasForeignKey("RootId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawTargetAttribute") + .WithMany() + .HasForeignKey("TargetAttributeId"); + + b.Navigation("RawReplacedSkill"); + + b.Navigation("RawRoot"); + + b.Navigation("RawTargetAttribute"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MasterSkillDefinitionSkill", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MasterSkillDefinition", "MasterSkillDefinition") + .WithMany("JoinedRequiredMasterSkills") + .HasForeignKey("MasterSkillDefinitionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", "Skill") + .WithMany() + .HasForeignKey("SkillId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MasterSkillDefinition"); + + b.Navigation("Skill"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MasterSkillRoot", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawMasterSkillRoots") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameChangeEvent", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameDefinition", null) + .WithMany("RawChangeEvents") + .HasForeignKey("MiniGameDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterSpawnArea", "RawSpawnArea") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameChangeEvent", "SpawnAreaId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", "RawTargetDefinition") + .WithMany() + .HasForeignKey("TargetDefinitionId"); + + b.Navigation("RawSpawnArea"); + + b.Navigation("RawTargetDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ExitGate", "RawEntrance") + .WithMany() + .HasForeignKey("EntranceId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawMiniGameDefinitions") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "RawTicketItem") + .WithMany() + .HasForeignKey("TicketItemId"); + + b.Navigation("RawEntrance"); + + b.Navigation("RawTicketItem"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameRankingEntry", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Character", "RawCharacter") + .WithMany() + .HasForeignKey("CharacterId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameDefinition", "RawMiniGame") + .WithMany() + .HasForeignKey("MiniGameId"); + + b.Navigation("RawCharacter"); + + b.Navigation("RawMiniGame"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameReward", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.DropItemGroup", "RawItemReward") + .WithMany() + .HasForeignKey("ItemRewardId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameDefinition", null) + .WithMany("RawRewards") + .HasForeignKey("MiniGameDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", "RawRequiredKill") + .WithMany() + .HasForeignKey("RequiredKillId"); + + b.Navigation("RawItemReward"); + + b.Navigation("RawRequiredKill"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameSpawnWave", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameDefinition", null) + .WithMany("RawSpawnWaves") + .HasForeignKey("MiniGameDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameTerrainChange", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameChangeEvent", null) + .WithMany("RawTerrainChanges") + .HasForeignKey("MiniGameChangeEventId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterAttribute", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawAttributeDefinition") + .WithMany() + .HasForeignKey("AttributeDefinitionId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", null) + .WithMany("RawAttributes") + .HasForeignKey("MonsterDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawAttributeDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", "RawAttackSkill") + .WithMany() + .HasForeignKey("AttackSkillId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawMonsters") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemStorage", "RawMerchantStore") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", "MerchantStoreId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawAttackSkill"); + + b.Navigation("RawMerchantStore"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinitionDropItemGroup", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.DropItemGroup", "DropItemGroup") + .WithMany() + .HasForeignKey("DropItemGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", "MonsterDefinition") + .WithMany("JoinedDropItemGroups") + .HasForeignKey("MonsterDefinitionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("DropItemGroup"); + + b.Navigation("MonsterDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterSpawnArea", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", null) + .WithMany("RawMonsterSpawns") + .HasForeignKey("GameMapDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", "RawGameMap") + .WithMany() + .HasForeignKey("GameMapId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", "RawMonsterDefinition") + .WithMany() + .HasForeignKey("MonsterDefinitionId"); + + b.Navigation("RawGameMap"); + + b.Navigation("RawMonsterDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.PlugInConfiguration", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawPlugInConfigurations") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinitionValue", "RawBoost") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinition", "BoostId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", null) + .WithMany("RawCharacterPowerUpDefinitions") + .HasForeignKey("GameMapDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MagicEffectDefinition", null) + .WithMany("RawPowerUpDefinitions") + .HasForeignKey("MagicEffectDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawTargetAttribute") + .WithMany() + .HasForeignKey("TargetAttributeId"); + + b.Navigation("RawBoost"); + + b.Navigation("RawTargetAttribute"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", null) + .WithMany("RawQuests") + .HasForeignKey("MonsterDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", "RawQualifiedCharacter") + .WithMany() + .HasForeignKey("QualifiedCharacterId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", "RawQuestGiver") + .WithMany() + .HasForeignKey("QuestGiverId"); + + b.Navigation("RawQualifiedCharacter"); + + b.Navigation("RawQuestGiver"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestItemRequirement", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.DropItemGroup", "RawDropItemGroup") + .WithMany() + .HasForeignKey("DropItemGroupId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", "RawItem") + .WithMany() + .HasForeignKey("ItemId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestDefinition", null) + .WithMany("RawRequiredItems") + .HasForeignKey("QuestDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawDropItemGroup"); + + b.Navigation("RawItem"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestMonsterKillRequirement", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", "RawMonster") + .WithMany() + .HasForeignKey("MonsterId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestDefinition", null) + .WithMany("RawRequiredMonsterKills") + .HasForeignKey("QuestDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawMonster"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestMonsterKillRequirementState", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterQuestState", null) + .WithMany("RawRequirementStates") + .HasForeignKey("CharacterQuestStateId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestMonsterKillRequirement", "RawRequirement") + .WithMany() + .HasForeignKey("RequirementId"); + + b.Navigation("RawRequirement"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestReward", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawAttributeReward") + .WithMany() + .HasForeignKey("AttributeRewardId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Item", "RawItemReward") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestReward", "ItemRewardId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestDefinition", null) + .WithMany("RawRewards") + .HasForeignKey("QuestDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", "RawSkillReward") + .WithMany() + .HasForeignKey("SkillRewardId"); + + b.Navigation("RawAttributeReward"); + + b.Navigation("RawItemReward"); + + b.Navigation("RawSkillReward"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawElementalModifierTarget") + .WithMany() + .HasForeignKey("ElementalModifierTargetId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawSkills") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MagicEffectDefinition", "RawMagicEffectDef") + .WithMany() + .HasForeignKey("MagicEffectDefId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.MasterSkillDefinition", "RawMasterDefinition") + .WithOne() + .HasForeignKey("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", "MasterDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawElementalModifierTarget"); + + b.Navigation("RawMagicEffectDef"); + + b.Navigation("RawMasterDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillCharacterClass", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", "CharacterClass") + .WithMany() + .HasForeignKey("CharacterClassId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", "Skill") + .WithMany("JoinedQualifiedCharacters") + .HasForeignKey("SkillId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CharacterClass"); + + b.Navigation("Skill"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillComboStep", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillComboDefinition", null) + .WithMany("RawSteps") + .HasForeignKey("SkillComboDefinitionId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", "RawSkill") + .WithMany() + .HasForeignKey("SkillId"); + + b.Navigation("RawSkill"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillEntry", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Character", null) + .WithMany("RawLearnedSkills") + .HasForeignKey("CharacterId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", "RawSkill") + .WithMany() + .HasForeignKey("SkillId"); + + b.Navigation("RawSkill"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.StatAttribute", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Account", null) + .WithMany("RawAttributes") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.Character", null) + .WithMany("RawAttributes") + .HasForeignKey("CharacterId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawDefinition") + .WithMany() + .HasForeignKey("DefinitionId"); + + b.Navigation("RawDefinition"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.StatAttributeDefinition", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.AttributeDefinition", "RawAttribute") + .WithMany() + .HasForeignKey("AttributeId"); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", null) + .WithMany("RawStatAttributes") + .HasForeignKey("CharacterClassId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("RawAttribute"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.WarpInfo", b => + { + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", null) + .WithMany("RawWarpList") + .HasForeignKey("GameConfigurationId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ExitGate", "RawGate") + .WithMany() + .HasForeignKey("GateId"); + + b.Navigation("RawGate"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Account", b => + { + b.Navigation("JoinedUnlockedCharacterClasses"); + + b.Navigation("RawAttributes"); + + b.Navigation("RawCharacters"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.AppearanceData", b => + { + b.Navigation("RawEquippedItems"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Character", b => + { + b.Navigation("JoinedDropItemGroups"); + + b.Navigation("RawAttributes"); + + b.Navigation("RawLearnedSkills"); + + b.Navigation("RawLetters"); + + b.Navigation("RawQuestStates"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterClass", b => + { + b.Navigation("RawAttributeCombinations"); + + b.Navigation("RawBaseAttributeValues"); + + b.Navigation("RawStatAttributes"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.CharacterQuestState", b => + { + b.Navigation("RawRequirementStates"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ChatServerDefinition", b => + { + b.Navigation("RawEndpoints"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.DropItemGroup", b => + { + b.Navigation("JoinedPossibleItems"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameConfiguration", b => + { + b.Navigation("RawAttributes"); + + b.Navigation("RawCharacterClasses"); + + b.Navigation("RawDropItemGroups"); + + b.Navigation("RawItemLevelBonusTables"); + + b.Navigation("RawItemOptionCombinationBonuses"); + + b.Navigation("RawItemOptionTypes"); + + b.Navigation("RawItemOptions"); + + b.Navigation("RawItemSetGroups"); + + b.Navigation("RawItemSlotTypes"); + + b.Navigation("RawItems"); + + b.Navigation("RawJewelMixes"); + + b.Navigation("RawMagicEffects"); + + b.Navigation("RawMaps"); + + b.Navigation("RawMasterSkillRoots"); + + b.Navigation("RawMiniGameDefinitions"); + + b.Navigation("RawMonsters"); + + b.Navigation("RawPlugInConfigurations"); + + b.Navigation("RawSkills"); + + b.Navigation("RawWarpList"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameMapDefinition", b => + { + b.Navigation("JoinedDropItemGroups"); + + b.Navigation("RawCharacterPowerUpDefinitions"); + + b.Navigation("RawEnterGates"); + + b.Navigation("RawExitGates"); + + b.Navigation("RawMapRequirements"); + + b.Navigation("RawMonsterSpawns"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerConfiguration", b => + { + b.Navigation("JoinedMaps"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.GameServerDefinition", b => + { + b.Navigation("RawEndpoints"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Guild", b => + { + b.Navigation("RawMembers"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.IncreasableItemOption", b => + { + b.Navigation("RawLevelDependentOptions"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Item", b => + { + b.Navigation("JoinedItemSetGroups"); + + b.Navigation("RawItemOptions"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemAppearance", b => + { + b.Navigation("JoinedVisibleOptions"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemCraftingRequiredItem", b => + { + b.Navigation("JoinedPossibleItems"); + + b.Navigation("JoinedRequiredItemOptions"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDefinition", b => + { + b.Navigation("JoinedPossibleItemOptions"); + + b.Navigation("JoinedPossibleItemSetGroups"); + + b.Navigation("JoinedQualifiedCharacters"); + + b.Navigation("RawBasePowerUpAttributes"); + + b.Navigation("RawDropItems"); + + b.Navigation("RawRequirements"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemDropItemGroup", b => + { + b.Navigation("JoinedPossibleItems"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemLevelBonusTable", b => + { + b.Navigation("RawBonusPerLevel"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionCombinationBonus", b => + { + b.Navigation("RawRequirements"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionDefinition", b => + { + b.Navigation("RawPossibleOptions"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemSetGroup", b => + { + b.Navigation("RawItems"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemStorage", b => + { + b.Navigation("RawItems"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MagicEffectDefinition", b => + { + b.Navigation("RawPowerUpDefinitions"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MasterSkillDefinition", b => + { + b.Navigation("JoinedRequiredMasterSkills"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameChangeEvent", b => + { + b.Navigation("RawTerrainChanges"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MiniGameDefinition", b => + { + b.Navigation("RawChangeEvents"); + + b.Navigation("RawRewards"); + + b.Navigation("RawSpawnWaves"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.MonsterDefinition", b => + { + b.Navigation("JoinedDropItemGroups"); + + b.Navigation("RawAttributes"); + + b.Navigation("RawItemCraftings"); + + b.Navigation("RawQuests"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.PowerUpDefinitionValue", b => + { + b.Navigation("RawRelatedValues"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.QuestDefinition", b => + { + b.Navigation("RawRequiredItems"); + + b.Navigation("RawRequiredMonsterKills"); + + b.Navigation("RawRewards"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SimpleCraftingSettings", b => + { + b.Navigation("RawRequiredItems"); + + b.Navigation("RawResultItems"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.Skill", b => + { + b.Navigation("JoinedQualifiedCharacters"); + + b.Navigation("RawConsumeRequirements"); + + b.Navigation("RawRequirements"); + }); + + modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.SkillComboDefinition", b => + { + b.Navigation("RawSteps"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Persistence/EntityFramework/Migrations/20240602085237_FixItemOptions2.cs b/src/Persistence/EntityFramework/Migrations/20240602085237_FixItemOptions2.cs new file mode 100644 index 000000000..cc554bd8b --- /dev/null +++ b/src/Persistence/EntityFramework/Migrations/20240602085237_FixItemOptions2.cs @@ -0,0 +1,117 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace MUnique.OpenMU.Persistence.EntityFramework.Migrations +{ + /// + public partial class FixItemOptions2 : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_IncreasableItemOption_ItemSetGroup_ItemSetGroupId", + schema: "config", + table: "IncreasableItemOption"); + + migrationBuilder.DropIndex( + name: "IX_IncreasableItemOption_ItemSetGroupId", + schema: "config", + table: "IncreasableItemOption"); + + migrationBuilder.DropColumn( + name: "ItemSetGroupId", + schema: "config", + table: "IncreasableItemOption"); + + migrationBuilder.AddColumn( + name: "OptionsId", + schema: "config", + table: "ItemSetGroup", + type: "uuid", + nullable: true); + + migrationBuilder.CreateIndex( + name: "IX_ItemSetGroup_OptionsId", + schema: "config", + table: "ItemSetGroup", + column: "OptionsId"); + + migrationBuilder.AddForeignKey( + name: "FK_ItemSetGroup_ItemOptionDefinition_OptionsId", + schema: "config", + table: "ItemSetGroup", + column: "OptionsId", + principalSchema: "config", + principalTable: "ItemOptionDefinition", + principalColumn: "Id"); + + // Now we are left with ItemSetGroups which have no options assigned. + // Luckily, we can identify them by their UUIDs, they share the same pattern. + // First we care about ancient sets, which have the same id as the option definition, + // except in their prefix. + migrationBuilder.Sql( + """ + UPDATE config."ItemSetGroup" s + SET "OptionsId" = UUID(REPLACE(TEXT(s."Id"), '00000092-','00000083-')) + WHERE EXISTS(SELECT "Id" FROM config."ItemOptionDefinition" WHERE "Id" = UUID(REPLACE(TEXT(s."Id"), '00000092-','00000083-')) ) + """); + + // Then we look at the non-ancient sets. + migrationBuilder.Sql( + """ + UPDATE config."ItemSetGroup" s SET + "AlwaysApplies" = true, + "OptionsId" = + CASE + WHEN "SetLevel"=0 THEN uuid('00000083-0021-0000-0000-000000000000') + ELSE uuid('00000083-0020-000' || to_hex("SetLevel") || '-0000-000000000000') + END + WHERE "OptionsId" is null + """); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_ItemSetGroup_ItemOptionDefinition_OptionsId", + schema: "config", + table: "ItemSetGroup"); + + migrationBuilder.DropIndex( + name: "IX_ItemSetGroup_OptionsId", + schema: "config", + table: "ItemSetGroup"); + + migrationBuilder.DropColumn( + name: "OptionsId", + schema: "config", + table: "ItemSetGroup"); + + migrationBuilder.AddColumn( + name: "ItemSetGroupId", + schema: "config", + table: "IncreasableItemOption", + type: "uuid", + nullable: true); + + migrationBuilder.CreateIndex( + name: "IX_IncreasableItemOption_ItemSetGroupId", + schema: "config", + table: "IncreasableItemOption", + column: "ItemSetGroupId"); + + migrationBuilder.AddForeignKey( + name: "FK_IncreasableItemOption_ItemSetGroup_ItemSetGroupId", + schema: "config", + table: "IncreasableItemOption", + column: "ItemSetGroupId", + principalSchema: "config", + principalTable: "ItemSetGroup", + principalColumn: "Id"); + } + } +} diff --git a/src/Persistence/EntityFramework/Migrations/EntityDataContextModelSnapshot.cs b/src/Persistence/EntityFramework/Migrations/EntityDataContextModelSnapshot.cs index 3d3c488d8..a1fdc2d74 100644 --- a/src/Persistence/EntityFramework/Migrations/EntityDataContextModelSnapshot.cs +++ b/src/Persistence/EntityFramework/Migrations/EntityDataContextModelSnapshot.cs @@ -17,7 +17,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "7.0.3") + .HasAnnotation("ProductVersion", "8.0.0") .HasAnnotation("Relational:MaxIdentifierLength", 63); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); @@ -1138,9 +1138,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("ItemOptionDefinitionId") .HasColumnType("uuid"); - b.Property("ItemSetGroupId") - .HasColumnType("uuid"); - b.Property("LevelType") .HasColumnType("integer"); @@ -1160,8 +1157,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasIndex("ItemOptionDefinitionId"); - b.HasIndex("ItemSetGroupId"); - b.HasIndex("OptionTypeId"); b.HasIndex("PowerUpDefinitionId") @@ -1881,6 +1876,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) .IsRequired() .HasColumnType("text"); + b.Property("OptionsId") + .HasColumnType("uuid"); + b.Property("SetLevel") .HasColumnType("integer"); @@ -1888,6 +1886,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasIndex("GameConfigurationId"); + b.HasIndex("OptionsId"); + b.ToTable("ItemSetGroup", "config"); }); @@ -3654,11 +3654,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasForeignKey("ItemOptionDefinitionId") .OnDelete(DeleteBehavior.Cascade); - b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemSetGroup", null) - .WithMany("RawOptions") - .HasForeignKey("ItemSetGroupId") - .OnDelete(DeleteBehavior.Cascade); - b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionType", "RawOptionType") .WithMany() .HasForeignKey("OptionTypeId"); @@ -4064,6 +4059,12 @@ protected override void BuildModel(ModelBuilder modelBuilder) .WithMany("RawItemSetGroups") .HasForeignKey("GameConfigurationId") .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemOptionDefinition", "RawOptions") + .WithMany() + .HasForeignKey("OptionsId"); + + b.Navigation("RawOptions"); }); modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemSlotType", b => @@ -4792,8 +4793,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemSetGroup", b => { b.Navigation("RawItems"); - - b.Navigation("RawOptions"); }); modelBuilder.Entity("MUnique.OpenMU.Persistence.EntityFramework.Model.ItemStorage", b => diff --git a/src/Persistence/EntityFramework/Model/ExtendedTypeContext.Generated.cs b/src/Persistence/EntityFramework/Model/ExtendedTypeContext.Generated.cs index b2598bb19..41e52a04a 100644 --- a/src/Persistence/EntityFramework/Model/ExtendedTypeContext.Generated.cs +++ b/src/Persistence/EntityFramework/Model/ExtendedTypeContext.Generated.cs @@ -187,7 +187,6 @@ protected override void OnModelCreating(Microsoft.EntityFrameworkCore.ModelBuild modelBuilder.Entity().HasOne(entity => entity.RawBonus).WithOne().OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity().HasMany(entity => entity.RawPossibleOptions).WithOne().OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity().HasOne(entity => entity.RawPowerUpDefinition).WithOne().OnDelete(DeleteBehavior.Cascade); - modelBuilder.Entity().HasMany(entity => entity.RawOptions).WithOne().OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity().HasMany(entity => entity.RawItems).WithOne().OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity().HasOne(entity => entity.RawSimpleCraftingSettings).WithOne().OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity().HasMany(entity => entity.RawRequiredItems).WithOne().OnDelete(DeleteBehavior.Cascade); diff --git a/src/Persistence/EntityFramework/Model/ItemSetGroup.Generated.cs b/src/Persistence/EntityFramework/Model/ItemSetGroup.Generated.cs index 347f0aca1..00ebf5da2 100644 --- a/src/Persistence/EntityFramework/Model/ItemSetGroup.Generated.cs +++ b/src/Persistence/EntityFramework/Model/ItemSetGroup.Generated.cs @@ -29,22 +29,39 @@ internal partial class ItemSetGroup : MUnique.OpenMU.DataModel.Configuration.Ite public Guid Id { get; set; } /// - /// Gets the raw collection of . + /// Gets the raw collection of . /// - public ICollection RawOptions { get; } = new EntityFramework.List(); + public ICollection RawItems { get; } = new EntityFramework.List(); /// [NotMapped] - public override ICollection Options => base.Options ??= new CollectionAdapter(this.RawOptions); + public override ICollection Items => base.Items ??= new CollectionAdapter(this.RawItems); /// - /// Gets the raw collection of . + /// Gets or sets the identifier of . /// - public ICollection RawItems { get; } = new EntityFramework.List(); - + public Guid? OptionsId { get; set; } + + /// + /// Gets the raw object of . + /// + [ForeignKey(nameof(OptionsId))] + public ItemOptionDefinition RawOptions + { + get => base.Options as ItemOptionDefinition; + set => base.Options = value; + } + /// [NotMapped] - public override ICollection Items => base.Items ??= new CollectionAdapter(this.RawItems); + public override MUnique.OpenMU.DataModel.Configuration.Items.ItemOptionDefinition Options + { + get => base.Options;set + { + base.Options = value; + this.OptionsId = this.RawOptions?.Id; + } + } /// public override MUnique.OpenMU.DataModel.Configuration.Items.ItemSetGroup Clone(MUnique.OpenMU.DataModel.Configuration.GameConfiguration gameConfiguration) diff --git a/src/Persistence/Initialization/Items/ArmorInitializerBase.cs b/src/Persistence/Initialization/Items/ArmorInitializerBase.cs index 0ca6fad5a..dd7f236de 100644 --- a/src/Persistence/Initialization/Items/ArmorInitializerBase.cs +++ b/src/Persistence/Initialization/Items/ArmorInitializerBase.cs @@ -53,6 +53,13 @@ protected void BuildSets() { var sets = this.GameConfiguration.Items.Where(item => item.Group is >= 7 and <= 11).GroupBy(item => item.Number); + var defenseRateBonusDef = this.Context.CreateNew(); + defenseRateBonusDef.SetGuid(ItemOptionDefinitionNumbers.DefenseRateSetBonusOption); + defenseRateBonusDef.Name = "Complete Set Bonus (any level)"; + defenseRateBonusDef.AddChance = 0; + defenseRateBonusDef.AddsRandomly = false; + this.GameConfiguration.ItemOptions.Add(defenseRateBonusDef); + var defenseRateBonus = this.Context.CreateNew(); defenseRateBonus.SetGuid(ItemOptionDefinitionNumbers.DefenseRateSetBonusOption); defenseRateBonus.PowerUpDefinition = this.Context.CreateNew(); @@ -60,11 +67,16 @@ protected void BuildSets() defenseRateBonus.PowerUpDefinition.Boost.ConstantValue.AggregateType = AggregateType.Multiplicate; defenseRateBonus.PowerUpDefinition.Boost.ConstantValue.Value = 1.1f; defenseRateBonus.PowerUpDefinition.TargetAttribute = Stats.DefenseRatePvm.GetPersistent(this.GameConfiguration); + defenseRateBonusDef.PossibleOptions.Add(defenseRateBonus); - var defenseBonus = new Dictionary(); + var defenseBonus = new Dictionary(); for (byte setLevel = 10; setLevel <= this.MaximumArmorLevel; setLevel++) { - defenseBonus.Add(setLevel, this.BuildDefenseBonusOption(1 + (setLevel - 9) * 0.05f, setLevel)); + var def = this.Context.CreateNew(); + def.SetGuid(setLevel); + def.Name = $"Complete Set Bonus (Level {setLevel})"; + def.PossibleOptions.Add(this.BuildDefenseBonusOption(1 + (setLevel - 9) * 0.05f, setLevel)); + defenseBonus.Add(setLevel, def); } foreach (var group in sets) @@ -73,9 +85,11 @@ protected void BuildSets() this.GameConfiguration.ItemSetGroups.Add(setForDefenseRate); setForDefenseRate.Name = group.First().Name.Split(' ')[0] + " Defense Rate Bonus"; setForDefenseRate.MinimumItemCount = group.Count(); - setForDefenseRate.Options.Add(defenseRateBonus); + setForDefenseRate.Options = defenseRateBonusDef; + setForDefenseRate.AlwaysApplies = true; foreach (var item in group) { + item.PossibleItemSetGroups.Add(setForDefenseRate); var itemOfSet = this.Context.CreateNew(); itemOfSet.SetGuid(item.Group, item.Number, 0xFF); itemOfSet.ItemDefinition = item; @@ -197,13 +211,14 @@ private IncreasableItemOption BuildDefenseBonusOption(float bonus, short level) return defenseBonus; } - private void CreateSetGroup(byte setLevel, IncreasableItemOption option, ICollection group) + private void CreateSetGroup(byte setLevel, ItemOptionDefinition options, ICollection group) { var setForDefense = this.Context.CreateNew(); this.GameConfiguration.ItemSetGroups.Add(setForDefense); setForDefense.Name = $"{group.First().Name.Split(' ')[0]} Defense Bonus (Level {setLevel})"; setForDefense.MinimumItemCount = group.Count; - setForDefense.Options.Add(option); + setForDefense.Options = options; + setForDefense.AlwaysApplies = true; setForDefense.SetLevel = setLevel; foreach (var item in group) @@ -212,6 +227,7 @@ private void CreateSetGroup(byte setLevel, IncreasableItemOption option, ICollec itemOfSet.SetGuid(item.Group, item.Number, setLevel); itemOfSet.ItemDefinition = item; setForDefense.Items.Add(itemOfSet); + item.PossibleItemSetGroups.Add(setForDefense); } } } \ No newline at end of file diff --git a/src/Persistence/Initialization/VersionSeasonSix/Items/AncientSets.cs b/src/Persistence/Initialization/VersionSeasonSix/Items/AncientSets.cs index 3ae846e20..bfa65aaf4 100644 --- a/src/Persistence/Initialization/VersionSeasonSix/Items/AncientSets.cs +++ b/src/Persistence/Initialization/VersionSeasonSix/Items/AncientSets.cs @@ -674,6 +674,10 @@ private ItemSetGroup AddAncientSet(string name, short setNumber, params (Attribu set.CountDistinct = true; set.MinimumItemCount = 2; int number = 1; + var options = this.Context.CreateNew(); + options.SetGuid(ItemOptionDefinitionNumbers.AncientOption, setNumber, (byte)number); + options.Name = $"{name} (Ancient Set)"; + set.Options = options; foreach (var optionTuple in ancientOptions) { var option = this.Context.CreateNew(); @@ -684,7 +688,7 @@ private ItemSetGroup AddAncientSet(string name, short setNumber, params (Attribu option.PowerUpDefinition.TargetAttribute = optionTuple.Attribute.GetPersistent(this.GameConfiguration); option.PowerUpDefinition.Boost = this.Context.CreateNew(); option.PowerUpDefinition.Boost.ConstantValue.Value = optionTuple.Value; - set.Options.Add(option); + options.PossibleOptions.Add(option); } this.GameConfiguration.ItemSetGroups.Add(set); diff --git a/src/Persistence/SourceGenerator/EfCoreModelGenerator.cs b/src/Persistence/SourceGenerator/EfCoreModelGenerator.cs index 41e42a6bd..ce225f936 100644 --- a/src/Persistence/SourceGenerator/EfCoreModelGenerator.cs +++ b/src/Persistence/SourceGenerator/EfCoreModelGenerator.cs @@ -34,6 +34,7 @@ private static readonly (string TypeName, bool StandaloneForEntityOnly)[] Standa { ("MUnique.OpenMU.DataModel.Configuration.CharacterClass", false), ("MUnique.OpenMU.DataModel.Configuration.DropItemGroup", false), + ("MUnique.OpenMU.DataModel.Configuration.Items.IncreasableItemOption", false), ("MUnique.OpenMU.DataModel.Configuration.Items.ItemDefinition", false), ("MUnique.OpenMU.DataModel.Configuration.Items.ItemOption", false), ("MUnique.OpenMU.DataModel.Configuration.Items.ItemOptionType", false), @@ -226,6 +227,7 @@ private string GenerateDbContext() .SelectMany(t => t.GetProperties().Where(p => p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>) && + !IsMemberOfAggregate(p) && IsStandaloneType(p.PropertyType.GenericTypeArguments[0].FullName, t))).ToList(); foreach (PropertyInfo propertyInfo in allStandaloneCollectionProperties) @@ -324,6 +326,7 @@ private string CreateNavigationProperties(Type type) .Where(p => type.FullName == GameConfigurationFullName || !(p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>) + && !IsMemberOfAggregate(p) && IsStandaloneType(p.PropertyType.GenericTypeArguments[0].FullName, type))) .ToList(); @@ -473,7 +476,10 @@ private static bool IsStandaloneType(string typeName, Type referencingType) private IEnumerable GetStandaloneCollectionProperties(Type type) { return type.FullName != GameConfigurationFullName ? - type.GetProperties().Where(p => p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>) && IsStandaloneType(p.PropertyType.GenericTypeArguments[0].FullName, type)).ToList() : + type.GetProperties().Where(p => p.PropertyType.IsGenericType + && p.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>) + && !IsMemberOfAggregate(p) + && IsStandaloneType(p.PropertyType.GenericTypeArguments[0].FullName, type)).ToList() : Enumerable.Empty(); } diff --git a/tests/MUnique.OpenMU.Tests/PowerUpFactoryTest.cs b/tests/MUnique.OpenMU.Tests/PowerUpFactoryTest.cs index c5798b6d0..c8c583430 100644 --- a/tests/MUnique.OpenMU.Tests/PowerUpFactoryTest.cs +++ b/tests/MUnique.OpenMU.Tests/PowerUpFactoryTest.cs @@ -318,12 +318,16 @@ private ItemOptionLink GetOption(AttributeDefinition targetAttribute, float valu private IEnumerable GetDefenseBonusSet(float setBonusDefense, byte minimumLevel, params byte[] levels) { + var itemOptionDef = new Mock(); + itemOptionDef.Setup(a => a.PossibleOptions).Returns(new List()); + itemOptionDef.Object.PossibleOptions.Add(this.GetOption(Stats.DefenseBase, setBonusDefense).ItemOption!); + var armorSet = new Mock(); armorSet.Setup(a => a.Items).Returns(new List()); - armorSet.Setup(a => a.Options).Returns(new List()); + armorSet.Object.Options = itemOptionDef.Object; armorSet.Object.MinimumItemCount = levels.Length; armorSet.Object.SetLevel = minimumLevel; - armorSet.Object.Options.Add(this.GetOption(Stats.DefenseBase, setBonusDefense).ItemOption!); + foreach (var level in levels) { var item = this.GetItem(); @@ -338,15 +342,18 @@ private IEnumerable GetDefenseBonusSet(float setBonusDefense, byte minimum private IEnumerable GetAncientSet(int ancientOptionCount, int itemCount) { + var itemOptionDef = new Mock(); + itemOptionDef.Setup(a => a.PossibleOptions).Returns(new List()); var ancientSet = new Mock(); ancientSet.Setup(a => a.Items).Returns(new List()); - ancientSet.Setup(a => a.Options).Returns(new List()); + + ancientSet.Object.Options = itemOptionDef.Object; ancientSet.Object.MinimumItemCount = 2; for (int i = 0; i < ancientOptionCount; i++) { var setOption = this.GetOption(Stats.DefenseBase, i + 10).ItemOption; setOption!.Number = i + 1; - ancientSet.Object.Options.Add(setOption); + itemOptionDef.Object.PossibleOptions.Add(setOption); } var bonusOption = this.GetOption(Stats.TotalStrength, 5).ItemOption; From 5398268b89810987e3e4a355680997aadc5aaca6 Mon Sep 17 00:00:00 2001 From: Niter88 Date: Sat, 8 Jun 2024 12:36:32 -0300 Subject: [PATCH 14/29] ADD reset points can be configured by character class --- src/DataModel/Configuration/CharacterClass.cs | 7 +++++++ src/GameLogic/Resets/ResetCharacterAction.cs | 20 ++++++++++++++++++- src/GameLogic/Resets/ResetConfiguration.cs | 7 +++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/DataModel/Configuration/CharacterClass.cs b/src/DataModel/Configuration/CharacterClass.cs index 3b9b39dfd..a81b7a477 100644 --- a/src/DataModel/Configuration/CharacterClass.cs +++ b/src/DataModel/Configuration/CharacterClass.cs @@ -49,6 +49,13 @@ public partial class CharacterClass /// public byte CreationAllowedFlag { get; set; } + /// + /// Gets or sets the amount of points which will be set at the when doing a reset. + /// This one is specific for the class and has to be activated in the reset plugin. + ///
Also, -1 means deactivated. + ///
+ public int PointsPerReset { get; set; } = -1; + /// /// Gets or sets the next generation class, to which a character can upgrade after /// fulfilling certain requirements, like quests. diff --git a/src/GameLogic/Resets/ResetCharacterAction.cs b/src/GameLogic/Resets/ResetCharacterAction.cs index e32447ca5..178c33355 100644 --- a/src/GameLogic/Resets/ResetCharacterAction.cs +++ b/src/GameLogic/Resets/ResetCharacterAction.cs @@ -4,6 +4,7 @@ namespace MUnique.OpenMU.GameLogic.Resets; +using MUnique.OpenMU.DataModel.Composition; using MUnique.OpenMU.GameLogic.Attributes; using MUnique.OpenMU.GameLogic.NPC; using MUnique.OpenMU.GameLogic.PlayerActions; @@ -11,6 +12,7 @@ namespace MUnique.OpenMU.GameLogic.Resets; using MUnique.OpenMU.GameLogic.Views.Login; using MUnique.OpenMU.GameLogic.Views.NPC; using MUnique.OpenMU.Interfaces; +using MUnique.OpenMU.Persistence; /// /// Action to reset a character. @@ -124,7 +126,7 @@ private async ValueTask TryConsumeMoneyAsync(ResetConfiguration configurat private void UpdateStats(ResetConfiguration configuration) { - var calculatedPointsPerReset = configuration.PointsPerReset; + var calculatedPointsPerReset = this.GetResetPoints(configuration); if (configuration.MultiplyPointsByResetCount) { calculatedPointsPerReset *= this.GetResetCount(); @@ -140,6 +142,22 @@ private void UpdateStats(ResetConfiguration configuration) this._player.SelectedCharacter!.LevelUpPoints = Math.Max(0, calculatedPointsPerReset); } + private int GetResetPoints(ResetConfiguration configuration) + { + int pointsPerReset = configuration.PointsPerReset; + + if (configuration.IsResetPointsByClass) + { + var classPointsPerReset = this._player.SelectedCharacter!.CharacterClass!.PointsPerReset; + if (classPointsPerReset >= 0) + { + pointsPerReset = classPointsPerReset; + } + } + + return pointsPerReset; + } + private async ValueTask MoveHomeAsync() { var homeMapDef = this._player.SelectedCharacter!.CharacterClass!.HomeMap; diff --git a/src/GameLogic/Resets/ResetConfiguration.cs b/src/GameLogic/Resets/ResetConfiguration.cs index b86a8168f..fa843c269 100644 --- a/src/GameLogic/Resets/ResetConfiguration.cs +++ b/src/GameLogic/Resets/ResetConfiguration.cs @@ -2,6 +2,8 @@ // Licensed under the MIT License. See LICENSE file in the project root for full license information. // +using MUnique.OpenMU.DataModel.Composition; + namespace MUnique.OpenMU.GameLogic.Resets; /// @@ -49,4 +51,9 @@ public class ResetConfiguration /// Gets or sets the amount of points which will be set at the when doing a reset. /// public int PointsPerReset { get; set; } = 1500; + + /// + /// Gets or sets a value indicating whether the class specific should override . + /// + public bool IsResetPointsByClass { get; set; } = false; } \ No newline at end of file From 78ac3923647aed1c7a6d85eacd9c4f7241a176d3 Mon Sep 17 00:00:00 2001 From: Niter88 Date: Sat, 8 Jun 2024 12:52:29 -0300 Subject: [PATCH 15/29] Not declaring IsResetPointsByClass fix proposed by codacity --- src/GameLogic/Resets/ResetConfiguration.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GameLogic/Resets/ResetConfiguration.cs b/src/GameLogic/Resets/ResetConfiguration.cs index fa843c269..b856f1e32 100644 --- a/src/GameLogic/Resets/ResetConfiguration.cs +++ b/src/GameLogic/Resets/ResetConfiguration.cs @@ -55,5 +55,5 @@ public class ResetConfiguration /// /// Gets or sets a value indicating whether the class specific should override . /// - public bool IsResetPointsByClass { get; set; } = false; + public bool IsResetPointsByClass { get; set; } } \ No newline at end of file From f1ef9d3b8d808a30c7d187cf5f7c92cbbb75d390 Mon Sep 17 00:00:00 2001 From: Niter88 Date: Sat, 8 Jun 2024 18:42:13 -0300 Subject: [PATCH 16/29] The reset by class property was moved to the Stats --- src/DataModel/Configuration/CharacterClass.cs | 7 ------- src/GameLogic/Attributes/Stats.cs | 5 +++++ src/GameLogic/Resets/ResetCharacterAction.cs | 11 +++-------- src/GameLogic/Resets/ResetConfiguration.cs | 5 ----- 4 files changed, 8 insertions(+), 20 deletions(-) diff --git a/src/DataModel/Configuration/CharacterClass.cs b/src/DataModel/Configuration/CharacterClass.cs index a81b7a477..3b9b39dfd 100644 --- a/src/DataModel/Configuration/CharacterClass.cs +++ b/src/DataModel/Configuration/CharacterClass.cs @@ -49,13 +49,6 @@ public partial class CharacterClass /// public byte CreationAllowedFlag { get; set; } - /// - /// Gets or sets the amount of points which will be set at the when doing a reset. - /// This one is specific for the class and has to be activated in the reset plugin. - ///
Also, -1 means deactivated. - ///
- public int PointsPerReset { get; set; } = -1; - /// /// Gets or sets the next generation class, to which a character can upgrade after /// fulfilling certain requirements, like quests. diff --git a/src/GameLogic/Attributes/Stats.cs b/src/GameLogic/Attributes/Stats.cs index d9371f14a..e6959e454 100644 --- a/src/GameLogic/Attributes/Stats.cs +++ b/src/GameLogic/Attributes/Stats.cs @@ -899,6 +899,11 @@ public class Stats /// public static AttributeDefinition IsVip { get; } = new(new Guid("195474D6-59A2-4033-9C30-8628ECC0097E"), "Is VIP", "The flag, if an account is a VIP."); + /// + /// Gets the attribute for the number of points this class will receive for reset, overwrites the default value. + /// + public static AttributeDefinition PointsPerResetByClass { get; } = new(new Guid("a34f4f57-b364-4cdb-9989-64cedd2cd831"), "Points Per Reset By Class", "The number of points this class will receive for reset, overwrites the default 'PointsPerReset' value."); + /// /// Gets the attributes which are regenerated in an interval. /// diff --git a/src/GameLogic/Resets/ResetCharacterAction.cs b/src/GameLogic/Resets/ResetCharacterAction.cs index 178c33355..33dda4a83 100644 --- a/src/GameLogic/Resets/ResetCharacterAction.cs +++ b/src/GameLogic/Resets/ResetCharacterAction.cs @@ -4,7 +4,6 @@ namespace MUnique.OpenMU.GameLogic.Resets; -using MUnique.OpenMU.DataModel.Composition; using MUnique.OpenMU.GameLogic.Attributes; using MUnique.OpenMU.GameLogic.NPC; using MUnique.OpenMU.GameLogic.PlayerActions; @@ -12,7 +11,6 @@ namespace MUnique.OpenMU.GameLogic.Resets; using MUnique.OpenMU.GameLogic.Views.Login; using MUnique.OpenMU.GameLogic.Views.NPC; using MUnique.OpenMU.Interfaces; -using MUnique.OpenMU.Persistence; /// /// Action to reset a character. @@ -144,15 +142,12 @@ private void UpdateStats(ResetConfiguration configuration) private int GetResetPoints(ResetConfiguration configuration) { + StatAttributeDefinition? pointsPerResetByClass = this._player.SelectedCharacter!.CharacterClass!.GetStatAttribute(Stats.PointsPerResetByClass); int pointsPerReset = configuration.PointsPerReset; - if (configuration.IsResetPointsByClass) + if (pointsPerResetByClass != null) { - var classPointsPerReset = this._player.SelectedCharacter!.CharacterClass!.PointsPerReset; - if (classPointsPerReset >= 0) - { - pointsPerReset = classPointsPerReset; - } + pointsPerReset = (int)pointsPerResetByClass.BaseValue; } return pointsPerReset; diff --git a/src/GameLogic/Resets/ResetConfiguration.cs b/src/GameLogic/Resets/ResetConfiguration.cs index b856f1e32..f4ab66071 100644 --- a/src/GameLogic/Resets/ResetConfiguration.cs +++ b/src/GameLogic/Resets/ResetConfiguration.cs @@ -51,9 +51,4 @@ public class ResetConfiguration /// Gets or sets the amount of points which will be set at the when doing a reset. /// public int PointsPerReset { get; set; } = 1500; - - /// - /// Gets or sets a value indicating whether the class specific should override . - /// - public bool IsResetPointsByClass { get; set; } } \ No newline at end of file From f934eecec5c507ff0919666b19075a325d992cfa Mon Sep 17 00:00:00 2001 From: sven-n Date: Sun, 9 Jun 2024 15:20:01 +0200 Subject: [PATCH 17/29] Take PointsPerReset from the attribute system --- src/GameLogic/Resets/ResetCharacterAction.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/GameLogic/Resets/ResetCharacterAction.cs b/src/GameLogic/Resets/ResetCharacterAction.cs index 33dda4a83..a14bb5905 100644 --- a/src/GameLogic/Resets/ResetCharacterAction.cs +++ b/src/GameLogic/Resets/ResetCharacterAction.cs @@ -142,12 +142,10 @@ private void UpdateStats(ResetConfiguration configuration) private int GetResetPoints(ResetConfiguration configuration) { - StatAttributeDefinition? pointsPerResetByClass = this._player.SelectedCharacter!.CharacterClass!.GetStatAttribute(Stats.PointsPerResetByClass); - int pointsPerReset = configuration.PointsPerReset; - - if (pointsPerResetByClass != null) + var pointsPerReset = (int)this._player.Attributes![Stats.PointsPerResetByClass]; + if (pointsPerReset == 0) { - pointsPerReset = (int)pointsPerResetByClass.BaseValue; + pointsPerReset = configuration.PointsPerReset; } return pointsPerReset; From 86bd13a2d15e6eb2153bd367d389d40abd0d87f8 Mon Sep 17 00:00:00 2001 From: sven-n Date: Sun, 9 Jun 2024 15:23:10 +0200 Subject: [PATCH 18/29] removed unused using --- src/GameLogic/Resets/ResetConfiguration.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/GameLogic/Resets/ResetConfiguration.cs b/src/GameLogic/Resets/ResetConfiguration.cs index f4ab66071..b86a8168f 100644 --- a/src/GameLogic/Resets/ResetConfiguration.cs +++ b/src/GameLogic/Resets/ResetConfiguration.cs @@ -2,8 +2,6 @@ // Licensed under the MIT License. See LICENSE file in the project root for full license information. // -using MUnique.OpenMU.DataModel.Composition; - namespace MUnique.OpenMU.GameLogic.Resets; /// From 3f82544b340d7df6d53094ed9308cb13382680b5 Mon Sep 17 00:00:00 2001 From: sven-n Date: Sun, 9 Jun 2024 15:29:38 +0200 Subject: [PATCH 19/29] Rename attribute The suffix ByClass is unneeded, and with the attribute system, this can not only differ between character classes. --- src/GameLogic/Attributes/Stats.cs | 2 +- src/GameLogic/Resets/ResetCharacterAction.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/GameLogic/Attributes/Stats.cs b/src/GameLogic/Attributes/Stats.cs index e6959e454..307ce715c 100644 --- a/src/GameLogic/Attributes/Stats.cs +++ b/src/GameLogic/Attributes/Stats.cs @@ -902,7 +902,7 @@ public class Stats /// /// Gets the attribute for the number of points this class will receive for reset, overwrites the default value. /// - public static AttributeDefinition PointsPerResetByClass { get; } = new(new Guid("a34f4f57-b364-4cdb-9989-64cedd2cd831"), "Points Per Reset By Class", "The number of points this class will receive for reset, overwrites the default 'PointsPerReset' value."); + public static AttributeDefinition PointsPerReset { get; } = new(new Guid("a34f4f57-b364-4cdb-9989-64cedd2cd831"), "Points Per Reset", "The number of points the player will receive for reset, overwrites the default 'PointsPerReset' value of the reset configuration."); /// /// Gets the attributes which are regenerated in an interval. diff --git a/src/GameLogic/Resets/ResetCharacterAction.cs b/src/GameLogic/Resets/ResetCharacterAction.cs index a14bb5905..d95700414 100644 --- a/src/GameLogic/Resets/ResetCharacterAction.cs +++ b/src/GameLogic/Resets/ResetCharacterAction.cs @@ -142,7 +142,7 @@ private void UpdateStats(ResetConfiguration configuration) private int GetResetPoints(ResetConfiguration configuration) { - var pointsPerReset = (int)this._player.Attributes![Stats.PointsPerResetByClass]; + var pointsPerReset = (int)this._player.Attributes![Stats.PointsPerReset]; if (pointsPerReset == 0) { pointsPerReset = configuration.PointsPerReset; From 5e6029d32d5d6e874cf268178321580a899a578a Mon Sep 17 00:00:00 2001 From: sven-n Date: Sun, 9 Jun 2024 15:31:48 +0200 Subject: [PATCH 20/29] Add initialization plugin to add the new attribute --- .../AddPointsPerResetAttributePlugIn.cs | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 src/Persistence/Initialization/Updates/AddPointsPerResetAttributePlugIn.cs diff --git a/src/Persistence/Initialization/Updates/AddPointsPerResetAttributePlugIn.cs b/src/Persistence/Initialization/Updates/AddPointsPerResetAttributePlugIn.cs new file mode 100644 index 000000000..5672c033a --- /dev/null +++ b/src/Persistence/Initialization/Updates/AddPointsPerResetAttributePlugIn.cs @@ -0,0 +1,57 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace MUnique.OpenMU.Persistence.Initialization.Updates; + +using System; +using System.Runtime.InteropServices; +using MUnique.OpenMU.AttributeSystem; + +using MUnique.OpenMU.DataModel.Configuration; +using MUnique.OpenMU.GameLogic.Attributes; +using MUnique.OpenMU.PlugIns; + +/// +/// This update adds the . +/// +[PlugIn(PlugInName, PlugInDescription)] +[Guid("6011A1B8-7FA5-48EB-935D-EEAF83017799")] +public class AddPointsPerResetAttributePlugIn : UpdatePlugInBase +{ + /// + /// The plug in name. + /// + internal const string PlugInName = "Adds attribute PointsPerReset"; + + /// + /// The plug in description. + /// + internal const string PlugInDescription = "This update adds the attribute PointsPerReset."; + + /// + public override string Name => PlugInName; + + /// + public override string Description => PlugInDescription; + + /// + public override UpdateVersion Version => UpdateVersion.AddPointsPerResetByClassAttribute; + + /// + public override string DataInitializationKey => VersionSeasonSix.DataInitialization.Id; + + /// + public override bool IsMandatory => true; + + /// + public override DateTime CreatedAt => new(2024, 06, 09, 13, 30, 0, DateTimeKind.Utc); + + /// + protected override async ValueTask ApplyAsync(IContext context, GameConfiguration gameConfiguration) + { + var attribute = Stats.PointsPerReset; + var persistentAttribute = context.CreateNew(attribute.Id, attribute.Designation, attribute.Description); + gameConfiguration.Attributes.Add(persistentAttribute); + } +} \ No newline at end of file From 5ecc45a32fb3ffcdf00c538210605f1a3c6b9ea9 Mon Sep 17 00:00:00 2001 From: sven-n Date: Sun, 9 Jun 2024 15:44:00 +0200 Subject: [PATCH 21/29] Update UpdateVersion.cs --- src/Persistence/Initialization/Updates/UpdateVersion.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Persistence/Initialization/Updates/UpdateVersion.cs b/src/Persistence/Initialization/Updates/UpdateVersion.cs index cf9ee08d7..4e7a53394 100644 --- a/src/Persistence/Initialization/Updates/UpdateVersion.cs +++ b/src/Persistence/Initialization/Updates/UpdateVersion.cs @@ -84,4 +84,9 @@ public enum UpdateVersion /// The version of the . /// InfinityArrowSkillOnQuestCompletion = 15, + + /// + /// The version of the . + /// + AddPointsPerResetByClassAttribute = 16 } \ No newline at end of file From 211d24cb72324a8ce2fbb34366400a1cb212d51e Mon Sep 17 00:00:00 2001 From: sven-n Date: Sun, 9 Jun 2024 18:49:14 +0200 Subject: [PATCH 22/29] Implemented logic to create lost map items. --- src/GameLogic/DroppedItem.cs | 5 ++ .../PlayerActions/Items/MoveItemAction.cs | 9 +- .../ChatCommands/ItemChatCommandPlugIn.cs | 2 +- src/GameLogic/PlugIns/IItemStackedPlugIn.cs | 24 +++++ .../PlugIns/SymbolOfKundunStackedPlugIn.cs | 47 ++++++++++ .../Initialization/Updates/AddKalimaPlugIn.cs | 87 +++++++++++++++++++ .../Initialization/Updates/UpdateVersion.cs | 7 +- .../VersionSeasonSix/Items/Misc.cs | 33 +++++++ 8 files changed, 211 insertions(+), 3 deletions(-) create mode 100644 src/GameLogic/PlugIns/IItemStackedPlugIn.cs create mode 100644 src/GameLogic/PlugIns/SymbolOfKundunStackedPlugIn.cs create mode 100644 src/Persistence/Initialization/Updates/AddKalimaPlugIn.cs diff --git a/src/GameLogic/DroppedItem.cs b/src/GameLogic/DroppedItem.cs index 7e8ce8f21..4c00f0f1e 100644 --- a/src/GameLogic/DroppedItem.cs +++ b/src/GameLogic/DroppedItem.cs @@ -250,6 +250,11 @@ private async ValueTask TryStackOnItemAsync(Player player, Item stackTarge player.Logger.LogInformation("Item '{0}' got picked up by player '{1}'. Durability of available stack {2} increased to {3}", this, player, stackTarget, stackTarget.Durability); this.DisposeAndDelete(null); + if (player.GameContext.PlugInManager.GetPlugInPoint() is { } itemStackedPlugIn) + { + await itemStackedPlugIn.ItemStackedAsync(player, this.Item, stackTarget).ConfigureAwait(false); + } + return true; } diff --git a/src/GameLogic/PlayerActions/Items/MoveItemAction.cs b/src/GameLogic/PlayerActions/Items/MoveItemAction.cs index cf9b94a1f..9dc0a14a3 100644 --- a/src/GameLogic/PlayerActions/Items/MoveItemAction.cs +++ b/src/GameLogic/PlayerActions/Items/MoveItemAction.cs @@ -80,11 +80,18 @@ public async ValueTask MoveItemAsync(Player player, byte fromSlot, Storages from break; } - if (movement != Movement.None + if (movement is not Movement.None && player.GameContext.PlugInManager.GetPlugInPoint() is { } itemMovedPlugIn) { await itemMovedPlugIn.ItemMovedAsync(player, item).ConfigureAwait(false); } + + if (movement is not (Movement.None or Movement.Normal) + && toItemStorage?.GetItem(toSlot) is { } target + && player.GameContext.PlugInManager.GetPlugInPoint() is { } itemStackedPlugIn) + { + await itemStackedPlugIn.ItemStackedAsync(player, item, target).ConfigureAwait(false); + } } private async ValueTask FullStackAsync(Player player, Item sourceItem, Item targetItem) diff --git a/src/GameLogic/PlugIns/ChatCommands/ItemChatCommandPlugIn.cs b/src/GameLogic/PlugIns/ChatCommands/ItemChatCommandPlugIn.cs index e0a68bd6d..27e88a72b 100644 --- a/src/GameLogic/PlugIns/ChatCommands/ItemChatCommandPlugIn.cs +++ b/src/GameLogic/PlugIns/ChatCommands/ItemChatCommandPlugIn.cs @@ -43,7 +43,7 @@ private static Item CreateItem(Player gameMaster, ItemChatCommandArgs arguments) { var item = new TemporaryItem(); item.Definition = GetItemDefination(gameMaster, arguments); - item.Durability = item.Definition.Durability; + item.Durability = item.IsStackable() ? 1 : item.Definition.Durability; item.HasSkill = item.Definition.Skill != null && arguments.Skill; item.Level = GetItemLevel(item.Definition, arguments); item.SocketCount = item.Definition.MaximumSockets; diff --git a/src/GameLogic/PlugIns/IItemStackedPlugIn.cs b/src/GameLogic/PlugIns/IItemStackedPlugIn.cs new file mode 100644 index 000000000..51c273268 --- /dev/null +++ b/src/GameLogic/PlugIns/IItemStackedPlugIn.cs @@ -0,0 +1,24 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace MUnique.OpenMU.GameLogic.PlugIns; + +using System.Runtime.InteropServices; +using MUnique.OpenMU.PlugIns; + +/// +/// A plugin interface which is called when an item got moved by the player. +/// +[Guid("FCDE60E9-6183-4833-BF59-CE907F9EECCD")] +[PlugInPoint("Item stacked", "Plugins which are called when an item has been stacked by the player.")] +public interface IItemStackedPlugIn +{ + /// + /// Is called when an item has been moved by the player. + /// + /// The player. + /// The source item. + /// The target item. + ValueTask ItemStackedAsync(Player player, Item sourceItem, Item targetItem); +} \ No newline at end of file diff --git a/src/GameLogic/PlugIns/SymbolOfKundunStackedPlugIn.cs b/src/GameLogic/PlugIns/SymbolOfKundunStackedPlugIn.cs new file mode 100644 index 000000000..f95244fba --- /dev/null +++ b/src/GameLogic/PlugIns/SymbolOfKundunStackedPlugIn.cs @@ -0,0 +1,47 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace MUnique.OpenMU.GameLogic.PlugIns; + +using System.Runtime.InteropServices; +using MUnique.OpenMU.PlugIns; + +/// +/// This plugin transforms a stack of symbol of kundun into a lost map. +/// +[PlugIn(nameof(SymbolOfKundunStackedPlugIn), "This plugin transforms a stack of symbol of kundun into a lost map.")] +[Guid("F07A9CED-F43E-4824-9587-F5C3C3187A13")] +public sealed class SymbolOfKundunStackedPlugIn : IItemStackedPlugIn +{ + private const byte SymbolOfKundunGroup = 14; + private const byte SymbolOfKundunNumber = 29; + private const byte LostMapGroup = 14; + private const byte LostMapNumber = 28; + + /// + public async ValueTask ItemStackedAsync(Player player, Item sourceItem, Item targetItem) + { + if (targetItem.Definition is not { Group: SymbolOfKundunGroup, Number: SymbolOfKundunNumber }) + { + return; + } + + if (targetItem.Durability() < targetItem.Definition.Durability) + { + return; + } + + var lostMap = player.GameContext.Configuration.Items.FirstOrDefault(item => item is { Group: LostMapGroup, Number: LostMapNumber }); + if (lostMap is null) + { + player.Logger.LogWarning("Lost map definition not found."); + return; + } + + await player.InvokeViewPlugInAsync(p => p.RemoveItemAsync(targetItem.ItemSlot)).ConfigureAwait(false); + targetItem.Definition = lostMap; + targetItem.Durability = 1; + await player.InvokeViewPlugInAsync(p => p.ItemAppearAsync(targetItem)).ConfigureAwait(false); + } +} diff --git a/src/Persistence/Initialization/Updates/AddKalimaPlugIn.cs b/src/Persistence/Initialization/Updates/AddKalimaPlugIn.cs new file mode 100644 index 000000000..6f7e43229 --- /dev/null +++ b/src/Persistence/Initialization/Updates/AddKalimaPlugIn.cs @@ -0,0 +1,87 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +using MUnique.OpenMU.DataModel.Configuration.Items; + +namespace MUnique.OpenMU.Persistence.Initialization.Updates; + +using System.Runtime.InteropServices; +using MUnique.OpenMU.DataModel.Configuration; +using MUnique.OpenMU.PlugIns; + +/// +/// This adds the items required to enter the kalima map. +/// +[PlugIn(PlugInName, PlugInDescription)] +[Guid("0C99155F-1289-4E73-97F0-47CB67C3716F")] +public class AddKalimaPlugIn : UpdatePlugInBase +{ + /// + /// The plug in name. + /// + internal const string PlugInName = "Add Kalima"; + + /// + /// The plug in description. + /// + internal const string PlugInDescription = "This adds the items required to enter the kalima map."; + + /// + public override UpdateVersion Version => UpdateVersion.AddKalima; + + /// + public override string DataInitializationKey => VersionSeasonSix.DataInitialization.Id; + + /// + public override string Name => PlugInName; + + /// + public override string Description => PlugInDescription; + + /// + public override bool IsMandatory => true; + + /// + public override DateTime CreatedAt => new(2024, 06, 09, 18, 0, 0, DateTimeKind.Utc); + + /// +#pragma warning disable CS1998 + protected override async ValueTask ApplyAsync(IContext context, GameConfiguration gameConfiguration) +#pragma warning restore CS1998 + { + this.CreateLostMap(context, gameConfiguration); + this.CreateSymbolOfKundun(context, gameConfiguration); + } + + private void CreateLostMap(IContext context, GameConfiguration gameConfiguration) + { + var itemDefinition = context.CreateNew(); + itemDefinition.Name = "Lost Map"; + itemDefinition.Number = 28; + itemDefinition.Group = 14; + itemDefinition.DropsFromMonsters = false; + itemDefinition.Durability = 1; + itemDefinition.Width = 1; + itemDefinition.Height = 1; + itemDefinition.MaximumItemLevel = 7; + itemDefinition.SetGuid(itemDefinition.Group, itemDefinition.Number); + gameConfiguration.Items.Add(itemDefinition); + } + + private void CreateSymbolOfKundun(IContext context, GameConfiguration gameConfiguration) + { + var itemDefinition = context.CreateNew(); + itemDefinition.Name = "Symbol of Kundun"; + itemDefinition.Number = 29; + itemDefinition.Group = 14; + itemDefinition.DropLevel = 0; + itemDefinition.DropsFromMonsters = true; + itemDefinition.Durability = 5; + itemDefinition.Width = 1; + itemDefinition.Height = 1; + itemDefinition.MaximumItemLevel = 7; + itemDefinition.SetGuid(itemDefinition.Group, itemDefinition.Number); + gameConfiguration.Items.Add(itemDefinition); + } +} \ No newline at end of file diff --git a/src/Persistence/Initialization/Updates/UpdateVersion.cs b/src/Persistence/Initialization/Updates/UpdateVersion.cs index 4e7a53394..fea089606 100644 --- a/src/Persistence/Initialization/Updates/UpdateVersion.cs +++ b/src/Persistence/Initialization/Updates/UpdateVersion.cs @@ -88,5 +88,10 @@ public enum UpdateVersion /// /// The version of the . /// - AddPointsPerResetByClassAttribute = 16 + AddPointsPerResetByClassAttribute = 16, + + /// + /// The version of the . + /// + AddKalima = 17, } \ No newline at end of file diff --git a/src/Persistence/Initialization/VersionSeasonSix/Items/Misc.cs b/src/Persistence/Initialization/VersionSeasonSix/Items/Misc.cs index ea97df119..e1a77dd16 100644 --- a/src/Persistence/Initialization/VersionSeasonSix/Items/Misc.cs +++ b/src/Persistence/Initialization/VersionSeasonSix/Items/Misc.cs @@ -27,6 +27,39 @@ public override void Initialize() { this.CreateLifeStone(); this.CreateGoldenCherryBlossomBranch(); + this.CreateLostMap(); + this.CreateSymbolOfKundun(); + } + + private void CreateLostMap() + { + var itemDefinition = this.Context.CreateNew(); + itemDefinition.Name = "Lost Map"; + itemDefinition.Number = 28; + itemDefinition.Group = 14; + itemDefinition.DropsFromMonsters = false; + itemDefinition.Durability = 1; + itemDefinition.Width = 1; + itemDefinition.Height = 1; + itemDefinition.MaximumItemLevel = 7; + itemDefinition.SetGuid(itemDefinition.Group, itemDefinition.Number); + this.GameConfiguration.Items.Add(itemDefinition); + } + + private void CreateSymbolOfKundun() + { + var itemDefinition = this.Context.CreateNew(); + itemDefinition.Name = "Symbol of Kundun"; + itemDefinition.Number = 29; + itemDefinition.Group = 14; + itemDefinition.DropLevel = 0; + itemDefinition.DropsFromMonsters = true; + itemDefinition.Durability = 5; + itemDefinition.Width = 1; + itemDefinition.Height = 1; + itemDefinition.MaximumItemLevel = 7; + itemDefinition.SetGuid(itemDefinition.Group, itemDefinition.Number); + this.GameConfiguration.Items.Add(itemDefinition); } private void CreateLifeStone() From 997dd6d728fba569136736beee0b404937e6b8e4 Mon Sep 17 00:00:00 2001 From: sven-n Date: Sun, 9 Jun 2024 21:18:23 +0200 Subject: [PATCH 23/29] Added DropItemGroups for Symbols of Kundun --- .../Initialization/Updates/AddKalimaPlugIn.cs | 16 +++++++++++++ .../VersionSeasonSix/Items/Misc.cs | 24 +++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/src/Persistence/Initialization/Updates/AddKalimaPlugIn.cs b/src/Persistence/Initialization/Updates/AddKalimaPlugIn.cs index 6f7e43229..cec6ae4ff 100644 --- a/src/Persistence/Initialization/Updates/AddKalimaPlugIn.cs +++ b/src/Persistence/Initialization/Updates/AddKalimaPlugIn.cs @@ -3,6 +3,7 @@ // using MUnique.OpenMU.DataModel.Configuration.Items; +using MUnique.OpenMU.GameLogic; namespace MUnique.OpenMU.Persistence.Initialization.Updates; @@ -83,5 +84,20 @@ private void CreateSymbolOfKundun(IContext context, GameConfiguration gameConfig itemDefinition.MaximumItemLevel = 7; itemDefinition.SetGuid(itemDefinition.Group, itemDefinition.Number); gameConfiguration.Items.Add(itemDefinition); + + (byte, byte)[] dropLevels = [(25, 46), (47, 65), (66, 77), (78, 84), (85, 91), (92, 107), (108, 255)]; + for (byte level = 1; level <= dropLevels.Length; level++) + { + var dropItemGroup = context.CreateNew(); + dropItemGroup.SetGuid(14, 29, level); + dropItemGroup.ItemLevel = level; + dropItemGroup.PossibleItems.Add(itemDefinition); + dropItemGroup.Chance = 0.003; // 0.3 Percent + dropItemGroup.Description = $"The drop item group for Symbol of Kundun (Level {level})"; + (dropItemGroup.MinimumMonsterLevel, dropItemGroup.MaximumMonsterLevel) = dropLevels[level - 1]; + + gameConfiguration.DropItemGroups.Add(dropItemGroup); + gameConfiguration.Maps.ForEach(map => map.DropItemGroups.Add(dropItemGroup)); + } } } \ No newline at end of file diff --git a/src/Persistence/Initialization/VersionSeasonSix/Items/Misc.cs b/src/Persistence/Initialization/VersionSeasonSix/Items/Misc.cs index e1a77dd16..677db1920 100644 --- a/src/Persistence/Initialization/VersionSeasonSix/Items/Misc.cs +++ b/src/Persistence/Initialization/VersionSeasonSix/Items/Misc.cs @@ -60,6 +60,30 @@ private void CreateSymbolOfKundun() itemDefinition.MaximumItemLevel = 7; itemDefinition.SetGuid(itemDefinition.Group, itemDefinition.Number); this.GameConfiguration.Items.Add(itemDefinition); + + /* Drop Levels: + Symbol +1: Monster Level 25 ~ 46 + Symbol +2: Monster Level 47 ~ 65 + Symbol +3: Monster Level 66 ~ 77 + Symbol +4: Monster Level 78 ~ 84 + Symbol +5: Monster Level 85 ~ 91 + Symbol +6: Monster Level 92 ~ 107 + Symbol +7: Monster Level 108+ + */ + (byte, byte)[] dropLevels = [(25, 46), (47, 65), (66, 77), (78, 84), (85, 91), (92, 107), (108, 255)]; + for (byte level = 1; level <= dropLevels.Length; level++) + { + var dropItemGroup = this.Context.CreateNew(); + dropItemGroup.SetGuid(14, 29, level); + dropItemGroup.ItemLevel = level; + dropItemGroup.PossibleItems.Add(itemDefinition); + dropItemGroup.Chance = 0.003; // 0.3 Percent + dropItemGroup.Description = $"The drop item group for Symbol of Kundun (Level {level})"; + (dropItemGroup.MinimumMonsterLevel, dropItemGroup.MaximumMonsterLevel) = dropLevels[level - 1]; + + this.GameConfiguration.DropItemGroups.Add(dropItemGroup); + BaseMapInitializer.RegisterDefaultDropItemGroup(dropItemGroup); + } } private void CreateLifeStone() From 1ce547c8e564c1cbef86782f3e12bdb7c93063bd Mon Sep 17 00:00:00 2001 From: sven-n Date: Mon, 10 Jun 2024 17:56:34 +0200 Subject: [PATCH 24/29] Implemented Kalima Gates --- src/GameLogic/LocateableExtensions.cs | 9 ++ src/GameLogic/NPC/GateNpc.cs | 113 ++++++++++++++++++ src/GameLogic/NPC/ISummonable.cs | 21 ++++ src/GameLogic/NPC/Monster.cs | 2 +- .../PlayerActions/Items/DropItemAction.cs | 79 ++++-------- .../Items/ItemBoxDroppedPlugIn.cs | 68 +++++++++++ .../Items/LostMapDroppedPlugIn.cs | 93 ++++++++++++++ src/GameLogic/PlugIns/IItemDropPlugIn.cs | 56 +++++++++ src/GameLogic/PlugIns/KalimaConstants.cs | 69 +++++++++++ .../PlugIns/SymbolOfKundunStackedPlugIn.cs | 11 +- .../RemoteView/World/NewNpcsInScopePlugIn.cs | 29 +++-- .../Initialization/Updates/AddKalimaPlugIn.cs | 15 ++- .../VersionSeasonSix/NpcInitialization.cs | 1 + 13 files changed, 487 insertions(+), 79 deletions(-) create mode 100644 src/GameLogic/NPC/GateNpc.cs create mode 100644 src/GameLogic/NPC/ISummonable.cs create mode 100644 src/GameLogic/PlayerActions/Items/ItemBoxDroppedPlugIn.cs create mode 100644 src/GameLogic/PlayerActions/Items/LostMapDroppedPlugIn.cs create mode 100644 src/GameLogic/PlugIns/IItemDropPlugIn.cs create mode 100644 src/GameLogic/PlugIns/KalimaConstants.cs diff --git a/src/GameLogic/LocateableExtensions.cs b/src/GameLogic/LocateableExtensions.cs index d316e894d..bcfa8a86b 100644 --- a/src/GameLogic/LocateableExtensions.cs +++ b/src/GameLogic/LocateableExtensions.cs @@ -68,6 +68,15 @@ public static double GetDistanceTo(this ILocateable objectFrom, Point objectToPo /// True, if the specified coordinate is in the specified range of the object; Otherwise, false. public static bool IsInRange(this ILocateable obj, Point point, int range) => obj.IsInRange(point.X, point.Y, range); + /// + /// Determines whether the specified coordinates are in the specified range of the object. + /// + /// The object. + /// The second object. + /// The maximum range. + /// True, if the specified coordinate is in the specified range of the object; Otherwise, false. + public static bool IsInRange(this ILocateable obj, ILocateable obj2, int range) => obj.IsInRange(obj2.Position, range); + /// /// Determines whether the specified coordinate is in the specified range of the object. /// diff --git a/src/GameLogic/NPC/GateNpc.cs b/src/GameLogic/NPC/GateNpc.cs new file mode 100644 index 000000000..cb8b9df2b --- /dev/null +++ b/src/GameLogic/NPC/GateNpc.cs @@ -0,0 +1,113 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace MUnique.OpenMU.GameLogic.NPC; + +using System.Threading; + +/// +/// Represents a which is a gate to another map. +/// When a player gets close to the gate, it will warp the player to the target gate, +/// if the player is in the same party as the summoner. +/// +public class GateNpc : NonPlayerCharacter, ISummonable +{ + private const int Range = 2; + private readonly ILogger _logger; + private readonly Task _warpTask; + private readonly CancellationTokenSource _cts; + private int _enterCount; + + /// + /// Initializes a new instance of the class. + /// + /// The spawn information. + /// The stats. + /// The map. + /// The summoned by. + /// The target gate. + /// The lifespan. + public GateNpc(MonsterSpawnArea spawnInfo, MonsterDefinition stats, GameMap map, Player summonedBy, ExitGate targetGate, TimeSpan lifespan) + : base(spawnInfo, stats, map) + { + this.SummonedBy = summonedBy; + this.TargetGate = targetGate; + this._logger = summonedBy.GameContext.LoggerFactory.CreateLogger(); + this._cts = new CancellationTokenSource(lifespan); + this._warpTask = Task.Run(this.RunTaskAsync); + } + + /// + public Player SummonedBy { get; } + + /// + /// Gets the target gate. + /// + public ExitGate TargetGate { get; } + + /// + protected override async ValueTask DisposeAsyncCore() + { + await this._cts.CancelAsync().ConfigureAwait(false); + this._cts.Dispose(); + + await this._warpTask.ConfigureAwait(false); + await base.DisposeAsyncCore().ConfigureAwait(false); + } + + private async Task RunTaskAsync() + { + try + { + var cancellationToken = this._cts.Token; + var playersInRange = new List(); + while (true) + { + cancellationToken.ThrowIfCancellationRequested(); + + await Task.Delay(1000, cancellationToken).ConfigureAwait(false); + + if (!this.SummonedBy.IsAlive) + { + this._logger.LogInformation("Closing the gate, player is dead or offline"); + return; + } + + playersInRange.Clear(); + if (this.SummonedBy.Party is { } party) + { + playersInRange.AddRange(party.PartyList.OfType().Where(p => p.IsActive() && p.IsInRange(this, Range) && this.CurrentMap == p.CurrentMap)); + } + else if (this.SummonedBy.IsActive() && this.SummonedBy.IsInRange(this, Range) && this.CurrentMap == this.SummonedBy.CurrentMap) + { + playersInRange.Add(this.SummonedBy); + } + + foreach (var player in playersInRange) + { + this._logger.LogInformation("Player {player} passes the gate ({enterCount})", player, this._enterCount); + await player.WarpToAsync(this.TargetGate).ConfigureAwait(false); + this._enterCount++; + if (this._enterCount >= this.SummonedBy.GameContext.Configuration.MaximumPartySize) + { + this._logger.LogInformation("Closing the gate, maximum entrances reached ({enterCount})", this._enterCount); + return; + } + } + } + } + catch (OperationCanceledException) + { + // ignored + } + catch (Exception ex) + { + this._logger.LogError(ex, "Error in GateNpc task."); + } + finally + { + await this.DisposeAsync().ConfigureAwait(false); + } + } +} \ No newline at end of file diff --git a/src/GameLogic/NPC/ISummonable.cs b/src/GameLogic/NPC/ISummonable.cs new file mode 100644 index 000000000..72d9d5581 --- /dev/null +++ b/src/GameLogic/NPC/ISummonable.cs @@ -0,0 +1,21 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace MUnique.OpenMU.GameLogic.NPC; + +/// +/// An interface for a class which can (but not must) be summoned by a player. +/// +public interface ISummonable : IIdentifiable, ILocateable, IRotatable +{ + /// + /// Gets the player which summoned this instance. + /// + Player? SummonedBy { get; } + + /// + /// Gets the definition for this instance. + /// + MonsterDefinition Definition { get; } +} \ No newline at end of file diff --git a/src/GameLogic/NPC/Monster.cs b/src/GameLogic/NPC/Monster.cs index f1dbe4a81..d13f7444d 100644 --- a/src/GameLogic/NPC/Monster.cs +++ b/src/GameLogic/NPC/Monster.cs @@ -15,7 +15,7 @@ namespace MUnique.OpenMU.GameLogic.NPC; /// /// The implementation of a monster, which can attack players. /// -public sealed class Monster : AttackableNpcBase, IAttackable, IAttacker, ISupportWalk, IMovable +public sealed class Monster : AttackableNpcBase, IAttackable, IAttacker, ISupportWalk, IMovable, ISummonable { private readonly AsyncLock _moveLock = new(); private readonly INpcIntelligence _intelligence; diff --git a/src/GameLogic/PlayerActions/Items/DropItemAction.cs b/src/GameLogic/PlayerActions/Items/DropItemAction.cs index 6987d6ca8..6d3e14e51 100644 --- a/src/GameLogic/PlayerActions/Items/DropItemAction.cs +++ b/src/GameLogic/PlayerActions/Items/DropItemAction.cs @@ -4,9 +4,10 @@ namespace MUnique.OpenMU.GameLogic.PlayerActions.Items; -using MUnique.OpenMU.GameLogic.Views.Character; using MUnique.OpenMU.GameLogic.Views.Inventory; using MUnique.OpenMU.Pathfinding; +using MUnique.OpenMU.GameLogic.PlugIns; +using static MUnique.OpenMU.GameLogic.PlugIns.IItemDropPlugIn; /// /// Action to drop an item from the inventory to the floor. @@ -23,70 +24,36 @@ public async ValueTask DropItemAsync(Player player, byte slot, Point target) { var item = player.Inventory?.GetItem(slot); - if (item is not null && (player.CurrentMap?.Terrain.WalkMap[target.X, target.Y] ?? false)) - { - if (item.Definition!.DropItems.Count > 0 - && item.Definition!.DropItems.Where(di => di.SourceItemLevel == item.Level) is { } itemDropGroups) - { - await this.DropRandomItemAsync(item, player, itemDropGroups).ConfigureAwait(false); - } - else - { - await this.DropItemAsync(player, item, target).ConfigureAwait(false); - } - } - else + if (item is null + || !(player.CurrentMap?.Terrain.WalkMap[target.X, target.Y] ?? false)) { await player.InvokeViewPlugInAsync(p => p.ItemDropResultAsync(slot, false)).ConfigureAwait(false); - } - } - - /// - /// Drops a random item of the given at the players coordinates. - /// - /// The source item. - /// The player. - /// The from which the random item is generated. - private async ValueTask DropRandomItemAsync(Item sourceItem, Player player, IEnumerable dropItemGroups) - { - if (dropItemGroups.Any(g => g.RequiredCharacterLevel > player.Level)) - { - await player.InvokeViewPlugInAsync(p => p.ItemDropResultAsync(sourceItem.ItemSlot, false)).ConfigureAwait(false); return; } - var (item, droppedMoneyAmount, dropEffect) = player.GameContext.DropGenerator.GenerateItemDrop(dropItemGroups); - if (droppedMoneyAmount is not null) + if (player.GameContext.PlugInManager.GetPlugInPoint() is { } plugInPoint) { - var droppedMoney = new DroppedMoney(droppedMoneyAmount.Value, player.Position, player.CurrentMap!); - await player.CurrentMap!.AddAsync(droppedMoney).ConfigureAwait(false); - } - - if (item is not null) - { - var droppedItem = new DroppedItem(item, player.Position, player.CurrentMap!, player); - await player.CurrentMap!.AddAsync(droppedItem).ConfigureAwait(false); - } + var dropArguments = new ItemDropArguments(); + await plugInPoint.HandleItemDropAsync(player, item, target, dropArguments).ConfigureAwait(false); + if (dropArguments.Cancel) + { + // If we're here, that means that a plugin has handled the drop request. + // Now, we have to decide if we should remove the item from the inventory or not. + if (dropArguments.Success) + { + await this.RemoveItemFromInventoryAsync(player, item).ConfigureAwait(false); + await player.PersistenceContext.DeleteAsync(item).ConfigureAwait(false); + } + else + { + await player.InvokeViewPlugInAsync(p => p.ItemDropResultAsync(slot, false)).ConfigureAwait(false); + } - if (dropEffect is not ItemDropEffect.Undefined) - { - await this.ShowDropEffectAsync(player, dropEffect).ConfigureAwait(false); + return; + } } - await this.RemoveItemFromInventoryAsync(player, sourceItem).ConfigureAwait(false); - await player.PersistenceContext.DeleteAsync(sourceItem).ConfigureAwait(false); - } - - private async ValueTask ShowDropEffectAsync(Player player, ItemDropEffect dropEffect) - { - if (dropEffect == ItemDropEffect.Swirl) - { - await player.InvokeViewPlugInAsync(p => p.ShowEffectAsync(player, IShowEffectPlugIn.EffectType.Swirl)).ConfigureAwait(false); - } - else - { - await player.InvokeViewPlugInAsync(p => p.ShowEffectAsync(dropEffect, player.Position)).ConfigureAwait(false); - } + await this.DropItemAsync(player, item, target).ConfigureAwait(false); } private async ValueTask DropItemAsync(Player player, Item item, Point target) diff --git a/src/GameLogic/PlayerActions/Items/ItemBoxDroppedPlugIn.cs b/src/GameLogic/PlayerActions/Items/ItemBoxDroppedPlugIn.cs new file mode 100644 index 000000000..c985bc067 --- /dev/null +++ b/src/GameLogic/PlayerActions/Items/ItemBoxDroppedPlugIn.cs @@ -0,0 +1,68 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace MUnique.OpenMU.GameLogic.PlayerActions.Items; + +using System.Runtime.InteropServices; +using MUnique.OpenMU.GameLogic.PlugIns; +using MUnique.OpenMU.GameLogic.Views.Character; +using MUnique.OpenMU.Pathfinding; +using MUnique.OpenMU.PlugIns; +using static MUnique.OpenMU.GameLogic.PlugIns.IItemDropPlugIn; + +/// +/// This plugin handles the drop of an item box, e.g. box of kundun. +/// +[PlugIn(nameof(ItemBoxDroppedPlugIn), "This plugin handles the drop of an item box, e.g. box of kundun.")] +[Guid("3D15D55D-EEFE-4B5F-89B1-6934AB3F0BEE")] +public sealed class ItemBoxDroppedPlugIn : IItemDropPlugIn +{ + /// + public async ValueTask HandleItemDropAsync(Player player, Item sourceItem, Point target, ItemDropArguments cancelArgs) + { + if (sourceItem.Definition!.DropItems.Count <= 0 + || sourceItem.Definition!.DropItems.Where(di => di.SourceItemLevel == sourceItem.Level) is not { } itemDropGroups) + { + return; + } + + cancelArgs.WasHandled = true; + if (itemDropGroups.Any(g => g.RequiredCharacterLevel > player.Level)) + { + cancelArgs.Success = false; + return; + } + + cancelArgs.Success = true; + var (item, droppedMoneyAmount, dropEffect) = player.GameContext.DropGenerator.GenerateItemDrop(itemDropGroups); + if (droppedMoneyAmount is not null) + { + var droppedMoney = new DroppedMoney(droppedMoneyAmount.Value, player.Position, player.CurrentMap!); + await player.CurrentMap!.AddAsync(droppedMoney).ConfigureAwait(false); + } + + if (item is not null) + { + var droppedItem = new DroppedItem(item, player.Position, player.CurrentMap!, player); + await player.CurrentMap!.AddAsync(droppedItem).ConfigureAwait(false); + } + + if (dropEffect is not ItemDropEffect.Undefined) + { + await this.ShowDropEffectAsync(player, dropEffect).ConfigureAwait(false); + } + } + + private async ValueTask ShowDropEffectAsync(Player player, ItemDropEffect dropEffect) + { + if (dropEffect == ItemDropEffect.Swirl) + { + await player.InvokeViewPlugInAsync(p => p.ShowEffectAsync(player, IShowEffectPlugIn.EffectType.Swirl)).ConfigureAwait(false); + } + else + { + await player.InvokeViewPlugInAsync(p => p.ShowEffectAsync(dropEffect, player.Position)).ConfigureAwait(false); + } + } +} \ No newline at end of file diff --git a/src/GameLogic/PlayerActions/Items/LostMapDroppedPlugIn.cs b/src/GameLogic/PlayerActions/Items/LostMapDroppedPlugIn.cs new file mode 100644 index 000000000..32dc37d6d --- /dev/null +++ b/src/GameLogic/PlayerActions/Items/LostMapDroppedPlugIn.cs @@ -0,0 +1,93 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace MUnique.OpenMU.GameLogic.PlayerActions.Items; + +using System.Runtime.InteropServices; +using MUnique.OpenMU.GameLogic.NPC; +using MUnique.OpenMU.GameLogic.PlugIns; +using MUnique.OpenMU.GameLogic.PlugIns.ChatCommands; +using MUnique.OpenMU.Pathfinding; +using MUnique.OpenMU.PlugIns; +using MonsterSpawnArea = MUnique.OpenMU.Persistence.BasicModel.MonsterSpawnArea; + +/// +/// This plugin transforms a stack of symbol of kundun into a lost map. +/// todo: implement plugin configuration to resolve magic numbers. +/// +[PlugIn(nameof(LostMapDroppedPlugIn), "This plugin handles the drop of the lost map item. It creates the gate to the kalima map.")] +[Guid("F6DB10E0-AE7F-4BC6-914F-B858763C5CF7")] +public sealed class LostMapDroppedPlugIn : IItemDropPlugIn +{ + private static readonly int[] KalimaMapNumbers = [24, 25, 26, 27, 28, 29, 36]; + + private const byte GateNpcStartNumber = 152; + + /// + public async ValueTask HandleItemDropAsync(Player player, Item item, Point target, IItemDropPlugIn.ItemDropArguments cancelArgs) + { + if (!item.IsLostMap()) + { + return; + } + + cancelArgs.WasHandled = true; + var currentMap = player.CurrentMap; + if (currentMap is null) + { + return; + } + + if (item.Level is < 1 or > 7) + { + await player.ShowMessageAsync("The lost map is not valid.").ConfigureAwait(false); + return; + } + + if (player.CurrentMiniGame is not null) + { + await player.ShowMessageAsync("Cannot create kalima gate on event map.").ConfigureAwait(false); + return; + } + + var gatePosition = target; + if (player.IsAtSafezone() || player.CurrentMap?.Terrain.SafezoneMap[gatePosition.X, gatePosition.Y] is true) + { + await player.ShowMessageAsync("Cannot create kalima gate in safe zone.").ConfigureAwait(false); + return; + } + + var gateNpcNumber = GateNpcStartNumber + item.Level; + var gateNpcDef = player.GameContext.Configuration.Monsters.FirstOrDefault(def => def.Number == gateNpcNumber); + if (gateNpcDef is null) + { + await player.ShowMessageAsync("The gate npc is not defined.").ConfigureAwait(false); + return; + } + + var spawnArea = new MonsterSpawnArea + { + Direction = Direction.West, + Quantity = 1, + MonsterDefinition = gateNpcDef, + SpawnTrigger = SpawnTrigger.ManuallyForEvent, + X1 = target.X, + X2 = target.X, + Y1 = target.Y, + Y2 = target.Y, + }; + + var targetGate = player.GameContext.Configuration.Maps.FirstOrDefault(g => g.Number == KalimaMapNumbers[item.Level - 1])?.ExitGates.FirstOrDefault(); + if (targetGate is null) + { + await player.ShowMessageAsync("The kalima entrance wasn't found.").ConfigureAwait(false); + return; + } + + var gate = new GateNpc(spawnArea, gateNpcDef, currentMap, player, targetGate, TimeSpan.FromMinutes(1)); + gate.Initialize(); + await currentMap.AddAsync(gate).ConfigureAwait(false); + cancelArgs.Success = true; + } +} \ No newline at end of file diff --git a/src/GameLogic/PlugIns/IItemDropPlugIn.cs b/src/GameLogic/PlugIns/IItemDropPlugIn.cs new file mode 100644 index 000000000..1c760aad4 --- /dev/null +++ b/src/GameLogic/PlugIns/IItemDropPlugIn.cs @@ -0,0 +1,56 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace MUnique.OpenMU.GameLogic.PlugIns; + +using System.ComponentModel; +using System.Runtime.InteropServices; +using MUnique.OpenMU.Pathfinding; +using MUnique.OpenMU.PlugIns; + +/// +/// A plugin interface which is called when an item has been dropped to the ground by the player. +/// +[Guid("EDB62A52-96BA-4ACA-9355-244834D53437")] +[PlugInPoint("Item dropping", "Plugins which are called when an item has been dropped to the ground by the player.")] +public interface IItemDropPlugIn +{ + /// + /// Is called when an item has been dropped to the ground by the player. + /// + /// The player. + /// The item. + /// The target point on the ground. + /// The instance containing the event data. + /// A plugin can define what's happening after the plugin has been executed. + /// + /// true, when the item should be removed and deleted from the inventory; otherwise, false. + /// + ValueTask HandleItemDropAsync(Player player, Item item, Point target, ItemDropArguments dropArgs); + + /// + /// Arguments for handling the item drop. + /// + public class ItemDropArguments : CancelEventArgs + { + /// + /// Gets or sets a value indicating whether the item drop request was handled. + /// In this case is set to true to prevent further plugins to execute. + /// + public bool WasHandled + { + get => this.Cancel; + set => this.Cancel = value; + } + + /// + /// Gets or sets a value indicating whether the item should be removed and deleted from the inventory + /// when also is set to true. + /// + /// + /// true if [remove item]; otherwise, false. + /// + public bool Success { get; set; } + } +} \ No newline at end of file diff --git a/src/GameLogic/PlugIns/KalimaConstants.cs b/src/GameLogic/PlugIns/KalimaConstants.cs new file mode 100644 index 000000000..90b6e9954 --- /dev/null +++ b/src/GameLogic/PlugIns/KalimaConstants.cs @@ -0,0 +1,69 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace MUnique.OpenMU.GameLogic.PlugIns; + +using MUnique.OpenMU.DataModel.Configuration.Items; + +/// +/// Constants for the Kalima map. +/// +public static class KalimaConstants +{ + /// + /// The symbol of kundun item group. + /// + internal const byte SymbolOfKundunGroup = 14; + + /// + /// The symbol of kundun item number. + /// + internal const byte SymbolOfKundunNumber = 29; + + /// + /// The lost map item group. + /// + internal const byte LostMapGroup = 14; + + /// + /// The lost map item number. + /// + internal const byte LostMapNumber = 28; + + /// + /// Determines whether the specified item is a lost map. + /// + /// The item. + /// + /// true if the specified item is a lost map; otherwise, false. + /// + public static bool IsLostMap(this Item item) + { + return item.Definition.IsLostMap(); + } + + /// + /// Determines whether the specified item is a lost map. + /// + /// The item definition. + /// + /// true if the specified item is a lost map; otherwise, false. + /// + public static bool IsLostMap(this ItemDefinition? itemDefinition) + { + return itemDefinition is { Group: LostMapGroup, Number: LostMapNumber }; + } + + /// + /// Determines whether the specified item is a symbol of kundun. + /// + /// The item. + /// + /// true if the specified item is a symbol of kundun; otherwise, false. + /// + public static bool IsSymbolOfKundun(this Item item) + { + return item.Definition is { Group: SymbolOfKundunGroup, Number: SymbolOfKundunNumber }; + } +} \ No newline at end of file diff --git a/src/GameLogic/PlugIns/SymbolOfKundunStackedPlugIn.cs b/src/GameLogic/PlugIns/SymbolOfKundunStackedPlugIn.cs index f95244fba..7b10836fd 100644 --- a/src/GameLogic/PlugIns/SymbolOfKundunStackedPlugIn.cs +++ b/src/GameLogic/PlugIns/SymbolOfKundunStackedPlugIn.cs @@ -14,25 +14,20 @@ namespace MUnique.OpenMU.GameLogic.PlugIns; [Guid("F07A9CED-F43E-4824-9587-F5C3C3187A13")] public sealed class SymbolOfKundunStackedPlugIn : IItemStackedPlugIn { - private const byte SymbolOfKundunGroup = 14; - private const byte SymbolOfKundunNumber = 29; - private const byte LostMapGroup = 14; - private const byte LostMapNumber = 28; - /// public async ValueTask ItemStackedAsync(Player player, Item sourceItem, Item targetItem) { - if (targetItem.Definition is not { Group: SymbolOfKundunGroup, Number: SymbolOfKundunNumber }) + if (!targetItem.IsSymbolOfKundun()) { return; } - if (targetItem.Durability() < targetItem.Definition.Durability) + if (targetItem.Durability() < targetItem.Definition?.Durability) { return; } - var lostMap = player.GameContext.Configuration.Items.FirstOrDefault(item => item is { Group: LostMapGroup, Number: LostMapNumber }); + var lostMap = player.GameContext.Configuration.Items.FirstOrDefault(item => item.IsLostMap()); if (lostMap is null) { player.Logger.LogWarning("Lost map definition not found."); diff --git a/src/GameServer/RemoteView/World/NewNpcsInScopePlugIn.cs b/src/GameServer/RemoteView/World/NewNpcsInScopePlugIn.cs index a7db6c307..0563da197 100644 --- a/src/GameServer/RemoteView/World/NewNpcsInScopePlugIn.cs +++ b/src/GameServer/RemoteView/World/NewNpcsInScopePlugIn.cs @@ -38,8 +38,8 @@ public async ValueTask NewNpcsInScopeAsync(IEnumerable newOb return; } - var summons = newObjects.OfType().Where(m => m.SummonedBy is { }).ToList(); - var npcs = newObjects.Except(summons).ToList(); + var summons = newObjects.OfType().Where(m => m.SummonedBy is { }).ToList(); + var npcs = newObjects.Except(summons.OfType()).ToList(); if (npcs.Any()) { @@ -100,7 +100,7 @@ int Write() await connection.SendAsync(Write).ConfigureAwait(false); } - private static async ValueTask SummonedMonstersInScopeAsync(bool isSpawned, IConnection connection, ICollection summons) + private static async ValueTask SummonedMonstersInScopeAsync(bool isSpawned, IConnection connection, ICollection summons) { int Write() { @@ -127,10 +127,10 @@ int Write() block.CurrentPositionX = summon.Position.X; block.CurrentPositionY = summon.Position.Y; - if (summon.IsWalking) + if (summon is ISupportWalk walker && walker.IsWalking) { - block.TargetPositionX = summon.WalkTarget.X; - block.TargetPositionY = summon.WalkTarget.Y; + block.TargetPositionX = walker.WalkTarget.X; + block.TargetPositionY = walker.WalkTarget.Y; } else { @@ -141,12 +141,19 @@ int Write() block.Rotation = summon.Rotation.ToPacketByte(); block.OwnerCharacterName = summon.SummonedBy?.Name ?? string.Empty; - var activeEffects = summon.MagicEffectList.VisibleEffects; - block.EffectCount = (byte)activeEffects.Count; - for (int e = block.EffectCount - 1; e >= 0; e--) + if (summon is IAttackable attackable) { - var effectBlock = block[e]; - effectBlock.Id = (byte)activeEffects[e].Id; + var activeEffects = attackable.MagicEffectList.VisibleEffects; + block.EffectCount = (byte)activeEffects.Count; + for (int e = block.EffectCount - 1; e >= 0; e--) + { + var effectBlock = block[e]; + effectBlock.Id = (byte)activeEffects[e].Id; + } + } + else + { + block.EffectCount = 0; } i++; diff --git a/src/Persistence/Initialization/Updates/AddKalimaPlugIn.cs b/src/Persistence/Initialization/Updates/AddKalimaPlugIn.cs index cec6ae4ff..b28a2ba41 100644 --- a/src/Persistence/Initialization/Updates/AddKalimaPlugIn.cs +++ b/src/Persistence/Initialization/Updates/AddKalimaPlugIn.cs @@ -2,13 +2,12 @@ // Licensed under the MIT License. See LICENSE file in the project root for full license information. // -using MUnique.OpenMU.DataModel.Configuration.Items; -using MUnique.OpenMU.GameLogic; - namespace MUnique.OpenMU.Persistence.Initialization.Updates; using System.Runtime.InteropServices; using MUnique.OpenMU.DataModel.Configuration; +using MUnique.OpenMU.DataModel.Configuration.Items; +using MUnique.OpenMU.GameLogic; using MUnique.OpenMU.PlugIns; /// @@ -53,6 +52,16 @@ protected override async ValueTask ApplyAsync(IContext context, GameConfiguratio { this.CreateLostMap(context, gameConfiguration); this.CreateSymbolOfKundun(context, gameConfiguration); + + // copy potion girl items to oracle layla: + var potionGirl = gameConfiguration.Monsters.First(m => m.Number == 253); + var oracleLayla = gameConfiguration.Monsters.First(m => m.Number == 259); + if (oracleLayla.NpcWindow is not NpcWindow.Merchant && oracleLayla.MerchantStore is null) + { + oracleLayla.NpcWindow = NpcWindow.Merchant; + oracleLayla.MerchantStore = potionGirl.MerchantStore!.Clone(gameConfiguration); + oracleLayla.MerchantStore.SetGuid(oracleLayla.Number); + } } private void CreateLostMap(IContext context, GameConfiguration gameConfiguration) diff --git a/src/Persistence/Initialization/VersionSeasonSix/NpcInitialization.cs b/src/Persistence/Initialization/VersionSeasonSix/NpcInitialization.cs index 0d34049c2..af82a718a 100644 --- a/src/Persistence/Initialization/VersionSeasonSix/NpcInitialization.cs +++ b/src/Persistence/Initialization/VersionSeasonSix/NpcInitialization.cs @@ -124,6 +124,7 @@ public override void Initialize() def.Number = 259; def.Designation = "Oracle Layla"; def.ObjectKind = NpcObjectKind.PassiveNpc; + def.MerchantStore = this.CreatePotionGirlItemStorage(def.Number); this.GameConfiguration.Monsters.Add(def); def.SetGuid(def.Number); } From 8fd9834902713be8f8c95cb2a4d7035aaea5977f Mon Sep 17 00:00:00 2001 From: sven-n Date: Wed, 12 Jun 2024 06:43:54 +0200 Subject: [PATCH 25/29] fix code style and missing dispose --- src/GameLogic/NPC/GateNpc.cs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/GameLogic/NPC/GateNpc.cs b/src/GameLogic/NPC/GateNpc.cs index cb8b9df2b..4bdb6498d 100644 --- a/src/GameLogic/NPC/GateNpc.cs +++ b/src/GameLogic/NPC/GateNpc.cs @@ -46,6 +46,14 @@ public GateNpc(MonsterSpawnArea spawnInfo, MonsterDefinition stats, GameMap map, /// public ExitGate TargetGate { get; } + /// + protected override void Dispose(bool disposing) + { + this._cts.Cancel(); + this._cts.Dispose(); + base.Dispose(disposing); + } + /// protected override async ValueTask DisposeAsyncCore() { @@ -77,12 +85,16 @@ private async Task RunTaskAsync() playersInRange.Clear(); if (this.SummonedBy.Party is { } party) { - playersInRange.AddRange(party.PartyList.OfType().Where(p => p.IsActive() && p.IsInRange(this, Range) && this.CurrentMap == p.CurrentMap)); + playersInRange.AddRange(party.PartyList.OfType().Where(this.IsPlayerInRange)); } - else if (this.SummonedBy.IsActive() && this.SummonedBy.IsInRange(this, Range) && this.CurrentMap == this.SummonedBy.CurrentMap) + else if (this.IsPlayerInRange(this.SummonedBy)) { playersInRange.Add(this.SummonedBy); } + else + { + // do nothing. + } foreach (var player in playersInRange) { @@ -110,4 +122,9 @@ private async Task RunTaskAsync() await this.DisposeAsync().ConfigureAwait(false); } } + + private bool IsPlayerInRange(Player player) + { + return player.IsActive() && player.IsInRange(this, Range) && this.CurrentMap == player.CurrentMap; + } } \ No newline at end of file From d23e728433af515400bb33914fd0e4f510f949ff Mon Sep 17 00:00:00 2001 From: sven-n Date: Thu, 13 Jun 2024 22:52:59 +0200 Subject: [PATCH 26/29] Fixed kalima gate npc selection --- src/GameLogic/PlayerActions/Items/LostMapDroppedPlugIn.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GameLogic/PlayerActions/Items/LostMapDroppedPlugIn.cs b/src/GameLogic/PlayerActions/Items/LostMapDroppedPlugIn.cs index 32dc37d6d..e88956903 100644 --- a/src/GameLogic/PlayerActions/Items/LostMapDroppedPlugIn.cs +++ b/src/GameLogic/PlayerActions/Items/LostMapDroppedPlugIn.cs @@ -58,7 +58,7 @@ public async ValueTask HandleItemDropAsync(Player player, Item item, Point targe return; } - var gateNpcNumber = GateNpcStartNumber + item.Level; + var gateNpcNumber = GateNpcStartNumber + item.Level - 1; var gateNpcDef = player.GameContext.Configuration.Monsters.FirstOrDefault(def => def.Number == gateNpcNumber); if (gateNpcDef is null) { From 084826e732ba26f6d6407fe24b047b8fca362290 Mon Sep 17 00:00:00 2001 From: sven-n Date: Fri, 14 Jun 2024 22:02:26 +0200 Subject: [PATCH 27/29] Increased resiliency against invalid data --- src/GameLogic/Player.cs | 25 ++++++- .../Character/DeleteCharacterAction.cs | 8 ++- src/GameLogic/Storage.cs | 68 +++++++++++++------ 3 files changed, 78 insertions(+), 23 deletions(-) diff --git a/src/GameLogic/Player.cs b/src/GameLogic/Player.cs index 0a24ce652..80f3d8bbe 100644 --- a/src/GameLogic/Player.cs +++ b/src/GameLogic/Player.cs @@ -1793,7 +1793,7 @@ private void AddMissingStatAttributes() { if (this.SelectedCharacter is not { CharacterClass: { } characterClass } character) { - return; + throw new InvalidOperationException($"The character {this.SelectedCharacter} has no assigned character class."); } var missingStats = characterClass.StatAttributes.Where(a => this.SelectedCharacter.Attributes.All(c => c.Definition != a.Attribute)); @@ -1804,8 +1804,29 @@ private void AddMissingStatAttributes() private async ValueTask OnPlayerEnteredWorldAsync() { - this.Attributes = new ItemAwareAttributeSystem(this.Account!, this.SelectedCharacter!); + if (this.SelectedCharacter is null) + { + throw new InvalidOperationException($"The player has no selected character."); + } + + if (this.SelectedCharacter?.CharacterClass is null) + { + throw new InvalidOperationException($"The character '{this.SelectedCharacter}' has no assigned character class."); + } + + // For characters which got created on the database or with the admin panel, + // it's possible that they're missing the inventory. In this case, we create it here + // and initialize with default items. + if (this.SelectedCharacter!.Inventory is null) + { + this.SelectedCharacter.Inventory = this.PersistenceContext.CreateNew(); + this.GameContext.PlugInManager.GetPlugInPoint()?.CharacterCreated(this, this.SelectedCharacter); + } + + this.SelectedCharacter.CurrentMap ??= this.SelectedCharacter.CharacterClass?.HomeMap; this.AddMissingStatAttributes(); + + this.Attributes = new ItemAwareAttributeSystem(this.Account!, this.SelectedCharacter!); this.Inventory = new InventoryStorage(this, this.GameContext); this.ShopStorage = new ShopStorage(this); this.TemporaryStorage = new Storage(InventoryConstants.TemporaryStorageSize, new TemporaryItemStorage()); diff --git a/src/GameLogic/PlayerActions/Character/DeleteCharacterAction.cs b/src/GameLogic/PlayerActions/Character/DeleteCharacterAction.cs index e7240ea1e..e5b7d0f27 100644 --- a/src/GameLogic/PlayerActions/Character/DeleteCharacterAction.cs +++ b/src/GameLogic/PlayerActions/Character/DeleteCharacterAction.cs @@ -46,7 +46,13 @@ private async ValueTask DeleteCharacterRequestAsync(Playe return CharacterDeleteResult.Unsuccessful; } - if (player.Account.SecurityCode != null && player.Account.SecurityCode != securityCode) + var checkAsPassword = string.IsNullOrEmpty(player.Account.SecurityCode); + if (checkAsPassword && !BCrypt.Net.BCrypt.Verify(securityCode, player.Account.PasswordHash)) + { + return CharacterDeleteResult.WrongSecurityCode; + } + + if (!checkAsPassword && player.Account.SecurityCode != securityCode) { return CharacterDeleteResult.WrongSecurityCode; } diff --git a/src/GameLogic/Storage.cs b/src/GameLogic/Storage.cs index a81ff1d60..2558dbb5b 100644 --- a/src/GameLogic/Storage.cs +++ b/src/GameLogic/Storage.cs @@ -43,15 +43,36 @@ public Storage(int numberOfSlots, int boxOffset, int slotOffset, ItemStorage ite this._boxOffset = boxOffset; var lastSlot = numberOfSlots + slotOffset; + List? unfittingItems = null; this.ItemStorage.Items .Where(item => item.ItemSlot <= lastSlot && item.ItemSlot >= slotOffset) .ForEach(item => { if (!this.AddItemInternal((byte)(item.ItemSlot - slotOffset), item)) { - throw new ArgumentException($"'{item}' did not fit into the storage at slot {item.ItemSlot}."); + (unfittingItems ??= new()).Add(item); } }); + + if (unfittingItems is null) + { + return; + } + + // we first try to add them. + for (var index = unfittingItems.Count - 1; index >= 0; index--) + { + var item = unfittingItems[index]; + if (this.AddItem(item)) + { + unfittingItems.RemoveAt(index); + } + } + + if (unfittingItems.Count > 0) + { + throw new ArgumentException($"Some items do not fit into the storage: {string.Join(';', unfittingItems)}"); + } } /// @@ -60,10 +81,7 @@ public Storage(int numberOfSlots, int boxOffset, int slotOffset, ItemStorage ite /// public IEnumerable Items { - get - { - return this.ItemArray.Where(i => i is not null).Select(item => item!); - } + get { return this.ItemArray.Where(i => i is not null).Select(item => item!); } } /// @@ -96,26 +114,13 @@ public IEnumerable FreeSlots /// public virtual async ValueTask AddItemAsync(byte slot, Item item) { - var result = this.AddItemInternal((byte)(slot - this._slotOffset), item); - if (result) - { - this.ItemStorage.Items.Add(item); - item.ItemSlot = slot; - } - - return result; + return this.AddItem(slot, item); } /// public async ValueTask AddItemAsync(Item item) { - var freeSlot = this.CheckInvSpace(item); - if (freeSlot is null) - { - return false; - } - - return await this.AddItemAsync((byte)freeSlot, item).ConfigureAwait(false); + return this.AddItem(item); } /// @@ -269,6 +274,29 @@ protected bool AddItemInternal(byte slot, Item item) return true; } + private bool AddItem(Item item) + { + var freeSlot = this.CheckInvSpace(item); + if (freeSlot is null) + { + return false; + } + + return this.AddItem((byte)freeSlot, item); + } + + private bool AddItem(byte slot, Item item) + { + var result = this.AddItemInternal((byte)(slot - this._slotOffset), item); + if (result) + { + this.ItemStorage.Items.Add(item); + item.ItemSlot = slot; + } + + return result; + } + private byte GetSlot(int column, int row) { byte result = (byte)(this._slotOffset + this._boxOffset + column + (row * InventoryConstants.RowSize)); From 0d02c12376b3529d262e0fe0689c24868544b295 Mon Sep 17 00:00:00 2001 From: sven-n Date: Fri, 14 Jun 2024 22:02:50 +0200 Subject: [PATCH 28/29] Added missing npc window for oracle layla --- .../Initialization/VersionSeasonSix/NpcInitialization.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Persistence/Initialization/VersionSeasonSix/NpcInitialization.cs b/src/Persistence/Initialization/VersionSeasonSix/NpcInitialization.cs index af82a718a..8da71c773 100644 --- a/src/Persistence/Initialization/VersionSeasonSix/NpcInitialization.cs +++ b/src/Persistence/Initialization/VersionSeasonSix/NpcInitialization.cs @@ -123,6 +123,7 @@ public override void Initialize() var def = this.Context.CreateNew(); def.Number = 259; def.Designation = "Oracle Layla"; + def.NpcWindow = NpcWindow.Merchant; def.ObjectKind = NpcObjectKind.PassiveNpc; def.MerchantStore = this.CreatePotionGirlItemStorage(def.Number); this.GameConfiguration.Monsters.Add(def); From 69df37085747b6232068ff61c17b46d150bb7c56 Mon Sep 17 00:00:00 2001 From: sven-n Date: Sat, 15 Jun 2024 17:40:29 +0200 Subject: [PATCH 29/29] Updated some nuget references --- .../MUnique.OpenMU.ChatServer.ExDbConnector.csproj | 2 +- .../AdminPanel.Host/MUnique.OpenMU.AdminPanel.Host.csproj | 2 +- .../ChatServer.Host/MUnique.OpenMU.ChatServer.Host.csproj | 2 +- src/Dapr/Common/MUnique.OpenMU.Dapr.Common.csproj | 6 +++--- .../MUnique.OpenMU.ConnectServer.Host.csproj | 2 +- .../MUnique.OpenMU.FriendServer.Host.csproj | 2 +- .../GameServer.Host/MUnique.OpenMU.GameServer.Host.csproj | 2 +- .../MUnique.OpenMU.GuildServer.Host.csproj | 2 +- .../MUnique.OpenMU.LoginServer.Host.csproj | 2 +- src/Directory.Build.props | 2 +- src/GameLogic/MUnique.OpenMU.GameLogic.csproj | 2 +- .../Analyzer/MUnique.OpenMU.Network.Analyzer.csproj | 4 ++-- src/Network/MUnique.OpenMU.Network.csproj | 2 +- .../MUnique.OpenMU.Persistence.EntityFramework.csproj | 8 ++++---- src/Persistence/MUnique.OpenMU.Persistence.csproj | 2 +- .../MUnique.OpenMU.Persistence.SourceGenerator.csproj | 2 +- src/PlugIns/MUnique.OpenMU.PlugIns.csproj | 6 +++--- .../MUnique.OpenMU.SourceGenerators.csproj | 2 +- src/Startup/MUnique.OpenMU.Startup.csproj | 4 ++-- src/Web/AdminPanel/MUnique.OpenMU.Web.AdminPanel.csproj | 2 +- src/Web/ItemEditor/MUnique.OpenMU.Web.ItemEditor.csproj | 2 +- src/Web/Map/MUnique.OpenMU.Web.Map.csproj | 2 +- .../MUnique.OpenMU.AttributeSystem.Tests.csproj | 2 +- .../MUnique.OpenMU.ChatServer.Tests.csproj | 2 +- .../MUnique.OpenMU.Network.Benchmarks.csproj | 2 +- .../MUnique.OpenMU.Network.Tests.csproj | 2 +- .../MUnique.OpenMU.Pathfinding.Tests.csproj | 2 +- ...MUnique.OpenMU.Persistence.Initialization.Tests.csproj | 2 +- .../MUnique.OpenMU.PlugIns.Tests.csproj | 2 +- tests/MUnique.OpenMU.Tests/MUnique.OpenMU.Tests.csproj | 2 +- 30 files changed, 39 insertions(+), 39 deletions(-) diff --git a/src/ChatServer/ExDbConnector/MUnique.OpenMU.ChatServer.ExDbConnector.csproj b/src/ChatServer/ExDbConnector/MUnique.OpenMU.ChatServer.ExDbConnector.csproj index 90d2f243e..a0e9ed3af 100644 --- a/src/ChatServer/ExDbConnector/MUnique.OpenMU.ChatServer.ExDbConnector.csproj +++ b/src/ChatServer/ExDbConnector/MUnique.OpenMU.ChatServer.ExDbConnector.csproj @@ -23,7 +23,7 @@ - + diff --git a/src/Dapr/AdminPanel.Host/MUnique.OpenMU.AdminPanel.Host.csproj b/src/Dapr/AdminPanel.Host/MUnique.OpenMU.AdminPanel.Host.csproj index 0523f073d..f5d134afe 100644 --- a/src/Dapr/AdminPanel.Host/MUnique.OpenMU.AdminPanel.Host.csproj +++ b/src/Dapr/AdminPanel.Host/MUnique.OpenMU.AdminPanel.Host.csproj @@ -15,7 +15,7 @@ - + diff --git a/src/Dapr/ChatServer.Host/MUnique.OpenMU.ChatServer.Host.csproj b/src/Dapr/ChatServer.Host/MUnique.OpenMU.ChatServer.Host.csproj index 872e4c4b0..46fa8d1be 100644 --- a/src/Dapr/ChatServer.Host/MUnique.OpenMU.ChatServer.Host.csproj +++ b/src/Dapr/ChatServer.Host/MUnique.OpenMU.ChatServer.Host.csproj @@ -15,7 +15,7 @@ - + diff --git a/src/Dapr/Common/MUnique.OpenMU.Dapr.Common.csproj b/src/Dapr/Common/MUnique.OpenMU.Dapr.Common.csproj index 61e97761c..fb09ceaa8 100644 --- a/src/Dapr/Common/MUnique.OpenMU.Dapr.Common.csproj +++ b/src/Dapr/Common/MUnique.OpenMU.Dapr.Common.csproj @@ -21,17 +21,17 @@ - + - + - + diff --git a/src/Dapr/ConnectServer.Host/MUnique.OpenMU.ConnectServer.Host.csproj b/src/Dapr/ConnectServer.Host/MUnique.OpenMU.ConnectServer.Host.csproj index 5d8c472f9..54dbee9a5 100644 --- a/src/Dapr/ConnectServer.Host/MUnique.OpenMU.ConnectServer.Host.csproj +++ b/src/Dapr/ConnectServer.Host/MUnique.OpenMU.ConnectServer.Host.csproj @@ -15,7 +15,7 @@ - + diff --git a/src/Dapr/FriendServer.Host/MUnique.OpenMU.FriendServer.Host.csproj b/src/Dapr/FriendServer.Host/MUnique.OpenMU.FriendServer.Host.csproj index 71932facd..b2c6de399 100644 --- a/src/Dapr/FriendServer.Host/MUnique.OpenMU.FriendServer.Host.csproj +++ b/src/Dapr/FriendServer.Host/MUnique.OpenMU.FriendServer.Host.csproj @@ -15,7 +15,7 @@ - + diff --git a/src/Dapr/GameServer.Host/MUnique.OpenMU.GameServer.Host.csproj b/src/Dapr/GameServer.Host/MUnique.OpenMU.GameServer.Host.csproj index 07dd7e3fc..73520483b 100644 --- a/src/Dapr/GameServer.Host/MUnique.OpenMU.GameServer.Host.csproj +++ b/src/Dapr/GameServer.Host/MUnique.OpenMU.GameServer.Host.csproj @@ -15,7 +15,7 @@ - + diff --git a/src/Dapr/GuildServer.Host/MUnique.OpenMU.GuildServer.Host.csproj b/src/Dapr/GuildServer.Host/MUnique.OpenMU.GuildServer.Host.csproj index e5ce5fe08..40b70062a 100644 --- a/src/Dapr/GuildServer.Host/MUnique.OpenMU.GuildServer.Host.csproj +++ b/src/Dapr/GuildServer.Host/MUnique.OpenMU.GuildServer.Host.csproj @@ -15,7 +15,7 @@ - + diff --git a/src/Dapr/LoginServer.Host/MUnique.OpenMU.LoginServer.Host.csproj b/src/Dapr/LoginServer.Host/MUnique.OpenMU.LoginServer.Host.csproj index 7aaf01d3c..f19a0b21f 100644 --- a/src/Dapr/LoginServer.Host/MUnique.OpenMU.LoginServer.Host.csproj +++ b/src/Dapr/LoginServer.Host/MUnique.OpenMU.LoginServer.Host.csproj @@ -15,7 +15,7 @@ - + diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 0b5bbfd96..edc43c7a7 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -3,7 +3,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/GameLogic/MUnique.OpenMU.GameLogic.csproj b/src/GameLogic/MUnique.OpenMU.GameLogic.csproj index e59831332..282bec7ce 100644 --- a/src/GameLogic/MUnique.OpenMU.GameLogic.csproj +++ b/src/GameLogic/MUnique.OpenMU.GameLogic.csproj @@ -24,7 +24,7 @@ - + diff --git a/src/Network/Analyzer/MUnique.OpenMU.Network.Analyzer.csproj b/src/Network/Analyzer/MUnique.OpenMU.Network.Analyzer.csproj index 5f941a73b..3a5ba83d3 100644 --- a/src/Network/Analyzer/MUnique.OpenMU.Network.Analyzer.csproj +++ b/src/Network/Analyzer/MUnique.OpenMU.Network.Analyzer.csproj @@ -33,8 +33,8 @@ - - + + diff --git a/src/Network/MUnique.OpenMU.Network.csproj b/src/Network/MUnique.OpenMU.Network.csproj index 6b97e8925..a4f62f9a1 100644 --- a/src/Network/MUnique.OpenMU.Network.csproj +++ b/src/Network/MUnique.OpenMU.Network.csproj @@ -42,7 +42,7 @@ - + diff --git a/src/Persistence/EntityFramework/MUnique.OpenMU.Persistence.EntityFramework.csproj b/src/Persistence/EntityFramework/MUnique.OpenMU.Persistence.EntityFramework.csproj index 275d28b4c..abada395a 100644 --- a/src/Persistence/EntityFramework/MUnique.OpenMU.Persistence.EntityFramework.csproj +++ b/src/Persistence/EntityFramework/MUnique.OpenMU.Persistence.EntityFramework.csproj @@ -21,13 +21,13 @@ - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + diff --git a/src/Persistence/MUnique.OpenMU.Persistence.csproj b/src/Persistence/MUnique.OpenMU.Persistence.csproj index 51a8d6db0..358f5c940 100644 --- a/src/Persistence/MUnique.OpenMU.Persistence.csproj +++ b/src/Persistence/MUnique.OpenMU.Persistence.csproj @@ -32,7 +32,7 @@ - + diff --git a/src/Persistence/SourceGenerator/MUnique.OpenMU.Persistence.SourceGenerator.csproj b/src/Persistence/SourceGenerator/MUnique.OpenMU.Persistence.SourceGenerator.csproj index 29a6b99bd..cb7d8e371 100644 --- a/src/Persistence/SourceGenerator/MUnique.OpenMU.Persistence.SourceGenerator.csproj +++ b/src/Persistence/SourceGenerator/MUnique.OpenMU.Persistence.SourceGenerator.csproj @@ -11,7 +11,7 @@ - + diff --git a/src/PlugIns/MUnique.OpenMU.PlugIns.csproj b/src/PlugIns/MUnique.OpenMU.PlugIns.csproj index c339f2cd2..ab8f86666 100644 --- a/src/PlugIns/MUnique.OpenMU.PlugIns.csproj +++ b/src/PlugIns/MUnique.OpenMU.PlugIns.csproj @@ -31,9 +31,9 @@ - - - + + + diff --git a/src/SourceGenerators/MUnique.OpenMU.SourceGenerators.csproj b/src/SourceGenerators/MUnique.OpenMU.SourceGenerators.csproj index afd58f693..4f522753a 100644 --- a/src/SourceGenerators/MUnique.OpenMU.SourceGenerators.csproj +++ b/src/SourceGenerators/MUnique.OpenMU.SourceGenerators.csproj @@ -16,7 +16,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + all diff --git a/src/Startup/MUnique.OpenMU.Startup.csproj b/src/Startup/MUnique.OpenMU.Startup.csproj index b86d7ddd5..9c89299e7 100644 --- a/src/Startup/MUnique.OpenMU.Startup.csproj +++ b/src/Startup/MUnique.OpenMU.Startup.csproj @@ -20,11 +20,11 @@ - + - + diff --git a/src/Web/AdminPanel/MUnique.OpenMU.Web.AdminPanel.csproj b/src/Web/AdminPanel/MUnique.OpenMU.Web.AdminPanel.csproj index 2a12b3602..aab70e69a 100644 --- a/src/Web/AdminPanel/MUnique.OpenMU.Web.AdminPanel.csproj +++ b/src/Web/AdminPanel/MUnique.OpenMU.Web.AdminPanel.csproj @@ -40,7 +40,7 @@ - + diff --git a/src/Web/ItemEditor/MUnique.OpenMU.Web.ItemEditor.csproj b/src/Web/ItemEditor/MUnique.OpenMU.Web.ItemEditor.csproj index e7a0d8f19..366e687c7 100644 --- a/src/Web/ItemEditor/MUnique.OpenMU.Web.ItemEditor.csproj +++ b/src/Web/ItemEditor/MUnique.OpenMU.Web.ItemEditor.csproj @@ -22,7 +22,7 @@ - + diff --git a/src/Web/Map/MUnique.OpenMU.Web.Map.csproj b/src/Web/Map/MUnique.OpenMU.Web.Map.csproj index b751e59ea..2bf68c338 100644 --- a/src/Web/Map/MUnique.OpenMU.Web.Map.csproj +++ b/src/Web/Map/MUnique.OpenMU.Web.Map.csproj @@ -24,7 +24,7 @@ The CI environment is identified by the parameter 'ci'. It's set in the azure pipelines and Dockerfile. If you run into errors here under Linux/Mac OS, it might help to add this parameter, too. --> - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/tests/MUnique.OpenMU.AttributeSystem.Tests/MUnique.OpenMU.AttributeSystem.Tests.csproj b/tests/MUnique.OpenMU.AttributeSystem.Tests/MUnique.OpenMU.AttributeSystem.Tests.csproj index 14a95ae65..7e159c2f9 100644 --- a/tests/MUnique.OpenMU.AttributeSystem.Tests/MUnique.OpenMU.AttributeSystem.Tests.csproj +++ b/tests/MUnique.OpenMU.AttributeSystem.Tests/MUnique.OpenMU.AttributeSystem.Tests.csproj @@ -32,7 +32,7 @@ - + diff --git a/tests/MUnique.OpenMU.ChatServer.Tests/MUnique.OpenMU.ChatServer.Tests.csproj b/tests/MUnique.OpenMU.ChatServer.Tests/MUnique.OpenMU.ChatServer.Tests.csproj index 7e8515127..1a3361860 100644 --- a/tests/MUnique.OpenMU.ChatServer.Tests/MUnique.OpenMU.ChatServer.Tests.csproj +++ b/tests/MUnique.OpenMU.ChatServer.Tests/MUnique.OpenMU.ChatServer.Tests.csproj @@ -32,7 +32,7 @@ - + diff --git a/tests/MUnique.OpenMU.Network.Benchmarks/MUnique.OpenMU.Network.Benchmarks.csproj b/tests/MUnique.OpenMU.Network.Benchmarks/MUnique.OpenMU.Network.Benchmarks.csproj index 6341fe4da..9a7c3105d 100644 --- a/tests/MUnique.OpenMU.Network.Benchmarks/MUnique.OpenMU.Network.Benchmarks.csproj +++ b/tests/MUnique.OpenMU.Network.Benchmarks/MUnique.OpenMU.Network.Benchmarks.csproj @@ -35,7 +35,7 @@ - + diff --git a/tests/MUnique.OpenMU.Network.Tests/MUnique.OpenMU.Network.Tests.csproj b/tests/MUnique.OpenMU.Network.Tests/MUnique.OpenMU.Network.Tests.csproj index 14099983c..ad2a1aa5b 100644 --- a/tests/MUnique.OpenMU.Network.Tests/MUnique.OpenMU.Network.Tests.csproj +++ b/tests/MUnique.OpenMU.Network.Tests/MUnique.OpenMU.Network.Tests.csproj @@ -31,7 +31,7 @@ - + diff --git a/tests/MUnique.OpenMU.Pathfinding.Tests/MUnique.OpenMU.Pathfinding.Tests.csproj b/tests/MUnique.OpenMU.Pathfinding.Tests/MUnique.OpenMU.Pathfinding.Tests.csproj index 0d1a9c12f..73095edf9 100644 --- a/tests/MUnique.OpenMU.Pathfinding.Tests/MUnique.OpenMU.Pathfinding.Tests.csproj +++ b/tests/MUnique.OpenMU.Pathfinding.Tests/MUnique.OpenMU.Pathfinding.Tests.csproj @@ -31,7 +31,7 @@ - + diff --git a/tests/MUnique.OpenMU.Persistence.Initialization.Tests/MUnique.OpenMU.Persistence.Initialization.Tests.csproj b/tests/MUnique.OpenMU.Persistence.Initialization.Tests/MUnique.OpenMU.Persistence.Initialization.Tests.csproj index 6d5955aa1..074eba241 100644 --- a/tests/MUnique.OpenMU.Persistence.Initialization.Tests/MUnique.OpenMU.Persistence.Initialization.Tests.csproj +++ b/tests/MUnique.OpenMU.Persistence.Initialization.Tests/MUnique.OpenMU.Persistence.Initialization.Tests.csproj @@ -38,7 +38,7 @@ - + diff --git a/tests/MUnique.OpenMU.PlugIns.Tests/MUnique.OpenMU.PlugIns.Tests.csproj b/tests/MUnique.OpenMU.PlugIns.Tests/MUnique.OpenMU.PlugIns.Tests.csproj index 331cc96c3..3f708e4f2 100644 --- a/tests/MUnique.OpenMU.PlugIns.Tests/MUnique.OpenMU.PlugIns.Tests.csproj +++ b/tests/MUnique.OpenMU.PlugIns.Tests/MUnique.OpenMU.PlugIns.Tests.csproj @@ -34,7 +34,7 @@ - + diff --git a/tests/MUnique.OpenMU.Tests/MUnique.OpenMU.Tests.csproj b/tests/MUnique.OpenMU.Tests/MUnique.OpenMU.Tests.csproj index b8b7344b2..bef5e8ec0 100644 --- a/tests/MUnique.OpenMU.Tests/MUnique.OpenMU.Tests.csproj +++ b/tests/MUnique.OpenMU.Tests/MUnique.OpenMU.Tests.csproj @@ -32,7 +32,7 @@ - +