UdonSharp 的前世今生
你好,来自现实的旅人 ${ LocalPlayer.displayName }
欢迎来到 UdonSharp 的世界。
// 此处应该有饱含人文关怀的序以安抚被 UdonSharp 伤透了心的可怜新手开发者
前情提要:VRCSDK 2.0
// 此处应有 SDK 2.0 和社区继承者 CyanTrigger
Udon乌冬面乌冬面 的诞生
VRCSDK 3.0 刚刚发布时,取代 VRCSDK 2.0 的并不是 UdonSharp,而是一种被称为 Udon Node Graph 的可视化图形编程语言。Udon Node Graph 需要被被编译为需要被编译为 Udon VM 字节码 才能在 VRChat 世界中运行。
为什么不直接允许用户编写任意 Unity C# 脚本,而是将用户代码放在 Udon VM 中运行?VRChat 的每个世界都由用户创建并上传,如果允许运行任意 Unity C# 代码,可能会有人上传恶意代码破坏你的 VRChat 客户端或破坏你的电脑。因此,用户创建的代码必须通过检查以保证不包含恶意功能,或隔离在单独的运行环境让它无法影响外界。
就像浏览器中的 JavaScript 运行在隔离沙盒中一样,将不可信代码隔离在虚拟机或沙盒中运行保证宿主安全是常用的安全策略。
在实际操作中,想要在 Unity 引擎内嵌入一个隔离沙盒环境有很多不同的成熟解决方案:
VRChat 选择的技术路线是将用户代码运行在自定义的字节码解释器中,并且将外部函数调用限制在白名单中。
作为背景介绍的一部分,尽管 VRChat 宣传“Udon Node Graph 适合编程新手”,但很多开发者并不认同这一说法。
主要的原因是,Udon Node Graph 没有简化编程,反而让简单的编程概念变得更复杂:用户不得不需要具有编程的大部分先验知识才能在 Udon Node Graph 中用简陋的工具“带着脚镣跳舞”,因此 SDK 2.0 的用户以及 VRChat 开发新手堆 Udon Node Graph 的接受度不高。当新手遇到问题想在社区里获得帮助时,往往会意外的发现几乎所有资深开发者都不了解 Udon Node Graph,而这反过来又降低了 Udon Node Graph 的使用率。
// 对于 SDK 2.0 用户,社区继承者 CyanTrigger
// 新手开发者怎么办?好像没办法,学习 U# 吧
将不可信代码隔离在虚拟机或沙盒中运行保证宿主安全稳定也是通用的安全策略,例如在浏览器中,网站的 JavaScript 运行在隔离沙盒,每个标签页运行在单独的进程等。
VRChat 社区里长出来的 UdonSharp
显然,Udon Node Graph 是无法满足开发者对于组织复杂代码、复杂工程的需求的,Udon Node Graph 也无法像常规文本脚本一样被简单复用。但好消息是,VRCSDK 并没有限制开发者自行实现新的编译器并生成 Udon VM 字节码。因此,UdonSharp (后文称 U#)这一社区项目诞生了。U# 允许用户使用 C# 的语法功能子集编写脚本,然后被 Udon VM 执行。抛开 Udon VM 的糟糕性能不谈,U# 大幅提高了开发者的开发效率,很快也被 VRChat 吸收作为官方项目。
附录:
为什么 VRChat 不直接允许用户编写任意 Unity C# 脚本,而是将用户程序放在 Udon VM 中运行?
因为 VRChat 的每个世界都由用户创建并上传,如果允许运行任意 Unity C# 代码,可能会有人上传恶意代码破坏你的 VRChat 客户端或破坏你的电脑。因此,用户创建的代码必须通过检查以保证不包含恶意功能,或隔离在单独的运行环境让它无法影响外界。
一种可能的方案是服务器对 C# 程序集进行验证,保证不会有恶意代码,但验证用户上传的代码需要额外的服务器资源;另外尽管 Mono 和 .Net 都有沙盒功能,但该功能一直被强烈推荐不要使用。这两种做法都很容易陷入安全攻防猫鼠游戏,用户总会找到漏洞,开发者不得不像“打地鼠”一样疲于奔命修复漏洞。
因此,大多数允许用户上传代码的游戏选择的方案是嵌入沙盒化的脚本引擎。沙盒化脚本引擎可以精确地控制安全边界,只允许用户代码使用被许可的功能,就算用户代码想要破坏运行环境最多也只能破坏沙盒内的环境,无法影响沙盒宿主。VRChat 的 Udon 就是沙盒化的字节码执行引擎,只有被列入 Udon 白名单里的外部方法才能被用户的 Udon 程序调用。