using UnityEngine;
using UnityEditor;
// Sci-Fi Ship Controller. Copyright (c) 2018-2020 SCSM Pty Ltd. All rights reserved.
namespace SciFiShipController
{
[CustomEditor(typeof(BeamModule))]
public class BeamModuleEditor : Editor
{
#region Custom Editor private variables
private BeamModule beamModule;
// Formatting and style variables
//private string txtColourName = "Black";
//private Color defaultTextColour = Color.black;
private string labelText;
private GUIStyle labelFieldRichText;
private GUIStyle helpBoxRichText;
private GUIStyle buttonCompact;
private float defaultEditorLabelWidth = 0f;
private float defaultEditorFieldWidth = 0f;
private bool isDebuggingEnabled = false;
#endregion
#region Static Strings
private readonly static string effectsDespawnWarning = "The Despawn Time of the Effects Object is less than the Max Burst Duration.";
#endregion
#region GUIContent
private readonly static GUIContent headerContent = new GUIContent("Beam Module\n\nThis module enables you to implement beam, ray or laser-type behaviour on the object it is attached to.");
private readonly static GUIContent damageTypeContent = new GUIContent("Damage Type", "The type of damage the beam does when hitting a ship. " +
"The amount of damage dealt to a ship upon collision is dependent on the ship's resistance to this damage type. If the " +
"damage type is set to Default, the ship's damage multipliers are ignored i.e. the damage amount is unchanged.");
private readonly static GUIContent damageRateContent = new GUIContent("Damage Rate", "The amount of damage this beam does, per second, to the ship or object it hits. NOTE: Non-ship objects need a DamageReceiver component.");
private readonly static GUIContent speedContent = new GUIContent("Speed", "The speed the beam travels in metres per second");
private readonly static GUIContent usePoolingContent = new GUIContent("Use Pooling", "Use the Pooling system to manage create, re-use, and destroy beams.");
private readonly static GUIContent minPoolSizeContent = new GUIContent("Min Pool Size", "When using the Pooling system, this is the number of beam objects kept in reserve for spawning and despawning.");
private readonly static GUIContent maxPoolSizeContent = new GUIContent("Max Pool Size", "When using the Pooling system, this is the maximum number of beams permitted in the scene at any one time.");
private readonly static GUIContent beamStartWidthContent = new GUIContent("Beam Width", "The (visual) width of the beam in metres");
private readonly static GUIContent minBurstDurationContent = new GUIContent("Min Burst Duration", "The minimum amount of time, in seconds, the beam must be active");
private readonly static GUIContent maxBurstDurationContent = new GUIContent("Max Burst Duration", "The maximum amount of time, in seconds, the beam can be active in a single burst");
private readonly static GUIContent dischargeDurationContent = new GUIContent("Discharge Duration", "The time (in seconds) it takes a single beam to discharge the beam weapon from full charge");
private readonly static GUIContent effectsObjectContent = new GUIContent("Effects Object", "The particle and/or sound effect prefab that will be instantiated when the beam hits something. This does not fire when the beam is automatically despawned. For beams, this would typically be a looping effect.");
private readonly static GUIContent muzzleFXObjectContent = new GUIContent("Muzzle FX Object", "The particle and/or sound effect prefab that will be instantiated when the beam is fired from a weapon.");
private readonly static GUIContent muzzleFXOffsetContent = new GUIContent("Muzzle FX Offset", "The distance in local space that the muzzle Effects Object should be instantiated from the weapon firing point. Typically only the z-axis will be used.");
private readonly static GUIContent gotoEffectFolderBtnContent = new GUIContent("F", "Find and highlight the sample Effects folder");
#endregion
#region GUIContent - Debug
private readonly static GUIContent debugModeContent = new GUIContent("Debug Mode", "Use this to troubleshoot the data at runtime in the editor.");
private readonly static GUIContent debugSourceShipIdContent = new GUIContent("Source Ship Id", "The ShipId of the ship that fired this beam");
private readonly static GUIContent debugSourceSquadronIdContent = new GUIContent("Source Squadron Id", "The Squadron which the ship belonged to when it fired the beam");
#endregion
#region Serialized Properties
private SerializedProperty usePoolingProp;
private SerializedProperty minPoolSizeProp;
private SerializedProperty maxPoolSizeProp;
private SerializedProperty minBurstDurationProp;
private SerializedProperty maxBurstDurationProp;
private SerializedProperty dischargeDurationProp;
private SerializedProperty effectsObjectProp;
private SerializedProperty muzzleEffectsObjectProp;
#endregion
#region Events
public void OnEnable()
{
beamModule = (BeamModule)target;
defaultEditorLabelWidth = 150f; // EditorGUIUtility.labelWidth;
defaultEditorFieldWidth = EditorGUIUtility.fieldWidth;
#region Find Properties
usePoolingProp = serializedObject.FindProperty("usePooling");
minBurstDurationProp = serializedObject.FindProperty("minBurstDuration");
maxBurstDurationProp = serializedObject.FindProperty("maxBurstDuration");
dischargeDurationProp = serializedObject.FindProperty("dischargeDuration");
effectsObjectProp = serializedObject.FindProperty("effectsObject");
muzzleEffectsObjectProp = serializedObject.FindProperty("muzzleEffectsObject");
#endregion
}
#endregion
#region OnInspectorGUI
// This function overides what is normally seen in the inspector window
// This allows stuff like buttons to be drawn there
public override void OnInspectorGUI()
{
#region Initialise
EditorGUIUtility.labelWidth = defaultEditorLabelWidth;
EditorGUIUtility.fieldWidth = defaultEditorFieldWidth;
#endregion
#region Configure Buttons and Styles
// Set up rich text GUIStyles
helpBoxRichText = new GUIStyle("HelpBox");
helpBoxRichText.richText = true;
labelFieldRichText = new GUIStyle("Label");
labelFieldRichText.richText = true;
buttonCompact = new GUIStyle("Button");
buttonCompact.fontSize = 10;
#endregion
// Read in all the properties
serializedObject.Update();
#region General Settings
GUILayout.BeginVertical("HelpBox");
EditorGUILayout.LabelField("Sci-Fi Ship Controller Version " + ShipControlModule.SSCVersion + " " + ShipControlModule.SSCBetaVersion, labelFieldRichText);
GUILayout.EndVertical();
EditorGUILayout.LabelField(headerContent, helpBoxRichText);
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
EditorGUILayout.PropertyField(serializedObject.FindProperty("speed"), speedContent);
EditorGUILayout.PropertyField(serializedObject.FindProperty("damageType"), damageTypeContent);
EditorGUILayout.PropertyField(serializedObject.FindProperty("damageRate"), damageRateContent);
EditorGUILayout.PropertyField(usePoolingProp, usePoolingContent);
if (usePoolingProp.boolValue)
{
minPoolSizeProp = serializedObject.FindProperty("minPoolSize");
maxPoolSizeProp = serializedObject.FindProperty("maxPoolSize");
EditorGUILayout.PropertyField(minPoolSizeProp, minPoolSizeContent);
EditorGUILayout.PropertyField(maxPoolSizeProp, maxPoolSizeContent);
if (minPoolSizeProp.intValue > maxPoolSizeProp.intValue) { maxPoolSizeProp.intValue = minPoolSizeProp.intValue; }
}
EditorGUILayout.PropertyField(serializedObject.FindProperty("beamStartWidth"), beamStartWidthContent);
EditorGUILayout.PropertyField(minBurstDurationProp, minBurstDurationContent);
EditorGUILayout.PropertyField(maxBurstDurationProp, maxBurstDurationContent);
if (minBurstDurationProp.floatValue > maxBurstDurationProp.floatValue) { maxBurstDurationProp.floatValue = minBurstDurationProp.floatValue; }
if (dischargeDurationProp.floatValue < 0.1f) { dischargeDurationProp.floatValue = 0.1f; }
EditorGUILayout.PropertyField(dischargeDurationProp, dischargeDurationContent);
if (beamModule.effectsObject != null)
{
if (beamModule.effectsObject.despawnTime < beamModule.maxBurstDuration)
{
EditorGUILayout.HelpBox(effectsDespawnWarning, MessageType.Info);
}
}
GUILayout.BeginHorizontal();
EditorGUILayout.LabelField(effectsObjectContent, GUILayout.Width(defaultEditorLabelWidth - 28f));
if (GUILayout.Button(gotoEffectFolderBtnContent, buttonCompact, GUILayout.Width(20f))) { SSCEditorHelper.HighlightFolderInProjectWindow(SSCSetup.effectsFolder, false, true); }
EditorGUILayout.PropertyField(effectsObjectProp, GUIContent.none);
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
EditorGUILayout.LabelField(muzzleFXObjectContent, GUILayout.Width(defaultEditorLabelWidth - 28f));
if (GUILayout.Button(gotoEffectFolderBtnContent, buttonCompact, GUILayout.Width(20f))) { SSCEditorHelper.HighlightFolderInProjectWindow(SSCSetup.effectsFolder, false, true); }
EditorGUILayout.PropertyField(muzzleEffectsObjectProp, GUIContent.none);
GUILayout.EndHorizontal();
if (muzzleEffectsObjectProp.objectReferenceValue != null)
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("muzzleEffectsOffset"), muzzleFXOffsetContent);
}
// Tell users not to add colliders
if (beamModule.GetComponentInChildren() != null)
{
EditorGUILayout.HelpBox("Beams should not have colliders attached. Collision detection currently occurs via " +
"raycasting to improve performance.", MessageType.Error);
}
// Tell users not to add rigidbodies
if (beamModule.GetComponentInChildren() != null)
{
EditorGUILayout.HelpBox("Beams should not have rigidbodies attached. Position is currently updated manually to improve performance.", MessageType.Error);
}
EditorGUILayout.EndVertical();
#endregion
// Apply property changes
serializedObject.ApplyModifiedProperties();
#region Debug Mode
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
isDebuggingEnabled = EditorGUILayout.Toggle(debugModeContent, isDebuggingEnabled);
if (isDebuggingEnabled && beamModule != null)
{
float rightLabelWidth = 150f;
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField(debugSourceShipIdContent, labelFieldRichText, GUILayout.Width(defaultEditorLabelWidth - 3f));
EditorGUILayout.LabelField(beamModule.sourceShipId.ToString(), GUILayout.MaxWidth(rightLabelWidth));
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField(debugSourceSquadronIdContent, labelFieldRichText, GUILayout.Width(defaultEditorLabelWidth - 3f));
EditorGUILayout.LabelField(beamModule.sourceSquadronId.ToString(), GUILayout.MaxWidth(rightLabelWidth));
EditorGUILayout.EndHorizontal();
}
EditorGUILayout.EndVertical();
#endregion
}
#endregion
}
}