专栏首页逍遥剑客的游戏开发基于Unity的编辑器开发(二): 进程间通信

基于Unity的编辑器开发(二): 进程间通信

共享代码

首先要做的, 是需要编辑器和Unity共享一部部分代码, 至少协议定义和解析我不想写两遍. 虽然有protobuf这样的工具库, 但是如果不是跨语言的话, 我觉得没必要引入另一套流程. 所以我就想能不能让一个C# dll库可以同时被Winforms的编辑器和Unity脚本引用呢? 考查了一下还是可以的:

  • Unity的.Net默认是Subset, 需要改成全的
  • Unity的.Net默认是C#3.5版本兼容的, 一些新的语法(如async)不支持
  • Unity中如果要引用Visual Studio编译出来的C# dll, 需要把Target framework改成”Unity 3.5 .net full Base Class Libraries”
  • 把VS编译出来的dll, 拷到Unity的Asset目录, mono脚本里就可以直接引用了

同时, 编辑器这边也需要知道一些游戏的数据类型和接口的定义, 实验了一下, UnityEngine.dll, Assembly-CSharp.dll, Assembly-CSharp-firstpass.dll可以直接被VS这边的C#工程引用, 只要不执行Unity特有的方法(会报”ECall 方法必须打包到系统模块中”的异常), 就可以在Winforms工程中安全地复用游戏脚本中的代码了.

经过这样的设置, 编辑器和Unity游戏可以共享一个dll库, 从代码上做到了共享, 这就为我们的代码复用和通信协议定义提供了基础保障.

进程间通信

为了达成这一通信需求, 首先做了一些搜索:

总结下来, 要么是基于NamedPipe, 要么是基于Socket. 尝试使用Full Duplex Asynchronous Read/Write with Named Pipes - CodeProject里的基于NamedPipe方法, 遇到一些问题:

  • Unity这边会报异常, Unity的mono对NamePipe支持不是很好
  • 有时候会连不上, 比如管道被占用

所以又换了一个不依赖mono那个不靠谱.net framework的方案, 搜了搜看起来NNanomsg不错, 使用起来够简单, 不过也遇到一些问题:

  • NNanomsg如果要在Unity用使用, 需要做一点修改, 主要是native dll的载入: https://github.com/xoyojank/NNanomsg
  • 使用ipc协议也会出现莫名其妙连不上的问题, 本质上底层还是走的NamePipe, 换成tcp协议就好了
  • 错误信息不够直观, 所以我又在NNanomsg里加了nanomsg的一些调试用的函数的接口
  • 一次性发送大量数据(比如几MB), 会导致链接断开或卡死, 问了作者说实现机制的问题, 让我尝试nanomsg next gen, 不过这个问题暂时可以绕过

用nanomsg的好处就是连接的建立/发送/接收等不用自己操心, 可以直接连接UnityEditor进行双端开发, 对于调试修改非常方便:

通信协议

通常网络通信都需要定义协议, protobuf是最常用的. 不过既然我们做到了两个进程的代码共享, 那完全可以直接把消息的定义直接写在里面, 类似这样:https://stackoverflow.com/questions/13558422/trying-to-design-a-small-message-handler-class-to-simulate-c-sharp-events-what

class IntMessage : Message
{
    public int Value = 100;
}
class StringMessage : Message
{
    public string Value = "a string";
}
static void Main(string[] args)
{
    MessageHandler.Subscribe((StringMessage m) => Console.WriteLine("String : " + m.Value));
    MessageHandler.Subscribe((StringMessage m) => Console.WriteLine("2nd String : " + m.Value));
    MessageHandler.Subscribe((IntMessage m) => Console.WriteLine("Int : " + m.Value));
    MessageHandler.Subscribe((IntMessage m) => Console.WriteLine("2nd Int : " + m.Value));
    MessageHandler.Publish(new IntMessage());
    MessageHandler.Publish(new StringMessage());
}

Message直接序列化后就可以发送到另一端进程了. 不过这样还是有点繁琐, 所以我照着Unity的RPC山寨了个LPC:

本质上的实现也是把MethodCall给序列化了, 走的还是SendMessage的流程:

        public static void SendMessage(Message message)
        {
            var stream = new MemoryStream();
            binaryFormatter.Serialize(stream, message);
            if (!IPC.SendImmediate(stream.GetBuffer()))
            {
                string log = String.Format("{0} : {1}", message.ToString(), NN.StrError(NN.Errno()));
                LogCore(LogType.Error, log);
            }
        }

        public static void ProcedureCall(string className, string methodName, params object[] args)
        {
            SendMessage(new ProcedureCallMessage { ClassName = className, MethodName = methodName, Arguments = args });
        }

收到消息后通过预先注册好的MethodInfo直接Invoke调用执行就可以了.

其它

还有更高级的需求, 那就是跨进程的对象属性编辑. 目前的思路是这样的: * Unity这边的数据对象序列化, 发送到编辑器 * 编辑器收到数据, 反序列化出数据对象(不能依赖Unity的方法, 否则会抛异常) * 编辑器修改后的对象序列化后发送到Unity * Unity这边反序列化出修改后的对象, 把属性值拷贝到当前编辑对象上去

虽然简单暴力, 但也是行之有效的做法, IPC也不用过多考虑数据流量的问题, 当然比较极致一点是实现一套像WPF那样的DataBinding, 针对每个变化的属性做进程间同步, 有时间可以尝试下.

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 基于Unity的编辑器开发(一): GUI框架技术

    用Unity开发的游戏, 需要做个关卡编辑器. 如果只是内部用用, 其实直接扩展Unity就够了; 但问题是需要发布给外部的用户使用, 那么总不能把全套资源和U...

    逍遥剑客
  • 移植了OVRLipSync到UE4

    逍遥剑客
  • Bullet的最小化功能封装

    逍遥剑客
  • U3D安装与破解

    1.打开Finder,在Application(中文系统就是显示“应用程序”)下有Unity文件夹,打开Unity文件夹,选中unity 鼠标右键 选择显示包内...

    py3study
  • EMC Unity架构和增强功能概述

    EMC Unity是EMC最新发布的中端存储系列产品。Unity在简化管理、现代化架构设计、总拥有成本和灵活部署等方面建立了新的标准,满足大型或小型公司资源越趋...

    企鹅号小编
  • Unity推出最新测试版,将支持立体360°影像和视频捕捉技术

    VRPinea
  • 初识 Unity3D

    早些年,游戏引擎市场的变化是非常大的,其中有一些比较出色的软件。比如 unreal,但是 unreal 走的商业模式针对的是大型的游戏公司,大公司通过购买序列号...

    hrscy
  • 用ECMAScript4 ( ActionScript3) 实现Unity的热更新

    unity热更新是一个经久不衰的话题。除了最常见的lua之外,还有如JSBinding,C#等等。这里介绍一个使用ECMAScript4进行热更新的方案。它吸收...

    用户1687945
  • Unity 发布新版本:支持谷歌空间音频和Magic Leap SDK

    Unity是当前市场上最为流行的游戏开发引擎之一,能够支持传统游戏,VR和AR内容开发。近日,Unity发布了新版本的中间件,并且为开发者带来了一系列的功能与优...

    BestSDK
  • Unity 2018.1 beta 发布,支持谷歌空间音频和Magic Leap SDK

    VRPinea

扫码关注云+社区

领取腾讯云代金券