Reworked the inventory system so that each inventory type is contained in it's own "Inventory" object. Also, fixed the Inventory packets being all malformed.

This commit is contained in:
Filip Maj 2016-02-13 14:12:05 -05:00
parent df2ac1fb32
commit 69b34fdce7
10 changed files with 187 additions and 223 deletions

View File

@ -16,6 +16,7 @@ using FFXIVClassic_Map_Server.common.EfficientHashTables;
using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.dataobjects;
using FFXIVClassic_Map_Server.packets.send.Actor.inventory;
using FFXIVClassic_Map_Server.actors.chara.player;
namespace FFXIVClassic_Lobby_Server
{
@ -451,9 +452,9 @@ namespace FFXIVClassic_Lobby_Server
}
}
player.invNormal = getInventory(player, 0, InventorySetBeginPacket.CODE_INVENTORY);
player.invKeyItems = getInventory(player, 0, InventorySetBeginPacket.CODE_KEYITEMS);
player.invCurrancy = getInventory(player, 0, InventorySetBeginPacket.CODE_CURRANCY);
player.inventories[Inventory.NORMAL].initList(getInventory(player, 0, Inventory.NORMAL));
player.inventories[Inventory.KEYITEMS].initList(getInventory(player, 0, Inventory.KEYITEMS));
player.inventories[Inventory.CURRANCY].initList(getInventory(player, 0, Inventory.CURRANCY));
}
catch (MySqlException e)
@ -575,7 +576,7 @@ namespace FFXIVClassic_Lobby_Server
cmd.Parameters.AddWithValue("@durability", durability);
cmd.ExecuteNonQuery();
insertedItem = new Item((uint)cmd.LastInsertedId, itemId, quantity, (uint)player.getLastInventorySlot(type), isUntradeable, quality, durability, 0, 0, 0, 0, 0, 0);
insertedItem = new Item((uint)cmd.LastInsertedId, itemId, quantity, (uint)player.inventories[type].getNextEmptySlot(), isUntradeable, quality, durability, 0, 0, 0, 0, 0, 0);
}
catch (MySqlException e)
{ Console.WriteLine(e); }
@ -588,7 +589,7 @@ namespace FFXIVClassic_Lobby_Server
return insertedItem;
}
public static void addQuantity(Player player, uint itemId, int quantity)
public static void addQuantity(Player player, uint slot, int quantity)
{
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)))
{
@ -599,13 +600,13 @@ namespace FFXIVClassic_Lobby_Server
string query = @"
UPDATE characters_inventory
SET quantity = quantity + @quantity
WHERE serverItemId = (SELECT id FROM server_items WHERE characterId = @charId AND itemId = @itemId LIMIT 1)
WHERE serverItemId = (SELECT id FROM server_items WHERE characterId = @charId AND slot = @slot LIMIT 1)
";
MySqlCommand cmd = new MySqlCommand(query, conn);
cmd.Parameters.AddWithValue("@charId", player.actorId);
cmd.Parameters.AddWithValue("@quantity", quantity);
cmd.Parameters.AddWithValue("@itemId", itemId);
cmd.Parameters.AddWithValue("@slot", slot);
cmd.ExecuteNonQuery();
}

View File

@ -65,6 +65,7 @@
<Compile Include="actors\area\Zone.cs" />
<Compile Include="actors\chara\npc\NpcWork.cs" />
<Compile Include="actors\chara\AetheryteWork.cs" />
<Compile Include="actors\chara\player\Inventory.cs" />
<Compile Include="actors\chara\Work.cs" />
<Compile Include="actors\debug\Debug.cs" />
<Compile Include="actors\director\WeatherDirector.cs" />

View File

@ -16,6 +16,7 @@ using FFXIVClassic_Map_Server.packets.send;
using FFXIVClassic_Map_Server.dataobjects.chara;
using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.lua;
using FFXIVClassic_Map_Server.actors.chara.player;
namespace FFXIVClassic_Lobby_Server
{
@ -411,14 +412,14 @@ namespace FFXIVClassic_Lobby_Server
if (client != null)
{
Player p = client.getActor();
p.addItem(itemId, 0, 1, 1);
p.inventories[Inventory.NORMAL].addItem(itemId, 0, 1, 1);
}
else
{
foreach (KeyValuePair<uint, ConnectedPlayer> entry in mConnectedPlayerList)
{
Player p = entry.Value.getActor();
p.addItem(itemId, 0, 1, 1);
p.inventories[Inventory.NORMAL].addItem(itemId, 0, 1, 1);
}
}
}

View File

@ -0,0 +1,160 @@
using FFXIVClassic_Lobby_Server;
using FFXIVClassic_Lobby_Server.packets;
using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.dataobjects;
using FFXIVClassic_Map_Server.packets.send.actor.inventory;
using FFXIVClassic_Map_Server.packets.send.Actor.inventory;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_Map_Server.actors.chara.player
{
class Inventory
{
public const ushort NORMAL = 0x0000; //Max 0xC8
public const ushort LOOT = 0x0004; //Max 0xA
public const ushort MELDREQUEST = 0x0005; //Max 0x04
public const ushort BAZAAR = 0x0007; //Max 0x0A
public const ushort CURRANCY = 0x0063; //Max 0x140
public const ushort KEYITEMS = 0x0064; //Max 0x500
public const ushort EQUIPMENT = 0x00FE; //Max 0x23
private Player owner;
private ushort inventoryCapacity;
private ushort inventoryCode;
private List<Item> list;
public Inventory(Player ownerPlayer, ushort capacity, ushort code)
{
owner = ownerPlayer;
inventoryCapacity = capacity;
inventoryCode = code;
}
#region Inventory Management
public void initList(List<Item> itemsFromDB)
{
list = itemsFromDB;
}
public void addItem(uint itemId, ushort type, int quantity, byte quality)
{
List<SubPacket> addItemPackets = new List<SubPacket>();
Item storedItem = null;
//Check if item id exists
foreach (Item item in list)
{
if (item.itemId == itemId && item.quantity < 99)
{
storedItem = item;
break;
}
}
//If it's unique, abort
// if (storedItem != null && storedItem.isUnique)
// return ITEMERROR_UNIQUE;
//If Inventory is full
// if (storedItem == null && isInventoryFull())
// return ITEMERROR_FULL;
//Update lists and db
owner.queuePacket(InventoryBeginChangePacket.buildPacket(owner.actorId));
owner.queuePacket(InventorySetBeginPacket.buildPacket(owner.actorId, inventoryCapacity, inventoryCode));
if (storedItem == null)
{
Item addedItem = Database.addItem(owner, itemId, quantity, quality, false, 100, type);
list.Add(addedItem);
sendInventoryPackets(addedItem);
}
else
{
Database.addQuantity(owner, storedItem.slot, quantity);
storedItem.quantity += quantity;
sendInventoryPackets(storedItem);
}
owner.queuePacket(InventorySetEndPacket.buildPacket(owner.actorId));
owner.queuePacket(InventoryEndChangePacket.buildPacket(owner.actorId));
}
public void removeItem(uint itemId, uint quantity)
{
}
public void changeDurability(uint slot, uint durabilityChange)
{
}
public void changeSpiritBind(uint slot, uint spiritBindChange)
{
}
public void changeMateria(uint slot, byte materiaSlot, byte materiaId)
{
}
#endregion
#region Packet Functions
public void sendFullInventory()
{
owner.queuePacket(InventorySetBeginPacket.buildPacket(owner.actorId, inventoryCapacity, inventoryCode));
sendInventoryPackets(list);
owner.queuePacket(InventorySetEndPacket.buildPacket(owner.actorId));
}
private void sendInventoryPackets(Item item)
{
owner.queuePacket(InventoryListX01Packet.buildPacket(owner.actorId, item));
}
private void sendInventoryPackets(List<Item> items)
{
int currentIndex = 0;
while (true)
{
if (items.Count - currentIndex >= 64)
owner.queuePacket(InventoryListX64Packet.buildPacket(owner.actorId, items, ref currentIndex));
else if (items.Count - currentIndex >= 32)
owner.queuePacket(InventoryListX32Packet.buildPacket(owner.actorId, items, ref currentIndex));
else if (items.Count - currentIndex >= 16)
owner.queuePacket(InventoryListX16Packet.buildPacket(owner.actorId, items, ref currentIndex));
else if (items.Count - currentIndex > 1)
owner.queuePacket(InventoryListX08Packet.buildPacket(owner.actorId, items, ref currentIndex));
else if (items.Count - currentIndex == 1)
{
owner.queuePacket(InventoryListX01Packet.buildPacket(owner.actorId, items[currentIndex]));
currentIndex++;
}
else
break;
}
}
#endregion
#region Inventory Utils
public bool isFull()
{
return list.Count >= inventoryCapacity;
}
public int getNextEmptySlot()
{
return list.Count == 0 ? 0 : list.Count();
}
#endregion
}
}

View File

@ -2,6 +2,7 @@
using FFXIVClassic_Lobby_Server.common;
using FFXIVClassic_Lobby_Server.packets;
using FFXIVClassic_Map_Server.actors.area;
using FFXIVClassic_Map_Server.actors.chara.player;
using FFXIVClassic_Map_Server.dataobjects;
using FFXIVClassic_Map_Server.dataobjects.chara;
using FFXIVClassic_Map_Server.lua;
@ -60,12 +61,7 @@ namespace FFXIVClassic_Map_Server.Actors
public uint currentTitle;
//Inventory
public List<Item> invNormal = new List<Item>();
public List<Item> invCurrancy = new List<Item>();
public List<Item> invKeyItems = new List<Item>();
public List<Item> invLoot = new List<Item>();
public List<Item> invMeldRequest = new List<Item>();
public List<Item> invBazaar = new List<Item>();
public Dictionary<ushort, Inventory> inventories = new Dictionary<ushort, Inventory>();
public int[] invEquipment = new int[MAXSIZE_INVENTORY_EQUIPMENT];
//GC Related
@ -99,6 +95,10 @@ namespace FFXIVClassic_Map_Server.Actors
className = "Player";
currentSubState = SetActorStatePacket.SUB_STATE_PLAYER;
inventories[Inventory.NORMAL] = new Inventory(this, MAXSIZE_INVENTORY_NORMAL, Inventory.NORMAL);
inventories[Inventory.KEYITEMS] = new Inventory(this, MAXSIZE_INVENTORY_KEYITEMS, Inventory.KEYITEMS);
inventories[Inventory.CURRANCY] = new Inventory(this, MAXSIZE_INVENTORY_CURRANCY, Inventory.CURRANCY);
charaWork.property[0] = 1;
charaWork.property[1] = 1;
charaWork.property[2] = 1;
@ -429,57 +429,8 @@ namespace FFXIVClassic_Map_Server.Actors
playerSession.queuePacket(partyListPacket);
#endregion
#region itemsetup
////////ITEMS////////
queuePacket(InventoryBeginChangePacket.buildPacket(actorId));
queuePacket(InventorySetBeginPacket.buildPacket(actorId, 200, InventorySetBeginPacket.CODE_INVENTORY));
sendInventoryPackets(invNormal);
queuePacket(InventorySetEndPacket.buildPacket(actorId));
/*
//TEST
List<Item> items = new List<Item>();
items.Add(new Item(1337, 8030920, 0)); //Leather Jacket
items.Add(new Item(1338, 8013626, 1)); //Chocobo Mask
items.Add(new Item(1339, 5030402, 2)); //Thyrus
items.Add(new Item(1340, 8013635, 3)); //Dalamud Horn
items.Add(new Item(1341, 10100132, 4)); //Savage Might 4
items.Add(new Item(1342, 8032407, 5)); //Green Summer Halter (Female)
//items.Add(new Item(1343, 8051307, 6)); //Green Summer Tanga (Female)
int count = 0;
items[2].quality = 2;
items[0].durability = 9999;
items[0].spiritbind = 10000;
items[0].materia1 = 6;
items[0].materia2 = 7;
items[0].materia3 = 8;
items[0].materia4 = 9;
items[0].materia5 = 10;
items[1].durability = 9999;
items[2].durability = 0xFFFFFFF;
items[3].durability = 9999;
items[4].quantity = 99;
List<SubPacket> packets = new List<SubPacket>();
packets.Add(InventorySetBeginPacket.buildPacket(actorId, 200, InventorySetBeginPacket.CODE_INVENTORY));
packets.Add(InventoryListX08Packet.buildPacket(actorId, items,ref count));
packets.Add(InventorySetEndPacket.buildPacket(actorId));
Item i = new Item(1343, 8051307, 0);
packets.Add(InventorySetBeginPacket.buildPacket(actorId, 0x500, InventorySetBeginPacket.CODE_KEYITEMS));
packets.Add(InventoryListX01Packet.buildPacket(actorId, i));
packets.Add(InventorySetEndPacket.buildPacket(actorId));
BasePacket testPacket = BasePacket.createPacket(packets, true, false);
testPacket.debugPrintPacket();
playerSession.queuePacket(testPacket);
*/
#endregion
inventories[Inventory.NORMAL].sendFullInventory();
#region equipsetup
EquipmentListX08Packet initialEqupmentPacket = new EquipmentListX08Packet();
initialEqupmentPacket.setItem(EquipmentListX08Packet.SLOT_BODY, 5);
@ -492,13 +443,9 @@ namespace FFXIVClassic_Map_Server.Actors
//Equip Init
// playerSession.queuePacket(InventorySetBeginPacket.buildPacket(actorId, 0x23, InventorySetBeginPacket.CODE_EQUIPMENT), true, false);
// playerSession.queuePacket(BasePacket.createPacket(initialEqupmentPacket.buildPackets(actorId), true, false));
// playerSession.queuePacket(InventorySetEndPacket.buildPacket(actorId), true, false);
playerSession.queuePacket(InventoryEndChangePacket.buildPacket(actorId), true, false);
////////ITEMS////////
// playerSession.queuePacket(InventorySetEndPacket.buildPacket(actorId), true, false);
#endregion
playerSession.queuePacket(InventoryEndChangePacket.buildPacket(actorId), true, false);
playerSession.queuePacket(getInitPackets(actorId));
@ -520,36 +467,6 @@ namespace FFXIVClassic_Map_Server.Actors
}
private void sendInventoryPackets(Item item)
{
queuePacket(InventoryListX01Packet.buildPacket(actorId, item));
}
private void sendInventoryPackets(List<Item> items)
{
int currentIndex = 0;
while (true)
{
if (items.Count - currentIndex >= 64)
queuePacket(InventoryListX64Packet.buildPacket(actorId, items, ref currentIndex));
else if (items.Count - currentIndex >= 32)
queuePacket(InventoryListX32Packet.buildPacket(actorId, items, ref currentIndex));
else if (items.Count - currentIndex >= 16)
queuePacket(InventoryListX16Packet.buildPacket(actorId, items, ref currentIndex));
else if (items.Count - currentIndex <= 8 && items.Count - currentIndex > 1)
queuePacket(InventoryListX08Packet.buildPacket(actorId, items, ref currentIndex));
else if (items.Count - currentIndex == 1)
{
queuePacket(InventoryListX01Packet.buildPacket(actorId, items[currentIndex]));
currentIndex++;
}
else
break;
}
}
private void sendRemoveInventoryPackets(List<ushort> slots)
{
int currentIndex = 0;
@ -716,94 +633,6 @@ namespace FFXIVClassic_Map_Server.Actors
//zone.broadcastPacketAroundActor(this, worldMasterMessage);
}
public void addItem(uint itemId, ushort type, int quantity, byte quality)
{
List<SubPacket> addItemPackets = new List<SubPacket>();
Item storedItem = null;
//Check if item id exists
switch (type)
{
case InventorySetBeginPacket.CODE_INVENTORY:
foreach (Item item in invNormal)
{
if (item.itemId == itemId)
{
storedItem = item;
break;
}
}
break;
case InventorySetBeginPacket.CODE_KEYITEMS:
break;
case InventorySetBeginPacket.CODE_CURRANCY:
break;
case InventorySetBeginPacket.CODE_MELDREQUEST:
break;
case InventorySetBeginPacket.CODE_BAZAAR:
break;
case InventorySetBeginPacket.CODE_LOOT:
break;
}
//Update lists and db
queuePacket(InventoryBeginChangePacket.buildPacket(actorId));
switch (type)
{
case InventorySetBeginPacket.CODE_INVENTORY:
queuePacket(InventorySetBeginPacket.buildPacket(actorId, 200, InventorySetBeginPacket.CODE_INVENTORY));
if (storedItem == null)
{
Item addedItem = Database.addItem(this, itemId, quantity, quality, false, 100, type);
invNormal.Add(addedItem);
sendInventoryPackets(addedItem);
}
else
{
Database.addQuantity(this, itemId, quantity);
storedItem.quantity += quantity;
sendInventoryPackets(storedItem);
}
queuePacket(InventorySetEndPacket.buildPacket(actorId));
break;
case InventorySetBeginPacket.CODE_KEYITEMS:
break;
case InventorySetBeginPacket.CODE_CURRANCY:
break;
case InventorySetBeginPacket.CODE_MELDREQUEST:
break;
case InventorySetBeginPacket.CODE_BAZAAR:
break;
case InventorySetBeginPacket.CODE_LOOT:
break;
}
//addItemPackets.Add(InventorySetBeginPacket.buildPacket(actorId, MAXSIZE_INVENTORY_NORMAL, type));
//sendInventoryPackets()
queuePacket(InventorySetEndPacket.buildPacket(actorId));
}
public void removeItem(uint itemId, uint quantity)
{
}
public void changeDurability(uint slot, uint durabilityChange)
{
}
public void changeSpiritBind(uint slot, uint spiritBindChange)
{
}
public void changeMateria(uint slot, byte materiaSlot, byte materiaId)
{
}
public void runEventFunction(string functionName, params object[] parameters)
{
List<LuaParam> lParams = LuaUtils.createLuaParamList(parameters);
@ -845,25 +674,5 @@ namespace FFXIVClassic_Map_Server.Actors
}
public int getLastInventorySlot(ushort type)
{
switch (type)
{
case InventorySetBeginPacket.CODE_INVENTORY:
return invNormal.Count == 0 ? 0 : invNormal.Count() + 1;
case InventorySetBeginPacket.CODE_KEYITEMS:
return invKeyItems.Count == 0 ? 0 : invKeyItems.Count() + 1;
case InventorySetBeginPacket.CODE_CURRANCY:
return invCurrancy.Count == 0 ? 0 : invCurrancy.Count() + 1;
case InventorySetBeginPacket.CODE_MELDREQUEST:
return invMeldRequest.Count == 0 ? 0 : invMeldRequest.Count() + 1;
case InventorySetBeginPacket.CODE_BAZAAR:
return invBazaar.Count == 0 ? 0 : invBazaar.Count() + 1;
case InventorySetBeginPacket.CODE_LOOT:
return invLoot.Count == 0 ? 0 : invLoot.Count() + 1;
}
return 0;
}
}
}

View File

@ -28,9 +28,9 @@ namespace FFXIVClassic_Map_Server.packets.send.actor.inventory
else
max = 8;
for (int i = listOffset; i < max; i++)
for (int i = 0; i < max; i++)
{
binWriter.Write(items[i].toPacketBytes());
binWriter.Write(items[listOffset].toPacketBytes());
listOffset++;
}

View File

@ -28,7 +28,7 @@ namespace FFXIVClassic_Map_Server.packets.send.actor.inventory
else
max = 16;
for (int i = listOffset; i < items.Count; i++)
for (int i = 0; i < max; i++)
{
binWriter.Write(items[i].toPacketBytes());
listOffset++;

View File

@ -28,7 +28,7 @@ namespace FFXIVClassic_Map_Server.packets.send.actor.inventory
else
max = 32;
for (int i = listOffset; i < items.Count; i++)
for (int i = 0; i < max; i++)
{
binWriter.Write(items[i].toPacketBytes());
listOffset++;

View File

@ -28,7 +28,7 @@ namespace FFXIVClassic_Map_Server.packets.send.actor.inventory
else
max = 64;
for (int i = listOffset; i < max; i++)
for (int i = 0; i < max; i++)
{
binWriter.Write(items[i].toPacketBytes());
listOffset++;

View File

@ -13,14 +13,6 @@ namespace FFXIVClassic_Map_Server.packets.send.Actor.inventory
public const ushort OPCODE = 0x0146;
public const uint PACKET_SIZE = 0x28;
public const ushort CODE_INVENTORY = 0x0000; //Max 0xC8
public const ushort CODE_LOOT = 0x0004; //Max 0xA
public const ushort CODE_MELDREQUEST = 0x0005; //Max 0x04
public const ushort CODE_BAZAAR = 0x0007; //Max 0x0A
public const ushort CODE_CURRANCY = 0x0063; //Max 0x140
public const ushort CODE_KEYITEMS = 0x0064; //Max 0x500
public const ushort CODE_EQUIPMENT = 0x00FE; //Max 0x23
public static SubPacket buildPacket(uint playerActorID, ushort size, ushort code)
{
byte[] data = new byte[8];