Kicked/Promote leader added but broke login. D/Cing now.

This commit is contained in:
Filip Maj 2016-12-21 18:02:50 -05:00
parent e89b7557b3
commit 16c9b741bf
30 changed files with 1120 additions and 211 deletions

View File

@ -81,10 +81,9 @@
<Compile Include="actors\chara\player\Equipment.cs" /> <Compile Include="actors\chara\player\Equipment.cs" />
<Compile Include="actors\chara\player\Inventory.cs" /> <Compile Include="actors\chara\player\Inventory.cs" />
<Compile Include="actors\chara\Work.cs" /> <Compile Include="actors\chara\Work.cs" />
<Compile Include="actors\group\GroupInvitationRelationGroup.cs" /> <Compile Include="actors\group\Group.cs" />
<Compile Include="actors\group\LinkshellGroup.cs" /> <Compile Include="actors\group\Party.cs" />
<Compile Include="actors\group\PartyGroup.cs" /> <Compile Include="actors\group\Relation.cs" />
<Compile Include="actors\group\RetainerGroup.cs" />
<Compile Include="actors\group\work\ContentWork.cs" /> <Compile Include="actors\group\work\ContentWork.cs" />
<Compile Include="actors\debug\Debug.cs" /> <Compile Include="actors\debug\Debug.cs" />
<Compile Include="actors\director\Director.cs" /> <Compile Include="actors\director\Director.cs" />
@ -94,7 +93,6 @@
<Compile Include="actors\director\quest\QuestDirectorMan0u001.cs" /> <Compile Include="actors\director\quest\QuestDirectorMan0u001.cs" />
<Compile Include="actors\director\WeatherDirector.cs" /> <Compile Include="actors\director\WeatherDirector.cs" />
<Compile Include="actors\EventList.cs" /> <Compile Include="actors\EventList.cs" />
<Compile Include="actors\group\Group.cs" />
<Compile Include="actors\group\work\GroupGlobalSave.cs" /> <Compile Include="actors\group\work\GroupGlobalSave.cs" />
<Compile Include="actors\group\work\GroupGlobalTemp.cs" /> <Compile Include="actors\group\work\GroupGlobalTemp.cs" />
<Compile Include="actors\group\work\GroupMemberSave.cs" /> <Compile Include="actors\group\work\GroupMemberSave.cs" />
@ -288,6 +286,7 @@
<Compile Include="packets\WorldPackets\Send\Group\CreateLinkshellPacket.cs" /> <Compile Include="packets\WorldPackets\Send\Group\CreateLinkshellPacket.cs" />
<Compile Include="packets\WorldPackets\Send\Group\DeleteLinkshellPacket.cs" /> <Compile Include="packets\WorldPackets\Send\Group\DeleteLinkshellPacket.cs" />
<Compile Include="packets\WorldPackets\Send\Group\ModifyLinkshellPacket.cs" /> <Compile Include="packets\WorldPackets\Send\Group\ModifyLinkshellPacket.cs" />
<Compile Include="packets\WorldPackets\Send\Group\PartyModifyPacket.cs" />
<Compile Include="packets\WorldPackets\Send\SessionBeginConfirmPacket.cs" /> <Compile Include="packets\WorldPackets\Send\SessionBeginConfirmPacket.cs" />
<Compile Include="packets\WorldPackets\Send\SessionEndConfirmPacket.cs" /> <Compile Include="packets\WorldPackets\Send\SessionEndConfirmPacket.cs" />
<Compile Include="Program.cs" /> <Compile Include="Program.cs" />

View File

@ -248,7 +248,7 @@ namespace FFXIVClassic_Map_Server
break; break;
//Party Window Opened, Request State //Party Window Opened, Request State
case 0x01C5: case 0x01C5:
client.QueuePacket(BasePacket.CreatePacket(RecruiterStatePacket.BuildPacket(session.id, true, true, 1), true, false)); client.QueuePacket(BasePacket.CreatePacket(RecruiterStatePacket.BuildPacket(session.id, false, false, 0), true, false));
break; break;
//Search Recruiting //Search Recruiting
case 0x01C7: case 0x01C7:

View File

@ -33,6 +33,8 @@ namespace FFXIVClassic_Map_Server
private Dictionary<uint, ActorClass> actorClasses = new Dictionary<uint,ActorClass>(); private Dictionary<uint, ActorClass> actorClasses = new Dictionary<uint,ActorClass>();
private Dictionary<ulong, Party> currentPlayerParties = new Dictionary<ulong, Party>(); //GroupId, Party object private Dictionary<ulong, Party> currentPlayerParties = new Dictionary<ulong, Party>(); //GroupId, Party object
private Object groupLock = new Object();
private Server mServer; private Server mServer;
public WorldManager(Server server) public WorldManager(Server server)
@ -699,6 +701,8 @@ namespace FFXIVClassic_Map_Server
//World server sent a party member list synch packet to the zone server. Add and update players that may be a part of it. //World server sent a party member list synch packet to the zone server. Add and update players that may be a part of it.
public void PartyMemberListRecieved(PartySyncPacket syncPacket) public void PartyMemberListRecieved(PartySyncPacket syncPacket)
{
lock (currentPlayerParties)
{ {
Party group; Party group;
@ -717,11 +721,12 @@ namespace FFXIVClassic_Map_Server
else else
group = currentPlayerParties[syncPacket.partyGroupId]; group = currentPlayerParties[syncPacket.partyGroupId];
currentPlayerParties[syncPacket.partyGroupId].members = syncPacket.memberActorIds.ToList(); group.members = syncPacket.memberActorIds.ToList();
//Add group to everyone //Add group to everyone
foreach (uint member in currentPlayerParties[syncPacket.partyGroupId].members) for (int i = 0; i < group.members.Count; i++ )
{ {
uint member = group.members[i];
Session session = Server.GetServer().GetSession(member); Session session = Server.GetServer().GetSession(member);
if (session == null) if (session == null)
@ -733,6 +738,7 @@ namespace FFXIVClassic_Map_Server
player.SetParty(group); player.SetParty(group);
} }
} }
}
//Player was removed from the party either due to leaving it or leaving the server. Remove if empty. //Player was removed from the party either due to leaving it or leaving the server. Remove if empty.
public void NoMembersInParty(Party party) public void NoMembersInParty(Party party)

View File

@ -17,6 +17,7 @@ using FFXIVClassic_Map_Server.packets.receive.events;
using FFXIVClassic_Map_Server.packets.send.actor.inventory; using FFXIVClassic_Map_Server.packets.send.actor.inventory;
using FFXIVClassic_Map_Server.actors.group; using FFXIVClassic_Map_Server.actors.group;
using FFXIVClassic_Map_Server.packets.send.group; using FFXIVClassic_Map_Server.packets.send.group;
using FFXIVClassic_Map_Server.packets.WorldPackets.Send.Group;
namespace FFXIVClassic_Map_Server.Actors namespace FFXIVClassic_Map_Server.Actors
{ {
@ -1290,8 +1291,10 @@ namespace FFXIVClassic_Map_Server.Actors
return false; return false;
} }
public void PartyOustPlayer() public void PartyOustPlayer(string name)
{ {
SubPacket oustPacket = PartyModifyPacket.BuildPacket(playerSession, 1, name);
QueuePacket(oustPacket);
} }
public void PartyLeave() public void PartyLeave()
@ -1302,8 +1305,10 @@ namespace FFXIVClassic_Map_Server.Actors
{ {
} }
public void PartyPromote() public void PartyPromote(string name)
{ {
SubPacket promotePacket = PartyModifyPacket.BuildPacket(playerSession, 0, name);
QueuePacket(promotePacket);
} }
//A party member list packet came, set the party //A party member list packet came, set the party

View File

@ -20,14 +20,14 @@ namespace FFXIVClassic_Map_Server.actors.group
members.Add(leaderCharaId); members.Add(leaderCharaId);
} }
public void SetLeader(uint actorId) public void SetLeader(uint leaderCharaId)
{ {
partyGroupWork._globalTemp.owner = (ulong)((actorId << 32) | 0xB36F92); partyGroupWork._globalTemp.owner = (ulong)(((ulong)leaderCharaId << 32) | 0xB36F92);
} }
public uint GetLeader() public uint GetLeader()
{ {
return (uint)((partyGroupWork._globalTemp.owner >> 32) & 0xFFFFFFFF); return (uint)((ulong)(partyGroupWork._globalTemp.owner >> 32) & 0xFFFFFFFF);
} }
public bool IsInParty(uint charaId) public bool IsInParty(uint charaId)

View File

@ -25,11 +25,10 @@ namespace FFXIVClassic_Map_Server.packets.WorldPackets.Receive
try try
{ {
partyGroupId = binReader.ReadUInt64(); partyGroupId = binReader.ReadUInt64();
uint owner = binReader.ReadUInt32(); owner = binReader.ReadUInt32();
uint numMembers = binReader.ReadUInt32(); uint numMembers = binReader.ReadUInt32();
memberActorIds = new uint[numMembers]; memberActorIds = new uint[numMembers];
PartyGroup group = new PartyGroup(partyGroupId, owner);
for (int i = 0; i < numMembers; i++) for (int i = 0; i < numMembers; i++)
memberActorIds[i] = binReader.ReadUInt32(); memberActorIds[i] = binReader.ReadUInt32();
} }

View File

@ -0,0 +1,30 @@
using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.dataobjects;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace FFXIVClassic_Map_Server.packets.WorldPackets.Send.Group
{
class PartyModifyPacket
{
public const ushort OPCODE = 0x1020;
public const uint PACKET_SIZE = 0x48;
public static SubPacket BuildPacket(Session session, ushort command, string name)
{
byte[] data = new byte[PACKET_SIZE - 0x20];
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
binWriter.Write((UInt16)command);
binWriter.Write(Encoding.ASCII.GetBytes(name), 0, Encoding.ASCII.GetByteCount(name) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(name));
}
}
return new SubPacket(true, OPCODE, session.id, session.id, data);
}
}
}

View File

@ -23,15 +23,15 @@ namespace FFXIVClassic_Map_Server.packets.send.group
{ {
using (BinaryWriter binWriter = new BinaryWriter(mem)) using (BinaryWriter binWriter = new BinaryWriter(mem))
{ {
binWriter.Write((UInt64)group.groupId); binWriter.Write((UInt64)group.groupIndex);
binWriter.Write((UInt32)group.groupTypeId); binWriter.Write((UInt32)group.GetTypeId());
binWriter.Write((Int32)group.localizedNamed); binWriter.Write((Int32)group.GetGroupLocalizedName());
binWriter.Write((UInt16)0x121C); binWriter.Write((UInt16)0x121C);
binWriter.Seek(0x20, SeekOrigin.Begin); binWriter.Seek(0x20, SeekOrigin.Begin);
binWriter.Write(Encoding.ASCII.GetBytes(group.groupName), 0, Encoding.ASCII.GetByteCount(group.groupName) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(group.groupName)); binWriter.Write(Encoding.ASCII.GetBytes(group.GetGroupName()), 0, Encoding.ASCII.GetByteCount(group.GetGroupName()) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(group.GetGroupName()));
} }
} }

View File

@ -33,15 +33,15 @@ namespace FFXIVClassic_Map_Server.packets.send.group
Group group = groups[offset+i]; Group group = groups[offset+i];
binWriter.Write((UInt64)group.groupId); binWriter.Write((UInt64)group.groupIndex);
binWriter.Write((UInt32)group.groupTypeId); binWriter.Write((UInt32)group.GetTypeId());
binWriter.Write((Int32)group.localizedNamed); binWriter.Write((Int32)group.GetGroupLocalizedName());
binWriter.Write((UInt16)0x121C); binWriter.Write((UInt16)0x121C);
binWriter.Seek(0x20, SeekOrigin.Begin); binWriter.Seek(0x20, SeekOrigin.Begin);
binWriter.Write(Encoding.ASCII.GetBytes(group.groupName), 0, Encoding.ASCII.GetByteCount(group.groupName) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(group.groupName)); 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.Seek(0x200, SeekOrigin.Begin);

View File

@ -16,7 +16,7 @@ namespace FFXIVClassic_Map_Server.packets.send.groups
public static SubPacket buildPacket(uint playerActorID, Group group) public static SubPacket buildPacket(uint playerActorID, Group group)
{ {
return buildPacket(playerActorID, group.groupId); return buildPacket(playerActorID, group.groupIndex);
} }
public static SubPacket buildPacket(uint playerActorID, ulong groupId) public static SubPacket buildPacket(uint playerActorID, ulong groupId)

View File

@ -33,17 +33,17 @@ namespace FFXIVClassic_Map_Server.packets.send.group
//Write list id //Write list id
binWriter.Write((UInt64)3); binWriter.Write((UInt64)3);
binWriter.Write((UInt64)group.groupId); binWriter.Write((UInt64)group.groupIndex);
binWriter.Write((UInt64)0); binWriter.Write((UInt64)0);
binWriter.Write((UInt64)group.groupId); binWriter.Write((UInt64)group.groupIndex);
//This seems to change depending on what the list is for //This seems to change depending on what the list is for
binWriter.Write((UInt32)group.groupTypeId); binWriter.Write((UInt32)group.GetTypeId());
binWriter.Seek(0x40, SeekOrigin.Begin); binWriter.Seek(0x40, SeekOrigin.Begin);
//This is for Linkshell //This is for Linkshell
binWriter.Write((UInt32)group.localizedNamed); binWriter.Write((UInt32)group.GetGroupLocalizedName());
binWriter.Write(Encoding.ASCII.GetBytes(group.groupName), 0, Encoding.ASCII.GetByteCount(group.groupName) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(group.groupName)); 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.Seek(0x64, SeekOrigin.Begin);
@ -52,7 +52,7 @@ namespace FFXIVClassic_Map_Server.packets.send.group
binWriter.Write((UInt32)0x6D); binWriter.Write((UInt32)0x6D);
binWriter.Write((UInt32)0x6D); binWriter.Write((UInt32)0x6D);
binWriter.Write((UInt32)group.members.Count); binWriter.Write((UInt32)group.GetMemberCount());
} }
} }

View File

@ -27,8 +27,8 @@ namespace FFXIVClassic_Map_Server.packets.send.group
binWriter.Write((UInt64)locationCode); binWriter.Write((UInt64)locationCode);
binWriter.Write((UInt64)sequenceId); binWriter.Write((UInt64)sequenceId);
//Write List Info //Write List Info
binWriter.Write((UInt64)group.groupId); binWriter.Write((UInt64)group.groupIndex);
binWriter.Write((UInt32)group.members.Count); binWriter.Write((UInt32)group.GetMemberCount());
} }
} }

View File

@ -27,7 +27,7 @@ namespace FFXIVClassic_Map_Server.packets.send.group
binWriter.Write((UInt64)locationCode); binWriter.Write((UInt64)locationCode);
binWriter.Write((UInt64)sequenceId); binWriter.Write((UInt64)sequenceId);
//Write List Info //Write List Info
binWriter.Write((UInt64)group.groupId); binWriter.Write((UInt64)group.groupIndex);
} }
} }

View File

@ -48,6 +48,17 @@ namespace FFXIVClassic_World_Server.DataObjects.Group
return new List<GroupMember>(); return new List<GroupMember>();
} }
public void SendGroupPacketsAll(List<uint> sessionIds)
{
for (int i = 0; i < sessionIds.Count; i++)
{
Session session = Server.GetServer().GetSession(sessionIds[i]);
if (session != null)
SendGroupPackets(session);
}
}
public void SendGroupPackets(Session session) public void SendGroupPackets(Session session)
{ {
ulong time = Utils.MilisUnixTimeStampUTC(); ulong time = Utils.MilisUnixTimeStampUTC();

View File

@ -20,6 +20,90 @@ namespace FFXIVClassic_World_Server.DataObjects.Group
members.Add(leaderCharaId); members.Add(leaderCharaId);
} }
public void SetLeaderPlayerRequest(Session requestSession, string name)
{
if (GetLeader() != requestSession.sessionId)
{
requestSession.SendGameMessage(30428, 0x20, Server.GetServer().GetNameForId(requestSession.sessionId));
return;
}
uint newLeader = GetIdForName(name);
if (newLeader == 0)
{
requestSession.SendGameMessage(30575, 0x20);
return;
}
else if (newLeader == GetLeader())
{
requestSession.SendGameMessage(30563, 0x20, name);
return;
}
SetLeader(newLeader);
SendLeaderWorkToAllMembers();
for (int i = 0; i < members.Count; i++)
{
Session session = Server.GetServer().GetSession(members[i]);
if (session == null)
continue;
session.SendGameMessage(30429, 0x20, Server.GetServer().GetNameForId(members[i]));
}
Server.GetServer().GetWorldManager().SendPartySync(this);
}
public void KickPlayerRequest(Session requestSession, string name)
{
if (GetLeader() != requestSession.sessionId)
{
requestSession.SendGameMessage(30428, 0x20, Server.GetServer().GetNameForId(requestSession.sessionId));
return;
}
uint kickedMemberId = GetIdForName(name);
if (kickedMemberId == 0)
{
requestSession.SendGameMessage(30575, 0x20);
return;
}
for (int i = 0; i < members.Count; i++)
{
Session session = Server.GetServer().GetSession(members[i]);
if (session == null)
continue;
if (members[i] == kickedMemberId)
session.SendGameMessage(30410, 0x20);
else
session.SendGameMessage(30428, 0x20, (Object)name);
}
//All good, remove
members.Remove(kickedMemberId);
SendGroupPacketsAll(members);
Server.GetServer().GetWorldManager().SendPartySync(this);
}
public void SendLeaderWorkToAllMembers()
{
for (int i = 0; i < members.Count; i++)
{
SynchGroupWorkValuesPacket leaderUpdate = new SynchGroupWorkValuesPacket(groupIndex);
leaderUpdate.addProperty(this, "partyGroupWork._globalTemp.owner");
leaderUpdate.setTarget("partyGroupWork/leader");
Session session = Server.GetServer().GetSession(members[i]);
if (session == null)
continue;
else
session.clientConnection.QueuePacket(leaderUpdate.buildPacket(session.sessionId, session.sessionId), true, false);
}
}
public void SetLeader(uint actorId) public void SetLeader(uint actorId)
{ {
partyGroupWork._globalTemp.owner = (ulong)((actorId << 32) | 0xB36F92); partyGroupWork._globalTemp.owner = (ulong)((actorId << 32) | 0xB36F92);
@ -30,6 +114,18 @@ namespace FFXIVClassic_World_Server.DataObjects.Group
return (uint)((partyGroupWork._globalTemp.owner >> 32) & 0xFFFFFFFF); return (uint)((partyGroupWork._globalTemp.owner >> 32) & 0xFFFFFFFF);
} }
public uint GetIdForName(string name)
{
for (int i = 0; i < members.Count; i++)
{
if (Server.GetServer().GetNameForId(members[i]).Equals(name))
{
return members[i];
}
}
return 0;
}
public bool IsInParty(uint charaId) public bool IsInParty(uint charaId)
{ {
return members.Contains(charaId); return members.Contains(charaId);
@ -64,5 +160,6 @@ namespace FFXIVClassic_World_Server.DataObjects.Group
return groupMembers; return groupMembers;
} }
} }
} }

View File

@ -0,0 +1,16 @@
using System;
namespace FFXIVClassic_World_Server.DataObjects
{
class LuaParam
{
public int typeID;
public Object value;
public LuaParam(int type, Object value)
{
this.typeID = type;
this.value = value;
}
}
}

View File

@ -0,0 +1,380 @@
using FFXIVClassic.Common;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace FFXIVClassic_World_Server.DataObjects
{
class LuaUtils
{
public class Type7Param
{
public uint actorId;
public byte unknown;
public byte slot;
public byte inventoryType;
public Type7Param(uint actorId, byte unknown, byte slot, byte inventoryType)
{
this.actorId = actorId;
this.unknown = unknown;
this.slot = slot;
this.inventoryType = inventoryType;
}
}
public class Type9Param
{
public ulong item1;
public ulong item2;
public Type9Param(ulong item1, ulong item2)
{
this.item1 = item1;
this.item2 = item2;
}
}
public static List<LuaParam> ReadLuaParams(BinaryReader reader)
{
List<LuaParam> luaParams = new List<LuaParam>();
bool isDone = false;
while (true)
{
byte code = reader.ReadByte();
object value = null;
bool wasNil = false;
switch (code)
{
case 0x0: //Int32
value = Utils.SwapEndian(reader.ReadInt32());
break;
case 0x1: //Int32
value = Utils.SwapEndian(reader.ReadUInt32());
break;
case 0x2: //Null Termed String
List<byte> list = new List<byte>();
while(true){
byte readByte = reader.ReadByte();
if (readByte == 0)
break;
list.Add(readByte);
}
value = Encoding.ASCII.GetString(list.ToArray());
break;
case 0x3: //Boolean True
value = true;
break;
case 0x4: //Boolean False
value = false;
break;
case 0x5: //Nil
wasNil = true;
break;
case 0x6: //Actor (By Id)
value = Utils.SwapEndian(reader.ReadUInt32());
break;
case 0x7: //Weird one used for inventory
uint type7ActorId = Utils.SwapEndian(reader.ReadUInt32());
byte type7Unknown = reader.ReadByte();
byte type7Slot = reader.ReadByte();
byte type7InventoryType = reader.ReadByte();
value = new Type7Param(type7ActorId, type7Unknown, type7Slot, type7InventoryType);
break;
case 0x9: //Two Longs (only storing first one)
value = new Type9Param(Utils.SwapEndian(reader.ReadUInt64()), Utils.SwapEndian(reader.ReadUInt64()));
break;
case 0xC: //Byte
value = reader.ReadByte();
break;
case 0x1B: //Short?
value = reader.ReadUInt16();
break;
case 0xF: //End
isDone = true;
continue;
}
if (isDone)
break;
if (value != null)
luaParams.Add(new LuaParam(code, value));
else if (wasNil)
luaParams.Add(new LuaParam(code, value));
}
return luaParams;
}
public static void WriteLuaParams(BinaryWriter writer, List<LuaParam> luaParams)
{
foreach (LuaParam l in luaParams)
{
if (l.typeID == 0x1)
writer.Write((Byte)0);
else
writer.Write((Byte)l.typeID);
switch (l.typeID)
{
case 0x0: //Int32
writer.Write((Int32)Utils.SwapEndian((Int32)l.value));
break;
case 0x1: //Int32
writer.Write((UInt32)Utils.SwapEndian((UInt32)l.value));
break;
case 0x2: //Null Termed String
string sv = (string)l.value;
writer.Write(Encoding.ASCII.GetBytes(sv), 0, Encoding.ASCII.GetByteCount(sv));
writer.Write((Byte)0);
break;
case 0x3: //Boolean True
break;
case 0x4: //Boolean False
break;
case 0x5: //Nil
break;
case 0x6: //Actor (By Id)
writer.Write((UInt32)Utils.SwapEndian((UInt32)l.value));
break;
case 0x7: //Weird one used for inventory
Type7Param type7 = (Type7Param)l.value;
writer.Write((UInt32)Utils.SwapEndian((UInt32)type7.actorId));
writer.Write((Byte)type7.unknown);
writer.Write((Byte)type7.slot);
writer.Write((Byte)type7.inventoryType);
break;
case 0x9: //Two Longs (only storing first one)
writer.Write((UInt64)Utils.SwapEndian(((Type9Param)l.value).item1));
writer.Write((UInt64)Utils.SwapEndian(((Type9Param)l.value).item2));
break;
case 0xC: //Byte
writer.Write((Byte)l.value);
break;
case 0x1B: //Short?
break;
case 0xF: //End
continue;
}
}
writer.Write((Byte)0xF);
}
public static List<LuaParam> ReadLuaParams(byte[] bytesIn)
{
List<LuaParam> luaParams = new List<LuaParam>();
using (MemoryStream memStream = new MemoryStream(bytesIn))
{
using (BinaryReader reader = new BinaryReader(memStream))
{
bool isDone = false;
while (true)
{
byte code = reader.ReadByte();
object value = null;
bool wasNil = false;
switch (code)
{
case 0x0: //Int32
value = Utils.SwapEndian(reader.ReadInt32());
break;
case 0x1: //Int32
value = Utils.SwapEndian(reader.ReadUInt32());
break;
case 0x2: //Null Termed String
List<byte> list = new List<byte>();
while (true)
{
byte readByte = reader.ReadByte();
if (readByte == 0)
break;
list.Add(readByte);
}
value = Encoding.ASCII.GetString(list.ToArray());
break;
case 0x3: //Boolean True
value = true;
break;
case 0x4: //Boolean False
value = false;
break;
case 0x5: //Nil
wasNil = true;
break;
case 0x6: //Actor (By Id)
value = Utils.SwapEndian(reader.ReadUInt32());
break;
case 0x7: //Weird one used for inventory
uint type7ActorId = Utils.SwapEndian(reader.ReadUInt32());
byte type7Unknown = reader.ReadByte();
byte type7Slot = reader.ReadByte();
byte type7InventoryType = reader.ReadByte();
value = new Type7Param(type7ActorId, type7Unknown, type7Slot, type7InventoryType);
break;
case 0x9: //Two Longs (only storing first one)
value = new Type9Param(Utils.SwapEndian(reader.ReadUInt64()), Utils.SwapEndian(reader.ReadUInt64()));
break;
case 0xC: //Byte
value = reader.ReadByte();
break;
case 0x1B: //Short?
value = reader.ReadUInt16();
break;
case 0xF: //End
isDone = true;
continue;
}
if (isDone)
break;
if (value != null)
luaParams.Add(new LuaParam(code, value));
else if (wasNil)
luaParams.Add(new LuaParam(code, value));
}
}
}
return luaParams;
}
public static List<LuaParam> CreateLuaParamList(params object[] list)
{
List<LuaParam> luaParams = new List<LuaParam>();
foreach (object o in list)
{
if (o != null && o.GetType().IsArray)
{
Array arrayO = (Array)o;
foreach (object o2 in arrayO)
AddToList(o2, luaParams);
}
else
AddToList(o, luaParams);
}
return luaParams;
}
private static void AddToList(object o, List<LuaParam> luaParams)
{
if (o is int)
{
luaParams.Add(new LuaParam(0x0, (int)o));
}
else if (o is uint)
{
luaParams.Add(new LuaParam(0x1, (uint)o));
}
else if (o is Double)
{
if (((double)o) % 1 == 0)
luaParams.Add(new LuaParam(0x0, (int)(double)o));
}
else if (o is string)
{
luaParams.Add(new LuaParam(0x2, (string)o));
}
else if (o is bool)
{
if (((bool)o))
luaParams.Add(new LuaParam(0x3, null));
else
luaParams.Add(new LuaParam(0x4, null));
}
else if (o == null)
{
luaParams.Add(new LuaParam(0x5, null));
}
else if (o is Type7Param)
{
luaParams.Add(new LuaParam(0x7, (Type7Param)o));
}
else if (o is Type9Param)
{
luaParams.Add(new LuaParam(0x9, (Type9Param)o));
}
else if (o is byte)
{
luaParams.Add(new LuaParam(0xC, (byte)o));
}
}
public static object[] CreateLuaParamObjectList(List <LuaParam> luaParams)
{
object[] list = new object[luaParams.Count];
for (int i = 0; i < list.Length; i++)
list[i] = luaParams[i].value;
return list;
}
public static string DumpParams(List<LuaParam> lParams)
{
if (lParams == null)
return "Param list was null?";
string dumpString = "";
for (int i = 0; i < lParams.Count; i++)
{
switch (lParams[i].typeID)
{
case 0x0: //Int32
dumpString += String.Format("0x{0:X}", (int)lParams[i].value);
break;
case 0x1: //Int32
dumpString += String.Format("0x{0:X}", (uint)lParams[i].value);
break;
case 0x2: //Null Termed String
dumpString += String.Format("\"{0}\"", (string)lParams[i].value);
break;
case 0x3: //Boolean True
dumpString += "true";
break;
case 0x4: //Boolean False
dumpString += "false";
break;
case 0x5: //NULL???
dumpString += "nil";
break;
case 0x6: //Actor (By Id)
dumpString += String.Format("0x{0:X}", (uint)lParams[i].value);
break;
case 0x7: //Weird one used for inventory
Type7Param type7Param = ((Type7Param)lParams[i].value);
dumpString += String.Format("Type7 Param: (0x{0:X}, 0x{1:X}, 0x{2:X}, 0x{3:X})", type7Param.actorId, type7Param.unknown, type7Param.slot, type7Param.inventoryType);
break;
case 0xC: //Byte
dumpString += String.Format("0x{0:X}", (byte)lParams[i].value);
break;
case 0x9: //Long (+ 8 bytes ignored)
Type9Param type9Param = ((Type9Param)lParams[i].value);
dumpString += String.Format("Type9 Param: (0x{0:X}, 0x{1:X})", type9Param.item1, type9Param.item2);
break;
case 0x1B: //Short?
dumpString += String.Format("0x{0:X}", (ushort)lParams[i].value);
break;
case 0xF: //End
break;
}
if (i != lParams.Count - 1)
dumpString += ", ";
}
return dumpString;
}
}
}

View File

@ -1,4 +1,5 @@
using System; using FFXIVClassic_World_Server.Packets.Send.Subpackets;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net.Sockets; using System.Net.Sockets;
@ -29,5 +30,29 @@ namespace FFXIVClassic_World_Server.DataObjects
Database.LoadZoneSessionInfo(this); Database.LoadZoneSessionInfo(this);
} }
public void SendGameMessage( ushort textId, byte log, params object[] msgParams)
{
if (msgParams == null || msgParams.Length == 0)
clientConnection.QueuePacket(GameMessagePacket.BuildPacket(0x5FF80001, sessionId, 0x5FF80001, textId, log), true, false);
else
clientConnection.QueuePacket(GameMessagePacket.BuildPacket(0x5FF80001, sessionId, 0x5FF80001, textId, log, LuaUtils.CreateLuaParamList(msgParams)), true, false);
}
public void SendGameMessage( ushort textId, byte log, string customSender, params object[] msgParams)
{
if (msgParams == null || msgParams.Length == 0)
clientConnection.QueuePacket(GameMessagePacket.BuildPacket(0x5FF80001, sessionId, 0x5FF80001, textId, customSender, log), true, false);
else
clientConnection.QueuePacket(GameMessagePacket.BuildPacket(0x5FF80001, sessionId, 0x5FF80001, textId, customSender, log, LuaUtils.CreateLuaParamList(msgParams)), true, false);
}
public void SendGameMessage(ushort textId, byte log, uint displayId, params object[] msgParams)
{
if (msgParams == null || msgParams.Length == 0)
clientConnection.QueuePacket(GameMessagePacket.BuildPacket(0x5FF80001, sessionId, 0x5FF80001, textId, displayId, log), true, false);
else
clientConnection.QueuePacket(GameMessagePacket.BuildPacket(0x5FF80001, sessionId, 0x5FF80001, textId, displayId, log, LuaUtils.CreateLuaParamList(msgParams)), true, false);
}
} }
} }

View File

@ -193,6 +193,41 @@ namespace FFXIVClassic_World_Server
return members; return members;
} }
public static Linkshell GetLinkshell(ulong groupIndex, string lsName)
{
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, crestIcon, master FROM server_linkshells WHERE name = @lsName", conn);
cmd.Parameters.AddWithValue("@lsName", lsName);
using (MySqlDataReader Reader = cmd.ExecuteReader())
{
while (Reader.Read())
{
ulong lsId = Reader.GetUInt64("id");
string name = Reader.GetString("name");
ushort crest = Reader.GetUInt16("crestIcon");
uint master = Reader.GetUInt32("master");
Linkshell linkshell = new Linkshell(lsId, groupIndex, name, crest, master, 0xa);
return linkshell;
}
}
}
catch (MySqlException e)
{
Program.Log.Error(e.ToString());
}
finally
{
conn.Dispose();
}
}
return null;
}
public static Linkshell GetLinkshell(ulong groupIndex, ulong lsId) public static Linkshell GetLinkshell(ulong groupIndex, ulong lsId)
{ {
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))) 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)))

View File

@ -83,12 +83,15 @@
<Compile Include="DataObjects\Group\Relation.cs" /> <Compile Include="DataObjects\Group\Relation.cs" />
<Compile Include="DataObjects\Group\RetainerGroup.cs" /> <Compile Include="DataObjects\Group\RetainerGroup.cs" />
<Compile Include="DataObjects\Group\RetainerGroupMember.cs" /> <Compile Include="DataObjects\Group\RetainerGroupMember.cs" />
<Compile Include="DataObjects\LuaParam.cs" />
<Compile Include="DataObjects\LuaUtils.cs" />
<Compile Include="DataObjects\ZoneServer.cs" /> <Compile Include="DataObjects\ZoneServer.cs" />
<Compile Include="DataObjects\Session.cs" /> <Compile Include="DataObjects\Session.cs" />
<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\Receive\Subpackets\GroupCreatedPacket.cs" /> <Compile Include="Packets\Receive\Subpackets\GroupCreatedPacket.cs" />
<Compile Include="Packets\Send\Subpackets\GameMessagePacket.cs" />
<Compile Include="Packets\Send\Subpackets\Groups\CreateNamedGroup.cs" /> <Compile Include="Packets\Send\Subpackets\Groups\CreateNamedGroup.cs" />
<Compile Include="Packets\Send\Subpackets\Groups\CreateNamedGroupMultiple.cs" /> <Compile Include="Packets\Send\Subpackets\Groups\CreateNamedGroupMultiple.cs" />
<Compile Include="Packets\Send\Subpackets\Groups\DeleteGroupPacket.cs" /> <Compile Include="Packets\Send\Subpackets\Groups\DeleteGroupPacket.cs" />
@ -105,22 +108,19 @@
<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" />
<Compile Include="Packets\WorldPackets\Receive\Group\PartyLeavePacket.cs" />
<Compile Include="Packets\WorldPackets\Receive\Group\PartyModifyPacket.cs" />
<Compile Include="Packets\WorldPackets\Receive\Group\SetActiveLinkshellPacket.cs" /> <Compile Include="Packets\WorldPackets\Receive\Group\SetActiveLinkshellPacket.cs" />
<Compile Include="Packets\WorldPackets\Receive\Group\ModifyLinkshellPacket.cs" /> <Compile Include="Packets\WorldPackets\Receive\Group\ModifyLinkshellPacket.cs" />
<Compile Include="Packets\WorldPackets\Receive\Group\CreateRelationPacket.cs" /> <Compile Include="Packets\WorldPackets\Receive\Group\CreateRelationPacket.cs" />
<Compile Include="Packets\WorldPackets\Receive\Group\CreateLinkshellPacket.cs" /> <Compile Include="Packets\WorldPackets\Receive\Group\CreateLinkshellPacket.cs" />
<Compile Include="Packets\WorldPackets\Receive\Group\GetGroupPacket.cs" /> <Compile Include="Packets\WorldPackets\Receive\Group\GetGroupPacket.cs" />
<Compile Include="Packets\WorldPackets\Receive\Group\DeleteLinkshellPacket.cs" /> <Compile Include="Packets\WorldPackets\Receive\Group\DeleteLinkshellPacket.cs" />
<Compile Include="Packets\WorldPackets\Receive\Group\GroupMemberChangePacket.cs" />
<Compile Include="Packets\WorldPackets\Receive\SessionBeginConfirmPacket.cs" /> <Compile Include="Packets\WorldPackets\Receive\SessionBeginConfirmPacket.cs" />
<Compile Include="Packets\WorldPackets\Receive\WorldRequestZoneChangePacket.cs" /> <Compile Include="Packets\WorldPackets\Receive\WorldRequestZoneChangePacket.cs" />
<Compile Include="Packets\WorldPackets\Receive\SessionEndConfirmPacket.cs" /> <Compile Include="Packets\WorldPackets\Receive\SessionEndConfirmPacket.cs" />
<Compile Include="Packets\WorldPackets\Send\ErrorPacket.cs" /> <Compile Include="Packets\WorldPackets\Send\ErrorPacket.cs" />
<Compile Include="Packets\WorldPackets\Send\Group\PartySyncPacket.cs" /> <Compile Include="Packets\WorldPackets\Send\Group\PartySyncPacket.cs" />
<Compile Include="Packets\WorldPackets\Send\Group\GroupWorkValuesPacket.cs" />
<Compile Include="Packets\WorldPackets\Send\Group\GroupMemberListPacket.cs" />
<Compile Include="Packets\WorldPackets\Send\Group\GroupMemberListEndPacket.cs" />
<Compile Include="Packets\WorldPackets\Send\Group\GroupMemberListStartPacket.cs" />
<Compile Include="Packets\WorldPackets\Send\SessionBeginPacket.cs" /> <Compile Include="Packets\WorldPackets\Send\SessionBeginPacket.cs" />
<Compile Include="Packets\WorldPackets\Send\SessionEndPacket.cs" /> <Compile Include="Packets\WorldPackets\Send\SessionEndPacket.cs" />
<Compile Include="PartyManager.cs" /> <Compile Include="PartyManager.cs" />

View File

@ -11,9 +11,10 @@ namespace FFXIVClassic_World_Server
{ {
private WorldManager mWorldManager; private WorldManager mWorldManager;
private Object mGroupLockReference; private Object mGroupLockReference;
private Dictionary<ulong, Group> mCurrentWorldGroupsReference; private Dictionary<ulong, Group> mCurrentWorldGroupsReference; //GroupId, LS
private Dictionary<ulong, Linkshell> mLinkshellList = new Dictionary<ulong, Linkshell>(); private Dictionary<ulong, Linkshell> mLinkshellList = new Dictionary<ulong, Linkshell>(); //GroupId, LS
private Dictionary<string, ulong> mNameToIdLookup = new Dictionary<string, ulong>(); private Dictionary<ulong, Linkshell> mLSIdToIdLookup = new Dictionary<ulong, Linkshell>(); //Name, GroupId
private Dictionary<string, ulong> mNameToIdLookup = new Dictionary<string, ulong>(); //Name, GroupId
public LinkshellManager(WorldManager worldManager, Object groupLock, Dictionary<ulong, Group> worldGroupList) public LinkshellManager(WorldManager worldManager, Object groupLock, Dictionary<ulong, Group> worldGroupList)
{ {
@ -161,15 +162,32 @@ namespace FFXIVClassic_World_Server
{ {
if (mNameToIdLookup.ContainsKey(name)) if (mNameToIdLookup.ContainsKey(name))
return (Linkshell)mCurrentWorldGroupsReference[mNameToIdLookup[name]]; return (Linkshell)mCurrentWorldGroupsReference[mNameToIdLookup[name]];
else
{
lock (mGroupLockReference)
{
Linkshell ls = Database.GetLinkshell(mWorldManager.GetGroupIndex(), name);
ls.LoadMembers();
if (ls != null)
{
mLinkshellList.Add(ls.groupIndex, ls);
mNameToIdLookup.Add(ls.name, ls.groupIndex);
mCurrentWorldGroupsReference.Add(ls.groupIndex, ls);
mWorldManager.IncrementGroupIndex();
return ls;
}
else else
return null; return null;
} }
}
}
//Get a single linkshell group either already instantiated or make one from the db //Get a single linkshell group either already instantiated or make one from the db
public Linkshell GetLinkshell(ulong lsId) public Linkshell GetLinkshell(ulong lsId)
{ {
if (mLinkshellList.ContainsKey(lsId)) if (mLSIdToIdLookup.ContainsKey(lsId))
return mLinkshellList[lsId]; return mLSIdToIdLookup[lsId];
else else
{ {
lock (mGroupLockReference) lock (mGroupLockReference)
@ -181,6 +199,7 @@ namespace FFXIVClassic_World_Server
{ {
mLinkshellList.Add(ls.groupIndex, ls); mLinkshellList.Add(ls.groupIndex, ls);
mNameToIdLookup.Add(ls.name, ls.groupIndex); mNameToIdLookup.Add(ls.name, ls.groupIndex);
mLSIdToIdLookup.Add(ls.dbId, ls);
mCurrentWorldGroupsReference.Add(ls.groupIndex, ls); mCurrentWorldGroupsReference.Add(ls.groupIndex, ls);
mWorldManager.IncrementGroupIndex(); mWorldManager.IncrementGroupIndex();
return ls; return ls;

View File

@ -0,0 +1,348 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using FFXIVClassic.Common;
using FFXIVClassic_World_Server.DataObjects;
namespace FFXIVClassic_World_Server.Packets.Send.Subpackets
{
class GameMessagePacket
{
private const ushort OPCODE_GAMEMESSAGE_WITH_ACTOR1 = 0x157;
private const ushort OPCODE_GAMEMESSAGE_WITH_ACTOR2 = 0x158;
private const ushort OPCODE_GAMEMESSAGE_WITH_ACTOR3 = 0x159;
private const ushort OPCODE_GAMEMESSAGE_WITH_ACTOR4 = 0x15a;
private const ushort OPCODE_GAMEMESSAGE_WITH_ACTOR5 = 0x15b;
private const ushort OPCODE_GAMEMESSAGE_WITH_CUSTOM_SENDER1 = 0x15c;
private const ushort OPCODE_GAMEMESSAGE_WITH_CUSTOM_SENDER2 = 0x15d;
private const ushort OPCODE_GAMEMESSAGE_WITH_CUSTOM_SENDER3 = 0x15e;
private const ushort OPCODE_GAMEMESSAGE_WITH_CUSTOM_SENDER4 = 0x15f;
private const ushort OPCODE_GAMEMESSAGE_WITH_CUSTOM_SENDER5 = 0x160;
private const ushort OPCODE_GAMEMESSAGE_WITH_DISPID_SENDER1 = 0x161;
private const ushort OPCODE_GAMEMESSAGE_WITH_DISPID_SENDER2 = 0x162;
private const ushort OPCODE_GAMEMESSAGE_WITH_DISPID_SENDER3 = 0x163;
private const ushort OPCODE_GAMEMESSAGE_WITH_DISPID_SENDER4 = 0x164;
private const ushort OPCODE_GAMEMESSAGE_WITH_DISPID_SENDER5 = 0x165;
private const ushort OPCODE_GAMEMESSAGE_WITHOUT_ACTOR1 = 0x166;
private const ushort OPCODE_GAMEMESSAGE_WITHOUT_ACTOR2 = 0x167;
private const ushort OPCODE_GAMEMESSAGE_WITHOUT_ACTOR3 = 0x168;
private const ushort OPCODE_GAMEMESSAGE_WITHOUT_ACTOR4 = 0x169;
private const ushort OPCODE_GAMEMESSAGE_WITHOUT_ACTOR5 = 0x16a;
private const ushort SIZE_GAMEMESSAGE_WITH_ACTOR1 = 0x30;
private const ushort SIZE_GAMEMESSAGE_WITH_ACTOR2 = 0x38;
private const ushort SIZE_GAMEMESSAGE_WITH_ACTOR3 = 0x40;
private const ushort SIZE_GAMEMESSAGE_WITH_ACTOR4 = 0x50;
private const ushort SIZE_GAMEMESSAGE_WITH_ACTOR5 = 0x70;
private const ushort SIZE_GAMEMESSAGE_WITH_CUSTOM_SENDER1 = 0x48;
private const ushort SIZE_GAMEMESSAGE_WITH_CUSTOM_SENDER2 = 0x58;
private const ushort SIZE_GAMEMESSAGE_WITH_CUSTOM_SENDER3 = 0x68;
private const ushort SIZE_GAMEMESSAGE_WITH_CUSTOM_SENDER4 = 0x78;
private const ushort SIZE_GAMEMESSAGE_WITH_CUSTOM_SENDER5 = 0x98;
private const ushort SIZE_GAMEMESSAGE_WITH_DISPID_SENDER1 = 0x30;
private const ushort SIZE_GAMEMESSAGE_WITH_DISPID_SENDER2 = 0x38;
private const ushort SIZE_GAMEMESSAGE_WITH_DISPID_SENDER3 = 0x40;
private const ushort SIZE_GAMEMESSAGE_WITH_DISPID_SENDER4 = 0x50;
private const ushort SIZE_GAMEMESSAGE_WITH_DISPID_SENDER5 = 0x60;
private const ushort SIZE_GAMEMESSAGE_WITHOUT_ACTOR1 = 0x28;
private const ushort SIZE_GAMEMESSAGE_WITHOUT_ACTOR2 = 0x38;
private const ushort SIZE_GAMEMESSAGE_WITHOUT_ACTOR3 = 0x38;
private const ushort SIZE_GAMEMESSAGE_WITHOUT_ACTOR4 = 0x48;
private const ushort SIZE_GAMEMESSAGE_WITHOUT_ACTOR5 = 0x68;
public static SubPacket BuildPacket(uint sourceId, uint targetId, uint actorId, uint textOwnerActorId, ushort textId, byte log)
{
byte[] data = new byte[SIZE_GAMEMESSAGE_WITH_ACTOR1 - 0x20];
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
binWriter.Write((UInt32)actorId);
binWriter.Write((UInt32)textOwnerActorId);
binWriter.Write((UInt16)textId);
binWriter.Write((UInt16)log);
}
}
return new SubPacket(OPCODE_GAMEMESSAGE_WITH_ACTOR1, sourceId, targetId, data);
}
public static SubPacket BuildPacket(uint sourceId, uint targetId, uint actorId, uint textOwnerActorId, ushort textId, byte log, List<LuaParam> lParams)
{
int lParamsSize = findSizeOfParams(lParams);
byte[] data;
ushort opcode;
if (lParamsSize <= 0x8)
{
data = new byte[SIZE_GAMEMESSAGE_WITH_ACTOR2 - 0x20];
opcode = OPCODE_GAMEMESSAGE_WITH_ACTOR2;
}
else if (lParamsSize <= 0x10)
{
data = new byte[SIZE_GAMEMESSAGE_WITH_ACTOR3 - 0x20];
opcode = OPCODE_GAMEMESSAGE_WITH_ACTOR3;
}
else if (lParamsSize <= 0x20)
{
data = new byte[SIZE_GAMEMESSAGE_WITH_ACTOR4 - 0x20];
opcode = OPCODE_GAMEMESSAGE_WITH_ACTOR4;
}
else
{
data = new byte[SIZE_GAMEMESSAGE_WITH_ACTOR5 - 0x20];
opcode = OPCODE_GAMEMESSAGE_WITH_ACTOR5;
}
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
binWriter.Write((UInt32)actorId);
binWriter.Write((UInt32)textOwnerActorId);
binWriter.Write((UInt16)textId);
binWriter.Write((UInt16)log);
LuaUtils.WriteLuaParams(binWriter, lParams);
if (lParamsSize <= 0x14-12)
{
binWriter.Seek(0x14, SeekOrigin.Begin);
binWriter.Write((UInt32)8);
}
}
}
return new SubPacket(opcode, sourceId, targetId, data);
}
public static SubPacket BuildPacket(uint sourceId, uint targetId, uint textOwnerActorId, ushort textId, string sender, byte log)
{
byte[] data = new byte[SIZE_GAMEMESSAGE_WITH_CUSTOM_SENDER1 - 0x20];
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
binWriter.Write((UInt32)textOwnerActorId);
binWriter.Write((UInt16)textId);
binWriter.Write((UInt16)log);
binWriter.Write(Encoding.ASCII.GetBytes(sender), 0, Encoding.ASCII.GetByteCount(sender) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(sender));
}
}
return new SubPacket(OPCODE_GAMEMESSAGE_WITH_CUSTOM_SENDER1, sourceId, targetId, data);
}
public static SubPacket BuildPacket(uint sourceId, uint targetId, uint textOwnerActorId, ushort textId, string sender, byte log, List<LuaParam> lParams)
{
int lParamsSize = findSizeOfParams(lParams);
byte[] data;
ushort opcode;
if (lParamsSize <= 0x8)
{
data = new byte[SIZE_GAMEMESSAGE_WITH_CUSTOM_SENDER2 - 0x20];
opcode = OPCODE_GAMEMESSAGE_WITH_CUSTOM_SENDER2;
}
else if (lParamsSize <= 0x10)
{
data = new byte[SIZE_GAMEMESSAGE_WITH_CUSTOM_SENDER3 - 0x20];
opcode = OPCODE_GAMEMESSAGE_WITH_CUSTOM_SENDER3;
}
else if (lParamsSize <= 0x20)
{
data = new byte[SIZE_GAMEMESSAGE_WITH_CUSTOM_SENDER4 - 0x20];
opcode = OPCODE_GAMEMESSAGE_WITH_CUSTOM_SENDER4;
}
else
{
data = new byte[SIZE_GAMEMESSAGE_WITH_CUSTOM_SENDER5 - 0x20];
opcode = OPCODE_GAMEMESSAGE_WITH_CUSTOM_SENDER5;
}
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
binWriter.Write((UInt32)textOwnerActorId);
binWriter.Write((UInt16)textId);
binWriter.Write((UInt16)log);
binWriter.Write(Encoding.ASCII.GetBytes(sender), 0, Encoding.ASCII.GetByteCount(sender) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(sender));
LuaUtils.WriteLuaParams(binWriter, lParams);
if (lParamsSize <= 0x14 - 12)
{
binWriter.Seek(0x30, SeekOrigin.Begin);
binWriter.Write((UInt32)8);
}
}
}
return new SubPacket(opcode, sourceId, targetId, data);
}
public static SubPacket BuildPacket(uint sourceId, uint targetId, uint textOwnerActorId, ushort textId, uint senderDisplayNameId, byte log)
{
byte[] data = new byte[SIZE_GAMEMESSAGE_WITH_DISPID_SENDER1 - 0x20];
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
binWriter.Write((UInt32)senderDisplayNameId);
binWriter.Write((UInt32)textOwnerActorId);
binWriter.Write((UInt16)textId);
binWriter.Write((UInt16)log);
}
}
return new SubPacket(OPCODE_GAMEMESSAGE_WITH_DISPID_SENDER1, sourceId, targetId, data);
}
public static SubPacket BuildPacket(uint sourceId, uint targetId, uint textOwnerActorId, ushort textId, uint senderDisplayNameId, byte log, List<LuaParam> lParams)
{
int lParamsSize = findSizeOfParams(lParams);
byte[] data;
ushort opcode;
if (lParamsSize <= 0x8)
{
data = new byte[SIZE_GAMEMESSAGE_WITH_DISPID_SENDER2 - 0x20];
opcode = OPCODE_GAMEMESSAGE_WITH_DISPID_SENDER2;
}
else if (lParamsSize <= 0x10)
{
data = new byte[SIZE_GAMEMESSAGE_WITH_DISPID_SENDER3 - 0x20];
opcode = OPCODE_GAMEMESSAGE_WITH_DISPID_SENDER3;
}
else if (lParamsSize <= 0x20)
{
data = new byte[SIZE_GAMEMESSAGE_WITH_DISPID_SENDER4 - 0x20];
opcode = OPCODE_GAMEMESSAGE_WITH_DISPID_SENDER4;
}
else
{
data = new byte[SIZE_GAMEMESSAGE_WITH_DISPID_SENDER5 - 0x20];
opcode = OPCODE_GAMEMESSAGE_WITH_DISPID_SENDER5;
}
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
binWriter.Write((UInt32)senderDisplayNameId);
binWriter.Write((UInt32)textOwnerActorId);
binWriter.Write((UInt16)textId);
binWriter.Write((UInt16)log);
LuaUtils.WriteLuaParams(binWriter, lParams);
if (lParamsSize <= 0x14 - 12)
{
binWriter.Seek(0x14, SeekOrigin.Begin);
binWriter.Write((UInt32)8);
}
}
}
return new SubPacket(opcode, sourceId, targetId, data);
}
public static SubPacket BuildPacket(uint sourceId, uint targetId, uint textOwnerActorId, ushort textId, byte log)
{
byte[] data = new byte[SIZE_GAMEMESSAGE_WITHOUT_ACTOR1 - 0x20];
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
binWriter.Write((UInt32)textOwnerActorId);
binWriter.Write((UInt16)textId);
binWriter.Write((UInt16)log);
}
}
return new SubPacket(OPCODE_GAMEMESSAGE_WITHOUT_ACTOR1, sourceId, targetId, data);
}
public static SubPacket BuildPacket(uint sourceId, uint targetId, uint textOwnerActorId, ushort textId, byte log, List<LuaParam> lParams)
{
int lParamsSize = findSizeOfParams(lParams);
byte[] data;
ushort opcode;
if (lParamsSize <= 0x8)
{
data = new byte[SIZE_GAMEMESSAGE_WITHOUT_ACTOR2 - 0x20];
opcode = OPCODE_GAMEMESSAGE_WITHOUT_ACTOR2;
}
else if (lParamsSize <= 0x10)
{
data = new byte[SIZE_GAMEMESSAGE_WITHOUT_ACTOR3 - 0x20];
opcode = OPCODE_GAMEMESSAGE_WITHOUT_ACTOR3;
}
else if (lParamsSize <= 0x20)
{
data = new byte[SIZE_GAMEMESSAGE_WITHOUT_ACTOR4 - 0x20];
opcode = OPCODE_GAMEMESSAGE_WITHOUT_ACTOR4;
}
else
{
data = new byte[SIZE_GAMEMESSAGE_WITHOUT_ACTOR5 - 0x20];
opcode = OPCODE_GAMEMESSAGE_WITHOUT_ACTOR5;
}
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
binWriter.Write((UInt32)textOwnerActorId);
binWriter.Write((UInt16)textId);
binWriter.Write((UInt16)log);
LuaUtils.WriteLuaParams(binWriter, lParams);
if (lParamsSize <= 0x8)
{
binWriter.Seek(0x10, SeekOrigin.Begin);
binWriter.Write((UInt32)8);
}
}
}
return new SubPacket(opcode, sourceId, targetId, data);
}
private static int findSizeOfParams(List<LuaParam> lParams)
{
int total = 0;
foreach (LuaParam l in lParams)
{
switch (l.typeID)
{
case 0:
case 1:
case 2:
total += 1 + 0x20;
break;
case 6:
total += 5;
break;
case 3:
case 4:
case 5:
total += 1;
break;
}
}
return total + 1;
}
}
}

View File

@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace FFXIVClassic_World_Server.Packets.WorldPackets.Receive.Group
{
class PartyLeavePacket
{
public bool invalidPacket = false;
public bool isDisband;
public PartyLeavePacket(byte[] data)
{
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryReader binReader = new BinaryReader(mem))
{
try
{
isDisband = binReader.ReadByte() == 1;
}
catch (Exception)
{
invalidPacket = true;
}
}
}
}
}
}

View File

@ -1,19 +1,21 @@
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text;
namespace FFXIVClassic_World_Server.Packets.WorldPackets.Receive.Group namespace FFXIVClassic_World_Server.Packets.WorldPackets.Receive.Group
{ {
class GroupMemberChangePacket class PartyModifyPacket
{ {
public const int GROUP_MEMBER_ADD = 0;
public const int GROUP_MEMBER_REMOVE = 0;
public bool invalidPacket = false; public bool invalidPacket = false;
public uint controlCode;
public ulong groupId;
public uint memberId;
public GroupMemberChangePacket(byte[] data) public const ushort MODIFY_LEADER = 0;
public const ushort MODIFY_KICKPLAYER = 1;
public ushort command;
public string name;
public PartyModifyPacket(byte[] data)
{ {
using (MemoryStream mem = new MemoryStream(data)) using (MemoryStream mem = new MemoryStream(data))
{ {
@ -21,9 +23,8 @@ namespace FFXIVClassic_World_Server.Packets.WorldPackets.Receive.Group
{ {
try try
{ {
controlCode = binReader.ReadUInt32(); command = binReader.ReadUInt16();
groupId = binReader.ReadUInt64(); name = Encoding.ASCII.GetString(binReader.ReadBytes(0x20)).Trim(new[] { '\0' });
memberId = binReader.ReadUInt32();
} }
catch (Exception) catch (Exception)
{ {

View File

@ -1,28 +0,0 @@
using FFXIVClassic.Common;
using FFXIVClassic_World_Server.DataObjects;
using System;
using System.IO;
namespace FFXIVClassic_World_Server.Packets.WorldPackets.Send.Group
{
class GroupMemberListEndPacket
{
public const ushort OPCODE = 0x1022;
public const uint PACKET_SIZE = 0x28;
public static SubPacket BuildPacket(Session session, ulong groupId)
{
byte[] data = new byte[PACKET_SIZE - 0x20];
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
binWriter.Write((UInt64)groupId);
}
}
return new SubPacket(true, OPCODE, 0, session.sessionId, data);
}
}
}

View File

@ -1,31 +0,0 @@
using FFXIVClassic.Common;
using FFXIVClassic_World_Server.DataObjects;
using System;
using System.IO;
namespace FFXIVClassic_World_Server.Packets.WorldPackets.Send.Group
{
class GroupMemberListPacket
{
public const ushort OPCODE = 0x1021;
public const uint PACKET_SIZE = 0x2C;
public static SubPacket BuildPacket(Session session, ulong groupId, uint numMembersInPacket)
{
byte[] data = new byte[PACKET_SIZE - 0x20];
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
binWriter.Write((UInt64)groupId);
binWriter.Write((UInt32)numMembersInPacket);
//Members
}
}
return new SubPacket(true, OPCODE, 0, session.sessionId, data);
}
}
}

View File

@ -1,30 +0,0 @@
using FFXIVClassic.Common;
using FFXIVClassic_World_Server.DataObjects;
using System;
using System.IO;
namespace FFXIVClassic_World_Server.Packets.WorldPackets.Send.Group
{
class GroupMemberListStartPacket
{
public const ushort OPCODE = 0x1020;
public const uint PACKET_SIZE = 0x30;
public static SubPacket BuildPacket(Session session, int resultCode, ulong groupId, int numMembers)
{
byte[] data = new byte[PACKET_SIZE - 0x20];
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
binWriter.Write((UInt32) resultCode);
binWriter.Write((UInt64) groupId);
binWriter.Write((UInt32) numMembers);
}
}
return new SubPacket(true, OPCODE, 0, session.sessionId, data);
}
}
}

View File

@ -1,29 +0,0 @@
using FFXIVClassic.Common;
using FFXIVClassic_World_Server.DataObjects;
using System;
using System.IO;
namespace FFXIVClassic_World_Server.Packets.WorldPackets.Send.Group
{
class GroupWorkValuesPacket
{
public const ushort OPCODE = 0x1023;
public const uint PACKET_SIZE = 0x80;
public static SubPacket BuildPacket(Session session, ulong groupId)
{
byte[] data = new byte[PACKET_SIZE - 0x20];
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
binWriter.Write((UInt64)groupId);
//Write data
}
}
return new SubPacket(true, OPCODE, 0, session.sessionId, data);
}
}
}

View File

@ -199,6 +199,24 @@ namespace FFXIVClassic_World_Server
GetWorldManager().DoZoneServerChange(session, zoneChangePacket.destinationZoneId, "", zoneChangePacket.destinationSpawnType, zoneChangePacket.destinationX, zoneChangePacket.destinationY, zoneChangePacket.destinationZ, zoneChangePacket.destinationRot); GetWorldManager().DoZoneServerChange(session, zoneChangePacket.destinationZoneId, "", zoneChangePacket.destinationSpawnType, zoneChangePacket.destinationX, zoneChangePacket.destinationY, zoneChangePacket.destinationZ, zoneChangePacket.destinationRot);
} }
break;
//Change leader or kick
case 0x1020:
PartyModifyPacket partyModifyPacket = new PartyModifyPacket(subpacket.data);
Party pt = mWorldManager.GetPartyManager().GetParty(subpacket.header.targetId);
if (pt.GetMemberCount() <= 1)
return;
if (partyModifyPacket.command == PartyModifyPacket.MODIFY_LEADER)
pt.SetLeaderPlayerRequest(GetSession(subpacket.header.sourceId), partyModifyPacket.name);
else if (partyModifyPacket.command == PartyModifyPacket.MODIFY_KICKPLAYER)
pt.KickPlayerRequest(GetSession(subpacket.header.sourceId), partyModifyPacket.name);
break;
//Party Resign or Disband
case 0x1021:
break; break;
//Linkshell create request //Linkshell create request
case 0x1025: case 0x1025:

View File

@ -212,13 +212,13 @@ namespace FFXIVClassic_World_Server
//Send party, retainer, ls groups //Send party, retainer, ls groups
Party pt = mPartyManager.GetParty(session.sessionId); Party pt = mPartyManager.GetParty(session.sessionId);
if (session.sessionId == 0x6c)
{
mPartyManager.AddToParty(pt.groupIndex, 156); mPartyManager.AddToParty(pt.groupIndex, 156);
mPartyManager.AddToParty(pt.groupIndex, 157); }
mPartyManager.AddToParty(pt.groupIndex, 158);
mPartyManager.AddToParty(pt.groupIndex, 159);
mPartyManager.AddToParty(pt.groupIndex, 160);
mPartyManager.AddToParty(pt.groupIndex, 161);
mPartyManager.AddToParty(pt.groupIndex, 162);
pt.SendGroupPackets(session); pt.SendGroupPackets(session);
SendPartySync(pt); SendPartySync(pt);
mRetainerGroupManager.GetRetainerGroup(session.sessionId).SendGroupPackets(session); mRetainerGroupManager.GetRetainerGroup(session.sessionId).SendGroupPackets(session);
@ -239,11 +239,17 @@ namespace FFXIVClassic_World_Server
public void SendPartySync(Party party) public void SendPartySync(Party party)
{ {
List<ZoneServer> alreadySent = new List<ZoneServer>();
foreach (uint member in party.members) foreach (uint member in party.members)
{ {
Session session = Server.GetServer().GetSession(member); Session session = Server.GetServer().GetSession(member);
if (session == null) if (session == null)
continue; continue;
if (alreadySent.Contains(session.routing1))
continue;
alreadySent.Add(session.routing1);
SubPacket syncPacket = PartySyncPacket.BuildPacket(session, party); SubPacket syncPacket = PartySyncPacket.BuildPacket(session, party);
session.routing1.SendPacket(syncPacket); session.routing1.SendPacket(syncPacket);
} }