diff --git a/src/GameServer/MessageHandler/EnterMarketPlaceHandlerPlugIn.cs b/src/GameServer/MessageHandler/EnterMarketPlaceHandlerPlugIn.cs
new file mode 100644
index 000000000..0fa4c015d
--- /dev/null
+++ b/src/GameServer/MessageHandler/EnterMarketPlaceHandlerPlugIn.cs
@@ -0,0 +1,75 @@
+//
+// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+//
+
+namespace MUnique.OpenMU.GameServer.MessageHandler;
+
+using System.Runtime.InteropServices;
+using MUnique.OpenMU.DataModel.Configuration;
+using MUnique.OpenMU.GameLogic;
+using MUnique.OpenMU.GameServer.MessageHandler.MuHelper;
+using MUnique.OpenMU.Network.Packets.ClientToServer;
+using MUnique.OpenMU.PlugIns;
+
+///
+/// Handler for the , sent by the 'Warp' button of the
+/// Market Union Member Julia window. It warps the player between Lorencia and the Loren Market,
+/// depending on which side the player is currently on.
+///
+[PlugIn]
+[Display(Name = PlugInName, Description = PlugInDescription)]
+[Guid("5e028dcf-a5af-40a0-b958-2deb38aae4bc")]
+[BelongsToGroup(MuHelperGroupHandler.GroupKey)]
+internal class EnterMarketPlaceHandlerPlugIn : ISubPacketHandlerPlugIn
+{
+ private const string PlugInName = "Enter Market Place Handler";
+
+ private const string PlugInDescription = "Handler which warps a player between Lorencia and the Loren Market when using the 'Warp' button of Market Union Member Julia.";
+
+ ///
+ /// The map number of the Loren Market.
+ ///
+ private const short LorenMarketMapNumber = 79;
+
+ ///
+ /// The map number of Lorencia, where the player is warped back to.
+ ///
+ private const short LorenciaMapNumber = 0;
+
+ ///
+ public bool IsEncryptionExpected => false;
+
+ ///
+ public byte Key => EnterMarketPlaceRequest.SubCode;
+
+ ///
+ public async ValueTask HandlePacketAsync(Player player, Memory packet)
+ {
+ if (packet.Length < EnterMarketPlaceRequest.Length)
+ {
+ return;
+ }
+
+ // Only allow the warp through the actual Julia window, so a crafted packet can't be used
+ // as a free teleport from anywhere.
+ if (player.OpenedNpc?.Definition.NpcWindow != NpcWindow.JuliaWarpMarketServer)
+ {
+ return;
+ }
+
+ // Julia warps both ways: from the Loren Market back to Lorencia, and from anywhere else
+ // (her counterpart in Lorencia) into the Loren Market.
+ var targetMapNumber = player.CurrentMap?.Definition.Number == LorenMarketMapNumber
+ ? LorenciaMapNumber
+ : LorenMarketMapNumber;
+
+ var targetMap = await player.GameContext.GetMapAsync((ushort)targetMapNumber).ConfigureAwait(false);
+ if (targetMap?.SafeZoneSpawnGate is not { } targetGate)
+ {
+ return;
+ }
+
+ player.OpenedNpc = null;
+ await player.WarpToAsync(targetGate).ConfigureAwait(false);
+ }
+}
diff --git a/src/Persistence/Initialization/Updates/AddLorenMarketJuliaWarpPlugIn.cs b/src/Persistence/Initialization/Updates/AddLorenMarketJuliaWarpPlugIn.cs
new file mode 100644
index 000000000..42b494678
--- /dev/null
+++ b/src/Persistence/Initialization/Updates/AddLorenMarketJuliaWarpPlugIn.cs
@@ -0,0 +1,89 @@
+//
+// 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;
+
+///
+/// This update turns Market Union Member Julia (547) into a working warp NPC for the Loren Market,
+/// on both sides. It changes her NPC window so that talking to her opens the warp dialog instead of
+/// an empty merchant shop, and spawns a second instance of her in Lorencia, which is the entrance.
+///
+///
+/// The actual warp is performed server-side by the EnterMarketPlaceHandlerPlugIn when the
+/// player uses the 'Warp' button of the (client-side) Julia window.
+///
+[PlugIn]
+[Display(Name = PlugInName, Description = PlugInDescription)]
+[Guid("ed2f1728-b35c-4a3d-810e-eab5b6e12a82")]
+public class AddLorenMarketJuliaWarpPlugIn : UpdatePlugInBase
+{
+ ///
+ /// The plug in name.
+ ///
+ internal const string PlugInName = "Add Loren Market Julia warp";
+
+ ///
+ /// The plug in description.
+ ///
+ internal const string PlugInDescription = "Makes Market Union Member Julia (547) a working warp NPC between Lorencia and the Loren Market, on both sides, instead of an empty merchant.";
+
+ private const short JuliaNpcNumber = 547;
+
+ ///
+ public override UpdateVersion Version => UpdateVersion.AddLorenMarketJuliaWarp;
+
+ ///
+ public override string DataInitializationKey => VersionSeasonSix.DataInitialization.Id;
+
+ ///
+ public override string Name => PlugInName;
+
+ ///
+ public override string Description => PlugInDescription;
+
+ ///
+ public override bool IsMandatory => false;
+
+ ///
+ public override DateTime CreatedAt => new(2026, 06, 24, 0, 0, 0, DateTimeKind.Utc);
+
+ ///
+ protected override ValueTask ApplyAsync(IContext context, GameConfiguration gameConfiguration)
+ {
+ var julia = gameConfiguration.Monsters.FirstOrDefault(m => m.Number == JuliaNpcNumber);
+ if (julia is null)
+ {
+ return default;
+ }
+
+ julia.NpcWindow = NpcWindow.JuliaWarpMarketServer;
+ julia.MerchantStore = null;
+
+ var lorencia = gameConfiguration.Maps.FirstOrDefault(m => m.Number == Lorencia.Number);
+ if (lorencia is null
+ || lorencia.MonsterSpawns.Any(s => s.MonsterDefinition?.Number == JuliaNpcNumber))
+ {
+ return default;
+ }
+
+ var juliaSpawn = context.CreateNew();
+ lorencia.MonsterSpawns.Add(juliaSpawn);
+ juliaSpawn.SetGuid(JuliaNpcNumber);
+ juliaSpawn.GameMap = lorencia;
+ juliaSpawn.MonsterDefinition = julia;
+ juliaSpawn.SpawnTrigger = SpawnTrigger.Automatic;
+ juliaSpawn.Direction = Direction.SouthEast;
+ juliaSpawn.X1 = 139;
+ juliaSpawn.X2 = 139;
+ juliaSpawn.Y1 = 138;
+ juliaSpawn.Y2 = 138;
+
+ return default;
+ }
+}
diff --git a/src/Persistence/Initialization/Updates/UpdateVersion.cs b/src/Persistence/Initialization/Updates/UpdateVersion.cs
index 0fe9cd751..141dd17e1 100644
--- a/src/Persistence/Initialization/Updates/UpdateVersion.cs
+++ b/src/Persistence/Initialization/Updates/UpdateVersion.cs
@@ -439,4 +439,9 @@ public enum UpdateVersion
/// The version of the .
///
AddMovementSpeedAttributesSeason6 = 86,
+
+ ///
+ /// The version of the .
+ ///
+ AddLorenMarketJuliaWarp = 87,
}
diff --git a/src/Persistence/Initialization/VersionSeasonSix/Maps/Lorencia.cs b/src/Persistence/Initialization/VersionSeasonSix/Maps/Lorencia.cs
index 9d023a5d2..a2b498697 100644
--- a/src/Persistence/Initialization/VersionSeasonSix/Maps/Lorencia.cs
+++ b/src/Persistence/Initialization/VersionSeasonSix/Maps/Lorencia.cs
@@ -43,5 +43,6 @@ protected override IEnumerable CreateNpcSpawns()
yield return this.CreateMonsterSpawn(24, this.NpcDictionary[543], 141, 143, Direction.South);
yield return this.CreateMonsterSpawn(25, this.NpcDictionary[371], 130, 126, Direction.SouthEast);
yield return this.CreateMonsterSpawn(26, this.NpcDictionary[568], 131, 139, Direction.South, SpawnTrigger.Wandering); // Wandering Merchant Zyro
+ yield return this.CreateMonsterSpawn(27, this.NpcDictionary[547], 139, 138, Direction.SouthEast); // Market Union Member Julia (warps to the Loren Market)
}
}
\ No newline at end of file
diff --git a/src/Persistence/Initialization/VersionSeasonSix/NpcInitialization.cs b/src/Persistence/Initialization/VersionSeasonSix/NpcInitialization.cs
index b4bcefd2f..e285f87ac 100644
--- a/src/Persistence/Initialization/VersionSeasonSix/NpcInitialization.cs
+++ b/src/Persistence/Initialization/VersionSeasonSix/NpcInitialization.cs
@@ -958,7 +958,7 @@ public override void Initialize()
var def = this.Context.CreateNew();
def.Number = 547;
def.Designation = "Market Union Member Julia";
- def.NpcWindow = NpcWindow.Merchant;
+ def.NpcWindow = NpcWindow.JuliaWarpMarketServer;
def.ObjectKind = NpcObjectKind.PassiveNpc;
def.SetGuid(def.Number);
this.GameConfiguration.Monsters.Add(def);