mirror of
				https://bitbucket.org/Ioncannon/project-meteor-server.git
				synced 2025-05-20 08:26:59 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			317 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			317 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| /*
 | |
| ===========================================================================
 | |
| Copyright (C) 2015-2019 Project Meteor Dev Team
 | |
| 
 | |
| This file is part of Project Meteor Server.
 | |
| 
 | |
| Project Meteor Server is free software: you can redistribute it and/or modify
 | |
| it under the terms of the GNU Affero General Public License as published by
 | |
| the Free Software Foundation, either version 3 of the License, or
 | |
| (at your option) any later version.
 | |
| 
 | |
| Project Meteor Server is distributed in the hope that it will be useful,
 | |
| but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | |
| GNU Affero General Public License for more details.
 | |
| 
 | |
| You should have received a copy of the GNU Affero General Public License
 | |
| along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
 | |
| ===========================================================================
 | |
| */
 | |
| 
 | |
| using Meteor.Map.actors.chara.player;
 | |
| using Meteor.Map.Actors;
 | |
| using Meteor.Map.DataObjects;
 | |
| using Meteor.Map.packets.send.actor.inventory;
 | |
| using System.Collections.Generic;
 | |
| using System.Diagnostics;
 | |
| 
 | |
| namespace Meteor.Map.actors.chara
 | |
| {
 | |
| 
 | |
|     class ReferencedItemPackage
 | |
|     {
 | |
|         const uint EMPTY = 0xFFFFFFFF;
 | |
| 
 | |
|         private readonly Player owner;
 | |
|         private readonly InventoryItem[] referenceList;
 | |
|         private readonly ushort itemPackageCode;
 | |
|         private readonly ushort itemPackageCapacity;
 | |
|         private bool writeToDB = false;
 | |
| 
 | |
|         public ReferencedItemPackage(Player owner, ushort capacity, ushort code)
 | |
|         {
 | |
|             this.owner = owner;
 | |
|             itemPackageCode = code;
 | |
|             itemPackageCapacity = capacity;
 | |
|             referenceList = new InventoryItem[capacity];
 | |
| 
 | |
|             if (code == ItemPackage.EQUIPMENT)
 | |
|                 writeToDB = true;
 | |
|         }
 | |
| 
 | |
|         public void ToggleDBWrite(bool flag)
 | |
|         {
 | |
|             writeToDB = flag;
 | |
|         }
 | |
| 
 | |
|         #region Package Management
 | |
|         public void SetList(InventoryItem[] toSet)
 | |
|         {
 | |
|             Debug.Assert(referenceList.Length == itemPackageCapacity);
 | |
|             toSet.CopyTo(referenceList, 0);
 | |
|         }
 | |
| 
 | |
|         public void Set(ushort[] positions, ushort[] itemSlots, ushort itemPackage)
 | |
|         {
 | |
|             Debug.Assert(positions.Length == itemSlots.Length);
 | |
|            
 | |
|             for (int i = 0; i < positions.Length; i++)
 | |
|             {
 | |
|                 InventoryItem item = owner.GetItemPackage(itemPackage)?.GetItemAtSlot(itemSlots[i]);
 | |
| 
 | |
|                 if (item == null)
 | |
|                     continue;
 | |
| 
 | |
|                 Database.EquipItem(owner, positions[i], item.uniqueId);
 | |
|                 referenceList[positions[i]] = item;
 | |
|             }
 | |
| 
 | |
|             owner.QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.Id));
 | |
|             SendUpdate();
 | |
|             owner.QueuePacket(InventoryEndChangePacket.BuildPacket(owner.Id));
 | |
|         }
 | |
|         
 | |
|         public void Set(ushort position, ushort itemPackagePosition, ushort itemPackageCode)
 | |
|         {
 | |
|             InventoryItem item = owner.GetItemPackage(itemPackageCode).GetItemAtSlot(itemPackagePosition);
 | |
| 
 | |
|             if (item == null)
 | |
|                 return;
 | |
| 
 | |
|             Set(position, item);
 | |
|         }
 | |
| 
 | |
|         public void Set(ushort position, InventoryItem item)
 | |
|         {
 | |
|             if (position >= referenceList.Length)
 | |
|                 return;
 | |
| 
 | |
|             if (writeToDB)
 | |
|                 Database.EquipItem(owner, position, item.uniqueId);
 | |
| 
 | |
|             ItemPackage newPackage = owner.GetItemPackage(item.itemPackage);
 | |
|             ItemPackage oldPackage = null;
 | |
| 
 | |
|             if (referenceList[position] != null)
 | |
|             {
 | |
|                 oldPackage = owner.GetItemPackage(referenceList[position].itemPackage);
 | |
|                 InventoryItem oldItem = referenceList[position];
 | |
|                 oldPackage.MarkDirty(oldItem);
 | |
|             }
 | |
|             
 | |
|             newPackage.MarkDirty(item);
 | |
| 
 | |
|             referenceList[position] = item;
 | |
| 
 | |
|             owner.QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.Id));
 | |
|             if (oldPackage != null)
 | |
|                 oldPackage.SendUpdate();
 | |
|             newPackage.SendUpdate();
 | |
|             SendSingleUpdate(position);
 | |
|             owner.QueuePacket(InventoryEndChangePacket.BuildPacket(owner.Id));            
 | |
|         }
 | |
| 
 | |
|         public void Clear(ushort position)
 | |
|         {
 | |
|             if (position >= referenceList.Length)
 | |
|                 return;
 | |
| 
 | |
|             if (writeToDB)
 | |
|                 Database.UnequipItem(owner, position);
 | |
| 
 | |
|             ItemPackage oldItemPackage = owner.GetItemPackage(referenceList[position].itemPackage);
 | |
| 
 | |
|             oldItemPackage.MarkDirty(referenceList[position]);
 | |
|             referenceList[position] = null;
 | |
| 
 | |
|             owner.QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.Id));
 | |
|             oldItemPackage.SendUpdate();
 | |
|             SendSingleUpdate(position);
 | |
|             owner.QueuePacket(InventoryEndChangePacket.BuildPacket(owner.Id));
 | |
|         }
 | |
| 
 | |
|         public void ClearAll()
 | |
|         {
 | |
|             List<ItemPackage> packagesToRefresh = new List<ItemPackage>();
 | |
| 
 | |
|             for (int i = 0; i < referenceList.Length; i++)
 | |
|             {
 | |
|                 if (referenceList[i] == null)
 | |
|                     continue;
 | |
| 
 | |
|                 if (writeToDB)
 | |
|                     Database.UnequipItem(owner, (ushort)i);
 | |
| 
 | |
|                 ItemPackage package = owner.GetItemPackage(referenceList[i].itemPackage);               
 | |
|                 package.MarkDirty(referenceList[i]);            
 | |
|                 packagesToRefresh.Add(package);
 | |
| 
 | |
|                 referenceList[i] = null;               
 | |
|             }
 | |
| 
 | |
|             owner.QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.Id));
 | |
|             for (int i = 0; i < packagesToRefresh.Count; i++)
 | |
|                 packagesToRefresh[i].SendUpdate();
 | |
|             SendUpdate();
 | |
|             owner.QueuePacket(InventoryEndChangePacket.BuildPacket(owner.Id));
 | |
|         }
 | |
|         #endregion
 | |
| 
 | |
|         #region Send Update Functions
 | |
|         public void SendSingleUpdate(ushort position)
 | |
|         {
 | |
|             owner.QueuePacket(InventorySetBeginPacket.BuildPacket(owner.Id, itemPackageCapacity, itemPackageCode));
 | |
|             SendSingleLinkedItemPacket(owner, position);
 | |
|             owner.QueuePacket(InventorySetEndPacket.BuildPacket(owner.Id));
 | |
|         }
 | |
| 
 | |
|         public void SendUpdate()
 | |
|         {
 | |
|             SendUpdate(owner);
 | |
|         }
 | |
| 
 | |
|         public void SendUpdate(Player targetPlayer)
 | |
|         {
 | |
|             List<ushort> slotsToUpdate = new List<ushort>();
 | |
| 
 | |
|             for (ushort i = 0; i < referenceList.Length; i++)
 | |
|             {
 | |
|                 if (referenceList[i] != null)
 | |
|                     slotsToUpdate.Add(i);
 | |
|             }
 | |
|          
 | |
|             targetPlayer.QueuePacket(InventorySetBeginPacket.BuildPacket(owner.Id, itemPackageCapacity, itemPackageCode));
 | |
|             SendLinkedItemPackets(targetPlayer, slotsToUpdate);
 | |
|             targetPlayer.QueuePacket(InventorySetEndPacket.BuildPacket(owner.Id));
 | |
|         }
 | |
| 
 | |
|         public void SendUpdateAsItemPackage(Player targetPlayer)
 | |
|         {
 | |
|             SendUpdateAsItemPackage(targetPlayer, itemPackageCapacity, itemPackageCode);
 | |
|         }
 | |
| 
 | |
|         public void SendUpdateAsItemPackage(Player targetPlayer, ushort destinationCapacity, ushort destinationCode)
 | |
|         {
 | |
|             List<InventoryItem> items = new List<InventoryItem>();
 | |
| 
 | |
|             for (ushort i = 0; i < referenceList.Length; i++)
 | |
|             {
 | |
|                 if (referenceList[i] == null)
 | |
|                     continue;
 | |
| 
 | |
|                 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(referenceList[i]);
 | |
|             }
 | |
|             
 | |
|             targetPlayer.QueuePacket(InventorySetBeginPacket.BuildPacket(owner.Id, destinationCapacity, destinationCode));         
 | |
|             SendItemPackets(targetPlayer, items);
 | |
|             targetPlayer.QueuePacket(InventorySetEndPacket.BuildPacket(owner.Id));
 | |
| 
 | |
|             //Clean Up linkSlots
 | |
|             for (ushort i = 0; i < referenceList.Length; i++)
 | |
|             {
 | |
|                 if (referenceList[i] == null)
 | |
|                     continue;
 | |
|                 InventoryItem item = referenceList[i];
 | |
|                 item.linkSlot = 0xFFFF;
 | |
|             }
 | |
|         }
 | |
|         #endregion
 | |
| 
 | |
|         #region Packet Functions (Private)
 | |
|         private void SendSingleLinkedItemPacket(Player targetPlayer, ushort position)
 | |
|         {
 | |
|             if (referenceList[position] == null)
 | |
|                 targetPlayer.QueuePacket(InventoryRemoveX01Packet.BuildPacket(owner.Id, position));
 | |
|             else
 | |
|                 targetPlayer.QueuePacket(LinkedItemListX01Packet.BuildPacket(owner.Id, position, referenceList[position]));
 | |
|         }
 | |
| 
 | |
|         private void SendLinkedItemPackets(Player targetPlayer, List<ushort> slotsToUpdate)
 | |
|         {
 | |
|             int currentIndex = 0;
 | |
| 
 | |
|             while (true)
 | |
|             {
 | |
|                 if (slotsToUpdate.Count - currentIndex >= 64)
 | |
|                     targetPlayer.QueuePacket(LinkedItemListX64Packet.BuildPacket(owner.Id, referenceList, slotsToUpdate, ref currentIndex));
 | |
|                 else if (slotsToUpdate.Count - currentIndex >= 32)
 | |
|                     targetPlayer.QueuePacket(LinkedItemListX32Packet.BuildPacket(owner.Id, referenceList, slotsToUpdate, ref currentIndex));
 | |
|                 else if (slotsToUpdate.Count - currentIndex >= 16)
 | |
|                     targetPlayer.QueuePacket(LinkedItemListX16Packet.BuildPacket(owner.Id, referenceList, slotsToUpdate, ref currentIndex));
 | |
|                 else if (slotsToUpdate.Count - currentIndex > 1)
 | |
|                     targetPlayer.QueuePacket(LinkedItemListX08Packet.BuildPacket(owner.Id, referenceList, slotsToUpdate, ref currentIndex));
 | |
|                 else if (slotsToUpdate.Count - currentIndex == 1)
 | |
|                 {
 | |
|                     targetPlayer.QueuePacket(LinkedItemListX01Packet.BuildPacket(owner.Id, slotsToUpdate[currentIndex], referenceList[slotsToUpdate[currentIndex]]));
 | |
|                     currentIndex++;
 | |
|                 }
 | |
|                 else
 | |
|                     break;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private void SendItemPackets(Player player, List<InventoryItem> items)
 | |
|         {
 | |
|             int currentIndex = 0;
 | |
| 
 | |
|             while (true)
 | |
|             {
 | |
|                 if (items.Count - currentIndex >= 64)
 | |
|                     player.QueuePacket(InventoryListX64Packet.BuildPacket(owner.Id, items, ref currentIndex));
 | |
|                 else if (items.Count - currentIndex >= 32)
 | |
|                     player.QueuePacket(InventoryListX32Packet.BuildPacket(owner.Id, items, ref currentIndex));
 | |
|                 else if (items.Count - currentIndex >= 16)
 | |
|                     player.QueuePacket(InventoryListX16Packet.BuildPacket(owner.Id, items, ref currentIndex));
 | |
|                 else if (items.Count - currentIndex > 1)
 | |
|                     player.QueuePacket(InventoryListX08Packet.BuildPacket(owner.Id, items, ref currentIndex));
 | |
|                 else if (items.Count - currentIndex == 1)
 | |
|                 {
 | |
|                     player.QueuePacket(InventoryListX01Packet.BuildPacket(owner.Id, items[currentIndex]));
 | |
|                     currentIndex++;
 | |
|                 }
 | |
|                 else
 | |
|                     break;
 | |
|             }
 | |
|         }
 | |
|         #endregion
 | |
| 
 | |
|         #region Getters/Setters
 | |
|         public ushort GetCode()
 | |
|         {
 | |
|             return itemPackageCode;
 | |
|         }
 | |
| 
 | |
|         public int GetCapacity()
 | |
|         {
 | |
|             return itemPackageCapacity;
 | |
|         }
 | |
| 
 | |
|         public Player GetOwner()
 | |
|         {
 | |
|             return owner;
 | |
|         }
 | |
| 
 | |
|         public InventoryItem GetItemAtSlot(ushort position)
 | |
|         {
 | |
|             if (position < referenceList.Length)
 | |
|                 return referenceList[position];
 | |
|             else
 | |
|                 return null;
 | |
|         }
 | |
|         #endregion        
 | |
|     }
 | |
| }
 |