More inventory fixing after I broke it. Added preliminary final trade code. Moved recalc stats to the end of equipcommand, not on every modification of the referred item package.

This commit is contained in:
Filip Maj 2019-06-04 00:11:36 -04:00
parent 88ff22e55e
commit 69d4b19979
13 changed files with 388 additions and 170 deletions

View file

@ -32,12 +32,10 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
public const ushort MAXSIZE_EQUIPMENT = 35;
public const ushort MAXSIZE_EQUIPMENT_OTHERPLAYER = 0x23;
public enum INV_ERROR {
SUCCESS = 0,
INVENTORY_FULL,
ALREADY_HAS_UNIQUE,
SYSTEM_ERROR
};
public const int ERROR_SUCCESS = 0;
public const int ERROR_FULL = 1;
public const int ERROR_HAS_UNIQUE = 2;
public const int ERROR_SYSTEM = 3;
private Character owner;
private ushort itemPackageCapacity;
@ -121,24 +119,64 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
return null;
}
public INV_ERROR AddItem(uint itemId)
public int AddItem(uint itemId)
{
return AddItem(itemId, 1, 1);
}
public INV_ERROR AddItem(uint itemId, int quantity)
public int AddItem(uint itemId, int quantity)
{
return AddItem(itemId, quantity, 1);
}
public bool AddItems(uint[] itemIds)
public int AddItems(uint[] itemIds, uint[] quantity, byte[] quality)
{
bool canAdd = GetFreeSlots() - itemIds.Length >= 0;
if (canAdd)
if (itemIds.Length != quantity.Length && itemIds.Length != quality.Length)
return ERROR_SYSTEM;
//Check if has space
if (!CanAdd(itemIds, quantity, quality))
return ERROR_FULL;
for (int i = 0; i < itemIds.Length; i++)
{
foreach (uint id in itemIds)
ItemData gItem = Server.GetItemGamedata(itemIds[i]);
//If it's unique, abort
if (HasItem(itemIds[i]) && gItem.isExclusive)
return ERROR_HAS_UNIQUE;
if (gItem == null)
{
Program.Log.Error("Inventory.AddItem: unable to find item %u", itemIds[i]);
return ERROR_SYSTEM;
}
//Check if item id exists
int quantityCount = (int) quantity[i];
for (int j = 0; j < endOfListIndex; j++)
{
InventoryItem item = list[j];
Debug.Assert(item != null, "Item slot was null!!!");
if (item.itemId == itemIds[i] && item.quality == quantity[i] && item.quantity < gItem.maxStack)
{
int oldQuantity = item.quantity;
item.quantity = Math.Min(item.quantity + quantityCount, gItem.maxStack);
isDirty[j] = true;
quantityCount -= (gItem.maxStack - oldQuantity);
DoDatabaseQuantity(item.uniqueId, item.quantity);
if (quantityCount <= 0)
break;
}
}
//New item that spilled over
while (quantityCount > 0)
{
ItemData gItem = Server.GetItemGamedata(id);
InventoryItem.ItemModifier modifiers = null;
if (gItem.durability != 0)
{
@ -146,31 +184,82 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
modifiers.durability = (uint)gItem.durability;
}
InventoryItem addedItem = Database.CreateItem(id, Math.Min(1, gItem.maxStack), 0, modifiers);
InventoryItem addedItem = Database.CreateItem(itemIds[i], Math.Min(quantityCount, gItem.maxStack), quality[i], modifiers);
addedItem.RefreshPositioning(owner, itemPackageCode, (ushort)endOfListIndex);
isDirty[endOfListIndex] = true;
list[endOfListIndex++] = addedItem;
quantityCount -= gItem.maxStack;
DoDatabaseAdd(addedItem);
}
}
}
return canAdd;
if (owner is Player)
{
(owner as Player).QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.actorId));
SendUpdate();
(owner as Player).QueuePacket(InventoryEndChangePacket.BuildPacket(owner.actorId));
}
return ERROR_SUCCESS;
}
public INV_ERROR AddItem(InventoryItem itemRef)
public bool CanAdd(uint[] itemIds, uint[] quantity, byte[] quality)
{
if (itemIds.Length != quantity.Length && itemIds.Length != quality.Length)
return false;
int tempInvSize = GetCount();
for (int i = 0; i < itemIds.Length; i++)
{
ItemData gItem = Server.GetItemGamedata(itemIds[i]);
//Check if item id exists and fill up til maxstack
int quantityCount = (int) quantity[i];
for (int j = 0; j < endOfListIndex; j++)
{
InventoryItem item = list[j];
Debug.Assert(item != null, "Item slot was null!!!");
if (item.itemId == itemIds[i] && item.quality == quality[i] && item.quantity < gItem.maxStack)
{
quantityCount -= (gItem.maxStack - item.quantity);
if (quantityCount <= 0)
break;
}
}
//New items that spilled over creating new stacks
while (quantityCount > 0)
{
quantityCount -= gItem.maxStack;
tempInvSize++;
}
//If the new stacks push us over capacity, can't add these items
if (tempInvSize > itemPackageCapacity)
return false;
}
return true;
}
public int AddItem(InventoryItem itemRef)
{
//If it isn't a single item (ie: armor) just add like normal (not valid for BAZAAR)
if (itemPackageCode != BAZAAR && itemRef.GetItemData().maxStack > 1)
return AddItem(itemRef.itemId, itemRef.quantity, itemRef.quality);
if (!IsSpaceForAdd(itemRef.itemId, itemRef.quantity, itemRef.quality))
return INV_ERROR.INVENTORY_FULL;
return ERROR_FULL;
ItemData gItem = Server.GetItemGamedata(itemRef.itemId);
if (gItem == null)
{
Program.Log.Error("Inventory.AddItem: unable to find item %u", itemRef.itemId);
return INV_ERROR.SYSTEM_ERROR;
return ERROR_SYSTEM;
}
itemRef.RefreshPositioning(owner, itemPackageCode, (ushort)endOfListIndex);
@ -179,26 +268,31 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
list[endOfListIndex++] = itemRef;
DoDatabaseAdd(itemRef);
SendUpdate();
if (owner is Player)
{
(owner as Player).QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.actorId));
SendUpdate();
(owner as Player).QueuePacket(InventoryEndChangePacket.BuildPacket(owner.actorId));
}
return INV_ERROR.SUCCESS;
return ERROR_SUCCESS;
}
public INV_ERROR AddItem(uint itemId, int quantity, byte quality)
public int AddItem(uint itemId, int quantity, byte quality)
{
if (!IsSpaceForAdd(itemId, quantity, quality))
return INV_ERROR.INVENTORY_FULL;
return ERROR_FULL;
ItemData gItem = Server.GetItemGamedata(itemId);
//If it's unique, abort
if (HasItem(itemId) && gItem.isExclusive)
return INV_ERROR.ALREADY_HAS_UNIQUE;
return ERROR_HAS_UNIQUE;
if (gItem == null)
{
Program.Log.Error("Inventory.AddItem: unable to find item %u", itemId);
return INV_ERROR.SYSTEM_ERROR;
return ERROR_SYSTEM;
}
//Check if item id exists
@ -242,15 +336,25 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
DoDatabaseAdd(addedItem);
}
SendUpdate();
if (owner is Player)
{
(owner as Player).QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.actorId));
SendUpdate();
(owner as Player).QueuePacket(InventoryEndChangePacket.BuildPacket(owner.actorId));
}
return INV_ERROR.SUCCESS;
return ERROR_SUCCESS;
}
public void SetItem(ushort slot, InventoryItem item)
{
list[slot] = item;
SendUpdate();
if (owner is Player)
{
(owner as Player).QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.actorId));
SendUpdate();
(owner as Player).QueuePacket(InventoryEndChangePacket.BuildPacket(owner.actorId));
}
item.RefreshPositioning(owner, itemPackageCode, slot);
}
@ -309,7 +413,13 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
}
DoRealign();
SendUpdate();
if (owner is Player)
{
(owner as Player).QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.actorId));
SendUpdate();
(owner as Player).QueuePacket(InventoryEndChangePacket.BuildPacket(owner.actorId));
}
}
public void RemoveItem(InventoryItem item)
@ -358,7 +468,13 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
isDirty[slot] = true;
DoRealign();
SendUpdate();
if (owner is Player)
{
(owner as Player).QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.actorId));
SendUpdate();
(owner as Player).QueuePacket(InventoryEndChangePacket.BuildPacket(owner.actorId));
}
}
public void RemoveItemAtSlot(ushort slot)
@ -373,7 +489,13 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
isDirty[slot] = true;
DoRealign();
SendUpdate();
if (owner is Player)
{
(owner as Player).QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.actorId));
SendUpdate();
(owner as Player).QueuePacket(InventoryEndChangePacket.BuildPacket(owner.actorId));
}
}
public void RemoveItemAtSlot(ushort slot, int quantity)
@ -397,7 +519,13 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
DoDatabaseQuantity(list[slot].uniqueId, list[slot].quantity);
isDirty[slot] = true;
SendUpdate();
if (owner is Player)
{
(owner as Player).QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.actorId));
SendUpdate();
(owner as Player).QueuePacket(InventoryEndChangePacket.BuildPacket(owner.actorId));
}
}
}
@ -411,7 +539,12 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
}
endOfListIndex = 0;
SendUpdate();
if (owner is Player)
{
(owner as Player).QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.actorId));
SendUpdate();
(owner as Player).QueuePacket(InventoryEndChangePacket.BuildPacket(owner.actorId));
}
}
public void MarkDirty(InventoryItem item)

View file

@ -13,7 +13,7 @@ namespace FFXIVClassic_Map_Server.actors.chara
const uint EMPTY = 0xFFFFFFFF;
private readonly Player owner;
private readonly uint[] contentList;
private readonly InventoryItem[] referenceList;
private readonly ushort itemPackageCode;
private readonly ushort itemPackageCapacity;
private bool writeToDB = false;
@ -23,13 +23,10 @@ namespace FFXIVClassic_Map_Server.actors.chara
this.owner = owner;
itemPackageCode = code;
itemPackageCapacity = capacity;
contentList = new uint[capacity];
referenceList = new InventoryItem[capacity];
if (code == ItemPackage.EQUIPMENT)
writeToDB = true;
for (int i = 0; i < contentList.Length; i++)
contentList[i] = EMPTY;
}
public void ToggleDBWrite(bool flag)
@ -38,25 +35,25 @@ namespace FFXIVClassic_Map_Server.actors.chara
}
#region Package Management
public void SetList(uint[] toSet)
public void SetList(InventoryItem[] toSet)
{
Debug.Assert(contentList.Length == itemPackageCapacity);
toSet.CopyTo(contentList, 0);
Debug.Assert(referenceList.Length == itemPackageCapacity);
toSet.CopyTo(referenceList, 0);
}
public void SetList(ushort[] positions, uint[] values)
public void SetList(ushort[] positions, InventoryItem[] values)
{
Debug.Assert(positions.Length == values.Length);
for (int i = 0; i < positions.Length; i++)
{
InventoryItem item = GetItem(values[i]);
InventoryItem item = values[i];
if (item == null)
continue;
//Database.EquipItem(owner, positions[i], item.uniqueId);
contentList[positions[i]] = values[i];
referenceList[positions[i]] = values[i];
}
owner.QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.actorId));
@ -76,70 +73,70 @@ namespace FFXIVClassic_Map_Server.actors.chara
public void Set(ushort position, InventoryItem item)
{
if (position >= contentList.Length)
if (position >= referenceList.Length)
return;
if (writeToDB)
Database.EquipItem(owner, position, item.uniqueId);
ItemPackage newPackage = owner.GetItemPackage(item.itemPackage);
ItemPackage oldPackage = GetItemPackage(contentList[position]);
InventoryItem oldItem = GetItem(contentList[position]);
ItemPackage oldPackage = null;
if (oldPackage != null && oldItem != null)
if (referenceList[position] != null)
{
oldPackage = owner.GetItemPackage(referenceList[position].itemPackage);
InventoryItem oldItem = referenceList[position];
oldPackage.MarkDirty(oldItem);
}
newPackage.MarkDirty(item);
contentList[position] = GetValue(item.itemPackage, item.slot);
referenceList[position] = item;
owner.QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.actorId));
if (oldPackage != null)
oldPackage.SendUpdate();
newPackage.SendUpdate();
SendSingleUpdate(position);
owner.QueuePacket(InventoryEndChangePacket.BuildPacket(owner.actorId));
owner.CalculateBaseStats();// RecalculateStats();
owner.QueuePacket(InventoryEndChangePacket.BuildPacket(owner.actorId));
}
public void Clear(ushort position)
{
if (position >= contentList.Length)
if (position >= referenceList.Length)
return;
if (writeToDB)
Database.UnequipItem(owner, position);
ItemPackage oldItemPackage = GetItemPackage(contentList[position]);
ItemPackage oldItemPackage = owner.GetItemPackage(referenceList[position].itemPackage);
oldItemPackage.MarkDirty(GetItem(contentList[position]));
contentList[position] = EMPTY;
oldItemPackage.MarkDirty(referenceList[position]);
referenceList[position] = null;
owner.QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.actorId));
oldItemPackage.SendUpdate();
SendSingleUpdate(position);
owner.QueuePacket(InventoryEndChangePacket.BuildPacket(owner.actorId));
owner.RecalculateStats();
}
public void ClearAll()
{
List<ItemPackage> packagesToRefresh = new List<ItemPackage>();
for (int i = 0; i < contentList.Length; i++)
for (int i = 0; i < referenceList.Length; i++)
{
if (contentList[i] == EMPTY)
if (referenceList[i] == null)
continue;
if (writeToDB)
Database.UnequipItem(owner, (ushort)i);
ItemPackage package = GetItemPackage(contentList[i]);
package.MarkDirty(GetItem(contentList[i]));
ItemPackage package = owner.GetItemPackage(referenceList[i].itemPackage);
package.MarkDirty(referenceList[i]);
packagesToRefresh.Add(package);
contentList[i] = EMPTY;
referenceList[i] = null;
}
owner.QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.actorId));
@ -147,8 +144,6 @@ namespace FFXIVClassic_Map_Server.actors.chara
packagesToRefresh[i].SendUpdate();
SendUpdate();
owner.QueuePacket(InventoryEndChangePacket.BuildPacket(owner.actorId));
owner.RecalculateStats();
}
#endregion
@ -169,9 +164,9 @@ namespace FFXIVClassic_Map_Server.actors.chara
{
List<ushort> slotsToUpdate = new List<ushort>();
for (ushort i = 0; i < contentList.Length; i++)
for (ushort i = 0; i < referenceList.Length; i++)
{
if (contentList[i] != EMPTY)
if (referenceList[i] != null)
slotsToUpdate.Add(i);
}
@ -189,14 +184,14 @@ namespace FFXIVClassic_Map_Server.actors.chara
{
List<InventoryItem> items = new List<InventoryItem>();
for (ushort i = 0; i < contentList.Length; i++)
for (ushort i = 0; i < referenceList.Length; i++)
{
if (contentList[i] == EMPTY)
if (referenceList[i] == null)
continue;
InventoryItem item = GetItem(contentList[i]);
InventoryItem item = referenceList[i];
item.linkSlot = i; //We have to set the linkSlot as this is the position in the Referenced IP, not the original IP it's linked from.
items.Add(GetItem(contentList[i]));
items.Add(referenceList[i]);
}
targetPlayer.QueuePacket(InventorySetBeginPacket.BuildPacket(owner.actorId, destinationCapacity, destinationCode));
@ -204,11 +199,11 @@ namespace FFXIVClassic_Map_Server.actors.chara
targetPlayer.QueuePacket(InventorySetEndPacket.BuildPacket(owner.actorId));
//Clean Up linkSlots
for (ushort i = 0; i < contentList.Length; i++)
for (ushort i = 0; i < referenceList.Length; i++)
{
if (contentList[i] == EMPTY)
if (referenceList[i] == null)
continue;
InventoryItem item = GetItem(contentList[i]);
InventoryItem item = referenceList[i];
item.linkSlot = 0xFFFF;
}
}
@ -217,10 +212,10 @@ namespace FFXIVClassic_Map_Server.actors.chara
#region Packet Functions (Private)
private void SendSingleLinkedItemPacket(Player targetPlayer, ushort position)
{
if (contentList[position] == EMPTY)
if (referenceList[position] == null)
targetPlayer.QueuePacket(InventoryRemoveX01Packet.BuildPacket(owner.actorId, position));
else
targetPlayer.QueuePacket(LinkedItemListX01Packet.BuildPacket(owner.actorId, position, contentList[position]));
targetPlayer.QueuePacket(LinkedItemListX01Packet.BuildPacket(owner.actorId, position, referenceList[position]));
}
private void SendLinkedItemPackets(Player targetPlayer, List<ushort> slotsToUpdate)
@ -230,16 +225,16 @@ namespace FFXIVClassic_Map_Server.actors.chara
while (true)
{
if (slotsToUpdate.Count - currentIndex >= 64)
targetPlayer.QueuePacket(LinkedItemListX64Packet.BuildPacket(owner.actorId, contentList, slotsToUpdate, ref currentIndex));
targetPlayer.QueuePacket(LinkedItemListX64Packet.BuildPacket(owner.actorId, referenceList, slotsToUpdate, ref currentIndex));
else if (slotsToUpdate.Count - currentIndex >= 32)
targetPlayer.QueuePacket(LinkedItemListX32Packet.BuildPacket(owner.actorId, contentList, slotsToUpdate, ref currentIndex));
targetPlayer.QueuePacket(LinkedItemListX32Packet.BuildPacket(owner.actorId, referenceList, slotsToUpdate, ref currentIndex));
else if (slotsToUpdate.Count - currentIndex >= 16)
targetPlayer.QueuePacket(LinkedItemListX16Packet.BuildPacket(owner.actorId, contentList, slotsToUpdate, ref currentIndex));
targetPlayer.QueuePacket(LinkedItemListX16Packet.BuildPacket(owner.actorId, referenceList, slotsToUpdate, ref currentIndex));
else if (slotsToUpdate.Count - currentIndex > 1)
targetPlayer.QueuePacket(LinkedItemListX08Packet.BuildPacket(owner.actorId, contentList, slotsToUpdate, ref currentIndex));
targetPlayer.QueuePacket(LinkedItemListX08Packet.BuildPacket(owner.actorId, referenceList, slotsToUpdate, ref currentIndex));
else if (slotsToUpdate.Count - currentIndex == 1)
{
targetPlayer.QueuePacket(LinkedItemListX01Packet.BuildPacket(owner.actorId, slotsToUpdate[currentIndex], contentList[slotsToUpdate[currentIndex]]));
targetPlayer.QueuePacket(LinkedItemListX01Packet.BuildPacket(owner.actorId, slotsToUpdate[currentIndex], referenceList[slotsToUpdate[currentIndex]]));
currentIndex++;
}
else
@ -290,35 +285,11 @@ namespace FFXIVClassic_Map_Server.actors.chara
public InventoryItem GetItemAtSlot(ushort position)
{
if (position < contentList.Length)
return GetItem(contentList[position]);
if (position < referenceList.Length)
return referenceList[position];
else
return null;
}
#endregion
#region Utils
private ItemPackage GetItemPackage(uint value)
{
if (value == EMPTY)
return null;
return owner.GetItemPackage((ushort)((value >> 16) & 0xFFFF));
}
private InventoryItem GetItem(uint value)
{
if (value == EMPTY)
return null;
ItemPackage package = GetItemPackage(value);
if (package != null)
return package.GetItemAtSlot((ushort)(value & 0xFFFF));
return null;
}
private uint GetValue(ushort code, ushort slot)
{
return (uint) ((code << 16) | slot);
}
#endregion
#endregion
}
}

View file

@ -982,7 +982,7 @@ namespace FFXIVClassic_Map_Server.Actors
return max;
}
public uint[] GetGearset(ushort classId)
public InventoryItem[] GetGearset(ushort classId)
{
return Database.GetEquipment(this, classId);
}