diff --git a/FFXIVClassic Map Server/Database.cs b/FFXIVClassic Map Server/Database.cs index f345256f..f8ef5398 100644 --- a/FFXIVClassic Map Server/Database.cs +++ b/FFXIVClassic Map Server/Database.cs @@ -1698,7 +1698,9 @@ namespace FFXIVClassic_Map_Server } } - public static void SetQuantity(Player player, ulong serverItemId, int quantity) + + + public static void SetQuantity(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))) { @@ -1707,13 +1709,12 @@ namespace FFXIVClassic_Map_Server conn.Open(); string query = @" - UPDATE characters_inventory + UPDATE server_items SET quantity = @quantity - WHERE characterId = @charId and serverItemId = @serverItemId; + WHERE id = @serverItemId; "; MySqlCommand cmd = new MySqlCommand(query, conn); - cmd.Parameters.AddWithValue("@charId", player.actorId); cmd.Parameters.AddWithValue("@serverItemId", serverItemId); cmd.Parameters.AddWithValue("@quantity", quantity); cmd.ExecuteNonQuery(); @@ -1796,39 +1797,6 @@ namespace FFXIVClassic_Map_Server } } - public static void SetQuantity(Retainer retainer, 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))) - { - try - { - conn.Open(); - - string query = @" - UPDATE retainers_inventory - SET quantity = @quantity - WHERE retainerId = @retainerId and serverItemId = @serverItemId; - "; - - MySqlCommand cmd = new MySqlCommand(query, conn); - cmd.Parameters.AddWithValue("@retainerId", retainer.getRetainerId()); - cmd.Parameters.AddWithValue("@serverItemId", serverItemId); - cmd.Parameters.AddWithValue("@quantity", quantity); - cmd.ExecuteNonQuery(); - - } - catch (MySqlException e) - { - Program.Log.Error(e.ToString()); - } - finally - { - conn.Dispose(); - } - } - - } - public static void RemoveItem(Retainer retainer, 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))) diff --git a/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj b/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj index 3febcfd7..7f5f9e68 100644 --- a/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj +++ b/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj @@ -146,6 +146,7 @@ + diff --git a/FFXIVClassic Map Server/PacketProcessor.cs b/FFXIVClassic Map Server/PacketProcessor.cs index ed297041..829c1b0d 100644 --- a/FFXIVClassic Map Server/PacketProcessor.cs +++ b/FFXIVClassic Map Server/PacketProcessor.cs @@ -240,6 +240,12 @@ namespace FFXIVClassic_Map_Server if (paramRequest.paramName.Equals("charaWork/exp")) session.GetActor().SendCharaExpInfo(); break; + //Item Package Request + case 0x0131: + UpdateItemPackagePacket packageRequest = new UpdateItemPackagePacket(subpacket.data); + if (Server.GetWorldManager().GetPCInWorld(packageRequest.actorID) != null) + Server.GetWorldManager().GetPCInWorld(packageRequest.actorID).SendItemPackage(session.GetActor(), packageRequest.packageId); + break; //Group Created Confirm case 0x0133: GroupCreatedPacket groupCreated = new GroupCreatedPacket(subpacket.data); diff --git a/FFXIVClassic Map Server/WorldManager.cs b/FFXIVClassic Map Server/WorldManager.cs index 7434f6ca..daba1e69 100644 --- a/FFXIVClassic Map Server/WorldManager.cs +++ b/FFXIVClassic Map Server/WorldManager.cs @@ -1049,6 +1049,33 @@ namespace FFXIVClassic_Map_Server return Database.CreateItem(itemId, amount, quality, modifiers); } + public bool BazaarPurchaseOperation(Player bazaar, Player buyer, InventoryItem itemToBuy, int quantity, int cost) + { + if (bazaar == null || buyer == null || itemToBuy == null) + return false; + + if (quantity <= 0) + return false; + + if (cost < 0) + return false; + + if (itemToBuy.GetBazaarMode() == InventoryItem.TYPE_STACK) + { + itemToBuy.ChangeQuantity(-quantity); + buyer.AddItemStack(itemToBuy.itemId, quantity, itemToBuy.quality); + buyer.GetItemPackage(Inventory.CURRENCY_CRYSTALS).RemoveItem(1000001, cost); + } + else + { + itemToBuy.ChangeQuantity(-quantity); + buyer.AddItem(itemToBuy.itemId, quantity, itemToBuy.quality); + buyer.GetItemPackage(Inventory.CURRENCY_CRYSTALS).RemoveItem(1000001, cost); + } + + return true; + } + public void AddToBazaar(Player player, InventoryItem reward, InventoryItem seek, int rewardAmount, int seekAmount, byte bazaarMode) { bool succ = false; @@ -1079,6 +1106,8 @@ namespace FFXIVClassic_Map_Server } } + + player.CheckBazaarFlags(); } @@ -1106,6 +1135,8 @@ namespace FFXIVClassic_Map_Server seekRef.SetNormal(); player.AddItem(seekRef); } + + player.CheckBazaarFlags(); } /* public void TransactionBazaar(Player owner, Player other, InventoryItem reward, InventoryItem seek, int rewardAmount, int seekAmount) diff --git a/FFXIVClassic Map Server/actors/chara/Character.cs b/FFXIVClassic Map Server/actors/chara/Character.cs index e9a08c74..3e0c1cb8 100644 --- a/FFXIVClassic Map Server/actors/chara/Character.cs +++ b/FFXIVClassic Map Server/actors/chara/Character.cs @@ -145,6 +145,16 @@ namespace FFXIVClassic_Map_Server.Actors } } + public void AddItemStack(uint catalogID, int quantity, byte quality) + { + ItemData itemData = Server.GetItemGamedata(catalogID); + if (itemData != null) + { + int totalQuantity = itemData.maxStack * quantity; + AddItem(catalogID, totalQuantity, quality); + } + } + public void AddItem(InventoryItem item) { ushort itemPackage = GetPackageForItem(item.GetItemData().catalogID); @@ -228,7 +238,7 @@ namespace FFXIVClassic_Map_Server.Actors ushort itemPackage = GetPackageForItem(catalogID); if (itemPackages.ContainsKey(itemPackage)) { - itemPackages[itemPackage].HasItem(catalogID, minQuantity, quality); + return itemPackages[itemPackage].HasItem(catalogID, minQuantity, quality); } return false; } diff --git a/FFXIVClassic Map Server/actors/chara/player/Player.cs b/FFXIVClassic Map Server/actors/chara/player/Player.cs index 9f362fc2..f38dd81c 100644 --- a/FFXIVClassic Map Server/actors/chara/player/Player.cs +++ b/FFXIVClassic Map Server/actors/chara/player/Player.cs @@ -139,9 +139,6 @@ namespace FFXIVClassic_Map_Server.Actors //Nameplate Stuff public uint currentLSPlate = 0; - public bool isBazaarRetail = false; - public bool isBazaarRepair = false; - public bool isMateriaRequest = false; public byte repairType = 0; //Retainer @@ -505,6 +502,7 @@ namespace FFXIVClassic_Map_Server.Actors } //Bazaar + CheckBazaarFlags(true); if (charaWork.eventSave.repairType != 0) propPacketUtil.AddProperty("charaWork.eventSave.repairType"); if (charaWork.eventTemp.bazaarRetail) @@ -1067,7 +1065,7 @@ namespace FFXIVClassic_Map_Server.Actors QueuePackets(propPacketUtil.Done()); } - public void CheckBazaarFlags() + public void CheckBazaarFlags(bool noUpdate = false) { bool isDealing = false, isRepairing = false, seekingItem = false; lock (GetItemPackage(Inventory.BAZAAR)) @@ -1089,15 +1087,26 @@ namespace FFXIVClassic_Map_Server.Actors } } + bool doUpdate = false; + + if (charaWork.eventTemp.bazaarRetail != isDealing || charaWork.eventTemp.bazaarRepair != isRepairing || charaWork.eventTemp.bazaarMateria != (GetItemPackage(Inventory.MELDREQUEST).GetCount() != 0)) + doUpdate = true; + charaWork.eventTemp.bazaarRetail = isDealing; charaWork.eventTemp.bazaarRepair = isRepairing; charaWork.eventTemp.bazaarMateria = GetItemPackage(Inventory.MELDREQUEST).GetCount() == 0; - ActorPropertyPacketUtil propPacketUtil = new ActorPropertyPacketUtil("charaWork/bazaar", this); - propPacketUtil.AddProperty("charaWork.eventTemp.bazaarRetail"); - propPacketUtil.AddProperty("charaWork.eventTemp.bazaarRepair"); - propPacketUtil.AddProperty("charaWork.eventTemp.bazaarMateria"); - QueuePackets(propPacketUtil.Done()); + if (noUpdate) + return; + + if (doUpdate) + { + ActorPropertyPacketUtil propPacketUtil = new ActorPropertyPacketUtil("charaWork/bazaar", this); + propPacketUtil.AddProperty("charaWork.eventTemp.bazaarRetail"); + propPacketUtil.AddProperty("charaWork.eventTemp.bazaarRepair"); + propPacketUtil.AddProperty("charaWork.eventTemp.bazaarMateria"); + QueuePackets(propPacketUtil.Done()); + } } public int GetCurrentGil() @@ -1808,6 +1817,16 @@ namespace FFXIVClassic_Map_Server.Actors chocoboAppearance = appearanceId; } + public void SendItemPackage(Player player, uint id) + { + if (!itemPackages.ContainsKey((ushort)id)) + return; + + player.QueuePacket(InventoryBeginChangePacket.BuildPacket(actorId)); + itemPackages[(ushort)id].SendFullInventory(player); + player.QueuePacket(InventoryEndChangePacket.BuildPacket(actorId)); + } + public Retainer SpawnMyRetainer(Npc bell, int retainerIndex) { Retainer retainer = Database.LoadRetainer(this, retainerIndex); diff --git a/FFXIVClassic Map Server/dataobjects/InventoryItem.cs b/FFXIVClassic Map Server/dataobjects/InventoryItem.cs index 5ce9f0d9..50d570a0 100644 --- a/FFXIVClassic Map Server/dataobjects/InventoryItem.cs +++ b/FFXIVClassic Map Server/dataobjects/InventoryItem.cs @@ -1,4 +1,5 @@ -using System; +using FFXIVClassic_Map_Server.Actors; +using System; using System.IO; namespace FFXIVClassic_Map_Server.dataobjects @@ -39,6 +40,7 @@ namespace FFXIVClassic_Map_Server.dataobjects public ItemModifier modifiers; public readonly ItemData itemData; + public Character owner = null; public ushort slot = 0xFFFF; public ushort itemPackage = 0xFFFF; @@ -197,10 +199,49 @@ namespace FFXIVClassic_Map_Server.dataobjects return data; } - public void RefreshPositioning(ushort itemPackage, ushort slot) + public void SetQuantity(uint quantity) { - this.itemPackage = itemPackage; - this.slot = slot; + lock (owner.GetItemPackage(itemPackage)) + { + this.quantity = (int)quantity; + if (quantity < 0) + quantity = 0; + Database.SetQuantity(uniqueId, this.quantity); + + if (owner != null && owner is Player) + owner.GetItemPackage(itemPackage).RefreshItem((Player)owner, this); + } + } + + public void ChangeQuantity(int quantityDelta) + { + lock (owner.GetItemPackage(itemPackage)) + { + this.quantity += quantityDelta; + if (quantity < 0) + quantity = 0; + + if (quantity == 0) + { + owner.RemoveItem(this); + return; + } + + Database.SetQuantity(uniqueId, this.quantity); + + if (owner != null && owner is Player) + owner.GetItemPackage(itemPackage).RefreshItem((Player)owner, this); + } + } + + public void RefreshPositioning(Character owner, ushort itemPackage, ushort slot) + { + lock (owner.GetItemPackage(itemPackage)) + { + this.owner = owner; + this.itemPackage = itemPackage; + this.slot = slot; + } } public void SetExclusive(bool isExclusive) diff --git a/FFXIVClassic Map Server/packets/receive/UpdateItemPackagePacket.cs b/FFXIVClassic Map Server/packets/receive/UpdateItemPackagePacket.cs new file mode 100644 index 00000000..2f863013 --- /dev/null +++ b/FFXIVClassic Map Server/packets/receive/UpdateItemPackagePacket.cs @@ -0,0 +1,29 @@ +using System; +using System.IO; + +namespace FFXIVClassic_Map_Server.packets.receive +{ + class UpdateItemPackagePacket + { + public bool invalidPacket = false; + public uint actorID; + public uint packageId; + + public UpdateItemPackagePacket(byte[] data) + { + using (MemoryStream mem = new MemoryStream(data)) + { + using (BinaryReader binReader = new BinaryReader(mem)) + { + try{ + actorID = binReader.ReadUInt32(); + packageId = binReader.ReadUInt32(); + } + catch (Exception){ + invalidPacket = true; + } + } + } + } + } +}