Firstborn/Assets/RPG Creation Kit/Scripts/Character System/Editor/RaceEditor.cs
Schaken-Mods 774d18a99d 5/18/2023 Update
made most of the game Moddable. There is an in editor tool to make the mods and set them all up, and im making an external tool that will show your mods, lets you edit any information and it will pack it up and upload it. currently working on the uploading. Next I will make the game able to download and install. - Fuck Nexus.
2023-05-18 20:28:45 -05:00

1122 lines
36 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditorInternal;
using System;
using RPGCreationKit;
namespace RPGCreationKit
{
/// <summary>
/// Window to create races.
/// </summary>
public class RaceEditor : EditorWindow
{
bool isReady = false;
SerializedObject serializedObject;
// Navigation
public enum CurrentWindow { General, BodyData, FaceData, TextData, Factions };
CurrentWindow m_Window;
// Buttons scroll
Vector2 indexesScrollView;
Vector2 contentScrollView;
Vector2 hairWindowScrollView;
Vector2 eyeWindowScrollView;
GUIStyle guiLayoutDarkColor = new GUIStyle();
GUIStyle guiLayoutLightColor = new GUIStyle();
List<Race> allRaces = new List<Race>();
UnityEngine.Object malePrefab; // prefabs in the scene that are being edited
UnityEngine.Object femalePrefab; // prefabs in the scene that are being edited
string assetPathMale;
string assetPathFemale;
Race selectedRace; // copy of the original race object
bool hasSelectedRace = false;
int selectedRaceIndex = -1;
bool isCreatingNewRace = false;
Texture refreshButtonIcon;
public ReorderableList maleHairList;
public ReorderableList femaleHairList;
public ReorderableList eyeList;
GameObject gameObject;
Editor windowEditor;
bool gameObjectChanged = false;
bool maleSelected = true;
// Customize face
Vector2 faceBlendshapesContent;
float sliderValue;
int selectedBlendshapeIndex;
struct HairSelection
{
public int index;
public bool isMale;
public HairSelection(int _index, bool _isMale)
{
index = _index;
isMale = _isMale;
}
}
struct EyeSelection
{
public int index;
public bool isMale;
public EyeSelection(int _index, bool _isMale)
{
index = _index;
isMale = _isMale;
}
}
[MenuItem("RPG Creation Kit/Race Editor")]
public static void ShowWindow()
{
EditorWindow thisWindow = GetWindow(typeof(RaceEditor));
// Set Title
Texture icon = AssetDatabase.LoadAssetAtPath<Texture>(EditorIconsPath.RaceEditorIcon);
GUIContent titleContent = new GUIContent("Race Editor", icon);
thisWindow.titleContent = titleContent;
thisWindow.minSize = new Vector2(1265, 575);
thisWindow.maxSize = new Vector2(1265, 575);
}
void Init()
{
guiLayoutDarkColor.normal.background = MakeTex(600, 1, new Color(5.0f, 5.0f, 5.0f, .1f));
guiLayoutLightColor.normal.background = MakeTex(600, 1, new Color(37.0f, 79.0f, 133.0f, .4f));
refreshButtonIcon = AssetDatabase.LoadAssetAtPath<Texture>(EditorIconsPath.RefreshButton);
RefreshRaceList();
isReady = true;
}
private Texture2D MakeTex(int width, int height, Color col)
{
Color[] pix = new Color[width * height];
for (int i = 0; i < pix.Length; i++)
pix[i] = col;
Texture2D result = new Texture2D(width, height);
result.SetPixels(pix);
result.Apply();
return result;
}
public void RefreshRaceList()
{
allRaces = GetAllRaces<Race>();
allRaces.Sort(SortByID);
}
private void OnSelectedRaceChanges()
{
selectedRace = allRaces[selectedRaceIndex];
// Create a new object of this race
serializedObject = new SerializedObject(allRaces[selectedRaceIndex]);
RegenerateMalePrefabs();
RegenerateFemalePrefabs();
// Restore the lists
maleHairList = new ReorderableList(serializedObject, serializedObject.FindProperty("maleHairTypes"), true, true, true, true);
femaleHairList = new ReorderableList(serializedObject, serializedObject.FindProperty("femaleHairTypes"), true, true, true, true);
eyeList = new ReorderableList(serializedObject, serializedObject.FindProperty("eyeTypes"), true, true, true, true);
}
private void RegenerateFemalePrefabs()
{
DestroyImmediate(windowEditor);
if (femalePrefab != null)
DestroyImmediate(((GameObject)femalePrefab).gameObject);
if (serializedObject.FindProperty("femaleModel").objectReferenceValue != null)
{
assetPathFemale = AssetDatabase.GetAssetPath(((BodyData)serializedObject.FindProperty("femaleModel").objectReferenceValue).gameObject);
femalePrefab = PrefabUtility.LoadPrefabContents(assetPathFemale);
femalePrefab.hideFlags = HideFlags.HideInHierarchy | HideFlags.HideInInspector;
EditorUtility.SetDirty(femalePrefab);
}
gameObjectChanged = true;
}
private void RegenerateMalePrefabs()
{
DestroyImmediate(windowEditor);
// If there is an Editor instance of the body, destroy it
if (malePrefab != null)
DestroyImmediate(((GameObject)malePrefab).gameObject);
// If the Races has models, spawn them as prefabs
if (serializedObject.FindProperty("maleModel").objectReferenceValue != null)
{
assetPathMale = AssetDatabase.GetAssetPath(((BodyData)serializedObject.FindProperty("maleModel").objectReferenceValue).gameObject);
malePrefab = PrefabUtility.LoadPrefabContents(assetPathMale);
//malePrefab.hideFlags = HideFlags.HideInHierarchy | HideFlags.HideInInspector;
EditorUtility.SetDirty(malePrefab);
}
gameObjectChanged = true;
}
private static int SortByID(Race r1, Race r2)
{
return r1.ID.CompareTo(r2.ID);
}
private void OnGUI()
{
if (!isReady)
Init();
GUIStyle ButtonStyle = new GUIStyle(GUI.skin.button) { alignment = TextAnchor.MiddleCenter };
ButtonStyle.border = new RectOffset(2, 2, 2, 2);
ButtonStyle.fontSize = 16;
ButtonStyle.font = (Font)AssetDatabase.LoadAssetAtPath<Font>("Assets/RPG Creation Kit/Fonts/monofonto.ttf");
GUIStyle HeaderStyle = new GUIStyle(GUI.skin.label) { alignment = TextAnchor.MiddleLeft };
HeaderStyle.fontSize = 14;
HeaderStyle.font = (Font)AssetDatabase.LoadAssetAtPath<Font>("Assets/RPG Creation Kit/Fonts/monofonto.ttf");
EditorGUILayout.BeginHorizontal();
EditorGUILayout.BeginVertical("box", GUILayout.MaxWidth(200.0f), GUILayout.ExpandWidth(false));
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("RACES", HeaderStyle, GUILayout.MaxWidth(165.0f), GUILayout.ExpandWidth(false));
if (GUILayout.Button(new GUIContent(refreshButtonIcon, "Refreshes the Race list."), GUILayout.MaxWidth(32)))
RefreshRaceList();
EditorGUILayout.EndHorizontal();
indexesScrollView = EditorGUILayout.BeginScrollView(indexesScrollView, GUIStyle.none, GUI.skin.verticalScrollbar, GUILayout.Width(200.0f), GUILayout.Height(500.0f));
indexesScrollView.x = (indexesScrollView.x / 2);
Rect clickArea = EditorGUILayout.BeginVertical(guiLayoutDarkColor, GUILayout.Width(200.0f), GUILayout.Height(500.0f));
Event current = Event.current;
GUI.enabled = !isCreatingNewRace;
Color defaultColor = GUI.color;
// Display all current quest stages
for (int i = 0; i < allRaces.Count; i++)
{
if (selectedRaceIndex == i && hasSelectedRace)
GUI.color = Color.green;
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (GUILayout.Button(allRaces[i].ID, GUILayout.MaxWidth(170.0f)))
{
GUI.FocusControl(null);
selectedRaceIndex = i;
hasSelectedRace = true;
OnSelectedRaceChanges();
}
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
GUI.color = defaultColor;
}
GUI.enabled = true;
if (!isCreatingNewRace)
{
// DROPDOWN TO CREATE NEW STAGES
if (clickArea.Contains(current.mousePosition) && current.type == EventType.ContextClick)
{
GenericMenu menu = new GenericMenu();
menu.AddDisabledItem(new GUIContent("Races"));
menu.AddSeparator("");
menu.AddItem(new GUIContent("New"), false, CreateNew);
menu.AddItem(new GUIContent("Delete Selected"), false, DeleteSelected);
menu.ShowAsContext();
current.Use();
}
void CreateNew()
{
Debug.Log("Creating new Race");
}
void DeleteSelected()
{
if(hasSelectedRace)
Debug.Log("Deleting: " + selectedRace.ID);
}
}
EditorGUILayout.EndScrollView();
EditorGUILayout.EndHorizontal();
EditorGUILayout.EndVertical();
EditorGUILayout.BeginVertical();
EditorGUILayout.BeginHorizontal("box");
#region NavigationMenu
// Buttons for navigation
if (m_Window == CurrentWindow.General)
GUI.color = Color.green;
else
GUI.color = defaultColor;
if (GUILayout.Button("General", GUILayout.Width(200), GUILayout.Height(20)))
{
m_Window = CurrentWindow.General;
}
if (m_Window == CurrentWindow.BodyData)
GUI.color = Color.green;
else
GUI.color = defaultColor;
if (GUILayout.Button("Body Data", GUILayout.Width(200), GUILayout.Height(20)))
{
if (m_Window != CurrentWindow.BodyData)
DestroyImmediate(windowEditor);
m_Window = CurrentWindow.BodyData;
gameObjectChanged = true;
}
if (m_Window == CurrentWindow.FaceData)
GUI.color = Color.green;
else
GUI.color = defaultColor;
if (GUILayout.Button("Face Data", GUILayout.Width(200), GUILayout.Height(20)))
{
if (m_Window != CurrentWindow.FaceData)
DestroyImmediate(windowEditor);
m_Window = CurrentWindow.FaceData;
gameObjectChanged = true;
}
if (m_Window == CurrentWindow.TextData)
GUI.color = Color.green;
else
GUI.color = defaultColor;
if (GUILayout.Button("Text Data", GUILayout.Width(200), GUILayout.Height(20)))
{
m_Window = CurrentWindow.TextData;
}
if (m_Window == CurrentWindow.Factions)
GUI.color = Color.green;
else
GUI.color = defaultColor;
if (GUILayout.Button("Factions", GUILayout.Width(200), GUILayout.Height(20)))
{
m_Window = CurrentWindow.Factions;
}
EditorGUILayout.EndHorizontal();
GUI.color = defaultColor;
#endregion
if (hasSelectedRace && serializedObject != null)
{
// here goes the switch window
switch (m_Window)
{
case CurrentWindow.General:
contentScrollView =
EditorGUILayout.BeginScrollView(contentScrollView, GUIStyle.none, GUI.skin.verticalScrollbar, GUILayout.Width(650.0f), GUILayout.Height(500.0f));
var raceID = serializedObject.FindProperty("ID");
var raceName = serializedObject.FindProperty("raceName");
var maleAtt = serializedObject.FindProperty("baseAttributesMale");
var femaleAtt = serializedObject.FindProperty("baseAttributesFemale");
var maleDerAtt = serializedObject.FindProperty("baseDerivedAttributesMale");
var femaleDerAtt = serializedObject.FindProperty("baseDerivedAttributesFemale");
EditorGUILayout.LabelField("BASE INFORMATION", HeaderStyle);
EditorGUILayout.BeginVertical("box");
EditorGUILayout.PropertyField(raceID, GUILayout.Width(400));
EditorGUILayout.PropertyField(raceName, GUILayout.Width(400));
EditorGUILayout.EndVertical();
EditorGUILayout.Space(5);
EditorGUILayout.LabelField("BASE ATTRIBUTES", HeaderStyle);
EditorGUILayout.BeginVertical();
EditorGUILayout.BeginHorizontal("box");
EditorGUILayout.PropertyField(maleAtt, GUILayout.Width(200));
EditorGUILayout.PropertyField(femaleAtt, GUILayout.Width(200));
maleAtt.isExpanded = true;
femaleAtt.isExpanded = true;
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal("box");
EditorGUILayout.PropertyField(maleDerAtt, GUILayout.Width(200));
EditorGUILayout.PropertyField(femaleDerAtt, GUILayout.Width(200));
maleDerAtt.isExpanded = true;
femaleDerAtt.isExpanded = true;
EditorGUILayout.EndHorizontal();
EditorGUILayout.EndVertical();
EditorGUILayout.EndScrollView();
break;
case CurrentWindow.BodyData:
#region content
contentScrollView =
EditorGUILayout.BeginScrollView(contentScrollView, GUIStyle.none, GUI.skin.verticalScrollbar, GUILayout.Width(650.0f), GUILayout.Height(500.0f));
var maleBody = serializedObject.FindProperty("maleModel");
var femaleBody = serializedObject.FindProperty("femaleModel");
var maleFPS = serializedObject.FindProperty("maleFPS");
var femaleFPS = serializedObject.FindProperty("femaleFPS");
EditorGUILayout.LabelField("BODY DATA", HeaderStyle);
EditorGUILayout.BeginHorizontal();
EditorGUILayout.BeginVertical("box");
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(maleBody, GUILayout.MaxWidth(350));
if (EditorGUI.EndChangeCheck())
RegenerateMalePrefabs();
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(femaleBody, GUILayout.MaxWidth(350));
if (EditorGUI.EndChangeCheck())
RegenerateFemalePrefabs();
EditorGUILayout.PropertyField(maleFPS, GUILayout.MaxWidth(350));
EditorGUILayout.PropertyField(femaleFPS, GUILayout.MaxWidth(350));
// Draw Model Preview
// Draw Model Preview
GUIStyle bgColor = new GUIStyle();
bgColor.normal.background = Texture2D.blackTexture;
if (windowEditor == null)
{
if (maleSelected)
{
if (malePrefab != null)
{
windowEditor = Editor.CreateEditor(malePrefab);
gameObjectChanged = false;
}
else
DestroyImmediate(windowEditor);
}
else if (femalePrefab != null)
{
windowEditor = Editor.CreateEditor(femalePrefab);
gameObjectChanged = false;
}else
DestroyImmediate(windowEditor);
}
if (windowEditor != null)
{
windowEditor.DrawPreview(GUILayoutUtility.GetRect(64, 355));
windowEditor.OnInteractivePreviewGUI(GUILayoutUtility.GetRect(1, 1), bgColor);
windowEditor.ReloadPreviewInstances();
windowEditor.Repaint();
windowEditor.ResetTarget();
this.Repaint();
} else
{
EditorGUILayout.Space(315);
if (maleSelected)
EditorGUILayout.HelpBox("There is no Male Model associated with this race, reference a prefab in the \"Body Data\" tab.", MessageType.Warning);
else
EditorGUILayout.HelpBox("There is no Female Model associated with this race, reference a prefab in the \"Body Data\" tab.", MessageType.Warning);
}
// Male/Female switch
EditorGUILayout.BeginHorizontal();
GUI.color = (maleSelected) ? Color.grey : defaultColor;
if (GUILayout.Button("Male"))
{
maleSelected = true;
DestroyImmediate(windowEditor);
}
GUI.color = (!maleSelected) ? Color.grey : defaultColor;
if (GUILayout.Button("Female"))
{
maleSelected = false;
DestroyImmediate(windowEditor);
}
GUI.color = defaultColor;
EditorGUILayout.EndHorizontal();
this.Repaint();
EditorGUILayout.EndVertical();
EditorGUILayout.BeginVertical();
hairWindowScrollView =
EditorGUILayout.BeginScrollView(hairWindowScrollView, GUIStyle.none, GUI.skin.verticalScrollbar, GUILayout.MaxHeight(200.0f));
EditorGUILayout.BeginVertical("box", GUILayout.MaxHeight(200.0f));
int currentMaleIndex = serializedObject.FindProperty("defaultMaleHair").intValue;
int currentFemaleIndex = serializedObject.FindProperty("defaultFemaleHair").intValue;
if (maleSelected)
{
maleHairList.DoLayoutList();
maleHairList.drawHeaderCallback = (Rect rect) =>
{
EditorGUI.LabelField(rect, "(MALE) Hair Types", HeaderStyle);
};
maleHairList.drawElementCallback =
(Rect rect, int index, bool isActive, bool isFocused) =>
{
var element = maleHairList.serializedProperty.GetArrayElementAtIndex(index);
rect.y += 2;
EditorGUI.LabelField(rect, "Type " + index.ToString());
EditorGUI.PropertyField(
new Rect(rect.x + 60, rect.y, 150, EditorGUIUtility.singleLineHeight),
element, GUIContent.none);
};
maleHairList.onRemoveCallback = (ReorderableList list) =>
{
var element = list.serializedProperty.GetArrayElementAtIndex(list.index);
element.DeleteCommand();
element.DeleteCommand();
serializedObject.FindProperty("defaultMaleHair").intValue = -1;
currentMaleIndex = -1;
SelectHairType(new HairSelection(-1, true));
};
} else
{
femaleHairList.DoLayoutList();
femaleHairList.drawHeaderCallback = (Rect rect) =>
{
EditorGUI.LabelField(rect, "(FEMALE) Hair Types", HeaderStyle);
};
femaleHairList.drawElementCallback =
(Rect rect, int index, bool isActive, bool isFocused) =>
{
var element = femaleHairList.serializedProperty.GetArrayElementAtIndex(index);
rect.y += 2;
EditorGUI.LabelField(rect, "Type " + index.ToString());
EditorGUI.PropertyField(
new Rect(rect.x + 60, rect.y, 150, EditorGUIUtility.singleLineHeight),
element, GUIContent.none);
};
femaleHairList.onRemoveCallback = (ReorderableList list) =>
{
var element = list.serializedProperty.GetArrayElementAtIndex(list.index);
element.DeleteCommand();
element.DeleteCommand();
serializedObject.FindProperty("defaultFemaleHair").intValue = -1;
currentFemaleIndex = -1;
SelectHairType(new HairSelection(-1, false));
};
}
EditorGUILayout.EndScrollView();
EditorGUILayout.EndVertical();
eyeWindowScrollView =
EditorGUILayout.BeginScrollView(eyeWindowScrollView, GUIStyle.none, GUI.skin.verticalScrollbar, GUILayout.MaxHeight(200.0f));
EditorGUILayout.BeginVertical("box", GUILayout.MaxHeight(200.0f));
eyeList.DoLayoutList();
eyeList.drawHeaderCallback = (Rect rect) => {
EditorGUI.LabelField(rect, "Eyes Types", HeaderStyle);
};
eyeList.drawElementCallback =
(Rect rect, int index, bool isActive, bool isFocused) => {
var element = eyeList.serializedProperty.GetArrayElementAtIndex(index);
rect.y += 2;
EditorGUI.LabelField(rect, "Type " + index.ToString());
EditorGUI.PropertyField(
new Rect(rect.x + 60, rect.y, 150, EditorGUIUtility.singleLineHeight),
element, GUIContent.none);
};
EditorGUILayout.EndScrollView();
EditorGUILayout.EndVertical();
EditorGUILayout.BeginVertical("box", GUILayout.MaxWidth(280.0f));
EditorGUILayout.LabelField("Default Hair", HeaderStyle);
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Male:", GUILayout.MaxWidth(55.0f));
GUIContent newContent = new GUIContent();
// And update the serializedObject
currentMaleIndex = serializedObject.FindProperty("defaultMaleHair").intValue;
try
{
newContent.text = (currentMaleIndex != -1) ? maleHairList.serializedProperty.GetArrayElementAtIndex(currentMaleIndex).objectReferenceValue.name : "NONE";
}
catch
{
currentMaleIndex = -1;
newContent.text = (currentMaleIndex != -1) ? maleHairList.serializedProperty.GetArrayElementAtIndex(currentMaleIndex).objectReferenceValue.name : "NONE";
}
if (GUILayout.Button(newContent))
{
GenericMenu menu = new GenericMenu();
menu.AddDisabledItem(new GUIContent("HairTypes"));
menu.AddSeparator("");
menu.AddItem(new GUIContent("NONE"), (serializedObject.FindProperty("defaultMaleHair").intValue == -1), SelectHairType, new HairSelection(-1, true));
for (int i = 0; i < maleHairList.count; i++)
{
bool isSelected = (serializedObject.FindProperty("defaultMaleHair").intValue == i);
if(maleHairList.serializedProperty.GetArrayElementAtIndex(i).objectReferenceValue != null)
menu.AddItem(new GUIContent(maleHairList.serializedProperty.GetArrayElementAtIndex(i).objectReferenceValue.name), isSelected, SelectHairType, new HairSelection(i, true));
}
menu.ShowAsContext();
current.Use();
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Female:", GUILayout.MaxWidth(55.0f));
newContent = new GUIContent();
currentFemaleIndex = serializedObject.FindProperty("defaultFemaleHair").intValue;
try
{
newContent.text = (currentFemaleIndex != -1) ? femaleHairList.serializedProperty.GetArrayElementAtIndex(currentFemaleIndex).objectReferenceValue.name : "NONE";
}
catch
{
currentFemaleIndex = -1;
newContent.text = (currentFemaleIndex != -1) ? femaleHairList.serializedProperty.GetArrayElementAtIndex(currentFemaleIndex).objectReferenceValue.name : "NONE";
}
if (GUILayout.Button(newContent))
{
GenericMenu menu = new GenericMenu();
menu.AddDisabledItem(new GUIContent("HairTypes"));
menu.AddSeparator("");
menu.AddItem(new GUIContent("NONE"), (serializedObject.FindProperty("defaultFemaleHair").intValue == -1), SelectHairType, new HairSelection(-1, false));
for (int i = 0; i < femaleHairList.count; i++)
{
bool isSelected = (serializedObject.FindProperty("defaultFemaleHair").intValue == i);
if(femaleHairList.serializedProperty.GetArrayElementAtIndex(i) != null)
menu.AddItem(new GUIContent(femaleHairList.serializedProperty.GetArrayElementAtIndex(i).objectReferenceValue.name), isSelected, SelectHairType, new HairSelection(i, false));
}
menu.ShowAsContext();
current.Use();
}
EditorGUILayout.EndHorizontal();
void SelectHairType(object hairSelection)
{
HairSelection hSel = (HairSelection)hairSelection;
serializedObject.FindProperty((hSel.isMale) ? "defaultMaleHair" : "defaultFemaleHair").intValue = hSel.index;
// Instantiate Hair in the selected body
BodyData sBodyData;
if (hSel.isMale)
{
sBodyData = (malePrefab as GameObject).GetComponent<BodyData>();
if (sBodyData.hair != null)
DestroyImmediate(sBodyData.hair.gameObject);
if (hSel.index > -1)
{
serializedObject.FindProperty("defaultMaleHair").intValue = hSel.index;
SerializedObject hairElement = new SerializedObject(maleHairList.serializedProperty.GetArrayElementAtIndex(hSel.index).objectReferenceValue); // this is Hair
UnityEngine.Object sHair = hairElement.FindProperty("mesh").objectReferenceValue;
sBodyData.hair = ((GameObject)(Instantiate(sHair, sBodyData.head.transform))).GetComponent<SkinnedMeshRenderer>();
Debug.Log(sBodyData.hair);
// Attach the hair
sBodyData.hair.transform.parent = sBodyData.head.transform;
sBodyData.hair.rootBone = sBodyData.head.rootBone;
sBodyData.hair.bones = sBodyData.head.bones;
this.Repaint();
windowEditor.Repaint();
windowEditor.ReloadPreviewInstances();
windowEditor.Repaint();
this.Repaint();
}
}
else
{
sBodyData = (femalePrefab as GameObject).GetComponent<BodyData>();
if (sBodyData.hair != null)
DestroyImmediate(sBodyData.hair.gameObject);
if (hSel.index > -1)
{
serializedObject.FindProperty("defaultFemaleHair").intValue = hSel.index;
SerializedObject hairElement = new SerializedObject(femaleHairList.serializedProperty.GetArrayElementAtIndex(hSel.index).objectReferenceValue); // this is Hair
UnityEngine.Object sHair = hairElement.FindProperty("mesh").objectReferenceValue;
sBodyData.hair = ((GameObject)(Instantiate(sHair, sBodyData.head.transform))).GetComponent<SkinnedMeshRenderer>();
Debug.Log(sBodyData.hair);
// Attach the hair
sBodyData.hair.transform.parent = sBodyData.head.transform;
sBodyData.hair.rootBone = sBodyData.head.rootBone;
sBodyData.hair.bones = sBodyData.head.bones;
this.Repaint();
windowEditor.Repaint();
windowEditor.ReloadPreviewInstances();
windowEditor.Repaint();
this.Repaint();
}
}
}
EditorGUILayout.LabelField("Default Eyes", HeaderStyle);
EditorGUILayout.BeginHorizontal();
int currentEyeMaleIndex = serializedObject.FindProperty("defaultMaleEye").intValue;
int currentEyeFemaleIndex = serializedObject.FindProperty("defaultFemaleEye").intValue;
EditorGUILayout.LabelField("Male:", GUILayout.MaxWidth(55.0f));
var maleEyeContent = new GUIContent();
currentEyeMaleIndex = serializedObject.FindProperty("defaultMaleEye").intValue;
try
{
maleEyeContent.text = (currentEyeMaleIndex != 0) ? eyeList.serializedProperty.GetArrayElementAtIndex(currentEyeMaleIndex).objectReferenceValue.name : "Default";
}
catch
{
currentEyeMaleIndex = 0;
maleEyeContent.text = (currentEyeMaleIndex != 0) ? eyeList.serializedProperty.GetArrayElementAtIndex(currentEyeMaleIndex).objectReferenceValue.name : "Default";
}
if (GUILayout.Button(maleEyeContent))
{
GenericMenu menu = new GenericMenu();
menu.AddDisabledItem(new GUIContent("Eyes Type"));
menu.AddSeparator("");
menu.AddItem(new GUIContent("Default"), (serializedObject.FindProperty("defaultMaleEye").intValue == 0), SelectEyeType, new EyeSelection(0, true));
for (int i = 0; i < eyeList.count; i++)
{
if (eyeList.serializedProperty.GetArrayElementAtIndex(i) != null)
menu.AddItem(new GUIContent(eyeList.serializedProperty.GetArrayElementAtIndex(i).objectReferenceValue.name), (serializedObject.FindProperty("defaultMaleEye").intValue == i), SelectEyeType, new EyeSelection(i, true));
}
menu.ShowAsContext();
current.Use();
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Female:", GUILayout.MaxWidth(55.0f));
var femaleEyeContent = new GUIContent();
currentEyeFemaleIndex = serializedObject.FindProperty("defaultFemaleEye").intValue;
try
{
femaleEyeContent.text = (currentEyeFemaleIndex != 0) ? eyeList.serializedProperty.GetArrayElementAtIndex(currentEyeFemaleIndex).objectReferenceValue.name : "Default";
}
catch
{
currentEyeFemaleIndex = 0;
femaleEyeContent.text = (currentEyeFemaleIndex != 0) ? eyeList.serializedProperty.GetArrayElementAtIndex(currentEyeFemaleIndex).objectReferenceValue.name : "Default";
}
if (GUILayout.Button(femaleEyeContent))
{
GenericMenu menu = new GenericMenu();
menu.AddDisabledItem(new GUIContent("Eyes Type"));
menu.AddSeparator("");
menu.AddItem(new GUIContent("Default"), (serializedObject.FindProperty("defaultFemaleEye").intValue == 0), SelectEyeType, new EyeSelection(0, false));
for (int i = 0; i < eyeList.count; i++)
{
if (eyeList.serializedProperty.GetArrayElementAtIndex(i) != null)
menu.AddItem(new GUIContent(eyeList.serializedProperty.GetArrayElementAtIndex(i).objectReferenceValue.name), (serializedObject.FindProperty("defaultFemaleEye").intValue == i), SelectEyeType, new EyeSelection(i, false));
}
menu.ShowAsContext();
current.Use();
}
void SelectEyeType(object _eyeSelection)
{
EyeSelection hSel = (EyeSelection)_eyeSelection;
serializedObject.FindProperty((hSel.isMale) ? "defaultMaleEye" : "defaultFemaleEye").intValue = hSel.index;
// Instantiate Hair in the selected body
BodyData sBodyData;
if (hSel.isMale)
{
sBodyData = (malePrefab as GameObject).GetComponent<BodyData>();
serializedObject.FindProperty("defaultMaleEye").intValue = hSel.index;
SerializedObject eyeElement = new SerializedObject(eyeList.serializedProperty.GetArrayElementAtIndex(hSel.index).objectReferenceValue); // this is Hair
UnityEngine.Object sEye = eyeElement.FindProperty("eyes").objectReferenceValue;
sBodyData.eyeIndex = serializedObject.FindProperty("defaultMaleEye").intValue;
sBodyData.eyes.sharedMaterial = ((SkinnedMeshRenderer)sEye).sharedMaterial;
this.Repaint();
windowEditor.Repaint();
windowEditor.ReloadPreviewInstances();
windowEditor.Repaint();
this.Repaint();
}
else
{
sBodyData = (femalePrefab as GameObject).GetComponent<BodyData>();
serializedObject.FindProperty("defaultFemaleEye").intValue = hSel.index;
SerializedObject eyeElement = new SerializedObject(eyeList.serializedProperty.GetArrayElementAtIndex(hSel.index).objectReferenceValue); // this is Hair
UnityEngine.Object sEye = eyeElement.FindProperty("eyes").objectReferenceValue;
sBodyData.eyeIndex = serializedObject.FindProperty("defaultFemaleEye").intValue;
sBodyData.eyes.sharedMaterial = ((SkinnedMeshRenderer)sEye).sharedMaterial;
this.Repaint();
windowEditor.Repaint();
windowEditor.ReloadPreviewInstances();
windowEditor.Repaint();
this.Repaint();
}
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.EndVertical();
EditorGUILayout.EndVertical();
EditorGUILayout.EndHorizontal();
EditorGUILayout.EndScrollView();
#endregion
break;
case CurrentWindow.FaceData:
contentScrollView =
EditorGUILayout.BeginScrollView(contentScrollView, GUIStyle.none, GUI.skin.verticalScrollbar, GUILayout.Width(650.0f), GUILayout.Height(500.0f));
EditorGUILayout.BeginHorizontal();
faceBlendshapesContent =
EditorGUILayout.BeginScrollView(faceBlendshapesContent, GUIStyle.none, GUI.skin.verticalScrollbar, GUILayout.Width(270.0f), GUILayout.Height(500.0f));
EditorGUILayout.BeginVertical("box");
EditorGUILayout.LabelField("FACE BLENDSHAPES", HeaderStyle);
// Get Blendshapes of the selected mesh
string blendshapeName;
GUIContent guicontent = new GUIContent();
SkinnedMeshRenderer selectedHead = null;
if (malePrefab != null && maleSelected)
selectedHead = (malePrefab as GameObject).GetComponent<BodyData>().head;
else if(femalePrefab != null && !maleSelected)
selectedHead = (femalePrefab as GameObject).GetComponent<BodyData>().head;
if (selectedHead != null)
{
// Display all blendshapes
for (int i = 0; i < selectedHead.sharedMesh.blendShapeCount; i++)
{
blendshapeName = selectedHead.sharedMesh.GetBlendShapeName(i).ToString();
guicontent.text = blendshapeName;
guicontent.tooltip = blendshapeName;
if (selectedBlendshapeIndex == i)
GUI.color = Color.gray;
if (GUILayout.Button(guicontent))
{
selectedBlendshapeIndex = i;
sliderValue = selectedHead.GetBlendShapeWeight(i);
}
GUI.color = defaultColor;
}
}
EditorGUILayout.EndVertical();
EditorGUILayout.EndScrollView();
GUILayout.FlexibleSpace();
EditorGUILayout.BeginVertical();
bgColor = new GUIStyle();
if (selectedHead != null)
{
if (windowEditor == null || gameObjectChanged)
{
windowEditor = Editor.CreateEditor(selectedHead.gameObject);
gameObjectChanged = false;
}
}
if (windowEditor != null)
{
windowEditor.DrawPreview(GUILayoutUtility.GetRect(64, 390));
windowEditor.OnInteractivePreviewGUI(GUILayoutUtility.GetRect(1, 1), bgColor);
windowEditor.ReloadPreviewInstances();
windowEditor.Repaint();
windowEditor.ResetTarget();
this.Repaint();
}
else
{
EditorGUILayout.Space(350);
if (maleSelected)
EditorGUILayout.HelpBox("There is no Male Model associated with this race, reference a prefab in the \"Body Data\" tab.", MessageType.Warning);
else
EditorGUILayout.HelpBox("There is no Female Model associated with this race, reference a prefab in the \"Body Data\" tab.", MessageType.Warning);
}
// Male/Female switch
EditorGUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
GUI.color = (maleSelected) ? Color.grey : defaultColor;
if (GUILayout.Button("Male", GUILayout.MaxWidth(100)))
{
maleSelected = true;
gameObjectChanged = true;
DestroyImmediate(windowEditor);
selectedBlendshapeIndex = 0;
}
GUI.color = (!maleSelected) ? Color.grey : defaultColor;
if (GUILayout.Button("Female", GUILayout.MaxWidth(100)))
{
maleSelected = false;
gameObjectChanged = true;
DestroyImmediate(windowEditor);
selectedBlendshapeIndex = 0;
}
GUI.color = defaultColor;
GUILayout.FlexibleSpace();
EditorGUILayout.EndHorizontal();
if (selectedHead != null)
{
HeadBlendshapesManager bsManager = selectedHead.GetComponent<HeadBlendshapesManager>();
if (bsManager != null)
bsManager.AdjustChildBlendshapes();
if (selectedHead.sharedMesh.blendShapeCount > 0)
{
sliderValue = EditorGUILayout.Slider(selectedHead.GetBlendShapeWeight(selectedBlendshapeIndex), -100, 100);
selectedHead.SetBlendShapeWeight(selectedBlendshapeIndex, sliderValue);
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("Random Face"))
{
for (int i = 0; i < selectedHead.sharedMesh.blendShapeCount; i++)
selectedHead.SetBlendShapeWeight(i, UnityEngine.Random.Range(-100, 100));
}
if (GUILayout.Button("Reset Face"))
{
for (int i = 0; i < selectedHead.sharedMesh.blendShapeCount; i++)
selectedHead.SetBlendShapeWeight(i, 0);
}
EditorGUILayout.EndHorizontal();
}
else
{
EditorGUILayout.HelpBox("The selected mesh has no blendshapes, therefore you cannot customize this character's face.", MessageType.Warning);
}
}
EditorGUILayout.EndVertical();
EditorGUILayout.EndHorizontal();
EditorGUILayout.EndScrollView();
break;
}
}
EditorGUILayout.EndVertical();
EditorGUILayout.EndHorizontal();
GUILayout.FlexibleSpace();
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("SAVE", ButtonStyle))
{
serializedObject.ApplyModifiedProperties();
// Apply prefab
SkinnedMeshRenderer selectedHead = null;
if (malePrefab != null && maleSelected)
selectedHead = (malePrefab as GameObject).GetComponent<BodyData>().head;
else if(femalePrefab != null && !maleSelected)
selectedHead = (femalePrefab as GameObject).GetComponent<BodyData>().head;
BodyData sBodyData = (malePrefab as GameObject).GetComponent<BodyData>();
HeadBlendshapesManager bsManager = selectedHead.GetComponent<HeadBlendshapesManager>();
if (bsManager == null)
Debug.Log("Null");
bsManager.HairMesh = sBodyData.hair;
if (malePrefab != null)
{
PrefabUtility.SaveAsPrefabAsset((GameObject)malePrefab, assetPathMale);
//PrefabUtility.UnloadPrefabContents((GameObject)malePrefab);
}
if (femalePrefab != null)
{
PrefabUtility.SaveAsPrefabAsset((GameObject)femalePrefab, assetPathFemale);
//PrefabUtility.UnloadPrefabContents((GameObject)femalePrefab);
}
}
if (GUILayout.Button("SAVE & CLOSE", ButtonStyle))
{
serializedObject.ApplyModifiedProperties();
if (malePrefab != null)
{
PrefabUtility.SaveAsPrefabAsset((GameObject)malePrefab, assetPathMale);
PrefabUtility.UnloadPrefabContents((GameObject)malePrefab);
}
if (femalePrefab != null)
{
PrefabUtility.SaveAsPrefabAsset((GameObject)femalePrefab, assetPathFemale);
PrefabUtility.UnloadPrefabContents((GameObject)femalePrefab);
}
DestroyImmediate(windowEditor);
this.Close();
}
if (GUILayout.Button("CANCEL", ButtonStyle))
{
DestroyImmediate(windowEditor);
this.Close();
}
EditorGUILayout.EndHorizontal();
GUILayout.FlexibleSpace();
}
private void OnDestroy()
{
DestroyImmediate(malePrefab);
DestroyImmediate(femalePrefab);
}
public static List<T> GetAllRaces<T>() where T : Race
{
string[] guids = AssetDatabase.FindAssets("t:" + typeof(T).Name);
List<T> a = new List<T>(guids.Length);
for (int i = 0; i < guids.Length; i++)
{
string path = AssetDatabase.GUIDToAssetPath(guids[i]);
a.Add(AssetDatabase.LoadAssetAtPath<T>(path));
}
return a;
}
}
}