diff --git a/FFXIVClassic Map Server/Database.cs b/FFXIVClassic Map Server/Database.cs
index 0bb01eb3..39a41099 100644
--- a/FFXIVClassic Map Server/Database.cs
+++ b/FFXIVClassic Map Server/Database.cs
@@ -1258,6 +1258,43 @@ namespace FFXIVClassic_Map_Server
return cheevosPacket.BuildPacket(player.actorId);
}
+ public static bool CreateLinkshell(Player player, string lsName, ushort lsCrest)
+ {
+ bool success = false;
+ using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD)))
+ {
+ try
+ {
+ conn.Open();
+
+ string query = @"
+ INSERT INTO server_linkshells
+ (name, master, crest)
+ VALUES
+ (@lsName, @master, @crest)
+ ;
+ ";
+
+ MySqlCommand cmd = new MySqlCommand(query, conn);
+ cmd.Parameters.AddWithValue("@lsName", lsName);
+ cmd.Parameters.AddWithValue("@master", player.actorId);
+ cmd.Parameters.AddWithValue("@crest", lsCrest);
+
+ cmd.ExecuteNonQuery();
+ success = true;
+ }
+ catch (MySqlException e)
+ {
+ Program.Log.Error(e.ToString());
+ }
+ finally
+ {
+ conn.Dispose();
+ }
+ }
+ return success;
+ }
}
+
}
diff --git a/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj b/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj
index bdc58e1d..057b64c3 100644
--- a/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj
+++ b/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj
@@ -201,6 +201,8 @@
+
+
@@ -208,6 +210,7 @@
+
diff --git a/FFXIVClassic Map Server/packets/send/Actor/_0xD8Packet.cs b/FFXIVClassic Map Server/packets/send/Actor/_0xD8Packet.cs
new file mode 100644
index 00000000..6753f7b6
--- /dev/null
+++ b/FFXIVClassic Map Server/packets/send/Actor/_0xD8Packet.cs
@@ -0,0 +1,29 @@
+using System.IO;
+
+using FFXIVClassic.Common;
+using System;
+
+namespace FFXIVClassic_Map_Server.packets.send.actor
+{
+ class _0xD8Packet
+ {
+ public const ushort OPCODE = 0x00D8;
+ public const uint PACKET_SIZE = 0x28;
+
+ public static SubPacket BuildPacket(uint playerActorID, uint targetActorID, uint val1, uint val2)
+ {
+ byte[] data = new byte[PACKET_SIZE - 0x20];
+
+ using (MemoryStream mem = new MemoryStream(data))
+ {
+ using (BinaryWriter binWriter = new BinaryWriter(mem))
+ {
+ binWriter.Write((UInt32)val1);
+ binWriter.Write((UInt32)val2);
+ }
+ }
+
+ return new SubPacket(OPCODE, playerActorID, targetActorID, data);
+ }
+ }
+}
diff --git a/FFXIVClassic Map Server/packets/send/Actor/_0xD9Packet.cs b/FFXIVClassic Map Server/packets/send/Actor/_0xD9Packet.cs
new file mode 100644
index 00000000..f5198508
--- /dev/null
+++ b/FFXIVClassic Map Server/packets/send/Actor/_0xD9Packet.cs
@@ -0,0 +1,29 @@
+using System.IO;
+
+using FFXIVClassic.Common;
+using System;
+using System.Text;
+
+namespace FFXIVClassic_Map_Server.packets.send.actor
+{
+ class _0xD9Packet
+ {
+ public const ushort OPCODE = 0x00D9;
+ public const uint PACKET_SIZE = 0x28;
+
+ public static SubPacket BuildPacket(uint playerActorID, uint targetActorID, string anim)
+ {
+ byte[] data = new byte[PACKET_SIZE - 0x20];
+
+ using (MemoryStream mem = new MemoryStream(data))
+ {
+ using (BinaryWriter binWriter = new BinaryWriter(mem))
+ {
+ binWriter.Write(Encoding.ASCII.GetBytes(anim), 0, Encoding.ASCII.GetByteCount(anim) >= 4 ? 4 : Encoding.ASCII.GetByteCount(anim));
+ }
+ }
+
+ return new SubPacket(OPCODE, playerActorID, targetActorID, data);
+ }
+ }
+}
diff --git a/FFXIVClassic Map Server/packets/send/groups/DeleteGroupPacket.cs b/FFXIVClassic Map Server/packets/send/groups/DeleteGroupPacket.cs
new file mode 100644
index 00000000..5e3b0c95
--- /dev/null
+++ b/FFXIVClassic Map Server/packets/send/groups/DeleteGroupPacket.cs
@@ -0,0 +1,43 @@
+using FFXIVClassic.Common;
+using FFXIVClassic_Map_Server.actors.group;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FFXIVClassic_Map_Server.packets.send.groups
+{
+ class DeleteGroupPacket
+ {
+ public const ushort OPCODE = 0x0143;
+ public const uint PACKET_SIZE = 0x40;
+
+ public static SubPacket buildPacket(uint playerActorID, Group group)
+ {
+ return buildPacket(playerActorID, group.groupId);
+ }
+
+ public static SubPacket buildPacket(uint playerActorID, ulong groupId)
+ {
+ byte[] data = new byte[PACKET_SIZE - 0x20];
+
+ using (MemoryStream mem = new MemoryStream(data))
+ {
+ using (BinaryWriter binWriter = new BinaryWriter(mem))
+ {
+ //Write control num ????
+ binWriter.Write((UInt64)3);
+
+ //Write Ids
+ binWriter.Write((UInt64)groupId);
+ binWriter.Write((UInt64)0);
+ binWriter.Write((UInt64)groupId);
+ }
+ }
+
+ return new SubPacket(OPCODE, playerActorID, playerActorID, data);
+ }
+ }
+}
diff --git a/FFXIVClassic World Server/WorldMaster.cs b/FFXIVClassic World Server/WorldMaster.cs
index 22ebd24a..b7c1d0bb 100644
--- a/FFXIVClassic World Server/WorldMaster.cs
+++ b/FFXIVClassic World Server/WorldMaster.cs
@@ -169,6 +169,10 @@ namespace FFXIVClassic_World_Server
public void DoZoneServerChange(Session session, uint destinationZoneId, string destinationPrivateArea, byte spawnType, float spawnX, float spawnY, float spawnZ, float spawnRotation)
{
ZoneServer zs = GetZoneServer(destinationZoneId);
+
+ if (zs == null)
+ return;
+
if (zs.isConnected)
session.routing1.SendSessionEnd(session, destinationZoneId, destinationPrivateArea, spawnType, spawnX, spawnY, spawnZ, spawnRotation);
else if (zs.Connect())