-
Notifications
You must be signed in to change notification settings - Fork 4
/
AvaloniaApp.cs
144 lines (126 loc) · 4.84 KB
/
AvaloniaApp.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
using System;
using System.Reflection;
using System.Threading;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.ReactiveUI;
using Unilonia.Settings;
#if UNITY_EDITOR
using UnityEditor;
#endif
using UnityEngine;
using Application = Avalonia.Application;
namespace Unilonia
{
[InitializeOnLoad]
public static class AvaloniaApp
{
#if UNITY_EDITOR
static AvaloniaApp()
{
var settings = UniloniaSettings.Load();
EditorApplication.playModeStateChanged += VerifySettings;
EditorApplication.playModeStateChanged += (state) =>
{
if (state == PlayModeStateChange.ExitingPlayMode)
{
Stop();
}
};
UnityEngine.Application.quitting += Stop;
if (settings.applicationType.Type != null)
Start();
}
private static void VerifySettings(PlayModeStateChange state)
{
if (state == PlayModeStateChange.ExitingEditMode)
UniloniaSettings.Load();
}
#endif
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)]
static void SelfStart()
{
Start();
}
private static readonly object _lock = new object();
private static Thread avaloniaThread;
private static EventWaitHandle init;
public static void Start()
{
if (UnityEngine.Application.isPlaying && UnityEngine.Object.FindObjectOfType<UnityDispatcher>() == null)
{
var gameObject = new GameObject("AvaloniaThreading");
gameObject.AddComponent<UnityDispatcher>();
}
lock (_lock)
{
if (Application.Current == null)
{
var settings = UniloniaSettings.Load();
if (settings.applicationType.Type == null) throw new ArgumentNullException(nameof(UniloniaSettings.applicationType));
init = new EventWaitHandle(false, EventResetMode.ManualReset);
avaloniaThread = new Thread(AvaloniaThread);
avaloniaThread.Name = "Avalonia Thread";
avaloniaThread.Start(settings.applicationType.Type);
if (UnityEngine.Application.isPlaying)
init.WaitOne();
init.Dispose();
init = null;
}
}
}
public static void Stop() => Stop(0);
public static void Stop(int exitCode = 0)
{
if (Application.Current != null)
{
var lifetime = Application.Current.ApplicationLifetime as IControlledApplicationLifetime;
lifetime.Shutdown(exitCode);
}
}
private static void AvaloniaThread(object parameters)
{
var applicationType = (Type)parameters;
var builderType = typeof(AppBuilderBase<>).MakeGenericType(typeof(UnityAppBuilder));
var configureMethod = builderType.GetMethod(nameof(UnityAppBuilder.Configure), BindingFlags.Public | BindingFlags.Static, null, new Type[0], null);
var builder = (UnityAppBuilder)configureMethod.MakeGenericMethod(applicationType).Invoke(null, new object[0]);
builder
.UseUnity()
.UseDirect2D1()
.UseReactiveUI()
.LogToUnityDebug();
var lifetime = new UnityLifetime();
builder.SetupWithLifetime(lifetime);
if (init != null)
init.Set();
lifetime.Start(Array.Empty<string>());
builder.Instance.Run(lifetime.Token);
}
class UnityLifetime : IControlledApplicationLifetime
{
private readonly CancellationTokenSource _cts = new CancellationTokenSource();
public CancellationToken Token => _cts.Token;
public int ExitCode { get; private set; }
public event EventHandler<ControlledApplicationLifetimeStartupEventArgs> Startup;
public event EventHandler<ControlledApplicationLifetimeExitEventArgs> Exit;
public void Start(string[] args)
{
Startup?.Invoke(this, new ControlledApplicationLifetimeStartupEventArgs(args));
}
public void Shutdown(int exitCode)
{
ExitCode = exitCode;
var e = new ControlledApplicationLifetimeExitEventArgs(exitCode);
Exit?.Invoke(this, e);
ExitCode = e.ApplicationExitCode;
#if UNITY_EDITOR
EditorApplication.ExitPlaymode();
#else
_cts.Cancel();
UnityEngine.Application.Quit(exitCode);
#endif
}
}
}
}