More group work. Added packet operations to the world server so it can send global group info.

This commit is contained in:
Filip Maj 2016-12-15 12:19:44 -05:00
parent 6c409e93a9
commit 1148619ca5
30 changed files with 1173 additions and 43 deletions

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_World_Server.Actor.Group.Work
{
class ContentWork
{
public GroupGlobalTemp _globalTemp = new GroupGlobalTemp();
}
}

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_World_Server.Actor.Group.Work
{
class GroupGlobalSave
{
public ulong master;
public ushort[] crestIcon = new ushort[4];
public byte rank = 1;
}
}

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_World_Server.Actor.Group.Work
{
class GroupGlobalTemp
{
public ulong owner;
//For content group
public ulong director;
//For relation group
public ulong host;
public uint variableCommand;
}
}

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_World_Server.Actor.Group.Work
{
class GroupMemberSave
{
//For LS
public byte rank;
//For Retainers
public byte cdIDOffset;
public ushort placeName;
public byte conditions;
public byte level;
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_World_Server.Actor.Group.Work
{
class LinkshellWork
{
public GroupGlobalSave _globalSave = new GroupGlobalSave();
public GroupMemberSave[] _memberSave = new GroupMemberSave[128];
}
}

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_World_Server.Actor.Group.Work
{
class PartyWork
{
public GroupGlobalTemp _globalTemp = new GroupGlobalTemp();
}
}

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_World_Server.Actor.Group.Work
{
class RelationWork
{
public GroupGlobalTemp _globalTemp = new GroupGlobalTemp();
}
}

View File

@ -0,0 +1,8 @@

namespace FFXIVClassic_World_Server.Actor.Group.Work
{
class RetainerWork
{
public GroupMemberSave[] _memberSave = new GroupMemberSave[128];
}
}

View File

@ -1,18 +1,79 @@
using System; using FFXIVClassic.Common;
using FFXIVClassic_World_Server.Packets.Send.Subpackets.Groups;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_World_Server.DataObjects.Group namespace FFXIVClassic_World_Server.DataObjects.Group
{ {
class Group class Group
{ {
public const uint PlayerPartyGroup = 10001;
public const uint CompanyGroup = 20001;
public const uint GroupInvitationRelationGroup = 50001;
public const uint TradeRelationGroup = 50002;
public const uint BazaarBuyItemRelationGroup = 50009;
public const uint RetainerGroup = 80001;
public readonly ulong groupIndex; public readonly ulong groupIndex;
public Group(ulong groupIndex) public Group(ulong groupIndex)
{ {
this.groupIndex = groupIndex; this.groupIndex = groupIndex;
} }
public virtual int GetMemberCount()
{
return 0;
}
public virtual uint GetTypeId()
{
return 0;
}
public virtual string GetGroupName()
{
return "";
}
public virtual int GetGroupLocalizedName()
{
return -1;
}
public virtual List<GroupMember> BuildMemberList()
{
return new List<GroupMember>();
}
public void SendGroupPackets(Session session)
{
ulong time = Utils.MilisUnixTimeStampUTC();
List<GroupMember> members = BuildMemberList();
session.clientConnection.QueuePacket(GroupHeaderPacket.buildPacket(session.sessionId, session.currentZoneId, time, this), true, false);
session.clientConnection.QueuePacket(GroupMembersBeginPacket.buildPacket(session.sessionId, session.currentZoneId, time, this), true, false);
int currentIndex = 0;
while (true)
{
if (GetMemberCount() - currentIndex >= 64)
session.clientConnection.QueuePacket(GroupMembersX64Packet.buildPacket(session.sessionId, session.currentZoneId, time, members, ref currentIndex), true, false);
else if (GetMemberCount() - currentIndex >= 32)
session.clientConnection.QueuePacket(GroupMembersX32Packet.buildPacket(session.sessionId, session.currentZoneId, time, members, ref currentIndex), true, false);
else if (GetMemberCount() - currentIndex >= 16)
session.clientConnection.QueuePacket(GroupMembersX16Packet.buildPacket(session.sessionId, session.currentZoneId, time, members, ref currentIndex), true, false);
else if (GetMemberCount() - currentIndex > 0)
session.clientConnection.QueuePacket(GroupMembersX08Packet.buildPacket(session.sessionId, session.currentZoneId, time, members, ref currentIndex), true, false);
else
break;
}
session.clientConnection.QueuePacket(GroupMembersEndPacket.buildPacket(session.sessionId, session.currentZoneId, time, this), true, false);
}
} }
} }

View File

@ -1,8 +1,10 @@
using System; using FFXIVClassic_World_Server.Actor.Group.Work;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using FFXIVClassic_World_Server.Packets.Send.Subpackets.Groups;
namespace FFXIVClassic_World_Server.DataObjects.Group namespace FFXIVClassic_World_Server.DataObjects.Group
{ {
@ -10,19 +12,63 @@ namespace FFXIVClassic_World_Server.DataObjects.Group
{ {
public ulong dbId; public ulong dbId;
public string name; public string name;
public ushort crestId;
public uint master; public LinkshellWork linkshellWork = new LinkshellWork();
public ushort rank;
public Dictionary<ulong, LinkshellMember> members = new Dictionary<ulong, LinkshellMember>(); public Dictionary<ulong, LinkshellMember> members = new Dictionary<ulong, LinkshellMember>();
public Linkshell(ulong dbId, ulong groupIndex, string name, ushort crestId, uint master, ushort rank) : base(groupIndex) public Linkshell(ulong dbId, ulong groupIndex, string name, ushort crestId, uint master, byte rank) : base(groupIndex)
{ {
this.dbId = dbId; this.dbId = dbId;
this.name = name; this.name = name;
this.crestId = crestId; linkshellWork._globalSave.crestIcon[0] = crestId;
this.master = master; linkshellWork._globalSave.master = master;
this.rank = rank; linkshellWork._globalSave.rank = rank;
}
public void setMaster(uint actorId)
{
linkshellWork._globalSave.master = (ulong)((0xB36F92 << 8) | actorId);
}
public void setCrest(ushort crestId)
{
linkshellWork._globalSave.crestIcon[0] = crestId;
}
public void setRank(byte rank = 1)
{
linkshellWork._globalSave.rank = rank;
}
public void setMemberRank(int index, byte rank)
{
if (members.Count >= index)
return;
linkshellWork._memberSave[index].rank = rank;
}
public override int GetMemberCount()
{
return members.Count;
}
public override string GetGroupName()
{
return name;
}
public override uint GetTypeId()
{
return Group.CompanyGroup;
}
public override List<GroupMember> BuildMemberList()
{
List<GroupMember> groupMembers = new List<GroupMember>();
foreach (LinkshellMember member in members.Values)
groupMembers.Add(new GroupMember(member.charaId, -1, 0, false, Server.GetServer().GetSession(member.charaId) != null, Server.GetServer().GetNameForId(member.charaId)));
return groupMembers;
} }
} }
} }

View File

@ -1,4 +1,6 @@
using System; using FFXIVClassic_World_Server.Actor.Group.Work;
using FFXIVClassic_World_Server.Packets.Send.Subpackets.Groups;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@ -8,12 +10,53 @@ namespace FFXIVClassic_World_Server.DataObjects.Group
{ {
class Party : Group class Party : Group
{ {
public uint leader; public PartyWork partyGroupWork = new PartyWork();
public List<uint> members = new List<uint>(); public List<uint> members = new List<uint>();
public Party(ulong groupId, uint leaderCharaId) : base(groupId) public Party(ulong groupId, uint leaderCharaId) : base(groupId)
{ {
this.leader = leaderCharaId; partyGroupWork._globalTemp.owner = (ulong)((0xB36F92 << 8) | leaderCharaId);
} }
public void SetLeader(uint actorId)
{
partyGroupWork._globalTemp.owner = (ulong)((0xB36F92 << 8) | actorId);
}
public uint GetLeader()
{
return (uint)(partyGroupWork._globalTemp.owner & 0xFFFFFF);
}
/*
public override void sendWorkValues(Session session)
{
SynchGroupWorkValuesPacket groupWork = new SynchGroupWorkValuesPacket(groupId);
groupWork.addProperty(this, "partyGroupWork._globalTemp.owner");
groupWork.setTarget("/_init");
SubPacket test = groupWork.buildPacket(session.sessionId, session.sessionId);
session.clientConnection.QueuePacket(test, true, false);
}
*/
public override int GetMemberCount()
{
return members.Count;
}
public override uint GetTypeId()
{
return Group.PlayerPartyGroup;
}
public override List<GroupMember> BuildMemberList()
{
List<GroupMember> groupMembers = new List<GroupMember>();
foreach (uint charaId in members)
groupMembers.Add(new GroupMember(charaId, -1, 0, false, Server.GetServer().GetSession(charaId) != null, Server.GetServer().GetNameForId(charaId)));
return groupMembers;
}
} }
} }

View File

@ -1,4 +1,5 @@
using System; using FFXIVClassic_World_Server.Packets.Send.Subpackets.Groups;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@ -17,5 +18,24 @@ namespace FFXIVClassic_World_Server.DataObjects.Group
this.charaOther = other; this.charaOther = other;
this.command = command; this.command = command;
} }
public override int GetMemberCount()
{
return 2;
}
public override uint GetTypeId()
{
return Group.GroupInvitationRelationGroup;
}
public override List<GroupMember> BuildMemberList()
{
List<GroupMember> groupMembers = new List<GroupMember>();
groupMembers.Add(new GroupMember(charaHost, -1, 0, false, Server.GetServer().GetSession(charaHost) != null, Server.GetServer().GetNameForId(charaHost)));
groupMembers.Add(new GroupMember(charaOther, -1, 0, false, Server.GetServer().GetSession(charaOther) != null, Server.GetServer().GetNameForId(charaOther)));
return groupMembers;
}
} }
} }

View File

@ -1,4 +1,6 @@
using System; using FFXIVClassic_World_Server.Actor.Group.Work;
using FFXIVClassic_World_Server.Packets.Send.Subpackets.Groups;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@ -8,6 +10,7 @@ namespace FFXIVClassic_World_Server.DataObjects.Group
{ {
class RetainerGroup : Group class RetainerGroup : Group
{ {
public RetainerWork work = new RetainerWork();
public uint owner; public uint owner;
public Dictionary<uint, RetainerGroupMember> members = new Dictionary<uint, RetainerGroupMember>(); public Dictionary<uint, RetainerGroupMember> members = new Dictionary<uint, RetainerGroupMember>();
@ -15,5 +18,48 @@ namespace FFXIVClassic_World_Server.DataObjects.Group
{ {
this.owner = owner; this.owner = owner;
} }
public void setRetainerProperties(int index, byte cdIDOffset, ushort placeName, byte condition, byte level)
{
if (members.Count >= index)
return;
work._memberSave[index].cdIDOffset = cdIDOffset;
work._memberSave[index].placeName = placeName;
work._memberSave[index].conditions = condition;
work._memberSave[index].level = level;
}
/*
public override void sendWorkValues(Session session)
{
SynchGroupWorkValuesPacket groupWork = new SynchGroupWorkValuesPacket(groupId);
groupWork.addProperty(this, "work._memberSave[0].cdIDOffset");
groupWork.addProperty(this, "work._memberSave[0].placeName");
groupWork.addProperty(this, "work._memberSave[0].conditions");
groupWork.addProperty(this, "work._memberSave[0].level");
groupWork.setTarget("/_init");
SubPacket test = groupWork.buildPacket(session.sessionId, session.sessionId);
session.clientConnection.QueuePacket(test, true, false);
}
*/
public override int GetMemberCount()
{
return members.Count;
}
public override uint GetTypeId()
{
return Group.RetainerGroup;
}
public override List<GroupMember> BuildMemberList()
{
List<GroupMember> groupMembers = new List<GroupMember>();
foreach (RetainerGroupMember member in members.Values)
groupMembers.Add(new GroupMember(member.retainerId, -1, 0, false, true, member.name));
return groupMembers;
}
} }
} }

View File

@ -8,5 +8,7 @@ namespace FFXIVClassic_World_Server.DataObjects.Group
{ {
class RetainerGroupMember class RetainerGroupMember
{ {
public uint retainerId;
public string name;
} }
} }

View File

@ -50,6 +50,35 @@ namespace FFXIVClassic_World_Server
return readIn; return readIn;
} }
public static void GetAllCharaNames(Dictionary<uint, string> mIdToNameMap)
{
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();
MySqlCommand cmd = new MySqlCommand("SELECT id, name FROM characters", conn);
using (MySqlDataReader Reader = cmd.ExecuteReader())
{
while (Reader.Read())
{
uint id = Reader.GetUInt32("id");
string name = Reader.GetString("name");
mIdToNameMap.Add(id, name);
}
}
}
catch (MySqlException e)
{
Program.Log.Error(e.ToString());
}
finally
{
conn.Dispose();
}
}
}
public static uint GetCurrentZoneForSession(uint charId) public static uint GetCurrentZoneForSession(uint charId)
{ {
uint currentZone = 0; uint currentZone = 0;

View File

@ -64,6 +64,20 @@
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Actor\Group\Group.cs" />
<Compile Include="Actor\Group\GroupInvitationRelationGroup.cs" />
<Compile Include="Actor\Group\GroupMember.cs" />
<Compile Include="Actor\Group\LinkshellGroup.cs" />
<Compile Include="Actor\Group\PartyGroup.cs" />
<Compile Include="Actor\Group\RetainerGroup.cs" />
<Compile Include="Actor\Group\Work\ContentWork.cs" />
<Compile Include="Actor\Group\Work\GroupGlobalSave.cs" />
<Compile Include="Actor\Group\Work\GroupGlobalTemp.cs" />
<Compile Include="Actor\Group\Work\GroupMemberSave.cs" />
<Compile Include="Actor\Group\Work\LinkshellWork.cs" />
<Compile Include="Actor\Group\Work\PartyWork.cs" />
<Compile Include="Actor\Group\Work\RelationWork.cs" />
<Compile Include="Actor\Group\Work\RetainerWork.cs" />
<Compile Include="ConfigConstants.cs" /> <Compile Include="ConfigConstants.cs" />
<Compile Include="Database.cs" /> <Compile Include="Database.cs" />
<Compile Include="DataObjects\ClientConnection.cs" /> <Compile Include="DataObjects\ClientConnection.cs" />
@ -79,6 +93,18 @@
<Compile Include="LinkshellManager.cs" /> <Compile Include="LinkshellManager.cs" />
<Compile Include="PacketProcessor.cs" /> <Compile Include="PacketProcessor.cs" />
<Compile Include="Packets\Receive\HelloPacket.cs" /> <Compile Include="Packets\Receive\HelloPacket.cs" />
<Compile Include="Packets\Send\Subpackets\Groups\CreateNamedGroup.cs" />
<Compile Include="Packets\Send\Subpackets\Groups\CreateNamedGroupMultiple.cs" />
<Compile Include="Packets\Send\Subpackets\Groups\DeleteGroupPacket.cs" />
<Compile Include="Packets\Send\Subpackets\Groups\GroupHeaderPacket.cs" />
<Compile Include="Packets\Send\Subpackets\Groups\GroupMember.cs" />
<Compile Include="Packets\Send\Subpackets\Groups\GroupMembersBeginPacket.cs" />
<Compile Include="Packets\Send\Subpackets\Groups\GroupMembersEndPacket.cs" />
<Compile Include="Packets\Send\Subpackets\Groups\GroupMembersX08Packet.cs" />
<Compile Include="Packets\Send\Subpackets\Groups\GroupMembersX16Packet.cs" />
<Compile Include="Packets\Send\Subpackets\Groups\GroupMembersX32Packet.cs" />
<Compile Include="Packets\Send\Subpackets\Groups\GroupMembersX64Packet.cs" />
<Compile Include="Packets\Send\Subpackets\Groups\SynchGroupWorkValuesPacket.cs" />
<Compile Include="Packets\Send\_0x2Packet.cs" /> <Compile Include="Packets\Send\_0x2Packet.cs" />
<Compile Include="Packets\Send\_0x7Packet.cs" /> <Compile Include="Packets\Send\_0x7Packet.cs" />
<Compile Include="Packets\Send\_0x8PingPacket.cs" /> <Compile Include="Packets\Send\_0x8PingPacket.cs" />

View File

@ -0,0 +1,41 @@
using FFXIVClassic.Common;
using FFXIVClassic_World_Server.Actor.Group;
using FFXIVClassic_World_Server.DataObjects.Group;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_World_Server.Packets.Send.Subpackets.Groups
{
class CreateNamedGroup
{
public const ushort OPCODE = 0x0188;
public const uint PACKET_SIZE = 0x60;
public static SubPacket buildPacket(uint sessionId, Group group)
{
byte[] data = new byte[PACKET_SIZE - 0x20];
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
binWriter.Write((UInt64)group.groupIndex);
binWriter.Write((UInt32)group.GetTypeId());
binWriter.Write((Int32)group.GetGroupLocalizedName());
binWriter.Write((UInt16)0x121C);
binWriter.Seek(0x20, SeekOrigin.Begin);
binWriter.Write(Encoding.ASCII.GetBytes(group.GetGroupName()), 0, Encoding.ASCII.GetByteCount(group.GetGroupName()) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(group.GetGroupName()));
}
}
return new SubPacket(OPCODE, sessionId, sessionId, data);
}
}
}

View File

@ -0,0 +1,55 @@
using FFXIVClassic.Common;
using FFXIVClassic_World_Server.Actor.Group;
using FFXIVClassic_World_Server.DataObjects.Group;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_World_Server.Packets.Send.Subpackets.Groups
{
class CreateNamedGroupMultiple
{
public const ushort OPCODE = 0x0189;
public const uint PACKET_SIZE = 0x228;
public static SubPacket buildPacket(uint playerActorID, Group[] groups, ref int offset)
{
byte[] data = new byte[PACKET_SIZE - 0x20];
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
int max = 8;
if (groups.Length - offset <= 8)
max = groups.Length - offset;
for (int i = 0; i < max; i++)
{
binWriter.Seek(i * 0x40, SeekOrigin.Begin);
Group group = groups[offset+i];
binWriter.Write((UInt64)group.groupIndex);
binWriter.Write((UInt32)group.GetTypeId());
binWriter.Write((Int32)group.GetGroupLocalizedName());
binWriter.Write((UInt16)0x121C);
binWriter.Seek(0x20, SeekOrigin.Begin);
binWriter.Write(Encoding.ASCII.GetBytes(group.GetGroupName()), 0, Encoding.ASCII.GetByteCount(group.GetGroupName()) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(group.GetGroupName()));
}
binWriter.Seek(0x200, SeekOrigin.Begin);
binWriter.Write((Byte)max);
}
}
return new SubPacket(OPCODE, playerActorID, playerActorID, data);
}
}
}

View File

@ -0,0 +1,44 @@
using FFXIVClassic.Common;
using FFXIVClassic_World_Server.Actor.Group;
using FFXIVClassic_World_Server.DataObjects.Group;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_World_Server.Packets.Send.Subpackets.Groups
{
class DeleteGroupPacket
{
public const ushort OPCODE = 0x0143;
public const uint PACKET_SIZE = 0x40;
public static SubPacket buildPacket(uint sessionId, Group group)
{
return buildPacket(sessionId, group.groupIndex);
}
public static SubPacket buildPacket(uint sessionId, 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, sessionId, sessionId, data);
}
}
}

View File

@ -0,0 +1,61 @@
using FFXIVClassic.Common;
using FFXIVClassic_World_Server.DataObjects.Group;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_World_Server.Packets.Send.Subpackets.Groups
{
class GroupHeaderPacket
{
public const uint TYPEID_RETAINER = 0x13881;
public const uint TYPEID_PARTY = 0x2711;
public const uint TYPEID_LINKSHELL = 0x4E22;
public const ushort OPCODE = 0x017C;
public const uint PACKET_SIZE = 0x98;
public static SubPacket buildPacket(uint playerActorID, uint locationCode, ulong sequenceId, Group group)
{
byte[] data = new byte[PACKET_SIZE - 0x20];
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
//Write list header
binWriter.Write((UInt64)locationCode);
binWriter.Write((UInt64)sequenceId);
//Write list id
binWriter.Write((UInt64)3);
binWriter.Write((UInt64)group.groupIndex);
binWriter.Write((UInt64)0);
binWriter.Write((UInt64)group.groupIndex);
//This seems to change depending on what the list is for
binWriter.Write((UInt32)group.GetTypeId());
binWriter.Seek(0x40, SeekOrigin.Begin);
//This is for Linkshell
binWriter.Write((UInt32)group.GetGroupLocalizedName());
binWriter.Write(Encoding.ASCII.GetBytes(group.GetGroupName()), 0, Encoding.ASCII.GetByteCount(group.GetGroupName()) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(group.GetGroupName()));
binWriter.Seek(0x64, SeekOrigin.Begin);
binWriter.Write((UInt32)0x6D);
binWriter.Write((UInt32)0x6D);
binWriter.Write((UInt32)0x6D);
binWriter.Write((UInt32)0x6D);
binWriter.Write((UInt32)group.GetMemberCount());
}
}
return new SubPacket(OPCODE, playerActorID, playerActorID, data);
}
}
}

View File

@ -0,0 +1,24 @@
using FFXIVClassic.Common;
namespace FFXIVClassic_World_Server.Packets.Send.Subpackets.Groups
{
class GroupMember
{
public uint actorId;
public int localizedName;
public uint unknown2;
public bool flag1;
public bool isOnline;
public string name;
public GroupMember(uint actorId, int localizedName, uint unknown2, bool flag1, bool isOnline, string name)
{
this.actorId = actorId;
this.localizedName = localizedName;
this.unknown2 = unknown2;
this.flag1 = flag1;
this.isOnline = isOnline;
this.name = name;
}
}
}

View File

@ -0,0 +1,37 @@
using FFXIVClassic.Common;
using FFXIVClassic_World_Server.DataObjects.Group;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_World_Server.Packets.Send.Subpackets.Groups
{
class GroupMembersBeginPacket
{
public const ushort OPCODE = 0x017D;
public const uint PACKET_SIZE = 0x40;
public static SubPacket buildPacket(uint playerActorID, uint locationCode, ulong sequenceId, Group group)
{
byte[] data = new byte[PACKET_SIZE - 0x20];
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
//Write List Header
binWriter.Write((UInt64)locationCode);
binWriter.Write((UInt64)sequenceId);
//Write List Info
binWriter.Write((UInt64)group.groupIndex);
binWriter.Write((UInt32)group.GetMemberCount());
}
}
return new SubPacket(OPCODE, playerActorID, playerActorID, data);
}
}
}

View File

@ -0,0 +1,38 @@
using FFXIVClassic.Common;
using FFXIVClassic_World_Server.Actor.Group;
using FFXIVClassic_World_Server.DataObjects.Group;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_World_Server.Packets.Send.Subpackets.Groups
{
class GroupMembersEndPacket
{
public const ushort OPCODE = 0x017E;
public const uint PACKET_SIZE = 0x38;
public static SubPacket buildPacket(uint sessionId, uint locationCode, ulong sequenceId, Group group)
{
byte[] data = new byte[PACKET_SIZE - 0x20];
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
//Write List Header
binWriter.Write((UInt64)locationCode);
binWriter.Write((UInt64)sequenceId);
//Write List Info
binWriter.Write((UInt64)group.groupIndex);
}
}
return new SubPacket(OPCODE, sessionId, sessionId, data);
}
}
}

View File

@ -0,0 +1,54 @@
using FFXIVClassic.Common;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_World_Server.Packets.Send.Subpackets.Groups
{
class GroupMembersX08Packet
{
public const ushort OPCODE = 0x017F;
public const uint PACKET_SIZE = 0x1B8;
public static SubPacket buildPacket(uint playerActorID, uint locationCode, ulong sequenceId, List<GroupMember> entries, ref int offset)
{
byte[] data = new byte[PACKET_SIZE - 0x20];
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
//Write List Header
binWriter.Write((UInt64)locationCode);
binWriter.Write((UInt64)sequenceId);
//Write Entries
int max = 8;
if (entries.Count-offset < 8)
max = entries.Count - offset;
for (int i = 0; i < max; i++)
{
binWriter.Seek(0x10 + (0x30 * i), SeekOrigin.Begin);
GroupMember entry = entries[i];
binWriter.Write((UInt32)entry.actorId);
binWriter.Write((Int32)entry.localizedName);
binWriter.Write((UInt32)entry.unknown2);
binWriter.Write((Byte)(entry.flag1? 1 : 0));
binWriter.Write((Byte)(entry.isOnline? 1 : 0));
binWriter.Write(Encoding.ASCII.GetBytes(entry.name), 0, Encoding.ASCII.GetByteCount(entry.name) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(entry.name));
offset++;
}
//Write Count
binWriter.Seek(0x10 + (0x30 * 8), SeekOrigin.Begin);
binWriter.Write(max);
}
}
return new SubPacket(OPCODE, playerActorID, playerActorID, data);
}
}
}

View File

@ -0,0 +1,51 @@
using FFXIVClassic.Common;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_World_Server.Packets.Send.Subpackets.Groups
{
class GroupMembersX16Packet
{
public const ushort OPCODE = 0x0180;
public const uint PACKET_SIZE = 0x330;
public static SubPacket buildPacket(uint playerActorID, uint locationCode, ulong sequenceId, List<GroupMember> entries, ref int offset)
{
byte[] data = new byte[PACKET_SIZE - 0x20];
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
//Write List Header
binWriter.Write((UInt64)locationCode);
binWriter.Write((UInt64)sequenceId);
//Write Entries
int max = 16;
if (entries.Count-offset < 16)
max = entries.Count - offset;
for (int i = 0; i < max; i++)
{
binWriter.Seek(0x10 + (0x30 * i), SeekOrigin.Begin);
GroupMember entry = entries[i];
binWriter.Write((UInt32)entry.actorId);
binWriter.Write((Int32)entry.localizedName);
binWriter.Write((UInt32)entry.unknown2);
binWriter.Write((Byte)(entry.flag1? 1 : 0));
binWriter.Write((Byte)(entry.isOnline? 1 : 0));
binWriter.Write(Encoding.ASCII.GetBytes(entry.name), 0, Encoding.ASCII.GetByteCount(entry.name) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(entry.name));
offset++;
}
}
}
return new SubPacket(OPCODE, playerActorID, playerActorID, data);
}
}
}

View File

@ -0,0 +1,51 @@
using FFXIVClassic.Common;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_World_Server.Packets.Send.Subpackets.Groups
{
class GroupMembersX32Packet
{
public const ushort OPCODE = 0x0181;
public const uint PACKET_SIZE = 0x630;
public static SubPacket buildPacket(uint playerActorID, uint locationCode, ulong sequenceId, List<GroupMember> entries, ref int offset)
{
byte[] data = new byte[PACKET_SIZE - 0x20];
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
//Write List Header
binWriter.Write((UInt64)locationCode);
binWriter.Write((UInt64)sequenceId);
//Write Entries
int max = 32;
if (entries.Count-offset < 32)
max = entries.Count - offset;
for (int i = 0; i < max; i++)
{
binWriter.Seek(0x10 + (0x30 * i), SeekOrigin.Begin);
GroupMember entry = entries[i];
binWriter.Write((UInt32)entry.actorId);
binWriter.Write((Int32)entry.localizedName);
binWriter.Write((UInt32)entry.unknown2);
binWriter.Write((Byte)(entry.flag1? 1 : 0));
binWriter.Write((Byte)(entry.isOnline? 1 : 0));
binWriter.Write(Encoding.ASCII.GetBytes(entry.name), 0, Encoding.ASCII.GetByteCount(entry.name) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(entry.name));
offset++;
}
}
}
return new SubPacket(OPCODE, playerActorID, playerActorID, data);
}
}
}

View File

@ -0,0 +1,51 @@
using FFXIVClassic.Common;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_World_Server.Packets.Send.Subpackets.Groups
{
class GroupMembersX64Packet
{
public const ushort OPCODE = 0x0182;
public const uint PACKET_SIZE = 0xC30;
public static SubPacket buildPacket(uint playerActorID, uint locationCode, ulong sequenceId, List<GroupMember> entries, ref int offset)
{
byte[] data = new byte[PACKET_SIZE - 0x20];
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
//Write List Header
binWriter.Write((UInt64)locationCode);
binWriter.Write((UInt64)sequenceId);
//Write Entries
int max = 64;
if (entries.Count - offset < 64)
max = entries.Count - offset;
for (int i = 0; i < max; i++)
{
binWriter.Seek(0x10 + (0x30 * i), SeekOrigin.Begin);
GroupMember entry = entries[i];
binWriter.Write((UInt32)entry.actorId);
binWriter.Write((Int32)entry.localizedName);
binWriter.Write((UInt32)entry.unknown2);
binWriter.Write((Byte)(entry.flag1? 1 : 0));
binWriter.Write((Byte)(entry.isOnline? 1 : 0));
binWriter.Write(Encoding.ASCII.GetBytes(entry.name), 0, Encoding.ASCII.GetByteCount(entry.name) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(entry.name));
offset++;
}
}
}
return new SubPacket(OPCODE, playerActorID, playerActorID, data);
}
}
}

View File

@ -0,0 +1,211 @@
using FFXIVClassic.Common;
using FFXIVClassic_World_Server.Actor.Group;
using FFXIVClassic_World_Server.DataObjects.Group;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_World_Server.Packets.Send.Subpackets.Groups
{
class SynchGroupWorkValuesPacket
{
public const ushort OPCODE = 0x017A;
public const uint PACKET_SIZE = 0xB0;
private const ushort MAXBYTES = 0x98;
private ushort runningByteTotal = 0;
private byte[] data = new byte[PACKET_SIZE - 0x20];
private bool isMore = false;
private MemoryStream mem;
private BinaryWriter binWriter;
public SynchGroupWorkValuesPacket(ulong listId)
{
mem = new MemoryStream(data);
binWriter = new BinaryWriter(mem);
binWriter.Write((UInt64)listId);
binWriter.Seek(1, SeekOrigin.Current);
}
public void closeStreams()
{
binWriter.Dispose();
mem.Dispose();
}
public bool addByte(uint id, byte value)
{
if (runningByteTotal + 6 > MAXBYTES)
return false;
binWriter.Write((byte)1);
binWriter.Write((UInt32)id);
binWriter.Write((byte)value);
runningByteTotal += 6;
return true;
}
public bool addShort(uint id, ushort value)
{
if (runningByteTotal + 7 > MAXBYTES)
return false;
binWriter.Write((byte)2);
binWriter.Write((UInt32)id);
binWriter.Write((UInt16)value);
runningByteTotal += 7;
return true;
}
public bool addInt(uint id, uint value)
{
if (runningByteTotal + 9 > MAXBYTES)
return false;
binWriter.Write((byte)4);
binWriter.Write((UInt32)id);
binWriter.Write((UInt32)value);
runningByteTotal += 9;
return true;
}
public bool addLong(uint id, ulong value)
{
if (runningByteTotal + 13 > MAXBYTES)
return false;
binWriter.Write((byte)8);
binWriter.Write((UInt32)id);
binWriter.Write((UInt64)value);
runningByteTotal += 13;
return true;
}
public bool addBuffer(uint id, byte[] buffer)
{
if (runningByteTotal + 5 + buffer.Length > MAXBYTES)
return false;
binWriter.Write((byte)buffer.Length);
binWriter.Write((UInt32)id);
binWriter.Write(buffer);
runningByteTotal += (ushort)(5 + buffer.Length);
return true;
}
public void addProperty(Group group, string name)
{
string[] split = name.Split('.');
int arrayIndex = 0;
if (!(split[0].Equals("work") || split[0].Equals("partyGroupWork")))
return;
Object curObj = group;
for (int i = 0; i < split.Length; i++)
{
//For arrays
if (split[i].Contains('['))
{
if (split[i].LastIndexOf(']') - split[i].IndexOf('[') <= 0)
return;
arrayIndex = Convert.ToInt32(split[i].Substring(split[i].IndexOf('[') + 1, split[i].Length - split[i].LastIndexOf(']')));
split[i] = split[i].Substring(0, split[i].IndexOf('['));
if (i != split.Length - 1)
{
curObj = curObj.GetType().GetField(split[i]).GetValue(curObj);
curObj = ((Array)curObj).GetValue(arrayIndex);
i++;
}
}
FieldInfo field = curObj.GetType().GetField(split[i]);
if (field == null)
return;
curObj = field.GetValue(curObj);
if (curObj == null)
return;
}
if (curObj == null)
return;
else
{
//Array, we actually care whats inside
if (curObj.GetType().IsArray)
{
if (((Array)curObj).Length <= arrayIndex)
return;
curObj = ((Array)curObj).GetValue(arrayIndex);
}
if (curObj == null)
return;
//Cast to the proper object and add to packet
uint id = Utils.MurmurHash2(name, 0);
if (curObj is bool)
addByte(id, (byte)(((bool)curObj) ? 1 : 0));
else if (curObj is byte)
addByte(id, (byte)curObj);
else if (curObj is ushort)
addShort(id, (ushort)curObj);
else if (curObj is short)
addShort(id, (ushort)(short)curObj);
else if (curObj is uint)
addInt(id, (uint)curObj);
else if (curObj is int)
addInt(id, (uint)(int)curObj);
else if (curObj is long)
addLong(id, (ulong)(long)curObj);
else if (curObj is ulong)
addLong(id, (ulong)curObj);
else if (curObj is float)
addBuffer(id, BitConverter.GetBytes((float)curObj));
else
return;
}
}
public void setIsMore(bool flag)
{
isMore = flag;
}
public void setTarget(string target)
{
binWriter.Write((byte)(isMore ? 0x62 + target.Length : 0x82 + target.Length));
binWriter.Write(Encoding.ASCII.GetBytes(target));
runningByteTotal += (ushort)(1 + Encoding.ASCII.GetByteCount(target));
}
public SubPacket buildPacket(uint playerActorID, uint actorID)
{
binWriter.Seek(0x8, SeekOrigin.Begin);
binWriter.Write((byte)runningByteTotal);
closeStreams();
SubPacket packet = new SubPacket(OPCODE, playerActorID, actorID, data);
return packet;
}
}
}

View File

@ -60,8 +60,8 @@ namespace FFXIVClassic_World_Server
party.members.Remove(charaId); party.members.Remove(charaId);
//If current ldr, make a new ldr if not empty pt //If current ldr, make a new ldr if not empty pt
if (party.leader == charaId && party.members.Count != 0) if (party.GetLeader() == charaId && party.members.Count != 0)
party.leader = party.members[0]; party.SetLeader(party.members[0]);
} }
return party.members.Count; return party.members.Count;
} }
@ -75,7 +75,7 @@ namespace FFXIVClassic_World_Server
Party party = mPartyList[groupId]; Party party = mPartyList[groupId];
if (party.members.Contains(charaId)) if (party.members.Contains(charaId))
{ {
party.leader = charaId; party.SetLeader(charaId);
return true; return true;
} }
} }

View File

@ -17,14 +17,16 @@ namespace FFXIVClassic_World_Server
public const int BACKLOG = 100; public const int BACKLOG = 100;
private static Server mSelf; private static Server mSelf;
//Connection and Session Management //Connections
private Socket mServerSocket; private Socket mServerSocket;
WorldManager mWorldManager; WorldManager mWorldManager;
PacketProcessor mPacketProcessor; PacketProcessor mPacketProcessor;
private List<ClientConnection> mConnectionList = new List<ClientConnection>(); //Preloaded Maps
private Dictionary<uint, string> mIdToNameMap = new Dictionary<uint, string>();
//Session Management
private List<ClientConnection> mConnectionList = new List<ClientConnection>();
private Dictionary<uint, Session> mZoneSessionList = new Dictionary<uint, Session>(); private Dictionary<uint, Session> mZoneSessionList = new Dictionary<uint, Session>();
private Dictionary<uint, Session> mChatSessionList = new Dictionary<uint, Session>(); private Dictionary<uint, Session> mChatSessionList = new Dictionary<uint, Session>();
@ -102,13 +104,17 @@ namespace FFXIVClassic_World_Server
switch (type) switch (type)
{ {
case Session.Channel.ZONE: case Session.Channel.ZONE:
//New character since world server loaded
if (!mIdToNameMap.ContainsKey(id))
AddNameToMap(id, session.characterName);
if (!mZoneSessionList.ContainsKey(id)) if (!mZoneSessionList.ContainsKey(id))
mZoneSessionList.Add(id, session); mZoneSessionList.Add(id, session);
break; break;
case Session.Channel.CHAT: case Session.Channel.CHAT:
if (!mChatSessionList.ContainsKey(id)) if (!mChatSessionList.ContainsKey(id))
mChatSessionList.Add(id, session); mChatSessionList.Add(id, session);
break; break;
} }
} }
@ -376,6 +382,23 @@ namespace FFXIVClassic_World_Server
#endregion #endregion
public void LoadCharaNames()
{
Database.GetAllCharaNames(mIdToNameMap);
}
public void AddNameToMap(uint charaId, string name)
{
mIdToNameMap.Add(charaId, name);
}
public string GetNameForId(uint charaId)
{
if (mIdToNameMap.ContainsKey(charaId))
return mIdToNameMap[charaId];
return null;
}
private void SendGroupData(Session session, ulong groupId) private void SendGroupData(Session session, ulong groupId)
{ {
if (mCurrentWorldGroups.ContainsKey(groupId)) if (mCurrentWorldGroups.ContainsKey(groupId))