Created
March 6, 2023 18:43
-
-
Save DirtyHarryE/d387cfcb052b9d468bb337c1d2868450 to your computer and use it in GitHub Desktop.
Plant Data
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using ItalicPig.PaleoPines.Loading; | |
using UnityEngine; | |
using UnityEngine.Serialization; | |
/* | |
* Copyright © 2020, Italic Pig, All Rights Reserved | |
* | |
* Author: Harry Evans | |
* Date: 25/02/2020 | |
*/ | |
namespace ItalicPig.PaleoPines.Inventories | |
{ | |
/// <summary> | |
/// Abstract superclass for parent object holding Additional Item Information Data. | |
/// </summary> | |
/// <typeparam name="TItemInformationData">Type of additional data to store.</typeparam> | |
public abstract class AdditionalInventoryInformationData<TItemInformationData> : ScriptableObject, ILoadable<AdditionalInventoryInformationData<TItemInformationData>> | |
where TItemInformationData : AdditionalItemInformationData | |
{ | |
public const string MenuPrefix = "Italic Pig/Paleo/Inventory/Additional Info/"; | |
#pragma warning disable CS0414, IDE0052, IDE0051, IDE0169, IDE0649 // Remove unread private members warning - they are used in Unity editor | |
[SerializeField, HideInInspector, FormerlySerializedAs("importerMode")] | |
private int _ImporterMode = 0; | |
[SerializeField, HideInInspector, FormerlySerializedAs("csvPath")] | |
private string _CsvPath = string.Empty; | |
[SerializeField, HideInInspector, FormerlySerializedAs("csvStartRow")] | |
private int _CsvStartRow = 0; | |
#pragma warning restore CS0414, IDE0052, IDE0051, IDE0169, IDE0649 // Remove unread private members warning - they are used in Unity editor | |
/// <summary> | |
/// Array of Additional Item Information Data | |
/// </summary> | |
[SerializeField] | |
private TItemInformationData[] _infoData; | |
int ILoadable.Priority => 25; | |
protected virtual void OnValidate() { } | |
public virtual void Load() { } | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Linq; | |
using System.Reflection; | |
using System.Text; | |
using ItalicPig.PaleoPines.Importing; | |
using ItalicPig.PaleoPines.Inventories; | |
using ItalicPig.PaleoPines.LinqExtensions; | |
using ItalicPig.PaleoPines.Misc; | |
using UnityEditor; | |
using UnityEditorInternal; | |
using UnityEngine; | |
using Object = UnityEngine.Object; | |
namespace ItalicPig.PaleoPines.Editor.Inventory | |
{ | |
public abstract class AdditionalInventoryInformationDataEditor<TItemInformationData> : UnityEditor.Editor | |
where TItemInformationData : AdditionalItemInformationData | |
{ | |
public enum VariableType | |
{ | |
AutoDetect = 0, | |
Bool = 1, | |
Integer = 2, | |
Float = 3, | |
String = 4, | |
Enum = 5, | |
EnumFlags = 6, | |
ItemID = 7 | |
} | |
protected struct SerializationNameInfo | |
{ | |
public string SerializedPropertyName; | |
public StringPlayerPref NameInCSVPref; | |
public EnumPlayerPref<VariableType> VariableTypePref; | |
public SerializationNameInfo(string serializedPropertyName, StringPlayerPref nameInCSVPref, EnumPlayerPref<VariableType> variableTypePref) | |
{ | |
SerializedPropertyName = serializedPropertyName; | |
NameInCSVPref = nameInCSVPref; | |
VariableTypePref = variableTypePref; | |
} | |
} | |
private struct ColToPropertyNameInfo | |
{ | |
public readonly string PropertyName; | |
public readonly EnumPlayerPref<VariableType> VariableTypePref; | |
public readonly bool IsCSVItem; | |
public readonly int Width; | |
public readonly int Height; | |
public readonly bool IsItemID; | |
public readonly string[] Headers; | |
public ColToPropertyNameInfo(string propertyName, EnumPlayerPref<VariableType> variableTypePref) | |
{ | |
PropertyName = propertyName; | |
VariableTypePref = variableTypePref; | |
Width = 1; | |
Height = 1; | |
IsCSVItem = false; | |
Headers = Array.Empty<string>(); | |
IsItemID = false; | |
} | |
public ColToPropertyNameInfo(string propertyName) | |
{ | |
PropertyName = propertyName; | |
VariableTypePref = default; | |
Width = 1; | |
Height = 1; | |
IsCSVItem = false; | |
Headers = Array.Empty<string>(); | |
IsItemID = false; | |
} | |
public ColToPropertyNameInfo(string propertyName, | |
EnumPlayerPref<VariableType> variableTypePref, | |
int width, | |
int height, | |
bool isCSVItem, | |
string[] headers, | |
bool isItemID) | |
: this(propertyName, variableTypePref) | |
{ | |
Width = width; | |
Height = height; | |
IsCSVItem = isCSVItem; | |
Headers = headers; | |
IsItemID = isItemID; | |
} | |
} | |
private struct PropertyToValueInfo | |
{ | |
public string SerializedPropertyName; | |
public string PropertyValue; | |
public readonly EnumPlayerPref<VariableType> VariableTypePref; | |
public readonly int X; | |
public readonly int Y; | |
public readonly bool IsSubtable; | |
public readonly int Width; | |
public readonly int Height; | |
public readonly bool IsItemID; | |
public readonly string[] Headers; | |
public PropertyToValueInfo(string serializedPropertyName, | |
string propertyValue, | |
EnumPlayerPref<VariableType> variableTypePref, | |
int x, int y) | |
{ | |
SerializedPropertyName = serializedPropertyName; | |
PropertyValue = propertyValue; | |
VariableTypePref = variableTypePref; | |
X = x; | |
Y = y; | |
Width = 1; | |
Height = 1; | |
Headers = Array.Empty<string>(); | |
IsSubtable = false; | |
IsItemID = false; | |
} | |
public PropertyToValueInfo(string serializedPropertyName, | |
string propertyValue, | |
EnumPlayerPref<VariableType> variableTypePref, | |
int x, int y, | |
int width, | |
int height, | |
bool isCSVItem, | |
string[] headers, | |
bool isItemID) | |
: this(serializedPropertyName, propertyValue, variableTypePref, x, y) | |
{ | |
Width = width; | |
Height = height; | |
IsSubtable = isCSVItem; | |
IsItemID = isItemID; | |
Headers = headers; | |
} | |
} | |
private enum FindElementMethod | |
{ | |
ByUniqueID, | |
ByName | |
} | |
private ReorderableList reorderableList; | |
private CSVImporterWidget csvImporterWidget; | |
protected SerializationNameInfo[] SerializedPropertyToCSVName; | |
protected virtual int HeaderRow => 0; | |
private StringPlayerPref uniqueID; | |
private StringPlayerPref itemName; | |
private string guid; | |
private bool debugOptions = false; | |
private string assetName = string.Empty; | |
protected virtual void OnEnable() | |
{ | |
assetName = target.name; | |
guid = AssetDatabase.GUIDToAssetPath(AssetDatabase.GetAssetPath(target)); | |
uniqueID = new StringPlayerPref(guid + "_uniqueID", "itemID"); | |
itemName = new StringPlayerPref(guid + "_name", "name"); | |
SerializedPropertyToCSVName = GetSerializationNameInfos(); | |
} | |
protected virtual SerializationNameInfo[] GetSerializationNameInfos() | |
{ | |
string[] serializableNames = EditorHelper.GetSerializablePropertyNames(typeof(TItemInformationData), true).DistinctBy(s => s).ToArray(); | |
var names = new SerializationNameInfo[serializableNames.Length]; | |
for (int i = 0; i < serializableNames.Length; i++) | |
{ | |
string n = serializableNames[i]; | |
names[i] = new SerializationNameInfo( | |
n, | |
new StringPlayerPref(guid + "_" + n, GetDefaultCSVHeader(n)), | |
new EnumPlayerPref<VariableType>( | |
guid + "_" + n + "_" + "VariableType", | |
VariableType.AutoDetect | |
)); | |
} | |
return names; | |
} | |
public override void OnInspectorGUI() | |
{ | |
if (DrawRenamePanel()) | |
{ | |
return; | |
} | |
var infoDataSerializedProperty = serializedObject.FindProperty("_infoData"); | |
reorderableList = reorderableList ?? GetReorderableList(serializedObject, infoDataSerializedProperty); | |
if (csvImporterWidget == null) | |
{ | |
string dataName = typeof(TItemInformationData).Name; | |
csvImporterWidget = new CSVImporterWidget(dataName, OnCSVImported, ExportCSV) | |
{ | |
GetPathname = delegate () | |
{ | |
using (SerializedProperty csvPathProperty = serializedObject.FindProperty("_CsvPath")) | |
{ | |
return csvPathProperty.stringValue; | |
} | |
}, | |
SetPathname = delegate (string pathname) | |
{ | |
using (SerializedProperty csvPathProperty = serializedObject.FindProperty("_CsvPath")) | |
{ | |
if (csvPathProperty.stringValue != pathname) | |
{ | |
csvPathProperty.stringValue = pathname; | |
serializedObject.ApplyModifiedProperties(); | |
} | |
} | |
}, | |
GetStartRow = delegate () | |
{ | |
using (SerializedProperty rowProperty = serializedObject.FindProperty("_CsvStartRow")) | |
{ | |
return rowProperty.intValue; | |
} | |
}, | |
SetStartRow = delegate (int row) | |
{ | |
using (SerializedProperty rowProperty = serializedObject.FindProperty("_CsvStartRow")) | |
{ | |
if (rowProperty.intValue != row) | |
{ | |
rowProperty.intValue = row; | |
serializedObject.ApplyModifiedProperties(); | |
} | |
} | |
}, | |
GetImporterMode = delegate () | |
{ | |
using (var rowProperty = serializedObject.FindProperty("_ImporterMode")) | |
{ | |
return (CSVImporterWidget.ImporterMode)rowProperty.intValue; | |
} | |
}, | |
SetImporterMode = delegate (CSVImporterWidget.ImporterMode mode) | |
{ | |
int m = (int)mode; | |
using (var rowProperty = serializedObject.FindProperty("_ImporterMode")) | |
{ | |
if (rowProperty.intValue != m) | |
{ | |
rowProperty.intValue = m; | |
serializedObject.ApplyModifiedProperties(); | |
} | |
} | |
} | |
}; | |
csvImporterWidget.ExtraOptions = ExtraOptions; | |
csvImporterWidget.IsReadyToExport = true; | |
} | |
csvImporterWidget.DrawLayout(); | |
EditorGUI.BeginChangeCheck(); | |
DrawRemainingProperties(); | |
reorderableList.DoLayoutList(); | |
GUILayout.Space(50); | |
DrawFixButtonsArea(); | |
if (EditorGUI.EndChangeCheck()) | |
{ | |
serializedObject.ApplyModifiedProperties(); | |
} | |
} | |
protected virtual void DrawRemainingProperties() | |
{ | |
DrawPropertiesExcluding(serializedObject, "m_Script", "_infoData"); | |
} | |
private bool DrawRenamePanel() | |
{ | |
using (new EditorGUILayout.HorizontalScope()) | |
{ | |
assetName = EditorGUILayout.TextField(assetName); | |
if (GUILayout.Button("Rename", EditorStyles.miniButton, GUILayout.Width(70))) | |
{ | |
if (string.CompareOrdinal(assetName, target.name) != 0) | |
{ | |
var oldPath = AssetDatabase.GetAssetPath(target); | |
var list = AssetDatabase.LoadAllAssetsAtPath(oldPath).Where(a => a != target).ToList(); | |
var ext = Path.GetExtension(oldPath); | |
var newPath = oldPath.Substring(0, oldPath.Length - Path.GetFileName(oldPath).Length); | |
newPath = Path.Combine(newPath, assetName + ext); | |
var newAsset = Object.Instantiate(target); | |
newAsset.name = assetName; | |
AssetDatabase.CreateAsset(newAsset, newPath); | |
foreach (var subAsset in list) | |
{ | |
AssetDatabase.RemoveObjectFromAsset(subAsset); | |
AssetDatabase.AddObjectToAsset(subAsset, newAsset); | |
} | |
AssetDatabase.ImportAsset(newPath); | |
AssetDatabase.DeleteAsset(oldPath); | |
AssetDatabase.Refresh(); | |
Selection.objects = new[] { newAsset }; | |
return true; | |
} | |
} | |
} | |
return false; | |
} | |
protected virtual void ExtraOptions() | |
{ | |
var label = new GUIContent("CSV Headers"); | |
if (EditorHelper.DrawHelpButton(() => EditorGUILayout.LabelField(label, EditorStyles.boldLabel), | |
label, | |
EditorStyles.boldLabel)) | |
{ | |
CustomWindow.ShowHelpWindow(GUILayoutUtility.GetLastRect(), label, delegate (GUIStyle style) | |
{ | |
EditorGUILayout.LabelField("Here is where you assign the header name for the program to look for in the CSV.", style); | |
EditorGUILayout.LabelField("In the left hand column you will see a description of what data the program expects.", style); | |
EditorGUILayout.LabelField("In the right hand column is the corresponding column header in the CSV that contains that data. Write the header of the info there", style); | |
} | |
); | |
} | |
var types = Enum.GetNames(typeof(VariableType)).Select(ObjectNames.NicifyVariableName).ToArray(); | |
var variableTypeLabel = new GUIContent("Type"); | |
var varLabelW = EditorStyles.label.CalcSize(variableTypeLabel).x; | |
GUILayoutOption nameGUIOptions = GUILayout.Width(100); | |
GUILayoutOption typeLabelGUIOptions = GUILayout.Width(varLabelW); | |
uniqueID.Value = EditorGUILayout.TextField("Unique ID", uniqueID.Value); | |
itemName.Value = EditorGUILayout.TextField("Name", itemName.Value); | |
GUILayout.Space(EditorGUIUtility.singleLineHeight * 0.5f); | |
for (var i = 0; i < SerializedPropertyToCSVName.Length; i++) | |
{ | |
SerializationNameInfo info = SerializedPropertyToCSVName[i]; | |
StringPlayerPref nameInCSVPref = info.NameInCSVPref; | |
EnumPlayerPref<VariableType> variableTypePref = info.VariableTypePref; | |
using (new EditorGUILayout.HorizontalScope()) | |
{ | |
EditorGUILayout.PrefixLabel(ObjectNames.NicifyVariableName(info.SerializedPropertyName)); | |
var nameVal = EditorGUILayout.TextField(nameInCSVPref.Value, nameGUIOptions); | |
EditorGUILayout.LabelField(variableTypeLabel, typeLabelGUIOptions); | |
nameInCSVPref.Value = nameVal; | |
var isSubtable = typeof(TItemInformationData).GetField(info.SerializedPropertyName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) | |
.GetCustomAttributes<CSVItemAttribute>() | |
.Any(); | |
using (new EditorGUI.DisabledScope(isSubtable)) | |
{ | |
int pre = (int)variableTypePref.Value; | |
int typeVal = EditorGUILayout.Popup( | |
isSubtable | |
? 0 : pre, | |
isSubtable | |
? new[] { "Subtable" } : types); | |
if (!isSubtable && pre != typeVal) | |
{ | |
variableTypePref.Value = (VariableType)typeVal; | |
} | |
} | |
} | |
} | |
} | |
protected virtual void OnCSVImported(string[][] output) | |
{ | |
EditorCoroutiner.StartCoroutine(ImportCSVCoroutine(output)); | |
} | |
protected virtual IEnumerator ImportCSVCoroutine(string[][] output) | |
{ | |
var debugSubtable = false; | |
var progressBarTitle = "Importing " + typeof(TItemInformationData).Name; | |
const string errorTitle = "Error on Import!"; | |
const char delimiter = ','; | |
var tableRead = new StringBuilder(); | |
var report = new StringBuilder(); | |
var parseErrors = new List<string>(); | |
var generics = new List<string>(); | |
var csvNotImplemented = new List<string>(); | |
var unExpectedProperties = new List<string>(); | |
var cannotFindProperties = new List<string>(); | |
var couldNotFindItemID = new List<string>(); | |
var cannotFindAssignableProperties = new List<string>(); | |
var itemType = typeof(TItemInformationData); | |
EditorUtility.DisplayProgressBar(progressBarTitle, "Starting", 0); | |
const string UniqueIDPropertyName = "_Uid"; | |
var elements = serializedObject.FindProperty("_infoData"); | |
var data = new List<SerializedObject>(); | |
var uniqueIDcolumn = 0; | |
var nameIDcolumn = 0; | |
var additionalDataPropertyPathInItem = string.Empty; | |
var colToPropertyNameDict = new Dictionary<int, ColToPropertyNameInfo>(); | |
int x, y; | |
var uniqueIDFound = false; | |
var headerIncr = 1; | |
float GetProgress(int index, int total, int stage) | |
{ | |
const float totalStages = 3; | |
var thisProgress = index / ((float)total); | |
thisProgress = thisProgress / totalStages; | |
var incr = Mathf.Clamp(stage, 1f, totalStages) / totalStages; | |
return Mathf.Clamp01(thisProgress + incr); | |
} | |
for (x = 0; x < output[HeaderRow].Length; x += headerIncr) | |
{ | |
EditorUtility.DisplayProgressBar(progressBarTitle, "Reading headers... " + output[HeaderRow][x], GetProgress(x, output[HeaderRow].Length, 1)); | |
headerIncr = 1; | |
var header = output[HeaderRow][x]; | |
report.Append("Reading: ").Append(header).AppendLine(); | |
tableRead.Append(header).Append(delimiter); | |
if (ComparePossibleNames(header, uniqueID)) | |
{ | |
uniqueIDcolumn = x; | |
uniqueIDFound = true; | |
} | |
else if (ComparePossibleNames(header, itemName)) | |
{ | |
nameIDcolumn = x; | |
} | |
else | |
{ | |
bool found = false; | |
for (var k = 0; k < SerializedPropertyToCSVName.Length; k++) | |
{ | |
if (ComparePossibleNames(header, SerializedPropertyToCSVName[k].NameInCSVPref)) | |
{ | |
var serializedPropName = SerializedPropertyToCSVName[k].SerializedPropertyName; | |
var fieldinfo = itemType.GetField(serializedPropName, | |
BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); | |
int height = 1, width = 1; | |
var isCSVItem = false; | |
var headers = new[] { header }; | |
var isItemID = false; | |
report.Append("Finding: ") | |
.Append(serializedPropName) | |
.Append(" in ") | |
.Append(itemType.Name).Append(" = ").Append(fieldinfo != null).AppendLine(); | |
if (fieldinfo != null) | |
{ | |
var csvAtts = fieldinfo.GetCustomAttributes<CSVItemAttribute>(true); | |
var hasCSVAtts = csvAtts.Any(); | |
report.Append("Detecting CSV attributes ").Append(hasCSVAtts).AppendLine(); | |
if (hasCSVAtts) | |
{ | |
CSVItemAttribute csvAtt = csvAtts.First(); | |
headerIncr = csvAtt.Width; | |
headers = new string[csvAtt.Width]; | |
for (var i = 0; i < csvAtt.Width; i++) | |
{ | |
headers[i] = output[HeaderRow][x + i]; | |
} | |
width = csvAtt.Width; | |
height = csvAtt.Height; | |
isCSVItem = true; | |
report.Append("Adding CSV : ").Append(csvAtt.Width).Append("|").Append(csvAtt.Height).AppendLine(); | |
} | |
isItemID = fieldinfo.GetCustomAttributes<ItemIDAttribute>(true).Any(); | |
report.Append("Detecting Item ID attributes ").Append(isItemID).AppendLine(); | |
} | |
colToPropertyNameDict.Add(x, | |
new ColToPropertyNameInfo( | |
SerializedPropertyToCSVName[k].SerializedPropertyName, | |
SerializedPropertyToCSVName[k].VariableTypePref, | |
width, height, isCSVItem, headers, isItemID | |
)); | |
report.Append("Adding to dict : ").Append(x).Append(" :: ").Append(SerializedPropertyToCSVName[k].SerializedPropertyName).AppendLine(); | |
found = true; | |
break; | |
} | |
} | |
if (!found) | |
{ | |
unExpectedProperties.Add(header); | |
} | |
} | |
} | |
report.Append('-', 50).AppendLine().Append("Headers Completed").AppendLine(); | |
if (!uniqueIDFound) | |
{ | |
EditorUtility.DisplayDialog(errorTitle, "Could not find the column for the unique ID\n\nAre you sure \"" + uniqueID + "\" is correct?", "Cancel"); | |
yield break; | |
} | |
int xIncr = 1, yIncr = 1; | |
for (y = HeaderRow + 1; y < output.Length; y += yIncr) | |
{ | |
xIncr = 1; | |
report.Append("Reading row [").Append(y).Append("] \""); | |
for (int i = 0; i < output[y].Length; i++) | |
{ | |
if (i != 0) | |
{ | |
report.Append(delimiter).Append(' '); | |
} | |
var cell = output[y][i]; | |
if (cell.Contains(delimiter)) | |
{ | |
report.Append('"').Append(cell).Append('"'); | |
} | |
else | |
{ | |
report.Append(cell); | |
} | |
} | |
report.AppendLine(); | |
tableRead.AppendLine(); | |
yIncr = 1; | |
ItemData item = null; | |
var itemName = string.Empty; | |
var propertyToValueList = new List<PropertyToValueInfo>(); | |
if (Helper.GetVariableName(System.Globalization.CultureInfo.CurrentCulture.TextInfo.ToTitleCase(output[y][nameIDcolumn]), out string variableName)) | |
{ | |
itemName = char.ToUpper(variableName[0]) + variableName.Substring(1); | |
} | |
else | |
{ | |
itemName = typeof(TItemInformationData).Name; | |
} | |
report.Append("ITEMID: [").Append(uniqueIDcolumn).Append(", ").Append(y).Append("] ").Append(output[y][uniqueIDcolumn]).AppendLine(); | |
var itemID = output[y][uniqueIDcolumn]; | |
yield return ItemExists(itemID, delegate (string newItemID, ItemData foundItem) | |
{ | |
var propertyInfo = new PropertyToValueInfo( | |
UniqueIDPropertyName, | |
newItemID, | |
default, | |
uniqueIDcolumn, y, | |
1, 1, false, new[] { UniqueIDPropertyName }, | |
false | |
); | |
propertyToValueList.Add(propertyInfo); | |
item = foundItem; | |
itemID = foundItem.Uid; | |
}); | |
for (x = 0; x < output[y].Length; x += xIncr) | |
{ | |
if (x == nameIDcolumn || x == uniqueIDcolumn) | |
{ | |
continue; | |
} | |
report.Append("CELL: [").Append(x).Append(", ").Append(y).Append("] ").Append(output[y][x]).AppendLine(); | |
tableRead.Append(output[y][x]).Append(delimiter); | |
xIncr = 1; | |
if (!colToPropertyNameDict.TryGetValue(x, out ColToPropertyNameInfo info)) | |
{ | |
continue; | |
} | |
EditorUtility.DisplayProgressBar(progressBarTitle, "Reading cell... " + itemName, GetProgress(y, output[y].Length, 2)); | |
var propName = info.PropertyName; | |
var propertyInfo = new PropertyToValueInfo( | |
propName, | |
output[y][x], | |
info.VariableTypePref, | |
x, y, | |
info.Width, info.Height, info.IsCSVItem, info.Headers, | |
info.IsItemID); | |
propertyToValueList.Add(propertyInfo); | |
xIncr = info.Width; | |
yIncr = info.Height; | |
report.Append("Increasing: ").Append(xIncr).Append(", ").Append(yIncr).AppendLine(); | |
} | |
report.Append("ASSIGNING VALUES").AppendLine(); | |
var hasID = !string.IsNullOrEmpty(itemID); | |
var newData = CreateOrFindNewInfo( | |
elements, | |
hasID ? FindElementMethod.ByUniqueID : FindElementMethod.ByName, | |
hasID ? itemID : itemName, | |
elements.arraySize, | |
itemName); | |
using (var newSerializedObject = new SerializedObject(newData)) | |
{ | |
for (int p = 0; p < propertyToValueList.Count; p++) | |
{ | |
var propertyInfo = propertyToValueList[p]; | |
var key = propertyInfo.SerializedPropertyName; | |
var value = propertyInfo.PropertyValue; | |
var variableTypePref = propertyToValueList[p].VariableTypePref; | |
var variableType = string.IsNullOrEmpty(variableTypePref.Key) ? variableTypePref.Value : VariableType.AutoDetect; | |
using (var newProperty = newSerializedObject.FindProperty(key)) | |
{ | |
if (newProperty == null) | |
{ | |
cannotFindProperties.Add(key); | |
} | |
else | |
{ | |
if (debugSubtable) | |
{ | |
report | |
.Append("Is \"") | |
.Append(newProperty.name) | |
.Append("\" a CSV item? ") | |
.Append(propertyInfo.IsSubtable) | |
.AppendLine(); | |
} | |
if (propertyInfo.IsSubtable) | |
{ | |
if (debugSubtable) | |
{ | |
report.Append('-', 50).AppendLine() | |
.Append("BEGIN MAKING SUBTABLE").AppendLine(); | |
} | |
var subtable = new string[propertyInfo.Height][]; | |
var propX = propertyInfo.X; | |
var propY = propertyInfo.Y; | |
for (int h = 0; h < propertyInfo.Height; h++) | |
{ | |
subtable[h] = new string[propertyInfo.Width]; | |
for (int w = 0; w < propertyInfo.Width; w++) | |
{ | |
try | |
{ | |
if (debugSubtable) | |
{ | |
report.Append(h).Append(", ").Append(w).Append("; "); | |
report.Append(h + propY).Append(", ").Append(w + propX).Append("; "); | |
report.AppendLine(); | |
} | |
var cell = output[h + propY][w + propX]; | |
if (debugSubtable) | |
{ | |
report.Append(cell); | |
report.AppendLine(); | |
} | |
subtable[h][w] = cell; | |
} | |
catch | |
{ | |
if (debugSubtable) | |
{ | |
report.Append("Out of Bounds"); | |
report.AppendLine(); | |
} | |
} | |
} | |
} | |
try | |
{ | |
ProcessSubtable(itemID, newSerializedObject, newProperty, subtable, propertyInfo.Headers); | |
} | |
catch (NotImplementedException) | |
{ | |
csvNotImplemented.Add(propertyInfo.SerializedPropertyName); | |
} | |
if (debugSubtable) | |
{ | |
report | |
.Append("END SUBTABLE").AppendLine() | |
.Append('-', 50); | |
} | |
} | |
else | |
{ | |
report.Append("Begin Assignment \"") | |
.Append(newProperty.name) | |
.Append("\" :: ") | |
.Append(variableType) | |
.AppendLine(); | |
switch (variableType) | |
{ | |
case VariableType.AutoDetect: | |
{ | |
report.Append("Is \"") | |
.Append(newProperty.name) | |
.Append("\" an ItemID item? ") | |
.Append(propertyInfo.IsItemID) | |
.AppendLine(); | |
bool foundItem = false; | |
if (propertyInfo.IsItemID) | |
{ | |
yield return ItemExists(value, delegate (string newItemID, ItemData valueItem) | |
{ | |
report.Append("Trying to find: ").Append(value).AppendLine(); | |
newProperty.stringValue = valueItem.Uid; | |
foundItem = true; | |
}); | |
} | |
if (!foundItem) | |
{ | |
try | |
{ | |
switch (newProperty.propertyType) | |
{ | |
case SerializedPropertyType.Generic: | |
if (newProperty.hasVisibleChildren && value.Contains(delimiter)) | |
{ | |
var split = value.Split(delimiter); | |
SerializedProperty[] children = newProperty.GetVisibleChildren().ToArray(); | |
if (children.Length <= split.Length) | |
{ | |
for (int i = 0; i < children.Length; i++) | |
{ | |
report.Append("Assigning \"").Append(newProperty.name).Append('.').Append(children[i].name).Append("\" to ") | |
.Append("\"").Append(split[i]).Append("\"").AppendLine(); | |
children[i].SetValueString(split[i]); | |
} | |
} | |
} | |
break; | |
case SerializedPropertyType.Boolean: | |
newProperty.boolValue = Helper.StringToBoolFuzzy(value); | |
break; | |
default: | |
newProperty.SetValueString(value, delimiter); | |
break; | |
} | |
} | |
catch (ParseException e) | |
{ | |
var errBuilder = new StringBuilder(); | |
errBuilder.AppendMany("Could not parse \"", value, "\" to \"", newProperty.name, "\" (", newProperty.propertyType, ")") | |
.ToString(); | |
if (newProperty.propertyType == SerializedPropertyType.Generic) | |
{ | |
//errBuilder.AppendMany(" Make sure that \"", newProperty.GetPropertyType().Name, " \"can be converted to from a string!"); | |
generics.Add(newProperty.GetPropertyType().Name); | |
} | |
var err = errBuilder.ToString(); | |
parseErrors.Add(err); | |
report.Append(err).AppendLine().Append(e).AppendLine(); | |
} | |
catch (ArgumentException e) when (newProperty.propertyType == SerializedPropertyType.Enum) | |
{ | |
Debug.LogWarning(e.ToString()); | |
} | |
} | |
} | |
break; | |
case VariableType.Bool: | |
newProperty.boolValue = Helper.StringToBoolFuzzy(value); | |
break; | |
case VariableType.Integer: | |
newProperty.intValue = int.Parse(value); | |
break; | |
case VariableType.Float: | |
newProperty.floatValue = float.Parse(value); | |
break; | |
case VariableType.String: | |
newProperty.stringValue = value; | |
break; | |
case VariableType.Enum: | |
try | |
{ | |
newProperty.SetEnumValue(value); | |
} | |
catch (ArgumentException argumentException) | |
{ | |
Debug.LogWarning(argumentException.ToString()); | |
} | |
break; | |
case VariableType.EnumFlags: | |
newProperty.AssignEnumValueFlags(value, delimiter); | |
break; | |
case VariableType.ItemID: | |
{ | |
var assignString = false; | |
yield return ItemExists(value, delegate (string newItemID, ItemData valueItem) | |
{ | |
newProperty.stringValue = valueItem.Uid; | |
assignString = true; | |
}); | |
if (assignString) | |
{ | |
newProperty.stringValue = value; | |
} | |
} | |
break; | |
default: | |
break; | |
} | |
//Overriding autodetect | |
if (variableType == VariableType.AutoDetect) | |
{ | |
switch (newProperty.propertyType) | |
{ | |
case SerializedPropertyType.Integer: | |
variableTypePref.Value = VariableType.Integer; | |
break; | |
case SerializedPropertyType.Boolean: | |
variableTypePref.Value = VariableType.Bool; | |
break; | |
case SerializedPropertyType.Float: | |
variableTypePref.Value = VariableType.Float; | |
break; | |
case SerializedPropertyType.String: | |
report.Append("Overriding : ").Append(propertyInfo.SerializedPropertyName).Append("(").Append(propertyInfo.IsItemID).Append(")").AppendLine(); | |
if (propertyInfo.IsItemID) | |
{ | |
variableTypePref.Value = VariableType.ItemID; | |
} | |
else | |
{ | |
variableTypePref.Value = VariableType.String; | |
} | |
break; | |
case SerializedPropertyType.Enum: | |
variableTypePref.Value = value.Contains(delimiter) ? VariableType.EnumFlags : VariableType.Enum; | |
break; | |
case SerializedPropertyType.Character: | |
variableTypePref.Value = VariableType.String; | |
break; | |
} | |
} | |
} | |
} | |
} | |
} | |
if (item != null) | |
{ | |
var type = typeof(TItemInformationData); | |
using (var itemSerializedObject = new SerializedObject(item)) | |
{ | |
using (var target = string.IsNullOrEmpty(additionalDataPropertyPathInItem) | |
? itemSerializedObject.FindPropertyOfType(type, true) | |
: itemSerializedObject.FindProperty(additionalDataPropertyPathInItem)) | |
{ | |
if (target == null) | |
{ | |
cannotFindAssignableProperties.Add(newSerializedObject.targetObject.name + "(" + type + ")"); | |
} | |
else | |
{ | |
target.objectReferenceValue = newData; | |
target.serializedObject.ApplyModifiedProperties(); | |
additionalDataPropertyPathInItem = target.propertyPath; | |
} | |
} | |
} | |
} | |
else | |
{ | |
couldNotFindItemID.Add(itemID); | |
} | |
OnApplyChanges(newData, newSerializedObject); | |
data.Add(newSerializedObject); | |
} | |
OnImported(newData); | |
} | |
AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(target)); | |
AssetDatabase.Refresh(); | |
EditorUtility.ClearProgressBar(); | |
} | |
private IEnumerator ItemExists(string givenID, Action<string, ItemData> onFoundItem) | |
{ | |
foreach (var item in ItemDatabase.Items.Values) | |
{ | |
foreach (var term in ItemSearchTerms(item)) | |
{ | |
if (ComparePossibleNames(givenID, term)) | |
{ | |
onFoundItem(givenID, item); | |
yield break; | |
} | |
} | |
} | |
var layout = -1; | |
var options = new GUIContent[] { | |
new GUIContent("Create New Item"), | |
new GUIContent("Choose Item"), | |
new GUIContent("Cancel") }; | |
var newItemID = givenID; | |
var newItemName = Helper.CamelCaseToTitle(givenID); | |
var newPath = string.Empty; | |
var customWindow = CustomWindow.Show(delegate (CustomWindow window) | |
{ | |
using (new EditorGUILayout.HorizontalScope()) | |
{ | |
GUILayout.FlexibleSpace(); | |
using (new EditorGUILayout.VerticalScope()) | |
{ | |
GUILayout.FlexibleSpace(); | |
using (new EditorGUILayout.HorizontalScope()) | |
{ | |
GUILayout.Box(EditorGUIUtility.FindTexture("d_console.erroricon"), GUIStyle.none); | |
using (new EditorGUILayout.VerticalScope()) | |
{ | |
EditorGUILayout.LabelField("Could not find the following Item ID:"); | |
EditorGUILayout.LabelField(givenID); | |
EditorGUILayout.LabelField("What would you like to do?"); | |
} | |
} | |
GUILayout.FlexibleSpace(); | |
layout = GUILayout.Toolbar(layout, options); | |
switch (layout) | |
{ | |
case 0: | |
GUILayout.FlexibleSpace(); | |
using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) | |
{ | |
newItemID = EditorGUILayout.TextField("New Item ID", newItemID); | |
newItemName = EditorGUILayout.TextField("New Item Name", newItemName); | |
var rect = EditorGUILayout.GetControlRect(); | |
if (EditorGUI.DropdownButton(rect, new GUIContent(string.IsNullOrEmpty(newPath) ? "Choose..." : newPath), FocusType.Keyboard)) | |
{ | |
var menu = new GenericMenu(); | |
var databases = AssetDatabase.FindAssets("t:ItemDataGroup") | |
.Select(AssetDatabase.GUIDToAssetPath); | |
foreach (var path in databases) | |
{ | |
menu.AddItem(new GUIContent(Path.GetFileNameWithoutExtension(path)), | |
string.CompareOrdinal(newPath, path) == 0, | |
delegate | |
{ | |
newPath = path; | |
}); | |
} | |
menu.DropDown(rect); | |
} | |
using (new EditorGUI.DisabledGroupScope(string.IsNullOrEmpty(newPath))) | |
{ | |
if (GUILayout.Button("OK")) | |
{ | |
var database = AssetDatabase.LoadAssetAtPath<ItemDataGroup>(newPath); | |
if (database != null) | |
{ | |
using (var databaseSerializedObject = new SerializedObject(database)) | |
{ | |
using (var arraySerializedProperty = databaseSerializedObject.FindProperty("_Items")) | |
{ | |
int size = arraySerializedProperty.arraySize; | |
arraySerializedProperty.arraySize = size + 1; | |
using (var newElementProperty = arraySerializedProperty.GetArrayElementAtIndex(size)) | |
{ | |
var inventoryItemData = CreateInstance<ItemData>(); | |
inventoryItemData.name = newItemName; | |
using (var itemSerializedObject = new SerializedObject(inventoryItemData)) | |
{ | |
using (var idElementProperty = itemSerializedObject.FindProperty("_Uid")) | |
{ | |
idElementProperty.stringValue = newItemID; | |
} | |
itemSerializedObject.ApplyModifiedProperties(); | |
} | |
AssetDatabase.AddObjectToAsset(inventoryItemData, database); | |
inventoryItemData.name = newItemName; | |
newElementProperty.objectReferenceValue = inventoryItemData; | |
serializedObject.ApplyModifiedProperties(); | |
onFoundItem(newItemID, inventoryItemData); | |
} | |
} | |
databaseSerializedObject.ApplyModifiedProperties(); | |
} | |
} | |
AssetDatabase.ImportAsset(newPath); | |
AssetDatabase.Refresh(); | |
window.Close(); | |
} | |
} | |
} | |
break; | |
case 1: | |
GUILayout.FlexibleSpace(); | |
using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) | |
{ | |
var rect = EditorGUILayout.GetControlRect(); | |
if (EditorGUI.DropdownButton(rect, new GUIContent(string.CompareOrdinal(newItemID, givenID) == 0 ? "Choose..." : newItemID), FocusType.Keyboard)) | |
{ | |
var menu = new GenericMenu(); | |
foreach (var item in ItemDatabase.Items.Values | |
.WhereNotNull() | |
.Select((i, n) => new | |
{ | |
Index = n, | |
ID = i.Uid, | |
Item = i, | |
Menu = Path.GetFileNameWithoutExtension(AssetDatabase.GetAssetPath(i)) + Path.AltDirectorySeparatorChar + ItemName.GetWithQuality(i) | |
}) | |
.OrderBy(i => i.Menu) | |
) | |
{ | |
menu.AddItem(new GUIContent(item.Menu), | |
string.CompareOrdinal(item.ID, newItemID) == 0, | |
delegate | |
{ | |
newItemID = item.ID; | |
}); | |
} | |
menu.DropDown(rect); | |
} | |
using (new EditorGUI.DisabledGroupScope(!ItemDatabase.Items.ContainsKey(newItemID))) | |
{ | |
if (GUILayout.Button("OK")) | |
{ | |
onFoundItem(newItemID, ItemDatabase.Items[newItemID]); | |
window.Close(); | |
} | |
} | |
} | |
break; | |
case 2: | |
window.Close(); | |
break; | |
} | |
GUILayout.FlexibleSpace(); | |
} | |
GUILayout.FlexibleSpace(); | |
} | |
}, CustomWindow.WindowType.Utility); | |
EditorUtility.ClearProgressBar(); | |
while (customWindow.IsOpen) | |
{ | |
yield return null; | |
} | |
} | |
private IEnumerable<string> ItemSearchTerms(ItemData item) | |
{ | |
yield return item.Uid; | |
yield return item.Class.ToString(); | |
foreach (var tag in item.Tags) | |
{ | |
yield return tag; | |
} | |
} | |
private bool ComparePossibleNames(string a, string b) | |
{ | |
var comparison = StringComparison.OrdinalIgnoreCase; | |
foreach (var ai in GetOtherPossibleNamesForValue(a)) | |
{ | |
foreach (var bi in GetOtherPossibleNamesForValue(b)) | |
{ | |
if (string.Equals(ai, bi, comparison)) | |
{ | |
return true; | |
} | |
} | |
} | |
return false; | |
} | |
private IEnumerable<string> GetOtherPossibleNamesForValue(string str) | |
{ | |
yield return str; | |
string trimmed = str.Trim().ToLower(); | |
yield return trimmed; | |
yield return trimmed.Replace(" ", ""); | |
yield return trimmed.Replace(" ", "_"); | |
yield return trimmed.Replace("_", ""); | |
yield return trimmed.Replace("_", " "); | |
var noNumbers = new string(str.Where(c => char.IsLetter(c)).ToArray()); | |
if (str != noNumbers) | |
{ | |
foreach (string otherNoNumbers in GetOtherPossibleNamesForValue(noNumbers)) | |
{ | |
yield return otherNoNumbers; | |
} | |
} | |
} | |
protected virtual string[][] ExportCSV() | |
{ | |
var bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; | |
SerializedProperty elements = serializedObject.FindProperty("_infoData"); | |
var colNum = SerializedPropertyToCSVName.Length + 2; | |
var rowNum = elements.arraySize + 1; | |
var rows = new string[rowNum][]; | |
rows[0] = new string[colNum]; | |
int i, j; | |
int ii = 0; | |
const int idCol = 1; | |
const int nameCol = 0; | |
rows[0][idCol] = uniqueID.Value; | |
rows[0][nameCol] = itemName.Value; | |
for (j = 0; j < SerializedPropertyToCSVName.Length; j++) | |
{ | |
rows[0][j + 2] = SerializedPropertyToCSVName[j].NameInCSVPref.Value; | |
} | |
for (i = 0; i < elements.arraySize; i++) | |
{ | |
var elementProp = elements.GetArrayElementAtIndex(i); | |
var elementObj = elementProp.objectReferenceValue; | |
if (elementObj == null) | |
{ | |
Debug.LogError("Element " + elements.name + "[" + i + "] is null."); | |
continue; | |
} | |
var elementSerializedObject = new SerializedObject(elementObj); | |
var idProperty = elementSerializedObject.FindProperty("_Uid"); | |
if (idProperty == null) | |
{ | |
Debug.LogError("Cannot find ID on" + elements.name + "[" + i + "]."); | |
continue; | |
} | |
ii = i; | |
var row = ii + 1; | |
rows[row] = new string[colNum]; | |
rows[row][idCol] = idProperty.stringValue; | |
var suffix = "_" + typeof(TItemInformationData).Name; | |
var rowName = elementSerializedObject.targetObject.name; | |
if (rowName.EndsWith(suffix)) | |
{ | |
rowName = rowName.Substring(0, rowName.Length - suffix.Length); | |
} | |
rows[row][nameCol] = rowName; | |
for (j = 0; j < SerializedPropertyToCSVName.Length; j++) | |
{ | |
var t = elementObj.GetType(); | |
var propName = SerializedPropertyToCSVName[j].SerializedPropertyName; | |
var fieldInfo = t.GetField(propName, bindingFlags); | |
var obj = fieldInfo.GetValue(elementObj); | |
var val = GetObjectString(delegate | |
{ | |
return elementSerializedObject.FindProperty(propName); | |
}, propName, obj); | |
rows[row][j + 2] = val; | |
} | |
} | |
return rows; | |
} | |
protected virtual void ProcessSubtable(string uniqueID, SerializedObject serializedObject, SerializedProperty property, string[][] subtable, string[] headers) | |
{ | |
throw new NotImplementedException("If you have CSVItems, please override the ProcessCSVItem method to process them"); | |
} | |
protected virtual void OnApplyChanges(Object target, SerializedObject serializedObject) | |
{ | |
serializedObject.ApplyModifiedProperties(); | |
} | |
protected virtual void OnImported(TItemInformationData data) | |
{ | |
} | |
private string GetObjectString(Func<SerializedProperty> getProperty, string varName, object obj) | |
{ | |
if (obj == null) | |
{ | |
return string.Empty; | |
} | |
if (getProperty != null) | |
{ | |
var property = getProperty(); | |
try | |
{ | |
switch (property.propertyType) | |
{ | |
case SerializedPropertyType.Integer: | |
return property.intValue.ToString(); | |
case SerializedPropertyType.Boolean: | |
return property.boolValue.ToString(); | |
case SerializedPropertyType.Float: | |
return property.floatValue.ToString(); | |
case SerializedPropertyType.String: | |
return property.stringValue; | |
case SerializedPropertyType.Color: | |
return property.colorValue.ToString(); | |
case SerializedPropertyType.ObjectReference: | |
return AssetDatabase.GetAssetPath(property.objectReferenceValue); | |
case SerializedPropertyType.Vector2: | |
return property.vector2Value.ToString(); | |
case SerializedPropertyType.Vector3: | |
return property.vector3Value.ToString(); | |
case SerializedPropertyType.Vector4: | |
return property.vector4Value.ToString(); | |
case SerializedPropertyType.Rect: | |
return property.rectValue.ToString(); | |
case SerializedPropertyType.Character: | |
return new string((char)property.intValue, 1); | |
case SerializedPropertyType.Bounds: | |
return property.boundsValue.ToString(); | |
case SerializedPropertyType.Quaternion: | |
return property.quaternionValue.ToString(); | |
case SerializedPropertyType.Vector2Int: | |
return property.vector2IntValue.ToString(); | |
case SerializedPropertyType.Vector3Int: | |
return property.vector3IntValue.ToString(); | |
case SerializedPropertyType.RectInt: | |
return property.rectIntValue.ToString(); | |
} | |
} | |
catch (NullReferenceException) when (property == null) | |
{ | |
} | |
} | |
var type = obj.GetType(); | |
if (obj is string || type == typeof(string) || type == typeof(string)) | |
{ | |
return obj.ToString(); | |
} | |
if (type.IsArray) | |
{ | |
var builder = new StringBuilder(); | |
var addComma = false; | |
var index = 0; | |
foreach (object entry in (IEnumerable)obj) | |
{ | |
var i = index; | |
index += 1; | |
if (entry == null) | |
{ | |
continue; | |
} | |
if (addComma) | |
{ | |
builder.Append(','); | |
} | |
builder.Append(GetObjectString(delegate | |
{ | |
var prop = getProperty(); | |
var arrProp = prop.GetArrayElementAtIndex(i); | |
return arrProp; | |
}, varName, entry)); | |
addComma = true; | |
} | |
return builder.ToString(); | |
} | |
return obj.ToString() | |
.Replace("\n", string.Empty) | |
.Replace("\r", string.Empty) | |
.Trim(); | |
} | |
private ReorderableList GetReorderableList(SerializedObject serializedObject, SerializedProperty elements) | |
{ | |
var italicLabelStyle = new GUIStyle(EditorStyles.label) | |
{ | |
fontStyle = FontStyle.Italic | |
}; | |
var list = new ReorderableList(serializedObject, elements) | |
{ | |
drawHeaderCallback = GetElementHeader, | |
drawElementCallback = GetElement, | |
onAddDropdownCallback = delegate (Rect buttonRect, ReorderableList l) | |
{ | |
var window = CreateInstance<ItemSelectorWindow>(); | |
window.Instantiate(delegate (ItemData item) | |
{ | |
var infoData = CreateNewInfo(elements, l); | |
var infoSerializedObject = new SerializedObject(infoData); | |
infoSerializedObject.FindProperty("_Uid").stringValue = item.Uid; | |
var itemObj = item as Object; | |
if (itemObj != null) | |
{ | |
infoData.name = itemObj.name;// + "_" + typeof(TItemInformationData).Name; | |
var itemSerializedObject = new SerializedObject(itemObj); | |
var itm = itemSerializedObject.FindPropertyOfType<TItemInformationData>(); | |
if (itm != null) | |
{ | |
itm.objectReferenceValue = infoData; | |
} | |
itemSerializedObject.ApplyModifiedProperties(); | |
AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(target)); | |
} | |
infoSerializedObject.ApplyModifiedProperties(); | |
}, elements); | |
if (window == null) | |
{ | |
throw new NullReferenceException("Window was null"); | |
} | |
if (buttonRect == null) | |
{ | |
throw new NullReferenceException("buttonRect was null"); | |
} | |
window.ShowAsDropDown(GUIUtility.GUIToScreenRect(buttonRect), new Vector2(300, 200)); | |
}, | |
onRemoveCallback = delegate (ReorderableList l) | |
{ | |
ReorderableList.defaultBehaviours.DoRemoveButton(l); | |
serializedObject.ApplyModifiedProperties(); | |
bool deletedAsset = false; | |
foreach (var i in AssetDatabase.LoadAllAssetRepresentationsAtPath(AssetDatabase.GetAssetPath(target)) | |
.Select(o => o as TItemInformationData) | |
.WhereNotNull() | |
.Except(elements | |
.GetPropertiesInArray() | |
.Select(p => p.objectReferenceValue as TItemInformationData) | |
.WhereNotNull() | |
)) | |
{ | |
DestroyImmediate(i, true); | |
deletedAsset = true; | |
} | |
if (deletedAsset) | |
{ | |
AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(target)); | |
AssetDatabase.Refresh(); | |
} | |
for (int i = elements.arraySize - 1; i >= 0; i--) | |
{ | |
if (elements.GetArrayElementAtIndex(i).objectReferenceValue == null) | |
{ | |
elements.DeleteArrayElementAtIndex(i); | |
} | |
} | |
serializedObject.ApplyModifiedProperties(); | |
} | |
}; | |
return list; | |
} | |
protected virtual void GetElementHeader(Rect rect) | |
{ | |
const float buttonW = 70f; | |
using (var elements = serializedObject.FindProperty("_infoData")) | |
{ | |
var clearContent = new GUIContent("Clear"); | |
var clearStyle = new GUIStyle(EditorStyles.miniButton) | |
{ | |
fixedHeight = 0 | |
}; | |
float height = EditorGUIUtility.singleLineHeight; | |
float diff = 1; | |
var lRect = new Rect(rect.x, | |
rect.y + diff, | |
rect.width - buttonW, | |
rect.height - diff - diff); | |
var rRect = new Rect(rect.x + rect.width - buttonW, | |
rect.y + diff, | |
buttonW, | |
rect.height - diff - diff); | |
EditorGUI.LabelField(lRect, ObjectNames.NicifyVariableName(typeof(TItemInformationData).Name)); | |
if (GUI.Button(rRect, clearContent, clearStyle)) | |
{ | |
elements.arraySize = 0; | |
serializedObject.ApplyModifiedProperties(); | |
bool deletedAsset = false; | |
foreach (var i in AssetDatabase.LoadAllAssetRepresentationsAtPath(AssetDatabase.GetAssetPath(target)) | |
.Select(o => o as TItemInformationData) | |
.WhereNotNull() | |
.Except(elements | |
.GetPropertiesInArray() | |
.Select(p => p.objectReferenceValue as TItemInformationData) | |
.WhereNotNull() | |
)) | |
{ | |
DestroyImmediate(i, true); | |
deletedAsset = true; | |
} | |
if (deletedAsset) | |
{ | |
AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(target)); | |
AssetDatabase.Refresh(); | |
} | |
serializedObject.ApplyModifiedProperties(); | |
} | |
} | |
} | |
protected virtual void GetElement(Rect rect, int index, bool isActive, bool isFocused) | |
{ | |
var labelStyle = new GUIStyle(EditorStyles.label); | |
const float buttonW = 70f; | |
using (var elements = serializedObject.FindProperty("_infoData")) | |
{ | |
if (0 > index || index >= elements.arraySize) | |
{ | |
EditorGUI.LabelField(rect, "Error"); | |
return; | |
} | |
using (var property = elements.GetArrayElementAtIndex(index)) | |
{ | |
if (property == null || property.objectReferenceValue == null) | |
{ | |
EditorGUI.LabelField(rect, "Error"); | |
return; | |
} | |
string itemName; | |
using (var objectSO = new SerializedObject(property.objectReferenceValue)) | |
using (var uniqueID = objectSO.FindProperty("_Uid")) | |
{ | |
if (string.IsNullOrEmpty(uniqueID.stringValue)) | |
{ | |
itemName = ObjectNames.NicifyVariableName(property.objectReferenceValue.name); | |
} | |
else | |
{ | |
if (ItemDatabase.Items.TryGetValue(uniqueID.stringValue, out var item)) | |
{ | |
var casted = property.objectReferenceValue as TItemInformationData; | |
if (casted == null) | |
{ | |
itemName = "Item " + index; | |
} | |
else | |
{ | |
itemName = GetItemName(casted); | |
} | |
} | |
else | |
{ | |
itemName = "Item " + index; | |
} | |
} | |
} | |
var openContent = new GUIContent("Open"); | |
var openStyle = EditorStyles.miniButton; | |
var height = EditorGUIUtility.singleLineHeight; | |
var diff = 2; | |
var lRect = new Rect(rect.x, | |
rect.y + diff, | |
rect.width - buttonW, | |
height); | |
var rRect = new Rect(rect.x + rect.width - buttonW, | |
rect.y + diff, | |
buttonW, | |
height); | |
EditorGUI.LabelField(lRect, itemName, labelStyle); | |
if (GUI.Button(rRect, openContent, openStyle)) | |
{ | |
Selection.objects = new[] { elements.GetArrayElementAtIndex(index).objectReferenceValue }; | |
} | |
} | |
} | |
} | |
protected virtual string GetItemName(TItemInformationData objectReferenceValue) | |
{ | |
return ObjectNames.NicifyVariableName(objectReferenceValue.name); | |
} | |
private TItemInformationData CreateNewInfo(SerializedProperty elements, ReorderableList list) | |
{ | |
int index = list.index + 1; | |
if (0 > index || index >= elements.arraySize) | |
{ | |
index = elements.arraySize; | |
} | |
var infoData = CreateNewInfo(elements, index); | |
list.index = index; | |
return infoData; | |
} | |
private TItemInformationData CreateOrFindNewInfo(SerializedProperty elements, FindElementMethod findMethod, string uniqueID, int index, string itemName = "") | |
{ | |
if (TryFindElement(elements, findMethod, uniqueID, out var item)) | |
{ | |
return item; | |
} | |
return CreateNewInfo(elements, index, itemName); | |
} | |
private bool TryFindElement(SerializedProperty elements, FindElementMethod findMethod, string uniqueID, out TItemInformationData item) | |
{ | |
if (elements == null || !elements.isArray) | |
{ | |
item = default; | |
return false; | |
} | |
for (int i = 0; i < elements.arraySize; i++) | |
{ | |
using (var elementProperty = elements.GetArrayElementAtIndex(i)) | |
{ | |
if (elementProperty == null | |
|| elementProperty.propertyType != SerializedPropertyType.ObjectReference | |
) | |
{ | |
continue; | |
} | |
var obj = elementProperty.objectReferenceValue; | |
if (obj == null) | |
{ | |
continue; | |
} | |
var data = obj as TItemInformationData; | |
if (data == null) | |
{ | |
continue; | |
} | |
using (var elementObject = new SerializedObject(obj)) | |
{ | |
switch (findMethod) | |
{ | |
case FindElementMethod.ByUniqueID: | |
using (SerializedProperty uniqueIDProperty = elementObject.FindProperty("_Uid")) | |
{ | |
if (uniqueIDProperty == null || uniqueIDProperty.propertyType != SerializedPropertyType.String) | |
{ | |
continue; | |
} | |
if (string.CompareOrdinal(uniqueIDProperty.stringValue, uniqueID) == 0) | |
{ | |
item = data; | |
return true; | |
} | |
} | |
break; | |
case FindElementMethod.ByName: | |
if (string.CompareOrdinal(data.name, uniqueID) == 0) | |
{ | |
item = data; | |
return true; | |
} | |
break; | |
} | |
} | |
} | |
} | |
item = default; | |
return false; | |
} | |
private TItemInformationData CreateNewInfo(SerializedProperty elements, int index, string itemName = "") | |
{ | |
var infoData = ScriptableObject.CreateInstance<TItemInformationData>(); | |
if (string.IsNullOrEmpty(itemName)) | |
{ | |
infoData.name = typeof(TItemInformationData).Name + "_" + elements.arraySize; | |
} | |
else | |
{ | |
infoData.name = itemName; | |
} | |
AssetDatabase.AddObjectToAsset(infoData, target); | |
elements.InsertArrayElementAtIndex(index); | |
elements.GetArrayElementAtIndex(index).objectReferenceValue = infoData; | |
serializedObject.ApplyModifiedProperties(); | |
return infoData; | |
} | |
private string GetDefaultCSVHeader(string variableName) | |
{ | |
var s = variableName; | |
var builder = new StringBuilder(); | |
for (int i = 0; i < s.Length; i++) | |
{ | |
char c = s[i]; | |
if (builder.Length == 0) | |
{ | |
if (char.IsLetter(c)) | |
{ | |
builder.Append(char.ToUpper(c)); | |
} | |
} | |
else | |
{ | |
builder.Append(c); | |
} | |
} | |
return builder.ToString(); | |
} | |
private void DrawFixButtonsArea() | |
{ | |
debugOptions = EditorGUILayout.Foldout(debugOptions, "Debug Options", true); | |
if (!debugOptions) | |
{ | |
return; | |
} | |
using (new EditorGUILayout.VerticalScope(GUI.skin.box)) | |
{ | |
EditorGUILayout.Space(); | |
DrawFixButtons(); | |
} | |
} | |
protected virtual void DrawFixButtons() | |
{ | |
EditorGUILayout.LabelField("Array", EditorStyles.boldLabel); | |
if (DoFixButton("Adds items to the array that are present in the asset", "Add missing")) | |
{ | |
DoAddMissing(); | |
} | |
if (DoFixButton("Removes null entries in the array", "Remove Null")) | |
{ | |
DoRemoveNulls(); | |
} | |
EditorGUILayout.LabelField("Asset", EditorStyles.boldLabel); | |
if (DoFixButton("Renames the sub-assets to have the correct names", "Fix Names")) | |
{ | |
DoFixNames(); | |
} | |
if (DoFixButton("Adds all " + ObjectNames.NicifyVariableName(typeof(TItemInformationData).Name) + " to this asset", "Adopt All")) | |
{ | |
MakeMeMaster(); | |
} | |
EditorGUILayout.LabelField("Items", EditorStyles.boldLabel); | |
if (DoFixButton("Fixes references items to sub assets", "Fix Item to Asset References")) | |
{ | |
DoFixItemToAssetReferences(); | |
} | |
} | |
protected bool DoFixButton(string label, string buttonContent) | |
{ | |
using (new EditorGUILayout.HorizontalScope()) | |
{ | |
EditorGUILayout.LabelField(label, new GUIStyle(EditorStyles.label) { wordWrap = true }); | |
return GUILayout.Button(buttonContent, EditorStyles.miniButton, GUILayout.Width(120)); | |
} | |
} | |
private void DoRemoveNulls() | |
{ | |
var array = serializedObject.FindProperty("_infoData"); | |
for (int i = array.arraySize - 1; i >= 0; i--) | |
{ | |
var element = array.GetArrayElementAtIndex(i); | |
if (element == null || element.objectReferenceValue == null) | |
{ | |
array.DeleteArrayElementAtIndex(i); | |
} | |
} | |
serializedObject.ApplyModifiedProperties(); | |
} | |
private void DoAddMissing() | |
{ | |
var array = serializedObject.FindProperty("_infoData"); | |
var assets = AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GetAssetPath(target)) | |
.Where(a => a is TItemInformationData) | |
.Except(array.GetPropertiesInArray().Select(p => p.objectReferenceValue)); | |
foreach (var asset in assets) | |
{ | |
int size = array.arraySize; | |
array.arraySize = size + 1; | |
array.GetArrayElementAtIndex(size).objectReferenceValue = asset; | |
} | |
serializedObject.ApplyModifiedProperties(); | |
} | |
private void DoFixItemToAssetReferences() | |
{ | |
var typeName = typeof(TItemInformationData).Name.ToLower().Trim(); | |
var infoDataSerializedProperty = serializedObject.FindProperty("_infoData"); | |
var builder = new StringBuilder(); | |
builder.AppendManyLine("Begin : ", serializedObject.targetObject.name, " (", infoDataSerializedProperty.arraySize, ")"); | |
var paths = new List<string>(); | |
for (int i = 0; i < infoDataSerializedProperty.arraySize; i++) | |
{ | |
builder.AppendManyLine("Checking Item _infoData[", i, "]"); | |
builder.Append(" "); | |
var infoDataProperty = infoDataSerializedProperty.GetArrayElementAtIndex(i); | |
var infoDataPropertyContents = infoDataProperty.objectReferenceValue; | |
if (infoDataPropertyContents == null) | |
{ | |
builder.AppendManyLine("FAILURE: [", i, "] is null"); | |
continue; | |
} | |
var infoDataSerializedObject = new SerializedObject(infoDataPropertyContents); | |
var idProperty = infoDataSerializedObject.FindProperty("_Uid"); | |
var uniqueID = idProperty.stringValue; | |
ItemDatabase.Items.TryGetValue(uniqueID, out var item); | |
if (item == null) | |
{ | |
builder.AppendManyLine("FAILURE: Cannot find:- ", uniqueID); | |
continue; | |
} | |
var itemSerializedObject = new SerializedObject(item); | |
var iterator = itemSerializedObject.GetIterator(); | |
iterator.Next(true); | |
var changed = false; | |
do | |
{ | |
if (iterator.propertyType != SerializedPropertyType.ObjectReference) | |
{ | |
continue; | |
} | |
var t = iterator.GetPropertyType(); | |
if (t == null) | |
{ | |
builder.AppendManyLine("Could not find type for: ", iterator.name, " => ", iterator.type); | |
builder.Append(" "); | |
continue; | |
} | |
var thisTypeName = t.Name; | |
var iteratorTypeName = thisTypeName.ToLower().Trim(); | |
if (iteratorTypeName == typeName) | |
{ | |
builder.AppendManyLine("SUCCESS: ", item.name, " :: ", iterator.name, " => ", infoDataPropertyContents.name, " (", thisTypeName, ")"); | |
iterator.objectReferenceValue = infoDataPropertyContents; | |
changed = true; | |
string path = AssetDatabase.GetAssetPath(item); | |
if (!paths.Contains(path)) | |
{ | |
paths.Add(path); | |
} | |
} | |
} | |
while (iterator.Next(true)); | |
if (changed) | |
{ | |
itemSerializedObject.ApplyModifiedProperties(); | |
builder.AppendManyLine("Apply Changes: ", itemSerializedObject.targetObject.name); | |
} | |
else | |
{ | |
builder.AppendManyLine("FAILURE: Cannot find: ", typeof(TItemInformationData).Name, " on ", item.name); | |
} | |
} | |
if (paths.Count > 0) | |
{ | |
for (int i = 0; i < paths.Count; i++) | |
{ | |
AssetDatabase.ImportAsset(paths[i]); | |
} | |
AssetDatabase.Refresh(); | |
} | |
Debug.Log(builder.ToString()); | |
} | |
private void DoFixNames() | |
{ | |
var builder = new StringBuilder(); | |
bool reimportNeeded = false; | |
var items = AssetDatabase.FindAssets("t:InventoryItemData") | |
.Select(AssetDatabase.GUIDToAssetPath) | |
.Distinct() | |
.SelectMany(AssetDatabase.LoadAllAssetsAtPath) | |
.Select(o => o as ItemData) | |
.Where(d => d != null); | |
var infoDataArraySerializedProperty = serializedObject.FindProperty("_infoData"); | |
for (int i = 0; i < infoDataArraySerializedProperty.arraySize; i++) | |
{ | |
builder.AppendManyLine("Checking[", i, "]"); | |
var infoSerialializedProperty = infoDataArraySerializedProperty.GetArrayElementAtIndex(i); | |
if (infoSerialializedProperty == null) | |
{ | |
continue; | |
} | |
var targetObject = infoSerialializedProperty.objectReferenceValue; | |
if (targetObject == null) | |
{ | |
continue; | |
} | |
var dataSerializedObject = new SerializedObject(infoSerialializedProperty.objectReferenceValue); | |
var serializedProperty = dataSerializedObject.FindProperty("_Uid"); | |
if (serializedProperty == null) | |
{ | |
continue; | |
} | |
string uniqueID = serializedProperty.stringValue; | |
if (string.IsNullOrEmpty(uniqueID)) | |
{ | |
continue; | |
} | |
var itemData = items.FirstOrDefault(d => d.Uid == uniqueID); | |
if (itemData != null) | |
{ | |
builder.AppendManyLine("Changing ", targetObject.name, " to ", itemData.name); | |
targetObject.name = itemData.name; | |
reimportNeeded = true; | |
} | |
else | |
{ | |
} | |
} | |
if (reimportNeeded) | |
{ | |
AssetDatabase.Refresh(); | |
AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(target)); | |
} | |
Debug.Log(builder.ToString()); | |
} | |
private void MakeMeMaster() | |
{ | |
var builder = new StringBuilder(); | |
try | |
{ | |
builder.Append("ADOPTING " + target.name).AppendLine(); | |
var assets = AssetDatabase.FindAssets("t:" + typeof(TItemInformationData).Name) | |
.Select(AssetDatabase.GUIDToAssetPath) | |
.SelectMany(AssetDatabase.LoadAllAssetsAtPath) | |
.Where(a => a is TItemInformationData) | |
.Where(a => AssetDatabase.LoadMainAssetAtPath(AssetDatabase.GetAssetPath(a)) != target); | |
foreach (var asset in assets.Where(a => !AssetDatabase.IsMainAsset(a))) | |
{ | |
builder.Append("Removing : ").Append(asset.name).AppendLine(); | |
try | |
{ | |
AssetDatabase.RemoveObjectFromAsset(asset); | |
} | |
catch | |
{ | |
builder.Append("ERROR REMOVING : ").Append(asset.name).AppendLine(); | |
} | |
try | |
{ | |
AssetDatabase.AddObjectToAsset(asset, target); | |
} | |
catch | |
{ | |
builder.Append("ERROR ADDING : ").Append(asset.name).AppendLine(); | |
} | |
EditorUtility.SetDirty(asset); | |
} | |
foreach (var asset in assets.Where(a => AssetDatabase.IsMainAsset(a))) | |
{ | |
builder.Append("Adding : ").Append(asset.name).AppendLine(); | |
try | |
{ | |
AssetDatabase.AddObjectToAsset(asset, target); | |
} | |
catch | |
{ | |
builder.Append("ERROR ADDING : ").Append(asset.name).AppendLine(); | |
} | |
} | |
EditorUtility.SetDirty(target); | |
AssetDatabase.SaveAssets(); | |
} | |
finally | |
{ | |
Debug.Log(builder); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using ItalicPig.PaleoPines.Loading; | |
using UnityEngine; | |
using UnityEngine.Serialization; | |
/* | |
* Copyright © 2020, Italic Pig, All Rights Reserved | |
* | |
* Author: Harry Evans | |
* Date: 26/02/2020 | |
*/ | |
namespace ItalicPig.PaleoPines.Inventories | |
{ | |
/// <summary> | |
/// Abstract superclass for additional item information data to be associated with individual ItemData. | |
/// </summary> | |
public abstract class AdditionalItemInformationData : ScriptableObject, ILoadable<AdditionalItemInformationData> | |
{ | |
/// <summary> | |
/// Unique ID of the ItemData this Additional Data is associated with. | |
/// </summary> | |
[SerializeField, FormerlySerializedAs("_uniqueID"), ItemID(updateTargetItem: true)] | |
private string _Uid = string.Empty; | |
/// <summary> | |
/// Unique ID of the ItemData this Additional Data is associated with. | |
/// </summary> | |
public string UniqueID => _Uid; | |
public virtual int Priority => 100; | |
public virtual void Load() { } | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Linq; | |
using System.Reflection; | |
using ItalicPig.PaleoPines.Inventories; | |
using UnityEditor; | |
using UnityEngine; | |
using Object = UnityEngine.Object; | |
namespace ItalicPig.PaleoPines.Editor.Inventory | |
{ | |
[CustomEditor(typeof(AdditionalItemInformationData), true), CanEditMultipleObjects] | |
public class AdditionalItemInformationDataEditor : UnityEditor.Editor | |
{ | |
public static int BackInstanceID = 0; | |
private string objectName = string.Empty; | |
private GUIContent[] otherObjectContent = null; | |
private bool otherNamesSet = false; | |
protected virtual void OnEnable() | |
{ | |
otherNamesSet = false; | |
objectName = target.name; | |
} | |
protected virtual void OnDisable() | |
{ | |
BackInstanceID = 0; | |
} | |
public override void OnInspectorGUI() | |
{ | |
EditorGUI.BeginChangeCheck(); | |
Object obj = EditorUtility.InstanceIDToObject(BackInstanceID); | |
if (obj != null) | |
{ | |
DrawBackButton(obj.name, () => obj); | |
} | |
else if (!AssetDatabase.IsMainAsset(this)) | |
{ | |
string path = AssetDatabase.GetAssetPath(target); | |
DrawBackButton(Path.GetFileNameWithoutExtension(path), () => AssetDatabase.LoadMainAssetAtPath(path)); | |
} | |
DrawInspector(); | |
if (EditorGUI.EndChangeCheck()) | |
{ | |
serializedObject.ApplyModifiedProperties(); | |
} | |
} | |
private void DrawBackButton(string label, Func<Object> getObj) | |
{ | |
var buttonContent = new GUIContent(ObjectNames.NicifyVariableName(label), EditorGUIUtility.FindTexture("tab_prev")); | |
var buttonStyle = new GUIStyle("IN BigTitle") | |
{ | |
alignment = TextAnchor.MiddleLeft, | |
fontStyle = FontStyle.Bold | |
}; | |
buttonStyle.padding = new RectOffset(buttonStyle.padding.left + 5, buttonStyle.padding.right, buttonStyle.padding.top, buttonStyle.padding.bottom); | |
Vector2 size = buttonStyle.CalcSize(buttonContent); | |
float h = size.y * 1.25f; | |
if (GUI.Button(new Rect(0, -1, Screen.width, h), buttonContent, buttonStyle)) | |
{ | |
Selection.objects = new Object[] { getObj() }; | |
} | |
GUILayout.Space(h + 5f); | |
} | |
protected virtual void DrawInspector() | |
{ | |
if (!serializedObject.isEditingMultipleObjects) | |
{ | |
const string nameField = "NameField"; | |
GUI.SetNextControlName(nameField); | |
objectName = EditorGUILayout.TextField("Asset Name", objectName); | |
if (objectName != target.name && GUI.GetNameOfFocusedControl() != nameField) | |
{ | |
target.name = objectName; | |
AssetDatabase.Refresh(); | |
AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(target)); | |
} | |
} | |
using (var UniqueIDProperty = serializedObject.FindProperty("_Uid")) | |
{ | |
string OldVal = UniqueIDProperty.stringValue; | |
EditorGUILayout.PropertyField(UniqueIDProperty); | |
if (!otherNamesSet || OldVal != UniqueIDProperty.stringValue) | |
{ | |
otherNamesSet = true; | |
var TargetType = target.GetType(); | |
otherObjectContent = ItemDatabase.Items.Values.Where(item => | |
{ | |
if (item.Uid == UniqueIDProperty.stringValue) | |
{ | |
return false; | |
} | |
var ItemType = item.GetType(); | |
var Properties = ItemType.GetProperties(BindingFlags.Public | BindingFlags.Instance); | |
foreach (var propertyInfo in Properties) | |
{ | |
if (propertyInfo.PropertyType == TargetType) | |
{ | |
var value = propertyInfo.GetValue(item) as Object; | |
return target == value; | |
} | |
} | |
return false; | |
}) | |
.Select(i => new GUIContent(ItemName.GetWithQuality(i), i.Icon.texture)).ToArray(); | |
} | |
if (otherObjectContent != null && otherObjectContent.Length > 0) | |
{ | |
using (new EditorGUILayout.HorizontalScope()) | |
{ | |
EditorGUILayout.PrefixLabel("Also attached to"); | |
GUILayout.Space(3); | |
using (new EditorGUILayout.VerticalScope()) | |
{ | |
for (int i = 0; i < otherObjectContent.Length; i++) | |
{ | |
GUILayout.Label(otherObjectContent[i], GUILayout.Height(EditorGUIUtility.singleLineHeight)); | |
} | |
} | |
} | |
} | |
EditorGUILayout.Space(); | |
EditorHelper.GuiLine(); | |
EditorGUILayout.Space(); | |
} | |
DrawProperties(); | |
} | |
protected virtual void DrawProperties() | |
{ | |
DrawPropertiesExcluding(serializedObject, GetExcludedProperties().ToArray()); | |
} | |
protected virtual IEnumerable<string> GetExcludedProperties() | |
{ | |
yield return "m_Script"; | |
yield return "_Uid"; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
namespace ItalicPig.PaleoPines.Inventories | |
{ | |
public enum CropType | |
{ | |
Ground, | |
Tree, | |
Bush | |
} | |
[CreateAssetMenu(menuName = MenuPrefix + "Garden Inventory Information Data", fileName = "GardenInformationData")] | |
public class GardenInventoryInformationData : AdditionalInventoryInformationData<GardenItemInformationData> | |
{ | |
[SerializeField] | |
private GardenGlobalData _GardenGlobalData; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Globalization; | |
using System.IO; | |
using System.Linq; | |
using ItalicPig.PaleoPines.Inventories; | |
using UnityEditor; | |
using UnityEngine; | |
namespace ItalicPig.PaleoPines.Editor.Inventory | |
{ | |
[CustomEditor(typeof(GardenInventoryInformationData))] | |
public class GardenInventoryInformationDataEditor | |
: AdditionalInventoryInformationDataEditor<GardenItemInformationData> | |
{ | |
private const float ONE_HUNDRED_PERCENT = 100f; | |
private List<PlantStageData> existingStages = null; | |
protected override void DrawRemainingProperties() | |
{ | |
DrawPropertiesExcluding(serializedObject, "m_Script", "_infoData", "_GardenGlobalData"); | |
using (new EditorGUILayout.HorizontalScope()) | |
{ | |
using (var gardenGlobalDataProperty = serializedObject.FindProperty("_GardenGlobalData")) | |
{ | |
EditorGUI.BeginChangeCheck(); | |
gardenGlobalDataProperty.objectReferenceValue = EditorGUILayout.ObjectField(gardenGlobalDataProperty.objectReferenceValue, | |
typeof(GardenGlobalData), | |
false); | |
if (gardenGlobalDataProperty.objectReferenceValue == null) | |
{ | |
if (GUILayout.Button("Create Global Data")) | |
{ | |
string oldPath = AssetDatabase.GetAssetPath(target); | |
string newPath = oldPath.Substring(0, oldPath.Length - Path.GetFileName(oldPath).Length); | |
newPath = Path.Combine(newPath, "GlobalGardenData.asset"); | |
var instance = ScriptableObject.CreateInstance<GardenGlobalData>(); | |
AssetDatabase.CreateAsset(instance, newPath); | |
gardenGlobalDataProperty.objectReferenceValue = AssetDatabase.LoadAssetAtPath<GardenGlobalData>(newPath); | |
} | |
} | |
if (EditorGUI.EndChangeCheck()) | |
{ | |
serializedObject.ApplyModifiedProperties(); | |
} | |
} | |
} | |
} | |
protected override void OnCSVImported(string[][] output) | |
{ | |
existingStages = AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GetAssetPath(target)) | |
.Select(a => a as PlantStageData) | |
.Where(s => s != null) | |
.Distinct() | |
.ToList(); | |
base.OnCSVImported(output); | |
for (int i = existingStages.Count - 1; i >= 0; i--) | |
{ | |
DestroyImmediate(existingStages[i], true); | |
} | |
existingStages = null; | |
AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(target)); | |
AssetDatabase.Refresh(); | |
} | |
protected override void ProcessSubtable(string uniqueID, SerializedObject serializedObject, SerializedProperty property, string[][] subtable, string[] headers) | |
{ | |
if (property == null) | |
{ | |
return; | |
} | |
if (property.name == "_Stages") | |
{ | |
ProcessStages(uniqueID, serializedObject, property, subtable, headers); | |
} | |
} | |
protected void ProcessItemQualities(string uniqueID, SerializedObject serializedObject, SerializedProperty property, string[][] subtable, string[] headers) | |
{ | |
Debug.Log(uniqueID | |
+ "\n" + serializedObject.targetObject.name | |
+ "\n" + property.name | |
+ "\n" + string.Join("\n", subtable.Select(s => string.Join(", ", s)).ToArray()) | |
+ "\n" + string.Join(", ", headers) | |
); | |
} | |
protected void ProcessStages(string uniqueID, SerializedObject serializedObject, SerializedProperty property, string[][] subtable, string[] headers) | |
{ | |
if (!property.isArray) | |
{ | |
return; | |
} | |
try | |
{ | |
property.arraySize = 0; | |
int c, r; | |
var lists = new List<List<string>>(); | |
for (r = 0; r < subtable.Length; r++) | |
{ | |
string[] row = subtable[r]; | |
for (c = 0; c < row.Length; c++) | |
{ | |
if (c >= lists.Count) | |
{ | |
lists.Add(new List<string>()); | |
} | |
if (lists[c] == null) | |
{ | |
lists[c] = new List<string>(); | |
} | |
lists[c].Add(row[c]); | |
} | |
} | |
int index = 0; | |
var allInfo = lists.Skip(1).Select((l, i) => ( | |
Stage: l[0], | |
Length: l[1], | |
WiltingChance: l[2], | |
InTimeline: l[3], | |
WithersMature: l[4], | |
ChanceOfWeeds: l[5], | |
NumberOfHarvests: l[6], | |
StageAfterHarvest: l[7], | |
HarvestMinimum: l[8], | |
HarvestMaximum: l[9], | |
CropBumper: l[10], | |
SeedBumper: l[11], | |
QualityBase: l[12], | |
QualitySoilBoost: l[13], | |
QualitySeasonBoost: l[14], | |
QualityMusicBoost: l[15], | |
BumperWateringStreak: l[16], | |
BumperMusicBoost: l[17], | |
BumperSoilBoost: l[18], | |
SeasonBumperBoost: l[19] | |
)); | |
string family = serializedObject.FindProperty("_Family").stringValue; | |
bool isCrop = false, isTree = false, isBush = false; | |
if (family.ToLower().Contains("tree")) | |
{ | |
isTree = true; | |
} | |
else if (family.ToLower().Contains("bush")) | |
{ | |
isBush = true; | |
} | |
else | |
{ | |
int cropCount = allInfo.Count(i => ConvertCropGrowthStage(i.Stage).IsCrop()); | |
int treeCount = allInfo.Count(i => ConvertTreeGrowthStage(i.Stage).IsTree()); | |
int bushCount = allInfo.Count(i => ConvertBushGrowthStage(i.Stage).IsBush()); | |
isCrop = cropCount > treeCount && cropCount > bushCount; | |
isTree = treeCount > bushCount && treeCount > cropCount; | |
isBush = bushCount > treeCount && bushCount > cropCount; | |
} | |
foreach (var info in allInfo) | |
{ | |
PlantGrowthStage stage = | |
isCrop ? ConvertCropGrowthStage(info.Stage) : | |
isTree ? ConvertTreeGrowthStage(info.Stage) : | |
isBush ? ConvertBushGrowthStage(info.Stage) : | |
PlantGrowthStage.none; | |
if (stage == PlantGrowthStage.none || stage == PlantGrowthStage.count) | |
{ | |
continue; | |
} | |
int i = index++; | |
PlantStageData stageData = null; | |
int numberOfHarvests = ConvertInt(info.NumberOfHarvests, 0); | |
int harvestMin = ConvertInt(info.HarvestMinimum, 0); | |
int harvestMax = ConvertInt(info.HarvestMaximum, 0); | |
Type typeOfStage = GetTypeOfStage(stage, harvestMin, harvestMax); | |
if (existingStages.Any()) | |
{ | |
stageData = existingStages | |
.FirstOrDefault(delegate (PlantStageData plant) | |
{ | |
using (var existingStageObject = new SerializedObject(plant)) | |
{ | |
using (SerializedProperty stageProperty = existingStageObject.FindProperty("stage")) | |
{ | |
return existingStageObject.FindProperty("uniqueID").stringValue == uniqueID | |
&& stageProperty.enumNames[stageProperty.enumValueIndex] == stage.ToString() | |
&& plant.GetType() == typeOfStage; | |
} | |
} | |
}); | |
existingStages.Remove(stageData); | |
} | |
if (stageData == null) | |
{ | |
stageData = (PlantStageData)CreateInstance(typeOfStage); | |
AssetDatabase.AddObjectToAsset(stageData, target); | |
serializedObject.ApplyModifiedProperties(); | |
} | |
stageData.name = property.serializedObject.targetObject.name + " (" + i + ": " + stage + ")"; | |
property.InsertArrayElementAtIndex(i); | |
property.GetArrayElementAtIndex(i).objectReferenceValue = stageData; | |
var stageObject = new SerializedObject(stageData); | |
stageObject.FindProperty("uniqueID").stringValue = uniqueID; | |
stageObject.FindProperty("index").intValue = i; | |
ApplyGrowthStage(stageObject.FindProperty("stage"), stage); | |
if (stageData is GrowingStageData) | |
{ | |
stageObject.FindProperty("maturesOld").boolValue = ConvertBool(info.WithersMature); | |
stageObject.FindProperty("stageLength").intValue = ConvertInt(info.Length); | |
ConvertWiltingData(stageObject.FindProperty("wiltingInfo"), info.WiltingChance); | |
stageObject.FindProperty("enterableViaTimeline").boolValue = ConvertBool(info.InTimeline); | |
} | |
if (stageData is HarvestStageData) | |
{ | |
stageObject.FindProperty("numberOfHarvest").intValue = numberOfHarvests; | |
SerializedProperty stageToGoToOnHarvestProperty = stageObject.FindProperty("stageToGoToOnHarvest"); | |
if (numberOfHarvests <= 1) | |
{ | |
ApplyGrowthStage(stageToGoToOnHarvestProperty, PlantGrowthStage.none); | |
} | |
else if (isCrop) | |
{ | |
ApplyGrowthStage(stageToGoToOnHarvestProperty, ConvertCropGrowthStage(info.StageAfterHarvest, PlantGrowthStage.CROP_Mature)); | |
} | |
else if (isTree) | |
{ | |
ApplyGrowthStage(stageToGoToOnHarvestProperty, ConvertTreeGrowthStage(info.StageAfterHarvest, PlantGrowthStage.TREE_Mature)); | |
} | |
else if (isBush) | |
{ | |
ApplyGrowthStage(stageToGoToOnHarvestProperty, ConvertBushGrowthStage(info.StageAfterHarvest, PlantGrowthStage.BUSH_Mature)); | |
} | |
stageObject.FindProperty("infiniteHarvest").boolValue = false;//todo fix | |
stageObject.FindProperty("cropYieldMin").intValue = harvestMin; | |
stageObject.FindProperty("cropYieldMax").intValue = harvestMax; | |
stageObject.FindProperty("cropBumper").intValue = ConvertInt(info.CropBumper); | |
stageObject.FindProperty("seedBumper").intValue = ConvertInt(info.SeedBumper); | |
SerializedProperty bumperProperty = stageObject.FindProperty("bumper"); | |
bumperProperty.FindPropertyRelative("WateringStreakRequiredForBumper").intValue = ConvertInt(info.BumperWateringStreak); | |
bumperProperty.FindPropertyRelative("BumperIsSeed").boolValue = harvestMin <= 1 && harvestMax <= 1; | |
bumperProperty.FindPropertyRelative("HeardMusicBumperIncr").floatValue = ConvertFloat(info.BumperMusicBoost); | |
bumperProperty.FindPropertyRelative("CorrectSoilBumperIncr").floatValue = ConvertFloat(info.BumperSoilBoost); | |
bumperProperty.FindPropertyRelative("SeasonBumperIncr").floatValue = ConvertFloat(info.SeasonBumperBoost); | |
} | |
if (stageData is WitherStageData) | |
{ | |
stageObject.FindProperty("seedYieldMin").intValue = ConvertInt(info.HarvestMinimum); | |
stageObject.FindProperty("seedYieldMax").intValue = ConvertInt(info.HarvestMaximum); | |
} | |
stageObject.ApplyModifiedProperties(); | |
} | |
} | |
catch (System.Exception e) | |
{ | |
Debug.LogError(e); | |
} | |
} | |
protected override string GetItemName(GardenItemInformationData objectReferenceValue) | |
{ | |
using (var serializedObject = new SerializedObject(objectReferenceValue)) | |
using (var serializedProperty = serializedObject.FindProperty("_Season")) | |
{ | |
return $"{ base.GetItemName(objectReferenceValue) } ({serializedProperty.enumDisplayNames[serializedProperty.enumValueIndex]})"; | |
} | |
} | |
private Type GetTypeOfStage(PlantGrowthStage stage, int harvestMin, int harvestMax) | |
{ | |
if (harvestMin > 0 && harvestMax > 0) | |
{ | |
return stage == PlantGrowthStage.BUSH_Ripe_Full || stage == PlantGrowthStage.BUSH_Ripe_Partial ? typeof(BushHarvestStageData) : typeof(HarvestStageData); | |
} | |
else if (stage == PlantGrowthStage.CROP_WitheredYoung) | |
{ | |
return typeof(WitherYoungStageData); | |
} | |
else if (stage == PlantGrowthStage.CROP_WitheredMature) | |
{ | |
return typeof(WitherStageData); | |
} | |
return typeof(GrowingStageData); | |
} | |
private void ApplyGrowthStage(SerializedProperty property, PlantGrowthStage stage) | |
{ | |
string[] enumNames = property.enumNames; | |
for (int i = 0; i < enumNames.Length; i++) | |
{ | |
if (enumNames[i].Trim().Equals(stage.ToString())) | |
{ | |
property.enumValueIndex = i; | |
} | |
} | |
} | |
private PlantGrowthStage ConvertGrowthStage(string value, PlantGrowthStage defaultStage = PlantGrowthStage.none) | |
{ | |
if (string.IsNullOrEmpty(value) || value.Equals("-")) | |
{ | |
return defaultStage; | |
} | |
if (Enum.TryParse(value, true, out PlantGrowthStage enumStage)) | |
{ | |
return enumStage; | |
} | |
return ConvertCropGrowthStage(value); | |
} | |
private PlantGrowthStage ConvertCropGrowthStage(string value, PlantGrowthStage defaultStage = PlantGrowthStage.none) | |
{ | |
if (string.IsNullOrEmpty(value) || value.Equals("-")) | |
{ | |
return defaultStage; | |
} | |
if (Enum.TryParse(value, true, out PlantGrowthStage enumStage)) | |
{ | |
return enumStage; | |
} | |
string trimmed = value.Trim().ToLower().Replace(" ", string.Empty).Replace("_", string.Empty); | |
switch (trimmed) | |
{ | |
case "seed": return PlantGrowthStage.CROP_Seed; | |
case "seedling": return PlantGrowthStage.CROP_Seedling; | |
case "sprout": return PlantGrowthStage.CROP_Sprout; | |
case "flowering": return PlantGrowthStage.CROP_Flowering; | |
case "ripening": return PlantGrowthStage.CROP_Ripening; | |
case "ripe": return PlantGrowthStage.CROP_Ripe; | |
case "mature": return PlantGrowthStage.CROP_Mature; | |
case "witheredyoung": return PlantGrowthStage.CROP_WitheredYoung; | |
case "withered": | |
case "wither": | |
case "witheredmature": return PlantGrowthStage.CROP_WitheredMature; | |
default: | |
if (trimmed.Contains("wither")) | |
{ | |
return trimmed.Contains("young") | |
? PlantGrowthStage.CROP_WitheredYoung | |
: PlantGrowthStage.CROP_WitheredMature; | |
} | |
return PlantGrowthStage.none; | |
} | |
} | |
private PlantGrowthStage ConvertTreeGrowthStage(string value, PlantGrowthStage defaultStage = PlantGrowthStage.none) | |
{ | |
if (string.IsNullOrEmpty(value) || value.Equals("-")) | |
{ | |
return defaultStage; | |
} | |
if (Enum.TryParse(value, true, out PlantGrowthStage enumStage)) | |
{ | |
return enumStage; | |
} | |
string trimmed = value.Trim().ToLower().Replace(" ", string.Empty).Replace("_", string.Empty); | |
switch (trimmed) | |
{ | |
case "sprout": return PlantGrowthStage.TREE_Sprout; | |
case "sapling": return PlantGrowthStage.TREE_Sapling; | |
case "mature": return PlantGrowthStage.TREE_Mature; | |
case "flowering": return PlantGrowthStage.TREE_Flowering; | |
case "ripe": return PlantGrowthStage.TREE_Ripe; | |
default: return PlantGrowthStage.none; | |
} | |
} | |
private PlantGrowthStage ConvertBushGrowthStage(string value, PlantGrowthStage defaultStage = PlantGrowthStage.none) | |
{ | |
if (string.IsNullOrEmpty(value) || value.Equals("-")) | |
{ | |
return defaultStage; | |
} | |
if (Enum.TryParse(value, true, out PlantGrowthStage enumStage)) | |
{ | |
return enumStage; | |
} | |
string trimmed = value.Trim().ToLower().Replace(" ", string.Empty).Replace("_", string.Empty); | |
switch (trimmed) | |
{ | |
case "seeded": return PlantGrowthStage.BUSH_Seeded; | |
case "sprout": return PlantGrowthStage.BUSH_Sprout; | |
case "seeding": return PlantGrowthStage.BUSH_Sapling; | |
case "flowering": return PlantGrowthStage.BUSH_Flowering; | |
case "ripe": return PlantGrowthStage.BUSH_Ripe_Full; | |
case "mature": return PlantGrowthStage.BUSH_Mature; | |
case "sparse": return PlantGrowthStage.BUSH_Sparse; | |
default: return PlantGrowthStage.none; | |
} | |
} | |
private bool ConvertBool(string value, bool onNull = false) | |
{ | |
if (string.IsNullOrEmpty(value)) | |
{ | |
return onNull; | |
} | |
string trimmed = value.Trim().ToLower(); | |
if (trimmed.Equals("y") || trimmed.StartsWith("y") || trimmed.Equals("true")) | |
{ | |
return true; | |
} | |
return false; | |
} | |
private int ConvertInt(string value, int onNull = 0) | |
{ | |
return int.TryParse(value, NumberStyles.Number, CultureInfo.InvariantCulture, out int Result) ? Result : onNull; | |
} | |
private float ConvertFloat(string value, float onNull = 0) | |
{ | |
return float.TryParse(value, NumberStyles.Number, CultureInfo.InvariantCulture, out float Result) ? Result : onNull; | |
} | |
private void ConvertWiltingData(SerializedProperty property, string value) | |
{ | |
if (string.IsNullOrEmpty(value)) | |
{ | |
return; | |
} | |
void Apply(int initial, int cumulative, float weed, bool percent = true) | |
{ | |
property.FindPropertyRelative("initialWiltChance").floatValue = percent ? Mathf.Clamp01(initial / ONE_HUNDRED_PERCENT) : initial; | |
property.FindPropertyRelative("cumulativeChanceIncrease").floatValue = percent ? Mathf.Clamp01(cumulative / ONE_HUNDRED_PERCENT) : cumulative; | |
property.FindPropertyRelative("weedMultiplier").floatValue = Mathf.Max(1, weed); | |
} | |
if (int.TryParse(value, NumberStyles.Number, CultureInfo.InvariantCulture, out int integer)) | |
{ | |
if (integer <= 0) | |
{ | |
Apply(0, 0, 0, false); | |
} | |
else | |
{ | |
Apply(integer, 0, 2f, false); | |
} | |
} | |
else | |
{ | |
const char plus = '+'; | |
const string n = "n"; | |
const string w = "w"; | |
int initial = 5; | |
int cumulative = 0; | |
float weed = 2f; | |
string[] split = value.Split(plus); | |
for (int i = 0; i < split.Length; i++) | |
{ | |
string str = split[i].Trim().ToLower(); | |
bool foundcumulative = false; | |
bool foundweed = false; | |
if (split[i].Contains(n)) | |
{ | |
if (int.TryParse(str.Replace(n, string.Empty).Trim(), NumberStyles.Number, CultureInfo.InvariantCulture, out int nVal)) | |
{ | |
cumulative = nVal; | |
foundcumulative = true; | |
} | |
} | |
if (split[i].Contains(w)) | |
{ | |
if (int.TryParse(str.Replace(w, string.Empty).Trim(), NumberStyles.Number, CultureInfo.InvariantCulture, out int nVal)) | |
{ | |
weed = nVal; | |
foundweed = true; | |
} | |
} | |
if (!foundweed && !foundcumulative) | |
{ | |
if (int.TryParse(str, NumberStyles.Number, CultureInfo.InvariantCulture, out int initVal)) | |
{ | |
initial = initVal; | |
} | |
} | |
} | |
Apply(initial, cumulative, weed); | |
} | |
} | |
[MenuItem("CONTEXT/GardenInventoryInformationData/Fix Assets")] | |
private static void FixSubAssets(MenuCommand command) | |
{ | |
var assets = AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GetAssetPath(command.context)) | |
.Select(o => o as GardenItemInformationData) | |
.Where(o => o != null) | |
.SelectMany(GetStages); | |
foreach (var item in assets) | |
{ | |
Debug.Log(item.name); | |
} | |
} | |
private static IEnumerable<PlantStageData> GetStages(GardenItemInformationData data) | |
{ | |
using (var serializedObject = new SerializedObject(data)) | |
{ | |
using (var stagesProperty = serializedObject.FindProperty("_Stages")) | |
{ | |
for (int i = 0; i < stagesProperty.arraySize; i++) | |
{ | |
using (var element = stagesProperty.GetArrayElementAtIndex(i)) | |
{ | |
var stage = element.objectReferenceValue as PlantStageData; | |
if (stage != null) | |
{ | |
yield return stage; | |
} | |
} | |
} | |
} | |
} | |
} | |
[MenuItem("CONTEXT/GardenInventoryInformationData/Fix Seed Bumper Yields")] | |
private static void FixSeedBumoerYields(MenuCommand command) | |
{ | |
var Assets = AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GetAssetPath(command.context)) | |
.Select(o => o as GardenItemInformationData) | |
.Where(o => o != null) | |
.SelectMany(GetStages) | |
.Select(s => s as HarvestStageData) | |
.Where(s => s != null); | |
foreach (var Stage in Assets) | |
{ | |
using var SerializedObject = new SerializedObject(Stage); | |
#pragma warning disable CS0618 // Type or member is obsolete | |
if (Stage.BumperData.BumperIsSeed) | |
#pragma warning restore CS0618 // Type or member is obsolete | |
{ | |
using var CropBumperProperty = SerializedObject.FindProperty("cropBumper"); | |
using var SeedBumperProperty = SerializedObject.FindProperty("seedBumper"); | |
SeedBumperProperty.intValue = CropBumperProperty.intValue; | |
} | |
else | |
{ | |
using var SeedBumperProperty = SerializedObject.FindProperty("seedBumper"); | |
SeedBumperProperty.intValue = 0; | |
} | |
using (var BumperDataProperty = SerializedObject.FindProperty("_CropBumper")) | |
using (var IsSeedProperty = BumperDataProperty.FindPropertyRelative("BumperIsSeed")) | |
{ | |
IsSeedProperty.boolValue = false; | |
} | |
SerializedObject.ApplyModifiedProperties(); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#if UNITY_EDITOR | |
using UnityEditor; | |
#endif | |
using System; | |
using System.Collections.Generic; | |
using ItalicPig.PaleoPines.Importing; | |
using UnityEngine; | |
using UnityEngine.Serialization; | |
using Season = ItalicPig.PaleoPines.Global.Season; | |
using System.Linq; | |
using System.Text; | |
using ItalicPig.PaleoPines.UI; | |
namespace ItalicPig.PaleoPines.Inventories | |
{ | |
public enum PlantGrowthStage | |
{ | |
none = -1, | |
CROP_Seed, | |
CROP_Seedling, | |
CROP_Sprout, | |
CROP_Flowering, | |
CROP_Ripening, | |
CROP_Ripe, | |
CROP_Mature, | |
CROP_WitheredYoung, | |
CROP_WitheredMature, | |
TREE_Sprout, | |
TREE_Sapling, | |
TREE_Mature, | |
TREE_Flowering, | |
TREE_Picked, | |
TREE_Ripe, | |
BUSH_Seeded, | |
BUSH_Sprout, | |
BUSH_Sapling, | |
BUSH_Mature, | |
BUSH_Flowering, | |
BUSH_Picked, | |
BUSH_Ripe_Partial, | |
BUSH_Ripe_Full, | |
BUSH_Sparse, | |
BOTH_Dead, | |
count | |
} | |
public enum SoilType | |
{ | |
Soft = 0, | |
Firm = 1, | |
Sticky = 2, | |
Plain = 3, | |
Any = 4, | |
Grass = 5, | |
none = -1 | |
} | |
public enum HarvestAnimation | |
{ | |
Low, | |
Medium, | |
High, | |
Shake | |
} | |
public class GardenItemInformationData : AdditionalItemInformationData | |
{ | |
[SerializeField] | |
[ItemID(allowQualityLevels: false)] | |
[FormerlySerializedAs("produceID")] | |
private string _ProduceID = ""; | |
[Space] | |
[SerializeField] | |
[FormerlySerializedAs("cropType")] | |
private CropType _CropType = CropType.Ground; | |
[SerializeField] | |
[AutoComplete("GetFamily")] | |
[FormerlySerializedAs("family")] | |
private string _Family = ""; | |
[SerializeField] | |
[FormerlySerializedAs("season")] | |
private Season _Season = Season.Spring; | |
[SerializeField] | |
private GameRegion _Biome = GameRegion.None; | |
[Header("Soil")] | |
[SerializeField] | |
[FormerlySerializedAs("perfectSoil")] | |
private SoilType _PerfectSoil = SoilType.none; | |
[SerializeField] | |
[FormerlySerializedAs("badSoil")] | |
private SoilType _BadSoil = SoilType.none; | |
[SerializeField] | |
[FormerlySerializedAs("soilDepletion")] | |
private SoilType _SoilDepletion = SoilType.none; | |
[Header("Text")] | |
[SerializeField] | |
private string _GardeningTip; | |
[Header("Stages")] | |
[CSVItem(10, 20)] | |
[SerializeField] | |
[FormerlySerializedAs("stages")] | |
private PlantStageData[] _Stages = Array.Empty<PlantStageData>(); | |
public int SeedYieldMinimum => 0; | |
public int SeedYieldMaximum => 0; | |
public string DefaultProduceID => _ProduceID; | |
public Season Season => _Season; | |
public GameRegion Biome => _Biome; | |
public SoilType PerfectSoil => _PerfectSoil; | |
public SoilType BadSoil => _BadSoil; | |
public SoilType SoilDepletion => _SoilDepletion; | |
public GameObject OnHearMusicParticlesPrefab => null; | |
public string[] GetFamily() | |
{ | |
return new[] { "Rosaceae", "Solanaceae", "Cucurbiteae", "Apiaceae", "Asteraceae", "Brassicaceae", "Amaryllidaceae", "Poaceae", "Polygonaceae", "Amaranthaceae", "Bromeliaceae" }; | |
} | |
public string Name => ItemDatabase.Items[_ProduceID].Uid; | |
public int StageCount => _Stages.Length; | |
public CropType CropType => _CropType; | |
public string Family { get => _Family; set => _Family = value; } | |
public string GetGardeningTip() | |
{ | |
var key = $"item-{_ProduceID}-tip"; | |
if (GameManager.Strings.ContainsKey(key)) | |
{ | |
return GameManager.Strings[key]; | |
} | |
return _GardeningTip; | |
} | |
public IGrowthInfo GetStage(int index) | |
{ | |
if (0 > index || index >= _Stages.Length) | |
{ | |
return null; | |
} | |
return _Stages[index]; | |
} | |
public bool TryGetStage(PlantGrowthStage stage, out IGrowthInfo info) | |
{ | |
for (int i = 0; i < _Stages.Length; i++) | |
{ | |
if (_Stages[i].CurrentStage == stage) | |
{ | |
info = _Stages[i]; | |
return true; | |
} | |
} | |
info = null; | |
return false; | |
} | |
public bool HasCropStages() => _Stages.Any(s => !s.IsTree && !s.IsBush); | |
public bool HasTreeStages() => _Stages.Any(s => s.IsTree); | |
public bool HasBushStages() => _Stages.Any(s => s.IsBush); | |
public bool HasStage<TStageInfo>() where TStageInfo : IGrowthInfo | |
{ | |
for (int i = 0; i < _Stages.Length; i++) | |
{ | |
if (_Stages[i] is TStageInfo) | |
{ | |
return true; | |
} | |
} | |
return false; | |
} | |
public bool HasStage(PlantGrowthStage stage) | |
{ | |
for (int i = 0; i < _Stages.Length; i++) | |
{ | |
if (_Stages[i].CurrentStage == stage) | |
{ | |
return true; | |
} | |
} | |
return false; | |
} | |
public string GetItemByQuality(int quality) => ItemDatabase.Items[_ProduceID].GetUidForQualityLevel(quality); | |
public string GetItemWithHighestQuality() => GetItemByQuality(ItemData.HighestQuality); | |
public string GetItemWithLowestQuality() => _ProduceID; | |
public string GetItemWithMiddleQuality() => GetItemByQuality(Mathf.RoundToInt(ItemData.HighestQuality / 2f)); | |
private void OnValidate() | |
{ | |
for (int i = 0; i < _Stages.Length; i++) | |
{ | |
if (_Stages[i] == null) | |
{ | |
var list = new List<PlantStageData>(); | |
for (int j = 0; j < _Stages.Length; j++) | |
{ | |
if (_Stages[j] != null) | |
{ | |
list.Add(_Stages[j]); | |
} | |
} | |
_Stages = list.ToArray(); | |
break; | |
} | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using ItalicPig.PaleoPines.Global; | |
using ItalicPig.PaleoPines.Inventories; | |
using UnityEditor; | |
using UnityEditorInternal; | |
using UnityEngine; | |
using Object = UnityEngine.Object; | |
namespace ItalicPig.PaleoPines.Editor.Inventory | |
{ | |
[CustomEditor(typeof(GardenItemInformationData))] | |
[CanEditMultipleObjects] | |
public class GardenItemInformationDataEditor : AdditionalItemInformationDataEditor | |
{ | |
protected override void OnEnable() | |
{ | |
base.OnEnable(); | |
if (serializedObject.targetObjects.Length == 1) | |
{ | |
RefreshReorderableList(); | |
} | |
} | |
protected override void OnDisable() | |
{ | |
base.OnDisable(); | |
reorderableList = null; | |
} | |
protected override void DrawProperties() | |
{ | |
base.DrawProperties(); | |
if (reorderableList != null && reorderableList.serializedProperty != null) | |
{ | |
reorderableList.DoLayoutList(); | |
} | |
} | |
protected override IEnumerable<string> GetExcludedProperties() | |
{ | |
foreach (string baseItems in base.GetExcludedProperties()) | |
{ | |
yield return baseItems; | |
} | |
yield return "_Stages"; | |
} | |
#region Private | |
private void RefreshReorderableList() | |
{ | |
SerializedProperty stagesProperty = serializedObject.FindProperty("_Stages"); | |
reorderableList = new ReorderableList(serializedObject, stagesProperty) | |
{ | |
drawHeaderCallback = delegate (Rect rect) | |
{ | |
EditorGUI.LabelField(rect, $"Stages \t{UI.Plantdex.CalculateDaysToMature((GardenItemInformationData)target)}"); | |
}, | |
drawElementCallback = DrawElementCallback, | |
onReorderCallback = OnReorderCallback, | |
onAddDropdownCallback = OnAddDropdownCallback, | |
onRemoveCallback = OnRemoveCallback | |
}; | |
} | |
private void DrawElementCallback(Rect rect, int index, bool isActive, bool isFocused) | |
{ | |
var stagesProperty = reorderableList.serializedProperty; | |
using (var elementProperty = stagesProperty.GetArrayElementAtIndex(index)) | |
{ | |
var stageData = elementProperty.objectReferenceValue; | |
if (stageData == null) | |
{ | |
EditorGUI.LabelField(rect, "ERROR"); | |
return; | |
} | |
var openContent = new GUIContent("Open"); | |
var openStyle = new GUIStyle(EditorStyles.miniButton); | |
var openSize = openStyle.CalcSize(openContent); | |
var openWidth = openSize.x + 50f; | |
var rWidth = (rect.width - openWidth) / 3f; | |
var r1Rect = new Rect(rect.x, rect.y, rWidth, rect.height); | |
var r2Rect = new Rect(rect.x + rWidth, rect.y, rWidth, rect.height); | |
var r3Rect = new Rect(rect.x + rWidth + rWidth, rect.y, rWidth, rect.height); | |
var lRect = new Rect( | |
rect.x + rect.width - openWidth, | |
rect.y + Mathf.Floor((rect.height - openSize.y) * 0.5f), | |
openWidth, | |
rect.height); | |
using (var stageDataSerializedObject = new SerializedObject(stageData)) | |
{ | |
EditorGUI.LabelField(r1Rect, getName(stageDataSerializedObject)); | |
EditorGUI.LabelField(r2Rect, getType(stageData, out var typeCol), getStyle(typeCol)); | |
EditorGUI.LabelField(r3Rect, getSeason(stageData as IGrowthInfo, out var styleCol), getStyle(styleCol)); | |
} | |
if (GUI.Button(lRect, openContent, openStyle)) | |
{ | |
Selection.objects = new[] { stageData }; | |
} | |
} | |
string getName(SerializedObject stageDataSerializedObject) | |
{ | |
string enumName; | |
using (var property = stageDataSerializedObject.FindProperty("_Stage")) | |
{ | |
enumName = property.enumNames[property.enumValueIndex]; | |
} | |
var split = enumName.Split('_'); | |
var type = split.First(); | |
var stageName = split.Skip(1); | |
return $"{type.ToUpper()}: {Helper.CamelCaseToTitle(string.Join(" ", stageName.ToArray()))}"; | |
} | |
string getSeason(IGrowthInfo growthInfo, out Color color) | |
{ | |
if (growthInfo == null || !growthInfo.OnlyEnterStageDuringSeason) | |
{ | |
color = Color.gray; | |
return "Any Season"; | |
} | |
string season = growthInfo.SeasonAllowedToEnterOn.ToString(); | |
switch (growthInfo.SeasonAllowedToEnterOn) | |
{ | |
case Season.Spring: | |
color = Color.green; | |
break; | |
case Season.Summer: | |
color = Color.yellow; | |
break; | |
case Season.Autumn: | |
color = new Color(1, 0.4f, 0); | |
break; | |
default: | |
color = Color.gray; | |
break; | |
} | |
if (growthInfo.OnlyEnterStageDuringLastWeekOfSeason) | |
{ | |
season = $"Last week of {season}"; | |
} | |
return season; | |
} | |
string getType(object stageData, out Color color) | |
{ | |
if (stageData is WitherYoungStageData || stageData is WitherStageData) | |
{ | |
color = Color.black; | |
return "Wither"; | |
} | |
if (stageData is HarvestStageData) | |
{ | |
color = Color.red; | |
return "Harvest"; | |
} | |
if (stageData is GrowingStageData) | |
{ | |
color = new Color(0, 0.7f, 0.1f); | |
return "Growing"; | |
} | |
if (stageData is SparseStageData) | |
{ | |
color = Color.gray; | |
return "Sparse"; | |
} | |
color = Color.gray; | |
return "n/a"; | |
} | |
GUIStyle getStyle(Color color) | |
{ | |
var style = new GUIStyle(EditorStyles.label); | |
style.ToAllStyleStates(s => s.textColor = color); | |
return style; | |
} | |
} | |
private void OnAddDropdownCallback(Rect buttonRect, ReorderableList list) | |
{ | |
var stagesProperty = reorderableList.serializedProperty; | |
var menu = new GenericMenu(); | |
int j; | |
var values = Enum.GetValues(typeof(PlantGrowthStage)); | |
foreach (PlantGrowthStage value in values) | |
{ | |
if (value == PlantGrowthStage.count || value == PlantGrowthStage.none || value == PlantGrowthStage.BOTH_Dead) | |
{ | |
continue; | |
} | |
string stage = value.ToString(); | |
bool exists = false; | |
for (j = 0; j < stagesProperty.arraySize; j++) | |
{ | |
using (var elementProperty = stagesProperty.GetArrayElementAtIndex(j)) | |
using (var stageDataSerializedObject = new SerializedObject(elementProperty.objectReferenceValue)) | |
using (var stageProperty = stageDataSerializedObject.FindProperty("_Stage")) | |
{ | |
if (stage.Equals(stageProperty.enumNames[stageProperty.enumValueIndex])) | |
{ | |
exists = true; | |
break; | |
} | |
} | |
} | |
var menuPath = string.Join("/", stage.Split('_') | |
.Select(b => char.ToUpper(b[0]) + b.Substring(1).ToLower()) | |
.ToArray()); | |
var menuPathContent = new GUIContent(menuPath); | |
if (exists) | |
{ | |
menu.AddDisabledItem(menuPathContent); | |
} | |
else | |
{ | |
menu.AddItem(menuPathContent, | |
false, | |
OnAdd, | |
value); | |
} | |
} | |
menu.DropDown(buttonRect); | |
} | |
private void OnAdd(object userData) | |
{ | |
var stage = (PlantGrowthStage)userData; | |
var stageStr = stage.ToString(); | |
var stagesProperty = reorderableList.serializedProperty; | |
var indexToAdd = reorderableList.index == -1 ? stagesProperty.arraySize : reorderableList.index + 1; | |
stagesProperty.InsertArrayElementAtIndex(indexToAdd); | |
var newType = GetTypeOfStage(stage); | |
var newObj = ScriptableObject.CreateInstance(newType); | |
AssetDatabase.AddObjectToAsset(newObj, target); | |
newObj.name = serializedObject.targetObject.name + " (" + indexToAdd + ": " + stageStr + ")"; | |
using (var newSerializedObject = new SerializedObject(newObj)) | |
{ | |
using (var uniqueIDProperty = newSerializedObject.FindProperty("_ProduceID")) | |
using (var existingUniqueID = serializedObject.FindProperty("_Uid")) | |
{ | |
uniqueIDProperty.stringValue = existingUniqueID.stringValue; | |
} | |
using (var indexProperty = newSerializedObject.FindProperty("_Index")) | |
{ | |
indexProperty.intValue = indexToAdd; | |
} | |
using (var stageProperty = newSerializedObject.FindProperty("_Stage")) | |
{ | |
stageProperty.SetEnumValue(stage); | |
} | |
if (newObj is GrowingStageData) | |
{ | |
using (var stageLengthProperty = newSerializedObject.FindProperty("stageLength")) | |
{ | |
stageLengthProperty.intValue = stage.IsCrop() ? 1 : 7; | |
} | |
using (var chanceOfWeedsProperty = newSerializedObject.FindProperty("chanceOfWeeds")) | |
{ | |
chanceOfWeedsProperty.floatValue = stage.IsCrop() ? 0.2f : 0f; | |
} | |
using (var chanceOfWeedsProperty = newSerializedObject.FindProperty("chanceOfWeeds")) | |
{ | |
chanceOfWeedsProperty.floatValue = stage.IsCrop() ? 0.2f : 0f; | |
} | |
using (var startScaleProperty = newSerializedObject.FindProperty("startScale")) | |
{ | |
startScaleProperty.floatValue = | |
stage == PlantGrowthStage.TREE_Sprout ? 1f : | |
stage == PlantGrowthStage.TREE_Sapling ? 0.75f : | |
1f; | |
} | |
using (var endScaleProperty = newSerializedObject.FindProperty("endScale")) | |
{ | |
endScaleProperty.floatValue = | |
stage == PlantGrowthStage.TREE_Sprout ? 1.5f : | |
stage == PlantGrowthStage.TREE_Sprout ? 2f : | |
1f; | |
} | |
using (var enterableViaTimelineProperty = newSerializedObject.FindProperty("enterableViaTimeline")) | |
{ | |
enterableViaTimelineProperty.boolValue = stage != PlantGrowthStage.CROP_Mature && stage != PlantGrowthStage.TREE_Mature && stage != PlantGrowthStage.BUSH_Mature && stage != PlantGrowthStage.BUSH_Sparse; | |
} | |
using (var onlyEnterStageDuringSeasonProperty = newSerializedObject.FindProperty("_OnlyEnterStageDuringSeason")) | |
{ | |
onlyEnterStageDuringSeasonProperty.boolValue = stage == PlantGrowthStage.TREE_Ripe || stage == PlantGrowthStage.BUSH_Ripe_Partial || stage == PlantGrowthStage.BUSH_Ripe_Full; | |
} | |
} | |
if (newObj is HarvestStageData) | |
{ | |
using (var infiniteHarvestProperty = newSerializedObject.FindProperty("infiniteHarvest")) | |
{ | |
infiniteHarvestProperty.boolValue = stage == PlantGrowthStage.TREE_Ripe || stage == PlantGrowthStage.BUSH_Ripe_Partial || stage == PlantGrowthStage.BUSH_Ripe_Full; | |
} | |
using (var numberOfHarvestProperty = newSerializedObject.FindProperty("numberOfHarvest")) | |
{ | |
numberOfHarvestProperty.intValue = stage == PlantGrowthStage.TREE_Ripe || stage == PlantGrowthStage.BUSH_Ripe_Partial || stage == PlantGrowthStage.BUSH_Ripe_Full ? 0 : 1; | |
} | |
using (var infiniteHarvestProperty = newSerializedObject.FindProperty("stageToGoToOnHarvest")) | |
{ | |
infiniteHarvestProperty.SetEnumValue(stage == PlantGrowthStage.TREE_Ripe ? PlantGrowthStage.TREE_Mature : stage == PlantGrowthStage.BUSH_Ripe_Partial || stage == PlantGrowthStage.BUSH_Ripe_Full ? PlantGrowthStage.BUSH_Mature : PlantGrowthStage.CROP_Mature); | |
} | |
using (var harvestAnimationProperty = newSerializedObject.FindProperty("harvestAnimation")) | |
{ | |
harvestAnimationProperty.SetEnumValue(stage == PlantGrowthStage.TREE_Ripe ? HarvestAnimation.Shake : HarvestAnimation.Low); | |
} | |
} | |
if (newObj is BushHarvestStageData) | |
{ | |
using (var bushDataProperty = newSerializedObject.FindProperty("_BushData")) | |
{ | |
using (var harvestChanceProperty = bushDataProperty.FindPropertyRelative("HarvestChance")) | |
{ | |
harvestChanceProperty.floatValue = 0.25f; | |
} | |
using (var harvestChanceWithMusicProperty = bushDataProperty.FindPropertyRelative("HarvestChanceWithMusic")) | |
{ | |
harvestChanceWithMusicProperty.floatValue = 0.5f; | |
} | |
} | |
} | |
newSerializedObject.ApplyModifiedProperties(); | |
} | |
using (var newProperty = stagesProperty.GetArrayElementAtIndex(indexToAdd)) | |
{ | |
newProperty.objectReferenceValue = newObj; | |
} | |
ResyncIndices(stagesProperty); | |
reorderableList.index = indexToAdd; | |
serializedObject.ApplyModifiedProperties(); | |
AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(target)); | |
AssetDatabase.Refresh(); | |
} | |
private void OnRemoveCallback(ReorderableList list) | |
{ | |
//ReorderableList.defaultBehaviours.DoRemoveButton(list); | |
if (0 > list.index || list.index >= list.serializedProperty.arraySize) | |
{ | |
return; | |
} | |
list.serializedProperty.DeleteArrayElementAtIndex(list.index); | |
list.serializedProperty.serializedObject.ApplyModifiedProperties(); | |
DeleteUnusedAssets(); | |
RefreshReorderableList(); | |
Repaint(); | |
} | |
private void OnReorderCallback(ReorderableList list) | |
{ | |
ResyncIndices(reorderableList.serializedProperty); | |
} | |
private void DeleteUnusedAssets() | |
{ | |
Object[] loaded = AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GetAssetPath(target)); | |
IEnumerable<Object> existingStages = loaded.Where(a => a is PlantStageData); | |
IEnumerable<PlantStageData> referencedStages = loaded.Where(a => a is GardenItemInformationData).SelectMany(GetStagesFromAsset); | |
if (referencedStages.Any() || | |
EditorUtility.DisplayDialog("Error", "Could not find any referenced stages at all in this asset. Something may have gone wrong!", "Continue", "Cancel")) | |
{ | |
IEnumerable<Object> except = existingStages.Except(referencedStages); | |
if (except.Any()) | |
{ | |
foreach (Object item in except) | |
{ | |
UnityEngine.Object.DestroyImmediate(item, true); | |
} | |
AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(target)); | |
AssetDatabase.Refresh(); | |
Repaint(); | |
} | |
} | |
} | |
private void ResyncIndices(SerializedProperty stagesProperty) | |
{ | |
bool reImportNeeded = false; | |
for (int i = 0; i < stagesProperty.arraySize; i++) | |
{ | |
using (var elementProperty = stagesProperty.GetArrayElementAtIndex(i)) | |
{ | |
Object stageData = elementProperty.objectReferenceValue; | |
using (var stageDataSerializedObject = new SerializedObject(stageData)) | |
{ | |
using (var stageProperty = stageDataSerializedObject.FindProperty("_Index")) | |
{ | |
if (stageProperty.intValue != i) | |
{ | |
stageProperty.intValue = i; | |
stageDataSerializedObject.ApplyModifiedProperties(); | |
} | |
using (var stageEnumProperty = stageDataSerializedObject.FindProperty("_Stage")) | |
{ | |
string newName = serializedObject.targetObject.name + " (" + stageProperty.intValue + ": " + stageEnumProperty.GetEnumValue<PlantGrowthStage>().ToString() + ")"; | |
if (!stageData.name.Equals(newName)) | |
{ | |
stageData.name = newName; | |
reImportNeeded = true; | |
} | |
} | |
} | |
} | |
} | |
} | |
if (reImportNeeded) | |
{ | |
AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(target)); | |
AssetDatabase.Refresh(); | |
} | |
} | |
private Type GetTypeOfStage(PlantGrowthStage stage) | |
{ | |
switch (stage) | |
{ | |
case PlantGrowthStage.CROP_Ripe: | |
case PlantGrowthStage.TREE_Ripe: | |
return typeof(HarvestStageData); | |
case PlantGrowthStage.BUSH_Ripe_Partial: | |
case PlantGrowthStage.BUSH_Ripe_Full: | |
return typeof(BushHarvestStageData); | |
case PlantGrowthStage.BUSH_Sparse: | |
return typeof(SparseStageData); | |
case PlantGrowthStage.CROP_WitheredYoung: | |
return typeof(WitherYoungStageData); | |
case PlantGrowthStage.CROP_WitheredMature: | |
return typeof(WitherStageData); | |
} | |
return typeof(GrowingStageData); | |
} | |
private IEnumerable<PlantStageData> GetStagesFromAsset(Object asset) | |
{ | |
using (var assetSerializedObject = new SerializedObject(asset)) | |
{ | |
using (var stagesSerializedProperty = assetSerializedObject.FindProperty("_Stages")) | |
{ | |
if (stagesSerializedProperty != null) | |
{ | |
for (int i = 0; i < stagesSerializedProperty.arraySize; i++) | |
{ | |
using (var elementSerializedProperty = stagesSerializedProperty.GetArrayElementAtIndex(i)) | |
{ | |
var plantStageData = elementSerializedProperty.objectReferenceValue as PlantStageData; | |
if (plantStageData != null) | |
{ | |
yield return plantStageData; | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
private ReorderableList reorderableList = null; | |
#endregion | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using ItalicPig.PaleoPines.Global; | |
using UnityEngine; | |
using UnityEngine.Serialization; | |
namespace ItalicPig.PaleoPines.Inventories | |
{ | |
public class GrowingStageData : PlantStageData, IGrowableGrowthInfo | |
{ | |
public bool MaturesOld => maturesOld; | |
public int StageLength => lengthAsSeasons ? Mathf.RoundToInt(CalendarData.DaysPerSeason * seasonLength) : stageLength; | |
public float ChanceOfWeeds => chanceOfWeeds; | |
public WiltingData WiltingInfo => wiltingInfo; | |
public BoostData BoostInfo => boostInfo; | |
public override bool IsEnterableViaTimeline => enterableViaTimeline; | |
public float StartScale => startScale; | |
public float EndScale => endScale; | |
public override bool OnlyEnterStageDuringSeason => _OnlyEnterStageDuringSeason; | |
public override Season SeasonAllowedToEnterOn => _SeasonAllowedToEnterOn; | |
public override bool OnlyEnterStageDuringLastWeekOfSeason => _LastWeekOfSeason; | |
public override bool GoToAnotherStageIfOutOfSeason => _GoToAnotherStage; | |
public override PlantGrowthStage StageToGoAfterSeason => _GoToAnotherStage ? _StageToGoAfterSeason : PlantGrowthStage.none; | |
public override bool TryNextStageIfOutOfSeason => _TryNextStageIfOutOfSeason; | |
public override bool NeedsWatering | |
{ | |
get | |
{ | |
switch (CurrentStage) | |
{ | |
case PlantGrowthStage.none: | |
case PlantGrowthStage.CROP_Seed: | |
case PlantGrowthStage.TREE_Sprout: | |
case PlantGrowthStage.TREE_Sapling: | |
case PlantGrowthStage.TREE_Mature: | |
case PlantGrowthStage.TREE_Picked: | |
case PlantGrowthStage.TREE_Flowering: | |
case PlantGrowthStage.TREE_Ripe: | |
case PlantGrowthStage.BUSH_Seeded: | |
case PlantGrowthStage.BUSH_Sprout: | |
case PlantGrowthStage.BUSH_Sapling: | |
case PlantGrowthStage.BUSH_Flowering: | |
case PlantGrowthStage.BUSH_Ripe_Partial: | |
case PlantGrowthStage.BUSH_Ripe_Full: | |
case PlantGrowthStage.BUSH_Mature: | |
case PlantGrowthStage.BUSH_Sparse: | |
case PlantGrowthStage.BOTH_Dead: | |
case PlantGrowthStage.count: | |
return false; | |
default: | |
return WiltingInfo.InitialWiltChance > 0 || WiltingInfo.CumulativeChanceIncrease > 0; | |
} | |
} | |
} | |
#region Serailized Variables | |
[SerializeField] | |
[MinMaxPair("endScale")] | |
private float startScale = 1f; | |
[SerializeField] | |
[MinMaxPair("startScale", "Start", "End", 0, 2, "Scale over Lifetime")] | |
private float endScale = 1f; | |
[Header("Growing Info")] | |
[SerializeField] | |
private bool maturesOld = false; | |
[SerializeField] | |
private bool lengthAsSeasons = false; | |
[SerializeField, Toggle("lengthAsSeasons", invert = true)] | |
private int stageLength = 1; | |
[SerializeField, Toggle("lengthAsSeasons", invert = false)] | |
private float seasonLength = 0.5f; | |
[SerializeField, Range(0f, 1f)] | |
private float chanceOfWeeds = 0.2f; | |
[SerializeField] | |
private WiltingData wiltingInfo; | |
[SerializeField] | |
private BoostData boostInfo = BoostData.Default; | |
[Header("Staging info")] | |
[SerializeField] | |
private bool enterableViaTimeline = true; | |
[SerializeField] | |
private bool _OnlyEnterStageDuringSeason; | |
[SerializeField, Toggle("_OnlyEnterStageDuringSeason")] | |
private Season _SeasonAllowedToEnterOn; | |
[SerializeField, Toggle("_OnlyEnterStageDuringSeason")] | |
private bool _LastWeekOfSeason; | |
[SerializeField, Toggle("_OnlyEnterStageDuringSeason")] | |
private bool _GoToAnotherStage; | |
[SerializeField, Toggle("_GoToAnotherStage")] | |
[FormerlySerializedAs("_StageToGoWhenOutOfSeason")] | |
private PlantGrowthStage _StageToGoAfterSeason = PlantGrowthStage.none; | |
[SerializeField, Toggle("_OnlyEnterStageDuringSeason")] | |
[FormerlySerializedAs("_StageToGoWhenOutOfSeason")] | |
private bool _TryNextStageIfOutOfSeason; | |
#endregion | |
#region Unity Message | |
private void OnValidate() | |
{ | |
stageLength = Mathf.Max(0, stageLength); | |
seasonLength = Mathf.Max(0, seasonLength); | |
} | |
#endregion | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using UnityEngine.Serialization; | |
namespace ItalicPig.PaleoPines.Inventories | |
{ | |
public class HarvestStageData : GrowingStageData, IHarvestStageGrowthInfo | |
{ | |
[Header("Harvest Info")] | |
[SerializeField, FormerlySerializedAs("harvestAnimation")] | |
private HarvestAnimation _HarvestAnimation = HarvestAnimation.Low; | |
[SerializeField, FormerlySerializedAs("vfxPrefab")] | |
private GameObject _VfxPrefab = null; | |
[SerializeField, FormerlySerializedAs("vfxOffset")] | |
private Vector3 _VfxOffset = Vector3.zero; | |
[Space] | |
[SerializeField, FormerlySerializedAs("numberOfHarvest")] | |
private int _NumberOfReharvests = 1; | |
[SerializeField, FormerlySerializedAs("infiniteHarvest")] | |
private bool _InfiniteHarvest = false; | |
[SerializeField, FormerlySerializedAs("stageToGoToOnHarvest")] | |
private PlantGrowthStage _StageToGoToOnHarvest = PlantGrowthStage.none; | |
[Header("Yield")] | |
[SerializeField, FormerlySerializedAs("cropYieldMin"), MinMaxPair("_CropYieldMax")] | |
private int _CropYieldMin = 1; | |
[SerializeField, FormerlySerializedAs("cropYieldMax"), MinMaxPair("_CropYieldMin", "Min", "Max", 0, 20, "Crop Yield")] | |
private int _CropYieldMax = 1; | |
[SerializeField, FormerlySerializedAs("cropBumper")] | |
private int _CropBumper = 1; | |
[SerializeField, FormerlySerializedAs("seedBumper")] | |
private int _SeedBumper = 1; | |
[Space] | |
[SerializeField, FormerlySerializedAs("bumper"), FormerlySerializedAs("_CropBumper")] | |
private BumperData _BumperData = BumperData.Default; | |
public int NumberOfReharvests => _NumberOfReharvests; | |
public PlantGrowthStage StageToGoToOnHarvest => _StageToGoToOnHarvest; | |
public bool InfiniteHarvest => _InfiniteHarvest; | |
public int CropYieldMinimum => _CropYieldMin; | |
public int CropYieldMaximum => _CropYieldMax; | |
public int BumperCropYieldMinimum => _CropBumper; | |
public int BumperCropYieldMaximum => _CropBumper; | |
public int BumperSeedYieldMinimum => _SeedBumper; | |
public int BumperSeedYieldMaximum => _SeedBumper; | |
public BumperData BumperData => _BumperData; | |
public HarvestAnimation HarvestAnimation => _HarvestAnimation; | |
public GameObject VFXPrefab => _VfxPrefab; | |
public Vector3 VFXOffset => _VfxOffset; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace ItalicPig.PaleoPines.Inventories | |
{ | |
public interface IGrowableGrowthInfo : IGrowthInfo | |
{ | |
bool MaturesOld { get; } | |
int StageLength { get; } | |
float ChanceOfWeeds { get; } | |
WiltingData WiltingInfo { get; } | |
BoostData BoostInfo { get; } | |
float StartScale { get; } | |
float EndScale { get; } | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using ItalicPig.PaleoPines.Global; | |
using UnityEngine; | |
namespace ItalicPig.PaleoPines.Inventories | |
{ | |
public interface IGrowthInfo | |
{ | |
int Index { get; } | |
PlantGrowthStage CurrentStage { get; } | |
GameObject Prefab { get; } | |
bool IsTree { get; } | |
bool IsBush { get; } | |
bool NeedsWatering { get; } | |
bool CanBeFertilized { get; } | |
bool IsEnterableViaTimeline { get; } | |
bool OnlyEnterStageDuringSeason { get; } | |
bool OnlyEnterStageDuringLastWeekOfSeason { get; } | |
Season SeasonAllowedToEnterOn { get; } | |
bool GoToAnotherStageIfOutOfSeason { get; } | |
PlantGrowthStage StageToGoAfterSeason { get; } | |
bool TryNextStageIfOutOfSeason { get; } | |
void InitialiseCache(); | |
void DawnEvent(); | |
void ReCacheOrDestroy(GameObject gameObject); | |
GameObject GetPrefab(out bool isInstantiated); | |
bool CanEnterSeason(int gameDay); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
namespace ItalicPig.PaleoPines.Inventories | |
{ | |
public interface IHarvestableStage | |
{ | |
HarvestAnimation HarvestAnimation { get; } | |
GameObject VFXPrefab { get; } | |
Vector3 VFXOffset { get; } | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace ItalicPig.PaleoPines.Inventories | |
{ | |
public interface IHarvestStageGrowthInfo : IGrowableGrowthInfo, IHarvestableStage | |
{ | |
int NumberOfReharvests { get; } | |
PlantGrowthStage StageToGoToOnHarvest { get; } | |
bool InfiniteHarvest { get; } | |
int CropYieldMinimum { get; } | |
int CropYieldMaximum { get; } | |
int BumperCropYieldMinimum { get; } | |
int BumperCropYieldMaximum { get; } | |
int BumperSeedYieldMinimum { get; } | |
int BumperSeedYieldMaximum { get; } | |
BumperData BumperData { get; } | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Globalization; | |
using ItalicPig.PaleoPines.Audio; | |
using ItalicPig.PaleoPines.Global; | |
using UnityEditor; | |
using UnityEngine; | |
namespace ItalicPig.PaleoPines.Inventories | |
{ | |
public class ItemData : ScriptableObject | |
{ | |
public string Uid => _Uid; | |
public FoodItemInformationData FoodInfo => _AdditionalData.FoodInfo; | |
public EdibleItemInformationData EdibleInfo => _AdditionalData.EdibleInfo; | |
public DecorItemInformationData DecorInfo => _AdditionalData.DecorInfo; | |
public GardenItemInformationData GardenInfo => _AdditionalData.GardenInfo; | |
public FertiliserItemInformationData FertiliserInfo => _AdditionalData.FertiliserInfo; | |
public WildCropItemInformationData WildCropInfo => _AdditionalData.WildCropInfo; | |
public string DisplayNameStringKey => $"item-{BaseUid}"; | |
public string DisplayDescriptionStringKey => $"item-{BaseUid}-desc"; | |
public string GetDisplayName(bool noMessageIfNoKey = false) | |
{ | |
#if UNITY_EDITOR | |
if (!Application.isPlaying && !GameManager.Strings.ContainsKey(DisplayNameStringKey)) | |
{ | |
return ObjectNames.NicifyVariableName(BaseUid); | |
} | |
#endif | |
if (noMessageIfNoKey && !GameManager.Strings.ContainsKey(DisplayNameStringKey)) | |
{ | |
return $"*{DisplayNameStringKey}*"; | |
} | |
return GameManager.Strings[DisplayNameStringKey]; | |
} | |
public string GetDisplayDescription() | |
{ | |
return GameManager.Strings[DisplayDescriptionStringKey]; | |
} | |
#region Private | |
#region Private | |
[SerializeField] | |
[Tooltip("Each item must have a unique identifier, e.g. 'shovel' or 'medium-trough'.")] | |
private string _Uid = ""; | |
// Additional data - separate assets which are generated from a spreadsheet | |
[Serializable] | |
private struct AdditionalData | |
{ | |
public FoodItemInformationData FoodInfo; | |
public EdibleItemInformationData EdibleInfo; | |
public DecorItemInformationData DecorInfo; | |
public GardenItemInformationData GardenInfo; | |
public FertiliserItemInformationData FertiliserInfo; | |
public WildCropItemInformationData WildCropInfo; | |
} | |
[Header("Additional Data")] | |
[SerializeField] | |
private AdditionalData _AdditionalData; | |
#endregion | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace ItalicPig.PaleoPines.Inventories | |
{ | |
public interface IWitherStageGrowthInfo : IGrowthInfo, IHarvestableStage | |
{ | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#if UNITY_EDITOR | |
#define USE_EDITOR | |
#endif | |
using System.Collections.Generic; | |
using ItalicPig.PaleoPines.Global; | |
using UnityEngine; | |
using UnityEngine.Serialization; | |
namespace ItalicPig.PaleoPines.Inventories | |
{ | |
[System.Serializable] | |
public abstract class PlantStageData : ScriptableObject, IGrowthInfo | |
{ | |
private const int NUMBER_OF_PREFABS_TO_CACHE = 4; | |
private static Transform cacheParent; | |
[SerializeField, ReadOnly] | |
[FormerlySerializedAs("uniqueID")] | |
private string _ProduceID; | |
[SerializeField, ReadOnly] | |
[FormerlySerializedAs("index")] | |
private int _Index; | |
[Space] | |
[SerializeField] | |
[FormerlySerializedAs("stage")] | |
private PlantGrowthStage _Stage; | |
[SerializeField] | |
private bool _CanBeFertilized; | |
[Header("GameObject")] | |
[SerializeField] | |
[FormerlySerializedAs("prefab")] | |
private GameObject _Prefab; | |
public int Index => _Index; | |
public PlantGrowthStage CurrentStage => _Stage; | |
public bool CanBeFertilized => _CanBeFertilized; | |
public GameObject Prefab => _Prefab; | |
private Stack<GameObject> prefabCache = null; | |
public bool IsTree => CurrentStage.IsTree(); | |
public bool IsBush => CurrentStage.IsBush(); | |
public virtual bool NeedsWatering => false; | |
public virtual bool IsEnterableViaTimeline => true; | |
public virtual bool OnlyEnterStageDuringSeason => false; | |
public virtual Season SeasonAllowedToEnterOn => Season.Spring; | |
public virtual bool OnlyEnterStageDuringLastWeekOfSeason => false; | |
public virtual bool GoToAnotherStageIfOutOfSeason => false; | |
public virtual bool TryNextStageIfOutOfSeason => false; | |
public virtual PlantGrowthStage StageToGoAfterSeason => PlantGrowthStage.none; | |
public void InitialiseCache() | |
{ | |
if (Prefab == null) | |
{ | |
return; | |
} | |
if (cacheParent == null) | |
{ | |
var CacheGameObject = new GameObject("[PLANT MODEL CACHE]"); | |
DontDestroyOnLoad(CacheGameObject); | |
cacheParent = CacheGameObject.transform; | |
} | |
if (prefabCache == null) | |
{ | |
prefabCache = new Stack<GameObject>(NUMBER_OF_PREFABS_TO_CACHE); | |
} | |
TimeMaster.MorningEvent += DawnEvent; | |
} | |
public void DawnEvent() | |
{ | |
if (cacheParent == null) | |
{ | |
return; | |
} | |
int count = prefabCache.Count; | |
for (int i = count; i < NUMBER_OF_PREFABS_TO_CACHE; i++) | |
{ | |
ReCacheOrDestroy(Instantiate(Prefab, cacheParent)); | |
} | |
} | |
public void ReCacheOrDestroy(GameObject gameObject) | |
{ | |
if (gameObject == null) | |
{ | |
return; | |
} | |
if (prefabCache == null || prefabCache.Count >= NUMBER_OF_PREFABS_TO_CACHE) | |
{ | |
Destroy(gameObject); | |
return; | |
} | |
gameObject.SetActive(false); | |
gameObject.transform.SetParent(cacheParent); | |
prefabCache.Push(gameObject); | |
} | |
public GameObject GetPrefab(out bool isInstantiated) | |
{ | |
if (prefabCache != null) | |
{ | |
while (prefabCache.Count > 0) | |
{ | |
GameObject instantiated = prefabCache.Pop(); | |
if (instantiated != null) | |
{ | |
instantiated.SetActive(true); | |
isInstantiated = true; | |
return instantiated; | |
} | |
} | |
} | |
isInstantiated = false; | |
return Prefab; | |
} | |
public virtual bool CanEnterSeason(int gameDay) | |
{ | |
if (!OnlyEnterStageDuringSeason) | |
{ | |
return true; | |
} | |
var currentSeason = CalendarData.GetSeason(gameDay); | |
if (currentSeason != SeasonAllowedToEnterOn) | |
{ | |
return false; | |
} | |
if (OnlyEnterStageDuringLastWeekOfSeason) | |
{ | |
var dayOfWeek = CalendarData.GetDayInSeason(gameDay); | |
var dayOfLastWeek = CalendarData.DaysPerSeason - CalendarData.DaysPerWeek; | |
var inFinalWeek = dayOfWeek >= dayOfLastWeek; | |
if (!inFinalWeek) | |
{ | |
return false; | |
} | |
} | |
return true; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEditor; | |
using UnityEngine; | |
namespace ItalicPig.PaleoPines.Inventories | |
{ | |
[CanEditMultipleObjects] | |
[CustomEditor(typeof(PlantStageData), editorForChildClasses: true)] | |
public class PlantStageDataEditor : UnityEditor.Editor | |
{ | |
private void OnEnable() | |
{ | |
string MyUniqueID; | |
int MyIndex; | |
using (var UniqueIDProperty = serializedObject.FindProperty("_ProduceID")) | |
{ | |
MyUniqueID = UniqueIDProperty.stringValue; | |
} | |
using (var IndexProperty = serializedObject.FindProperty("_Index")) | |
{ | |
MyIndex = IndexProperty.intValue; | |
} | |
var MainAsset = GetAsset(); | |
if (MainAsset != null) | |
{ | |
using var MainSerializedObject = new SerializedObject(MainAsset); | |
using var InfoDataArrayProperty = MainSerializedObject.FindProperty("_infoData"); | |
for (int i = 0; i < InfoDataArrayProperty.arraySize; i++) | |
{ | |
Object Plant; | |
using (var InfoDataProperty = InfoDataArrayProperty.GetArrayElementAtIndex(i)) | |
{ | |
Plant = InfoDataProperty.objectReferenceValue; | |
} | |
using var InfoDataSerializedObject = new SerializedObject(Plant); | |
using (var UniqueIDProperty = InfoDataSerializedObject.FindProperty("_Uid")) | |
{ | |
if (string.CompareOrdinal(UniqueIDProperty.stringValue, MyUniqueID) != 0) | |
{ | |
continue; | |
} | |
} | |
_ParentPlant = Plant; | |
_CentreButtonContent = new GUIContent(Plant.name); | |
using var StagesProperty = InfoDataSerializedObject.FindProperty("_Stages"); | |
if (MyIndex > 0) | |
{ | |
using var PreviousProperty = StagesProperty.GetArrayElementAtIndex(MyIndex - 1); | |
_PreviousStage = PreviousProperty.objectReferenceValue; | |
_LeftButtonContent = new GUIContent($"Previous:\n{_PreviousStage.name}"); | |
} | |
else | |
{ | |
_PreviousStage = null; | |
_LeftButtonContent = GUIContent.none; | |
} | |
if (MyIndex < StagesProperty.arraySize - 1) | |
{ | |
using var NextProperty = StagesProperty.GetArrayElementAtIndex(MyIndex + 1); | |
_NextStage = NextProperty.objectReferenceValue; | |
_RightButtonContent = new GUIContent($"Next:\n{_NextStage.name}"); | |
} | |
else | |
{ | |
_NextStage = null; | |
_RightButtonContent = GUIContent.none; | |
} | |
break; | |
} | |
} | |
} | |
private Object GetAsset() | |
{ | |
var Path = AssetDatabase.GetAssetPath(target); | |
var MainAsset = AssetDatabase.LoadMainAssetAtPath(Path); | |
if (MainAsset is GardenInventoryInformationData) | |
{ | |
return MainAsset; | |
} | |
foreach (var Item in AssetDatabase.LoadAllAssetsAtPath(Path)) | |
{ | |
if (Item is GardenInventoryInformationData) | |
{ | |
return MainAsset; | |
} | |
} | |
return null; | |
} | |
public override void OnInspectorGUI() | |
{ | |
if (_LeftStyle == null || _CentreStyle == null || _RightStyle == null || _LeftTab == null || _RightTab == null) | |
{ | |
_LeftTab = new GUIContent(EditorGUIUtility.FindTexture("tab_prev")); | |
_RightTab = new GUIContent(EditorGUIUtility.FindTexture("tab_next")); | |
var HeaderStyle = new GUIStyle("IN BigTitle") | |
{ | |
fontStyle = FontStyle.Bold | |
}; | |
HeaderStyle.padding = new RectOffset(HeaderStyle.padding.left + 5, HeaderStyle.padding.right, HeaderStyle.padding.top, HeaderStyle.padding.bottom); | |
_LeftStyle = new GUIStyle(HeaderStyle) | |
{ | |
alignment = TextAnchor.MiddleLeft | |
}; | |
_CentreStyle = new GUIStyle(HeaderStyle) | |
{ | |
alignment = TextAnchor.MiddleCenter | |
}; | |
_RightStyle = new GUIStyle(HeaderStyle) | |
{ | |
alignment = TextAnchor.MiddleRight, | |
imagePosition = ImagePosition.ImageAbove | |
}; | |
} | |
EditorGUI.BeginChangeCheck(); | |
float Y = 0; | |
float YSize = Mathf.Max( | |
_LeftButtonContent == null ? 0 : _LeftStyle.CalcSize(_LeftButtonContent).y, | |
_CentreButtonContent == null ? 0 : _CentreStyle.CalcSize(_CentreButtonContent).y, | |
_RightButtonContent == null ? 0 : _RightStyle.CalcSize(_RightButtonContent).y, | |
EditorGUIUtility.singleLineHeight); | |
float TabX = (_LeftStyle.CalcSize(_LeftTab).x + _RightStyle.CalcSize(_RightTab).x) * 0.5f; | |
float Height = YSize * 1.25f; | |
float Width = Screen.width / 3; | |
if (_ParentPlant == null) | |
{ | |
var DeleteContent = new GUIContent("No parent found. Click here to delete"); | |
YSize = Mathf.Max(YSize, _CentreStyle.CalcSize(DeleteContent).y); | |
if (GUI.Button(new Rect(0, 0, Screen.width, YSize), DeleteContent, _CentreStyle)) | |
{ | |
if (EditorUtility.DisplayDialog("Delete", "Are you sure you want to delete this asset?", "Yes", "No")) | |
{ | |
var Path = AssetDatabase.GetAssetPath(target); | |
Selection.objects = new Object[] { AssetDatabase.LoadMainAssetAtPath(Path) }; | |
UnityEngine.Object.DestroyImmediate(target, true); | |
AssetDatabase.ImportAsset(Path); | |
AssetDatabase.Refresh(); | |
return; | |
} | |
} | |
} | |
else | |
{ | |
if (_PreviousStage != null) | |
{ | |
if (GUI.Button(new Rect(0, Y, TabX, Height), _LeftTab, _LeftStyle) || | |
GUI.Button(new Rect(TabX, Y, Width - TabX, Height), _LeftButtonContent, _LeftStyle)) | |
{ | |
Selection.objects = new Object[] { _PreviousStage }; | |
} | |
} | |
else | |
{ | |
GUI.Box(new Rect(0, Y, Width, Height), GUIContent.none, _LeftStyle); | |
} | |
if (GUI.Button(new Rect(Width, Y, Width, Height), _CentreButtonContent, _CentreStyle)) | |
{ | |
Selection.objects = new Object[] { _ParentPlant }; | |
} | |
if (_NextStage != null) | |
{ | |
if (GUI.Button(new Rect(Width + Width, Y, Width - TabX, Height), _RightButtonContent, _RightStyle) || | |
GUI.Button(new Rect(Width + Width + Width - TabX, Y, TabX, Height), _RightTab, _RightStyle)) | |
{ | |
Selection.objects = new Object[] { _NextStage }; | |
} | |
} | |
else | |
{ | |
GUI.Box(new Rect(Width + Width, Y, Width, Height), GUIContent.none, _LeftStyle); | |
} | |
} | |
GUILayout.Space(Height); | |
DrawPropertiesExcluding(serializedObject, "m_Script"); | |
if (EditorGUI.EndChangeCheck()) | |
{ | |
serializedObject.ApplyModifiedProperties(); | |
} | |
} | |
private GUIStyle _LeftStyle; | |
private GUIStyle _CentreStyle; | |
private GUIStyle _RightStyle; | |
private GUIContent _LeftTab; | |
private GUIContent _RightTab; | |
private GUIContent _LeftButtonContent; | |
private GUIContent _CentreButtonContent; | |
private GUIContent _RightButtonContent; | |
private Object _ParentPlant; | |
private Object _PreviousStage; | |
private Object _NextStage; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using UnityEngine.Serialization; | |
namespace ItalicPig.PaleoPines.Inventories | |
{ | |
public class WitherStageData : PlantStageData, IWitherStageGrowthInfo | |
{ | |
#pragma warning disable CS0414 | |
[Header("Harvest")] | |
[SerializeField, MinMaxPair("_SeedYieldMax")] | |
[FormerlySerializedAs("seedYieldMin")] | |
private int _SeedYieldMin = 1; | |
[SerializeField, MinMaxPair("_SeedYieldMin", "Min", "Max", 0, 10, "Seed Yield")] | |
[FormerlySerializedAs("seedYieldMax")] | |
private int _SeedYieldMax = 1; | |
[Space] | |
[SerializeField] | |
[FormerlySerializedAs("harvestAnimation")] | |
private HarvestAnimation _HarvestAnimation = HarvestAnimation.Low; | |
[SerializeField] | |
[FormerlySerializedAs("vfxPrefab")] | |
private GameObject _VfxPrefab = null; | |
[SerializeField] | |
[FormerlySerializedAs("vfxOffset")] | |
private Vector3 _VfxOffset = Vector3.zero; | |
#pragma warning restore CS0414 | |
public HarvestAnimation HarvestAnimation => _HarvestAnimation; | |
public GameObject VFXPrefab => _VfxPrefab; | |
public Vector3 VFXOffset => _VfxOffset; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment