Colony Tab Interface

Properties panel supports read/write properties
Colony tab is now populated with colony data when a colony is selected
This commit is contained in:
hyperion51 2020-06-01 03:11:04 +01:00
commit a99b4e82f3
30 changed files with 7598 additions and 3280 deletions

View file

@ -363,21 +363,60 @@ public class DatabaseListView : EditorWindow
}
}
}
using (var h = new HorizontalScope(ListItemStyle))
{
if (GUI.Button(h.rect, GUIContent.none, GUIStyle.none))
{
CreateItem(_itemTypes[i], newItem =>
{
if(newItem is SimpleCommodityData simpleCommodityData)
{
simpleCommodityData.Category =
(SimpleCommodityCategory) Enum.Parse(typeof(SimpleCommodityCategory),
itemGroup.Key);
simpleCommodityData.Name = $"New {itemGroup.Key}";
}
else if(newItem is CompoundCommodityData compoundCommodityData)
{
compoundCommodityData.Category =
(CompoundCommodityCategory) Enum.Parse(
typeof(CompoundCommodityCategory), itemGroup.Key);
compoundCommodityData.Name = $"New {itemGroup.Key}";
}
else if(newItem is GearData gearData)
{
gearData.Hardpoint =
(HardpointType) Enum.Parse(typeof(HardpointType), itemGroup.Key);
gearData.Name = $"New {itemGroup.Key}";
}
else if(newItem is HullData hullData)
{
hullData.HullType = (HullType) Enum.Parse(typeof(HullType), itemGroup.Key);
hullData.Name = $"New {itemGroup.Key}";
}
});
}
GUILayout.Space(30);
GUILayout.Label("New " + itemGroup.Key);
var rect = GetControlRect(false, GUILayout.Width(EditorGUIUtility.singleLineHeight));
GUI.DrawTexture(rect, Icons.Instance.plus, ScaleMode.StretchToFill, true, 1, LabelColor, 0, 0);
}
}
}
foreach (var item in items.Where(e=>e.GetType()==_itemTypes[i]).OrderBy(item=>item.Name))
if (!itemGroups.Any())
{
}
using (var h = new HorizontalScope(ListItemStyle))
{
if(GUI.Button(h.rect, GUIContent.none, GUIStyle.none))
CreateItem(_itemTypes[i]);
GUILayout.Space(20);
GUILayout.Label("New " + _itemTypes[i].Name);
var rect = GetControlRect(false, GUILayout.Width(EditorGUIUtility.singleLineHeight));
GUI.DrawTexture(rect, Icons.Instance.plus, ScaleMode.StretchToFill, true, 1, LabelColor, 0, 0);
using (var h = new HorizontalScope(ListItemStyle))
{
if(GUI.Button(h.rect, GUIContent.none, GUIStyle.none))
CreateItem(_itemTypes[i]);
GUILayout.Space(20);
GUILayout.Label("New " + _itemTypes[i].Name);
var rect = GetControlRect(false, GUILayout.Width(EditorGUIUtility.singleLineHeight));
GUI.DrawTexture(rect, Icons.Instance.plus, ScaleMode.StretchToFill, true, 1, LabelColor, 0, 0);
}
}
}
}
@ -449,11 +488,12 @@ public class DatabaseListView : EditorWindow
_inspector.Repaint();
}
private DatabaseEntry CreateItem(Type type)
private DatabaseEntry CreateItem(Type type, Action<DatabaseEntry> onCreate = null)
{
var newEntry = (DatabaseEntry) Activator.CreateInstance(type);
if(newEntry is INamedEntry entry)
entry.EntryName = $"New {FormatTypeName(type.Name)}";
onCreate?.Invoke(newEntry);
_databaseCache.Add(newEntry);
Select(newEntry);
return newEntry;

View file

@ -32,12 +32,16 @@ public interface INamedEntry
Union(11, typeof(Player)),
Union(12, typeof(Corporation)),
Union(13, typeof(MegaCorporation)),
Union(14, typeof(StationData)),
Union(14, typeof(OrbitalEntity)),
Union(15, typeof(OrbitData)),
Union(16, typeof(PlanetData)),
Union(17, typeof(PersonalityAttribute)),
Union(18, typeof(AgentTask)),
Union(19, typeof(LoadoutData)),
Union(20, typeof(Ship)),
Union(21, typeof(Mining)),
Union(22, typeof(StationTowing)),
Union(23, typeof(Survey)),
JsonObject(MemberSerialization.OptIn), JsonConverter(typeof(JsonKnownTypesConverter<DatabaseEntry>))]
//[Union(21, typeof(ContractData))]
//[Union(22, typeof(Station))]

View file

@ -15,19 +15,50 @@ using static Unity.Mathematics.math;
JsonObject(MemberSerialization.OptIn), JsonConverter(typeof(JsonKnownTypesConverter<Entity>))]
public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackReceiver, INamedEntry
{
[JsonProperty("temperature"), Key(1)] public float Temperature;
[JsonProperty("energy"), Key(2)] public float Energy;
[JsonProperty("position"), Key(3)] public float2 Position;
[JsonProperty("direction"), Key(4)] public float2 Direction = float2(0,1);
[JsonProperty("velocity"), Key(5)] public float2 Velocity;
[JsonProperty("cargo"), Key(6)] public readonly List<Guid> Cargo; // Type: ItemInstance
[JsonProperty("equipment"), Key(7)] public readonly List<Guid> EquippedItems; // Type: Gear
[JsonProperty("parent"), Key(8)] public Guid Parent; // Type: Entity
[JsonProperty("children"), Key(9)] public List<Guid> Children = new List<Guid>(); // Type: Entity
[JsonProperty("hull"), Key(10)] public Guid Hull; // Type: Gear
[JsonProperty("persistedBehaviorData"), Key(11)] public Dictionary<Guid, PersistentBehaviorData[]> PersistedBehaviors;
[JsonProperty("corporation"), Key(12)] public Guid Corporation;
[JsonProperty("name"), Key(13)] public string Name;
[JsonProperty("temperature"), Key(1)]
public float Temperature;
[JsonProperty("energy"), Key(2)]
public float Energy;
[JsonProperty("position"), Key(3)]
public float2 Position;
[JsonProperty("direction"), Key(4)]
public float2 Direction = float2(0,1);
[JsonProperty("velocity"), Key(5)]
public float2 Velocity;
[JsonProperty("cargo"), Key(6)]
public readonly List<Guid> Cargo; // Type: ItemInstance
[JsonProperty("equipment"), Key(7)]
public readonly List<Guid> EquippedItems; // Type: Gear
[JsonProperty("parent"), Key(8)]
public Guid Parent; // Type: Entity
[JsonProperty("children"), Key(9)]
public List<Guid> Children = new List<Guid>(); // Type: Entity
[JsonProperty("hull"), Key(10)]
public Guid Hull; // Type: Gear
[JsonProperty("persistedBehaviorData"), Key(11)]
public Dictionary<Guid, PersistentBehaviorData[]> PersistedBehaviors;
[JsonProperty("corporation"), Key(12)]
public Guid Corporation;
[JsonProperty("name"), Key(13)]
public string Name;
[JsonProperty("population"), Key(14)]
public int Population;
[JsonProperty("personality"), Key(15)]
public Dictionary<Guid, float> Personality = new Dictionary<Guid, float>();
// [IgnoreMember] protected List<IBehavior> Behaviors;
[IgnoreMember] public Guid Zone;

View file

@ -745,8 +745,12 @@ public class GameContext
cargo.Select(c => c.ID).Concat(simpleCargo.Select(c => c.ID)), orbit.ID, zone, corporation)
{
Name = $"{loadoutData.Name} {Random.NextInt(1,255):X}",
Temperature = 293
Temperature = 293,
Population = 1
};
var parentCorp = Cache.Get<MegaCorporation>(corpData.Parent);
foreach (var attribute in parentCorp.Personality)
entity.Personality[attribute.Key] = attribute.Value;
Cache.Add(entity);
ZoneEntities[zone][entity.ID] = entity;

View file

@ -40,37 +40,37 @@ public class ZoneData : DatabaseEntry, INamedEntry
}
}
[RethinkTable("Galaxy"), MessagePackObject, JsonObject(MemberSerialization.OptIn)]
public class StationData : DatabaseEntry, INamedEntry
{
[JsonProperty("name"), Key(1)]
public string Name;
// Can be Planet or Orbit
[JsonProperty("parent"), Key(2)]
public Guid Parent;
[JsonProperty("owner"), Key(3)]
public Guid Owner;
[JsonProperty("inventory"), Key(4)]
public List<ItemInstance> Inventory = new List<ItemInstance>();
[JsonProperty("buying"), Key(5)]
public Dictionary<Guid, float> BuyPrices = new Dictionary<Guid, float>();
[JsonProperty("selling"), Key(6)]
public Dictionary<Guid, float> SellPrices = new Dictionary<Guid, float>();
[JsonProperty("zone"), Key(7)]
public Guid Zone;
[IgnoreMember] public string EntryName
{
get => Name;
set => Name = value;
}
}
// [RethinkTable("Galaxy"), MessagePackObject, JsonObject(MemberSerialization.OptIn)]
// public class StationData : DatabaseEntry, INamedEntry
// {
// [JsonProperty("name"), Key(1)]
// public string Name;
//
// // Can be Planet or Orbit
// [JsonProperty("parent"), Key(2)]
// public Guid Parent;
//
// [JsonProperty("owner"), Key(3)]
// public Guid Owner;
//
// [JsonProperty("inventory"), Key(4)]
// public List<ItemInstance> Inventory = new List<ItemInstance>();
//
// [JsonProperty("buying"), Key(5)]
// public Dictionary<Guid, float> BuyPrices = new Dictionary<Guid, float>();
//
// [JsonProperty("selling"), Key(6)]
// public Dictionary<Guid, float> SellPrices = new Dictionary<Guid, float>();
//
// [JsonProperty("zone"), Key(7)]
// public Guid Zone;
//
// [IgnoreMember] public string EntryName
// {
// get => Name;
// set => Name = value;
// }
// }
[RethinkTable("Galaxy"), MessagePackObject, JsonObject(MemberSerialization.OptIn)]
public class PlanetData : DatabaseEntry, INamedEntry

View file

@ -27,10 +27,12 @@ public class StrategyGameManager : MonoBehaviour
public MeshRenderer ZoneBackground;
public MeshRenderer ZoneBoundary;
public ClickRaycaster ClickRaycaster;
public ReadOnlyPropertiesPanel PropertiesPanel;
public GameObject PropertiesPanelView;
public PropertiesPanel PropertiesPanel;
public ContextMenu ContextMenu;
public RectTransform GameMenuRoot;
public RectTransform CorpMenuRoot;
public ColonyTab ColonyTab;
public CorporationMenuItem CorpOptionPrefab;
public TabButton CorpMenuContinueButton;
public TMP_InputField CorpNameInputField;
@ -41,6 +43,7 @@ public class StrategyGameManager : MonoBehaviour
public TabButton GalaxyTabButton;
public TabButton ZoneTabButton;
public TabButton TechTabButton;
public TabButton ColonyTabButton;
[Section("Prefabs & Prototypes")]
public Prototype GalaxyZonePrototype;
@ -104,6 +107,7 @@ public class StrategyGameManager : MonoBehaviour
private Guid _selectedOrbit = Guid.Empty;
private Guid _selectedTowingTarget = Guid.Empty;
private float _orbitRadius;
private Guid _selectedEntity;
void Start()
{
@ -115,6 +119,7 @@ public class StrategyGameManager : MonoBehaviour
{
_cache.Load(new DirectoryInfo(Application.dataPath).Parent.FullName);
_context = new GameContext(_cache, Debug.Log);
ColonyTab.Context = _context;
TechTree.Context = _context;
_context.MapLayers = _cache.GetAll<GalaxyMapLayerData>().ToDictionary(ml => ml.Name);
_context.GalaxyZones = _cache.GetAll<ZoneData>()
@ -206,6 +211,7 @@ public class StrategyGameManager : MonoBehaviour
for(int i=0; i<loadout.Value; i++)
entities.Add(_context.CreateEntity(_selectedZone, newCorp.ID, loadout.Key));
var colony = entities.First(e => e is OrbitalEntity);
_selectedEntity = colony.ID;
foreach (var ship in entities.Where(e => e is Ship))
{
foreach (var controller in ship.GetBehaviors<ControllerBase>())
@ -257,7 +263,7 @@ public class StrategyGameManager : MonoBehaviour
_currentTab = button;
if (_currentTab == GalaxyTabButton)
{
PropertiesPanel.gameObject.SetActive(true);
PropertiesPanelView.gameObject.SetActive(true);
PopulateGalaxyProperties();
if (!_galaxyPopulated) PopulateGalaxy();
Camera.transform.position = _galaxyCameraPos;
@ -266,7 +272,7 @@ public class StrategyGameManager : MonoBehaviour
else if (_currentTab == ZoneTabButton)
{
PropertiesPanel.gameObject.SetActive(true);
PropertiesPanelView.gameObject.SetActive(true);
var zone = _cache.Get<ZoneData>(_selectedZone);
if (_populatedZone != _selectedZone && zone != null)
PopulateZone();
@ -278,7 +284,7 @@ public class StrategyGameManager : MonoBehaviour
else if (_currentTab == TechTabButton)
{
PropertiesPanel.gameObject.SetActive(true);
PropertiesPanelView.gameObject.SetActive(true);
PopulateTechProperties();
if (!_techLayoutGenerated)
{
@ -288,7 +294,12 @@ public class StrategyGameManager : MonoBehaviour
}
}
else PropertiesPanel.gameObject.SetActive(false);
else PropertiesPanelView.gameObject.SetActive(false);
if (_currentTab == ColonyTabButton)
{
ColonyTab.Open(_selectedEntity);
}
};
_boundaryMaterial = ZoneBoundary.material;
@ -464,7 +475,13 @@ public class StrategyGameManager : MonoBehaviour
zoneOrbital.Icon.GetComponent<ClickableCollider>().OnClick += (collider, data) =>
{
if (data.button == PointerEventData.InputButton.Left)
Select(orbital.ID);
{
_selectedEntity = orbital.ID;
if (data.clickCount == 1)
Select(orbital.ID);
else if (data.clickCount == 2)
ColonyTabButton.OnPointerClick(data);
}
else if (data.button == PointerEventData.InputButton.Right)
ShowContextMenu(orbital.ID);
};
@ -714,9 +731,6 @@ public class StrategyGameManager : MonoBehaviour
var equippedItems = entity.EquippedItems.Select(g => _context.Cache.Get<Gear>(g));
foreach(var gear in equippedItems)
PopulateGearProperties(gearList.AddList(gear.ItemData.Name), gear, entity);
// gearList.AddProperty(gear.ItemData.Name);
// var firstGear = equippedItems.First();
// PopulateGearProperties(gearList.AddList(firstGear.ItemData.Name), firstGear, entity);
if(!entity.Cargo.Any())
PropertiesPanel.AddProperty("No Cargo");
else
@ -741,6 +755,8 @@ public class StrategyGameManager : MonoBehaviour
PropertiesPanel.AddSection("Sector");
PropertiesPanel.AddProperty("Planets", () => $"{zone.Planets.Length}");
}
PropertiesPanel.RefreshValues();
}
void PopulateGearProperties(PropertiesList panel, Gear gear, Entity entity)

View file

@ -23,7 +23,7 @@ public class TechTreeMsagl : MonoBehaviour
public Prototype Arrow;
[Section("UI Links")]
public ReadOnlyPropertiesPanel PropertiesPanel;
public PropertiesPanel PropertiesPanel;
[Section("Graph Generation")]
public bool TestMode;

View file

@ -0,0 +1,95 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
public class ColonyTab : MonoBehaviour
{
public PropertiesPanel General;
public PropertiesPanel Inventory;
public PropertiesPanel Details;
[HideInInspector]
public GameContext Context;
private Guid _selectedColony;
public void Open(Guid colony)
{
_selectedColony = colony;
General.Clear();
Inventory.Clear();
Details.Clear();
var entity = Context.Cache.Get<Entity>(_selectedColony);
General.AddProperty("Capacity", () => $"{entity.OccupiedCapacity}/{entity.Capacity:0}");
General.AddProperty("Mass", () => $"{entity.Mass.SignificantDigits(Context.GlobalData.SignificantDigits)}");
General.AddProperty("Temperature", () => $"{entity.Temperature:0}°K");
General.AddProperty("Energy", () => $"{entity.Energy:0}/{entity.GetBehaviors<Reactor>().First().Capacitance:0}");
General.AddProperty("Population", () => $"{entity.Population}");
General.AddSection("Personality");
foreach (var attribute in entity.Personality)
General.AddPersonalityProperty(Context.Cache.Get<PersonalityAttribute>(attribute.Key),
() => attribute.Value);
General.RefreshValues();
Inventory.ChildRadioSelection = true;
Inventory.AddSection("Gear");
var equippedItems = entity.EquippedItems.Select(g => Context.Cache.Get<Gear>(g));
foreach(var gear in equippedItems)
Inventory.AddProperty(gear.ItemData.Name, null, () => PopulateDetails(gear, entity));
if(!entity.Cargo.Any())
Inventory.AddSection("No Cargo");
else
{
Inventory.AddSection("Cargo");
foreach (var itemID in entity.Cargo)
{
var itemInstance = Context.Cache.Get<ItemInstance>(itemID);
var data = Context.Cache.Get<ItemData>(itemInstance.Data);
if(itemInstance is SimpleCommodity simpleCommodity)
Inventory.AddProperty(data.Name, () => simpleCommodity.Quantity.ToString());
else
Inventory.AddProperty(data.Name);
}
}
Inventory.RefreshValues();
}
void PopulateDetails(ItemInstance item, Entity entity)
{
Details.Clear();
if (item is Gear gear)
{
var data = gear.ItemData;
Details.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<RuntimeInspectable>() != 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, gear, entity).SignificantDigits(Context.GlobalData.SignificantDigits)}");
}
}
}
}
}
Details.RefreshValues();
}
}

View file

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 8c2bf4a7080061d42a87046c37bf0c60
guid: 69422316520cbd649ad89629be288c06
MonoImporter:
externalObjects: {}
serializedVersion: 2

View file

@ -5,7 +5,7 @@ using TMPro;
using UnityEngine;
using UnityEngine.UI;
public class PropertiesList : ReadOnlyPropertiesPanel
public class PropertiesList : PropertiesPanel
{
public Image FoldoutIcon;
public float FoldoutRotationDamping;

View file

@ -3,214 +3,255 @@ using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text.RegularExpressions;
using JM.LinqFaster;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
public class PropertiesPanel : MonoBehaviour
{
public Prototype LabelField;
public Prototype FreeFloatField;
public Prototype RangedFloatField;
public Prototype EnumField;
public Prototype BoolField;
public Prototype ColorField;
public Prototype Divider;
public TextMeshProUGUI Title;
public RectTransform SectionPrefab;
public PropertiesList ListPrefab;
public PropertyLabel PropertyPrefab;
public AttributeProperty AttributePrefab;
public InputField InputField;
public RangedFloatField RangedFloatField;
public EnumField EnumField;
public BoolField BoolField;
public bool ChildRadioSelection;
public int ResolutionExponentMinumum = 6;
public int ResolutionExponentCount = 5;
protected List<GameObject> Properties = new List<GameObject>();
protected List<FlatFlatButton> Buttons = new List<FlatFlatButton>();
protected FlatFlatButton SelectedChild;
protected event Action RefreshPropertyValues;
private void Update()
{
RefreshValues();
}
public void Clear()
{
foreach(var property in Properties)
Destroy(property);
Properties.Clear();
Buttons.Clear();
SelectedChild = null;
RefreshPropertyValues = null;
}
public void Deselect()
{
if (SelectedChild != null)
SelectedChild.CurrentState = FlatButtonState.Unselected;
SelectedChild = null;
}
public RectTransform AddSection(string name)
{
var section = Instantiate(SectionPrefab, transform);
section.GetComponentInChildren<TextMeshProUGUI>().text = name;
Properties.Add(section.gameObject);
return section;
}
public PropertyLabel AddProperty(string name, Func<string> read = null, Action onClick = null)
{
var property = Instantiate(PropertyPrefab, transform);
property.Name.text = name;
if (ChildRadioSelection)
{
Buttons.Add(property.Button);
property.Button.OnClick += () =>
{
if (SelectedChild != null)
SelectedChild.CurrentState = FlatButtonState.Unselected;
SelectedChild = property.Button;
SelectedChild.CurrentState = FlatButtonState.Selected;
onClick?.Invoke();
};
}
else if(onClick!=null) property.Button.OnClick += onClick;
RefreshPropertyValues += () => property.Value.text = read?.Invoke() ?? "";
Properties.Add(property.gameObject);
return property;
}
public PropertiesList AddList(string name) //, IEnumerable<(string, Func<string>)> elements)
{
var list = Instantiate(ListPrefab, transform);
list.Title.text = name;
// foreach (var element in elements)
// {
// var item = Instantiate(PropertyPrefab, list);
// item.Name.text = element.Item1;
// item.Value.text = element.Item2();
// item.ValueFunction = element.Item2;
// Properties.Add(item.gameObject);
// }
RefreshPropertyValues += () => list.RefreshValues();
Properties.Add(list.gameObject);
return list;
}
public AttributeProperty AddPersonalityProperty(PersonalityAttribute attribute, Func<float> read)
{
var attributeInstance = Instantiate(AttributePrefab, transform);
attributeInstance.Title.text = attribute.Name;
attributeInstance.HighLabel.text = attribute.HighName;
attributeInstance.LowLabel.text = attribute.LowName;
RefreshPropertyValues += () => attributeInstance.Slider.value = read();
Properties.Add(attributeInstance.gameObject);
return attributeInstance;
}
private readonly List<Prototype> _propertyFields = new List<Prototype>();
private event EventHandler RefreshPropertyValues;
public void Clear()
public void AddProperty(string name, Func<string> read, Action<string> write)
{
foreach (var property in _propertyFields.ReverseF())
{
property.ReturnToPool();
}
RefreshPropertyValues = null;
var field = Instantiate(InputField, transform);
field.Label.text = name;
field.Field.contentType = TMP_InputField.ContentType.Standard;
field.Field.onValueChanged.AddListener(val => write(val));
RefreshPropertyValues += () => field.Field.text = read();
Properties.Add(field.gameObject);
}
public void Inspect(object obj, bool inspectablesOnly = false, bool readWrite = false, bool topLevel = false)
public void AddProperty(string name, Func<float> read, Action<float> write)
{
if(topLevel)
Clear();
var fields = obj.GetType().GetFields();
foreach (var field in fields)
Inspect(obj, field, inspectablesOnly, readWrite);
if(topLevel)
foreach (var field in _propertyFields)
field.transform.SetSiblingIndex(_propertyFields.IndexOf(field));
RefreshValues();
}
public void Inspect(object obj, FieldInfo field, bool inspectablesOnly = false, bool readWrite = false)
{
var inspectable = field.GetCustomAttribute<InspectableFieldAttribute>();
if (inspectable == null && inspectablesOnly) return;
var type = field.FieldType;
if (type == typeof(float))
{
if (readWrite)
{
var ranged = inspectable as RangedFloatInspectableAttribute;
if (ranged != null)
Inspect(field.Name.SplitCamelCase(), () => (float) field.GetValue(obj), f => field.SetValue(obj, f),
ranged.Min, ranged.Max);
else
Inspect(field.Name.SplitCamelCase(), () => (float) field.GetValue(obj), f => field.SetValue(obj, f));
} else Inspect(field.Name.SplitCamelCase(), () => ((float) field.GetValue(obj)).ToString("0.##"));
}
else if (type == typeof(int))
{
if (readWrite)
{
var ranged = inspectable as RangedIntInspectableAttribute;
if (ranged != null)
Inspect(field.Name.SplitCamelCase(), () => (int) field.GetValue(obj), f => field.SetValue(obj, f),
ranged.Min, ranged.Max);
else
Inspect(field.Name.SplitCamelCase(), () => (int) field.GetValue(obj), f => field.SetValue(obj, f));
} else Inspect(field.Name.SplitCamelCase(), () => ((int) field.GetValue(obj)).ToString());
}
else if (type.IsEnum)
{
if (readWrite)
Inspect(field.Name.SplitCamelCase(), () => (int) field.GetValue(obj), i => field.SetValue(obj, i),
Enum.GetNames(field.FieldType));
else
Inspect(field.Name.SplitCamelCase(), () => Enum.GetName(type, field.GetValue(obj)).SplitCamelCase());
}
else if (type == typeof(string))
{
if (readWrite)
Inspect(field.Name.SplitCamelCase(), () => (string) field.GetValue(obj), i => field.SetValue(obj, i));
else
Inspect(field.Name.SplitCamelCase(), () => (string) field.GetValue(obj));
}
//else if (field.FieldType == typeof(Color)) Inspect(field.Name, () => (Color) field.GetValue(obj), c => field.SetValue(obj, c));
else if (field.FieldType == typeof(bool)) Inspect(field.Name, () => (bool) field.GetValue(obj), b => field.SetValue(obj, b));
else if (type.GetCustomAttribute<InspectableFieldAttribute>() != null)
{
if(!_propertyFields.Any() || !_propertyFields.Last().gameObject.name.ToUpper().Contains("DIVIDER"))
_propertyFields.Add(Divider.Instantiate<Prototype>());
Inspect(field.GetValue(obj), inspectablesOnly, readWrite);
}
else
Debug.Log($"Field \"{field.Name}\" has unknown type {field.FieldType.Name}. No inspector was generated.");
}
public void Inspect(string name, Func<string> read)
{
var labelFieldInstance = LabelField.Instantiate<Prototype>();
_propertyFields.Add(labelFieldInstance);
labelFieldInstance.transform.Find("Label").GetComponent<TextMeshProUGUI>().text = name;
var field = labelFieldInstance.transform.Find("Field").GetComponent<TextMeshProUGUI>();
field.text = read();
RefreshPropertyValues += (sender, args) => field.text = read();
}
public void Inspect(string name, Func<float> read, Action<float> write)
{
var freeFloatFieldInstance = FreeFloatField.Instantiate<Prototype>();
_propertyFields.Add(freeFloatFieldInstance);
freeFloatFieldInstance.transform.Find("Label").GetComponent<TextMeshProUGUI>().text = name;
var inputField = freeFloatFieldInstance.GetComponentInChildren<TMP_InputField>();
inputField.contentType = TMP_InputField.ContentType.DecimalNumber;
inputField.onValueChanged.AddListener(val => write(float.Parse(val)));
RefreshPropertyValues += (sender, args) => inputField.text = read().ToString(CultureInfo.InvariantCulture);
}
public void Inspect(string name, Func<string> read, Action<string> write)
{
var freeFloatFieldInstance = FreeFloatField.Instantiate<Prototype>();
_propertyFields.Add(freeFloatFieldInstance);
freeFloatFieldInstance.transform.Find("Label").GetComponent<TextMeshProUGUI>().text = name;
var inputField = freeFloatFieldInstance.GetComponentInChildren<TMP_InputField>();
inputField.contentType = TMP_InputField.ContentType.Standard;
inputField.onValueChanged.AddListener(val => write(val));
RefreshPropertyValues += (sender, args) => inputField.text = read();
var field = Instantiate(InputField, transform);
field.Label.text = name;
field.Field.contentType = TMP_InputField.ContentType.DecimalNumber;
field.Field.onValueChanged.AddListener(val => write(float.Parse(val)));
RefreshPropertyValues += () => field.Field.text = read().ToString(CultureInfo.InvariantCulture);
Properties.Add(field.gameObject);
}
public void Inspect(string name, Func<float> read, Action<float> write, float min, float max)
public void AddProperty(string name, Func<int> read, Action<int> write)
{
var rangedFloatFieldInstance = RangedFloatField.Instantiate<Prototype>();
_propertyFields.Add(rangedFloatFieldInstance);
rangedFloatFieldInstance.transform.Find("Label").GetComponent<TextMeshProUGUI>().text = name;
var slider = rangedFloatFieldInstance.GetComponentInChildren<Slider>();
slider.minValue = min;
slider.maxValue = max;
slider.onValueChanged.AddListener(val => write(val));
RefreshPropertyValues += (sender, args) => slider.value = read();
var field = Instantiate(InputField, transform);
field.Label.text = name;
field.Field.contentType = TMP_InputField.ContentType.IntegerNumber;
field.Field.onValueChanged.AddListener(val => write(int.Parse(val)));
RefreshPropertyValues += () => field.Field.text = read().ToString(CultureInfo.InvariantCulture);
Properties.Add(field.gameObject);
}
public void AddProperty(string name, Func<float> read, Action<float> write, float min, float max)
{
var field = Instantiate(RangedFloatField, transform);
field.Label.text = name;
field.Slider.wholeNumbers = false;
field.Slider.minValue = min;
field.Slider.maxValue = max;
field.Slider.onValueChanged.AddListener(val => write(val));
RefreshPropertyValues += () => field.Slider.value = read();
Properties.Add(field.gameObject);
}
public void AddProperty(string name, Func<int> read, Action<int> write, int min, int max)
{
var field = Instantiate(RangedFloatField, transform);
field.Label.text = name;
field.Slider.wholeNumbers = true;
field.Slider.minValue = min;
field.Slider.maxValue = max;
field.Slider.onValueChanged.AddListener(val => write(Mathf.RoundToInt(val)));
RefreshPropertyValues += () => field.Slider.value = read();
Properties.Add(field.gameObject);
}
public void AddProperty(string name, Func<bool> read, Action<bool> write)
{
var field = Instantiate(BoolField, transform);
field.Label.text = name;
field.Toggle.onValueChanged.AddListener(val => write(val));
RefreshPropertyValues += () => field.Toggle.isOn = read();
Properties.Add(field.gameObject);
}
public void AddProperty(string name, Func<int> read, Action<int> write, string[] enumOptions)
{
var field = Instantiate(EnumField, transform);
field.Label.text = name;
field.Dropdown.options = enumOptions.Select(s => new TMP_Dropdown.OptionData(s)).ToList();
field.Dropdown.onValueChanged.AddListener(val => write(val));
RefreshPropertyValues += () => field.Dropdown.value = read();
Properties.Add(field.gameObject);
}
public void Inspect(string name, Func<int> read, Action<int> write)
{
var freeFloatFieldInstance = FreeFloatField.Instantiate<Prototype>();
_propertyFields.Add(freeFloatFieldInstance);
freeFloatFieldInstance.transform.Find("Label").GetComponent<TextMeshProUGUI>().text = name;
var inputField = freeFloatFieldInstance.GetComponentInChildren<TMP_InputField>();
inputField.contentType = TMP_InputField.ContentType.IntegerNumber;
inputField.onValueChanged.AddListener(val => write(int.Parse(val)));
RefreshPropertyValues += (sender, args) => inputField.text = read().ToString(CultureInfo.InvariantCulture);
}
public void Inspect(string name, Func<int> read, Action<int> write, int min, int max)
{
var rangedFloatFieldInstance = RangedFloatField.Instantiate<Prototype>();
_propertyFields.Add(rangedFloatFieldInstance);
rangedFloatFieldInstance.transform.Find("Label").GetComponent<TextMeshProUGUI>().text = name;
var slider = rangedFloatFieldInstance.GetComponentInChildren<Slider>();
slider.wholeNumbers = true;
slider.minValue = min;
slider.maxValue = max;
slider.onValueChanged.AddListener(val => write(Mathf.RoundToInt(val)));
RefreshPropertyValues += (sender, args) => slider.value = read();
}
// public void Inspect(string name, Func<Color> read, Action<Color> write)
// public void Inspect(object obj, bool inspectablesOnly = false, bool readWrite = false, bool topLevel = true)
// {
// var colorFieldInstance = ColorField.Instantiate<Prototype>();
// _propertyFields.Add(colorFieldInstance);
// colorFieldInstance.transform.Find("Label").GetComponent<TextMeshProUGUI>().text = name;
// var colorButton = colorFieldInstance.GetComponentInChildren<ColorButton>();
// colorButton.OnColorChanged.AddListener(col => write(col));
// RefreshPropertyValues += (sender, args) => colorButton.GetComponent<Image>().color = read();
// if(topLevel)
// Clear();
//
// var fields = obj.GetType().GetFields();
// foreach (var field in fields)
// Inspect(obj, field, inspectablesOnly, readWrite);
//
// if(topLevel)
// foreach (var field in _propertyFields)
// field.transform.SetSiblingIndex(_propertyFields.IndexOf(field));
//
// RefreshValues();
// }
//
// public void Inspect(object obj, FieldInfo field, bool inspectablesOnly = false, bool readWrite = false)
// {
// var inspectable = field.GetCustomAttribute<InspectableFieldAttribute>();
// if (inspectable == null && inspectablesOnly) return;
// var type = field.FieldType;
//
// if (type == typeof(float))
// {
// if (readWrite)
// {
// var ranged = inspectable as RangedFloatInspectableAttribute;
// if (ranged != null)
// Inspect(field.Name.SplitCamelCase(), () => (float) field.GetValue(obj), f => field.SetValue(obj, f),
// ranged.Min, ranged.Max);
// else
// Inspect(field.Name.SplitCamelCase(), () => (float) field.GetValue(obj), f => field.SetValue(obj, f));
// } else Inspect(field.Name.SplitCamelCase(), () => ((float) field.GetValue(obj)).ToString("0.##"));
// }
// else if (type == typeof(int))
// {
// if (readWrite)
// {
// var ranged = inspectable as RangedIntInspectableAttribute;
// if (ranged != null)
// Inspect(field.Name.SplitCamelCase(), () => (int) field.GetValue(obj), f => field.SetValue(obj, f),
// ranged.Min, ranged.Max);
// else
// Inspect(field.Name.SplitCamelCase(), () => (int) field.GetValue(obj), f => field.SetValue(obj, f));
// } else Inspect(field.Name.SplitCamelCase(), () => ((int) field.GetValue(obj)).ToString());
// }
// else if (type.IsEnum)
// {
// if (readWrite)
// Inspect(field.Name.SplitCamelCase(), () => (int) field.GetValue(obj), i => field.SetValue(obj, i),
// Enum.GetNames(field.FieldType));
// else
// Inspect(field.Name.SplitCamelCase(), () => Enum.GetName(type, field.GetValue(obj)).SplitCamelCase());
// }
// else if (type == typeof(string))
// {
// if (readWrite)
// Inspect(field.Name.SplitCamelCase(), () => (string) field.GetValue(obj), i => field.SetValue(obj, i));
// else
// Inspect(field.Name.SplitCamelCase(), () => (string) field.GetValue(obj));
// }
// //else if (field.FieldType == typeof(Color)) Inspect(field.Name, () => (Color) field.GetValue(obj), c => field.SetValue(obj, c));
// else if (field.FieldType == typeof(bool)) Inspect(field.Name, () => (bool) field.GetValue(obj), b => field.SetValue(obj, b));
// else if (type.GetCustomAttribute<InspectableFieldAttribute>() != null)
// {
// if(!_propertyFields.Any() || !_propertyFields.Last().gameObject.name.ToUpper().Contains("DIVIDER"))
// _propertyFields.Add(Divider.Instantiate<Prototype>());
// Inspect(field.GetValue(obj), inspectablesOnly, readWrite, false);
// }
// else
// Debug.Log($"Field \"{field.Name}\" has unknown type {field.FieldType.Name}. No inspector was generated.");
// }
public void Inspect(string name, Func<bool> read, Action<bool> write)
{
var boolFieldInstance = BoolField.Instantiate<Prototype>();
_propertyFields.Add(boolFieldInstance);
boolFieldInstance.transform.Find("Label").GetComponent<TextMeshProUGUI>().text = name;
var toggle = boolFieldInstance.GetComponentInChildren<Toggle>();
toggle.onValueChanged.AddListener(val => write(val));
RefreshPropertyValues += (sender, args) => toggle.isOn = read();
}
public void Inspect(string name, Func<int> read, Action<int> write, string[] enumOptions)
{
var enumFieldInstance = EnumField.Instantiate<Prototype>();
_propertyFields.Add(enumFieldInstance);
enumFieldInstance.transform.Find("Label").GetComponent<TextMeshProUGUI>().text = name;
var dropDown = enumFieldInstance.GetComponentInChildren<TMP_Dropdown>();
dropDown.options = enumOptions.Select(s => new TMP_Dropdown.OptionData(s)).ToList();
dropDown.onValueChanged.AddListener(val => write(val));
RefreshPropertyValues += (sender, args) => dropDown.value = read();
}
public void RefreshValues()
{
RefreshPropertyValues?.Invoke(this, EventArgs.Empty);
RefreshPropertyValues?.Invoke();
}
}
}

View file

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 522d91e5cc66d574486096884d806861
guid: 8c2bf4a7080061d42a87046c37bf0c60
MonoImporter:
externalObjects: {}
serializedVersion: 2

View file

@ -8,12 +8,5 @@ public class PropertyLabel : MonoBehaviour
{
public TextMeshProUGUI Name;
public TextMeshProUGUI Value;
public Func<string> ValueFunction;
public FlatFlatButton Button;
private void Update()
{
if(ValueFunction != null)
Value.text = ValueFunction();
}
}

View file

@ -1,170 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using TMPro;
using UnityEngine;
public class ReadOnlyPropertiesPanel : MonoBehaviour
{
public TextMeshProUGUI Title;
public RectTransform SectionPrefab;
public PropertiesList ListPrefab;
public PropertyLabel PropertyPrefab;
public AttributeProperty AttributePrefab;
public InputField InputField;
public RangedFloatField RangedFloatField;
public EnumField EnumField;
public BoolField BoolField;
public bool ChildRadioSelection;
protected List<GameObject> Properties = new List<GameObject>();
protected List<FlatFlatButton> Buttons = new List<FlatFlatButton>();
protected FlatFlatButton SelectedChild;
protected event Action RefreshPropertyValues;
public void Clear()
{
foreach(var property in Properties)
Destroy(property);
Properties.Clear();
Buttons.Clear();
SelectedChild = null;
}
public PropertyLabel AddProperty(string name, Func<string> value = null, Action onClick = null)
{
var property = Instantiate(PropertyPrefab, transform);
property.Name.text = name;
property.Value.text = value?.Invoke() ?? "";
property.ValueFunction = value;
if (ChildRadioSelection)
{
Buttons.Add(property.Button);
property.Button.OnClick += () =>
{
if (SelectedChild != null)
SelectedChild.CurrentState = FlatButtonState.Unselected;
SelectedChild = property.Button;
SelectedChild.CurrentState = FlatButtonState.Selected;
onClick?.Invoke();
};
}
else if(onClick!=null) property.Button.OnClick += onClick;
Properties.Add(property.gameObject);
return property;
}
public RectTransform AddSection(string name)
{
var section = Instantiate(SectionPrefab, transform);
section.GetComponentInChildren<TextMeshProUGUI>().text = name;
Properties.Add(section.gameObject);
return section;
}
public PropertiesList AddList(string name) //, IEnumerable<(string, Func<string>)> elements)
{
var list = Instantiate(ListPrefab, transform);
list.Title.text = name;
// foreach (var element in elements)
// {
// var item = Instantiate(PropertyPrefab, list);
// item.Name.text = element.Item1;
// item.Value.text = element.Item2();
// item.ValueFunction = element.Item2;
// Properties.Add(item.gameObject);
// }
Properties.Add(list.gameObject);
return list;
}
public AttributeProperty AddAttribute(PersonalityAttribute attribute, float value)
{
var attributeInstance = Instantiate(AttributePrefab, transform);
attributeInstance.Slider.value = value;
attributeInstance.Title.text = attribute.Name;
attributeInstance.HighLabel.text = attribute.HighName;
attributeInstance.LowLabel.text = attribute.LowName;
return attributeInstance;
}
public void AddProperty(string name, Func<string> read, Action<string> write)
{
var field = Instantiate(InputField, transform);
field.Label.text = name;
field.Field.contentType = TMP_InputField.ContentType.Standard;
field.Field.onValueChanged.AddListener(val => write(val));
RefreshPropertyValues += () => field.Field.text = read();
Properties.Add(field.gameObject);
}
public void AddProperty(string name, Func<float> read, Action<float> write)
{
var field = Instantiate(InputField, transform);
field.Label.text = name;
field.Field.contentType = TMP_InputField.ContentType.DecimalNumber;
field.Field.onValueChanged.AddListener(val => write(float.Parse(val)));
RefreshPropertyValues += () => field.Field.text = read().ToString(CultureInfo.InvariantCulture);
Properties.Add(field.gameObject);
}
public void AddProperty(string name, Func<int> read, Action<int> write)
{
var field = Instantiate(InputField, transform);
field.Label.text = name;
field.Field.contentType = TMP_InputField.ContentType.IntegerNumber;
field.Field.onValueChanged.AddListener(val => write(int.Parse(val)));
RefreshPropertyValues += () => field.Field.text = read().ToString(CultureInfo.InvariantCulture);
Properties.Add(field.gameObject);
}
public void AddProperty(string name, Func<float> read, Action<float> write, float min, float max)
{
var field = Instantiate(RangedFloatField, transform);
field.Label.text = name;
field.Slider.wholeNumbers = false;
field.Slider.minValue = min;
field.Slider.maxValue = max;
field.Slider.onValueChanged.AddListener(val => write(val));
RefreshPropertyValues += () => field.Slider.value = read();
Properties.Add(field.gameObject);
}
public void AddProperty(string name, Func<int> read, Action<int> write, int min, int max)
{
var field = Instantiate(RangedFloatField, transform);
field.Label.text = name;
field.Slider.wholeNumbers = true;
field.Slider.minValue = min;
field.Slider.maxValue = max;
field.Slider.onValueChanged.AddListener(val => write(Mathf.RoundToInt(val)));
RefreshPropertyValues += () => field.Slider.value = read();
Properties.Add(field.gameObject);
}
public void AddProperty(string name, Func<bool> read, Action<bool> write)
{
var field = Instantiate(BoolField, transform);
field.Label.text = name;
field.Toggle.onValueChanged.AddListener(val => write(val));
RefreshPropertyValues += () => field.Toggle.isOn = read();
Properties.Add(field.gameObject);
}
public void AddProperty(string name, Func<int> read, Action<int> write, string[] enumOptions)
{
var field = Instantiate(EnumField, transform);
field.Label.text = name;
field.Dropdown.options = enumOptions.Select(s => new TMP_Dropdown.OptionData(s)).ToList();
field.Dropdown.onValueChanged.AddListener(val => write(val));
RefreshPropertyValues += () => field.Dropdown.value = read();
Properties.Add(field.gameObject);
}
public void RefreshValues()
{
RefreshPropertyValues?.Invoke();
}
}