Revamp inventory, make it into a 1D array

This commit is contained in:
Sofia 2017-05-16 20:35:38 +03:00
parent 8e533220f0
commit 6c1669d1cc
10 changed files with 209 additions and 292 deletions

View File

@ -48,7 +48,7 @@ namespace Cyber.Controls {
private void Update() {
if (Time.time - LastUpdateTime >= 1f / UpdateFrequency) {
Dictionary<EquipSlot, Item> Equips = Inventory.Equipped.GetEquippedDict();
Dictionary<EquipSlot, Item> Equips = Inventory.Drive.GetEquippedItems();
// Empty all slots
for (int i = 0; i < Slots.Length; i++) {
Slots[i].Mesh.mesh = null;

View File

@ -143,16 +143,15 @@ namespace Cyber.Controls {
}
if (Input.GetButtonDown("Equip")) {
// Selected index was already this => equip (double-clicked)
Item SelectedItem = Inventory.Drive.Interface.GetItemAt(ItemGridSelectedIndex % (int) ItemGridDimensions.x,
ItemGridSelectedIndex / (int) ItemGridDimensions.y);
Item SelectedItem = Inventory.Drive.GetItemAt(ItemGridSelectedIndex);
if (SelectedItem != null) {
Item Equipped = Inventory.Equipped.GetItem(SelectedItem.Slot);
Item Equipped = Inventory.Drive.GetSlot(SelectedItem.Slot);
if (Equipped != null && Equipped.ID == SelectedItem.ID) {
Inventory.Equipped.ClearSlot(SelectedItem.Slot);
Inventory.Drive.UnequipSlot(SelectedItem.Slot);
Client.Send(PktType.InventoryAction, Inventory.ActionHandler.BuildClearSlot(SelectedItem.Slot));
} else {
Inventory.Equipped.SetSlot(SelectedItem.Slot, SelectedItem);
Client.Send(PktType.InventoryAction, Inventory.ActionHandler.BuildEquipItem(SelectedItem.ID));
Inventory.Drive.EquipItem(ItemGridSelectedIndex);
Client.Send(PktType.InventoryAction, Inventory.ActionHandler.BuildEquipItem(ItemGridSelectedIndex));
}
}
}
@ -206,7 +205,7 @@ namespace Cyber.Controls {
for (int x = 0; x < ItemGridDimensions.x; x++) {
// Find the item and mesh
int i = x + y * (int) ItemGridDimensions.x;
Item Item = Inventory.Drive.Interface.GetItemAt(x, y);
Item Item = Inventory.Drive.GetItemAt(x + y * (int) ItemGridDimensions.y);
Mesh Mesh = null;
if (Item != null) {
Mesh = MeshDB.GetMesh(Item.ModelID);

View File

@ -4,6 +4,7 @@ using Cyber.Items;
using Cyber.Networking;
using Cyber.Networking.Serverside;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
namespace Cyber.Entities.SyncBases {
@ -18,11 +19,6 @@ namespace Cyber.Entities.SyncBases {
/// </summary>
public Drive Drive;
/// <summary>
/// This entity's <see cref="Items.Equipped"/> <see cref="Item"/>s.
/// </summary>
public Equipped Equipped;
/// <summary>
/// The possible <see cref="Character"/> component associated with this Inventory. Used in <see cref="UseItemInSlot(EquipSlot)"/>.
/// </summary>
@ -38,7 +34,6 @@ namespace Cyber.Entities.SyncBases {
/// </summary>
public Inventory() {
Drive = new Drive(10f);
Equipped = new Equipped();
if (Server.IsRunning()) {
Drive.AddItem(ItemDB.Singleton.Get(0));
Drive.AddItem(ItemDB.Singleton.Get(1));
@ -51,15 +46,11 @@ namespace Cyber.Entities.SyncBases {
/// </summary>
/// <returns>A checksum of the IDs of the items</returns>
public override int GenerateChecksum() {
var Items = Drive.GetItems().ToArray();
var Slots = Drive.GetSlots();
int Checksum = 0;
for (int i = 0; i < Items.Length; i++) {
for (int i = 0; i < Slots.Length; i++) {
// Times with primes and sprinkle some i to spice up the stew
Checksum += (Items[i].ID + 1) * 509 * (i + 1) * 53;
}
var EquippedItems = Equipped.GetEquippedList().ToArray();
for (int i = 0; i < EquippedItems.Length; i++) {
Checksum += (EquippedItems[i].ID + 1) * 859 * (i + 1) * 97;
Checksum += (((Slots[i].Item != null) ? Slots[i].Item.ID : i) + 1) * 509 * (i + 1) * 53 + (Slots[i].Equipped ? 1789 : 431);
}
return Checksum;
}
@ -76,7 +67,7 @@ namespace Cyber.Entities.SyncBases {
/// Uses the item in the left hand if something is equipped.
/// </summary>
public void UseItemInSlot(EquipSlot slot) {
Item Item = Equipped.GetItem(slot);
Item Item = Drive.GetSlot(slot);
if (Item != null && Item.Action != null && Character != null) {
Item.Action(Character);
}
@ -95,29 +86,15 @@ namespace Cyber.Entities.SyncBases {
ByteArray[3] = reader.ReadBytesAndSize();
int[] IDs = NetworkHelper.DeserializeIntArray(ByteArray);
byte[] Equippeds = reader.ReadBytesAndSize();
Drive.Clear();
foreach (int id in IDs) {
Drive.AddItem(ItemDB.Singleton.Get(id));
}
bool ReceivedSlots = reader.ReadBoolean();
if (!ReceivedSlots) {
Equipped.ClearAllEquipped();
return;
}
byte[] Slots = reader.ReadBytesAndSize();
byte[][] EquippedIdsBytes = new byte[4][];
EquippedIdsBytes[0] = reader.ReadBytesAndSize();
EquippedIdsBytes[1] = reader.ReadBytesAndSize();
EquippedIdsBytes[2] = reader.ReadBytesAndSize();
EquippedIdsBytes[3] = reader.ReadBytesAndSize();
int[] EquippedIds = NetworkHelper.DeserializeIntArray(EquippedIdsBytes);
Equipped.ClearAllEquipped();
for (int i = 0; i < Slots.Length; i++) {
Equipped.SetSlot((EquipSlot) Slots[i], ItemDB.Singleton.Get(EquippedIds[i]));
for (int i = 0; i < IDs.Length; i++) {
int ID = IDs[i];
if (ID >= 0) {
Drive.AddItemToIndex(ItemDB.Singleton.Get(ID), i);
Drive.GetSlots()[i].Equipped = (Equippeds[i] == 1 ? true : false);
}
}
}
@ -126,11 +103,19 @@ namespace Cyber.Entities.SyncBases {
/// </summary>
/// <param name="writer"></param>
public override void Serialize(NetworkWriter writer) {
var Items = Drive.GetItems();
int[] IDs = new int[Items.Count];
for (int i = 0; i < Items.Count; i++) {
IDs[i] = Items[i].ID;
Slot[] Slots = Drive.GetSlots();
int[] IDs = new int[Slots.Length];
byte[] Equippeds = new byte[Slots.Length];
for (int i = 0; i < Slots.Length; i++) {
if (Slots[i].Item == null) {
IDs[i] = -1;
} else {
IDs[i] = Slots[i].Item.ID;
}
Equippeds[i] = (byte) ((Slots[i].Equipped) ? 1 : 0);
}
byte[][] ByteArray = NetworkHelper.SerializeIntArray(IDs);
writer.WriteBytesFull(ByteArray[0]);
@ -138,30 +123,7 @@ namespace Cyber.Entities.SyncBases {
writer.WriteBytesFull(ByteArray[2]);
writer.WriteBytesFull(ByteArray[3]);
var slotList = new List<EquipSlot>(Equipped.GetEquippedDict().Keys).ConvertAll(x => (byte) x);
if (slotList.Count > 0) {
writer.Write(true);
} else {
writer.Write(false);
}
slotList.Sort((a, b) => {
return b - a;
});
var idList = new List<int>();
slotList.ForEach(x => {
idList.Add(Equipped.GetItem((EquipSlot) x).ID);
});
writer.WriteBytesFull(slotList.ToArray());
byte[][] EquippedByteArray = NetworkHelper.SerializeIntArray(idList.ToArray());
writer.WriteBytesFull(EquippedByteArray[0]);
writer.WriteBytesFull(EquippedByteArray[1]);
writer.WriteBytesFull(EquippedByteArray[2]);
writer.WriteBytesFull(EquippedByteArray[3]);
writer.WriteBytesFull(Equippeds);
}
private void Start() {

View File

@ -8,25 +8,19 @@ namespace Cyber.Items {
/// </summary>
public class Drive {
private List<Item> Items = new List<Item>();
private Slot[] Slots = new Slot[0];
/// <summary>
/// The capacity of the drive, meaning how much stuff can this drive contain.
/// </summary>
public readonly float Capacity;
/// <summary>
/// The interface-class of this Drive.
/// </summary>
public DriveInterface Interface;
/// <summary>
/// Creates a drive with given capacity. Capacity cannot be changed after this.
/// </summary>
/// <param name="capacity">Capacity of the drive</param>
public Drive(float capacity) {
Capacity = capacity;
Interface = new DriveInterface(this);
}
/// <summary>
@ -35,8 +29,10 @@ namespace Cyber.Items {
/// <returns>The totam weight</returns>
public float TotalWeight() {
float sum = 0;
foreach (Item item in Items) {
sum += item.Weight;
foreach (Slot slot in Slots) {
if (slot.Item != null) {
sum += slot.Item.Weight;
}
}
return sum;
}
@ -54,7 +50,7 @@ namespace Cyber.Items {
/// <see cref="Inventory.Deserialize(NetworkReader)"/>
/// </summary>
public void Clear() {
Items.Clear();
Slots = new Slot[0];
}
/// <summary>
@ -65,21 +61,50 @@ namespace Cyber.Items {
if (item.Weight > FreeSpace()) {
return false;
}
Interface.AddNewItem(Items.Count);
Items.Add(item);
bool foundEmpty = false;
for (int i = 0; i < Slots.Length; i++) {
if (Slots[i].Item == null) {
Slots[i] = new Slot(item, false);
foundEmpty = true;
}
}
if (!foundEmpty) {
// Add space and set the item there
IncreaseCapacity(1);
Slots[Slots.Length - 1] = new Slot(item, false);
}
return true;
}
/// <summary>
/// Tries to add an item to a specific slot. Returns false if slot already occupied.
/// </summary>
/// <param name="item">Item to add.</param>
/// <param name="idx">Index in the inventory.</param>
/// <returns>Weather the slot was empty or not.</returns>
public bool AddItemToIndex(Item item, int idx) {
if (idx < 0) {
return false;
}
if (GetItemAt(idx) == null) {
if (Slots.Length > idx) {
Slots[idx].Item = item;
} else {
IncreaseCapacity(idx - Slots.Length + 1);
Slots[idx].Item = item;
}
return true;
}
return false;
}
/// <summary>
/// Gets the item at the given index, or null if there is nothing.
/// </summary>
/// <param name="idx">The index of the desired item</param>
/// <returns>The item or null if nothing was found.</returns>
public Item GetItem(int idx) {
if (idx < 0 || idx >= Items.Count) {
return null;
}
return Items[idx];
public Item GetItemAt(int idx) {
return GetSlotAt(idx).Item;
}
/// <summary>
@ -87,8 +112,104 @@ namespace Cyber.Items {
/// </summary>
/// <returns></returns>
public List<Item> GetItems() {
List<Item> Items = new List<Item>();
foreach (Slot slot in Slots) {
if (slot.Item != null) {
Items.Add(slot.Item);
}
}
return Items;
}
/// <summary>
/// Gets the item at the given slot. Loops through all items and checks if there is an item equipped at the given slot and returns it if there is.
/// </summary>
/// <param name="slot">The desired slot</param>
/// <returns>The item at the slot, or null if no items</returns>
public Item GetSlot(EquipSlot slot) {
Item Item = null;
foreach (Slot s in Slots) {
if (s.Item != null && s.Item.Slot == slot && s.Equipped) {
Item = s.Item;
break;
}
}
return Item;
}
/// <summary>
/// Returns all the equipped items in a dictionary.
/// </summary>
/// <returns>The dictionary of items.</returns>
public Dictionary<EquipSlot, Item> GetEquippedItems() {
Dictionary<EquipSlot, Item> Items = new Dictionary<EquipSlot, Item>();
foreach (Slot s in Slots) {
if (s.Item != null && s.Equipped) {
Items.Add(s.Item.Slot, s.Item);
}
}
return Items;
}
/// <summary>
/// Attempt to equip the item at the given index.
/// </summary>
/// <param name="idx">Equip the iten at the given slot</param>
/// <returns>Weather the item could be equipped or if there already exists something on that equip slot.</returns>
public bool EquipItem(int idx) {
Slot Slot = GetSlotAt(idx);
if (Slot.Item != null && GetSlot(Slot.Item.Slot) == null) {
Slots[idx].Equipped = true;
return true;
}
return false;
}
/// <summary>
/// Unequips the item at the given inventory index.
/// </summary>
/// <param name="idx">The index to unequip.</param>
public void UnequipItem(int idx) {
Slot Slot = GetSlotAt(idx);
if (Slot.Item != null) {
Slots[idx].Equipped = false;
}
}
/// <summary>
/// Unequip all items that are in this slot.
/// </summary>
/// <param name="equipSlot">The slot of the desired item to be unequipped.</param>
public void UnequipSlot(EquipSlot equipSlot) {
for (int i = 0; i < Slots.Length; i++) {
if (Slots[i].Item != null && Slots[i].Item.Slot == equipSlot) {
Slots[i].Equipped = false;
}
}
}
/// <summary>
/// Simply returns the slots-array. The fastest way to get all of inventory if needed.
/// </summary>
/// <returns>The Slot-structs</returns>
public Slot[] GetSlots() {
return Slots;
}
private void IncreaseCapacity(int moreCapacity) {
Slot[] NewSlots = new Slot[Slots.Length + moreCapacity];
for (int i = 0; i < Slots.Length; i++) {
NewSlots[i] = Slots[i];
}
Slots = NewSlots;
}
private Slot GetSlotAt(int idx) {
if (idx < 0 || idx >= Slots.Length) {
return new Slot(null, false);
}
return Slots[idx];
}
}
}

View File

@ -1,116 +0,0 @@

using UnityEngine;
namespace Cyber.Items {
/// <summary>
/// The <see cref="Drive"/> interface, which contains a grid of indices of items in the <see cref="Drive"/>. Use <see cref="GetItemAt(int, int)"/> to get items in the interface.
/// </summary>
public class DriveInterface {
/// <summary>
/// Width of the interface.
/// </summary>
public const int Width = 7;
/// <summary>
/// Minimun height of the interface.
/// </summary>
public const int MinHeight = 4;
private int[,] ItemGrid;
private Drive Drive;
/// <summary>
/// Creates a Drive interface for a <see cref="Drive"/>.
/// </summary>
/// <param name="drive"></param>
public DriveInterface(Drive drive) {
Drive = drive;
ItemGrid = CreateEmptyGrid(Width, 4);
}
/// <summary>
/// Returns the item at the specified coordinate on the interface. Returns null if invalid or empty coordinate.
/// </summary>
/// <param name="x">The x-coordinate</param>
/// <param name="y">The y-coordinate</param>
/// <returns>The item or null</returns>
public Item GetItemAt(int x, int y) {
if (y < 0 || x < 0 || y >= GetHeight() || x >= GetWidth() ||
ItemGrid[y, x] == -1) {
return null;
} else {
return Drive.GetItem(ItemGrid[y, x]);
}
}
/// <summary>
/// Gets the Width of the interface, or simply <see cref="Width"/>.
/// </summary>
/// <returns></returns>
public int GetWidth() {
return Width;
}
/// <summary>
/// Gets the current height of the interface
/// </summary>
/// <returns></returns>
public int GetHeight() {
return ItemGrid.GetLength(0);
}
/// <summary>
/// Updates the height of the interface, adding new rows or deleting old useless ones.
/// </summary>
public void UpdateHeight() {
int RequiredHeight = MinHeight;
for (int y = MinHeight; y < GetHeight(); y++) {
for (int x = 0; x < Width; x++) {
if (GetItemAt(x, y) == null || (x == Width - 1 && y == GetHeight() - 1)) {
RequiredHeight = y;
}
}
}
int[,] Temp = CreateEmptyGrid(Width, RequiredHeight + 1);
for (int y = 0; y < RequiredHeight - 1; y++) {
for (int x = 0; x < Width; x++) {
if (GetItemAt(x, y) != null) {
Temp[y, x] = Drive.GetItems().IndexOf(GetItemAt(x, y));
}
}
}
ItemGrid = Temp;
}
/// <summary>
/// Adds a new item to the grid. The idx in the parameter is the idx of the item in the drive.
/// </summary>
/// <param name="idx"></param>
public void AddNewItem(int idx) {
UpdateHeight();
for (int y = 0; y < GetHeight(); y++) {
for (int x = 0; x < Width; x++) {
if (GetItemAt(x, y) == null) {
ItemGrid[y, x] = idx;
return;
}
}
}
}
private int[,] CreateEmptyGrid(int width, int height) {
int[,] Grid = new int[height, width];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
Grid[y, x] = -1;
}
}
return Grid;
}
}
}

View File

@ -1,66 +0,0 @@

using System.Collections.Generic;
namespace Cyber.Items {
/// <summary>
/// Represents the equipped items at given slots.
/// </summary>
public class Equipped {
Dictionary<EquipSlot, Item> EquippedItems = new Dictionary<EquipSlot, Item>();
/// <summary>
/// Inserts an item here, marking it as 'equipped'.
/// </summary>
/// <param name="slot">The slot to equip the item to.</param>
/// <param name="item">The item to equip.</param>
public void SetSlot(EquipSlot slot, Item item) {
EquippedItems[slot] = item;
}
/// <summary>
/// Empties the desired slot of any items.
/// </summary>
/// <param name="slot">The slot to empty.</param>
public void ClearSlot(EquipSlot slot) {
EquippedItems.Remove(slot);
}
/// <summary>
/// Returns the item at the given slot, or null if no item at the slot was found.
/// </summary>
/// <param name="slot"></param>
/// <returns></returns>
public Item GetItem(EquipSlot slot) {
if (EquippedItems.ContainsKey(slot)) {
return EquippedItems[slot];
}
return null;
}
/// <summary>
/// Returns a dictionary of all equipped items.
/// </summary>
/// <returns>Dictionary of equipped items.</returns>
public Dictionary<EquipSlot, Item> GetEquippedDict() {
return EquippedItems;
}
/// <summary>
/// Returns a list of all items that are generally equipped.
/// </summary>
/// <returns>List of equipped items.</returns>
public List<Item> GetEquippedList() {
return new List<Item>(EquippedItems.Values);
}
/// <summary>
/// Clears all equipped items, removing them from their slots.
/// </summary>
public void ClearAllEquipped() {
EquippedItems.Clear();
}
}
}

View File

@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 1bc32847ce18a3b4987872f04887b6de
timeCreated: 1494785490
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -44,10 +44,10 @@ namespace Cyber.Items {
/// <summary>
/// Builds a <see cref="InventoryAction.Equip"/> packet.
/// </summary>
/// <param name="itemID">The item ID to equip.</param>
/// <param name="itemIdx">The item index to equip.</param>
/// <returns></returns>
public InventoryActionPkt BuildEquipItem(int itemID) {
return new InventoryActionPkt(InventoryAction.Equip, itemID);
public InventoryActionPkt BuildEquipItem(int itemIdx) {
return new InventoryActionPkt(InventoryAction.Equip, itemIdx);
}
/// <summary>
@ -59,16 +59,15 @@ namespace Cyber.Items {
public bool HandleAction(InventoryAction action, int relatedInt) {
switch (action) {
case InventoryAction.Equip:
Item Item = ItemDB.Singleton.Get(relatedInt);
Inventory.Equipped.SetSlot(Item.Slot, Item);
Inventory.Drive.EquipItem(relatedInt);
return true;
case InventoryAction.Unequip:
EquipSlot Slot = (EquipSlot) relatedInt;
Inventory.Equipped.ClearSlot(Slot);
Inventory.Drive.UnequipSlot(Slot);
return true;
case InventoryAction.Use:
EquipSlot UseSlot = (EquipSlot) relatedInt;
Item UseItem = Inventory.Equipped.GetItem(UseSlot);
Item UseItem = Inventory.Drive.GetSlot(UseSlot);
if (UseItem != null && UseItem.Action != null && Character != null &&
(!Client.IsRunning() || Client.GetConnectedPlayer().Character != Character)) {
// Item exists, it has an action, and the character

View File

@ -0,0 +1,30 @@

namespace Cyber.Items {
/// <summary>
/// Represents a slot which contains an item and a bool weather the item is equipped or not.
/// </summary>
public struct Slot {
/// <summary>
/// The item that this slot holds. If this is null, the slot is empty.
/// </summary>
public Item Item;
/// <summary>
/// Weather this item is equipped or not.
/// </summary>
public bool Equipped;
/// <summary>
/// Creates a slot.
/// </summary>
/// <param name="item">Item in the slot, or null if the slot is empty.</param>
/// <param name="equipped">Weather this slot is equipped or not.</param>
public Slot(Item item, bool equipped) {
Item = item;
Equipped = equipped;
}
}
}

View File

@ -1,6 +1,6 @@
fileFormatVersion: 2
guid: fc91d98b617f041da8ff205f4252ed06
timeCreated: 1494705607
guid: ca2662d3bcd2ddf4d94a410f907d028d
timeCreated: 1494949326
licenseType: Free
MonoImporter:
serializedVersion: 2