diff --git a/.gitignore b/.gitignore
index f01e314a..d03fb113 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,3 +10,5 @@ Blowfish/Debug/
Debug/
FFXIVClassic_Lobby_Server.opensdf
FFXIVClassic_Lobby_Server.sdf
+FFXIVClassic Lobby Server/obj/
+FFXIVClassic Lobby Server/bin/
diff --git a/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj b/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj
index 56e0932c..eee44060 100644
--- a/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj
+++ b/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj
@@ -115,6 +115,7 @@
+
diff --git a/FFXIVClassic Map Server/PacketProcessor.cs b/FFXIVClassic Map Server/PacketProcessor.cs
index 37233416..2632cc4c 100644
--- a/FFXIVClassic Map Server/PacketProcessor.cs
+++ b/FFXIVClassic Map Server/PacketProcessor.cs
@@ -277,6 +277,9 @@ namespace FFXIVClassic_Lobby_Server
break;
case 0x012F:
subpacket.debugPrintSubPacket();
+ ParameterDataRequestPacket paramRequest = new ParameterDataRequestPacket(subpacket.data);
+ if (paramRequest.paramName.Equals("charaWork/exp"))
+ player.getActor().sendCharaExpInfo();
break;
/* RECRUITMENT */
//Start Recruiting
diff --git a/FFXIVClassic Map Server/actors/chara/player/Player.cs b/FFXIVClassic Map Server/actors/chara/player/Player.cs
index fc6e9a60..c830cc61 100644
--- a/FFXIVClassic Map Server/actors/chara/player/Player.cs
+++ b/FFXIVClassic Map Server/actors/chara/player/Player.cs
@@ -26,6 +26,27 @@ namespace FFXIVClassic_Map_Server.Actors
{
class Player : Character
{
+ public const int CLASSID_PUG = 2;
+ public const int CLASSID_GLA = 3;
+ public const int CLASSID_MRD = 4;
+ public const int CLASSID_ARC = 7;
+ public const int CLASSID_LNC = 8;
+ public const int CLASSID_THM = 22;
+ public const int CLASSID_CNJ = 23;
+
+ public const int CLASSID_CRP = 29;
+ public const int CLASSID_BSM = 30;
+ public const int CLASSID_ARM = 31;
+ public const int CLASSID_GSM = 32;
+ public const int CLASSID_LTW = 33;
+ public const int CLASSID_WVR = 34;
+ public const int CLASSID_ALC = 35;
+ public const int CLASSID_CUL = 36;
+
+ public const int CLASSID_MIN = 39;
+ public const int CLASSID_BTN = 40;
+ public const int CLASSID_FSH = 41;
+
public const int MAXSIZE_INVENTORY_NORMAL = 200;
public const int MAXSIZE_INVENTORY_CURRANCY = 320;
public const int MAXSIZE_INVENTORY_KEYITEMS = 500;
@@ -93,6 +114,10 @@ namespace FFXIVClassic_Map_Server.Actors
public uint achievementPoints;
+ //Property Array Request Stuff
+ private int lastPosition = 0;
+ private int lastStep = 0;
+
public PlayerWork playerWork = new PlayerWork();
public ConnectedPlayer playerSession;
@@ -113,6 +138,39 @@ namespace FFXIVClassic_Map_Server.Actors
equipment = new Equipment(this, inventories[Inventory.NORMAL], MAXSIZE_INVENTORY_EQUIPMENT, Inventory.EQUIPMENT);
+ //Set the Skill level caps of all FFXIV (classes)skills to 50
+ for (int i = 0; i < charaWork.battleSave.skillLevelCap.Length; i++)
+ {
+ if (i != CLASSID_PUG &&
+ i != CLASSID_MRD &&
+ i != CLASSID_GLA &&
+ i != CLASSID_MRD &&
+ i != CLASSID_ARC &&
+ i != CLASSID_LNC &&
+ i != CLASSID_THM &&
+ i != CLASSID_CNJ &&
+ i != CLASSID_CRP &&
+ i != CLASSID_BSM &&
+ i != CLASSID_ARM &&
+ i != CLASSID_GSM &&
+ i != CLASSID_LTW &&
+ i != CLASSID_WVR &&
+ i != CLASSID_ALC &&
+ i != CLASSID_CUL &&
+ i != CLASSID_MIN &&
+ i != CLASSID_BTN &&
+ i != CLASSID_FSH)
+ charaWork.battleSave.skillLevelCap[i] = 0xFF;
+ else
+ charaWork.battleSave.skillLevelCap[i] = 50;
+
+ }
+
+ charaWork.battleSave.skillLevel[CLASSID_GLA - 1] = 32;
+ charaWork.battleSave.skillLevel[CLASSID_PUG - 1] = 50;
+ charaWork.battleSave.skillLevel[CLASSID_THM - 1] = 5;
+ charaWork.battleSave.skillLevel[CLASSID_MRD - 1] = 42;
+
charaWork.property[0] = 1;
charaWork.property[1] = 1;
charaWork.property[2] = 1;
@@ -718,7 +776,67 @@ namespace FFXIVClassic_Map_Server.Actors
public void sendCharaExpInfo()
{
+ if (lastStep == 0)
+ {
+ int maxLength;
+ if ((sizeof(short) * charaWork.battleSave.skillLevel.Length)-lastPosition < 0x5E)
+ maxLength = (sizeof(short) * charaWork.battleSave.skillLevel.Length) - lastPosition;
+ else
+ maxLength = 0x5E;
+ byte[] skillLevelBuffer = new byte[maxLength];
+ Buffer.BlockCopy(charaWork.battleSave.skillLevel, 0, skillLevelBuffer, 0, skillLevelBuffer.Length);
+ SetActorPropetyPacket charaInfo1 = new SetActorPropetyPacket("charaWork/exp");
+
+ charaInfo1.setIsArrayMode(true);
+ if (maxLength == 0x5E)
+ {
+ charaInfo1.addBuffer(Utils.MurmurHash2("charaWork.battleSave.skillLevel", 0), skillLevelBuffer, 0, skillLevelBuffer.Length, 0x0);
+ lastPosition += maxLength;
+ }
+ else
+ {
+ charaInfo1.addBuffer(Utils.MurmurHash2("charaWork.battleSave.skillLevel", 0), skillLevelBuffer, 0, skillLevelBuffer.Length, 0x3);
+ lastPosition = 0;
+ lastStep++;
+ }
+
+ charaInfo1.addTarget();
+
+ queuePacket(charaInfo1.buildPacket(actorId, actorId));
+ }
+ else if (lastStep == 1)
+ {
+ int maxLength;
+ if ((sizeof(short) * charaWork.battleSave.skillLevelCap.Length) - lastPosition < 0x5E)
+ maxLength = (sizeof(short) * charaWork.battleSave.skillLevelCap.Length) - lastPosition;
+ else
+ maxLength = 0x5E;
+
+ byte[] skillCapBuffer = new byte[maxLength];
+ Buffer.BlockCopy(charaWork.battleSave.skillLevelCap, lastPosition, skillCapBuffer, 0, skillCapBuffer.Length);
+ SetActorPropetyPacket charaInfo1 = new SetActorPropetyPacket("charaWork/exp");
+
+
+ if (maxLength == 0x5E)
+ {
+ charaInfo1.setIsArrayMode(true);
+ charaInfo1.addBuffer(Utils.MurmurHash2("charaWork.battleSave.skillLevelCap", 0), skillCapBuffer, 0, skillCapBuffer.Length, 0x1);
+ lastPosition += maxLength;
+ }
+ else
+ {
+ charaInfo1.setIsArrayMode(false);
+ charaInfo1.addBuffer(Utils.MurmurHash2("charaWork.battleSave.skillLevelCap", 0), skillCapBuffer, 0, skillCapBuffer.Length, 0x3);
+ lastStep = 0;
+ lastPosition = 0;
+ }
+
+ charaInfo1.addTarget();
+
+ queuePacket(charaInfo1.buildPacket(actorId, actorId));
+ }
+
}
public InventoryItem[] getGearset(ushort classId)
diff --git a/FFXIVClassic Map Server/packets/receive/ParameterDataRequestPacket.cs b/FFXIVClassic Map Server/packets/receive/ParameterDataRequestPacket.cs
new file mode 100644
index 00000000..7413feb8
--- /dev/null
+++ b/FFXIVClassic Map Server/packets/receive/ParameterDataRequestPacket.cs
@@ -0,0 +1,43 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FFXIVClassic_Map_Server.packets.receive
+{
+ class ParameterDataRequestPacket
+ {
+ public const ushort OPCODE = 0x012F;
+ public const uint PACKET_SIZE = 0x48;
+
+ public bool invalidPacket = false;
+
+ public uint actorID;
+ public string paramName;
+
+ public ParameterDataRequestPacket(byte[] data)
+ {
+ using (MemoryStream mem = new MemoryStream(data))
+ {
+ using (BinaryReader binReader = new BinaryReader(mem))
+ {
+ try{
+ actorID = binReader.ReadUInt32();
+ List strList = new List();
+ byte curByte;
+ while ((curByte = binReader.ReadByte()) != 0 && strList.Count<=0x20)
+ {
+ strList.Add(curByte);
+ }
+ paramName = Encoding.ASCII.GetString(strList.ToArray());
+ }
+ catch (Exception){
+ invalidPacket = true;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/FFXIVClassic Map Server/packets/send/Actor/SetActorPropetyPacket.cs b/FFXIVClassic Map Server/packets/send/Actor/SetActorPropetyPacket.cs
index afb787ac..fc4c85c4 100644
--- a/FFXIVClassic Map Server/packets/send/Actor/SetActorPropetyPacket.cs
+++ b/FFXIVClassic Map Server/packets/send/Actor/SetActorPropetyPacket.cs
@@ -20,6 +20,8 @@ namespace FFXIVClassic_Map_Server.packets.send.actor
private ushort runningByteTotal = 0;
private byte[] data = new byte[PACKET_SIZE - 0x20];
+
+ private bool isArrayMode = false;
private bool isMore = false;
string currentTarget;
@@ -93,6 +95,20 @@ namespace FFXIVClassic_Map_Server.packets.send.actor
return true;
}
+ public bool addBuffer(uint id, byte[] buffer, int index, int length, int page)
+ {
+ if (runningByteTotal + 5 + length + (1 + Encoding.ASCII.GetByteCount(currentTarget)) > MAXBYTES)
+ return false;
+
+ binWriter.Write((byte)(length + 1));
+ binWriter.Write((UInt32)id);
+ binWriter.Write(buffer, index, length);
+ binWriter.Write((byte)page);
+ runningByteTotal += (ushort)(6 + length);
+
+ return true;
+ }
+
public bool addProperty(FFXIVClassic_Map_Server.Actors.Actor actor, string name)
{
string[] split = name.Split('.');
@@ -159,6 +175,11 @@ namespace FFXIVClassic_Map_Server.packets.send.actor
}
}
+ public void setIsArrayMode(bool flag)
+ {
+ isArrayMode = flag;
+ }
+
public void setIsMore(bool flag)
{
isMore = flag;
@@ -171,7 +192,10 @@ namespace FFXIVClassic_Map_Server.packets.send.actor
public void addTarget()
{
- binWriter.Write((byte)(isMore ? 0x60 + currentTarget.Length : 0x82 + currentTarget.Length));
+ if (isArrayMode)
+ binWriter.Write((byte)(0xA4 + currentTarget.Length));
+ else
+ binWriter.Write((byte)(isMore ? 0x60 + currentTarget.Length : 0x82 + currentTarget.Length));
binWriter.Write(Encoding.ASCII.GetBytes(currentTarget));
runningByteTotal += (ushort)(1 + Encoding.ASCII.GetByteCount(currentTarget));
}
diff --git a/FFXIVClassic Map Server/utils/ActorPropertyPacketUtil.cs b/FFXIVClassic Map Server/utils/ActorPropertyPacketUtil.cs
index f99a3640..be3e2f6b 100644
--- a/FFXIVClassic Map Server/utils/ActorPropertyPacketUtil.cs
+++ b/FFXIVClassic Map Server/utils/ActorPropertyPacketUtil.cs
@@ -12,11 +12,11 @@ namespace FFXIVClassic_Map_Server.utils
{
class ActorPropertyPacketUtil
{
- Actor forActor;
- uint playerActorId;
- List subPackets = new List();
- SetActorPropetyPacket currentActorPropertyPacket;
- string currentTarget;
+ private Actor forActor;
+ private uint playerActorId;
+ private List subPackets = new List();
+ private SetActorPropetyPacket currentActorPropertyPacket;
+ private string currentTarget;
public ActorPropertyPacketUtil(string firstTarget, Actor forActor, uint playerActorId)
{