862 lines
40 KiB
C#
862 lines
40 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
|
|
using System.CodeDom;
|
|
using Microsoft.CSharp;
|
|
using System.IO;
|
|
using System.CodeDom.Compiler;
|
|
|
|
using System.Reflection;
|
|
using System.Linq.Expressions;
|
|
using UnityEditor.SceneManagement;
|
|
using UnityEditor.Callbacks;
|
|
using Valve.Newtonsoft.Json;
|
|
|
|
namespace Valve.VR
|
|
{
|
|
#pragma warning disable 0219 // variable assigned but not used.
|
|
|
|
public static class SteamVR_Input_Generator
|
|
{
|
|
public const string steamVRInputOverwriteBuildKey = "SteamVR_Input_OverwriteBuild";
|
|
public const string steamVRInputDeleteUnusedKey = "SteamVR_Input_DeleteUnused";
|
|
|
|
private const string actionSetClassNamePrefix = "SteamVR_Input_ActionSet_";
|
|
|
|
public const string generationNeedsReloadKey = "SteamVR_Input_GenerationNeedsReload";
|
|
|
|
private const string progressBarTitle = "SteamVR Input Generation";
|
|
|
|
public const string steamVRInputActionSetClassesFolder = "ActionSetClasses";
|
|
public const string steamVRInputActionsClass = "SteamVR_Input_Actions";
|
|
public const string steamVRInputActionSetsClass = "SteamVR_Input_ActionSets";
|
|
public const string steamVRInputInitializationClass = "SteamVR_Input_Initialization";
|
|
public const string steamVRActionsAssemblyDefinition = "SteamVR_Actions";
|
|
|
|
private static bool generating = false;
|
|
|
|
public static void BeginGeneration()
|
|
{
|
|
generating = true;
|
|
fileChanged = false;
|
|
|
|
SteamVR_Input_EditorWindow.SetProgressBarText("Beginning generation...", 0);
|
|
|
|
GenerationStep_CreateActionSetClasses();
|
|
GenerationStep_CreateHelperClasses();
|
|
GenerationStep_CreateInitClass();
|
|
GenerationStep_CreateAssemblyDefinition();
|
|
DeleteUnusedScripts();
|
|
|
|
if (fileChanged)
|
|
EditorPrefs.SetBool(generationNeedsReloadKey, true);
|
|
|
|
AssetDatabase.Refresh();
|
|
|
|
SteamVR_Input_EditorWindow.ClearProgressBar();
|
|
generating = false;
|
|
}
|
|
|
|
[DidReloadScripts]
|
|
private static void OnReload()
|
|
{
|
|
bool didGenerate = EditorPrefs.GetBool(generationNeedsReloadKey);
|
|
if (didGenerate)
|
|
{
|
|
EditorPrefs.SetBool(generationNeedsReloadKey, false);
|
|
|
|
if (string.IsNullOrEmpty(EditorSceneManager.GetActiveScene().path) == false)
|
|
EditorApplication.delayCall += ReloadScene;
|
|
}
|
|
}
|
|
|
|
|
|
public static void ReloadScene()
|
|
{
|
|
EditorPrefs.SetBool(generationNeedsReloadKey, false);
|
|
|
|
if (string.IsNullOrEmpty(EditorSceneManager.GetActiveScene().path) == false)
|
|
{
|
|
if (EditorSceneManager.GetActiveScene().isDirty)
|
|
{
|
|
EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo();
|
|
}
|
|
|
|
string previousPath = EditorSceneManager.GetActiveScene().path;
|
|
EditorSceneManager.NewScene(NewSceneSetup.EmptyScene);
|
|
EditorSceneManager.OpenScene(previousPath); //reload open scene to avoid any weird serialization
|
|
}
|
|
}
|
|
|
|
public static bool IsGenerating()
|
|
{
|
|
return generating;
|
|
}
|
|
|
|
public static void CancelGeneration()
|
|
{
|
|
generating = false;
|
|
|
|
}
|
|
|
|
private static List<CodeTypeDeclaration> setClasses = new List<CodeTypeDeclaration>();
|
|
|
|
private static void GenerationStep_CreateInitClass()
|
|
{
|
|
CodeCompileUnit compileUnit = new CodeCompileUnit();
|
|
|
|
CodeTypeDeclaration inputClass = CreatePartialInputClass(compileUnit);
|
|
|
|
CodeMemberMethod preinitMethod = CreateStaticMethod(inputClass, SteamVR_Input_Generator_Names.preinitializeMethodName, true);
|
|
|
|
string steamVRInputClassName = typeof(SteamVR_Input).Name;
|
|
|
|
AddStaticInvokeToMethod(preinitMethod, SteamVR_Input_Generator_Names.actionsClassName, startPreInitActionSetsMethodName);
|
|
AddStaticInvokeToMethod(preinitMethod, steamVRInputClassName, initializeActionSetDictionariesMethodName);
|
|
AddStaticInvokeToMethod(preinitMethod, SteamVR_Input_Generator_Names.actionsClassName, preInitActionsMethodName);
|
|
AddStaticInvokeToMethod(preinitMethod, SteamVR_Input_Generator_Names.actionsClassName, initializeActionsArraysMethodName);
|
|
AddStaticInvokeToMethod(preinitMethod, steamVRInputClassName, initializeActionDictionariesMethodName);
|
|
AddStaticInvokeToMethod(preinitMethod, steamVRInputClassName, finishPreInitActionSetsMethodName);
|
|
|
|
// Build the output file name.
|
|
string fullSourceFilePath = GetSourceFilePath(steamVRInputInitializationClass);
|
|
CreateFile(fullSourceFilePath, compileUnit);
|
|
}
|
|
|
|
private static void GenerationStep_CreateAssemblyDefinition()
|
|
{
|
|
string fullSourceFilePath = GetSourceFilePath(steamVRActionsAssemblyDefinition, ".asmdef");
|
|
|
|
if (File.Exists(fullSourceFilePath) == false)
|
|
{
|
|
SteamVR_Input_Unity_AssemblyFile_Definition actionsAssemblyDefinitionData = new SteamVR_Input_Unity_AssemblyFile_Definition();
|
|
actionsAssemblyDefinitionData.autoReferenced = true;
|
|
string jsonText = JsonConvert.SerializeObject(actionsAssemblyDefinitionData, Formatting.Indented, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Include });
|
|
File.WriteAllText(fullSourceFilePath, jsonText);
|
|
}
|
|
}
|
|
|
|
private static void GenerationStep_CreateActionSetClasses()
|
|
{
|
|
SteamVR_Input_EditorWindow.SetProgressBarText("Generating action set classes...", 0.25f);
|
|
|
|
SteamVR_Input.InitializeFile();
|
|
|
|
CreateActionsSubFolder();
|
|
|
|
setClasses = GenerateActionSetClasses();
|
|
|
|
Debug.LogFormat("<b>[SteamVR Input]</b> Created input script set classes: {0}", setClasses.Count);
|
|
}
|
|
|
|
private static void GenerationStep_CreateHelperClasses()
|
|
{
|
|
SteamVR_Input_EditorWindow.SetProgressBarText("Generating actions and actionsets classes...", 0.5f);
|
|
|
|
GenerateActionHelpers(steamVRInputActionsClass);
|
|
GenerateActionSetsHelpers(steamVRInputActionSetsClass);
|
|
|
|
string actionsFullpath = Path.Combine(GetClassPath(), steamVRInputActionsClass + ".cs");
|
|
string actionSetsFullpath = Path.Combine(GetClassPath(), steamVRInputActionSetsClass + ".cs");
|
|
|
|
Debug.LogFormat("<b>[SteamVR Input]</b> Created input script main classes: {0} and {1}", actionsFullpath, actionSetsFullpath);
|
|
}
|
|
|
|
|
|
private static void DeleteUnusedScripts()
|
|
{
|
|
string folderPath = GetSubFolderPath();
|
|
|
|
string[] files = Directory.GetFiles(folderPath);
|
|
|
|
List<string> toDelete = new List<string>();
|
|
|
|
for (int fileIndex = 0; fileIndex < files.Length; fileIndex++)
|
|
{
|
|
FileInfo file = new FileInfo(files[fileIndex]);
|
|
|
|
if (file.Name.EndsWith(".cs") || file.Name.EndsWith(".cs.meta"))
|
|
{
|
|
bool isSet = false;
|
|
if (SteamVR_Input.actionFile.action_sets.Any(set => string.Equals(GetSetClassName(set) + ".cs", file.Name, StringComparison.CurrentCultureIgnoreCase) ||
|
|
string.Equals(GetSetClassName(set) + ".cs.meta", file.Name, StringComparison.CurrentCultureIgnoreCase)))
|
|
{
|
|
isSet = true;
|
|
}
|
|
|
|
bool isAction = false;
|
|
if (SteamVR_Input.actionFile.actions.Any(action => string.Equals(action.codeFriendlyName + ".cs", file.Name, StringComparison.CurrentCultureIgnoreCase) ||
|
|
string.Equals(action.codeFriendlyName + ".cs.meta", file.Name, StringComparison.CurrentCultureIgnoreCase)))
|
|
{
|
|
|
|
isAction = true;
|
|
}
|
|
|
|
if (isSet == false && isAction == false)
|
|
{
|
|
toDelete.Add(files[fileIndex]);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (toDelete.Count > 0)
|
|
{
|
|
string filesToDelete = "";
|
|
foreach (string file in toDelete)
|
|
filesToDelete += file + "\n";
|
|
|
|
bool confirm = EditorUtility.DisplayDialog("SteamVR Input", "Would you like to delete the following unused input files:\n" + filesToDelete, "Delete", "No");
|
|
if (confirm)
|
|
{
|
|
foreach (string fileName in toDelete)
|
|
{
|
|
FileInfo file = new FileInfo(fileName);
|
|
file.IsReadOnly = false;
|
|
file.Delete();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void CreateActionsSubFolder()
|
|
{
|
|
string folderPath = GetSubFolderPath();
|
|
if (Directory.Exists(folderPath) == false)
|
|
{
|
|
Directory.CreateDirectory(folderPath);
|
|
}
|
|
}
|
|
|
|
public static void DeleteActionClassFiles()
|
|
{
|
|
DeleteActionClass(steamVRInputActionsClass);
|
|
DeleteActionClass(steamVRInputActionSetsClass);
|
|
|
|
string folderPath = GetSubFolderPath();
|
|
bool confirm = EditorUtility.DisplayDialog("Confirmation", "Are you absolutely sure you want to delete all code files in " + folderPath + "?", "Delete", "Cancel");
|
|
if (confirm)
|
|
{
|
|
DeleteActionObjects("*.cs*");
|
|
}
|
|
}
|
|
|
|
public static void DeleteGeneratedFolder()
|
|
{
|
|
string generatedFolderPath = GetClassPath();
|
|
string subFolderPath = GetSubFolderPath();
|
|
bool confirm = EditorUtility.DisplayDialog("Confirmation", "Are you absolutely sure you want to delete all code files in " + generatedFolderPath + "?", "Delete", "Cancel");
|
|
if (confirm)
|
|
{
|
|
DeleteActionObjects("*.cs*", generatedFolderPath);
|
|
|
|
DeleteActionObjects("*.cs*", subFolderPath);
|
|
}
|
|
}
|
|
|
|
public static void DeleteActionObjects(string filter, string folderPath = null)
|
|
{
|
|
if (folderPath == null)
|
|
folderPath = GetSubFolderPath();
|
|
|
|
string[] assets = Directory.GetFiles(folderPath, filter);
|
|
|
|
for (int assetIndex = 0; assetIndex < assets.Length; assetIndex++)
|
|
{
|
|
AssetDatabase.DeleteAsset(assets[assetIndex]);
|
|
}
|
|
|
|
Debug.LogFormat("<b>[SteamVR Input]</b> Deleted {0} files at path: {1}", assets.Length, folderPath);
|
|
}
|
|
|
|
private static void DeleteActionClass(string className)
|
|
{
|
|
string filePath = GetSourceFilePath(className);
|
|
if (File.Exists(filePath) == true)
|
|
{
|
|
AssetDatabase.DeleteAsset(filePath);
|
|
Debug.Log("<b>[SteamVR Input]</b> Deleted: " + filePath);
|
|
}
|
|
else
|
|
{
|
|
Debug.Log("<b>[SteamVR Input]</b> No file found at: " + filePath);
|
|
}
|
|
}
|
|
|
|
private static string GetTypeStringForAction(SteamVR_Input_ActionFile_Action action)
|
|
{
|
|
return GetTypeForAction(action).Name;
|
|
}
|
|
|
|
private static Type GetTypeForAction(SteamVR_Input_ActionFile_Action action)
|
|
{
|
|
string actionType = action.type.ToLower();
|
|
|
|
if (SteamVR_Input_ActionFile_ActionTypes.boolean == actionType)
|
|
{
|
|
return typeof(SteamVR_Action_Boolean);
|
|
}
|
|
|
|
if (SteamVR_Input_ActionFile_ActionTypes.vector1 == actionType)
|
|
{
|
|
return typeof(SteamVR_Action_Single);
|
|
}
|
|
|
|
if (SteamVR_Input_ActionFile_ActionTypes.vector2 == actionType)
|
|
{
|
|
return typeof(SteamVR_Action_Vector2);
|
|
}
|
|
|
|
if (SteamVR_Input_ActionFile_ActionTypes.vector3 == actionType)
|
|
{
|
|
return typeof(SteamVR_Action_Vector3);
|
|
}
|
|
|
|
if (SteamVR_Input_ActionFile_ActionTypes.pose == actionType)
|
|
{
|
|
return typeof(SteamVR_Action_Pose);
|
|
}
|
|
|
|
if (SteamVR_Input_ActionFile_ActionTypes.skeleton == actionType)
|
|
{
|
|
return typeof(SteamVR_Action_Skeleton);
|
|
}
|
|
|
|
if (SteamVR_Input_ActionFile_ActionTypes.vibration == actionType)
|
|
{
|
|
return typeof(SteamVR_Action_Vibration);
|
|
}
|
|
|
|
throw new System.Exception("unknown type (" + action.type + ") in actions file for action: " + action.name);
|
|
}
|
|
|
|
private static string GetClassPath()
|
|
{
|
|
string path = Path.Combine(SteamVR.GetSteamVRFolderParentPath(), SteamVR_Settings.instance.steamVRInputPath);
|
|
|
|
if (Directory.Exists(path) == false)
|
|
Directory.CreateDirectory(path);
|
|
|
|
return path;
|
|
}
|
|
|
|
private static string GetSubFolderPath()
|
|
{
|
|
return Path.Combine(GetClassPath(), steamVRInputActionSetClassesFolder);
|
|
}
|
|
|
|
private static string GetSourceFilePath(string classname, string suffix = ".cs")
|
|
{
|
|
string sourceFileName = string.Format("{0}{1}", classname, suffix);
|
|
|
|
return Path.Combine(GetClassPath(), sourceFileName);
|
|
}
|
|
|
|
private static bool fileChanged = false;
|
|
private static void CreateFile(string fullPath, CodeCompileUnit compileUnit)
|
|
{
|
|
// Generate the code with the C# code provider.
|
|
CSharpCodeProvider provider = new CSharpCodeProvider();
|
|
|
|
// Build the output file name.
|
|
string fullSourceFilePath = fullPath;
|
|
//Debug.Log("[SteamVR] Writing class to: " + fullSourceFilePath);
|
|
|
|
string path = GetClassPath();
|
|
|
|
string priorMD5 = null;
|
|
FileInfo file = new FileInfo(fullSourceFilePath);
|
|
if (file.Exists)
|
|
{
|
|
file.IsReadOnly = false;
|
|
priorMD5 = SteamVR_Utils.GetBadMD5HashFromFile(fullSourceFilePath);
|
|
}
|
|
|
|
// Create a TextWriter to a StreamWriter to the output file.
|
|
using (StreamWriter sw = new StreamWriter(fullSourceFilePath, false))
|
|
{
|
|
IndentedTextWriter tw = new IndentedTextWriter(sw, " ");
|
|
|
|
// Generate source code using the code provider.
|
|
provider.GenerateCodeFromCompileUnit(compileUnit, tw,
|
|
new CodeGeneratorOptions() { BracingStyle = "C" });
|
|
|
|
// Close the output file.
|
|
tw.Close();
|
|
|
|
string newMD5 = SteamVR_Utils.GetBadMD5HashFromFile(fullSourceFilePath);
|
|
|
|
if (priorMD5 != newMD5)
|
|
fileChanged = true;
|
|
}
|
|
|
|
//Debug.Log("[SteamVR] Complete! Input class at: " + fullSourceFilePath);
|
|
}
|
|
|
|
private const string getActionMethodParamName = "path";
|
|
private const string skipStateUpdatesParamName = "skipStateAndEventUpdates";
|
|
|
|
private static List<CodeTypeDeclaration> GenerateActionSetClasses()
|
|
{
|
|
List<CodeTypeDeclaration> setClasses = new List<CodeTypeDeclaration>();
|
|
|
|
for (int actionSetIndex = 0; actionSetIndex < SteamVR_Input.actionFile.action_sets.Count; actionSetIndex++)
|
|
{
|
|
SteamVR_Input_ActionFile_ActionSet actionSet = SteamVR_Input.actionFile.action_sets[actionSetIndex];
|
|
|
|
CodeTypeDeclaration setClass = CreateActionSetClass(actionSet);
|
|
|
|
setClasses.Add(setClass);
|
|
}
|
|
|
|
return setClasses;
|
|
}
|
|
|
|
private const string initializeActionDictionariesMethodName = "PreinitializeActionDictionaries";
|
|
private const string initializeActionSetDictionariesMethodName = "PreinitializeActionSetDictionaries";
|
|
|
|
private const string preInitActionsMethodName = "PreInitActions";
|
|
private const string initializeActionsArraysMethodName = "InitializeActionArrays";
|
|
|
|
private static void GenerateActionHelpers(string actionsClassFileName)
|
|
{
|
|
CodeCompileUnit compileUnit = new CodeCompileUnit();
|
|
|
|
CodeTypeDeclaration inputClass = CreatePartialInputClass(compileUnit);
|
|
|
|
CodeArrayCreateExpression actionsArray = new CodeArrayCreateExpression(new CodeTypeReference(typeof(SteamVR_Action)));
|
|
|
|
CodeArrayCreateExpression actionsInArray = new CodeArrayCreateExpression(new CodeTypeReference(typeof(ISteamVR_Action_In)));
|
|
|
|
CodeArrayCreateExpression actionsOutArray = new CodeArrayCreateExpression(new CodeTypeReference(typeof(ISteamVR_Action_Out)));
|
|
|
|
CodeArrayCreateExpression actionsVibrationArray = new CodeArrayCreateExpression(new CodeTypeReference(typeof(SteamVR_Action_Vibration)));
|
|
|
|
CodeArrayCreateExpression actionsPoseArray = new CodeArrayCreateExpression(new CodeTypeReference(typeof(SteamVR_Action_Pose)));
|
|
|
|
CodeArrayCreateExpression actionsSkeletonArray = new CodeArrayCreateExpression(new CodeTypeReference(typeof(SteamVR_Action_Skeleton)));
|
|
|
|
CodeArrayCreateExpression actionsBooleanArray = new CodeArrayCreateExpression(new CodeTypeReference(typeof(SteamVR_Action_Boolean)));
|
|
|
|
CodeArrayCreateExpression actionsSingleArray = new CodeArrayCreateExpression(new CodeTypeReference(typeof(SteamVR_Action_Single)));
|
|
|
|
CodeArrayCreateExpression actionsVector2Array = new CodeArrayCreateExpression(new CodeTypeReference(typeof(SteamVR_Action_Vector2)));
|
|
|
|
CodeArrayCreateExpression actionsVector3Array = new CodeArrayCreateExpression(new CodeTypeReference(typeof(SteamVR_Action_Vector3)));
|
|
|
|
CodeArrayCreateExpression actionsNonPoseNonSkeletonArray = new CodeArrayCreateExpression(new CodeTypeReference(typeof(ISteamVR_Action_In)));
|
|
|
|
|
|
//add the getaction method to
|
|
CodeMemberMethod actionsArraysInitMethod = CreateStaticMethod(inputClass, initializeActionsArraysMethodName, false);
|
|
CodeMemberMethod actionsPreInitMethod = CreateStaticMethod(inputClass, preInitActionsMethodName, false);
|
|
|
|
|
|
|
|
for (int actionSetIndex = 0; actionSetIndex < SteamVR_Input.actionFile.action_sets.Count; actionSetIndex++)
|
|
{
|
|
SteamVR_Input_ActionFile_ActionSet actionSet = SteamVR_Input.actionFile.action_sets[actionSetIndex];
|
|
string actionSetShortName = actionSet.shortName;
|
|
actionSetShortName = actionSetShortName.Substring(0, 1).ToLower() + actionSetShortName.Substring(1);
|
|
|
|
for (int actionIndex = 0; actionIndex < actionSet.actionsList.Count; actionIndex++)
|
|
{
|
|
SteamVR_Input_ActionFile_Action action = actionSet.actionsList[actionIndex];
|
|
string actionShortName = action.shortName;
|
|
|
|
string typeName = GetTypeStringForAction(action);
|
|
|
|
string codeFriendlyInstanceName;
|
|
if (actionSet.actionsList.Count(findAction => findAction.shortName == actionShortName) >= 2)
|
|
codeFriendlyInstanceName = string.Format("{0}_{1}_{2}", actionSetShortName, action.direction.ToString().ToLower(), actionShortName);
|
|
else
|
|
codeFriendlyInstanceName = string.Format("{0}_{1}", actionSetShortName, actionShortName);
|
|
|
|
|
|
CodeMemberField actionField = CreateFieldAndPropertyWrapper(inputClass, codeFriendlyInstanceName, typeName);
|
|
|
|
AddAssignActionStatement(actionsPreInitMethod, inputClass.Name, actionField.Name, action.name, typeName);
|
|
|
|
actionsArray.Initializers.Add(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(inputClass.Name), codeFriendlyInstanceName));
|
|
|
|
if (action.direction == SteamVR_ActionDirections.In)
|
|
{
|
|
actionsInArray.Initializers.Add(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(inputClass.Name), codeFriendlyInstanceName));
|
|
|
|
if (typeName == typeof(SteamVR_Action_Pose).Name)
|
|
{
|
|
actionsPoseArray.Initializers.Add(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(inputClass.Name), codeFriendlyInstanceName));
|
|
}
|
|
else if (typeName == typeof(SteamVR_Action_Skeleton).Name)
|
|
{
|
|
actionsSkeletonArray.Initializers.Add(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(inputClass.Name), codeFriendlyInstanceName));
|
|
}
|
|
else if (typeName == typeof(SteamVR_Action_Boolean).Name)
|
|
{
|
|
actionsBooleanArray.Initializers.Add(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(inputClass.Name), codeFriendlyInstanceName));
|
|
}
|
|
else if (typeName == typeof(SteamVR_Action_Single).Name)
|
|
{
|
|
actionsSingleArray.Initializers.Add(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(inputClass.Name), codeFriendlyInstanceName));
|
|
}
|
|
else if (typeName == typeof(SteamVR_Action_Vector2).Name)
|
|
{
|
|
actionsVector2Array.Initializers.Add(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(inputClass.Name), codeFriendlyInstanceName));
|
|
}
|
|
else if (typeName == typeof(SteamVR_Action_Vector3).Name)
|
|
{
|
|
actionsVector3Array.Initializers.Add(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(inputClass.Name), codeFriendlyInstanceName));
|
|
}
|
|
|
|
if ((typeName == typeof(SteamVR_Action_Skeleton).Name) == false && (typeName == typeof(SteamVR_Action_Pose).Name) == false)
|
|
{
|
|
actionsNonPoseNonSkeletonArray.Initializers.Add(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(inputClass.Name), codeFriendlyInstanceName));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
actionsVibrationArray.Initializers.Add(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(inputClass.Name), codeFriendlyInstanceName));
|
|
|
|
actionsOutArray.Initializers.Add(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(inputClass.Name), codeFriendlyInstanceName));
|
|
}
|
|
}
|
|
}
|
|
|
|
AddAssignStatement(actionsArraysInitMethod, SteamVR_Input_Generator_Names.actionsFieldName, actionsArray);
|
|
AddAssignStatement(actionsArraysInitMethod, SteamVR_Input_Generator_Names.actionsInFieldName, actionsInArray);
|
|
AddAssignStatement(actionsArraysInitMethod, SteamVR_Input_Generator_Names.actionsOutFieldName, actionsOutArray);
|
|
AddAssignStatement(actionsArraysInitMethod, SteamVR_Input_Generator_Names.actionsVibrationFieldName, actionsVibrationArray);
|
|
AddAssignStatement(actionsArraysInitMethod, SteamVR_Input_Generator_Names.actionsPoseFieldName, actionsPoseArray);
|
|
AddAssignStatement(actionsArraysInitMethod, SteamVR_Input_Generator_Names.actionsBooleanFieldName, actionsBooleanArray);
|
|
AddAssignStatement(actionsArraysInitMethod, SteamVR_Input_Generator_Names.actionsSingleFieldName, actionsSingleArray);
|
|
AddAssignStatement(actionsArraysInitMethod, SteamVR_Input_Generator_Names.actionsVector2FieldName, actionsVector2Array);
|
|
AddAssignStatement(actionsArraysInitMethod, SteamVR_Input_Generator_Names.actionsVector3FieldName, actionsVector3Array);
|
|
AddAssignStatement(actionsArraysInitMethod, SteamVR_Input_Generator_Names.actionsSkeletonFieldName, actionsSkeletonArray);
|
|
AddAssignStatement(actionsArraysInitMethod, SteamVR_Input_Generator_Names.actionsNonPoseNonSkeletonIn, actionsNonPoseNonSkeletonArray);
|
|
|
|
|
|
// Build the output file name.
|
|
string fullSourceFilePath = GetSourceFilePath(actionsClassFileName);
|
|
CreateFile(fullSourceFilePath, compileUnit);
|
|
}
|
|
|
|
|
|
private const string startPreInitActionSetsMethodName = "StartPreInitActionSets";
|
|
private const string finishPreInitActionSetsMethodName = "PreinitializeFinishActionSets";
|
|
|
|
private static void GenerateActionSetsHelpers(string actionSetsClassFileName)
|
|
{
|
|
CodeCompileUnit compileUnit = new CodeCompileUnit();
|
|
|
|
CodeTypeDeclaration inputClass = CreatePartialInputClass(compileUnit);
|
|
|
|
|
|
CodeMemberMethod startPreInitActionSetsMethod = CreateStaticMethod(inputClass, startPreInitActionSetsMethodName, false);
|
|
|
|
CodeArrayCreateExpression actionSetsArray = new CodeArrayCreateExpression(new CodeTypeReference(typeof(SteamVR_ActionSet)));
|
|
|
|
for (int actionSetIndex = 0; actionSetIndex < SteamVR_Input.actionFile.action_sets.Count; actionSetIndex++)
|
|
{
|
|
SteamVR_Input_ActionFile_ActionSet actionSet = SteamVR_Input.actionFile.action_sets[actionSetIndex];
|
|
|
|
string shortName = GetValidIdentifier(actionSet.shortName);
|
|
|
|
string codeFriendlyInstanceName = shortName;
|
|
|
|
string setTypeName = GetSetClassName(actionSet);
|
|
|
|
CodeMemberField actionSetField = CreateFieldAndPropertyWrapper(inputClass, shortName, setTypeName);
|
|
|
|
AddAssignActionSetStatement(startPreInitActionSetsMethod, inputClass.Name, actionSetField.Name, actionSet.name, setTypeName);
|
|
|
|
actionSetsArray.Initializers.Add(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(inputClass.Name), codeFriendlyInstanceName));
|
|
}
|
|
|
|
AddAssignStatement(startPreInitActionSetsMethod, SteamVR_Input_Generator_Names.actionSetsFieldName, actionSetsArray);
|
|
|
|
// Build the output file name.
|
|
string fullSourceFilePath = GetSourceFilePath(actionSetsClassFileName);
|
|
CreateFile(fullSourceFilePath, compileUnit);
|
|
}
|
|
|
|
private static CSharpCodeProvider provider = new CSharpCodeProvider();
|
|
private static string GetValidIdentifier(string name)
|
|
{
|
|
string newName = name.Replace("-", "_");
|
|
newName = provider.CreateValidIdentifier(newName);
|
|
return newName;
|
|
}
|
|
|
|
public static MethodInfo GetMethodInfo<T>(Expression<Action<T>> expression)
|
|
{
|
|
var member = expression.Body as MethodCallExpression;
|
|
|
|
if (member != null)
|
|
return member.Method;
|
|
|
|
throw new ArgumentException("Expression is not a method", "expression");
|
|
}
|
|
|
|
private static CodeTypeDeclaration CreatePartialInputClass(CodeCompileUnit compileUnit)
|
|
{
|
|
CodeNamespace codeNamespace = new CodeNamespace(typeof(SteamVR_Input).Namespace);
|
|
codeNamespace.Imports.Add(new CodeNamespaceImport("System"));
|
|
codeNamespace.Imports.Add(new CodeNamespaceImport("UnityEngine"));
|
|
compileUnit.Namespaces.Add(codeNamespace);
|
|
|
|
CodeTypeDeclaration inputClass = new CodeTypeDeclaration(SteamVR_Input_Generator_Names.actionsClassName);
|
|
inputClass.IsPartial = true;
|
|
codeNamespace.Types.Add(inputClass);
|
|
|
|
return inputClass;
|
|
}
|
|
|
|
private static string GetSetClassName(SteamVR_Input_ActionFile_ActionSet set)
|
|
{
|
|
return actionSetClassNamePrefix + set.shortName;
|
|
}
|
|
|
|
private const string inActionFieldPrefix = "in_";
|
|
private const string outActionFieldPrefix = "out_";
|
|
private const string setFinishPreInitializeMethodName = "FinishPreInitialize";
|
|
private static CodeTypeDeclaration CreateActionSetClass(SteamVR_Input_ActionFile_ActionSet set)
|
|
{
|
|
CodeCompileUnit compileUnit = new CodeCompileUnit();
|
|
|
|
CodeNamespace codeNamespace = new CodeNamespace(typeof(SteamVR_Input).Namespace);
|
|
codeNamespace.Imports.Add(new CodeNamespaceImport("System"));
|
|
codeNamespace.Imports.Add(new CodeNamespaceImport("UnityEngine"));
|
|
compileUnit.Namespaces.Add(codeNamespace);
|
|
|
|
CodeTypeDeclaration setClass = new CodeTypeDeclaration(GetSetClassName(set));
|
|
setClass.BaseTypes.Add(typeof(SteamVR_ActionSet));
|
|
setClass.Attributes = MemberAttributes.Public;
|
|
codeNamespace.Types.Add(setClass);
|
|
|
|
string actionSetShortName = set.shortName;
|
|
actionSetShortName = actionSetShortName.Substring(0, 1).ToLower() + actionSetShortName.Substring(1);
|
|
|
|
foreach (var inAction in set.actionsInList)
|
|
{
|
|
string inActionName = inAction.shortName;
|
|
if (set.actionsOutList.Any(outAction => inAction.shortName == outAction.shortName))
|
|
inActionName = inActionFieldPrefix + inActionName;
|
|
|
|
string actionClassPropertyName = string.Format("{0}_{1}", actionSetShortName, inActionName);
|
|
|
|
CreateActionPropertyWrapper(setClass, SteamVR_Input_Generator_Names.actionsClassName, inActionName, actionClassPropertyName, inAction);
|
|
}
|
|
|
|
foreach (var outAction in set.actionsOutList)
|
|
{
|
|
string outActionName = outAction.shortName;
|
|
if (set.actionsInList.Any(inAction => inAction.shortName == outAction.shortName))
|
|
outActionName = outActionFieldPrefix + outActionName;
|
|
|
|
string actionClassPropertyName = string.Format("{0}_{1}", actionSetShortName, outActionName);
|
|
|
|
CreateActionPropertyWrapper(setClass, SteamVR_Input_Generator_Names.actionsClassName, outActionName, actionClassPropertyName, outAction);
|
|
}
|
|
|
|
// Build the output file name.
|
|
string folderPath = GetSubFolderPath();
|
|
string fullSourceFilePath = Path.Combine(folderPath, setClass.Name + ".cs");
|
|
CreateFile(fullSourceFilePath, compileUnit);
|
|
|
|
return setClass;
|
|
}
|
|
|
|
private static CodeMemberMethod CreateStaticMethod(CodeTypeDeclaration inputClass, string methodName, bool isPublic)
|
|
{
|
|
CodeMemberMethod method = new CodeMemberMethod();
|
|
method.Name = methodName;
|
|
|
|
if (isPublic)
|
|
method.Attributes = MemberAttributes.Public | MemberAttributes.Static;
|
|
else
|
|
method.Attributes = MemberAttributes.Private | MemberAttributes.Static;
|
|
|
|
inputClass.Members.Add(method);
|
|
return method;
|
|
}
|
|
|
|
private static CodeMemberMethod CreateStaticConstructorMethod(CodeTypeDeclaration inputClass)
|
|
{
|
|
CodeTypeConstructor method = new CodeTypeConstructor();
|
|
method.Attributes = MemberAttributes.Static;
|
|
|
|
inputClass.Members.Add(method);
|
|
return method;
|
|
}
|
|
|
|
private static CodeMemberField CreateField(CodeTypeDeclaration inputClass, string fieldName, Type fieldType, bool isStatic)
|
|
{
|
|
if (fieldType == null)
|
|
Debug.Log("null fieldType");
|
|
|
|
CodeMemberField field = new CodeMemberField();
|
|
field.Name = fieldName;
|
|
field.Type = new CodeTypeReference(fieldType);
|
|
field.Attributes = MemberAttributes.Public;
|
|
if (isStatic)
|
|
field.Attributes |= MemberAttributes.Static;
|
|
|
|
inputClass.Members.Add(field);
|
|
|
|
return field;
|
|
}
|
|
|
|
private static CodeMemberField CreateFieldAndPropertyWrapper(CodeTypeDeclaration inputClass, string name, string type)
|
|
{
|
|
CodeMemberField actionField = CreatePrivateField(inputClass, name, type, true);
|
|
|
|
CodeMemberProperty actionProperty = CreateStaticProperty(inputClass, name, type, actionField);
|
|
|
|
return actionField;
|
|
}
|
|
|
|
private static CodeMemberProperty CreateStaticProperty(CodeTypeDeclaration inputClass, string propertyName, string propertyType, CodeMemberField privateField)
|
|
{
|
|
CodeMemberProperty property = new CodeMemberProperty();
|
|
property.Name = propertyName;
|
|
property.Type = new CodeTypeReference(propertyType);
|
|
property.Attributes = MemberAttributes.Public | MemberAttributes.Static;
|
|
|
|
CodeFieldReferenceExpression fieldReference = new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(inputClass.Name), privateField.Name);
|
|
CodeMethodInvokeExpression invokeExpression = new CodeMethodInvokeExpression(fieldReference, "GetCopy");
|
|
invokeExpression.Method.TypeArguments.Add(property.Type);
|
|
|
|
CodeMethodReturnStatement returnStatement = new CodeMethodReturnStatement(invokeExpression);
|
|
|
|
property.GetStatements.Add(returnStatement);
|
|
|
|
inputClass.Members.Add(property);
|
|
|
|
return property;
|
|
}
|
|
|
|
private static CodeMemberProperty CreateActionPropertyWrapper(CodeTypeDeclaration addToClass, string actionClass, string propertyName, string actionClassFieldName, SteamVR_Input_ActionFile_Action action)
|
|
{
|
|
string propertyType = GetTypeStringForAction(action);
|
|
|
|
CodeMemberProperty property = new CodeMemberProperty();
|
|
property.Name = propertyName;
|
|
property.Type = new CodeTypeReference(propertyType);
|
|
property.Attributes = MemberAttributes.Public;
|
|
|
|
CodeFieldReferenceExpression fieldReference = new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(actionClass), actionClassFieldName);
|
|
|
|
CodeMethodReturnStatement returnStatement = new CodeMethodReturnStatement(fieldReference);
|
|
|
|
property.GetStatements.Add(returnStatement);
|
|
|
|
addToClass.Members.Add(property);
|
|
|
|
return property;
|
|
}
|
|
|
|
private const string privateFieldPrefix = "p_";
|
|
private static CodeMemberField CreatePrivateField(CodeTypeDeclaration inputClass, string fieldName, string fieldType, bool isStatic)
|
|
{
|
|
return CreateField(inputClass, privateFieldPrefix + fieldName, fieldType, isStatic, false);
|
|
}
|
|
|
|
private static CodeMemberField CreateField(CodeTypeDeclaration inputClass, string fieldName, string fieldType, bool isStatic, bool isPublic = true)
|
|
{
|
|
CodeMemberField field = new CodeMemberField();
|
|
field.Name = fieldName;
|
|
field.Type = new CodeTypeReference(fieldType);
|
|
if (isPublic)
|
|
field.Attributes = MemberAttributes.Public;
|
|
else
|
|
field.Attributes = MemberAttributes.Private;
|
|
|
|
if (isStatic)
|
|
field.Attributes |= MemberAttributes.Static;
|
|
|
|
inputClass.Members.Add(field);
|
|
|
|
return field;
|
|
}
|
|
|
|
private static CodeMethodInvokeExpression AddStaticInvokeToMethod(CodeMemberMethod methodToAddTo, string classToInvoke, string invokeMethodName)
|
|
{
|
|
CodeMethodInvokeExpression invokeMethod = new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(
|
|
new CodeTypeReferenceExpression(classToInvoke), invokeMethodName));
|
|
|
|
methodToAddTo.Statements.Add(invokeMethod);
|
|
|
|
return invokeMethod;
|
|
}
|
|
|
|
private static void AddAssignStatement(CodeMemberMethod methodToAddTo, string fieldToAssign, CodeArrayCreateExpression array)
|
|
{
|
|
methodToAddTo.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(typeof(SteamVR_Input)), fieldToAssign), array));
|
|
}
|
|
|
|
private const string createActionMethodName = "Create";
|
|
private const string createActionSetMethodName = "Create";
|
|
private const string getActionFromPathMethodName = "GetActionFromPath";
|
|
|
|
//grab = SteamVR_Action.Create<SteamVR_Action_Boolean>("path");
|
|
private static void AddAssignActionStatement(CodeMemberMethod methodToAddTo, string actionClassName, string fieldToAssign, string actionPath, string actionType)
|
|
{
|
|
CodeMethodInvokeExpression invokeMethod = new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(new CodeTypeReferenceExpression(typeof(SteamVR_Action).Name), createActionMethodName));
|
|
|
|
invokeMethod.Method.TypeArguments.Add(actionType);
|
|
invokeMethod.Parameters.Add(new CodePrimitiveExpression(actionPath));
|
|
|
|
methodToAddTo.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(actionClassName), fieldToAssign), new CodeCastExpression(new CodeTypeReference(actionType), invokeMethod)));
|
|
}
|
|
private static void AddAssignActionSetStatement(CodeMemberMethod methodToAddTo, string actionClassName, string fieldToAssign, string actionSetName, string actionSetType)
|
|
{
|
|
CodeMethodInvokeExpression invokeMethod = new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(new CodeTypeReferenceExpression(typeof(SteamVR_ActionSet).Name), createActionSetMethodName));
|
|
|
|
invokeMethod.Method.TypeArguments.Add(actionSetType);
|
|
invokeMethod.Parameters.Add(new CodePrimitiveExpression(actionSetName));
|
|
|
|
methodToAddTo.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(actionClassName), fieldToAssign), new CodeCastExpression(new CodeTypeReference(actionSetType), invokeMethod)));
|
|
}
|
|
private static void AddAssignLocalActionStatement(CodeMemberMethod methodToAddTo, string fieldToAssign, string actionPath, string actionType, bool create)
|
|
{
|
|
CodeMethodInvokeExpression invokeMethod;
|
|
|
|
if (create)
|
|
invokeMethod = new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(new CodeTypeReferenceExpression(typeof(SteamVR_Action).Name), createActionMethodName));
|
|
else
|
|
invokeMethod = new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(new CodeTypeReferenceExpression(typeof(SteamVR_Input).Name), getActionFromPathMethodName));
|
|
|
|
invokeMethod.Method.TypeArguments.Add(actionType);
|
|
invokeMethod.Parameters.Add(new CodePrimitiveExpression(actionPath));
|
|
|
|
methodToAddTo.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), fieldToAssign), new CodeCastExpression(new CodeTypeReference(actionType), invokeMethod)));
|
|
}
|
|
private static void AddAssignNewInstanceStatement(CodeMemberMethod methodToAddTo, string fieldToAssign, string fieldType)
|
|
{
|
|
CodeObjectCreateExpression createExpression = new CodeObjectCreateExpression(new CodeTypeReference(fieldType));
|
|
|
|
methodToAddTo.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), fieldToAssign), createExpression));
|
|
}
|
|
|
|
private static CodeConditionStatement CreateStringCompareStatement(CodeMemberMethod methodToAddTo, string action, string paramName, string returnActionName)
|
|
{
|
|
MethodInfo stringEqualsMethodInfo = GetMethodInfo<string>(set => string.Equals(null, null, StringComparison.CurrentCultureIgnoreCase));
|
|
CodeTypeReferenceExpression stringType = new CodeTypeReferenceExpression(typeof(string));
|
|
CodePrimitiveExpression actionName = new CodePrimitiveExpression(action);
|
|
CodeVariableReferenceExpression pathName = new CodeVariableReferenceExpression(paramName);
|
|
CodeVariableReferenceExpression caseInvariantName = new CodeVariableReferenceExpression("StringComparison.CurrentCultureIgnoreCase");
|
|
CodeMethodInvokeExpression stringCompare = new CodeMethodInvokeExpression(stringType, stringEqualsMethodInfo.Name, pathName, actionName, caseInvariantName);
|
|
CodeMethodReturnStatement returnAction = new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(typeof(SteamVR_Input)), returnActionName));
|
|
|
|
CodeConditionStatement condition = new CodeConditionStatement(stringCompare, returnAction);
|
|
methodToAddTo.Statements.Add(condition);
|
|
|
|
return condition;
|
|
}
|
|
}
|
|
}
|