feat(mod): 完成外部 DLL 事务热替换
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
|
||||
namespace ShrinkModFramework
|
||||
{
|
||||
/// <summary>把文件系统的 burst 事件折叠为一次主线程 reload。</summary>
|
||||
internal sealed class ShrinkModReloadDebouncer
|
||||
{
|
||||
private bool _pending;
|
||||
private float _reloadAt;
|
||||
|
||||
public bool IsPending => _pending;
|
||||
|
||||
public void Schedule(float now, float delaySeconds)
|
||||
{
|
||||
_pending = true;
|
||||
_reloadAt = now + Math.Max(0.05f, delaySeconds);
|
||||
}
|
||||
|
||||
public bool TryConsume(float now)
|
||||
{
|
||||
if (!_pending || now < _reloadAt)
|
||||
return false;
|
||||
|
||||
_pending = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_pending = false;
|
||||
_reloadAt = 0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ec113876ec861b64cb8391eed726108b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -11,10 +11,9 @@ namespace ShrinkModFramework
|
||||
private static ShrinkModRuntimeDriver _instance;
|
||||
|
||||
private readonly ConcurrentQueue<Action> _mainThreadActions = new();
|
||||
private readonly ShrinkModReloadDebouncer _externalReloadDebouncer = new();
|
||||
private FileSystemWatcher _watcher;
|
||||
private ShrinkModFrameworkSettings _settings;
|
||||
private bool _pendingExternalReload;
|
||||
private float _reloadAtRealtime;
|
||||
|
||||
public static void EnsureCreated(ShrinkModFrameworkSettings settings)
|
||||
{
|
||||
@@ -25,7 +24,8 @@ namespace ShrinkModFramework
|
||||
}
|
||||
|
||||
var go = new GameObject("ShrinkModRuntimeDriver");
|
||||
DontDestroyOnLoad(go);
|
||||
if (Application.isPlaying)
|
||||
DontDestroyOnLoad(go);
|
||||
_instance = go.AddComponent<ShrinkModRuntimeDriver>();
|
||||
_instance.ApplySettings(settings);
|
||||
}
|
||||
@@ -41,6 +41,12 @@ namespace ShrinkModFramework
|
||||
_instance._mainThreadActions.Enqueue(action);
|
||||
}
|
||||
|
||||
internal static ShrinkModRuntimeDriver InstanceForTesting => _instance;
|
||||
|
||||
internal bool HasWatcherForTesting => _watcher != null;
|
||||
|
||||
internal void PumpForTesting() => Update();
|
||||
|
||||
private void Update()
|
||||
{
|
||||
while (_mainThreadActions.TryDequeue(out var action))
|
||||
@@ -55,11 +61,9 @@ namespace ShrinkModFramework
|
||||
}
|
||||
}
|
||||
|
||||
if (!_pendingExternalReload || Time.realtimeSinceStartup < _reloadAtRealtime)
|
||||
if (!_externalReloadDebouncer.TryConsume(Time.realtimeSinceStartup))
|
||||
return;
|
||||
|
||||
_pendingExternalReload = false;
|
||||
|
||||
try
|
||||
{
|
||||
ShrinkModLoader.LoadNewExternalMods(_settings);
|
||||
@@ -117,6 +121,7 @@ namespace ShrinkModFramework
|
||||
};
|
||||
_watcher.Created += OnExternalModsChanged;
|
||||
_watcher.Changed += OnExternalModsChanged;
|
||||
_watcher.Deleted += OnExternalModsChanged;
|
||||
_watcher.Renamed += OnExternalModsRenamed;
|
||||
_watcher.EnableRaisingEvents = true;
|
||||
}
|
||||
@@ -135,6 +140,7 @@ namespace ShrinkModFramework
|
||||
|
||||
private void OnExternalModsRenamed(object sender, RenamedEventArgs args)
|
||||
{
|
||||
ScheduleExternalReload(args.OldFullPath);
|
||||
ScheduleExternalReload(args.FullPath);
|
||||
}
|
||||
|
||||
@@ -145,9 +151,8 @@ namespace ShrinkModFramework
|
||||
|
||||
_mainThreadActions.Enqueue(() =>
|
||||
{
|
||||
_pendingExternalReload = true;
|
||||
var delay = _settings ? Mathf.Max(0.05f, _settings.externalModsReloadDelaySeconds) : 0.5f;
|
||||
_reloadAtRealtime = Time.realtimeSinceStartup + delay;
|
||||
_externalReloadDebouncer.Schedule(Time.realtimeSinceStartup, delay);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -159,6 +164,7 @@ namespace ShrinkModFramework
|
||||
_watcher.EnableRaisingEvents = false;
|
||||
_watcher.Created -= OnExternalModsChanged;
|
||||
_watcher.Changed -= OnExternalModsChanged;
|
||||
_watcher.Deleted -= OnExternalModsChanged;
|
||||
_watcher.Renamed -= OnExternalModsRenamed;
|
||||
_watcher.Dispose();
|
||||
_watcher = null;
|
||||
|
||||
Reference in New Issue
Block a user