Skip to content

Commit c8e87cf

Browse files
committed
Tentative workarounds for Mono breaking on JP locale
- 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.
1 parent 205e3ad commit c8e87cf

File tree

6 files changed

+80
-19
lines changed

6 files changed

+80
-19
lines changed

Assets/UdonSharp/Editor/UdonSharpCompiler.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22
using System.CodeDom.Compiler;
33
using System.Collections.Concurrent;
44
using System.Collections.Generic;
5+
using System.Globalization;
56
using System.IO;
67
using System.Linq;
78
using System.Reflection;
89
using System.Text;
10+
using System.Threading;
911
using System.Threading.Tasks;
1012
using JetBrains.Annotations;
1113
using Microsoft.CodeAnalysis;
@@ -690,9 +692,10 @@ private int RunFieldInitalizers(CompilationModule[] compiledModules)
690692
}
691693
else
692694
{
693-
memoryStream.Seek(0, SeekOrigin.Begin);
695+
Assembly assembly;
694696

695-
Assembly assembly = Assembly.Load(memoryStream.ToArray());
697+
using (var loadScope = new UdonSharpUtils.UdonSharpAssemblyLoadStripScope())
698+
assembly = Assembly.Load(memoryStream.ToArray());
696699

697700
for (int moduleIdx = 0; moduleIdx < modulesToInitialize.Length; ++moduleIdx)
698701
{

Assets/UdonSharp/Editor/UdonSharpEditorManager.cs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ internal class UdonSharpEditorManager
2222
{
2323
static UdonSharpEditorManager()
2424
{
25+
RuntimeLogWatcher.InitLogWatcher();
26+
2527
EditorSceneManager.sceneOpened += OnSceneOpened;
2628
EditorApplication.update += OnEditorUpdate;
2729
EditorApplication.playModeStateChanged += OnChangePlayMode;
@@ -79,7 +81,9 @@ static void InjectUnityEventInterceptors()
7981
}
8082

8183
Harmony harmony = new Harmony(HARMONY_ID);
82-
harmony.UnpatchAll(HARMONY_ID);
84+
85+
using (var patchScope = new UdonSharpUtils.UdonSharpAssemblyLoadStripScope())
86+
harmony.UnpatchAll(HARMONY_ID);
8387

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

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

93-
try
94-
{
95-
if (eventInfo != null) harmony.Patch(eventInfo, injectedMethod);
96-
}
97-
catch (System.Exception)
97+
using (var loadScope = new UdonSharpUtils.UdonSharpAssemblyLoadStripScope())
9898
{
99-
Debug.LogWarning($"Failed to patch event {eventInfo} on {behaviourType}");
99+
try
100+
{
101+
if (eventInfo != null) harmony.Patch(eventInfo, injectedMethod);
102+
}
103+
catch (System.Exception e)
104+
{
105+
Debug.LogWarning($"Failed to patch event {eventInfo} on {behaviourType}\nException:\n{e}");
106+
}
100107
}
101108
}
102109

Assets/UdonSharp/Editor/UdonSharpResolverContext.cs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -293,13 +293,20 @@ public System.Type ResolveExternType(string qualifiedTypeName)
293293
if (loadedAssemblyCache == null)
294294
{
295295
loadedAssemblyCache = System.AppDomain.CurrentDomain.GetAssemblies()
296-
.OrderBy(e =>
297-
e.GetName().Name.Contains("UnityEngine") ||
298-
e.GetName().Name.Contains("System") ||
299-
e.GetName().Name.Contains("VRC") ||
300-
e.GetName().Name.Contains("Udon") ||
301-
e.GetName().Name.Contains("Assembly-CSharp") ||
302-
e.GetName().Name.Contains("mscorlib")).Reverse().ToList();
296+
.OrderBy(e => {
297+
if (e.IsDynamic || string.IsNullOrEmpty(e.Location) || e.Location.StartsWith("data"))
298+
return false;
299+
300+
string assemblyName = e.GetName().Name;
301+
302+
return
303+
assemblyName.Contains("UnityEngine") ||
304+
assemblyName.Contains("System") ||
305+
assemblyName.Contains("VRC") ||
306+
assemblyName.Contains("Udon") ||
307+
assemblyName.Contains("Assembly-CSharp") ||
308+
assemblyName.Contains("mscorlib");
309+
}).Reverse().ToList();
303310
}
304311
}
305312
}

Assets/UdonSharp/Editor/UdonSharpRuntimeLogWatcher.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
namespace UdonSharp
1313
{
14-
[InitializeOnLoad]
1514
public static class RuntimeLogWatcher
1615
{
1716
class LogFileState
@@ -30,7 +29,7 @@ class LogFileState
3029
static Dictionary<string, LogFileState> logFileStates = new Dictionary<string, LogFileState>();
3130
static HashSet<string> modifiedLogPaths = new HashSet<string>();
3231

33-
static RuntimeLogWatcher()
32+
public static void InitLogWatcher()
3433
{
3534
EditorApplication.update += OnEditorUpdate;
3635
Application.logMessageReceived += OnLog;
@@ -149,7 +148,7 @@ static void OnLogFileChanged(object source, FileSystemEventArgs args)
149148

150149
static void OnLog(string logStr, string stackTrace, LogType type)
151150
{
152-
if (type == LogType.Error)
151+
if (type == LogType.Error || type == LogType.Exception)
153152
{
154153
debugOutputQueue.Enqueue(logStr);
155154
}
@@ -404,6 +403,12 @@ static void HandleForwardedLog(string logMessage, LogFileState state, UdonSharpS
404403

405404
static void HandleLogError(string errorStr, string logPrefix, string prePrefix)
406405
{
406+
if (errorStr.StartsWith("ExecutionEngineException: String conversion error: Illegal byte sequence encounted in the input.")) // Nice typo Mono
407+
{
408+
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.");
409+
return;
410+
}
411+
407412
UdonSharpEditorCache.DebugInfoType debugType;
408413
if (errorStr.StartsWith("[<color=yellow>UdonBehaviour</color>] An exception occurred during Udon execution, this UdonBehaviour will be halted.")) // Editor
409414
{

Assets/UdonSharp/Editor/UdonSharpUtils.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,5 +740,44 @@ internal static Assembly[] GetLoadedEditorAssemblies()
740740

741741
return (Assembly[])getLoadedAssembliesProp.GetValue(null);
742742
}
743+
744+
/// <summary>
745+
/// 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
746+
/// </summary>
747+
internal class UdonSharpAssemblyLoadStripScope : IDisposable
748+
{
749+
Delegate[] originalDelegates;
750+
751+
public UdonSharpAssemblyLoadStripScope()
752+
{
753+
FieldInfo info = AppDomain.CurrentDomain.GetType().GetField("AssemblyLoad", BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance);
754+
755+
AssemblyLoadEventHandler handler = info.GetValue(AppDomain.CurrentDomain) as AssemblyLoadEventHandler;
756+
757+
originalDelegates = handler.GetInvocationList();
758+
759+
if (originalDelegates != null)
760+
{
761+
foreach (Delegate del in handler.GetInvocationList())
762+
handler -= (AssemblyLoadEventHandler)del;
763+
764+
info.SetValue(AppDomain.CurrentDomain, handler);
765+
}
766+
}
767+
768+
public void Dispose()
769+
{
770+
if (originalDelegates != null)
771+
{
772+
FieldInfo info = AppDomain.CurrentDomain.GetType().GetField("AssemblyLoad", BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance);
773+
AssemblyLoadEventHandler handler = info.GetValue(AppDomain.CurrentDomain) as AssemblyLoadEventHandler;
774+
775+
foreach (Delegate del in originalDelegates)
776+
handler += (AssemblyLoadEventHandler)del;
777+
778+
info.SetValue(AppDomain.CurrentDomain, handler);
779+
}
780+
}
781+
}
743782
}
744783
}
29 KB
Binary file not shown.

0 commit comments

Comments
 (0)