From 39ce6809c0f31c2af662f2398adbd03b2bda8e97 Mon Sep 17 00:00:00 2001 From: hyperion51 Date: Sat, 6 Jun 2020 03:21:03 +0100 Subject: [PATCH] Inventory Events Added an event system allowing the UI to subscribe to changes in entity cargo, hardpoints or on specific items Fixed bugs in colony tab caused by recent refactoring --- .../.idea/contentModel.xml | 1 + .../ServerShared/Behaviors/FactoryBehavior.cs | 11 +- .../Behaviors/MiningController.cs | 9 +- Assets/Scripts/ServerShared/Entity.cs | 48 +++- .../ServerShared/IDynamicProperties.cs | 10 + .../ServerShared/IDynamicProperties.cs.meta | 11 + Assets/Scripts/ServerShared/ItemInstance.cs | 9 +- Assets/Scripts/StrategyGameManager.cs | 78 +----- Assets/Scripts/UI/ColonyTab.cs | 264 +++++++----------- Assets/Scripts/UI/PropertiesPanel.cs | 177 +++++++++++- Economy.Shared.Unity.csproj | 1 + 11 files changed, 370 insertions(+), 249 deletions(-) create mode 100644 Assets/Scripts/ServerShared/IDynamicProperties.cs create mode 100644 Assets/Scripts/ServerShared/IDynamicProperties.cs.meta diff --git a/.idea/.idea.Aetheria-Economy/.idea/contentModel.xml b/.idea/.idea.Aetheria-Economy/.idea/contentModel.xml index 6c4643e50..277d49fa2 100644 --- a/.idea/.idea.Aetheria-Economy/.idea/contentModel.xml +++ b/.idea/.idea.Aetheria-Economy/.idea/contentModel.xml @@ -1298,6 +1298,7 @@ + diff --git a/Assets/Scripts/ServerShared/Behaviors/FactoryBehavior.cs b/Assets/Scripts/ServerShared/Behaviors/FactoryBehavior.cs index 7ac9f32cf..86c9fb2c7 100644 --- a/Assets/Scripts/ServerShared/Behaviors/FactoryBehavior.cs +++ b/Assets/Scripts/ServerShared/Behaviors/FactoryBehavior.cs @@ -47,14 +47,11 @@ public class Factory : IBehavior, IPersistentBehavior _blueprint = value; RetoolingTime = ToolingTime; _retooling = true; - OnProductionUpdate?.Invoke(); - OnProductionUpdate = null; + Item.Change(); ItemName = Context.Cache.Get(value).Name; } } } - - public event Action OnProductionUpdate; private FactoryData _data; @@ -87,7 +84,7 @@ public class Factory : IBehavior, IPersistentBehavior if (_retooling) { _retooling = false; - OnProductionUpdate?.Invoke(); + Item.Change(); } if (ItemUnderConstruction != Guid.Empty) @@ -106,6 +103,7 @@ public class Factory : IBehavior, IPersistentBehavior Entity.AddCargo(craftedItemInstance); Entity.IncompleteCargo.Remove(ItemUnderConstruction); ItemUnderConstruction = Guid.Empty; + Item.Change(); } return true; @@ -117,7 +115,8 @@ public class Factory : IBehavior, IPersistentBehavior (pow(Context.Random.NextFloat(), blueprint.RandomExponent) + pow(Context.Random.NextFloat(), blueprint.RandomExponent)) / 2, ItemName); - OnProductionUpdate?.Invoke(); + if(ItemUnderConstruction!=Guid.Empty) + Item.Change(); return false; } diff --git a/Assets/Scripts/ServerShared/Behaviors/MiningController.cs b/Assets/Scripts/ServerShared/Behaviors/MiningController.cs index f3e4785a4..5a8617656 100644 --- a/Assets/Scripts/ServerShared/Behaviors/MiningController.cs +++ b/Assets/Scripts/ServerShared/Behaviors/MiningController.cs @@ -99,13 +99,14 @@ public class MiningController : ControllerBase, IBehavior, IPersistentBehavior, foreach (var item in _entity.Cargo .Select(id => _context.Cache.Get(id)) .Where(item => item is SimpleCommodity) - .Cast()) + .Cast() + .ToArray()) { - int supportedQuantity = (int) ((homeEntity.Capacity - homeEntity.OccupiedCapacity) / item.ItemData.Size); - var newItem = _entity.RemoveCargo(item, supportedQuantity); + int quantity = min((int) ((homeEntity.Capacity - homeEntity.OccupiedCapacity) / item.ItemData.Size), item.Quantity); + var newItem = _entity.RemoveCargo(item, quantity); homeEntity.AddCargo(newItem); - if (supportedQuantity < item.Quantity) + if (quantity < item.Quantity) { homeEntity.SetMessage("Colony is out of cargo space. Closing Mining Task."); FinishTask(); diff --git a/Assets/Scripts/ServerShared/Entity.cs b/Assets/Scripts/ServerShared/Entity.cs index 2d87f58ca..1bab9c44c 100644 --- a/Assets/Scripts/ServerShared/Entity.cs +++ b/Assets/Scripts/ServerShared/Entity.cs @@ -75,15 +75,25 @@ public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackR // [IgnoreMember] public Dictionary GearData; // [IgnoreMember] public Dictionary> ItemBehaviors; - private bool _inventoryChanged; - [IgnoreMember] public float Mass { get; private set; } [IgnoreMember] public float OccupiedCapacity { get; private set; } [IgnoreMember] public float ThermalMass { get; private set; } [IgnoreMember] public float Visibility => VisibilitySources.Values.Sum(); - public event Action OnInventoryUpdate; - + public class InventoryEvent : IDynamicProperties + { + public event Action OnChanged; + + public void Change() + { + OnChanged?.Invoke(); + } + } + private bool _cargoChanged; + public InventoryEvent CargoEvent = new InventoryEvent(); + private bool _gearChanged; + public InventoryEvent GearEvent = new InventoryEvent(); + public float Capacity { get @@ -161,6 +171,8 @@ public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackR return; } + hardpoint.ItemData = hardpoint.Gear.ItemData; + hardpoint.Behaviors = hardpoint.Gear.ItemData.Behaviors .Select(bd => bd.CreateInstance(Context, this, hardpoint.Gear)) .ToArray(); @@ -184,11 +196,12 @@ public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackR { Gear.Remove(hardpoint.Gear.ID); Cargo.Add(hardpoint.Gear.ID); + _cargoChanged = true; } hardpoint.Gear = gear; HydrateHardpoint(hardpoint); - _inventoryChanged = true; + _gearChanged = true; } public bool Equip(Guid gearID, bool force = false) @@ -226,7 +239,7 @@ public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackR Mass += item.Mass; ThermalMass += item.ThermalMass; OccupiedCapacity += item.Size; - _inventoryChanged = true; + _cargoChanged = true; return item; } @@ -238,7 +251,7 @@ public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackR Mass -= item.Mass; ThermalMass -= item.ThermalMass; OccupiedCapacity -= item.Size; - _inventoryChanged = true; + _cargoChanged = true; return item; } @@ -260,12 +273,13 @@ public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackR var existingCommodity = Context.Cache.Get(existingCommodityID); existingCommodity.Quantity += item.Quantity; Context.Cache.Delete(item); + _cargoChanged = true; return existingCommodity; } // No match was found, simply add the item instance to the cargo Cargo.Add(item.ID); - _inventoryChanged = true; + _cargoChanged = true; return item; } @@ -294,7 +308,7 @@ public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackR ThermalMass -= item.ThermalMass; OccupiedCapacity -= item.Size; - _inventoryChanged = true; + _cargoChanged = true; return item; } @@ -442,11 +456,6 @@ public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackR Cargo.Select(i => Context.Cache.Get(i)).Sum(ii => ii.Size); } - public void ClearInventoryListeners() - { - OnInventoryUpdate = null; - } - public T GetBehavior() where T : class, IBehavior { foreach (var hardpoint in Hardpoints) @@ -605,6 +614,17 @@ public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackR // foreach (var axis in ItemBehaviors[staleItem].Where(b => b is IAnalogBehavior).Cast()) // Axes[axis] = 0; // } + + if (_cargoChanged) + { + CargoEvent.Change(); + _cargoChanged = false; + } + if (_gearChanged) + { + GearEvent.Change(); + _gearChanged = false; + } } public void SetMessage(string message) diff --git a/Assets/Scripts/ServerShared/IDynamicProperties.cs b/Assets/Scripts/ServerShared/IDynamicProperties.cs new file mode 100644 index 000000000..4bdc321e4 --- /dev/null +++ b/Assets/Scripts/ServerShared/IDynamicProperties.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + + +public interface IDynamicProperties +{ + event Action OnChanged; +} diff --git a/Assets/Scripts/ServerShared/IDynamicProperties.cs.meta b/Assets/Scripts/ServerShared/IDynamicProperties.cs.meta new file mode 100644 index 000000000..7e0c6be5a --- /dev/null +++ b/Assets/Scripts/ServerShared/IDynamicProperties.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9188eb1236c6f6f42b4c2d04b3111867 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/ServerShared/ItemInstance.cs b/Assets/Scripts/ServerShared/ItemInstance.cs index 62b42062f..ff20b2eba 100644 --- a/Assets/Scripts/ServerShared/ItemInstance.cs +++ b/Assets/Scripts/ServerShared/ItemInstance.cs @@ -55,9 +55,16 @@ public class SimpleCommodity : ItemInstance } [MessagePackObject, JsonObject(MemberSerialization.OptIn)] -public class Gear : CraftedItemInstance +public class Gear : CraftedItemInstance, IDynamicProperties { [JsonProperty("durability"), Key(7)] public float Durability; public EquippableItemData ItemData => Context.GetData(this); + + public event Action OnChanged; + + public void Change() + { + OnChanged?.Invoke(); + } } \ No newline at end of file diff --git a/Assets/Scripts/StrategyGameManager.cs b/Assets/Scripts/StrategyGameManager.cs index 24bd00136..ce2c14b93 100644 --- a/Assets/Scripts/StrategyGameManager.cs +++ b/Assets/Scripts/StrategyGameManager.cs @@ -108,7 +108,8 @@ public class StrategyGameManager : MonoBehaviour private Guid _selectedOrbit = Guid.Empty; private Guid _selectedTowingTarget = Guid.Empty; private float _orbitRadius; - private Guid _selectedEntity; + private Guid _selectedObject; + private Guid _selectedColony; void Start() { @@ -122,6 +123,7 @@ public class StrategyGameManager : MonoBehaviour _context = new GameContext(_cache, Debug.Log); ColonyTab.Context = _context; TechTree.Context = _context; + PropertiesPanel.Context = _context; _context.MapLayers = _cache.GetAll().ToDictionary(ml => ml.Name); _context.GalaxyZones = _cache.GetAll() .ToDictionary(z => z.ID, z => new SimplifiedZoneData @@ -215,7 +217,7 @@ public class StrategyGameManager : MonoBehaviour for(int i=0; i e is OrbitalEntity); - _selectedEntity = colony.ID; + _selectedColony = colony.ID; foreach (var ship in entities.Where(e => e is Ship)) { foreach (var controller in ship.GetBehaviors()) @@ -302,7 +304,7 @@ public class StrategyGameManager : MonoBehaviour if (_currentTab == ColonyTabButton) { - ColonyTab.Open(_selectedEntity); + ColonyTab.Open(_selectedColony); } }; @@ -441,7 +443,12 @@ public class StrategyGameManager : MonoBehaviour zoneShip.Icon.GetComponent().OnClick += (collider, data) => { if (data.button == PointerEventData.InputButton.Left) - Select(ship.ID); + { + if (data.clickCount == 1) + Select(ship.ID); + else if (data.clickCount == 2) + ColonyTabButton.OnPointerClick(data); + } else if (data.button == PointerEventData.InputButton.Right) ShowContextMenu(ship.ID); }; @@ -480,7 +487,6 @@ public class StrategyGameManager : MonoBehaviour { if (data.button == PointerEventData.InputButton.Left) { - _selectedEntity = orbital.ID; if (data.clickCount == 1) Select(orbital.ID); else if (data.clickCount == 2) @@ -670,7 +676,8 @@ public class StrategyGameManager : MonoBehaviour void Select(Guid clickTarget) { - var targetObject = _context.Cache.Get(clickTarget); + _selectedObject = clickTarget; + var targetObject = _context.Cache.Get(_selectedObject); if (targetObject is PlanetData planet) { @@ -717,39 +724,7 @@ public class StrategyGameManager : MonoBehaviour if (targetObject is Entity entity) { - PropertiesPanel.Clear(); - PropertiesPanel.Title.text = entity.Name; - var hull = _context.Cache.Get(entity.Hull); - var hullData = _context.Cache.Get(hull.Data); - PropertiesPanel.AddSection( - hullData.HullType == HullType.Ship ? "Drone Ship" : - hullData.HullType == HullType.Station ? "Colony" : - "Weapons Platform"); - PopulateGearProperties(PropertiesPanel.AddList(hullData.Name), hull, entity); - //PropertiesPanel.AddProperty("Hull", () => $"{hullData.Name}"); - PropertiesPanel.AddProperty("Capacity", () => $"{entity.OccupiedCapacity}/{entity.Capacity:0}"); - PropertiesPanel.AddProperty("Mass", () => $"{entity.Mass.SignificantDigits(_context.GlobalData.SignificantDigits)}"); - PropertiesPanel.AddProperty("Temperature", () => $"{entity.Temperature:0}°K"); - PropertiesPanel.AddProperty("Energy", () => $"{entity.Energy:0}/{entity.GetBehaviors().First().Capacitance:0}"); - var gearList = PropertiesPanel.AddList("Gear"); - var equippedItems = entity.Hardpoints.Where(hp => hp.Gear != null).Select(hp => hp.Gear); - foreach(var gear in equippedItems) - PopulateGearProperties(gearList.AddList(gear.ItemData.Name), gear, entity); - if(!entity.Cargo.Any()) - PropertiesPanel.AddProperty("No Cargo"); - else - { - var cargoList = PropertiesPanel.AddList("Cargo"); - foreach (var itemID in entity.Cargo) - { - var itemInstance = _context.Cache.Get(itemID); - var data = _context.Cache.Get(itemInstance.Data); - if(itemInstance is SimpleCommodity simpleCommodity) - cargoList.AddProperty(data.Name, () => simpleCommodity.Quantity.ToString()); - else - cargoList.AddProperty(data.Name); - } - } + PropertiesPanel.Inspect(entity); } if (targetObject is ZoneData zone) @@ -763,31 +738,6 @@ public class StrategyGameManager : MonoBehaviour PropertiesPanel.RefreshValues(); } - void PopulateGearProperties(PropertiesList panel, Gear gear, Entity entity) - { - var data = gear.ItemData; - panel.AddProperty("Durability", () => $"{gear.Durability.SignificantDigits(_context.GlobalData.SignificantDigits)}/{_context.Evaluate(data.Durability, gear).SignificantDigits(_context.GlobalData.SignificantDigits)}"); - foreach (var behavior in data.Behaviors) - { - var type = behavior.GetType(); - if (type.GetCustomAttribute(typeof(RuntimeInspectable)) != null) - { - foreach (var field in type.GetFields().Where(f => f.GetCustomAttribute() != null)) - { - var fieldType = field.FieldType; - if (fieldType == typeof(float)) - panel.AddProperty(field.Name, () => $"{((float) field.GetValue(behavior)).SignificantDigits(_context.GlobalData.SignificantDigits)}"); - else if (fieldType == typeof(int)) - panel.AddProperty(field.Name, () => $"{(int) field.GetValue(behavior)}"); - else if (fieldType == typeof(PerformanceStat)) - { - var stat = (PerformanceStat) field.GetValue(behavior); - panel.AddProperty(field.Name, () => $"{_context.Evaluate(stat, gear, entity).SignificantDigits(_context.GlobalData.SignificantDigits)}"); - } - } - } - } - } void PopulateGalaxy() { diff --git a/Assets/Scripts/UI/ColonyTab.cs b/Assets/Scripts/UI/ColonyTab.cs index c537a35b5..3a49e131c 100644 --- a/Assets/Scripts/UI/ColonyTab.cs +++ b/Assets/Scripts/UI/ColonyTab.cs @@ -31,6 +31,10 @@ public class ColonyTab : MonoBehaviour private Guid _selectedColony; private GameContext _context; private Hardpoint _selectedHardpoint; + private IDynamicProperties HardpointChange; + private IDynamicProperties CargoChange; + private Action OnHardpointsChanged; + private Action OnCargoChanged; public void Open(Guid colony) { @@ -43,14 +47,14 @@ public class ColonyTab : MonoBehaviour UpdateGeneral(entity); - entity.OnInventoryUpdate += () => UpdateInventory(entity); UpdateInventory(entity); } private void OnDisable() { - var entity = Context.Cache.Get(_selectedColony); - entity.ClearInventoryListeners(); + HardpointChange.OnChanged -= OnHardpointsChanged; + CargoChange.OnChanged -= OnCargoChanged; + Details.Clear(); } public void UpdateGeneral(Entity entity) @@ -72,108 +76,125 @@ public class ColonyTab : MonoBehaviour public void UpdateInventory(Entity entity) { - Inventory.Clear(); - var corporation = Context.Cache.Get(entity.Corporation); var blueprints = corporation.UnlockedBlueprints.Select(id => Context.Cache.Get(id)); var hull = Context.Cache.Get(entity.Hull); var hullData = Context.Cache.Get(hull.Data); - - // Create item data mapping for cargo - var cargoData = entity.Cargo.ToDictionary(id => _context.Cache.Get(id), - id => Context.Cache.Get(_context.Cache.Get(id).Data)); + OnHardpointsChanged = RefreshInventory; + HardpointChange = entity.GearEvent; + HardpointChange.OnChanged += OnHardpointsChanged; + OnCargoChanged = RefreshInventory; + CargoChange = entity.CargoEvent; + CargoChange.OnChanged += OnCargoChanged; - Inventory.AddSection("Gear"); + RefreshInventory(); - // Skip first hardpoint, that one is always the hull - foreach (var hardpoint in entity.Hardpoints.Skip(1)) + void RefreshInventory() { - // These are the items in the inventory which can be equipped to the current hardpoint - var matchingCargoGear = cargoData - .Where(x => - x.Value is GearData gearData && - gearData.HardpointType == hardpoint.HardpointData.Type) - .Select(x => x.Key as Gear) - .ToArray(); + Debug.Log("Refreshing Inventory!"); - // Hardpoint has no gear assigned to it - if (hardpoint.Gear == null) + // Create item data mapping for cargo + var cargoData = entity.Cargo.ToDictionary(id => _context.Cache.Get(id), + id => Context.Cache.Get(_context.Cache.Get(id).Data)); + + Inventory.Clear(); + Inventory.AddSection("Hardpoints"); + var incompleteGearList = entity.IncompleteGear.Keys + .Select(id => Context.Cache.Get(id)) + .ToList(); + // Skip first hardpoint, that one is always the hull + foreach (var hardpoint in entity.Hardpoints.Skip(1)) { - // Check whether we're currently building some gear for this hardpoint - var incompleteGear = entity.IncompleteGear.Keys - .Select(id => Context.Cache.Get(id)) - .FirstOrDefault(g => g.ItemData.HardpointType == hardpoint.HardpointData.Type); - - // We're building something for this hardpoint, show a progress bar! - if (incompleteGear != null) + // These are the items in the inventory which can be equipped to the current hardpoint + var matchingCargoGear = cargoData + .Where(x => + x.Value is GearData gearData && + gearData.HardpointType == hardpoint.HardpointData.Type) + .Select(x => x.Key as Gear) + .ToArray(); + + // Hardpoint has no gear assigned to it + if (hardpoint.Gear == null) { - Inventory.AddProgressField(incompleteGear.Name, () => - { - var productionTime = _context.Cache.Get(incompleteGear.Blueprint).ProductionTime; - return (productionTime - (float) entity.IncompleteGear[incompleteGear.ID]) / productionTime; - }); - } - else // We're not building anything - { - // These are the blueprints we could build onto this hardpoint directly - var matchingBlueprints = blueprints.Where(bp => - bp.FactoryItem == Guid.Empty && - Context.Cache.Get(bp.Item) is GearData gearData && - gearData.HardpointType == hardpoint.HardpointData.Type).ToArray(); + // Check whether we're currently building some gear for this hardpoint + var incompleteGear = incompleteGearList.FirstOrDefault(g => g.ItemData.HardpointType == hardpoint.HardpointData.Type); - Action onClick = null; - if (matchingCargoGear.Any() || matchingBlueprints.Any()) - onClick = data => + // We're building something for this hardpoint, show a progress bar! + if (incompleteGear != null) + { + incompleteGearList.Remove(incompleteGear); + Inventory.AddProgressField(incompleteGear.Name, () => { - if (data.button == PointerEventData.InputButton.Left) - PopulateDetails(entity, matchingBlueprints); - - else if (data.button == PointerEventData.InputButton.Right) + var productionTime = _context.Cache.Get(incompleteGear.Blueprint).ProductionTime; + return (productionTime - (float) entity.IncompleteGear[incompleteGear.ID]) / productionTime; + }); + } + else // We're not building anything + { + // These are the blueprints we could build onto this hardpoint directly + var matchingBlueprints = blueprints.Where(bp => + bp.FactoryItem == Guid.Empty && + Context.Cache.Get(bp.Item) is GearData gearData && + gearData.HardpointType == hardpoint.HardpointData.Type).ToArray(); + + Action onClick = null; + if (matchingCargoGear.Any() || matchingBlueprints.Any()) + onClick = data => { - ContextMenu.gameObject.SetActive(true); - ContextMenu.Clear(); - if (matchingCargoGear.Any()) - ContextMenu.AddDropdown("Install", matchingCargoGear - .Select(gear => (gear.Name, () => entity.Equip(gear, hardpoint), true))); - if (matchingBlueprints.Any()) - ContextMenu.AddDropdown("Build", matchingBlueprints - .Select(blueprint => - (blueprint.Name, () => - entity.Build(blueprint, 1, _context.Cache.Get(blueprint.Item).Name, true), - entity.GetBlueprintIngredients(blueprint, out _, out _)))); - ContextMenu.Show(); - } - }; - Inventory.AddProperty($"Empty {Enum.GetName(typeof(HardpointType), hardpoint.HardpointData.Type)} Hardpoint", null, onClick, matchingBlueprints.Any()); + if (data.button == PointerEventData.InputButton.Left) + PopulateDetails(entity, matchingBlueprints); + + else if (data.button == PointerEventData.InputButton.Right) + { + ContextMenu.gameObject.SetActive(true); + ContextMenu.Clear(); + if (matchingCargoGear.Any()) + ContextMenu.AddDropdown("Install", matchingCargoGear + .Select(gear => (gear.Name, () => entity.Equip(gear, hardpoint), true))); + if (matchingBlueprints.Any()) + ContextMenu.AddDropdown("Build", matchingBlueprints + .Select(blueprint => + (blueprint.Name, () => + entity.Build(blueprint, 1, _context.Cache.Get(blueprint.Item).Name, true), + entity.GetBlueprintIngredients(blueprint, out _, out _)))); + ContextMenu.Show(); + } + }; + Inventory.AddProperty($"Empty {Enum.GetName(typeof(HardpointType), hardpoint.HardpointData.Type)} Hardpoint", null, onClick, matchingBlueprints.Any()); + } + } + else + { + var prop = Inventory.AddProperty(hardpoint.Gear.Name, null, _ => + { + _selectedHardpoint = hardpoint; + Details.Inspect(entity, hardpoint); + }, true); + + if (hardpoint == _selectedHardpoint) + { + Inventory.SelectedChild = prop.Button; + prop.Button.CurrentState = FlatButtonState.Selected; + } } } + + if(!entity.Cargo.Any()) + Inventory.AddSection("No Cargo"); else { - var prop = Inventory.AddProperty(hardpoint.Gear.Name, null, _ => + Inventory.AddSection("Cargo"); + foreach (var x in cargoData) { - _selectedHardpoint = hardpoint; - PopulateDetails(entity, hardpoint); - }, true); - - if (hardpoint == _selectedHardpoint) prop.Button.OnPointerClick(new PointerEventData(null){button = PointerEventData.InputButton.Left}); + if(x.Key is SimpleCommodity simpleCommodity) + Inventory.AddProperty(x.Value.Name, () => simpleCommodity.Quantity.ToString()); + else + Inventory.AddProperty(x.Value.Name); + } } + Inventory.RefreshValues(); } - - if(!entity.Cargo.Any()) - Inventory.AddSection("No Cargo"); - else - { - Inventory.AddSection("Cargo"); - foreach (var x in cargoData) - { - if(x.Key is SimpleCommodity simpleCommodity) - Inventory.AddProperty(x.Value.Name, () => simpleCommodity.Quantity.ToString()); - else - Inventory.AddProperty(x.Value.Name); - } - } - Inventory.RefreshValues(); } void PopulateDetails(Entity entity, IEnumerable blueprints) @@ -193,79 +214,8 @@ public class ColonyTab : MonoBehaviour if(entity.GetBlueprintIngredients(blueprint, out _, out _)) blueprintList.AddButton("Build", _ => entity.Build(blueprint, 1, bpItemData.Name, true)); - } - Details.RefreshValues(); - } - - void PopulateDetails(Entity entity, Hardpoint hardpoint) - { - Details.Clear(); - Details.AddProperty("Durability", - () => $"{hardpoint.Gear.Durability.SignificantDigits(Context.GlobalData.SignificantDigits)}/{Context.Evaluate(hardpoint.ItemData.Durability, hardpoint.Gear).SignificantDigits(Context.GlobalData.SignificantDigits)}"); - foreach (var behavior in hardpoint.Behaviors) - { - if (behavior is Factory factory) - { - factory.OnProductionUpdate += () => PopulateDetails(entity, hardpoint); - Details.AddField("Production Quality", () => factory.ProductionQuality, f => factory.ProductionQuality = f, 0, 1); - var corporation = Context.Cache.Get(entity.Corporation); - var compatibleBlueprints = corporation.UnlockedBlueprints - .Select(id => _context.Cache.Get(id)) - .Where(bp => bp.FactoryItem == hardpoint.ItemData.ID).ToList(); - if (factory.RetoolingTime > 0) - { - Details.AddProgressField("Retooling", () => (factory.ToolingTime - (float) factory.RetoolingTime) / factory.ToolingTime); - } - else - { - Details.AddField("Item", - () => compatibleBlueprints.FindIndex(bp=>bp.ID== factory.Blueprint) + 1, - i => factory.Blueprint = i == 0 ? Guid.Empty : compatibleBlueprints[i - 1].ID, - new []{"None"}.Concat(compatibleBlueprints.Select(bp=>bp.Name)).ToArray()); - if (factory.Blueprint != Guid.Empty) - { - if (factory.ItemUnderConstruction != Guid.Empty) - { - Details.AddProgressField("Production", () => - { - var itemInstance = _context.Cache.Get(factory.ItemUnderConstruction); - var blueprintData = _context.Cache.Get(itemInstance.Blueprint); - return (blueprintData.ProductionTime - (float) entity.IncompleteCargo[factory.ItemUnderConstruction]) / blueprintData.ProductionTime; - }); - } - else - { - var ingredientsList = Details.AddList("Ingredients Needed"); - var blueprintData = _context.Cache.Get(factory.Blueprint); - foreach (var ingredient in blueprintData.Ingredients) - { - var itemData = _context.Cache.Get(ingredient.Key); - ingredientsList.AddProperty(itemData.Name, () => ingredient.Value.ToString()); - } - } - } - } - } - } - foreach (var behavior in hardpoint.ItemData.Behaviors) - { - var type = behavior.GetType(); - if (type.GetCustomAttribute(typeof(RuntimeInspectable)) != null) - { - foreach (var field in type.GetFields().Where(f => f.GetCustomAttribute() != null)) - { - var fieldType = field.FieldType; - if (fieldType == typeof(float)) - Details.AddProperty(field.Name, () => $"{((float) field.GetValue(behavior)).SignificantDigits(Context.GlobalData.SignificantDigits)}"); - else if (fieldType == typeof(int)) - Details.AddProperty(field.Name, () => $"{(int) field.GetValue(behavior)}"); - else if (fieldType == typeof(PerformanceStat)) - { - var stat = (PerformanceStat) field.GetValue(behavior); - Details.AddProperty(field.Name, () => $"{Context.Evaluate(stat, hardpoint.Gear, entity).SignificantDigits(Context.GlobalData.SignificantDigits)}"); - } - } - } + + blueprintList.RefreshValues(); } Details.RefreshValues(); } diff --git a/Assets/Scripts/UI/PropertiesPanel.cs b/Assets/Scripts/UI/PropertiesPanel.cs index 107670512..526b7840d 100644 --- a/Assets/Scripts/UI/PropertiesPanel.cs +++ b/Assets/Scripts/UI/PropertiesPanel.cs @@ -3,6 +3,7 @@ using System.Collections; using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Reflection; using TMPro; using UnityEngine; using UnityEngine.EventSystems; @@ -22,19 +23,32 @@ public class PropertiesPanel : MonoBehaviour public BoolField BoolField; public PropertyButton PropertyButton; public ButtonField ButtonField; + [HideInInspector] public FlatFlatButton SelectedChild; [HideInInspector] public GameContext Context; protected List Properties = new List(); protected List Buttons = new List(); - protected FlatFlatButton SelectedChild; protected event Action RefreshPropertyValues; protected bool RadioSelection = false; - private void Update() + protected IDynamicProperties ChangeSource; + protected Action OnPropertiesChanged; + + protected void Update() { RefreshValues(); } + private void OnDestroy() + { + RemoveListener(); + } + + private void OnDisable() + { + RemoveListener(); + } + public void Clear() { foreach(var property in Properties) @@ -96,6 +110,7 @@ public class PropertiesPanel : MonoBehaviour public PropertiesList AddList(string name) //, IEnumerable<(string, Func)> elements) { var list = Instantiate(ListPrefab, transform); + list.Context = Context; list.Title.text = name; // foreach (var element in elements) // { @@ -105,7 +120,7 @@ public class PropertiesPanel : MonoBehaviour // item.ValueFunction = element.Item2; // Properties.Add(item.gameObject); // } - RefreshPropertyValues += () => list.RefreshValues(); + //RefreshPropertyValues += () => list.RefreshValues(); Properties.Add(list.gameObject); return list; } @@ -224,6 +239,162 @@ public class PropertiesPanel : MonoBehaviour Properties.Add(field.gameObject); } + void RemoveListener() + { + if (ChangeSource != null) + ChangeSource.OnChanged -= OnPropertiesChanged; + } + + public void Inspect(Entity entity) + { + Clear(); + Title.text = entity.Name; + var hull = Context.Cache.Get(entity.Hull); + var hullData = Context.Cache.Get(hull.Data); + AddSection( + hullData.HullType == HullType.Ship ? "Ship" : + hullData.HullType == HullType.Station ? "Station" : + "Platform"); + //AddList(hullData.Name).Inspect(hull, entity); + //PropertiesPanel.AddProperty("Hull", () => $"{hullData.Name}"); + AddProperty("Capacity", () => $"{entity.OccupiedCapacity}/{entity.Capacity:0}"); + AddProperty("Mass", () => $"{entity.Mass.SignificantDigits(Context.GlobalData.SignificantDigits)}"); + AddProperty("Temperature", () => $"{entity.Temperature:0}°K"); + AddProperty("Energy", () => $"{entity.Energy:0}/{entity.GetBehaviors().First().Capacitance:0}"); + + AddList("Gear").InspectHardpoints(entity); + AddList("Cargo").InspectCargo(entity); + + RefreshValues(); + } + + public void InspectHardpoints(Entity entity) + { + RemoveListener(); + + ChangeSource = entity.GearEvent; + OnPropertiesChanged = InspectGearInternal; + ChangeSource.OnChanged += OnPropertiesChanged; + InspectGearInternal(); + + void InspectGearInternal() + { + Clear(); + var equippedItems = entity.Hardpoints.Where(hp => hp.Gear != null); + foreach(var hardpoint in equippedItems) + AddList(hardpoint.ItemData.Name).Inspect(entity, hardpoint); + RefreshValues(); + } + } + + public void InspectCargo(Entity entity) + { + RemoveListener(); + + ChangeSource = entity.CargoEvent; + OnPropertiesChanged = InspectCargoInternal; + ChangeSource.OnChanged += OnPropertiesChanged; + InspectCargoInternal(); + + void InspectCargoInternal() + { + Clear(); + foreach (var itemID in entity.Cargo) + { + var itemInstance = Context.Cache.Get(itemID); + var data = Context.Cache.Get(itemInstance.Data); + if(itemInstance is SimpleCommodity simpleCommodity) + AddProperty(data.Name, () => simpleCommodity.Quantity.ToString()); + else + AddProperty(data.Name); + } + RefreshValues(); + } + } + + public void Inspect(Entity entity, Hardpoint hardpoint) + { + RemoveListener(); + + ChangeSource = hardpoint.Gear; + OnPropertiesChanged = InspectGearInternal; + ChangeSource.OnChanged += OnPropertiesChanged; + InspectGearInternal(); + + void InspectGearInternal() + { + Clear(); + AddProperty("Durability", () => $"{hardpoint.Gear.Durability.SignificantDigits(Context.GlobalData.SignificantDigits)}/{Context.Evaluate(hardpoint.ItemData.Durability, hardpoint.Gear).SignificantDigits(Context.GlobalData.SignificantDigits)}"); + foreach (var behavior in hardpoint.ItemData.Behaviors) + { + var type = behavior.GetType(); + if (type.GetCustomAttribute(typeof(RuntimeInspectable)) != null) + { + foreach (var field in type.GetFields().Where(f => f.GetCustomAttribute() != null)) + { + var fieldType = field.FieldType; + if (fieldType == typeof(float)) + AddProperty(field.Name, () => $"{((float) field.GetValue(behavior)).SignificantDigits(Context.GlobalData.SignificantDigits)}"); + else if (fieldType == typeof(int)) + AddProperty(field.Name, () => $"{(int) field.GetValue(behavior)}"); + else if (fieldType == typeof(PerformanceStat)) + { + var stat = (PerformanceStat) field.GetValue(behavior); + AddProperty(field.Name, () => $"{Context.Evaluate(stat, hardpoint.Gear, entity).SignificantDigits(Context.GlobalData.SignificantDigits)}"); + } + } + } + } + foreach (var behavior in hardpoint.Behaviors) + { + if (behavior is Factory factory) + { + AddField("Production Quality", () => factory.ProductionQuality, f => factory.ProductionQuality = f, 0, 1); + var corporation = Context.Cache.Get(entity.Corporation); + var compatibleBlueprints = corporation.UnlockedBlueprints + .Select(id => Context.Cache.Get(id)) + .Where(bp => bp.FactoryItem == hardpoint.ItemData.ID).ToList(); + if (factory.RetoolingTime > 0) + { + AddProgressField("Retooling", () => (factory.ToolingTime - (float) factory.RetoolingTime) / factory.ToolingTime); + } + else + { + AddField("Item", + () => compatibleBlueprints.FindIndex(bp=>bp.ID== factory.Blueprint) + 1, + i => factory.Blueprint = i == 0 ? Guid.Empty : compatibleBlueprints[i - 1].ID, + new []{"None"}.Concat(compatibleBlueprints.Select(bp=>bp.Name)).ToArray()); + if (factory.Blueprint != Guid.Empty) + { + if (factory.ItemUnderConstruction != Guid.Empty) + { + AddProgressField("Production", () => + { + if (factory.ItemUnderConstruction == Guid.Empty) return 1; + var itemInstance = Context.Cache.Get(factory.ItemUnderConstruction); + var blueprintData = Context.Cache.Get(itemInstance.Blueprint); + return (blueprintData.ProductionTime - (float) entity.IncompleteCargo[factory.ItemUnderConstruction]) / blueprintData.ProductionTime; + }); + } + else + { + var ingredientsList = AddList("Ingredients Needed"); + var blueprintData = Context.Cache.Get(factory.Blueprint); + foreach (var ingredient in blueprintData.Ingredients) + { + var itemData = Context.Cache.Get(ingredient.Key); + ingredientsList.AddProperty(itemData.Name, () => ingredient.Value.ToString()); + } + ingredientsList.RefreshValues(); + } + } + } + } + } + RefreshValues(); + } + } + // public void Inspect(object obj, bool inspectablesOnly = false, bool readWrite = false, bool topLevel = true) // { // if(topLevel) diff --git a/Economy.Shared.Unity.csproj b/Economy.Shared.Unity.csproj index 4e1c16b33..1de2a4b59 100644 --- a/Economy.Shared.Unity.csproj +++ b/Economy.Shared.Unity.csproj @@ -113,6 +113,7 @@ +