unity热更方案 java script binding中使用protobuff(三)
来源:互联网 发布:手机地图标注软件 编辑:程序博客网 时间:2024/06/06 04:47
上一篇中提到了JSB中要想使用protobuff-net生成的C#代码需要进行的工作,可以看到,对生成的代码改动量还是蛮大的,
手动非常不现实,其实写个简单的基于.proto文件的分析程序,把类中的变量名修改下,然后去掉特定变量,修改函数实现
也不是什么难事,都是字符串替换而已,殊途同归,所以这篇文章就当是protobuff-net的原理介绍吧
先放上protobuff-net的github
https://github.com/mgravell/protobuf-net
protobuff-net分为两部分,运行库和生成工具,生成工具负责生成具有描述性质的C#代码,在运行库中序列化和反序列化需要用到
既然说要改变生成的C#代码,那肯定是改生成工具了
https://github.com/mgravell/protobuf-net/tree/master/ProtoGen
这是对应的protogen的子工程,点进去发现代码很少
CommandLineOptions.cs负责命令行解析
InputFileLoader.cs 负责protobuff的.proto文件加载
注意,后边代码贴的比较多,如果懒得看代码解释过程,直接看最后的结论即可
public static int Main(params string[] args) { CommandLineOptions opt = null; try { opt = Parse(Console.Out, args); opt.Execute(); return opt.ShowHelp ? 1 : 0; // count help as a non-success (we didn't generate code) } catch (Exception ex) { Console.Error.Write(ex.Message); return 1; } }只能顺着程序入口找逻辑了,打开Execute函数
public void Execute() { StringBuilder errors = new StringBuilder(); string oldDir = Environment.CurrentDirectory; Environment.CurrentDirectory = WorkingDirectory; try { if (string.IsNullOrEmpty(OutPath)) { WriteErrorsToFile = false; // can't be } else if (WriteErrorsToFile) { ErrorWriter = new StringWriter(errors); } try { if (ShowLogo) { messageOutput.WriteLine(Properties.Resources.LogoText); } if (ShowHelp) { messageOutput.WriteLine(Properties.Resources.Usage); return; } string xml = LoadFilesAsXml(this); Code = ApplyTransform(this, xml); if (this.OutPath == "-") { } else if (!string.IsNullOrEmpty(this.OutPath)) { File.WriteAllText(this.OutPath, Code); }可以看到,核心功能就俩函数,一个是LoadFileAsXml,一个是 ApplyTransform
<span style="color:#333333;">private static string LoadFilesAsXml(CommandLineOptions options) { FileDescriptorSet set = new FileDescriptorSet(); foreach (string inPath in options.InPaths) { </span><span style="color:#ff0000;">InputFileLoader.Merge</span><span style="color:#333333;">(set, inPath, options.ErrorWriter, options.Arguments.ToArray()); } XmlSerializer xser = new XmlSerializer(typeof(FileDescriptorSet)); XmlWriterSettings settings = new XmlWriterSettings(); settings.Indent = true; settings.IndentChars = " "; settings.NewLineHandling = NewLineHandling.Entitize; StringBuilder sb = new StringBuilder(); using (XmlWriter writer = XmlWriter.Create(sb, settings)) { xser.Serialize(writer, set); } return sb.ToString(); }</span>可以看到FileDescriptorSet这个类,这个类是protobuff的meta数据的描述类,再看下merge函数做的事情
public static void Merge(FileDescriptorSet files, string path, TextWriter stderr, params string[] args) { if (stderr == null) throw new ArgumentNullException("stderr"); if (files == null) throw new ArgumentNullException("files"); if (string.IsNullOrEmpty(path)) throw new ArgumentNullException("path"); bool deletePath = false; if(!IsValidBinary(path)) { // try to use protoc path = <span style="color:#ff0000;">CompileDescriptor</span>(path, stderr, args); deletePath = true; } try { using (FileStream stream = File.OpenRead(path)) { Serializer.Merge(stream, files); } } finally { if(deletePath) { File.Delete(path); } } }通过生成的xml,生成了一个FileDescriptorSet类,并且把生成的xml删除了
private static string CompileDescriptor(string path, TextWriter stderr, params string[] args) { string tmp = Path.GetTempFileName(); string tmpFolder = null, protocPath = null; try { protocPath = GetProtocPath(out tmpFolder); ProcessStartInfo psi = new ProcessStartInfo( protocPath, string.Format(@"""--descriptor_set_out={0}"" ""--proto_path={1}"" ""--proto_path={2}"" ""--proto_path={3}"" --error_format=gcc ""{4}"" {5}", tmp, // output file Path.GetDirectoryName(path), // primary search path Environment.CurrentDirectory, // primary search path Path.GetDirectoryName(protocPath), // secondary search path Path.Combine(Environment.CurrentDirectory, path), // input file string.Join(" ", args) // extra args ) ); Debug.WriteLine(psi.FileName + " " + psi.Arguments, "protoc"); psi.CreateNoWindow = true; psi.WindowStyle = ProcessWindowStyle.Hidden; psi.WorkingDirectory = Environment.CurrentDirectory; psi.UseShellExecute = false; psi.RedirectStandardOutput = psi.RedirectStandardError = true; using (Process proc = Process.Start(psi))
可以看到,生成描述文件的其实就是google的protoc.exe,
private static string ApplyTransform(CommandLineOptions options, string xml) { XmlWriterSettings settings = new XmlWriterSettings(); settings.ConformanceLevel = ConformanceLevel.Auto; settings.CheckCharacters = false; StringBuilder sb = new StringBuilder(); using (XmlReader reader = XmlReader.Create(new StringReader(xml))) using (TextWriter writer = new StringWriter(sb)) { XslCompiledTransform xslt = new XslCompiledTransform(); string xsltTemplate = Path.ChangeExtension(options.Template, "xslt"); if (!File.Exists(xsltTemplate)) { string localXslt = InputFileLoader.CombinePathFromAppRoot(xsltTemplate); if (File.Exists(localXslt)) xsltTemplate = localXslt; } try { xslt.Load(xsltTemplate); } catch (Exception ex) { throw new InvalidOperationException("Unable to load tranform: " + options.Template, ex); } options.XsltOptions.RemoveParam("defaultNamespace", ""); if (options.DefaultNamespace != null) { options.XsltOptions.AddParam("defaultNamespace", "", options.DefaultNamespace); } xslt.Transform(reader, options.XsltOptions, writer); } return sb.ToString(); } }最后看下,ApplyTransform做的事情就是通过xslt模版将生成的xml字符串转换为C#代码
梳理下过程作为结论,protobuff-net的工作流程就是
1.protoc.exe生成单独的一个个类的描述文件xml
2.loader合并类描述并且生成一个总的xml字符串
3.xslt转换生成xml字符串生成代码
4.要改生成规则,改xlst即可,就是那个不适宜人类阅读的csharp.xslt
关于xslt的介绍就不多说了,实施这个事情的是组里的晓川同学,我看着有点晕,他也在群里,有兴趣的同学可以跟他交流
http://download.csdn.net/detail/bn0305/9664369
对应的xslt的下载,替换protogen目录下的文件即可改变生成的C#代码
- unity热更方案 java script binding中使用protobuff(三)
- unity热更方案 java script binding中使用protobuff(一)
- unity热更方案 java script binding中使用protobuff(二)
- unity热更方案 java script binding中使用protobuff(四)
- unity热更方案 java script binding中使用protobuff(收尾)
- Erlang中使用protobuff
- unity-热更1
- Unity热更新方案
- Unity热更新方案
- Unity中使用Script编程小知识(C#语言)
- Unity C#脚本热更
- java热更
- Unity热更新方案(uLua vs sLua)
- Unity热更新方案(uLua vs sLua)
- unity+slua热更流程演示
- Unity 5.3 Assetbundle热更资源
- 【unity系统模块开发】热更
- Unity 资源热更之AssetBundle
- [转]How to load an AutoLISP program
- Unity中颜色空间(Color)HSV,HSB,HSL
- No bean named 'shiroFilter' is defined
- 从零开始学C++之对象语义与值语义、资源管理(RAII、资源所有权)、模拟实现auto_ptr<class>、实现Ptr_vector
- (设计模式1)设计模式5大原则:SOLID原则
- unity热更方案 java script binding中使用protobuff(三)
- Java正则表达式
- 通配符
- 线程池+队列 优先级方式执行队列任务
- Global.asax 文件中可以执行的事件总结
- vim 命令常用
- 一屋不扫,何以扫天下
- 忽明忽暗的闪屏问题
- 由浅到深理解ROS- launch启动文件的理解与编写