【发布时间】:2018-03-29 07:44:54
【问题描述】:
我正在尝试使用 Mono.Cecil 在 Unity 中修补我的自定义用户脚本。
我想将代码注入到 Unity 中的自定义用户脚本中,以避免在项目中的每个 MonoBehaviour 中编写相同的代码行。 但是,当我这样做时:
using (AssemblyDefinition assemblyDefinition = AssemblyDefinition.ReadAssembly(assembly.Location, new ReaderParameters() { ReadWrite = true }))
{
//Do some patching here
assemblyDefinition.Write();
}
然后我得到一个异常说
IOException: Win32 IO 返回 1224
这显然意味着文件被锁定而无法写入。
如果我改为尝试使用:
File.Delete(sourceAssemblyPath);
File.Move(targetAssemblyPath, sourceAssemblyPath);
然后 dll 被正确修补,但是当我尝试播放应用程序时,我场景中的脚本失去了引用,好像文件的替换导致他们认为场景对象上的脚本不再存在于项目中(我想这是有道理的,因为我确实删除了他们所在的 dll 以用新的替换它)。
有没有人知道如何在 Unity 中修补用户的项目程序集,同时保持当前项目的可用性? 还是我应该只在构建期间进行修补或其他什么? 有什么建议吗?
谢谢
【问题讨论】:
-
这段代码什么时候运行?如果您使用 [InitializeOnLoad] 执行此操作,则程序集显然已经加载,因此此时修改它们无济于事;您需要加载程序集一次来触发 Cecil,而不是每次通常只重新加载一次时重新加载以加载修改。尝试使用 UnityEditor.AssemblyReloadEvents.beforeAssemblyReload。上次我尝试使用 Cecil 时,我能够使用单个
var stream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);来读取和写入文件而无需删除/复制。 -
目前我正在通过菜单命令手动运行它。这些都是有趣的建议,我会尽快尝试并报告,谢谢~
-
所以我现在正在这样做:使用 (Stream assemblyStream = new FileStream(assembly.Location, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)) { using (AssemblyDefinition assemblyDefinition = AssemblyDefinition.ReadAssembly (assemblyStream, new ReaderParameters() { ReadWrite = true })) { assemblyDefinition.Write(assemblyStream); } } 仍然得到 1224 IO 异常。
-
即使我尝试这个也一样:使用 (FileStream assemblyStream = new FileStream(assembly.Location, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)) { byte[] bytes = new byte[装配流。长度]; assemblyStream.Write(字节,(int)assemblyStream.Position,(int)assemblyStream.Length); }
-
您需要在读取和写入之间设置
assemblyStream.Position = 0;,以便您实际上是从文件开头覆盖。不确定这是否是错误的原因。除此之外,它看起来与我的代码几乎相同(尽管我没有使用任何 ReaderParameters)。
标签: unity3d mono.cecil