1
Fork 0
mirror of https://bitbucket.org/Ioncannon/project-meteor-server.git synced 2025-04-21 20:27:47 +00:00

Merge branch 'inventory_overhaul' into retainers

This commit is contained in:
Filip Maj 2017-09-09 12:21:51 -04:00
commit 9529a1374e
8 changed files with 478 additions and 424 deletions

View file

@ -1225,7 +1225,6 @@ namespace FFXIVClassic_Map_Server
serverItemId,
itemId,
quantity,
slot,
itemType,
quality,
durability,
@ -1237,35 +1236,37 @@ namespace FFXIVClassic_Map_Server
materia5
FROM characters_inventory
INNER JOIN server_items ON serverItemId = server_items.id
WHERE characterId = @charId AND inventoryType = @type AND slot >= @slot ORDER BY slot";
WHERE characterId = @charId AND inventoryType = @type";
MySqlCommand cmd = new MySqlCommand(query, conn);
cmd.Parameters.AddWithValue("@charId", player.actorId);
cmd.Parameters.AddWithValue("@slot", slotOffset);
cmd.Parameters.AddWithValue("@type", type);
ushort slot = 0;
using (MySqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
uint uniqueId = reader.GetUInt32(0);
uint itemId = reader.GetUInt32(1);
int quantity = reader.GetInt32(2);
ushort slot = reader.GetUInt16(3);
uint uniqueId = reader.GetUInt32("serverItemId");
uint itemId = reader.GetUInt32("itemId");
int quantity = reader.GetInt32("quantity");
byte itemType = reader.GetByte(4);
byte qualityNumber = reader.GetByte(5);
byte itemType = reader.GetByte("itemType");
byte qualityNumber = reader.GetByte("quality");
int durability = reader.GetInt32(6);
ushort spiritBind = reader.GetUInt16(7);
int durability = reader.GetInt32("durability");
ushort spiritBind = reader.GetUInt16("spiritBind");
byte materia1 = reader.GetByte(8);
byte materia2 = reader.GetByte(9);
byte materia3 = reader.GetByte(10);
byte materia4 = reader.GetByte(11);
byte materia5 = reader.GetByte(12);
byte materia1 = reader.GetByte("materia1");
byte materia2 = reader.GetByte("materia2");
byte materia3 = reader.GetByte("materia3");
byte materia4 = reader.GetByte("materia4");
byte materia5 = reader.GetByte("materia5");
items.Add(new InventoryItem(uniqueId, itemId, quantity, slot, itemType, qualityNumber, durability, spiritBind, materia1, materia2, materia3, materia4, materia5));
InventoryItem item = new InventoryItem(uniqueId, itemId, quantity, itemType, qualityNumber, durability, spiritBind, materia1, materia2, materia3, materia4, materia5);
item.slot = slot;
slot++;
items.Add(item);
}
}
}
@ -1282,7 +1283,7 @@ namespace FFXIVClassic_Map_Server
return items;
}
public static InventoryItem AddItem(Player player, uint itemId, int quantity, byte quality, byte itemType, int durability, ushort type)
public static InventoryItem CreateItem(uint itemId, int quantity, byte quality, byte itemType, int durability)
{
InventoryItem insertedItem = null;
@ -1303,27 +1304,14 @@ namespace FFXIVClassic_Map_Server
MySqlCommand cmd = new MySqlCommand(query, conn);
string query2 = @"
INSERT INTO characters_inventory
(characterId, slot, inventoryType, serverItemId, quantity)
SELECT @charId, IFNULL(MAX(SLOT)+1, 0), @inventoryType, LAST_INSERT_ID(), @quantity FROM characters_inventory WHERE characterId = @charId AND inventoryType = @inventoryType;
";
MySqlCommand cmd2 = new MySqlCommand(query2, conn);
cmd.Parameters.AddWithValue("@itemId", itemId);
cmd.Parameters.AddWithValue("@quality", quality);
cmd.Parameters.AddWithValue("@itemType", itemType);
cmd.Parameters.AddWithValue("@durability", durability);
cmd2.Parameters.AddWithValue("@charId", player.actorId);
cmd2.Parameters.AddWithValue("@inventoryType", type);
cmd2.Parameters.AddWithValue("@quantity", quantity);
cmd.ExecuteNonQuery();
cmd2.ExecuteNonQuery();
insertedItem = new InventoryItem((uint)cmd.LastInsertedId, itemId, quantity, (ushort)player.GetInventory(type).GetNextEmptySlot(), itemType, quality, durability, 0, 0, 0, 0, 0, 0);
insertedItem = new InventoryItem((uint)cmd.LastInsertedId, itemId, quantity, itemType, quality, durability, 0, 0, 0, 0, 0, 0);
}
catch (MySqlException e)
{
@ -1338,7 +1326,42 @@ namespace FFXIVClassic_Map_Server
return insertedItem;
}
public static void SetQuantity(Player player, uint slot, ushort type, int quantity)
public static void AddItem(Player player, InventoryItem addedItem, uint type)
{
using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD)))
{
try
{
conn.Open();
string query = @"
INSERT INTO characters_inventory
(characterId, inventoryType, serverItemId, quantity)
VALUES
(@charId, @inventoryType, @serverItemId, @quantity)
";
MySqlCommand cmd = new MySqlCommand(query, conn);
cmd.Parameters.AddWithValue("@serverItemId", addedItem.uniqueId);
cmd.Parameters.AddWithValue("@charId", player.actorId);
cmd.Parameters.AddWithValue("@inventoryType", type);
cmd.Parameters.AddWithValue("@quantity", addedItem.quantity);
cmd.ExecuteNonQuery();
}
catch (MySqlException e)
{
Program.Log.Error(e.ToString());
}
finally
{
conn.Dispose();
}
}
}
public static void SetQuantity(Player player, ulong serverItemId, 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)))
{
@ -1349,54 +1372,13 @@ namespace FFXIVClassic_Map_Server
string query = @"
UPDATE characters_inventory
SET quantity = @quantity
WHERE characterId = @charId AND slot = @slot AND inventoryType = @type;
";
MySqlCommand cmd = new MySqlCommand(query, conn);
cmd.Parameters.AddWithValue("@charId", player.actorId);
cmd.Parameters.AddWithValue("@quantity", quantity);
cmd.Parameters.AddWithValue("@slot", slot);
cmd.Parameters.AddWithValue("@type", type);
cmd.ExecuteNonQuery();
}
catch (MySqlException e)
{
Program.Log.Error(e.ToString());
}
finally
{
conn.Dispose();
}
}
}
public static void RemoveItem(Player player, ulong serverItemId, ushort type)
{
using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}; Allow User Variables=True", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD)))
{
try
{
conn.Open();
string query = @"
SELECT slot INTO @slotToDelete FROM characters_inventory WHERE serverItemId = @serverItemId;
UPDATE characters_inventory
SET slot = slot - 1
WHERE characterId = @charId AND slot > @slotToDelete AND inventoryType = @type;
DELETE FROM characters_inventory
WHERE serverItemId = @serverItemId AND inventoryType = @type;
DELETE FROM server_items
WHERE id = @serverItemId;
WHERE characterId = @charId and serverItemId = @serverItemId;
";
MySqlCommand cmd = new MySqlCommand(query, conn);
cmd.Parameters.AddWithValue("@charId", player.actorId);
cmd.Parameters.AddWithValue("@serverItemId", serverItemId);
cmd.Parameters.AddWithValue("@type", type);
cmd.Parameters.AddWithValue("@quantity", quantity);
cmd.ExecuteNonQuery();
}
@ -1412,7 +1394,7 @@ namespace FFXIVClassic_Map_Server
}
public static void RemoveItem(Player player, ushort slot, ushort type)
public static void RemoveItem(Player player, ulong serverItemId)
{
using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}; Allow User Variables=True", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD)))
{
@ -1421,23 +1403,13 @@ namespace FFXIVClassic_Map_Server
conn.Open();
string query = @"
SELECT serverItemId INTO @serverItemId FROM characters_inventory WHERE characterId = @charId AND slot = @slot;
DELETE FROM characters_inventory
WHERE characterId = @charId AND slot = @slot AND inventoryType = @type;
DELETE FROM server_items
WHERE id = @serverItemId;
UPDATE characters_inventory
SET slot = slot - 1
WHERE characterId = @charId AND slot > @slot AND inventoryType = @type;
WHERE characterId = @charId and serverItemId = @serverItemId;
";
MySqlCommand cmd = new MySqlCommand(query, conn);
cmd.Parameters.AddWithValue("@charId", player.actorId);
cmd.Parameters.AddWithValue("@slot", slot);
cmd.Parameters.AddWithValue("@type", type);
cmd.Parameters.AddWithValue("@serverItemId", serverItemId);
cmd.ExecuteNonQuery();
}

View file

@ -182,8 +182,12 @@ namespace FFXIVClassic_Map_Server
if (ownerActor == null)
{
//Is it your retainer?
if (session.GetActor().currentSpawnedRetainer != null && session.GetActor().currentSpawnedRetainer.actorId == eventStart.scriptOwnerActorID)
ownerActor = session.GetActor().currentSpawnedRetainer;
//Is it a instance actor?
ownerActor = session.GetActor().zone.FindActorInArea(session.GetActor().currentEventOwner);
if (ownerActor == null)
ownerActor = session.GetActor().zone.FindActorInArea(session.GetActor().currentEventOwner);
if (ownerActor == null)
{
//Is it a Director?

View file

@ -1,5 +1,7 @@
using FFXIVClassic_Map_Server.actors.chara.player;
using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.actors.chara.player;
using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.packets.send.actor.inventory;
using System;
using System.Collections.Generic;
using System.Linq;
@ -10,22 +12,45 @@ namespace FFXIVClassic_Map_Server.actors.chara.npc
{
class Retainer : Npc
{
public Retainer(uint id, string retainerName, ActorClass actorClass, Player player, float posX, float posY, float posZ, float rot)
: base(0, actorClass, String.Format("_rtnre{0:x7}", id), player.GetZone(), posX, posY, posZ, rot, 0, 0, retainerName)
Player player;
public Retainer(string retainerName, ActorClass actorClass, Player player, float posX, float posY, float posZ, float rot)
: base(0, actorClass, "myretainer", player.GetZone(), posX, posY, posZ, rot, 0, 0, retainerName)
{
this.actorId = 0xD0000000 | id;
this.player = player;
this.actorName = String.Format("_rtnre{0:x7}", actorId);
}
public void SendBazaarItems(Player player)
{
Inventory bazaar = new Inventory(this, 4, Inventory.RETAINER_BAZAAR);
bazaar.SendFullInventory(player);
Inventory bazaar = new Inventory(this, 150, (ushort)0);
bazaar.AddItem(1000001);
bazaar.AddItem(3020517);
player.QueuePacket(InventoryBeginChangePacket.BuildPacket(actorId));
bazaar.SendFullInventory(player);
player.QueuePacket(InventoryEndChangePacket.BuildPacket(actorId));
}
public void SendStorageItems(Player player)
{
Inventory storage = new Inventory(this, 4, 1);
Inventory storage = new Inventory(this, 10, Inventory.CURRENCY);
storage.AddItem(1000001);
storage.AddItem(3020519);
player.QueuePacket(InventoryBeginChangePacket.BuildPacket(actorId));
storage.SendFullInventory(player);
player.QueuePacket(InventoryEndChangePacket.BuildPacket(actorId));
}
public void SendHuhItems(Player player)
{
Inventory storage = new Inventory(this, 20, 7);
storage.AddItem(1000003);
storage.AddItem(1000016);
player.QueuePacket(InventoryBeginChangePacket.BuildPacket(actorId));
storage.SendFullInventory(player);
player.QueuePacket(InventoryEndChangePacket.BuildPacket(actorId));
}
}
}

View file

@ -106,13 +106,13 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
for (int i = 0; i < slots.Length; i++)
{
InventoryItem item = normalInventory.GetItemBySlot(itemSlots[i]);
InventoryItem item = normalInventory.GetItemAtSlot(itemSlots[i]);
if (item == null)
continue;
Database.EquipItem(owner, slots[i], item.uniqueId);
list[slots[i]] = normalInventory.GetItemBySlot(itemSlots[i]);
list[slots[i]] = normalInventory.GetItemAtSlot(itemSlots[i]);
}
owner.QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.actorId));
@ -133,7 +133,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
public void Equip(ushort slot, ushort invSlot)
{
InventoryItem item = normalInventory.GetItemBySlot(invSlot);
InventoryItem item = normalInventory.GetItemAtSlot(invSlot);
if (item == null)
return;
@ -152,9 +152,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
owner.QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.actorId));
if (list[slot] != null)
normalInventory.RefreshItem(list[slot], item);
normalInventory.RefreshItem(owner, list[slot], item);
else
normalInventory.RefreshItem(item);
normalInventory.RefreshItem(owner, item);
owner.QueuePacket(InventorySetBeginPacket.BuildPacket(owner.actorId, inventoryCapacity, inventoryCode));
SendEquipmentPackets(slot, item);
@ -180,7 +180,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
owner.QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.actorId));
normalInventory.RefreshItem(list[slot]);
normalInventory.RefreshItem(owner, list[slot]);
owner.QueuePacket(InventorySetBeginPacket.BuildPacket(owner.actorId, inventoryCapacity, inventoryCode));
SendEquipmentPackets(slot, null);

View file

@ -1,10 +1,11 @@


using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.dataobjects;
using FFXIVClassic_Map_Server.packets.send.actor.inventory;
using System;
using System.Collections.Generic;
using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.dataobjects;
using FFXIVClassic_Map_Server.packets.send.actor.inventory;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace FFXIVClassic_Map_Server.actors.chara.player
@ -20,38 +21,50 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
public const ushort CURRENCY = 0x0063; //Max 0x140
public const ushort KEYITEMS = 0x0064; //Max 0x500
public const ushort EQUIPMENT = 0x00FE; //Max 0x23
public const ushort EQUIPMENT_OTHERPLAYER = 0x00F9; //Max 0x23
public const ushort EQUIPMENT_OTHERPLAYER = 0x00F9; //Max 0x23
private int endOfListIndex = 0;
private Player owner;
private Character owner;
private ushort inventoryCapacity;
private ushort inventoryCode;
private List<InventoryItem> list;
public Inventory(Player ownerPlayer, ushort capacity, ushort code)
private InventoryItem[] list;
private bool[] isDirty;
public Inventory(Character ownerPlayer, ushort capacity, ushort code)
{
owner = ownerPlayer;
inventoryCapacity = capacity;
inventoryCode = code;
inventoryCode = code;
list = new InventoryItem[capacity];
isDirty = new bool[capacity];
}
#region Inventory Management
public void InitList(List<InventoryItem> itemsFromDB)
{
list = itemsFromDB;
int i = 0;
foreach (InventoryItem item in itemsFromDB)
list[i++] = item;
endOfListIndex = i;
}
public InventoryItem GetItemBySlot(ushort slot)
public InventoryItem GetItemAtSlot(ushort slot)
{
if (slot < list.Count)
if (slot < list.Length)
return list[slot];
else
return null;
}
public InventoryItem GetItemByUniqueId(ulong uniqueItemId)
{
foreach (InventoryItem item in list)
{
for (int i = 0; i < endOfListIndex; i++)
{
InventoryItem item = list[i];
Debug.Assert(item != null, "Item slot was null!!!");
if (item.uniqueId == uniqueItemId)
return item;
}
@ -60,54 +73,35 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
public InventoryItem GetItemByCatelogId(ulong catelogId)
{
foreach (InventoryItem item in list)
for (int i = 0; i < endOfListIndex; i++)
{
InventoryItem item = list[i];
Debug.Assert(item != null, "Item slot was null!!!");
if (item.itemId == catelogId)
return item;
}
return null;
}
public void RefreshItem(InventoryItem item)
}
public bool AddItem(uint itemId)
{
owner.QueuePacket(InventorySetBeginPacket.BuildPacket(owner.actorId, inventoryCapacity, inventoryCode));
SendInventoryPackets(item);
owner.QueuePacket(InventorySetEndPacket.BuildPacket(owner.actorId));
}
public void RefreshItem(params InventoryItem[] items)
{
owner.QueuePacket(InventorySetBeginPacket.BuildPacket(owner.actorId, inventoryCapacity, inventoryCode));
SendInventoryPackets(items.ToList());
owner.QueuePacket(InventorySetEndPacket.BuildPacket(owner.actorId));
}
public void RefreshItem(List<InventoryItem> items)
{
owner.QueuePacket(InventorySetBeginPacket.BuildPacket(owner.actorId, inventoryCapacity, inventoryCode));
SendInventoryPackets(items);
owner.QueuePacket(InventorySetEndPacket.BuildPacket(owner.actorId));
}
public void AddItem(uint itemId)
{
AddItem(itemId, 1, 1);
}
public void AddItem(uint itemId, int quantity)
{
AddItem(itemId, quantity, 1);
return AddItem(itemId, 1, 1);
}
public bool AddItem(uint itemId, int quantity)
{
return AddItem(itemId, quantity, 1);
}
public bool AddItem(uint itemId, int quantity, byte quality)
{
if (!IsSpaceForAdd(itemId, quantity))
if (!IsSpaceForAdd(itemId, quantity, quality))
return false;
ItemData gItem = Server.GetItemGamedata(itemId);
List<ushort> slotsToUpdate = new List<ushort>();
List<SubPacket> addItemPackets = new List<SubPacket>();
if (gItem == null)
{
Program.Log.Error("Inventory.AddItem: unable to find item %u", itemId);
@ -115,16 +109,25 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
}
//Check if item id exists
int quantityCount = quantity;
for (int i = 0; i < list.Count; i++)
int quantityCount = quantity;
for (int i = 0; i < endOfListIndex; i++)
{
InventoryItem item = list[i];
if (item.itemId == itemId && item.quantity < gItem.maxStack)
InventoryItem item = list[i];
Debug.Assert(item != null, "Item slot was null!!!");
if (item.itemId == itemId && item.quality == quality && item.quantity < gItem.maxStack)
{
slotsToUpdate.Add(item.slot);
int oldQuantity = item.quantity;
item.quantity = Math.Min(item.quantity + quantityCount, gItem.maxStack);
quantityCount -= (gItem.maxStack - oldQuantity);
item.quantity = Math.Min(item.quantity + quantityCount, gItem.maxStack);
isDirty[i] = true;
quantityCount -= (gItem.maxStack - oldQuantity);
if (owner is Player)
{
Database.SetQuantity((Player)owner, item.uniqueId, item.quantity);
}
if (quantityCount <= 0)
break;
}
@ -136,71 +139,44 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
//If Inventory is full
//if (quantityCount > 0 && isInventoryFull())
// return ITEMERROR_FULL;
//Update lists and db
owner.QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.actorId));
owner.QueuePacket(InventorySetBeginPacket.BuildPacket(owner.actorId, inventoryCapacity, inventoryCode));
//These had their quantities Changed
foreach (ushort slot in slotsToUpdate)
{
Database.SetQuantity(owner, slot, inventoryCode, list[slot].quantity);
if (inventoryCode != CURRENCY && inventoryCode != KEYITEMS)
SendInventoryPackets(list[slot]);
}
// return ITEMERROR_FULL;
//New item that spilled over
while (quantityCount > 0)
{
InventoryItem addedItem = Database.AddItem(owner, itemId, Math.Min(quantityCount, gItem.maxStack), quality, gItem.isExclusive ? (byte)0x3 : (byte)0x0, gItem.durability, inventoryCode);
list.Add(addedItem);
if (inventoryCode != CURRENCY && inventoryCode != KEYITEMS)
SendInventoryPackets(addedItem);
InventoryItem addedItem = Database.CreateItem(itemId, Math.Min(quantityCount, gItem.maxStack), quality, gItem.isExclusive ? (byte)0x3 : (byte)0x0, gItem.durability);
addedItem.slot = (ushort)endOfListIndex;
isDirty[endOfListIndex] = true;
list[endOfListIndex++] = addedItem;
quantityCount -= gItem.maxStack;
if (owner is Player)
{
Database.AddItem((Player)owner, addedItem, inventoryCode);
}
}
if (owner is Player)
{
SendUpdatePackets((Player)owner);
}
if (inventoryCode == CURRENCY || inventoryCode == KEYITEMS)
SendFullInventory();
owner.QueuePacket(InventorySetEndPacket.BuildPacket(owner.actorId));
owner.QueuePacket(InventoryEndChangePacket.BuildPacket(owner.actorId));
return true;
}
public void AddItem(uint[] itemId)
{
if (!IsSpaceForAdd(itemId[0], itemId.Length))
return;
//Update lists and db
owner.QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.actorId));
owner.QueuePacket(InventorySetBeginPacket.BuildPacket(owner.actorId, inventoryCapacity, inventoryCode));
int startPos = list.Count;
//New item that spilled over
for (int i = 0; i < itemId.Length; i++)
{
ItemData gItem = Server.GetItemGamedata(itemId[i]);
InventoryItem addedItem = Database.AddItem(owner, itemId[i], 1, (byte)1, gItem.isExclusive ? (byte)0x3 : (byte)0x0, gItem.durability, inventoryCode);
list.Add(addedItem);
}
SendInventoryPackets(startPos);
owner.QueuePacket(InventorySetEndPacket.BuildPacket(owner.actorId));
owner.QueuePacket(InventoryEndChangePacket.BuildPacket(owner.actorId));
public void RemoveItem(uint itemId)
{
RemoveItem(itemId, 1);
}
public void RemoveItem(uint itemId, int quantity)
{
RemoveItem(itemId, quantity, 1);
}
public void RemoveItem(uint itemId, int quantity)
public void RemoveItem(uint itemId, int quantity, int quality)
{
if (!HasItem(itemId, quantity))
if (!HasItem(itemId, quantity, quality))
return;
List<ushort> slotsToUpdate = new List<ushort>();
@ -211,23 +187,31 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
//Remove as we go along
int quantityCount = quantity;
ushort lowestSlot = 0;
for (int i = list.Count - 1; i >= 0; i--)
for (int i = endOfListIndex - 1; i >= 0; i--)
{
InventoryItem item = list[i];
if (item.itemId == itemId)
InventoryItem item = list[i];
Debug.Assert(item != null, "Item slot was null!!!");
if (item.itemId == itemId && item.quality == quality)
{
int oldQuantity = item.quantity;
//Stack nomnomed
if (item.quantity - quantityCount <= 0)
{
itemsToRemove.Add(item);
slotsToRemove.Add(item.slot);
}
else
{
slotsToUpdate.Add(item.slot);
item.quantity -= quantityCount; //Stack reduced
}
//Stack nomnomed
if (item.quantity - quantityCount <= 0)
{
if (owner is Player)
Database.RemoveItem((Player)owner, list[i].uniqueId);
list[i] = null;
}
//Stack reduced
else
{
item.quantity -= quantityCount;
if (owner is Player)
Database.SetQuantity((Player)owner, list[i].uniqueId, list[i].quantity);
}
isDirty[i] = true;
quantityCount -= oldQuantity;
lowestSlot = item.slot;
@ -235,51 +219,23 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
if (quantityCount <= 0)
break;
}
}
for (int i = 0; i < slotsToUpdate.Count; i++)
{
Database.SetQuantity(owner, slotsToUpdate[i], inventoryCode, list[slotsToUpdate[i]].quantity);
}
int oldListSize = list.Count;
for (int i = 0; i < itemsToRemove.Count; i++)
{
Database.RemoveItem(owner, itemsToRemove[i].uniqueId, inventoryCode);
list.Remove(itemsToRemove[i]);
}
//Realign slots
for (int i = lowestSlot; i < list.Count; i++)
list[i].slot = (ushort)i;
//Added tail end items that need to be cleared for slot realignment
for (int i = oldListSize-1; i >= oldListSize - itemsToRemove.Count; i--)
{
if (!slotsToRemove.Contains((ushort)i))
slotsToRemove.Add((ushort)i);
}
owner.QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.actorId));
owner.QueuePacket(InventorySetBeginPacket.BuildPacket(owner.actorId, inventoryCapacity, inventoryCode));
SendInventoryPackets(lowestSlot);
SendInventoryRemovePackets(slotsToRemove);
owner.QueuePacket(InventorySetEndPacket.BuildPacket(owner.actorId));
if (inventoryCode == NORMAL)
owner.GetEquipment().SendFullEquipment(false);
owner.QueuePacket(InventoryEndChangePacket.BuildPacket(owner.actorId));
}
doRealign();
if (owner is Player)
SendUpdatePackets((Player)owner);
}
public void RemoveItemByUniqueId(ulong itemDBId)
{
ushort slot = 0;
InventoryItem toDelete = null;
foreach (InventoryItem item in list)
{
InventoryItem toDelete = null;
for (int i = endOfListIndex - 1; i >= 0; i--)
{
InventoryItem item = list[i];
Debug.Assert(item != null, "Item slot was null!!!");
if (item.uniqueId == itemDBId)
{
toDelete = item;
@ -289,188 +245,248 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
}
if (toDelete == null)
return;
int oldListSize = list.Count;
list.RemoveAt(slot);
Database.RemoveItem(owner, itemDBId, inventoryCode);
//Realign slots
for (int i = slot; i < list.Count; i++)
list[i].slot = (ushort)i;
owner.QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.actorId));
owner.QueuePacket(InventorySetBeginPacket.BuildPacket(owner.actorId, inventoryCapacity, inventoryCode));
SendInventoryPackets(slot);
SendInventoryRemovePackets(slot);
if (slot != oldListSize - 1)
SendInventoryRemovePackets((ushort)(oldListSize - 1));
owner.QueuePacket(InventorySetEndPacket.BuildPacket(owner.actorId));
if (inventoryCode == NORMAL)
owner.GetEquipment().SendFullEquipment(false);
owner.QueuePacket(InventoryEndChangePacket.BuildPacket(owner.actorId));
return;
if (owner is Player)
Database.RemoveItem((Player)owner, toDelete.uniqueId);
list[slot] = null;
isDirty[slot] = true;
doRealign();
if (owner is Player)
SendUpdatePackets((Player)owner);
}
public void RemoveItemAtSlot(ushort slot)
{
if (slot >= list.Count)
return;
int oldListSize = list.Count;
list.RemoveAt((int)slot);
Database.RemoveItem(owner, slot, inventoryCode);
//Realign slots
for (int i = slot; i < list.Count; i++)
list[i].slot = (ushort)i;
owner.QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.actorId));
owner.QueuePacket(InventorySetBeginPacket.BuildPacket(owner.actorId, inventoryCapacity, inventoryCode));
SendInventoryPackets(slot);
SendInventoryRemovePackets(slot);
if (slot != oldListSize - 1)
SendInventoryRemovePackets((ushort)(oldListSize - 1));
owner.QueuePacket(InventorySetEndPacket.BuildPacket(owner.actorId));
if (inventoryCode == NORMAL)
owner.GetEquipment().SendFullEquipment(false);
owner.QueuePacket(InventoryEndChangePacket.BuildPacket(owner.actorId));
if (slot >= endOfListIndex)
return;
if (owner is Player)
Database.RemoveItem((Player)owner, list[slot].uniqueId);
list[slot] = null;
isDirty[slot] = true;
doRealign();
if (owner is Player)
SendUpdatePackets((Player)owner);
}
public void RemoveItemAtSlot(ushort slot, int quantity)
{
if (slot >= endOfListIndex)
return;
if (list[slot] != null)
{
list[slot].quantity -= quantity;
if (list[slot].quantity <= 0)
{
if (owner is Player)
Database.RemoveItem((Player)owner, list[slot].uniqueId);
list[slot] = null;
doRealign();
}
else
{
if (owner is Player)
Database.SetQuantity((Player)owner, list[slot].uniqueId, list[slot].quantity);
}
isDirty[slot] = true;
if (owner is Player)
SendUpdatePackets((Player)owner);
}
}
public void ChangeDurability(uint slot, uint durabilityChange)
{
{
isDirty[slot] = true;
}
public void ChangeSpiritBind(uint slot, uint spiritBindChange)
{
{
isDirty[slot] = true;
}
public void ChangeMateria(uint slot, byte materiaSlot, byte materiaId)
{
{
isDirty[slot] = true;
}
#endregion
#region Packet Functions
public void SendFullInventory()
{
owner.QueuePacket(InventorySetBeginPacket.BuildPacket(owner.actorId, inventoryCapacity, inventoryCode));
SendInventoryPackets(0);
owner.QueuePacket(InventorySetEndPacket.BuildPacket(owner.actorId));
}
private void SendInventoryPackets(InventoryItem item)
{
owner.QueuePacket(InventoryListX01Packet.BuildPacket(owner.actorId, item));
}
private void SendInventoryPackets(List<InventoryItem> items)
public void SendFullInventory(Player player)
{
player.QueuePacket(InventorySetBeginPacket.BuildPacket(owner.actorId, inventoryCapacity, inventoryCode));
SendInventoryPackets(player, 0);
player.QueuePacket(InventorySetEndPacket.BuildPacket(owner.actorId));
}
private void SendInventoryPackets(Player player, InventoryItem item)
{
player.QueuePacket(InventoryListX01Packet.BuildPacket(owner.actorId, item));
}
private void SendInventoryPackets(Player player, List<InventoryItem> 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));
if (items.Count - currentIndex >= 64)
player.QueuePacket(InventoryListX64Packet.BuildPacket(owner.actorId, items, ref currentIndex));
else if (items.Count - currentIndex >= 32)
player.QueuePacket(InventoryListX32Packet.BuildPacket(owner.actorId, items, ref currentIndex));
else if (items.Count - currentIndex >= 16)
player.QueuePacket(InventoryListX16Packet.BuildPacket(owner.actorId, items, ref currentIndex));
else if (items.Count - currentIndex > 1)
player.QueuePacket(InventoryListX08Packet.BuildPacket(owner.actorId, items, ref currentIndex));
else if (items.Count - currentIndex == 1)
{
owner.QueuePacket(InventoryListX01Packet.BuildPacket(owner.actorId, items[currentIndex]));
{
player.QueuePacket(InventoryListX01Packet.BuildPacket(owner.actorId, items[currentIndex]));
currentIndex++;
}
else
break;
}
}
private void SendInventoryPackets(int startOffset)
}
private void SendInventoryPackets(Player player, int startOffset)
{
int currentIndex = startOffset;
while (true)
{
if (list.Count - currentIndex >= 64)
owner.QueuePacket(InventoryListX64Packet.BuildPacket(owner.actorId, list, ref currentIndex));
else if (list.Count - currentIndex >= 32)
owner.QueuePacket(InventoryListX32Packet.BuildPacket(owner.actorId, list, ref currentIndex));
else if (list.Count - currentIndex >= 16)
owner.QueuePacket(InventoryListX16Packet.BuildPacket(owner.actorId, list, ref currentIndex));
else if (list.Count - currentIndex > 1)
owner.QueuePacket(InventoryListX08Packet.BuildPacket(owner.actorId, list, ref currentIndex));
else if (list.Count - currentIndex == 1)
{
owner.QueuePacket(InventoryListX01Packet.BuildPacket(owner.actorId, list[currentIndex]));
currentIndex++;
}
else
break;
int currentIndex = startOffset;
List<InventoryItem> lst = new List<InventoryItem>();
for (int i = 0; i < endOfListIndex; i++)
lst.Add(list[i]);
while (true)
{
if (endOfListIndex - currentIndex >= 64)
player.QueuePacket(InventoryListX64Packet.BuildPacket(owner.actorId, lst, ref currentIndex));
else if (endOfListIndex - currentIndex >= 32)
player.QueuePacket(InventoryListX32Packet.BuildPacket(owner.actorId, lst, ref currentIndex));
else if (endOfListIndex - currentIndex >= 16)
player.QueuePacket(InventoryListX16Packet.BuildPacket(owner.actorId, lst, ref currentIndex));
else if (endOfListIndex - currentIndex > 1)
player.QueuePacket(InventoryListX08Packet.BuildPacket(owner.actorId, lst, ref currentIndex));
else if (endOfListIndex - currentIndex == 1)
{
player.QueuePacket(InventoryListX01Packet.BuildPacket(owner.actorId, list[currentIndex]));
currentIndex++;
}
else
break;
}
}
private void SendInventoryRemovePackets(ushort index)
}
private void SendInventoryRemovePackets(Player player, ushort index)
{
owner.QueuePacket(InventoryRemoveX01Packet.BuildPacket(owner.actorId, index));
}
player.QueuePacket(InventoryRemoveX01Packet.BuildPacket(owner.actorId, index));
}
private void SendInventoryRemovePackets(List<ushort> indexes)
private void SendInventoryRemovePackets(Player player, List<ushort> indexes)
{
int currentIndex = 0;
while (true)
{
if (indexes.Count - currentIndex >= 64)
owner.QueuePacket(InventoryRemoveX64Packet.BuildPacket(owner.actorId, indexes, ref currentIndex));
else if (indexes.Count - currentIndex >= 32)
owner.QueuePacket(InventoryRemoveX32Packet.BuildPacket(owner.actorId, indexes, ref currentIndex));
else if (indexes.Count - currentIndex >= 16)
owner.QueuePacket(InventoryRemoveX16Packet.BuildPacket(owner.actorId, indexes, ref currentIndex));
else if (indexes.Count - currentIndex > 1)
owner.QueuePacket(InventoryRemoveX08Packet.BuildPacket(owner.actorId, indexes, ref currentIndex));
if (indexes.Count - currentIndex >= 64)
player.QueuePacket(InventoryRemoveX64Packet.BuildPacket(owner.actorId, indexes, ref currentIndex));
else if (indexes.Count - currentIndex >= 32)
player.QueuePacket(InventoryRemoveX32Packet.BuildPacket(owner.actorId, indexes, ref currentIndex));
else if (indexes.Count - currentIndex >= 16)
player.QueuePacket(InventoryRemoveX16Packet.BuildPacket(owner.actorId, indexes, ref currentIndex));
else if (indexes.Count - currentIndex > 1)
player.QueuePacket(InventoryRemoveX08Packet.BuildPacket(owner.actorId, indexes, ref currentIndex));
else if (indexes.Count - currentIndex == 1)
{
owner.QueuePacket(InventoryRemoveX01Packet.BuildPacket(owner.actorId, indexes[currentIndex]));
{
player.QueuePacket(InventoryRemoveX01Packet.BuildPacket(owner.actorId, indexes[currentIndex]));
currentIndex++;
}
else
break;
}
}
public void RefreshItem(Player player, InventoryItem item)
{
player.QueuePacket(InventorySetBeginPacket.BuildPacket(owner.actorId, inventoryCapacity, inventoryCode));
SendInventoryPackets(player, item);
player.QueuePacket(InventorySetEndPacket.BuildPacket(owner.actorId));
}
public void RefreshItem(Player player, params InventoryItem[] items)
{
player.QueuePacket(InventorySetBeginPacket.BuildPacket(owner.actorId, inventoryCapacity, inventoryCode));
SendInventoryPackets(player, items.ToList());
player.QueuePacket(InventorySetEndPacket.BuildPacket(owner.actorId));
}
public void RefreshItem(Player player, List<InventoryItem> items)
{
player.QueuePacket(InventorySetBeginPacket.BuildPacket(owner.actorId, inventoryCapacity, inventoryCode));
SendInventoryPackets(player, items);
player.QueuePacket(InventorySetEndPacket.BuildPacket(owner.actorId));
}
#endregion
#region Inventory Utils
#endregion
#region Client Updating
private void SendUpdatePackets(Player player)
{
List<InventoryItem> items = new List<InventoryItem>();
List<ushort> slotsToRemove = new List<ushort>();
for (int i = 0; i < list.Length; i++)
{
if (i == endOfListIndex)
break;
if (isDirty[i])
items.Add(list[i]);
}
for (int i = endOfListIndex; i < list.Length; i++)
{
if (isDirty[i])
slotsToRemove.Add((ushort)i);
}
Array.Clear(isDirty, 0, isDirty.Length);
player.QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.actorId));
player.QueuePacket(InventorySetBeginPacket.BuildPacket(owner.actorId, inventoryCapacity, inventoryCode));
//Send Updated Slots
SendInventoryPackets(player, items);
//Send Remove packets for tail end
SendInventoryRemovePackets(player, slotsToRemove);
player.QueuePacket(InventorySetEndPacket.BuildPacket(owner.actorId));
player.QueuePacket(InventoryEndChangePacket.BuildPacket(owner.actorId));
}
#endregion
#region Inventory Utils
public bool IsFull()
{
return list.Count >= inventoryCapacity;
return endOfListIndex >= inventoryCapacity;
}
public bool IsSpaceForAdd(uint itemId, int quantity)
public bool IsSpaceForAdd(uint itemId, int quantity, int quality)
{
int quantityCount = quantity;
for (int i = 0; i < list.Count; i++)
int quantityCount = quantity;
for (int i = 0; i < endOfListIndex; i++)
{
InventoryItem item = list[i];
ItemData gItem = Server.GetItemGamedata(item.itemId);
if (item.itemId == itemId && item.quantity < gItem.maxStack)
ItemData gItem = Server.GetItemGamedata(item.itemId);
if (item.itemId == itemId && item.quality == quality && item.quantity < gItem.maxStack)
{
quantityCount -= (gItem.maxStack - item.quantity);
if (quantityCount <= 0)
@ -484,27 +500,61 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
public bool HasItem(uint itemId)
{
return HasItem(itemId, 1);
}
public bool HasItem(uint itemId, int minQuantity)
{
return HasItem(itemId, minQuantity, 1);
}
public bool HasItem(uint itemId, int minQuantity)
public bool HasItem(uint itemId, int minQuantity, int quality)
{
int count = 0;
foreach (InventoryItem item in list)
{
if (item.itemId == itemId)
count += item.quantity;
if (count >= minQuantity)
return true;
int count = 0;
for (int i = endOfListIndex - 1; i >= 0; i--)
{
InventoryItem item = list[i];
Debug.Assert(item != null, "Item slot was null!!!");
if (item.itemId == itemId && item.quality == quality)
count += item.quantity;
if (count >= minQuantity)
return true;
}
return false;
}
public int GetNextEmptySlot()
{
return list.Count == 0 ? 0 : list.Count();
{
return endOfListIndex;
}
private void doRealign()
{
int lastNullSlot = -1;
for (int i = 0; i < endOfListIndex; i++)
{
if (list[i] == null && lastNullSlot == -1)
{
lastNullSlot = i;
continue;
}
else if (list[i] != null && lastNullSlot != -1)
{
list[lastNullSlot] = list[i];
list[lastNullSlot].slot = (ushort)lastNullSlot;
list[i] = null;
isDirty[lastNullSlot] = true;
isDirty[i] = true;
lastNullSlot++;
}
}
endOfListIndex = lastNullSlot;
}
#endregion

View file

@ -135,7 +135,8 @@ namespace FFXIVClassic_Map_Server.Actors
public uint homepoint = 0;
public byte homepointInn = 0;
//Instancing
//Retainer
RetainerMeetingRelationGroup retainerMeetingGroup = null;
public Retainer currentSpawnedRetainer = null;
public bool sentRetainerSpawn = false;
@ -533,12 +534,12 @@ namespace FFXIVClassic_Map_Server.Actors
#region Inventory & Equipment
QueuePacket(InventoryBeginChangePacket.BuildPacket(actorId));
inventories[Inventory.NORMAL].SendFullInventory();
inventories[Inventory.CURRENCY].SendFullInventory();
inventories[Inventory.KEYITEMS].SendFullInventory();
inventories[Inventory.BAZAAR].SendFullInventory();
inventories[Inventory.MELDREQUEST].SendFullInventory();
inventories[Inventory.LOOT].SendFullInventory();
inventories[Inventory.NORMAL].SendFullInventory(this);
inventories[Inventory.CURRENCY].SendFullInventory(this);
inventories[Inventory.KEYITEMS].SendFullInventory(this);
inventories[Inventory.BAZAAR].SendFullInventory(this);
inventories[Inventory.MELDREQUEST].SendFullInventory(this);
inventories[Inventory.LOOT].SendFullInventory(this);
equipment.SendFullEquipment(false);
playerSession.QueuePacket(InventoryEndChangePacket.BuildPacket(actorId));
#endregion
@ -1742,30 +1743,30 @@ namespace FFXIVClassic_Map_Server.Actors
chocoboAppearance = appearanceId;
}
public bool SpawnMyRetainer(Npc bell, int retainerIndex)
public Retainer SpawnMyRetainer(Npc bell, int retainerIndex)
{
Tuple<uint, uint, string> retainerData = Database.GetRetainer(this, retainerIndex);
ActorClass actorClass = Server.GetWorldManager().GetActorClass(retainerData.Item2);
if (actorClass == null)
return false;
return null;
float distance = (float)Math.Sqrt(((positionX - bell.positionX) * (positionX - bell.positionX)) + ((positionZ - bell.positionZ) * (positionZ - bell.positionZ)));
float posX = bell.positionX - ((-1.0f * (bell.positionX - positionX)) / distance);
float posZ = bell.positionZ - ((-1.0f * (bell.positionZ - positionZ)) / distance);
Retainer retainer = new Retainer(retainerData.Item1, retainerData.Item3, actorClass, this, posX, bell.positionY, positionZ, (float)Math.Atan2(positionX - posX, positionZ - posZ));
Retainer retainer = new Retainer(retainerData.Item3, actorClass, this, posX, bell.positionY, positionZ, (float)Math.Atan2(positionX - posX, positionZ - posZ));
retainer.LoadEventConditions(actorClass.eventConditions);
//RetainerMeetingRelationGroup group = new RetainerMeetingRelationGroup(5555, this, retainer);
//group.SendGroupPackets(playerSession);
retainerMeetingGroup = new RetainerMeetingRelationGroup(5555, this, retainer);
retainerMeetingGroup.SendGroupPackets(playerSession);
currentSpawnedRetainer = retainer;
sentRetainerSpawn = false;
return true;
return retainer;
}
public void DespawnMyRetainer()
@ -1773,6 +1774,8 @@ namespace FFXIVClassic_Map_Server.Actors
if (currentSpawnedRetainer != null)
{
currentSpawnedRetainer = null;
retainerMeetingGroup.SendDeletePacket(playerSession);
retainerMeetingGroup = null;
}
}

View file

@ -23,12 +23,11 @@ namespace FFXIVClassic_Map_Server.dataobjects
public byte materia5 = 0;
//Bare Minimum
public InventoryItem(uint id, uint itemId, ushort slot)
public InventoryItem(uint id, uint itemId)
{
this.uniqueId = id;
this.itemId = itemId;
this.quantity = 1;
this.slot = slot;
ItemData gItem = Server.GetItemGamedata(itemId);
itemType = gItem.isExclusive ? (byte)0x3 : (byte)0x0;
@ -55,12 +54,11 @@ namespace FFXIVClassic_Map_Server.dataobjects
this.materia5 = item.materia5;
}
public InventoryItem(uint uniqueId, uint itemId, int quantity, ushort slot, byte itemType, byte qualityNumber, int durability, ushort spiritbind, byte materia1, byte materia2, byte materia3, byte materia4, byte materia5)
public InventoryItem(uint uniqueId, uint itemId, int quantity, byte itemType, byte qualityNumber, int durability, ushort spiritbind, byte materia1, byte materia2, byte materia3, byte materia4, byte materia5)
{
this.uniqueId = uniqueId;
this.itemId = itemId;
this.quantity = quantity;
this.slot = slot;
this.itemType = itemType;
this.quality = qualityNumber;
this.durability = durability;

View file

@ -169,7 +169,9 @@ namespace FFXIVClassic_World_Server
{
uint sessionId = subpacket.header.targetId;
Session session = GetSession(sessionId);
subpacket.DebugPrintSubPacket();
if (subpacket.gameMessage.opcode != 0x1 && subpacket.gameMessage.opcode != 0xca)
subpacket.DebugPrintSubPacket();
if (subpacket.gameMessage.opcode >= 0x1000)
{
//subpacket.DebugPrintSubPacket();