Skip to content
This repository has been archived by the owner on Jan 22, 2022. It is now read-only.

Commit

Permalink
Tentative workarounds for Mono breaking on JP locale
Browse files Browse the repository at this point in the history
- Update Harmony to a pre-release which changes how its persistent state works and happens to not use GetName(). Also slightly modified part of Harmony to not use GetName, and modified Harmony's dependency MonoMod similarly
- Remove assembly callbacks in certain scopes so that Odin doesn't break things
- Make U# resolver assembly search not try to use generated assemblies which can break
- Add check in log watcher to warn about Mono bug with GetName and give a solution because there are still a number of random Unity things that can break and we don't know what other assets people are using which may break.
  • Loading branch information
MerlinVR committed Mar 26, 2021
1 parent 205e3ad commit c8e87cf
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 19 deletions.
7 changes: 5 additions & 2 deletions Assets/UdonSharp/Editor/UdonSharpCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
using System.CodeDom.Compiler;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.CodeAnalysis;
Expand Down Expand Up @@ -690,9 +692,10 @@ private int RunFieldInitalizers(CompilationModule[] compiledModules)
}
else
{
memoryStream.Seek(0, SeekOrigin.Begin);
Assembly assembly;

Assembly assembly = Assembly.Load(memoryStream.ToArray());
using (var loadScope = new UdonSharpUtils.UdonSharpAssemblyLoadStripScope())
assembly = Assembly.Load(memoryStream.ToArray());

for (int moduleIdx = 0; moduleIdx < modulesToInitialize.Length; ++moduleIdx)
{
Expand Down
21 changes: 14 additions & 7 deletions Assets/UdonSharp/Editor/UdonSharpEditorManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ internal class UdonSharpEditorManager
{
static UdonSharpEditorManager()
{
RuntimeLogWatcher.InitLogWatcher();

EditorSceneManager.sceneOpened += OnSceneOpened;
EditorApplication.update += OnEditorUpdate;
EditorApplication.playModeStateChanged += OnChangePlayMode;
Expand Down Expand Up @@ -79,7 +81,9 @@ static void InjectUnityEventInterceptors()
}

Harmony harmony = new Harmony(HARMONY_ID);
harmony.UnpatchAll(HARMONY_ID);

using (var patchScope = new UdonSharpUtils.UdonSharpAssemblyLoadStripScope())
harmony.UnpatchAll(HARMONY_ID);

MethodInfo injectedEvent = typeof(InjectedMethods).GetMethod(nameof(InjectedMethods.EventInterceptor), BindingFlags.Static | BindingFlags.Public);
HarmonyMethod injectedMethod = new HarmonyMethod(injectedEvent);
Expand All @@ -90,13 +94,16 @@ void InjectEvent(System.Type behaviourType, string eventName)

MethodInfo eventInfo = behaviourType.GetMethods(eventBindingFlags).FirstOrDefault(e => e.Name == eventName && e.ReturnType == typeof(void));

try
{
if (eventInfo != null) harmony.Patch(eventInfo, injectedMethod);
}
catch (System.Exception)
using (var loadScope = new UdonSharpUtils.UdonSharpAssemblyLoadStripScope())
{
Debug.LogWarning($"Failed to patch event {eventInfo} on {behaviourType}");
try
{
if (eventInfo != null) harmony.Patch(eventInfo, injectedMethod);
}
catch (System.Exception e)
{
Debug.LogWarning($"Failed to patch event {eventInfo} on {behaviourType}\nException:\n{e}");
}
}
}

Expand Down
21 changes: 14 additions & 7 deletions Assets/UdonSharp/Editor/UdonSharpResolverContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -293,13 +293,20 @@ public System.Type ResolveExternType(string qualifiedTypeName)
if (loadedAssemblyCache == null)
{
loadedAssemblyCache = System.AppDomain.CurrentDomain.GetAssemblies()
.OrderBy(e =>
e.GetName().Name.Contains("UnityEngine") ||
e.GetName().Name.Contains("System") ||
e.GetName().Name.Contains("VRC") ||
e.GetName().Name.Contains("Udon") ||
e.GetName().Name.Contains("Assembly-CSharp") ||
e.GetName().Name.Contains("mscorlib")).Reverse().ToList();
.OrderBy(e => {
if (e.IsDynamic || string.IsNullOrEmpty(e.Location) || e.Location.StartsWith("data"))
return false;
string assemblyName = e.GetName().Name;
return
assemblyName.Contains("UnityEngine") ||
assemblyName.Contains("System") ||
assemblyName.Contains("VRC") ||
assemblyName.Contains("Udon") ||
assemblyName.Contains("Assembly-CSharp") ||
assemblyName.Contains("mscorlib");
}).Reverse().ToList();
}
}
}
Expand Down
11 changes: 8 additions & 3 deletions Assets/UdonSharp/Editor/UdonSharpRuntimeLogWatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

namespace UdonSharp
{
[InitializeOnLoad]
public static class RuntimeLogWatcher
{
class LogFileState
Expand All @@ -30,7 +29,7 @@ class LogFileState
static Dictionary<string, LogFileState> logFileStates = new Dictionary<string, LogFileState>();
static HashSet<string> modifiedLogPaths = new HashSet<string>();

static RuntimeLogWatcher()
public static void InitLogWatcher()
{
EditorApplication.update += OnEditorUpdate;
Application.logMessageReceived += OnLog;
Expand Down Expand Up @@ -149,7 +148,7 @@ static void OnLogFileChanged(object source, FileSystemEventArgs args)

static void OnLog(string logStr, string stackTrace, LogType type)
{
if (type == LogType.Error)
if (type == LogType.Error || type == LogType.Exception)
{
debugOutputQueue.Enqueue(logStr);
}
Expand Down Expand Up @@ -404,6 +403,12 @@ static void HandleForwardedLog(string logMessage, LogFileState state, UdonSharpS

static void HandleLogError(string errorStr, string logPrefix, string prePrefix)
{
if (errorStr.StartsWith("ExecutionEngineException: String conversion error: Illegal byte sequence encounted in the input.")) // Nice typo Mono
{
Debug.LogError("[<color=#FF00FF>UdonSharp</color>] ExecutionEngineException detected! This means you have hit a bug in Mono. To fix this, move your project to a path without any unicode characters.");
return;
}

UdonSharpEditorCache.DebugInfoType debugType;
if (errorStr.StartsWith("[<color=yellow>UdonBehaviour</color>] An exception occurred during Udon execution, this UdonBehaviour will be halted.")) // Editor
{
Expand Down
39 changes: 39 additions & 0 deletions Assets/UdonSharp/Editor/UdonSharpUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -740,5 +740,44 @@ internal static Assembly[] GetLoadedEditorAssemblies()

return (Assembly[])getLoadedAssembliesProp.GetValue(null);
}

/// <summary>
/// Used to prevent Odin's DefaultSerializationBinder from getting a callback to register an assembly in specific cases where it will explode due to https://github.com/mono/mono/issues/20968
/// </summary>
internal class UdonSharpAssemblyLoadStripScope : IDisposable
{
Delegate[] originalDelegates;

public UdonSharpAssemblyLoadStripScope()
{
FieldInfo info = AppDomain.CurrentDomain.GetType().GetField("AssemblyLoad", BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance);

AssemblyLoadEventHandler handler = info.GetValue(AppDomain.CurrentDomain) as AssemblyLoadEventHandler;

originalDelegates = handler.GetInvocationList();

if (originalDelegates != null)
{
foreach (Delegate del in handler.GetInvocationList())
handler -= (AssemblyLoadEventHandler)del;

info.SetValue(AppDomain.CurrentDomain, handler);
}
}

public void Dispose()
{
if (originalDelegates != null)
{
FieldInfo info = AppDomain.CurrentDomain.GetType().GetField("AssemblyLoad", BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance);
AssemblyLoadEventHandler handler = info.GetValue(AppDomain.CurrentDomain) as AssemblyLoadEventHandler;

foreach (Delegate del in originalDelegates)
handler += (AssemblyLoadEventHandler)del;

info.SetValue(AppDomain.CurrentDomain, handler);
}
}
}
}
}
Binary file modified Assets/UdonSharp/Plugins/0Harmony.dll
Binary file not shown.

0 comments on commit c8e87cf

Please sign in to comment.