Hi, I’m transitioning a project with custom editor windows from 5.6 to 2021 to check compatibility, and have run into some new errors that haven’t shown up in previous versions.
The one below is preventing certain windows from opening up, and showing the same error each time, but with little indication as to what is causing them.
UnityException: Internal_CreateInstance is not allowed to be called from a ScriptableObject constructor (or instance field initializer), call it in OnEnable instead. Called from ScriptableObject 'ArcaneEnemyEditor'.
See "Script Serialization" page in the Unity Manual for further details.
UnityEngine.TextAsset..ctor (UnityEngine.TextAsset+CreateOptions options, System.String text) (at <4a31731933e0419ca5a995305014ad37>:0)
UnityEngine.TextAsset..ctor () (at <4a31731933e0419ca5a995305014ad37>:0)
ArcaneEnemyEditor..ctor () (at Assets/ArcaneEngine/Editor/ArcaneEnemyEditor.cs:15)
UnityEditor.EditorWindow:GetWindow(Type, Boolean, String)
ArcaneEnemyEditor:Init() (at Assets/ArcaneEngine/Editor/ArcaneEnemyEditor.cs:60)
This seems to be something to do with the window initialisation, but as far as I can see from the docs, I’m doing it correctly (also works in previous versions no problem).
I’ve pasted the window code below, it’s a bit big but the errors pertain to a Texture2D declaration, and GetWindow call in Init.
I’ve moved things around a couple times but can’t seem to get rid of the error, does anyone know what this is?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System;
using System.IO;
public class ArcaneEnemyEditor : EditorWindow
{
private Vector2 _scrollPosition;
private Vector2 _scrollPosition2;
int menuDocIndex = 0;
TextAsset enemFile = new TextAsset();
bool hasLoaded = false;
bool isNewFile = false;
bool spritesFoldout = false;
bool audioFoldout = false;
#region Enemy Stats
string enemyName;
enum EnemyTypes { melee, projectile };
EnemyTypes enemyType;
int enemyHealth;
float enemyFireRate;
float enemyDamagePerHit;
bool enemyNeedsReload;
float enemyReloadTime;
int enemyMagazineSize;
bool enemyWeaponSplashDamage;
int enemyWeaponSplashRadius;
int enemyWeaponSplashDamageAmount;
#endregion
[Serializable]
public class ArcaneEnemy
{
public string enemyName;
public enum EnemyTypes { melee, projectile };
public EnemyTypes enemyType;
public int enemyHealth;
public float enemyFireRate;
public float enemyDamagePerHit;
public bool enemyNeedsReload;
public float enemyReloadTime;
public int enemyMagazineSize;
public bool enemyWeaponSplashDamage;
public int enemyWeaponSplashRadius;
public int enemyWeaponSplashDamageAmount;
}
//% = Crtl, # = Shft, & = Alt
[MenuItem("Arcane Engine/Enemy Editor %&E", false, 103)]
public static void Init()
{
EditorWindow arcaneEnemies = GetWindow(typeof(ArcaneEnemyEditor), false, "Arc Enemies");
arcaneEnemies.Show();
}
void OnInspectorUpdate()
{
Repaint();
}
void OnGUI()
{
Texture2D backg = new Texture2D(1, 1, TextureFormat.RGBA32, false);
backg.SetPixel(0, 0, new Color(0.30f, 0.30f, 0.30f, 1.0f));
backg.Apply();
GUIStyle MainBtns = new GUIStyle("ShurikenModuleTitle");
MainBtns.font = new GUIStyle(EditorStyles.label).font;
MainBtns.border = new RectOffset(15, 7, 4, 4);
MainBtns.fixedHeight = 40;
MainBtns.contentOffset = new Vector2(0f, -2f);
MainBtns.margin = new RectOffset(3, 2, 0, 1);
MainBtns.alignment = TextAnchor.MiddleCenter;
MainBtns.richText = true;
GUIStyle labelCentred = new GUIStyle("Label");
labelCentred.alignment = TextAnchor.MiddleCenter;
GUIStyle bigLabelCentre = new GUIStyle("Label");
bigLabelCentre.alignment = TextAnchor.MiddleCenter;
bigLabelCentre.padding = new RectOffset(0, 0, (int)(position.height / 2), 0);
bigLabelCentre.fontSize = 20;
//bigLabelCentre.stretchHeight = true;
bigLabelCentre.stretchWidth = true;
bigLabelCentre.richText = true;
EditorGUILayout.BeginHorizontal(); //Begin Whole Window
#region Sidebar
EditorGUILayout.BeginVertical(GUILayout.Width(position.width / 3)); //Begin Sidebar
_scrollPosition2 = GUILayout.BeginScrollView(_scrollPosition2);
GUI.DrawTexture(new Rect(0, 0, position.width / 3, position.height), backg, ScaleMode.StretchToFill);
EditorGUILayout.BeginHorizontal(EditorStyles.toolbar, GUILayout.ExpandWidth(true));
{
GUILayout.Label("Menu", labelCentred);
}
EditorGUILayout.EndHorizontal();
GUILayout.Label("Enemies Menu", EditorStyles.boldLabel);
using (new EditorGUILayout.HorizontalScope())
{
if (GUILayout.Button("Create New"))
{
NewEnemy();
}
}
GUILayout.Label("Existing Enemies", EditorStyles.boldLabel);
enemFile = (TextAsset)EditorGUILayout.ObjectField("File", enemFile, typeof(TextAsset), false);
if (GUILayout.Button("Load File"))
{
LoadEnemy(AssetDatabase.GetAssetPath(enemFile));
}
GUILayout.Label("Enemies Directory", EditorStyles.boldLabel);
DirectoryInfo dir = new DirectoryInfo(Application.dataPath + "/ArcaneEngine/Resources/");
FileInfo[] wFiles = dir.GetFiles("Enemy_*.json");
foreach (FileInfo item in wFiles)
{
string strname = item.Name;
string strname1 = strname.Replace("Enemy_", "");
string strname2 = strname1.Replace(".json", "");
if (strname2 == enemyName)
{
GUI.backgroundColor = Color.green;
}
if (GUILayout.Button(strname2, EditorStyles.toolbarButton))
{
string oldPath = item.DirectoryName + "\\" + item.Name;
string newPath = oldPath.Replace("\\", "/");
LoadEnemy(newPath);
}
GUI.backgroundColor = Color.white;
}
GUILayout.EndScrollView();
EditorGUILayout.EndVertical(); //End Sidebar
#endregion
#region Main Window
EditorGUILayout.BeginVertical(); //Begin Main Window
_scrollPosition = GUILayout.BeginScrollView(_scrollPosition);
if (menuDocIndex == 0) //Getting Started
{
EditorGUILayout.BeginHorizontal(EditorStyles.toolbar, GUILayout.ExpandWidth(true));
{
GUILayout.Label("Arcane Engine Enemy Editor", labelCentred);
}
EditorGUILayout.EndHorizontal();
//GUI.enabled = hasLoaded;
if (!hasLoaded)
{
GUILayout.Label("No Enemy Loaded\n<size=10>Please click 'Create New', or load a file using the\nfile picker or by selecting one from the Enemies Directory</size>", bigLabelCentre);
}
else
{
GUILayout.Label("Enemy Settings", EditorStyles.boldLabel);
EditorGUILayout.Space();
enemyName = EditorGUILayout.TextField("Name", enemyName);
EditorGUILayout.HelpBox("The name of the enemy used in game.", MessageType.None);
GUILayout.Label("Enemy Type", EditorStyles.boldLabel);
using (new EditorGUILayout.VerticalScope(GUI.skin.box))
{
enemyType = (EnemyTypes)EditorGUILayout.EnumPopup("Type", enemyType);
EditorGUILayout.HelpBox("Whether the enemy uses a melee, or projectile attack.", MessageType.None);
}
GUILayout.Label("Enemy Statistics", EditorStyles.boldLabel);
using (new EditorGUILayout.VerticalScope(GUI.skin.box))
{
enemyHealth = EditorGUILayout.IntField("Health", enemyHealth);
EditorGUILayout.HelpBox("The total health of the enemy (amount of damage needed to kill them).", MessageType.None);
}
GUILayout.Label("Combat Settings", EditorStyles.boldLabel);
using (new EditorGUILayout.VerticalScope(GUI.skin.box))
{
enemyFireRate = EditorGUILayout.FloatField("Fire Rate / Second", enemyFireRate);
EditorGUILayout.HelpBox("The amount of times the enemy can fire per second.", MessageType.None);
enemyDamagePerHit = EditorGUILayout.FloatField("Damage Per Hit", enemyDamagePerHit);
EditorGUILayout.HelpBox("The damage dealt to player per successful hit.", MessageType.None);
enemyNeedsReload = EditorGUILayout.Toggle("Needs Reload", enemyNeedsReload);
EditorGUILayout.HelpBox("Whether the enemy needs to reload (creates a delay every x shots).", MessageType.None);
if (enemyNeedsReload)
{
enemyReloadTime = EditorGUILayout.FloatField("Reload Time (seconds)", enemyReloadTime);
EditorGUILayout.HelpBox("The reload speed of the enemy (in seconds).", MessageType.None);
enemyMagazineSize = EditorGUILayout.IntField("Magazine Size", enemyMagazineSize);
EditorGUILayout.HelpBox("Total number of shots enemy can fire before the reload (delay).", MessageType.None);
}
}
GUILayout.Label("Additional Settings", EditorStyles.boldLabel);
using (new EditorGUILayout.VerticalScope(GUI.skin.box))
{
enemyWeaponSplashDamage = EditorGUILayout.Toggle("Splash Damage?", enemyWeaponSplashDamage);
EditorGUILayout.HelpBox("Whether the enemy produces splash damage.", MessageType.None);
if (enemyWeaponSplashDamage)
{
enemyWeaponSplashRadius = EditorGUILayout.IntField("Splash Damage Radius", enemyWeaponSplashRadius);
EditorGUILayout.HelpBox("The max magazine size (ignored when 'Needs Reload' is off).", MessageType.None);
enemyWeaponSplashDamageAmount = EditorGUILayout.IntField("Splash Damage Amount", enemyWeaponSplashDamageAmount);
EditorGUILayout.HelpBox("The max amount of damage player takes at centre of splash.", MessageType.None);
}
}
EditorGUILayout.HelpBox("Due to limitations within Unity, audio clips are currently selected on the ArcaneEnemyAgent component, and not here.", MessageType.Info);
/*
audioFoldout = ArcaneCustomDrawers.Foldout("Audio Clips", audioFoldout);
if (audioFoldout)
{
weaponWalkSound = (AudioClip)EditorGUILayout.ObjectField("Walk Sound", weaponWalkSound, typeof(AudioClip), false);
EditorGUILayout.HelpBox("The audio clip looped through when walking with the weapon.", MessageType.None);
weaponFireSound = (AudioClip)EditorGUILayout.ObjectField("Fire Sound", weaponFireSound, typeof(AudioClip), false);
EditorGUILayout.HelpBox("The audio clip looped through when firing the weapon.", MessageType.None);
weaponReloadSound = (AudioClip)EditorGUILayout.ObjectField("Reload Sound", weaponReloadSound, typeof(AudioClip), false);
EditorGUILayout.HelpBox("The audio clip looped through when reloading the weapon.", MessageType.None);
weaponImpactSound = (AudioClip)EditorGUILayout.ObjectField("Impact Sound", weaponImpactSound, typeof(AudioClip), false);
EditorGUILayout.HelpBox("The audio clip looped through when the weapon/projectile impacts a surface or target.", MessageType.None);
}
*/
GUI.backgroundColor = Color.green;
if (GUILayout.Button("Save All Settings", MainBtns))
{
SaveEnemy();
AssetDatabase.Refresh();
}
GUI.backgroundColor = Color.white;
}
}
if (menuDocIndex == 1) //Btn2
{
GUILayout.Label("2");
}
GUILayout.EndScrollView();
EditorGUILayout.EndVertical(); //End Main Window
#endregion
EditorGUILayout.EndHorizontal(); //End Whole Window
}
void SaveEnemy()
{
ArcaneEnemy ae = new ArcaneEnemy();
if (!isNewFile)
{
ae.enemyName = enemyName;
ae.enemyType = (ArcaneEnemy.EnemyTypes)enemyType;
ae.enemyHealth = enemyHealth;
ae.enemyFireRate = enemyFireRate;
ae.enemyDamagePerHit = enemyDamagePerHit;
ae.enemyNeedsReload = enemyNeedsReload;
ae.enemyReloadTime = enemyReloadTime;
ae.enemyMagazineSize = enemyMagazineSize;
ae.enemyWeaponSplashDamage = enemyWeaponSplashDamage;
ae.enemyWeaponSplashRadius = enemyWeaponSplashRadius;
ae.enemyWeaponSplashDamageAmount = enemyWeaponSplashDamageAmount;
}
string saveenem = JsonUtility.ToJson(ae);
#if UNITY_EDITOR
System.IO.File.WriteAllText(Application.dataPath + "/ArcaneEngine/Resources/Enemy_" + enemyName + ".json", saveenem);
#endif
if (EditorPrefs.GetBool("arcaneDebugSaveLoad"))
{
Debug.Log("Arcane Engine - Enemy Saved\n" + enemyName + "\n" + saveenem);
}
ShowNotification(new GUIContent("Saved"));
}
void LoadEnemy(string path)
{
string fileContents = File.ReadAllText(path);
ArcaneEnemy ae = JsonUtility.FromJson<ArcaneEnemy>(fileContents);
enemyName = ae.enemyName;
enemyType = (EnemyTypes)ae.enemyType;
enemyHealth = ae.enemyHealth;
enemyFireRate = ae.enemyFireRate;
enemyDamagePerHit = ae.enemyDamagePerHit;
enemyNeedsReload = ae.enemyNeedsReload;
enemyReloadTime = ae.enemyReloadTime;
enemyMagazineSize = ae.enemyMagazineSize;
enemyWeaponSplashDamage = ae.enemyWeaponSplashDamage;
enemyWeaponSplashRadius = ae.enemyWeaponSplashRadius;
enemyWeaponSplashDamageAmount = ae.enemyWeaponSplashDamageAmount;
hasLoaded = true;
if (EditorPrefs.GetBool("arcaneDebugSaveLoad"))
{
Debug.Log("Arcane Engine - Enemy Loaded\n" + enemyName + "\n" + fileContents);
}
ShowNotification(new GUIContent("Loaded"));
}
void NewEnemy()
{
enemyName = "";
enemyType = EnemyTypes.melee;
enemyHealth = 100;
enemyFireRate = 2;
enemyDamagePerHit = 20;
enemyNeedsReload = true;
enemyReloadTime = 0.5f;
enemyMagazineSize = 5;
enemyWeaponSplashDamage = false;
enemyWeaponSplashRadius = 2;
enemyWeaponSplashDamageAmount = 10;
hasLoaded = true;
}
}