Added Unity project files

This commit is contained in:
2026-06-07 16:58:24 +01:00
parent 3cc05d260b
commit 23bbcab156
3942 changed files with 453676 additions and 0 deletions

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ce43b6297c145894390ff674ed7598a1
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8abd1cc8bd6eb464c886df3e4b6d6104
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,10 @@

namespace UdonSharp.Lib.Internal
{
public static class CompilerConstants
{
public const string UsbTypeIDHeapKey = "__refl_typeid";
public const string UsbTypeNameHeapKey = "__refl_typename";
public const string UsbTypeIDArrayHeapKey = "__refl_typeids";
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a434385f6fdf35b4a92bbe1db28fc52a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,486 @@

using System;
using JetBrains.Annotations;
using UnityEngine;
using VRC.Udon;
// These are invalid in C#, but valid in U# because UdonSharpBehaviours are weakly considered UdonBehaviours
// ReSharper disable PossibleInvalidCastException
// ReSharper disable SuspiciousTypeConversion.Global
namespace UdonSharp.Lib.Internal
{
public static class GetComponentShim
{
#region GetComponent
[UsedImplicitly]
internal static T GetComponent<T>(Component instance) where T : UdonSharpBehaviour
{
UdonBehaviour[] udonBehaviours = (UdonBehaviour[])instance.GetComponents(typeof(UdonBehaviour));
long targetID = UdonSharpBehaviour.GetUdonTypeID<T>();
foreach (UdonBehaviour behaviour in udonBehaviours)
{
#if UNITY_EDITOR
if (behaviour.GetProgramVariableType(CompilerConstants.UsbTypeIDHeapKey) == null)
continue;
#endif
object idValue = behaviour.GetProgramVariable(CompilerConstants.UsbTypeIDHeapKey);
if (idValue != null && (long) idValue == targetID)
return (T)(Component)behaviour;
}
return null;
}
[UsedImplicitly]
internal static T GetComponentInChildren<T>(Component instance) where T : UdonSharpBehaviour
{
UdonBehaviour[] udonBehaviours = (UdonBehaviour[])instance.GetComponentsInChildren(typeof(UdonBehaviour));
long targetID = UdonSharpBehaviour.GetUdonTypeID<T>();
foreach (UdonBehaviour behaviour in udonBehaviours)
{
#if UNITY_EDITOR
if (behaviour.GetProgramVariableType(CompilerConstants.UsbTypeIDHeapKey) == null)
continue;
#endif
object idValue = behaviour.GetProgramVariable(CompilerConstants.UsbTypeIDHeapKey);
if (idValue != null && (long) idValue == targetID)
return (T)(Component)behaviour;
}
return null;
}
[UsedImplicitly]
internal static T GetComponentInChildren<T>(Component instance, bool includeInactive) where T : UdonSharpBehaviour
{
UdonBehaviour[] udonBehaviours = (UdonBehaviour[])instance.GetComponentsInChildren(typeof(UdonBehaviour), includeInactive);
long targetID = UdonSharpBehaviour.GetUdonTypeID<T>();
foreach (UdonBehaviour behaviour in udonBehaviours)
{
#if UNITY_EDITOR
if (behaviour.GetProgramVariableType(CompilerConstants.UsbTypeIDHeapKey) == null)
continue;
#endif
object idValue = behaviour.GetProgramVariable(CompilerConstants.UsbTypeIDHeapKey);
if (idValue != null && (long) idValue == targetID)
return (T)(Component)behaviour;
}
return null;
}
[UsedImplicitly]
internal static T GetComponentInParent<T>(Component instance) where T : UdonSharpBehaviour
{
UdonBehaviour[] udonBehaviours = (UdonBehaviour[])instance.GetComponentsInParent(typeof(UdonBehaviour));
long targetID = UdonSharpBehaviour.GetUdonTypeID<T>();
foreach (UdonBehaviour behaviour in udonBehaviours)
{
#if UNITY_EDITOR
if (behaviour.GetProgramVariableType(CompilerConstants.UsbTypeIDHeapKey) == null)
continue;
#endif
object idValue = behaviour.GetProgramVariable(CompilerConstants.UsbTypeIDHeapKey);
if (idValue != null && (long) idValue == targetID)
return (T)(Component)behaviour;
}
return null;
}
[UsedImplicitly]
internal static T GetComponentInParent<T>(Component instance, bool includeInactive) where T : UdonSharpBehaviour
{
UdonBehaviour[] udonBehaviours = (UdonBehaviour[])instance.GetComponentsInParent(typeof(UdonBehaviour), includeInactive);
long targetID = UdonSharpBehaviour.GetUdonTypeID<T>();
foreach (UdonBehaviour behaviour in udonBehaviours)
{
#if UNITY_EDITOR
if (behaviour.GetProgramVariableType(CompilerConstants.UsbTypeIDHeapKey) == null)
continue;
#endif
object idValue = behaviour.GetProgramVariable(CompilerConstants.UsbTypeIDHeapKey);
if (idValue != null && (long) idValue == targetID)
return (T)(Component)behaviour;
}
return null;
}
#endregion
#region GetComponents
private static T[] GetComponentsOfType<T>(UdonBehaviour[] inputArray) where T : UdonSharpBehaviour
{
long targetID = UdonSharpBehaviour.GetUdonTypeID<T>();
int arraySize = 0;
foreach (UdonBehaviour behaviour in inputArray)
{
#if UNITY_EDITOR
if (behaviour.GetProgramVariableType(CompilerConstants.UsbTypeIDHeapKey) == null)
continue;
#endif
object typeID = behaviour.GetProgramVariable(CompilerConstants.UsbTypeIDHeapKey);
if (typeID != null && (long) typeID == targetID)
arraySize++;
}
Component[] foundBehaviours = new Component[arraySize];
int targetIdx = 0;
foreach (UdonBehaviour behaviour in inputArray)
{
#if UNITY_EDITOR
if (behaviour.GetProgramVariableType(CompilerConstants.UsbTypeIDHeapKey) == null)
continue;
#endif
object typeID = behaviour.GetProgramVariable(CompilerConstants.UsbTypeIDHeapKey);
if (typeID != null && (long) typeID == targetID)
foundBehaviours[targetIdx++] = behaviour;
}
return (T[])foundBehaviours;
}
[UsedImplicitly]
internal static T[] GetComponents<T>(Component instance) where T : UdonSharpBehaviour
{
UdonBehaviour[] instanceBehaviours = (UdonBehaviour[])instance.GetComponents(typeof(UdonBehaviour));
return GetComponentsOfType<T>(instanceBehaviours);
}
[UsedImplicitly]
internal static T[] GetComponentsInChildren<T>(Component instance) where T : UdonSharpBehaviour
{
UdonBehaviour[] instanceBehaviours = (UdonBehaviour[])instance.GetComponentsInChildren(typeof(UdonBehaviour));
return GetComponentsOfType<T>(instanceBehaviours);
}
[UsedImplicitly]
internal static T[] GetComponentsInChildren<T>(Component instance, bool includeInactive) where T : UdonSharpBehaviour
{
UdonBehaviour[] instanceBehaviours = (UdonBehaviour[])instance.GetComponentsInChildren(typeof(UdonBehaviour), includeInactive);
return GetComponentsOfType<T>(instanceBehaviours);
}
[UsedImplicitly]
internal static T[] GetComponentsInParent<T>(Component instance) where T : UdonSharpBehaviour
{
UdonBehaviour[] instanceBehaviours = (UdonBehaviour[])instance.GetComponentsInParent(typeof(UdonBehaviour));
return GetComponentsOfType<T>(instanceBehaviours);
}
[UsedImplicitly]
internal static T[] GetComponentsInParent<T>(Component instance, bool includeInactive) where T : UdonSharpBehaviour
{
UdonBehaviour[] instanceBehaviours = (UdonBehaviour[])instance.GetComponentsInParent(typeof(UdonBehaviour), includeInactive);
return GetComponentsOfType<T>(instanceBehaviours);
}
#endregion
#region Get UdonSharpBehaviour components
// For doing GetComponent(s)<UdonSharpBehaviour>() specifically, just checks for existence of ID variable
private static UdonSharpBehaviour GetUdonSharpComponent(Component[] behaviours)
{
foreach (UdonBehaviour behaviour in (UdonBehaviour[])behaviours)
{
#if UNITY_EDITOR
if (behaviour.GetProgramVariableType(CompilerConstants.UsbTypeIDHeapKey) == null)
continue;
#endif
object idValue = behaviour.GetProgramVariable(CompilerConstants.UsbTypeIDHeapKey);
if (idValue != null)
return (UdonSharpBehaviour)(Component)behaviour;
}
return null;
}
[UsedImplicitly]
internal static UdonSharpBehaviour GetComponentUSB(Component instance)
{
return GetUdonSharpComponent(instance.GetComponents(typeof(UdonBehaviour)));
}
[UsedImplicitly]
internal static UdonSharpBehaviour GetComponentInChildrenUSB(Component instance)
{
return GetUdonSharpComponent(instance.GetComponentsInChildren(typeof(UdonBehaviour)));
}
[UsedImplicitly]
internal static UdonSharpBehaviour GetComponentInChildrenUSB(Component instance, bool includeInactive)
{
return GetUdonSharpComponent(instance.GetComponentsInChildren(typeof(UdonBehaviour), includeInactive));
}
[UsedImplicitly]
internal static UdonSharpBehaviour GetComponentInParentUSB(Component instance)
{
return GetUdonSharpComponent(instance.GetComponentsInParent(typeof(UdonBehaviour)));
}
[UsedImplicitly]
internal static UdonSharpBehaviour GetComponentInParentUSB(Component instance, bool includeInactive)
{
return GetUdonSharpComponent(instance.GetComponentsInParent(typeof(UdonBehaviour), includeInactive));
}
// GetComponents
private static UdonSharpBehaviour[] GetUdonSharpComponents(Component[] inputArray)
{
int arraySize = 0;
foreach (UdonBehaviour behaviour in (UdonBehaviour[])inputArray)
{
#if UNITY_EDITOR
if (behaviour.GetProgramVariableType(CompilerConstants.UsbTypeIDHeapKey) == null)
continue;
#endif
object typeID = behaviour.GetProgramVariable(CompilerConstants.UsbTypeIDHeapKey);
if (typeID != null)
arraySize++;
}
Component[] foundBehaviours = new Component[arraySize];
int targetIdx = 0;
foreach (UdonBehaviour behaviour in (UdonBehaviour[])inputArray)
{
#if UNITY_EDITOR
if (behaviour.GetProgramVariableType(CompilerConstants.UsbTypeIDHeapKey) == null)
continue;
#endif
object typeID = behaviour.GetProgramVariable(CompilerConstants.UsbTypeIDHeapKey);
if (typeID != null)
foundBehaviours[targetIdx++] = behaviour;
}
return (UdonSharpBehaviour[])foundBehaviours;
}
[UsedImplicitly]
internal static UdonSharpBehaviour[] GetComponentsUSB(Component instance)
{
return GetUdonSharpComponents(instance.GetComponents(typeof(UdonBehaviour)));
}
[UsedImplicitly]
internal static UdonSharpBehaviour[] GetComponentsInChildrenUSB(Component instance)
{
return GetUdonSharpComponents(instance.GetComponentsInChildren(typeof(UdonBehaviour)));
}
[UsedImplicitly]
internal static UdonSharpBehaviour[] GetComponentsInChildrenUSB(Component instance, bool includeInactive)
{
return GetUdonSharpComponents(instance.GetComponentsInChildren(typeof(UdonBehaviour), includeInactive));
}
[UsedImplicitly]
internal static UdonSharpBehaviour[] GetComponentsInParentUSB(Component instance)
{
return GetUdonSharpComponents(instance.GetComponentsInParent(typeof(UdonBehaviour)));
}
[UsedImplicitly]
internal static UdonSharpBehaviour[] GetComponentsInParentUSB(Component instance, bool includeInactive)
{
return GetUdonSharpComponents(instance.GetComponentsInParent(typeof(UdonBehaviour), includeInactive));
}
#endregion
#region Get user component that has some inheritance
// Types with inheritance build a type array that we can do a lookup into
private static T GetUdonSharpComponentInherited<T>(Component[] behaviours) where T : UdonSharpBehaviour
{
long targetID = UdonSharpBehaviour.GetUdonTypeID<T>();
foreach (UdonBehaviour behaviour in (UdonBehaviour[])behaviours)
{
#if UNITY_EDITOR
if (behaviour.GetProgramVariableType(CompilerConstants.UsbTypeIDArrayHeapKey) == null)
continue;
#endif
object idValue = behaviour.GetProgramVariable(CompilerConstants.UsbTypeIDArrayHeapKey);
if (idValue != null)
{
if (Array.IndexOf((Array)idValue, targetID) != -1)
return (T)(Component)behaviour;
}
}
return null;
}
[UsedImplicitly]
internal static T GetComponentI<T>(Component instance) where T : UdonSharpBehaviour
{
return GetUdonSharpComponentInherited<T>(instance.GetComponents(typeof(UdonBehaviour)));
}
[UsedImplicitly]
internal static T GetComponentInChildrenI<T>(Component instance) where T : UdonSharpBehaviour
{
return GetUdonSharpComponentInherited<T>(instance.GetComponentsInChildren(typeof(UdonBehaviour)));
}
[UsedImplicitly]
internal static T GetComponentInChildrenI<T>(Component instance, bool includeInactive) where T : UdonSharpBehaviour
{
return GetUdonSharpComponentInherited<T>(instance.GetComponentsInChildren(typeof(UdonBehaviour), includeInactive));
}
[UsedImplicitly]
internal static T GetComponentInParentI<T>(Component instance) where T : UdonSharpBehaviour
{
return GetUdonSharpComponentInherited<T>(instance.GetComponentsInParent(typeof(UdonBehaviour)));
}
[UsedImplicitly]
internal static T GetComponentInParentI<T>(Component instance, bool includeInactive) where T : UdonSharpBehaviour
{
return GetUdonSharpComponentInherited<T>(instance.GetComponentsInParent(typeof(UdonBehaviour), includeInactive));
}
// GetComponents
private static T[] GetUdonSharpComponentsInherited<T>(Component[] behaviours) where T : UdonSharpBehaviour
{
long targetID = UdonSharpBehaviour.GetUdonTypeID<T>();
int arraySize = 0;
foreach (UdonBehaviour behaviour in (UdonBehaviour[])behaviours)
{
#if UNITY_EDITOR
if (behaviour.GetProgramVariableType(CompilerConstants.UsbTypeIDArrayHeapKey) == null)
continue;
#endif
object idValue = behaviour.GetProgramVariable(CompilerConstants.UsbTypeIDArrayHeapKey);
if (idValue != null)
{
if (Array.IndexOf((Array)idValue, targetID) != -1)
arraySize++;
}
}
Component[] foundBehaviours = new Component[arraySize];
int targetIdx = 0;
foreach (UdonBehaviour behaviour in (UdonBehaviour[])behaviours)
{
#if UNITY_EDITOR
if (behaviour.GetProgramVariableType(CompilerConstants.UsbTypeIDArrayHeapKey) == null)
continue;
#endif
object idValue = behaviour.GetProgramVariable(CompilerConstants.UsbTypeIDArrayHeapKey);
if (idValue != null)
{
if (Array.IndexOf((Array)idValue, targetID) != -1)
foundBehaviours[targetIdx++] = behaviour;
}
}
return (T[])foundBehaviours;
}
[UsedImplicitly]
internal static T[] GetComponentsI<T>(Component instance) where T : UdonSharpBehaviour
{
return GetUdonSharpComponentsInherited<T>(instance.GetComponents(typeof(UdonBehaviour)));
}
[UsedImplicitly]
internal static T[] GetComponentsInChildrenI<T>(Component instance) where T : UdonSharpBehaviour
{
return GetUdonSharpComponentsInherited<T>(instance.GetComponentsInChildren(typeof(UdonBehaviour)));
}
[UsedImplicitly]
internal static T[] GetComponentsInChildrenI<T>(Component instance, bool includeInactive) where T : UdonSharpBehaviour
{
return GetUdonSharpComponentsInherited<T>(instance.GetComponentsInChildren(typeof(UdonBehaviour), includeInactive));
}
[UsedImplicitly]
internal static T[] GetComponentsInParentI<T>(Component instance) where T : UdonSharpBehaviour
{
return GetUdonSharpComponentsInherited<T>(instance.GetComponentsInParent(typeof(UdonBehaviour)));
}
[UsedImplicitly]
internal static T[] GetComponentsInParentI<T>(Component instance, bool includeInactive) where T : UdonSharpBehaviour
{
return GetUdonSharpComponentsInherited<T>(instance.GetComponentsInParent(typeof(UdonBehaviour), includeInactive));
}
#endregion
#region Broken VRC component getcomponent workaround
[UsedImplicitly]
internal static T GetComponentVRC<T>(Component instance) where T : Component
{
return (T)instance.GetComponent(typeof(T));
}
[UsedImplicitly]
internal static T GetComponentInChildrenVRC<T>(Component instance) where T : Component
{
return (T)instance.GetComponentInChildren(typeof(T));
}
[UsedImplicitly]
internal static T GetComponentInChildrenVRC<T>(Component instance, bool includeInactive) where T : Component
{
return (T)instance.GetComponentInChildren(typeof(T), includeInactive);
}
[UsedImplicitly]
internal static T GetComponentInParentVRC<T>(Component instance) where T : Component
{
return (T)instance.GetComponentInParent(typeof(T));
}
private static T[] ConvertToTArray<T>(Component[] components) where T : Component
{
T[] newArr = new T[components.Length];
Array.Copy(components, newArr, components.Length);
return newArr;
}
[UsedImplicitly]
internal static T[] GetComponentsVRC<T>(Component instance) where T : Component
{
return ConvertToTArray<T>(instance.GetComponents(typeof(T)));
}
[UsedImplicitly]
internal static T[] GetComponentsInChildrenVRC<T>(Component instance) where T : Component
{
return ConvertToTArray<T>(instance.GetComponentsInChildren(typeof(T)));
}
[UsedImplicitly]
internal static T[] GetComponentsInChildrenVRC<T>(Component instance, bool includeInactive) where T : Component
{
return ConvertToTArray<T>(instance.GetComponentsInChildren(typeof(T), includeInactive));
}
[UsedImplicitly]
internal static T[] GetComponentsInParentVRC<T>(Component instance) where T : Component
{
return ConvertToTArray<T>(instance.GetComponentsInParent(typeof(T)));
}
[UsedImplicitly]
internal static T[] GetComponentsInParentVRC<T>(Component instance, bool includeInactive) where T : Component
{
return ConvertToTArray<T>(instance.GetComponentsInParent(typeof(T), includeInactive));
}
#endregion
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8232339c6b1acb3469fef9fd4ed71ad6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,59 @@

using JetBrains.Annotations;
using UnityEngine;
namespace UdonSharp.Lib.Internal
{
public static class InstantiationShim
{
// Gets aliased to VRCInstantiate by the compiler
private static GameObject Instantiate_Extern(GameObject original) => null;
[UsedImplicitly]
public static GameObject Instantiate(GameObject original)
{
return Instantiate_Extern(original);
}
[UsedImplicitly]
public static GameObject Instantiate(GameObject original, Vector3 position, Quaternion rotation)
{
GameObject instantiatedObject = Instantiate(original);
Transform objectTransform = instantiatedObject.transform;
objectTransform.SetPositionAndRotation(position, rotation);
return instantiatedObject;
}
[UsedImplicitly]
public static GameObject Instantiate(GameObject original, Transform parent)
{
GameObject instantiatedObject = Instantiate(original);
Transform objectTransform = instantiatedObject.transform;
objectTransform.SetParent(parent, false);
return instantiatedObject;
}
[UsedImplicitly]
public static GameObject Instantiate(GameObject original, Transform parent, bool worldPositionStays)
{
GameObject instantiatedObject = Instantiate(original);
Transform objectTransform = instantiatedObject.transform;
objectTransform.SetParent(parent, worldPositionStays);
return instantiatedObject;
}
[UsedImplicitly]
public static GameObject Instantiate(GameObject original, Vector3 position, Quaternion rotation, Transform parent)
{
GameObject instantiatedObject = Instantiate(original);
Transform objectTransform = instantiatedObject.transform;
objectTransform.SetPositionAndRotation(position, rotation);
objectTransform.SetParent(parent, true);
return instantiatedObject;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 65860a727d016b5419fa81530b1ab589
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,25 @@

using JetBrains.Annotations;
using VRC.Udon;
namespace UdonSharp.Lib.Internal
{
public static class UdonSharpBehaviourMethods
{
[UsedImplicitly]
internal static long GetUdonTypeID(UdonBehaviour behaviour)
{
object id = behaviour.GetProgramVariable(CompilerConstants.UsbTypeIDHeapKey);
if (id == null)
return 0;
return (long)id;
}
[UsedImplicitly]
internal static string GetUdonTypeName(UdonBehaviour behaviour)
{
return (string)behaviour.GetProgramVariable(CompilerConstants.UsbTypeNameHeapKey);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 31a99fcb8a0560a468dca1ec5706eaaf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,16 @@
{
"name": "UdonSharp.Lib",
"references": [
"GUID:3c1bc1267eab5884ebe7f232c09ee0d9",
"GUID:99835874ee819da44948776e0df4ff1d"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": false,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: e1a67d4778ffb214390ddafa61c1a557
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,16 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5136146375e9a0a498a72a0091b40cc1, type: 3}
m_Name: UdonSharp.Lib
m_EditorClassIdentifier:
sourceAssembly: {fileID: 5897886265953266890, guid: e1a67d4778ffb214390ddafa61c1a557,
type: 3}

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 891645f3172a08b47b8fdf0d6006b667
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3d1354616d45a9644b3c92a34f62c8c1
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,219 @@

#define UDONSHARP_LOC_DEBUG
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Xml.Linq;
using UdonSharp.Updater;
using UnityEditor;
using UnityEngine;
namespace UdonSharp.Localization
{
/// <summary>
/// Locale string ID list used to get a specified localized string
///
/// Used for UI, compiler messages, warnings, and errors
/// The int ID of a given LocStr is not reliable and is liable to change so do not depend on the integer value of it.
///
/// Enums are grouped and prefixed by the type of string they represent:
/// `UI_`: UI related strings for UI elements, for instance the Compile All UdonSharp Programs button
/// `CI_`: Compiler info messages, ex. Compile of X scripts finished in Y
/// `CW_`: Compiler warning messages, ex. Multiple UdonSharpProgramAssets referencing the same script
/// `CE_`: Compiler error messages, ex. Most compile errors
/// </summary>
public enum LocStr
{
UI_TestLocStr,
UI_CompileProgram,
UI_CompileAllPrograms,
UI_SendCustomEvent,
UI_TriggerInteract,
UI_ProgramSource,
UI_ProgramScript,
UI_SourceScript,
UI_SerializedUdonProgramAsset,
CE_UdonSharpBehaviourConstructorsNotSupported,
CE_PartialMethodsNotSupported,
CE_UdonSharpBehaviourGenericMethodsNotSupported,
CE_LocalMethodsNotSupported,
CE_NodeNotSupported,
CE_UdonMethodNotExposed,
CE_InitializerListsNotSupported,
CE_UdonFieldNotExposed,
Length,
}
/// <summary>
/// Instance of the currently selected locale, with lookups for appropriate messages and errors, falls back to en-US for missing strings
/// </summary>
internal class LocaleInstance
{
Dictionary<LocStr, string> localizedStringLookup = new Dictionary<LocStr, string>();
public LocaleInstance(string locale)
{
string localeDir = UdonSharpLocator.LocalizationPath;
string fileContents = "";
try
{
fileContents = LoadLocale(Path.Combine(localeDir, locale.ToLowerInvariant() + ".resx"));
}
catch (Exception e)
{
Debug.LogError($"Failed to load locale {locale}\nException: {e}");
}
XName nameAttributeID = XName.Get("name");
XName valueAttributeID = XName.Get("value");
using (StringReader strReader = new StringReader(fileContents))
{
XElement xml = XElement.Load(strReader, LoadOptions.PreserveWhitespace);
foreach (var element in xml.Elements())
{
if (element.Name != "data")
continue;
string elementName = element.Attribute(nameAttributeID).Value;
string elementValue = element.Element(valueAttributeID).Value;
if (Enum.TryParse(elementName, out LocStr elementResult))
{
localizedStringLookup.Add(elementResult, elementValue);
}
#if UDONSHARP_LOC_DEBUG
else
{
Debug.LogWarning($"Could not find corresponding enum for key '{elementName}'");
}
#endif
}
}
#if UDONSHARP_LOC_DEBUG
for (int i = 0; i < (int)LocStr.Length; ++i)
{
if (!localizedStringLookup.ContainsKey((LocStr)i))
Debug.LogWarning($"Did not find string for key '{(LocStr)i}'");
}
#endif
}
static string LoadLocale(string path)
{
if (!File.Exists(path))
throw new System.IO.FileNotFoundException($"Could not find locale file at {path}, make sure you have installed UdonSharp following the installation instructions.");
return ReadFileTextSync(path, 1f);
}
// Stolen from UdonSharpUtils because it's in a different assembly, todo: move it somewhere more accessible
static string ReadFileTextSync(string filePath, float timeoutSeconds)
{
bool sourceLoaded = false;
string fileText = "";
System.DateTime startTime = System.DateTime.Now;
while (true)
{
System.IO.IOException exception = null;
try
{
fileText = System.IO.File.ReadAllText(filePath);
sourceLoaded = true;
}
catch (System.IO.IOException e)
{
exception = e;
if (e is System.IO.FileNotFoundException ||
e is System.IO.DirectoryNotFoundException)
throw e;
}
if (sourceLoaded)
break;
else
System.Threading.Thread.Sleep(20);
System.TimeSpan timeFromStart = System.DateTime.Now - startTime;
if (timeFromStart.TotalSeconds > timeoutSeconds)
{
UnityEngine.Debug.LogError($"Timeout when attempting to read file {filePath}");
if (exception != null)
throw exception;
}
}
return fileText;
}
public string GetString(LocStr locStr)
{
if (localizedStringLookup.TryGetValue(locStr, out string foundStr))
{
return foundStr;
}
return "";
}
}
/// <summary>
/// Localization manager
/// </summary>
public static class Loc
{
private static LocaleInstance _instance;
public static void InitLocalization()
{
if (_instance == null)
ReloadLocalization();
}
internal static void ReloadLocalization()
{
_instance = new LocaleInstance("en-us");
}
public static string Get(LocStr locKey)
{
InitLocalization();
return _instance.GetString(locKey);
}
public static string Format(LocStr locKey, params object[] parameters)
{
InitLocalization();
return string.Format(_instance.GetString(locKey), parameters);
}
}
#if UDONSHARP_LOC_DEBUG && UNITY_EDITOR
internal class LocalePostProcessor : AssetPostprocessor
{
static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
{
foreach (string str in importedAssets)
{
if (Path.GetExtension(str) == ".resx")
{
Loc.ReloadLocalization();
break;
}
}
}
}
#endif
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b3874ffdfd4fe1d49a68990563c15819
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6525b4c44fdf9404dbe87bab83ba6cfb
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,95 @@
fileFormatVersion: 2
guid: bf93e699136730c4bb47d4aa04c1a922
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 1
validateReferences: 1
platformData:
- first:
: Any
second:
enabled: 0
settings:
Exclude Editor: 0
Exclude Linux: 1
Exclude Linux64: 1
Exclude LinuxUniversal: 1
Exclude OSXUniversal: 1
Exclude Win: 1
Exclude Win64: 1
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 1
settings:
CPU: AnyCPU
DefaultValueInitialized: true
OS: AnyOS
- first:
Facebook: Win
second:
enabled: 0
settings:
CPU: None
- first:
Facebook: Win64
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: Linux
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: Linux64
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: LinuxUniversal
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: OSXUniversal
second:
enabled: 0
settings:
CPU: x86
- first:
Standalone: Win
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: Win64
second:
enabled: 0
settings:
CPU: None
- first:
Windows Store Apps: WindowsStoreApps
second:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,102 @@
fileFormatVersion: 2
guid: a19a5153c23411a46923731185430b93
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 1
validateReferences: 0
platformData:
- first:
: Any
second:
enabled: 0
settings:
Exclude Android: 1
Exclude Editor: 0
Exclude Linux: 1
Exclude Linux64: 1
Exclude LinuxUniversal: 1
Exclude OSXUniversal: 1
Exclude Win: 1
Exclude Win64: 1
- first:
Android: Android
second:
enabled: 0
settings:
CPU: ARMv7
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 1
settings:
CPU: AnyCPU
DefaultValueInitialized: true
OS: AnyOS
- first:
Facebook: Win
second:
enabled: 0
settings:
CPU: None
- first:
Facebook: Win64
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: Linux
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: Linux64
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: LinuxUniversal
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: OSXUniversal
second:
enabled: 0
settings:
CPU: x86
- first:
Standalone: Win
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: Win64
second:
enabled: 0
settings:
CPU: None
- first:
Windows Store Apps: WindowsStoreApps
second:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,93 @@
fileFormatVersion: 2
guid: 94ef9729b9524a34ea4b868379e06f48
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 1
validateReferences: 0
platformData:
- first:
: Any
second:
enabled: 0
settings:
Exclude Editor: 0
Exclude Linux: 1
Exclude Linux64: 1
Exclude LinuxUniversal: 1
Exclude OSXUniversal: 1
Exclude Win: 1
Exclude Win64: 1
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 1
settings:
DefaultValueInitialized: true
- first:
Facebook: Win
second:
enabled: 0
settings:
CPU: None
- first:
Facebook: Win64
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: Linux
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: Linux64
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: LinuxUniversal
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: OSXUniversal
second:
enabled: 0
settings:
CPU: x86
- first:
Standalone: Win
second:
enabled: 0
settings:
CPU: None
- first:
Standalone: Win64
second:
enabled: 0
settings:
CPU: None
- first:
Windows Store Apps: WindowsStoreApps
second:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,33 @@
fileFormatVersion: 2
guid: 15eaba9fdc5c0b34a86676edbbb3afb0
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 0
platformData:
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
Windows Store Apps: WindowsStoreApps
second:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,16 @@
{
"name": "UdonSharp.Runtime",
"references": [
"VRC.Udon.Serialization.OdinSerializer",
"VRC.Udon"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 99835874ee819da44948776e0df4ff1d
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,123 @@

using JetBrains.Annotations;
using System;
namespace UdonSharp
{
// At the moment Udon syncing is in a very early state.
// This is very liable to be changed with changes to Udon syncing in the future.
[PublicAPI]
public enum UdonSyncMode
{
/// <summary>
/// Not synced, this is the same as not adding the UdonSynced attribute
/// </summary>
// [Obsolete("This is getting removed, do not use a UdonSynced attribute with NotSynced")]
NotSynced,
/// <summary>
/// Synced with no interpolation, this is the same as just using `[UdonSynced]`
/// </summary>
None,
/// <summary>
/// Lerped sync
/// </summary>
Linear,
/// <summary>
/// Smoothed sync
/// </summary>
Smooth,
}
[PublicAPI]
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
public class UdonSyncedAttribute : Attribute
{
public UdonSyncMode NetworkSyncType { get; }
public UdonSyncedAttribute(UdonSyncMode networkSyncTypeIn = UdonSyncMode.None)
{
NetworkSyncType = networkSyncTypeIn;
}
}
/// <summary>
/// Used to enforce consistent sync modes per behaviour since Udon Behaviours are usually authored with a specific type of sync in mind
/// and it's tedious to set and make sure the sync type is correct on each behaviour.
/// This also allows U# to verify that you're using types and variable tweening modes that are supported for the given sync mode
/// </summary>
[PublicAPI]
public enum BehaviourSyncMode
{
/// <summary>
/// Nothing is enforced and the behaviours can be set to either sync type by the user. This is the default when no BehaviourSyncTypeAttribute is specified on a behaviour
/// </summary>
Any,
/// <summary>
/// Enforces no synced variables on the behaviour and hides the selection dropdown in the UI for the sync mode. Nothing is synced and SendCustomNetworkEvent will not work on the behaviour
/// </summary>
None,
/// <summary>
/// Enforces no synced variables on the behaviour and hides the selection dropdown in the UI for the sync mode, SendCustomNetworkEvent() will still work on this behaviour
/// </summary>
NoVariableSync,
/// <summary>
/// Enforces continuous sync mode on the behaviour
/// </summary>
Continuous,
/// <summary>
/// Enforces manual sync mode on the behaviour
/// </summary>
Manual,
}
[PublicAPI]
[AttributeUsage(AttributeTargets.Class)]
public class UdonBehaviourSyncModeAttribute : Attribute
{
public BehaviourSyncMode behaviourSyncMode = BehaviourSyncMode.Any;
public UdonBehaviourSyncModeAttribute(BehaviourSyncMode behaviourSyncMode)
{
this.behaviourSyncMode = behaviourSyncMode;
}
}
/// <summary>
/// Marks a method that can be called recursively in U#.
/// This should be used on the methods that are being called recursively, you do not need to mark methods that are calling recursive methods with this.
/// This attribute has a performance overhead which makes the marked method perform slower and usually generate more garbage. So use it only on methods that **need** to be called recursively.
/// </summary>
[PublicAPI]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public class RecursiveMethodAttribute : Attribute
{
}
/// <summary>
/// Calls the target property's setter when the marked field is modified by network sync or SetProgramVariable().
/// Fields marked with this will instead have the target property's setter called. The setter is expected to set the field if you want the field to change.
/// </summary>
[PublicAPI]
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
public class FieldChangeCallbackAttribute : Attribute
{
public string CallbackPropertyName { get; private set; }
private FieldChangeCallbackAttribute() { }
public FieldChangeCallbackAttribute(string targetPropertyName)
{
CallbackPropertyName = targetPropertyName;
}
}
/// <summary>
/// Marks a field to only run its initializer at compile time. This may be used on particularly expensive initializers, or initializers that run code which is not currently valid in Udon.
/// </summary>
[PublicAPI]
[AttributeUsage(AttributeTargets.Field)]
[Obsolete("This attribute currently does nothing")]
public class CompileInitAttribute : Attribute
{}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ad41a74bd6fbe7346b4389a33103f5d4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,457 @@

using System;
using System.Linq;
using System.Reflection;
using JetBrains.Annotations;
using UnityEngine;
using VRC.Udon.Common.Interfaces;
using System.Diagnostics;
using UnityEngine.Serialization;
using VRC.Dynamics;
#if VRC_ENABLE_PLAYER_PERSISTENCE || VRC_ENABLE_INSTANCE_PERSISTENCE
using VRC.SDK3.Persistence;
#endif
using VRC.SDKBase;
using VRC.SDK3.Data;
using VRC.Udon.Serialization.OdinSerializer;
namespace UdonSharp
{
public abstract class UdonSharpBehaviour : MonoBehaviour, ISerializationCallbackReceiver, ISupportsPrefabSerialization
{
// Stubs for the UdonBehaviour functions that emulate Udon behavior
/// <summary>
/// Gets a field from the target UdonSharpBehaviour
/// </summary>
[PublicAPI]
public object GetProgramVariable(string name)
{
FieldInfo variableField = GetType().GetField(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (variableField == null)
return null;
return variableField.GetValue(this);
}
/// <summary>
/// Sets a field on the target UdonSharpBehaviour.
/// <remarks>Make sure you are setting a value on the behaviour with a compatible type to the given <paramref name="value"/>, or you may run into unexpected crashes.</remarks>
/// </summary>
[PublicAPI]
public void SetProgramVariable(string name, object value)
{
FieldInfo variableField = GetType().GetField(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (variableField == null)
return;
FieldChangeCallbackAttribute fieldChangeCallback = variableField.GetCustomAttribute<FieldChangeCallbackAttribute>();
if (fieldChangeCallback != null)
{
PropertyInfo targetProperty = variableField.DeclaringType.GetProperty(fieldChangeCallback.CallbackPropertyName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
if (targetProperty == null)
return;
MethodInfo setMethod = targetProperty.GetSetMethod(true);
if (setMethod == null)
return;
setMethod.Invoke(this, new object[] { value });
}
else
{
variableField.SetValue(this, value);
}
}
/// <summary>
/// Calls the method with <paramref name="eventName"/> on the target UdonSharpBehaviour. The target method must be public and have no parameters.
/// <remarks>The method is allowed to return a value, but the return value will not be accessible via this method.</remarks>
/// </summary>
/// <param name="eventName">Name of the method to call</param>
[PublicAPI]
public void SendCustomEvent(string eventName)
{
#if UNITY_EDITOR
if (_udonSharpBackingUdonBehaviour != null) // If this is a proxy, we need to check if this is a valid call to SendCustomEvent, since animation events can call it when they shouldn't
{
StackFrame frame = new StackFrame(1); // Get the frame of the calling method
// If the calling method is null, this has been called from native code which indicates it was called by Unity, which we don't want on proxies
if (frame.GetMethod() == null)
return;
}
#endif
MethodInfo eventMethod = GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance).FirstOrDefault(e => e.Name == eventName && e.GetParameters().Length == 0);
if (eventMethod != null)
{
eventMethod.Invoke(this, new object[] { });
}
}
/// <summary>
/// Sends a networked call to the method with <paramref name="eventName"/> on the target UdonSharpBehaviour. The target method must be public and have no parameters.
/// <remarks>The method is allowed to return a value, but the return value will not be accessible via this method.
/// Methods with an underscore as their first character will not be callable via SendCustomNetworkEvent, unless they have a [NetworkCallable] attribute.</remarks>
/// </summary>
/// <param name="target">Whether to send this event to only the owner of the target behaviour's GameObject, or to everyone in the instance</param>
/// <param name="eventName">Name of the method to call</param>
[PublicAPI]
public void SendCustomNetworkEvent(NetworkEventTarget target, string eventName)
{
SendCustomEvent(eventName);
}
/// <summary>
/// Sends a networked call to the method with <paramref name="eventName"/> on the target UdonSharpBehaviour. The target method must be public and have one parameter.
/// <remarks>The method is allowed to return a value, but the return value will not be accessible via this method.
/// Methods with an underscore as their first character will not be callable via SendCustomNetworkEvent, unless they have a [NetworkCallable] attribute..</remarks>
/// </summary>
/// <param name="target">Whether to send this event to only the owner of the target behaviour's GameObject, or to everyone in the instance</param>
/// <param name="eventName">Name of the method to call</param>
[PublicAPI]
public void SendCustomNetworkEvent(NetworkEventTarget target, string eventName, object parameter0)
{
MethodInfo eventMethod = GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance).FirstOrDefault(e => e.Name == eventName && e.GetParameters().Length == 1);
eventMethod?.Invoke(this, new object[] { parameter0 });
}
/// <summary>
/// Sends a networked call to the method with <paramref name="eventName"/> on the target UdonSharpBehaviour. The target method must be public and have two parameters.
/// <remarks>The method is allowed to return a value, but the return value will not be accessible via this method.
/// Methods with an underscore as their first character will not be callable via SendCustomNetworkEvent, unless they have a [NetworkCallable] attribute..</remarks>
/// </summary>
/// <param name="target">Whether to send this event to only the owner of the target behaviour's GameObject, or to everyone in the instance</param>
/// <param name="eventName">Name of the method to call</param>
[PublicAPI]
public void SendCustomNetworkEvent(NetworkEventTarget target, string eventName, object parameter0, object parameter1)
{
MethodInfo eventMethod = GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance).FirstOrDefault(e => e.Name == eventName && e.GetParameters().Length == 2);
eventMethod?.Invoke(this, new object[] { parameter0, parameter1 });
}
/// <summary>
/// Sends a networked call to the method with <paramref name="eventName"/> on the target UdonSharpBehaviour. The target method must be public and have three parameters.
/// <remarks>The method is allowed to return a value, but the return value will not be accessible via this method.
/// Methods with an underscore as their first character will not be callable via SendCustomNetworkEvent, unless they have a [NetworkCallable] attribute..</remarks>
/// </summary>
/// <param name="target">Whether to send this event to only the owner of the target behaviour's GameObject, or to everyone in the instance</param>
/// <param name="eventName">Name of the method to call</param>
[PublicAPI]
public void SendCustomNetworkEvent(NetworkEventTarget target, string eventName, object parameter0, object parameter1, object parameter2)
{
MethodInfo eventMethod = GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance).FirstOrDefault(e => e.Name == eventName && e.GetParameters().Length == 3);
eventMethod?.Invoke(this, new object[] { parameter0, parameter1, parameter2 });
}
/// <summary>
/// Sends a networked call to the method with <paramref name="eventName"/> on the target UdonSharpBehaviour. The target method must be public and have four parameters.
/// <remarks>The method is allowed to return a value, but the return value will not be accessible via this method.
/// Methods with an underscore as their first character will not be callable via SendCustomNetworkEvent, unless they have a [NetworkCallable] attribute..</remarks>
/// </summary>
/// <param name="target">Whether to send this event to only the owner of the target behaviour's GameObject, or to everyone in the instance</param>
/// <param name="eventName">Name of the method to call</param>
[PublicAPI]
public void SendCustomNetworkEvent(NetworkEventTarget target, string eventName, object parameter0, object parameter1, object parameter2, object parameter3)
{
MethodInfo eventMethod = GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance).FirstOrDefault(e => e.Name == eventName && e.GetParameters().Length == 4);
eventMethod?.Invoke(this, new object[] { parameter0, parameter1, parameter2, parameter3 });
}
/// <summary>
/// Sends a networked call to the method with <paramref name="eventName"/> on the target UdonSharpBehaviour. The target method must be public and have five parameters.
/// <remarks>The method is allowed to return a value, but the return value will not be accessible via this method.
/// Methods with an underscore as their first character will not be callable via SendCustomNetworkEvent, unless they have a [NetworkCallable] attribute..</remarks>
/// </summary>
/// <param name="target">Whether to send this event to only the owner of the target behaviour's GameObject, or to everyone in the instance</param>
/// <param name="eventName">Name of the method to call</param>
[PublicAPI]
public void SendCustomNetworkEvent(NetworkEventTarget target, string eventName, object parameter0, object parameter1, object parameter2, object parameter3, object parameter4)
{
MethodInfo eventMethod = GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance).FirstOrDefault(e => e.Name == eventName && e.GetParameters().Length == 5);
eventMethod?.Invoke(this, new object[] { parameter0, parameter1, parameter2, parameter3, parameter4 });
}
/// <summary>
/// Sends a networked call to the method with <paramref name="eventName"/> on the target UdonSharpBehaviour. The target method must be public and have five parameters.
/// <remarks>The method is allowed to return a value, but the return value will not be accessible via this method.
/// Methods with an underscore as their first character will not be callable via SendCustomNetworkEvent, unless they have a [NetworkCallable] attribute..</remarks>
/// </summary>
/// <param name="target">Whether to send this event to only the owner of the target behaviour's GameObject, or to everyone in the instance</param>
/// <param name="eventName">Name of the method to call</param>
[PublicAPI]
public void SendCustomNetworkEvent(NetworkEventTarget target, string eventName, object parameter0, object parameter1, object parameter2, object parameter3, object parameter4, object parameter5)
{
MethodInfo eventMethod = GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance).FirstOrDefault(e => e.Name == eventName && e.GetParameters().Length == 6);
eventMethod?.Invoke(this, new object[] { parameter0, parameter1, parameter2, parameter3, parameter4, parameter5 });
}
/// <summary>
/// Sends a networked call to the method with <paramref name="eventName"/> on the target UdonSharpBehaviour. The target method must be public and have five parameters.
/// <remarks>The method is allowed to return a value, but the return value will not be accessible via this method.
/// Methods with an underscore as their first character will not be callable via SendCustomNetworkEvent, unless they have a [NetworkCallable] attribute..</remarks>
/// </summary>
/// <param name="target">Whether to send this event to only the owner of the target behaviour's GameObject, or to everyone in the instance</param>
/// <param name="eventName">Name of the method to call</param>
[PublicAPI]
public void SendCustomNetworkEvent(NetworkEventTarget target, string eventName, object parameter0, object parameter1, object parameter2, object parameter3, object parameter4, object parameter5, object parameter6)
{
MethodInfo eventMethod = GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance).FirstOrDefault(e => e.Name == eventName && e.GetParameters().Length == 7);
eventMethod?.Invoke(this, new object[] { parameter0, parameter1, parameter2, parameter3, parameter4, parameter5, parameter6 });
}
/// <summary>
/// Sends a networked call to the method with <paramref name="eventName"/> on the target UdonSharpBehaviour. The target method must be public and have five parameters.
/// <remarks>The method is allowed to return a value, but the return value will not be accessible via this method.
/// Methods with an underscore as their first character will not be callable via SendCustomNetworkEvent, unless they have a [NetworkCallable] attribute..</remarks>
/// </summary>
/// <param name="target">Whether to send this event to only the owner of the target behaviour's GameObject, or to everyone in the instance</param>
/// <param name="eventName">Name of the method to call</param>
[PublicAPI]
public void SendCustomNetworkEvent(NetworkEventTarget target, string eventName, object parameter0, object parameter1, object parameter2, object parameter3, object parameter4, object parameter5, object parameter6, object parameter7)
{
MethodInfo eventMethod = GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance).FirstOrDefault(e => e.Name == eventName && e.GetParameters().Length == 8);
eventMethod?.Invoke(this, new object[] { parameter0, parameter1, parameter2, parameter3, parameter4, parameter5, parameter6, parameter7 });
}
/// <summary>
/// Executes target event after delaySeconds. If 0.0 delaySeconds is specified, will execute the following frame
/// </summary>
/// <param name="eventName"></param>
/// <param name="delaySeconds"></param>
/// <param name="eventTiming"></param>
[PublicAPI]
public void SendCustomEventDelayedSeconds(string eventName, float delaySeconds, VRC.Udon.Common.Enums.EventTiming eventTiming = VRC.Udon.Common.Enums.EventTiming.Update) { }
/// <summary>
/// Executes target event after delayFrames have passed. If 0 frames is specified, will execute the following frame. In effect 0 frame delay and 1 fame delay are the same on this method.
/// </summary>
/// <param name="eventName"></param>
/// <param name="delayFrames"></param>
/// <param name="eventTiming"></param>
[PublicAPI]
public void SendCustomEventDelayedFrames(string eventName, int delayFrames, VRC.Udon.Common.Enums.EventTiming eventTiming = VRC.Udon.Common.Enums.EventTiming.Update) { }
/// <summary>
/// Disables Interact events on this UdonBehaviour and disables the interact outline on the object this is attached to
/// </summary>
[PublicAPI]
public bool DisableInteractive { get; set; }
/// <summary>
/// Access the text that shows up on interactable tooltips
/// </summary>
[PublicAPI]
public string InteractionText { get; set; }
[Obsolete("This method is obsolete, use Object.Instantiate(gameObject) instead")]
protected static GameObject VRCInstantiate(GameObject original)
{
return Instantiate(original);
}
/// <summary>
/// Requests a network serialization of the target UdonSharpBehaviour.
/// <remarks>This will only function if the UdonSharpBehaviour is set to Manual sync mode and the person calling RequestSerialization() is the owner of the object.</remarks>
/// </summary>
[PublicAPI]
public void RequestSerialization() { }
// Stubs for builtin UdonSharp methods to get type info
private static long GetUdonTypeID(System.Type type)
{
return Internal.UdonSharpInternalUtility.GetTypeID(type);
}
/// <summary>
/// Returns the unique ID of the UdonBehavior user type. Will return 0 if the UdonBehavior has no ID, which usually means that it's a graph program.
/// </summary>
/// <returns></returns>
[PublicAPI]
public long GetUdonTypeID()
{
return GetUdonTypeID(GetType());
}
/// <summary>
/// Gets the type ID for the given T, usually used for checking UdonSharpBehaviour type equality
/// </summary>
[PublicAPI]
public static long GetUdonTypeID<T>() where T : UdonSharpBehaviour
{
return GetUdonTypeID(typeof(T));
}
private static string GetUdonTypeName(System.Type type)
{
return Internal.UdonSharpInternalUtility.GetTypeName(type);
}
[PublicAPI]
public string GetUdonTypeName()
{
return GetUdonTypeName(GetType());
}
[PublicAPI]
public static string GetUdonTypeName<T>() where T : UdonSharpBehaviour
{
return GetUdonTypeName(typeof(T));
}
// Method stubs for auto completion
[PublicAPI] public virtual void PostLateUpdate() { }
[PublicAPI] public virtual void Interact() { }
[PublicAPI] public virtual void OnAvatarChanged(VRC.SDKBase.VRCPlayerApi player) { }
[PublicAPI] public virtual void OnAvatarEyeHeightChanged(VRC.SDKBase.VRCPlayerApi player, float prevEyeHeightAsMeters) { }
[PublicAPI] public virtual void OnDrop() { }
[PublicAPI] public virtual void OnOwnershipTransferred(VRC.SDKBase.VRCPlayerApi player) { }
[PublicAPI] public virtual void OnMasterTransferred(VRC.SDKBase.VRCPlayerApi newMaster) { }
[PublicAPI] public virtual void OnPickup() { }
[PublicAPI] public virtual void OnPickupUseDown() { }
[PublicAPI] public virtual void OnPickupUseUp() { }
[PublicAPI] public virtual void OnPlayerJoined(VRC.SDKBase.VRCPlayerApi player) { }
[PublicAPI] public virtual void OnPlayerLeft(VRC.SDKBase.VRCPlayerApi player) { }
[PublicAPI] public virtual void OnSpawn() { }
[PublicAPI] public virtual void OnStationEntered(VRC.SDKBase.VRCPlayerApi player) { }
[PublicAPI] public virtual void OnStationExited(VRC.SDKBase.VRCPlayerApi player) { }
[PublicAPI] public virtual void OnVideoEnd() { }
[PublicAPI] public virtual void OnVideoError(VRC.SDK3.Components.Video.VideoError videoError) { }
[PublicAPI] public virtual void OnVideoLoop() { }
[PublicAPI] public virtual void OnVideoPause() { }
[PublicAPI] public virtual void OnVideoPlay() { }
[PublicAPI] public virtual void OnVideoReady() { }
[PublicAPI] public virtual void OnVideoStart() { }
[PublicAPI] public virtual void OnPreSerialization() { }
[PublicAPI] public virtual void OnDeserialization() { }
[PublicAPI] public virtual void OnDeserialization(VRC.Udon.Common.DeserializationResult result) { }
#if VRC_ENABLE_PLAYER_PERSISTENCE
[PublicAPI] public virtual void OnPlayerDataUpdated(VRC.SDKBase.VRCPlayerApi player, VRC.SDK3.Persistence.PlayerData.Info[] infos) { }
#endif
[PublicAPI] public virtual void OnPlayerRestored(VRC.SDKBase.VRCPlayerApi player) { }
[PublicAPI] public virtual void OnPlayerTriggerEnter(VRC.SDKBase.VRCPlayerApi player) { }
[PublicAPI] public virtual void OnPlayerTriggerExit(VRC.SDKBase.VRCPlayerApi player) { }
[PublicAPI] public virtual void OnPlayerTriggerStay(VRC.SDKBase.VRCPlayerApi player) { }
[PublicAPI] public virtual void OnPlayerCollisionEnter(VRC.SDKBase.VRCPlayerApi player) { }
[PublicAPI] public virtual void OnPlayerCollisionExit(VRC.SDKBase.VRCPlayerApi player) { }
[PublicAPI] public virtual void OnPlayerCollisionStay(VRC.SDKBase.VRCPlayerApi player) { }
[PublicAPI] public virtual void OnPlayerParticleCollision(VRC.SDKBase.VRCPlayerApi player) { }
[PublicAPI] public virtual void OnControllerColliderHitPlayer(VRC.SDK3.ControllerColliderPlayerHit hit) { }
[PublicAPI] public virtual void OnPlayerRespawn(VRC.SDKBase.VRCPlayerApi player) { }
[PublicAPI] public virtual void OnImageLoadSuccess(VRC.SDK3.Image.IVRCImageDownload result) { }
[PublicAPI] public virtual void OnImageLoadError(VRC.SDK3.Image.IVRCImageDownload result) { }
[PublicAPI] public virtual void OnStringLoadSuccess(VRC.SDK3.StringLoading.IVRCStringDownload result) { }
[PublicAPI] public virtual void OnStringLoadError(VRC.SDK3.StringLoading.IVRCStringDownload result) { }
[PublicAPI] public virtual void OnPlayerSuspendChanged(VRC.SDKBase.VRCPlayerApi player) { }
[PublicAPI] public virtual void OnDroneTriggerEnter(VRC.SDKBase.VRCDroneApi drone) { }
[PublicAPI] public virtual void OnDroneTriggerExit(VRC.SDKBase.VRCDroneApi drone) { }
[PublicAPI] public virtual void OnDroneTriggerStay(VRC.SDKBase.VRCDroneApi drone) { }
[PublicAPI] public virtual void OnPostSerialization(VRC.Udon.Common.SerializationResult result) { }
[PublicAPI] public virtual bool OnOwnershipRequest(VRC.SDKBase.VRCPlayerApi requestingPlayer, VRC.SDKBase.VRCPlayerApi requestedOwner) => true;
#region Creator Economy
[PublicAPI] public virtual void OnPurchaseConfirmed(VRC.Economy.IProduct product, VRC.SDKBase.VRCPlayerApi player, bool purchasedNow) { }
[PublicAPI] public virtual void OnPurchaseConfirmedMultiple(VRC.Economy.IProduct product, VRC.SDKBase.VRCPlayerApi player, bool purchasedNow, int quantity) { }
[PublicAPI] public virtual void OnPurchaseExpired(VRC.Economy.IProduct product, VRC.SDKBase.VRCPlayerApi player) { }
[PublicAPI] public virtual void OnPurchasesLoaded(VRC.Economy.IProduct[] products, VRC.SDKBase.VRCPlayerApi player) { }
[PublicAPI] public virtual void OnProductEvent(VRC.Economy.IProduct product, VRC.SDKBase.VRCPlayerApi player) { }
[PublicAPI] public virtual void OnListPurchases(VRC.Economy.IProduct[] products, VRC.SDKBase.VRCPlayerApi player) { }
[PublicAPI] public virtual void OnListAvailableProducts(VRC.Economy.IProduct[] products) { }
[PublicAPI] public virtual void OnListProductOwners(VRC.Economy.IProduct product, string[] owners) { }
#endregion
[PublicAPI] public virtual void MidiNoteOn(int channel, int number, int velocity) { }
[PublicAPI] public virtual void MidiNoteOff(int channel, int number, int velocity) { }
[PublicAPI] public virtual void MidiControlChange(int channel, int number, int value) { }
[PublicAPI] public virtual void InputJump(bool value, VRC.Udon.Common.UdonInputEventArgs args) { }
[PublicAPI] public virtual void InputUse(bool value, VRC.Udon.Common.UdonInputEventArgs args) { }
[PublicAPI] public virtual void InputGrab(bool value, VRC.Udon.Common.UdonInputEventArgs args) { }
[PublicAPI] public virtual void InputDrop(bool value, VRC.Udon.Common.UdonInputEventArgs args) { }
[PublicAPI] public virtual void InputMoveHorizontal(float value, VRC.Udon.Common.UdonInputEventArgs args) { }
[PublicAPI] public virtual void InputMoveVertical(float value, VRC.Udon.Common.UdonInputEventArgs args) { }
[PublicAPI] public virtual void InputLookHorizontal(float value, VRC.Udon.Common.UdonInputEventArgs args) { }
[PublicAPI] public virtual void InputLookVertical(float value, VRC.Udon.Common.UdonInputEventArgs args) { }
[PublicAPI] public virtual void OnInputMethodChanged(VRC.SDKBase.VRCInputMethod inputMethod) { }
[PublicAPI] public virtual void OnLanguageChanged(string language) { }
[PublicAPI] public virtual void OnAsyncGpuReadbackComplete(VRC.SDK3.Rendering.VRCAsyncGPUReadbackRequest request) { }
[PublicAPI] public virtual void OnVRCCameraSettingsChanged(VRC.SDK3.Rendering.VRCCameraSettings cameraSettings) { }
[PublicAPI] public virtual void OnVRCQualitySettingsChanged() { }
[PublicAPI] public virtual void OnScreenUpdate(VRC.SDK3.Platform.ScreenUpdateData data) {}
[PublicAPI] public virtual void OnVRCPlusMassGift(VRC.SDKBase.VRCPlayerApi gifter, int numGifts) { }
[PublicAPI] public virtual void OnPhysBoneGrabbed(PhysBoneGrabbedInfo physBoneInfo) { }
[PublicAPI] public virtual void OnPhysBoneReleased(PhysBoneReleasedInfo physBoneInfo) { }
[PublicAPI] public virtual void OnPhysBonePosed(PhysBonePosedInfo physBoneInfo) { }
[PublicAPI] public virtual void OnPhysBoneUnPosed(PhysBoneUnPosedInfo physBoneInfo) { }
[PublicAPI] public virtual void OnContactEnter(ContactEnterInfo contactInfo) { }
[PublicAPI] public virtual void OnContactExit(ContactExitInfo contactInfo) { }
#if VRC_ENABLE_PLAYER_PERSISTENCE || VRC_ENABLE_INSTANCE_PERSISTENCE
[PublicAPI] public virtual void OnPersistenceUsageUpdated() {}
#endif
#if VRC_ENABLE_PLAYER_PERSISTENCE
[PublicAPI] public virtual void OnPlayerDataStorageExceeded(VRCPlayerApi player) {}
[PublicAPI] public virtual void OnPlayerDataStorageWarning(VRCPlayerApi player) {}
[PublicAPI] public virtual void OnPlayerObjectStorageExceeded(VRCPlayerApi player) {}
[PublicAPI] public virtual void OnPlayerObjectStorageWarning(VRCPlayerApi player) {}
#endif
[Obsolete("The OnStationEntered() event is deprecated use the OnStationEntered(VRCPlayerApi player) event instead", true)]
public virtual void OnStationEntered() { }
[Obsolete("The OnStationExited() event is deprecated use the OnStationExited(VRCPlayerApi player) event instead", true)]
public virtual void OnStationExited() { }
[Obsolete("The OnOwnershipTransferred() event is deprecated use the OnOwnershipTransferred(VRCPlayerApi player) event instead", true)]
public virtual void OnOwnershipTransferred() { }
// Used for tracking serialization data in editor
// Also allows serializing user data on U# behaviours that is otherwise not supported by Unity, so stuff like jagged arrays and more complex collection types.
[SerializeField, HideInInspector]
private SerializationData serializationData;
[SerializeField, HideInInspector, UsedImplicitly]
private VRC.Udon.UdonBehaviour _udonSharpBackingUdonBehaviour;
// Used to preserve backing behaviour on Reset, paste component value calls, and preset applications
// http://answers.unity.com/answers/1754330/view.html
private VRC.Udon.UdonBehaviour _backingUdonBehaviourDump;
void ISerializationCallbackReceiver.OnBeforeSerialize()
{
UnitySerializationUtility.SerializeUnityObject(this, ref serializationData);
_backingUdonBehaviourDump = _udonSharpBackingUdonBehaviour;
}
void ISerializationCallbackReceiver.OnAfterDeserialize()
{
UnitySerializationUtility.DeserializeUnityObject(this, ref serializationData);
if (_backingUdonBehaviourDump)
{
_udonSharpBackingUdonBehaviour = _backingUdonBehaviourDump;
}
}
SerializationData ISupportsPrefabSerialization.SerializationData
{
get => serializationData;
set => serializationData = value;
}
#pragma warning disable CS0414 // Referenced via reflection
[UsedImplicitly]
private static bool _skipEvents;
#pragma warning restore CS0414
[UsedImplicitly]
private static bool ShouldSkipEvents() => _skipEvents;
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3c6e5249679282e459858775b10f38d0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,160 @@

using System.Collections.Generic;
using UnityEngine;
using System.IO;
using FileInfo = System.IO.FileInfo;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace UdonSharp.Updater
{
internal class UdonSharpDataLocator : ScriptableObject
{
private const string DEFAULT_DATA_PATH = "Assets/UdonSharp/UdonSharpDataLocator.asset";
private const string PROJECT_LOADED_KEY = "UdonSharpDataLocator_HasPostProcessedAssets";
private static string _cachedDataLocation;
#if UNITY_EDITOR
internal static bool HasEverPostProcessedAssets
{
get => SessionState.GetBool(PROJECT_LOADED_KEY, false);
set => SessionState.SetBool(PROJECT_LOADED_KEY, value);
}
#endif
public static string DataPath
{
get
{
#if UNITY_EDITOR
if (_cachedDataLocation != null)
return _cachedDataLocation;
string[] foundLocatorGuids = AssetDatabase.FindAssets($"t:{nameof(UdonSharpDataLocator)}");
List<UdonSharpDataLocator> foundLocators = new List<UdonSharpDataLocator>();
foreach (string locatorGuid in foundLocatorGuids)
{
UdonSharpDataLocator locator =
AssetDatabase.LoadAssetAtPath<UdonSharpDataLocator>(AssetDatabase.GUIDToAssetPath(locatorGuid));
if (locator)
foundLocators.Add(locator);
}
if (foundLocators.Count > 1)
throw new System.Exception(
"Multiple UdonSharp data locators found, make sure you do not have multiple installations of UdonSharp and have not duplicated any UdonSharp directories");
if (foundLocators.Count == 0)
{
if (!HasEverPostProcessedAssets)
{
// We can't trust this result, the asset database may be invalid if the Library folder was cleared.
// This may be running too early.
// Best effort, give back the default path without caching.
return Path.GetDirectoryName(DEFAULT_DATA_PATH);
}
foundLocators.Add(InitializeUdonSharpData());
}
_cachedDataLocation = Path.GetDirectoryName(AssetDatabase.GetAssetPath(foundLocators[0]));
return _cachedDataLocation;
#else
throw new System.PlatformNotSupportedException("Cannot get UdonSharp data path outside of the Editor runtime");
#endif
}
}
#if UNITY_EDITOR
private static string GetUtilitiesPath(string locatorPath)
{
return Path.Combine(Path.GetDirectoryName(locatorPath), "UtilityScripts");
}
private static UdonSharpDataLocator InitializeUdonSharpData()
{
if (!AssetDatabase.IsValidFolder(Path.GetDirectoryName(DEFAULT_DATA_PATH)))
AssetDatabase.CreateFolder("Assets", "UdonSharp");
string utilsTargetPath = GetUtilitiesPath(DEFAULT_DATA_PATH);
string utilsSourcePath = Path.Combine(UdonSharpLocator.SamplesPath, "Utilities");
if (Directory.Exists(utilsSourcePath))
DeepCopyDirectory(utilsSourcePath, utilsTargetPath);
else
Debug.LogWarning("No utilities directory found to copy from for UdonSharp utility scripts");
UdonSharpDataLocator locator = CreateInstance<UdonSharpDataLocator>();
AssetDatabase.CreateAsset(locator, DEFAULT_DATA_PATH);
Debug.Log("Created UdonSharp data directory", locator);
AssetDatabase.Refresh();
return locator;
}
#endif
private static void DeepCopyDirectory(string sourcePath, string destinationPath)
{
string[] sourceDirs = Directory.GetDirectories(sourcePath, "*", SearchOption.AllDirectories);
foreach (string sourceDir in sourceDirs)
{
Directory.CreateDirectory(sourceDir.Replace(sourcePath, destinationPath));
}
string[] sourceFiles = Directory.GetFiles(sourcePath, "*", SearchOption.AllDirectories);
foreach (string sourceFile in sourceFiles)
{
string targetFilePath = sourceFile.Replace(sourcePath, destinationPath);
File.Copy(sourceFile, targetFilePath, true);
new FileInfo(targetFilePath).IsReadOnly = false;
}
}
}
#if UNITY_EDITOR
[CustomEditor(typeof(UdonSharpDataLocator))]
internal class UdonSharpDataLocatorEditor : Editor
{
public override void OnInspectorGUI()
{
EditorGUILayout.HelpBox("Do not delete this file! This is used by UdonSharp to locate its data directory.", MessageType.Error);
}
}
internal class InitUSharpDataOnImport : AssetPostprocessor
{
private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
{
UdonSharpDataLocator.HasEverPostProcessedAssets = true;
if (importedAssets.Length <= 0) return;
try
{
foreach (string importedAsset in importedAssets)
{
if (Path.GetFileName(importedAsset) == "UdonSharpLocator.asset" &&
AssetDatabase.LoadAssetAtPath<UdonSharpLocator>(importedAsset))
{
string _ = UdonSharpDataLocator.DataPath; // Implicitly initializes the data asset if it doesn't exist
}
}
}
catch (System.Exception e)
{
Debug.LogError(e);
}
}
}
#endif
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6769ed80171cc314bb08688a48d812a1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,70 @@

using System.Collections.Generic;
using UnityEngine;
using System.IO;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace UdonSharp.Updater
{
/// <summary>
/// This scriptable object doesn't store anything, it just acts as an asset that marks the install location of U# similar to how Odin Inspector locates itself
/// This is included along with the updater to allow it to compile independently from the other UdonSharp scripts which are liable to fail to compile if the user has messed up the installation.
/// </summary>
// [CreateAssetMenu(menuName = "U# Locator", fileName = "UdonSharpLocator")]
public class UdonSharpLocator : ScriptableObject
{
private static string _cachedInstallLocation;
/// <summary>
/// Gets the install path for the root of UdonSharp, with a standard install this will be "Assets/UdonSharp"
/// </summary>
/// <returns></returns>
public static string InstallPath
{
get
{
#if UNITY_EDITOR
if (_cachedInstallLocation != null)
return _cachedInstallLocation;
_cachedInstallLocation = Path.GetDirectoryName("Packages/com.vrchat.worlds/Integrations/UdonSharp/UdonSharpLocator.asset");
return _cachedInstallLocation;
#else
throw new System.PlatformNotSupportedException("Cannot get UdonSharp installation path outside of the Editor runtime");
#endif
}
}
/// <summary>
/// Gets the resources path for U#
/// </summary>
/// <returns></returns>
public static string ResourcesPath => Path.Combine(InstallPath, "Editor", "Resources");
public static string LocalizationPath => Path.Combine(ResourcesPath, "Localization");
public static string SettingsPath => Path.Combine(UdonSharpDataLocator.DataPath, "Settings", "UdonSharpSettings.asset");
public static string SamplesPath => Path.Combine(InstallPath, "Samples~");
public static string IntermediatePrefabPath => Path.Combine(UdonSharpDataLocator.DataPath, "PrefabBuild");
}
#if UNITY_EDITOR
[CustomEditor(typeof(UdonSharpLocator))]
internal class UdonSharpLocatorEditor : Editor
{
public override void OnInspectorGUI()
{
EditorGUILayout.HelpBox("Do not delete or move this file! This is used by UdonSharp to locate its installation directory, if you delete it U# will break!", MessageType.Error);
EditorGUILayout.HelpBox($"Path: {UdonSharpLocator.InstallPath}\n" +
$"Resources Path: {UdonSharpLocator.ResourcesPath}\n" +
$"Localization Path: {UdonSharpLocator.LocalizationPath}\n" +
$"Settings Path: {UdonSharpLocator.SettingsPath}", MessageType.Info);
}
}
#endif
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 49f78320ed7fe0b4f8eb298ff4e9035c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: b7a7abf6cf40e2b44bf7173c3cb2728e, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,93 @@
using System;
using System.Security.Cryptography;
using System.Text;
namespace UdonSharp
{
namespace Internal
{
public static class UdonSharpInternalUtility
{
public static long GetTypeID(System.Type type)
{
SHA256 typeHash = new SHA256CryptoServiceProvider();
byte[] hash = typeHash.ComputeHash(Encoding.UTF8.GetBytes(type.FullName));
return BitConverter.ToInt64(hash, 0);
}
public static long GetTypeID(string typeName)
{
SHA256 typeHash = new SHA256CryptoServiceProvider();
byte[] hash = typeHash.ComputeHash(Encoding.UTF8.GetBytes(typeName));
return BitConverter.ToInt64(hash, 0);
}
public static string GetTypeName(System.Type type)
{
return type.Name;
}
}
}
#if false
public static class UdonSharpUtility
{
public static long GetTypeID<T>()
{
return Internal.UdonSharpInternalUtility.GetTypeID(typeof(T));
}
// These may be extended in the future to handle the edge cases with type names
public static string GetTypeName(System.Type type)
{
return Internal.UdonSharpInternalUtility.GetTypeID(type);
}
//public static string GetTypeNamespace(System.Type type)
//{
// return type.Namespace;
//}
// Placeholder stubs, won't give valid info unless used in the Udon runtime
public static int GetUdonScriptVersion()
{
return 0;
}
public static System.DateTime GetLastCompileDate()
{
return System.DateTime.Now;
}
public static string GetCompilerVersionString()
{
return "v0.0.0+0";
}
// Just assume people are on the correct runtime version for Udon, since other runtimes won't compile anyways
public static string GetCompilerName()
{
return "Roslyn C# compiler";
}
public static int GetCompilerMajorVersion()
{
return 0;
}
public static int GetCompilerMinorVersion()
{
return 0;
}
public static int GetCompilerPatchVersion()
{
return 0;
}
public static int GetCompilerBuild()
{
return 0;
}
}
#endif
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cfea4a50f25cacb44ad6ca62f61a7936
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: