774d18a99d
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.
1122 lines
36 KiB
C#
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;
|
|
}
|
|
}
|
|
} |