项目目标:完成远程真机调试插件,实现对端侧 3D/XR 场景的 Unity 实时场景部署与调试;
具体内容:
- 在端侧构建调试 SDK,用于接收 Unity 发送的命令,和向 Unity 同步状态;
- 在 Unity 中基于插件实现Debug Server,用于和端侧进行实时通信(Unity 场景快速导出并推送到端侧)和同步状态(Unity 场景双向状态同步调试);
- PC端:MacOS,移动端:iOS;
阶段任务概要:
- 端侧 DebugSDK 技术选型 - Unity / C++,Unity 插件技术选型 - OC / C++
- 通信协议选型:Socket Raw Packet / gRPC + Protobuf / Hybrid (Raw Packet + RPC)
- 基础 Socket 通道搭建:Unity Socket Server (nc test)、Socket Client
- RPC 通道搭建:Unity RPC、iOS gRPC、C/S 双端互调
Unity C++插件开发基础
参考:
- 官网介绍:.NET,Plugin,托管代码,P/Invoke,Mono Runtime官网对P/Invoke的介绍;
- P/Invoke:C++ Scripting: Part 1 – C#/C++ Communication,C#与C/C++的交互(PInvoke),Create A Native Plugin For Unity,关于Unity Native插件的开发,Unity与C++交互入门(1),Tutorial — Create C/C++ plugins for Unity3D,Rust FFI 编程 - FFI 概述
- 插件开发:Unity 3D编辑器插件开发,Unity3D插件开发教程,开发unity插件——一次搞定unity编辑器常用功能
.NET使用CIL作为高级语言与机器语言的中间层以实现跨平台,且使用公共语言运行时CLR(支持提前AOT和实时JIT类型),无论使用的是Mono、.NET Framework还是.NET Core。将执行过程交由运行时管理(如自动内存管理、安全边界、类型安全等)的代码称为托管代码(Managed Code);直接运行编译出的机器语言而不依赖运行时的代码称为原生代码(Native Code)。二者各有优势和局限性,具体见官网介绍。Unity最常用的托管代码形式插件使用C#语言,原生插件可以使用C/C++/Objective-C等。.NET中,C#与C++的互操作(Interop)可以通过P/Invoke实现(也可以使用C++/CLI作为中间层,但Mono不支持)。
Unity native 插件开发流程:C++ → C API → 打包 → C# 封装接口。
在 Safe Mode 下 C# 与 C++ 无法直接交互,C++ 需要包装成 C API,由 C#
调用 C API。 插件包:Android 打包成 so
,IOS 打包成
framework 或者 .a
,macOS 打包成
.bundle
,Windows 打包成 dll。Windows 放在
Plugins/x86(x64)
目录下,Mac 直接放在 Plugins
目录下,iOS 放在 Plugins/iOS
目录下,Android 放在
Plugins/Android/libs/armeabi-v7a
目录下。如果修改了本地插件,需要将 dll 或者 bundle 覆盖了之后重启 Unity,
不然还是会使用老的 Native Plugin。
CMakeLists.txt:
1 | cmake_minimum_required(VERSION 3.5) |
channel.h头文件:
1 |
|
在所有出现 func
声明或定义的时候都要带
EXPORT_API
;将 /bundles 中的 .dylib
文件复制到Unity的Assets/Plugins下,将 C#
插件放入Assets/Editor下即可。
注意:Unity 改变C#脚本后会实时重编译,但在移入新.dylib文件并不会,需要退出重新进入 Unity 项目。
RPC 协议选型与通道搭建
参考:gRPC官方文档中文版,gRPC官方文档,Protocol Buffer官方文档
gRPC是一个高性能、通用的开源RPC框架,其由Google 2015年主要面向移动应用开发并基于HTTP/2协议标准而设计,基于ProtoBuf序列化协议开发,且支持众多开发语言。
RPC 的主要目的是让客户端可以像调用函数一样直接与服务端通信,尽可能使网络交互过程变得透明。使用时,首先需要在 .proto 文件中定义各个函数原型与数据结构(将作为函数参数传递,也就是网络传输的数据),然后 Protobuf 会根据 .proto 生成桩程序 demo.pb.cc 和 demo.pb.h(这两个文件不应被用户修改),gRPC 再生成 demo.grpc.pb.cc 和 demo.grpc.pb.h(这两个文件也一般无需修改),最后用户在自定义程序 demo.client 和 demo.server 中自定义需要的操作和传递的信息。
具体安装使用方法:
1 | brew install autoconf automake libtool pkg-config # 安装依赖库 |
重新生成gRPC代码:
1 | cd examples/cpp/helloworld/cmake/build |
目录结构:
1 | cpp/ |
调通后,同样依照官方手册调通 Objective-C 语言的 gRPC (仅支持客户端)。然后修改 CMakeLists.txt 文件以得到 .dylib 文件,从而导入到 Unity 中被插件调用。
至此,我们已经能够实现在 Unity 上通过 C# 脚本实时获取场景树信息(Unity 序列化方案目前采用JsonUtility),并通过跨语言互操作将信息传递给 C++ gRPC,再通过 gRPC 实时传输至客户端(可以由客户端每 0.1 秒发送一次请求),最后客户端拿到 Unity 场景树信息后在本地重建场景。