// // Licensed under the MIT License. See LICENSE file in the project root for full license information. // namespace MUnique.OpenMU.Persistence.Initialization.Updates; using System.Runtime.InteropServices; using MUnique.OpenMU.DataModel.Configuration; using MUnique.OpenMU.Persistence.Initialization.VersionSeasonSix.Maps; using MUnique.OpenMU.PlugIns; /// /// Adds the four imported maps Acheron (83), Debenter (84), Uruk (85) and Ferea (86): /// the map definitions with their terrain, a spawn gate and a /move warp each, and /// assigns each to the game server configuration so it is hosted and its spawns run. /// Monsters and NPCs are added afterwards via the admin panel. /// [PlugIn] [Display(Name = PlugInName, Description = PlugInDescription)] [Guid("3D9C1B72-7C3F-4E8B-AF14-E29D47A8B012")] public class AddImportedMapsUpdateSeason6 : UpdatePlugInBase { internal const string PlugInName = "Add imported maps (Acheron, Debenter, Uruk, Ferea)"; internal const string PlugInDescription = "Adds maps 83-86 (Acheron, Debenter, Uruk, Ferea) with terrain, spawn gate and /move warp, hosted by the game server. Monsters/NPCs are added via the admin panel."; /// public override UpdateVersion Version => UpdateVersion.AddImportedMapsSeason6; /// 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(2026, 07, 19, 15, 0, 0, DateTimeKind.Utc); /// protected override async ValueTask ApplyAsync(IContext context, GameConfiguration gameConfiguration) { var serverConfigs = (await context.GetAsync().ConfigureAwait(false)).ToList(); AddMap(context, gameConfiguration, serverConfigs, new Acheron(context, gameConfiguration), Acheron.Number, Acheron.Name, 84, 127, 126); AddMap(context, gameConfiguration, serverConfigs, new Debenter(context, gameConfiguration), Debenter.Number, Debenter.Name, 85, 132, 105); AddMap(context, gameConfiguration, serverConfigs, new Uruk(context, gameConfiguration), Uruk.Number, Uruk.Name, 86, 128, 128); AddMap(context, gameConfiguration, serverConfigs, new Ferea(context, gameConfiguration), Ferea.Number, Ferea.Name, 87, 128, 128); } private static void AddMap(IContext context, GameConfiguration gameConfiguration, IList serverConfigs, IMapInitializer initializer, byte number, string name, short warpIndex, byte x, byte y) { // Idempotency guard: skip if the map already exists. if (gameConfiguration.Maps.Any(m => m.Number == number)) { return; } initializer.Initialize(); // creates the map + loads terrain from Terrain{number+1}.att initializer.SetSafezoneMap(); var map = gameConfiguration.Maps.First(m => m.Number == number); // Spawn gate on a walkable tile. var spawnGate = context.CreateNew(); map.ExitGates.Add(spawnGate); spawnGate.Map = map; spawnGate.X1 = x; spawnGate.Y1 = y; spawnGate.X2 = x; spawnGate.Y2 = y; spawnGate.IsSpawnGate = true; // /move warp entry. if (gameConfiguration.WarpList.All(w => w.Name != name)) { var warp = context.CreateNew(); gameConfiguration.WarpList.Add(warp); warp.Index = warpIndex; warp.Name = name; warp.Costs = 5000; warp.LevelRequirement = 10; warp.Gate = spawnGate; } // Host the map on every game server configuration (fresh seeds do this // automatically, but existing databases need it added explicitly). foreach (var serverConfig in serverConfigs) { if (serverConfig.Maps.All(m => m.Number != number)) { serverConfig.Maps.Add(map); } } } }