<?xml version="1.0" encoding="utf-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><title>CodeGize</title><link>http://www.codegize.com/</link><description>海客谈瀛洲——烟涛微茫信难求</description><item><title>zblog windows IIS下asp+access转php+sqlite</title><link>http://www.codegize.com/?id=93</link><description>&lt;p&gt;由于用的是阿里云的windows服务器，所以之前一直使用的是asp版本的zblog。一直想着转到php，于是趁着国庆休息来整一波。将zblogasp2.3升级为zblogphp1.7.4&lt;/p&gt;&lt;p&gt;首先是让IIS支持PHP&lt;/p&gt;&lt;h2&gt;&lt;br&gt;&lt;/h2&gt;&lt;h2&gt;PHP相关&lt;/h2&gt;&lt;p&gt;1、PHP的下载&lt;/p&gt;&lt;ul&gt;&lt;li&gt;访问 PHP 官网：&lt;a href=&quot;https://windows.php.net/download/&quot;&gt;https://windows.php.net/download/&lt;/a&gt;&lt;/li&gt;&lt;li&gt;选择与系统匹配的版本（建议 64 位），注意：后续将使用 IIS 的FastCGI 模式，所以需要下载&lt;strong&gt;Non Thread Safe (NTS)&lt;/strong&gt; 版本
&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;2、PHP安装&lt;/p&gt;&lt;ul&gt;&lt;li&gt;解压缩即可，比如解压缩到C:\php目录。另外需要在系统环境变量Path中新增这个路径&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;3、配置&lt;/p&gt;&lt;p&gt;由于我想要比较小型的数据库，所以选择了sqlite，因此需要让php开启sqlite3扩展&lt;/p&gt;&lt;ul&gt;&lt;li&gt;在解压缩目录下，可以酌情按需复制php.ini-development或者php.ini-production，并重新命名为php.ini&lt;/li&gt;&lt;li&gt;用记事本打开&lt;code&gt;php.ini&lt;/code&gt;，修改以下关键配置：&lt;/li&gt;&lt;/ul&gt;&lt;hr&gt;&lt;pre class=&quot;brush: csharp;&quot;&gt;; On windows:
extension_dir = &quot;ext&quot;&lt;/pre&gt;&lt;pre class=&quot;brush: csharp;&quot;&gt;
extension=pdo_sqlite
&lt;/pre&gt;&lt;pre class=&quot;brush: csharp;&quot;&gt;&lt;br&gt;&lt;/pre&gt;&lt;pre class=&quot;brush: csharp;&quot;&gt;extension=sqlite3&lt;/pre&gt;&lt;hr&gt;&lt;h2&gt;&lt;br&gt;&lt;/h2&gt;&lt;h2&gt;IIS支持PHP&lt;/h2&gt;&lt;p&gt;在IIS上创建一个网站，比如叫做zblog。在网站的根目录上创建一个web.config，内容如下&lt;/p&gt;&lt;hr&gt;&lt;p&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;&lt;br&gt;
&amp;lt;configuration&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;system.webServer&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;handlers&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;add name=&quot;php&quot; path=&quot;*.php&quot; verb=&quot;*&quot; modules=&quot;FastCgiModule&quot; scriptProcessor=&quot;C:\php\php-cgi.exe&quot; resourceType=&quot;File&quot; /&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/handlers&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;defaultDocument&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;files&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;add value=&quot;index.php&quot; /&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/files&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/defaultDocument&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/system.webServer&amp;gt;&lt;br&gt;
&amp;lt;/configuration&amp;gt;&lt;/p&gt;&lt;p&gt;&lt;hr&gt;&lt;/p&gt;&lt;p&gt;要注意scriptProcessor的值是php安装目录下对应的路径&lt;/p&gt;&lt;p&gt;回到IIS上，将这个网站的应用程序池改为如下设置&lt;br&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.codegize.com/zb_users/upload/2025/10/c289ac94650a140e73a1fcc1ec0b4969.png&quot;&gt;&lt;img width=&quot;237&quot; height=&quot;244&quot; title=&quot;202510061457&quot; style=&quot;display: inline; background-image: none;&quot; alt=&quot;202510061457&quot; src=&quot;http://www.codegize.com/zb_users/upload/2025/10/2ef7536ce8f5e138d8dbd014ac075ee0.png&quot; border=&quot;0&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;OK，这样IIS已经支持php了&lt;/p&gt;&lt;h2&gt;&lt;br&gt;&lt;/h2&gt;&lt;h2&gt;zblogPHP安装&lt;/h2&gt;&lt;p&gt;从官网下载完整包，并且解压到网站的根目录里面&lt;/p&gt;&lt;p&gt;网站创建的时候用的是8088端口，所以在浏览器上打开127.0.0.1:8088，立刻进入安装程序，一路填写，并且创建一个和zblogasp网站一样的管理员账户和密码，等待安装完成即可&lt;/p&gt;&lt;p&gt;注意，如果前面没有开启php的数据库扩展，就会卡住无法安装。我在这里栽了一把。&lt;/p&gt;&lt;h2&gt;&lt;br&gt;&lt;/h2&gt;&lt;h2&gt;数据转移&lt;/h2&gt;&lt;p&gt;这部分其实网上很多了，在老的asp网站上安装asp的数据导出(修复版)插件，并且导出。在新的php网站上安装php数据导入插件。将老网站导出的数据放在新网站的指定目录，使用插件导入即可。&lt;/p&gt;&lt;p&gt;比如&lt;a title=&quot;https://blog.csdn.net/weixin_42467224/article/details/115759941&quot; href=&quot;https://blog.csdn.net/weixin_42467224/article/details/115759941&quot;&gt;https://blog.csdn.net/weixin_42467224/article/details/115759941&lt;/a&gt;&lt;/p&gt;&lt;h2&gt;&lt;br&gt;&lt;/h2&gt;&lt;h2&gt;文章分类下没有文章&lt;/h2&gt;&lt;p&gt;但是导入之后出现了问题，文章分类虽然都正常，但是点击分类却没有显示任何文章&lt;/p&gt;&lt;p&gt;在尝试了各种方法之后发现，需要修改文章的是否置顶数据。可能是asp和php在处理上有点不同，或者是其他什么原因。&lt;/p&gt;&lt;p&gt;于是下载了sqlite的数据库可视化工具SQLiteStudio&lt;/p&gt;&lt;p&gt;打开数据库文件，在zbp_post上右键，选择生成对表的查询-&amp;gt;update&lt;/p&gt;&lt;p&gt;代码改为UPDATE zbp_post SET log_IsTop = 0&lt;/p&gt;&lt;p&gt;然后点击运行按钮去执行这个sql语句，将数据库中所有文章的是否置顶信息都改为0&lt;/p&gt;&lt;p&gt;回到网站后台，点击清除缓存并重新编译模板，一切都正常了。文章都能正常显示。&lt;/p&gt;&lt;h2&gt;&lt;br&gt;&lt;/h2&gt;&lt;h2&gt;其他内容转移&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;插件一个个安装，然后设置一个个改过去&lt;/li&gt;&lt;li&gt;主题也改成相同的，代码修改的部分也差不多一个个文件改过去&lt;/li&gt;&lt;/ul&gt;</description><pubDate>Mon, 06 Oct 2025 15:39:46 +0800</pubDate></item><item><title>IIS反向代理tomcat</title><link>http://www.codegize.com/?id=92</link><description>&lt;p&gt;由于我的网站是IIS搭建的，而某些项目必须使用Tomcat进行部署，所以就有了这次实践。&lt;/p&gt;&lt;h1&gt;主要解决以下问题&lt;/h1&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;&lt;p&gt;问题1：IIS和tomcat的2各网站使用的端口不同，但是希望使用二级域名来访问，而不是通过端口号来访问&lt;/p&gt;&lt;p&gt;问题2：不希望防火墙开放tomcat的接口给外部&lt;/p&gt;&lt;h1&gt;准备工作&lt;/h1&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;&lt;p&gt;1、先确保tomcat项目能够正常访问。&lt;/p&gt;&lt;p&gt;比如IIS通常使用的是80端口，tomcat项目使用8080端口。用localhost:8080访问，确保tomcat能正常访问。&lt;/p&gt;&lt;p&gt;2、安装IIS相关插件&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://www.alipan.com/s/Un17qi3Gbg3&quot;&gt;https://www.alipan.com/s/Un17qi3Gbg3&lt;/a&gt;&lt;br&gt;
提取码: a5b1&lt;/p&gt;&lt;p&gt;2个软件都安装&lt;/p&gt;&lt;h1&gt;IIS配置&lt;/h1&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;&lt;p&gt;打开IIS&lt;/p&gt;&lt;h2&gt;开启反向代理功能&lt;/h2&gt;&lt;p&gt;在IIS左侧网站的根节点下，可以看到有Application Request Routing Cache&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.codegize.com/zb_users/upload/2025/10/f68e3bbc8172ab3ede1497487d2d2ed3.png&quot;&gt;&lt;img width=&quot;518&quot; height=&quot;267&quot; title=&quot;image&quot; style=&quot;display: inline; background-image: none;&quot; alt=&quot;image&quot; src=&quot;http://www.codegize.com/zb_users/upload/2025/10/404d75386f98b1dab0a6585f0df23fd6.png&quot; border=&quot;0&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;双击进入，点击右侧栏的Server Proxy Settings进入代理配置&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.codegize.com/zb_users/upload/2025/10/51bc51469c4f0ff9a90e50b7d4c662d0.png&quot;&gt;&lt;img width=&quot;492&quot; height=&quot;228&quot; title=&quot;image&quot; style=&quot;display: inline; background-image: none;&quot; alt=&quot;image&quot; src=&quot;http://www.codegize.com/zb_users/upload/2025/10/1f3cc1e2f19dc9525a24fda135aedb8a.png&quot; border=&quot;0&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;勾选EnabkeProxy，并在右侧栏点击应用&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.codegize.com/zb_users/upload/2025/10/ef55d88326379538a5f260b4551089e2.png&quot;&gt;&lt;img width=&quot;495&quot; height=&quot;207&quot; title=&quot;image&quot; style=&quot;display: inline; background-image: none;&quot; alt=&quot;image&quot; src=&quot;http://www.codegize.com/zb_users/upload/2025/10/cfb694b3be084d0d450a4d2cebbb8f78.png&quot; border=&quot;0&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;h2&gt;配置网站url重写&lt;/h2&gt;&lt;p&gt;1、创建一个网站，网站的存储位置任意&lt;/p&gt;&lt;p&gt;2、在IIS中选中这个网站，可以看到URL重写功能，双击进入URL重写&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.codegize.com/zb_users/upload/2025/10/fc772e249b030be650e8a5b6dce6b20b.png&quot;&gt;&lt;img width=&quot;520&quot; height=&quot;300&quot; title=&quot;image&quot; style=&quot;display: inline; background-image: none;&quot; alt=&quot;image&quot; src=&quot;http://www.codegize.com/zb_users/upload/2025/10/13f6842487562b55da5b97d788cf5e02.png&quot; border=&quot;0&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;3、添加新规则(空白规则)&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.codegize.com/zb_users/upload/2025/10/62e872f9860f3c21536b42e9f1d31ffe.png&quot;&gt;&lt;img width=&quot;325&quot; height=&quot;180&quot; title=&quot;image&quot; style=&quot;display: inline; background-image: none;&quot; alt=&quot;image&quot; src=&quot;http://www.codegize.com/zb_users/upload/2025/10/b4cd551fcaadcff0ebe553c2fdbcc153.png&quot; border=&quot;0&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;如图所示，模式中填入^(.*)&lt;/p&gt;&lt;p&gt;4、填写条件&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.codegize.com/zb_users/upload/2025/10/1e2820c173fbec0877035f616963d9ba.png&quot;&gt;&lt;img width=&quot;336&quot; height=&quot;105&quot; title=&quot;202510051002&quot; style=&quot;display: inline; background-image: none;&quot; alt=&quot;202510051002&quot; src=&quot;http://www.codegize.com/zb_users/upload/2025/10/5b9d011dc7bde67173666cf1f3bc6b88.png&quot; border=&quot;0&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;如图所示，添加一个条件，条件输入填入{HTTP_HOST}&lt;/p&gt;&lt;p&gt;模式填入你的目标网址，比如^xxx.xxx.com$，这样如果用户输入了这个网址就会触发。当然这个网址的域名必须开通过解析&lt;/p&gt;&lt;p&gt;5、填入重写URL&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.codegize.com/zb_users/upload/2025/10/c8ed310a5a213a8abee46b1c40e172ef.png&quot;&gt;&lt;img width=&quot;244&quot; height=&quot;107&quot; title=&quot;202510051012&quot; style=&quot;display: inline; background-image: none;&quot; alt=&quot;202510051012&quot; src=&quot;http://www.codegize.com/zb_users/upload/2025/10/5e870bad04e2238a83a3f7ea94fbde7e.png&quot; border=&quot;0&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;比如填入tomcat的地址，这里我填入&lt;a href=&quot;http://localhost:8080/draw/{R:1&quot;&gt;http://localhost:8080/draw/{R:1&lt;/a&gt;}，它的意思就是跳转到tomcat的draw目录下&lt;/p&gt;&lt;p&gt;其中{R:1}表示用户输入的url后的参数，即xxx.xxx.com后面的字符。但是不是很确定，因为&lt;/p&gt;&lt;p&gt;{R:0}：匹配整个正则表达式的完整内容（整个 URL 中被匹配的部分）。
&lt;br&gt;{R:1}、{R:2}...{R:N}：对应正则表达式中第 1 到第 N 个捕获组（用 () 定义的部分）&lt;/p&gt;&lt;p&gt;6、应用一下&lt;/p&gt;&lt;p&gt;至此IIS就已经完成了反代理和URL重写的功能了&lt;/p&gt;</description><pubDate>Mon, 06 Oct 2025 10:26:04 +0800</pubDate></item><item><title>极空间与SVN</title><link>http://www.codegize.com/?id=89</link><description>&lt;h2&gt;&lt;a href=&quot;http://www.codegize.com/zb_users/upload/2024/2/96e9d71ecc0fa91e93519939d6222f43_2.jpg&quot;&gt;&lt;a href=&quot;http://www.codegize.com/zb_users/upload/2024/2/96e9d71ecc0fa91e93519939d6222f43_2.jpg&quot;&gt;&lt;img width=&quot;123&quot; height=&quot;123&quot; title=&quot;96e9d71ecc0fa91e93519939d6222f43&quot; style=&quot;display: inline; background-image: none;&quot; alt=&quot;96e9d71ecc0fa91e93519939d6222f43&quot; src=&quot;http://www.codegize.com/zb_users/upload/2024/2/96e9d71ecc0fa91e93519939d6222f43_thumb.jpg&quot; border=&quot;0&quot;&gt;&lt;/a&gt;&lt;br&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;去年搞了一个极空间Z2Pro，于是就想着把之前的svn库从移动硬盘转移到jZ2pro上。&lt;/p&gt;&lt;a href=&quot;http://www.codegize.com/zb_users/upload/2024/2/96e9d71ecc0fa91e93519939d6222f43_2.jpg&quot;&gt;&lt;a href=&quot;http://www.codegize.com/zb_users/upload/2024/2/96e9d71ecc0fa91e93519939d6222f43_2.jpg&quot;&gt;&lt;br&gt;&lt;/a&gt;&lt;p&gt;z2pro毕竟不是一个虚拟机，也没有虚拟机，所以没法按照svn服务器。另外使用的docker是arm版本对，所以svn服务器的docker库也没有。想着我的svn库以前都是本地库，所以也不纠结去装svn服务器了。&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.codegize.com/zb_users/upload/2024/2/96e9d71ecc0fa91e93519939d6222f43_2.jpg&quot;&gt;&lt;a href=&quot;http://www.codegize.com/zb_users/upload/2024/2/96e9d71ecc0fa91e93519939d6222f43_2.jpg&quot;&gt;&lt;br&gt;&lt;/a&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;所以最好对方法是本机能够直接访问到z2pro的svn本地库文件&lt;/p&gt;&lt;p&gt;极空间本身带有挂载磁盘的功能，但是要一直开着极空间这个软件，非常不方便。所以要使用其他方法&lt;/p&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;&lt;p&gt;极空间默认开启了Samba服务，说白了就是文件夹共享服务。每个极空间的账号可以访问z2pro下自己的文件夹或者是共享的那些文件夹。&lt;/p&gt;&lt;p&gt;所以可以把svn库文件全部放在z2pro自己文件夹下。&lt;/p&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;&lt;p&gt;在pc端，创建一个文件夹，右键，选择svn checkout。&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.codegize.com/zb_users/upload/2024/2/20240224234735_2.png&quot;&gt;&lt;img width=&quot;244&quot; height=&quot;215&quot; title=&quot;20240224234735&quot; style=&quot;display: inline; background-image: none;&quot; alt=&quot;20240224234735&quot; src=&quot;http://www.codegize.com/zb_users/upload/2024/2/20240224234735_thumb.png&quot; border=&quot;0&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;在弹出的窗口中，点击库目录输入框后面的按钮，&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.codegize.com/zb_users/upload/2024/2/20240224234836_2.png&quot;&gt;&lt;img width=&quot;244&quot; height=&quot;153&quot; title=&quot;20240224234836&quot; style=&quot;display: inline; background-image: none;&quot; alt=&quot;20240224234836&quot; src=&quot;http://www.codegize.com/zb_users/upload/2024/2/20240224234836_thumb.png&quot; border=&quot;0&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;选择网络，可以看到z2pro的机器。双击打开，会要求输入z2pro的账号和密码。输入之后就可以看到自己的文件夹和共享的文件夹了。一直选择到自己的svn库文件即可&lt;/p&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;&lt;p&gt;至此就完成了从z2pro的svn库的checkout操作了。后续的操作就和平常svn操作一致就可以了。&lt;/p&gt;</description><pubDate>Sat, 24 Feb 2024 23:53:49 +0800</pubDate></item><item><title>photon 简介</title><link>http://www.codegize.com/?id=88</link><description>&lt;p&gt;photon是德国Exit Games开发的一套网络同步框架，也叫photon engine。&lt;/p&gt;&lt;p&gt;这家公司有着15年以上的服务器端开发经验。&lt;/p&gt;&lt;p&gt;属于商业软件，收费。有提供免费的版本&lt;/p&gt;&lt;p&gt;photon产品目前比较有用的是&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;Fusion：适用于photon云服务器的Unity状态同步框架&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Quantum：适用于photon云服务器的Unity的ECS同步框架，给予预测回滚机制，适用于对网络延迟较为敏感对游戏，比如体育 moba 赛车 格斗游戏等&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Realtime：适用于photon云服务器或者自建服务器对一套解决方案，包括匹配机制等。比较泛用&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Server：用于自建服务器，只支持windows。底层用c++，开发用c#。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;很早以前测过，如果用国外对photon云服务器，基本上就没法用。所以用Realtime和Server是比较好对选择。当然也可以尝试用国内对photon云服务器（没试过）&lt;/p&gt;&lt;p&gt;如果只是小项目或者用于快速验证，考虑到都是用C#写，可以提高开发效率。&lt;/p&gt;</description><pubDate>Sat, 24 Feb 2024 22:58:20 +0800</pubDate></item><item><title>配对函数Cantor pairing</title><link>http://www.codegize.com/?id=86</link><description>&lt;p&gt;在&lt;a href=&quot;http://www.codegize.com/post/84.html&quot; target=&quot;_blank&quot;&gt;《正整数对的唯一解》&lt;/a&gt;一文中，提出了一个问题，对于不同的整数对（a，b）找到唯一的正整数c，这样就可以通过c，一次性的比较不同整数对的大小&lt;/p&gt;&lt;p&gt;其实这个问题的解决方案已经在文中很接近了，就是将2维数据编码为1维表的过程&lt;/p&gt;&lt;p&gt;在询问了ChatGPT之后，我得到了一个关键的词，叫做配对函数&lt;/p&gt;&lt;p&gt;在数学中，配对函数是一种将两个自然数唯一地编码成一个自然数的过程。&lt;/p&gt;&lt;p&gt;其中，最为广泛使用的是康托尔配对函数（&lt;span style=&quot;text-wrap: wrap;&quot;&gt;Cantor Pairing Function&lt;/span&gt;）&lt;/p&gt;&lt;p&gt;即&lt;img src=&quot;https://bkimg.cdn.bcebos.com/formula/5e6583fea4bfdbe3e4fe6b2d6c5233b9.svg&quot; style=&quot;box-sizing: content-box; margin: 0px; padding: 0px; display: initial; max-width: 100%; border: 0px; color: rgb(51, 51, 51); font-family: &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, sans-serif; text-wrap: wrap; background-color: rgb(255, 255, 255); vertical-align: -1.755ex; width: 42.567ex; height: 5.009ex;&quot;/&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;其原理是按照下图进行二维编码&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;http://www.codegize.com/zb_users/upload/2023/12/2023121150131301.jpg&quot; width=&quot;455&quot; height=&quot;440&quot; title=&quot;POPO-screenshot-20231211-135338.jpg&quot; alt=&quot;POPO-screenshot-20231211-135338.jpg&quot;/&gt;&lt;/p&gt;&lt;p&gt;然后通过k1作为横坐标，k2作为终坐标索引到编码。&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;text-wrap: wrap;&quot;&gt;配对函数有很多，但是&lt;/span&gt;Cantor Pairing Function相比其他的配对函数具备简明易懂，密布不易超界，计算简单等诸多优点&lt;/p&gt;&lt;p&gt;所以用途非常广泛，比如hash里面也常常用到。&lt;/p&gt;</description><pubDate>Mon, 11 Dec 2023 11:51:57 +0800</pubDate></item><item><title>Neat Download Manager</title><link>http://www.codegize.com/?id=85</link><description>&lt;p&gt;简称NeatDM，是一款多线程下载工具和视频嗅探工具&lt;/p&gt;&lt;p&gt;官网：&lt;a href=&quot;https://www.neatdownloadmanager.com/index.php/en/&quot; _src=&quot;https://www.neatdownloadmanager.com/index.php/en/&quot;&gt;https://www.neatdownloadmanager.com/index.php/en/&lt;/a&gt; &lt;/p&gt;&lt;p&gt;特点&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot; style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;&lt;p&gt;支持win+mac&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;默认8线程，最大32线程&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;带有浏览器插件，包括以下浏览器&lt;/p&gt;&lt;/li&gt;&lt;li&gt;Firefox , Chrome, MS Edge和Chromium内核的浏览器&lt;/li&gt;&lt;li&gt;&lt;p&gt;软件体积极小，安装包1MB不到&lt;br/&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;http://www.neatdownloadmanager.com/images/1.jpg&quot; width=&quot;546&quot; height=&quot;340&quot;/&gt;&lt;/p&gt;</description><pubDate>Wed, 25 Oct 2023 20:48:58 +0800</pubDate></item><item><title>正整数对的唯一解</title><link>http://www.codegize.com/?id=84</link><description>&lt;p&gt;失眠，原因很多&lt;/p&gt;&lt;p&gt;昨夜失眠，竟然是因为想到一个数学题&lt;/p&gt;&lt;p&gt;一开始是这样的，双方投掷2个骰子，一般的规则就是每个人用加法把自己的2个骰子点数加起来，然后比大小&lt;/p&gt;&lt;p&gt;但是有时候会出现双方相同的情况，比如1+6和2+5&lt;/p&gt;&lt;p&gt;所以就在想，如果排除掉点数完全一样的情况下，有没有一种数学算法，可以一次计算比出大小&lt;/p&gt;&lt;p&gt;扩展和归纳起来就是：&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;span style=&quot;color:#ff0000&quot;&gt;对于一个整数对a,b（ab不分先后，即1/6和6/1视为同一个整数对），设计一种算法，使得对于不同的整数对，计算出来的结果为整数且唯一？&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;span style=&quot;color:#ff0000&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color:#ff0000&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color:#ff0000&quot;&gt;&lt;span style=&quot;color:#000000&quot;&gt;想不到好的办法，一开始先试试乘法即f(a,b)=a*b&lt;/span&gt;&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;显然，这个算法很快就被排除了，原因很简单，比如2*3=1*6或者2*2 = 1*4&lt;/p&gt;&lt;p&gt;既然乘法不行，是不是可以和加法结合起来呢，比如f(a,b)=a*b+a+b&lt;/p&gt;&lt;p&gt;睡不着，想了2个小时，发现一个反例，2*3+2+3 = 11 = 1*5+1+5&lt;/p&gt;&lt;p&gt;好吧，自己解决不了，就去请求万能的朋友圈&lt;/p&gt;&lt;p&gt;恍恍惚惚，半睡半醒之间，感觉找到了突破口，就是查二维表&lt;/p&gt;&lt;p&gt;做游戏我们常常会有查表的操作，细细一想，不就是查个二维表么，只要构建一个可以利用一个一元公式构建的二维表就行&lt;/p&gt;&lt;p&gt;比如最简单有序的6*6的表&lt;/p&gt;&lt;table width=&quot;476&quot; border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;2&quot;&gt;&lt;tbody&gt;&lt;tr class=&quot;firstRow&quot;&gt;&lt;td width=&quot;79&quot; valign=&quot;top&quot;&gt;1&lt;/td&gt;&lt;td width=&quot;79&quot; valign=&quot;top&quot;&gt;2&lt;/td&gt;&lt;td width=&quot;79&quot; valign=&quot;top&quot;&gt;3&lt;/td&gt;&lt;td width=&quot;79&quot; valign=&quot;top&quot;&gt;4&lt;/td&gt;&lt;td width=&quot;79&quot; valign=&quot;top&quot;&gt;5&lt;/td&gt;&lt;td width=&quot;79&quot; valign=&quot;top&quot;&gt;6&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width=&quot;79&quot; valign=&quot;top&quot;&gt;7&lt;/td&gt;&lt;td width=&quot;79&quot; valign=&quot;top&quot;&gt;8&lt;/td&gt;&lt;td width=&quot;79&quot; valign=&quot;top&quot;&gt;9&lt;/td&gt;&lt;td width=&quot;79&quot; valign=&quot;top&quot;&gt;10&lt;/td&gt;&lt;td width=&quot;79&quot; valign=&quot;top&quot;&gt;11&lt;/td&gt;&lt;td width=&quot;79&quot; valign=&quot;top&quot;&gt;12&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width=&quot;79&quot; valign=&quot;top&quot;&gt;13&lt;/td&gt;&lt;td width=&quot;79&quot; valign=&quot;top&quot;&gt;14&lt;/td&gt;&lt;td width=&quot;79&quot; valign=&quot;top&quot;&gt;15&lt;/td&gt;&lt;td width=&quot;79&quot; valign=&quot;top&quot;&gt;16&lt;/td&gt;&lt;td width=&quot;79&quot; valign=&quot;top&quot;&gt;17&lt;/td&gt;&lt;td width=&quot;79&quot; valign=&quot;top&quot;&gt;18&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width=&quot;79&quot; valign=&quot;top&quot;&gt;19&lt;/td&gt;&lt;td width=&quot;79&quot; valign=&quot;top&quot;&gt;20&lt;/td&gt;&lt;td width=&quot;79&quot; valign=&quot;top&quot;&gt;21&lt;/td&gt;&lt;td width=&quot;79&quot; valign=&quot;top&quot;&gt;22&lt;/td&gt;&lt;td width=&quot;79&quot; valign=&quot;top&quot;&gt;23&lt;/td&gt;&lt;td width=&quot;79&quot; valign=&quot;top&quot;&gt;24&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width=&quot;79&quot; valign=&quot;top&quot;&gt;15&lt;/td&gt;&lt;td width=&quot;79&quot; valign=&quot;top&quot;&gt;26&lt;/td&gt;&lt;td width=&quot;79&quot; valign=&quot;top&quot;&gt;27&lt;/td&gt;&lt;td width=&quot;79&quot; valign=&quot;top&quot;&gt;28&lt;/td&gt;&lt;td width=&quot;79&quot; valign=&quot;top&quot;&gt;29&lt;/td&gt;&lt;td width=&quot;79&quot; valign=&quot;top&quot;&gt;30&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width=&quot;79&quot; valign=&quot;top&quot;&gt;31&lt;/td&gt;&lt;td width=&quot;79&quot; valign=&quot;top&quot;&gt;32&lt;/td&gt;&lt;td width=&quot;79&quot; valign=&quot;top&quot;&gt;33&lt;/td&gt;&lt;td width=&quot;79&quot; valign=&quot;top&quot;&gt;34&lt;/td&gt;&lt;td width=&quot;79&quot; valign=&quot;top&quot;&gt;35&lt;/td&gt;&lt;td width=&quot;79&quot; valign=&quot;top&quot;&gt;36&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;那么对于每一行a和每一行b就可以得到唯一的解(a-1)*6+b=a*6+b-6，-6不影响所以也可以去掉&lt;/p&gt;&lt;p&gt;这么一推广就可以得到这样的公式&lt;/p&gt;&lt;p&gt;f(a,b)=a*N+b&lt;/p&gt;&lt;p&gt;但是很显然有个问题，比如对于f(a,b)=a*6+b来说&lt;/p&gt;&lt;p&gt;随便取个ab，比如3和4，结果为3*6+4 = 22，那么我也可以a取个2，然后找到b使得结果也为22，即2*6+10=22&lt;/p&gt;&lt;p&gt;难道这样是思路是错误的么？&lt;/p&gt;&lt;p&gt;再看2*6+10这个例子，可以看到原因在于表里面根本就没有第10列，所以数据是超出了查表的范围的&lt;/p&gt;&lt;p&gt;那怎么办？既然超出列数，我们增加列数就可以。让列处于我们可查询的范围内。那么&lt;/p&gt;&lt;p&gt;N的最小值可以等于b。&lt;/p&gt;&lt;p&gt;那么公式就简化为f(a,b)=a*b+b= (a+1)*b&lt;/p&gt;&lt;p&gt;从公式上看就很神奇，之前f(a,b)=a*b不行，但是a加了一个1就可以&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;那么怎么从数学上证明这个公式是可行的呢？&lt;/p&gt;&lt;p&gt;来个反证法，&lt;/p&gt;&lt;p&gt;如果存在2对不同的整数对(a1,b1)和(a2,b2)，使得(a1+1)*b1 = (a2+1)*b2，那么我们的公式就是错误的，否则肯定是正确的。&lt;/p&gt;&lt;p&gt;好吧，下面不会了，等想到数学证明方法再继续&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;!--more--&gt;&lt;p&gt;最终解决办法见《&lt;a href=&quot;http://www.codegize.com/post/cantor_pairing.html&quot; target=&quot;_blank&quot;&gt;配对函数Cantor pairing&lt;/a&gt;》&lt;/p&gt;</description><pubDate>Sat, 20 Nov 2021 10:55:13 +0800</pubDate></item><item><title>迷宫地图编辑器：Xnode插件实践</title><link>http://www.codegize.com/?id=83</link><description>&lt;h1&gt;前言&lt;/h1&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;&lt;p&gt;在unity开发游戏编辑器扩展中，我们常常会用到节点编辑器。节点编辑器就是用节点和节点连接的图形话编辑器，比如unity自带的shadergraph就是一个节点编辑器。用户通过节点之间的拖拖拉拉，连线就能得到想要的结果。&lt;p&gt;在一段时间里，打算做一个迷宫的地图编辑器，每个地图有上下左右4个门，可以和其他地图连接。于是打算开发一个编辑器，通过可视化的方式去生成整个迷宫的数据。查了很多的节点插件，xnode作为轻量级的节点编辑器就非常适合用来做二次开发&lt;p&gt;Xnode（&lt;a href=&quot;https://github.com/Siccity/xNode&quot;&gt;https://github.com/Siccity/xNode&lt;/a&gt;）是开源的轻量级的节点编辑器插件。所以理解和开发起来非常方便&lt;p&gt;最终开发效果如下。可以在窗口内创建节点，设置四个门的跳转关系，最终点击导出保存为一个指定的数据文件&lt;p&gt;&lt;a href=&quot;http://www.codegize.com/zb_users/upload/2021/9/%E5%B1%8F%E5%B9%95%E6%88%AA%E5%9B%BE2021-09-25193709_2.jpg&quot;&gt;&lt;img width=&quot;495&quot; height=&quot;448&quot; title=&quot;屏幕截图 2021-09-25 193709&quot; style=&quot;display: inline; background-image: none;&quot; alt=&quot;屏幕截图 2021-09-25 193709&quot; src=&quot;http://www.codegize.com/zb_users/upload/2021/9/%E5%B1%8F%E5%B9%95%E6%88%AA%E5%9B%BE2021-09-25193709_thumb.jpg&quot; border=&quot;0&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;h1&gt;&lt;br&gt;&lt;/h1&gt;&lt;h1&gt;安装Xnode&lt;/h1&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;&lt;p&gt;从github下载这个插件，解压出来放在Assets目录下即可&lt;/p&gt;&lt;p&gt;不过这里我做了一点点改动。考虑到只想要xnode的编辑器功能，不打算打包的时候把xnode的代码带到最终的包里面，所以把runtime的代码全部放到了Editor目录里面。这样就可以保证打包时候，我们游戏的工程是和xnode相互独立的。&lt;/p&gt;&lt;p&gt;如图所示，现在工程里面代码全部在Editor下面&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.codegize.com/zb_users/upload/2021/9/%E5%B1%8F%E5%B9%95%E6%88%AA%E5%9B%BE2021-09-25194330_2.jpg&quot;&gt;&lt;img width=&quot;289&quot; height=&quot;176&quot; title=&quot;屏幕截图 2021-09-25 194330&quot; style=&quot;display: inline; background-image: none;&quot; alt=&quot;屏幕截图 2021-09-25 194330&quot; src=&quot;http://www.codegize.com/zb_users/upload/2021/9/%E5%B1%8F%E5%B9%95%E6%88%AA%E5%9B%BE2021-09-25194330_thumb.jpg&quot; border=&quot;0&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;h1&gt;&lt;br&gt;&lt;/h1&gt;&lt;h1&gt;定义图和节点&lt;/h1&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;&lt;p&gt;xnode是非常轻量级的非常易开发的。它的概念就是图Graph，节点Node，端口Port。端口我们可以先不关心。先来定义一下图&lt;/p&gt;&lt;div class=&quot;cnblogs_code&quot; style=&quot;padding: 5px; border: 1px solid rgb(204, 204, 204); border-image: none; background-color: rgb(245, 245, 245);&quot;&gt;&lt;pre&gt;[CreateAssetMenu(fileName = &lt;span style=&quot;color: rgb(128, 0, 0);&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: rgb(128, 0, 0);&quot;&gt;mazelayer&lt;/span&gt;&lt;span style=&quot;color: rgb(128, 0, 0);&quot;&gt;&quot;&lt;/span&gt;, menuName = &lt;span style=&quot;color: rgb(128, 0, 0);&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: rgb(128, 0, 0);&quot;&gt;UmGame/场景/迷宫编辑器数据&lt;/span&gt;&lt;span style=&quot;color: rgb(128, 0, 0);&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;)]
&lt;/span&gt;&lt;span style=&quot;color: rgb(0, 0, 255);&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: rgb(0, 0, 255);&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt; MazeLayerGraph : NodeGraph&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;{&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;}
&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;就是这么简单，继承一下NodeGraph即可。&lt;/p&gt;&lt;p&gt;这里给MazeLayerGraph加了一个CreateAssetMenu标签。这样就可以在Project面板中，通过右键菜单的方式创建出这个图文件。&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.codegize.com/zb_users/upload/2021/9/%E5%B1%8F%E5%B9%95%E6%88%AA%E5%9B%BE2021-09-25195638_2.jpg&quot;&gt;&lt;img width=&quot;594&quot; height=&quot;186&quot; title=&quot;屏幕截图 2021-09-25 195638&quot; style=&quot;display: inline; background-image: none;&quot; alt=&quot;屏幕截图 2021-09-25 195638&quot; src=&quot;http://www.codegize.com/zb_users/upload/2021/9/%E5%B1%8F%E5%B9%95%E6%88%AA%E5%9B%BE2021-09-25195638_thumb.jpg&quot; border=&quot;0&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;创建之后，就可以通过双击这个文件或者在Inspector面板中点击Open或者点击EditGraph都可以打开&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.codegize.com/zb_users/upload/2021/9/%E5%B1%8F%E5%B9%95%E6%88%AA%E5%9B%BE2021-09-25200003_2.jpg&quot;&gt;&lt;img width=&quot;381&quot; height=&quot;163&quot; title=&quot;屏幕截图 2021-09-25 200003&quot; style=&quot;display: inline; background-image: none;&quot; alt=&quot;屏幕截图 2021-09-25 200003&quot; src=&quot;http://www.codegize.com/zb_users/upload/2021/9/%E5%B1%8F%E5%B9%95%E6%88%AA%E5%9B%BE2021-09-25200003_thumb.jpg&quot; border=&quot;0&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;打开的界面什么都没有，右键菜单里面也没什么东西&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.codegize.com/zb_users/upload/2021/9/%E5%B1%8F%E5%B9%95%E6%88%AA%E5%9B%BE2021-09-25200210_4.jpg&quot;&gt;&lt;img width=&quot;366&quot; height=&quot;128&quot; title=&quot;屏幕截图 2021-09-25 200210&quot; style=&quot;display: inline; background-image: none;&quot; alt=&quot;屏幕截图 2021-09-25 200210&quot; src=&quot;http://www.codegize.com/zb_users/upload/2021/9/%E5%B1%8F%E5%B9%95%E6%88%AA%E5%9B%BE2021-09-25200210_thumb_1.jpg&quot; border=&quot;0&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;这是因为还没有定义节点Node，所以开始定义一下Node&lt;/p&gt;&lt;p&gt;&lt;font color=&quot;#5eaae4&quot;&gt;&lt;a&gt;&lt;font color=&quot;#000000&quot;&gt;&lt;/font&gt;&lt;/a&gt;&lt;/font&gt;&lt;div class=&quot;cnblogs_code&quot; style=&quot;padding: 5px; border: 1px solid rgb(204, 204, 204); border-image: none; background-color: rgb(245, 245, 245);&quot;&gt;&lt;pre&gt;&lt;font color=&quot;#5eaae4&quot;&gt;&lt;a&gt;&lt;font color=&quot;#000000&quot;&gt;&lt;span style=&quot;color: rgb(0, 0, 255);&quot;&gt;namespace&lt;/span&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt; Game
{
    &lt;/span&gt;&lt;span style=&quot;color: rgb(0, 0, 255);&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: rgb(0, 0, 255);&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt; MazeLayerRoomNode : Node
    {
        &lt;/span&gt;&lt;span style=&quot;color: rgb(0, 0, 255);&quot;&gt;public&lt;/span&gt; Texture2D Tex { &lt;span style=&quot;color: rgb(0, 0, 255);&quot;&gt;get&lt;/span&gt;; &lt;span style=&quot;color: rgb(0, 0, 255);&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;; }
        &lt;/span&gt;&lt;span style=&quot;color: rgb(0, 0, 255);&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: rgb(0, 0, 255);&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt; RoomID;

        &lt;/span&gt;&lt;span style=&quot;color: rgb(0, 0, 255);&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: rgb(0, 0, 255);&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt; TerrianID; 
        &lt;/span&gt;&lt;span style=&quot;color: rgb(0, 0, 255);&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: rgb(0, 0, 255);&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt; RoomName;

    }
}&lt;/span&gt;&lt;/font&gt;&lt;/a&gt;&lt;/font&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;font color=&quot;#5eaae4&quot;&gt;&lt;a&gt;&lt;font color=&quot;#000000&quot;&gt;也很简单，继承Node即可。这里因为后面打算要画一个迷宫房间的图，还要记录房间的ID，所以定义了一些变量。回到unity，右键就可以看到有一个菜单了&lt;/font&gt;&lt;/a&gt;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.codegize.com/zb_users/upload/2021/9/%E5%B1%8F%E5%B9%95%E6%88%AA%E5%9B%BE2021-09-25200917_2.jpg&quot;&gt;&lt;img width=&quot;385&quot; height=&quot;171&quot; title=&quot;屏幕截图 2021-09-25 200917&quot; style=&quot;display: inline; background-image: none;&quot; alt=&quot;屏幕截图 2021-09-25 200917&quot; src=&quot;http://www.codegize.com/zb_users/upload/2021/9/%E5%B1%8F%E5%B9%95%E6%88%AA%E5%9B%BE2021-09-25200917_thumb.jpg&quot; border=&quot;0&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;font color=&quot;#5eaae4&quot;&gt;&lt;a&gt;&lt;font color=&quot;#000000&quot;&gt;&lt;p&gt;&lt;font color=&quot;#000000&quot;&gt;选择这个菜单就可以创建出一个节点了&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.codegize.com/zb_users/upload/2021/9/%E5%B1%8F%E5%B9%95%E6%88%AA%E5%9B%BE2021-09-25201637_2.jpg&quot;&gt;&lt;img width=&quot;387&quot; height=&quot;144&quot; title=&quot;屏幕截图 2021-09-25 201637&quot; style=&quot;display: inline; background-image: none;&quot; alt=&quot;屏幕截图 2021-09-25 201637&quot; src=&quot;http://www.codegize.com/zb_users/upload/2021/9/%E5%B1%8F%E5%B9%95%E6%88%AA%E5%9B%BE2021-09-25201637_thumb.jpg&quot; border=&quot;0&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;但是这些数据不是我想在图中展示的，所以打算重写节点的绘制。&lt;/p&gt;&lt;h1&gt;&lt;br&gt;&lt;/h1&gt;&lt;h1&gt;Node重绘&lt;/h1&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;&lt;p&gt;xnode中实现Node重绘非常简单，只要类似unity写一个CustomEditor就可以。对二次开发非常友好。&lt;/p&gt;&lt;div class=&quot;cnblogs_code&quot; style=&quot;padding: 5px; border: 1px solid rgb(204, 204, 204); border-image: none; background-color: rgb(245, 245, 245);&quot;&gt;&lt;pre&gt;&lt;span style=&quot;color: rgb(0, 0, 255);&quot;&gt;namespace&lt;/span&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt; Game
{
&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [CustomNodeEditor(typeof(MazeLayerRoomNode))]&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public class MazeLayerRoomNodeEditor : NodeEditor&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public override void OnHeaderGUI()&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var tar = (MazeLayerRoomNode)target;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var head = tar.RoomID.ToString();&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (!string.IsNullOrEmpty(tar.RoomName))&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; head += &quot;:&quot; + tar.RoomName;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; EditorGUILayout.LabelField(head, NodeEditorResources.styles.nodeHeader, GUILayout.Height(30));&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public override int GetWidth()&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return 115;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public Rect[] Points = new Rect[4];&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public override void OnBodyGUI()&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var tar = (MazeLayerRoomNode)target;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var width = GetWidth();&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (tar.Tex == null)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; tar.Tex = AssetDatabase.LoadAssetAtPath&amp;lt;Texture2D&amp;gt;(&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; $&quot;Assets/Game/Art/Map/levelmap/{tar.TerrianID}.png&quot;);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GUILayout.Label(&quot;&quot;, GUILayout.Width(width - 20), GUILayout.Height(210 / 2f));&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var r = new Rect(20, 35, 150 / 2f, 210 / 2f);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (tar.Tex != null)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; EditorGUI.DrawPreviewTexture(r, tar.Tex);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; EditorGUI.DrawRect(r, Color.white);&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var height = GUILayoutUtility.GetLastRect().yMax;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; EditorGUILayout.LabelField(&quot;&quot;, GUILayout.Height(height));&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var rect = new Rect(0, 0, 16, 16);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; foreach (var port in target.DynamicPorts)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var rport = port;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var strs = rport.fieldName.Split(&#039;_&#039;);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (strs.Length != 2)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; continue;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var doorid = (EmDoorID)int.Parse(strs[0]);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; switch (doorid)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; case EmDoorID.Bottom:&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rect.y = height;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (rport.IsInput)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rect.x = width / 2f + 8;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rect.x = width / 2f - 8 - 16;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; break;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; case EmDoorID.Left:&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rect.x = 0;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (rport.IsInput)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rect.y = height / 2f - 8 - 16;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rect.y = height / 2f + 8;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rect.y += 15;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; break;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; case EmDoorID.Right:&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rect.x = width - 16;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (rport.IsInput)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rect.y = height / 2f + 8;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rect.y = height / 2f - 8 - 16;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rect.y += 15;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; break;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; case EmDoorID.Top:&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rect.y = 0;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (rport.IsInput)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rect.x = width / 2f - 8 - 16;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rect.x = width / 2f + 8;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; break;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; default:&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw new ArgumentOutOfRangeException();&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var color = rport.IsInput ? Color.red : Color.green;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; NodeEditorGUILayout.DrawPortHandle(rect, Color.black, color);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; portPositions[rport] = rect.center;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public override void AddContextMenuItems(GenericMenu menu)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; base.AddContextMenuItems(menu);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var tar = (MazeLayerRoomNode)target;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (Selection.objects.Length == 1 &amp;amp;&amp;amp; Selection.activeObject is XNode.Node)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; menu.AddItem(new GUIContent(&quot;增加门/↑上&quot;), false, () =&amp;gt; tar.AddDoor(EmDoorID.Top));&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; menu.AddItem(new GUIContent(&quot;增加门/↓下&quot;), false, () =&amp;gt; tar.AddDoor(EmDoorID.Bottom));&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; menu.AddItem(new GUIContent(&quot;增加门/上下&quot;), false, () =&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; tar.AddDoor(EmDoorID.Bottom);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; tar.AddDoor(EmDoorID.Top);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; });&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; menu.AddItem(new GUIContent(&quot;增加门/←左&quot;), false, () =&amp;gt; tar.AddDoor(EmDoorID.Left));&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; menu.AddItem(new GUIContent(&quot;增加门/→右&quot;), false, () =&amp;gt; tar.AddDoor(EmDoorID.Right));&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; menu.AddItem(new GUIContent(&quot;增加门/左右&quot;), false, () =&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; tar.AddDoor(EmDoorID.Right);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; tar.AddDoor(EmDoorID.Left);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; });&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; menu.AddItem(new GUIContent(&quot;增加门/上下左右&quot;), false, () =&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; tar.AddDoor(EmDoorID.Bottom);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; tar.AddDoor(EmDoorID.Top);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; tar.AddDoor(EmDoorID.Right);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; tar.AddDoor(EmDoorID.Left);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; });&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
}&lt;/p&gt;&lt;/div&gt;&lt;p&gt;1、继承NodeEditor，比用CustomNodeEditor和我们自定义的Node相关联&lt;/p&gt;&lt;p&gt;2、复写了OnHeaderGUI，让节点头部显示房间的ID和名称，这样查看比较方便&lt;/p&gt;&lt;p&gt;3、复写GetWidth。因为我知道画的图的大小，其他不想显示，所以固定为115&lt;/p&gt;&lt;p&gt;4、复写OnBodyGUI。这个是重点。因为在节点画出图，所以在这个函数里面，先去AssetDataBase里面找到图，然后使用DrawPreviewTexture画出来。最后我要画出门的出入口，所以使用Node的DynamicPorts存储门的数据。最后把这些port的位置记录到portPositions数组中，这样到时候去就可以去做连线了。&lt;/p&gt;&lt;p&gt;5、复写AddContextMenuItems，在节点的右键菜单的时候加上一些动态加门的方法&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.codegize.com/zb_users/upload/2021/9/%E5%B1%8F%E5%B9%95%E6%88%AA%E5%9B%BE2021-09-25203058_2.jpg&quot;&gt;&lt;img width=&quot;526&quot; height=&quot;335&quot; title=&quot;屏幕截图 2021-09-25 203058&quot; style=&quot;display: inline; background-image: none;&quot; alt=&quot;屏幕截图 2021-09-25 203058&quot; src=&quot;http://www.codegize.com/zb_users/upload/2021/9/%E5%B1%8F%E5%B9%95%E6%88%AA%E5%9B%BE2021-09-25203058_thumb.jpg&quot; border=&quot;0&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;如图，添加4个门之后，就在节点周围画出了4个入口和4个出口&lt;/p&gt;&lt;p&gt;多加几个节点，然后连接起来&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.codegize.com/zb_users/upload/2021/9/%E5%B1%8F%E5%B9%95%E6%88%AA%E5%9B%BE2021-09-25203300_2.jpg&quot;&gt;&lt;img width=&quot;210&quot; height=&quot;391&quot; title=&quot;屏幕截图 2021-09-25 203300&quot; style=&quot;display: inline; background-image: none;&quot; alt=&quot;屏幕截图 2021-09-25 203300&quot; src=&quot;http://www.codegize.com/zb_users/upload/2021/9/%E5%B1%8F%E5%B9%95%E6%88%AA%E5%9B%BE2021-09-25203300_thumb.jpg&quot; border=&quot;0&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;这个曲线不怎么满意，怎么办。&lt;/p&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;&lt;h1&gt;&lt;/h1&gt;&lt;h1&gt;Graph重绘&lt;/h1&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;&lt;p&gt;在xnode中，不仅Node可以重绘，Graph也可以&lt;/p&gt;&lt;div class=&quot;cnblogs_code&quot; style=&quot;padding: 5px; border: 1px solid rgb(204, 204, 204); border-image: none; background-color: rgb(245, 245, 245);&quot;&gt;&lt;pre&gt;    [CustomNodeGraphEditor(&lt;span style=&quot;color: rgb(0, 0, 255);&quot;&gt;typeof&lt;/span&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;(MazeLayerGraph))]
    &lt;/span&gt;&lt;span style=&quot;color: rgb(0, 0, 255);&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: rgb(0, 0, 255);&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt; MazeLayerGraphEditor : NodeGraphEditor
    {&lt;/span&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public override NoodlePath GetNoodlePath(NodePort output, NodePort input)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return NoodlePath.Straight;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;/blockquote&gt;&lt;pre&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;    }&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;&lt;p&gt;类似的，我们只要继承NodeGraphEditor，并用CustomNodeGraphEditor和我们自定义的Graph关联就可以了。&lt;/p&gt;&lt;p&gt;为了实现曲线变直线，我们只要复写GetNoodlePath即可，NoodlePath.Straight表示直线&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.codegize.com/zb_users/upload/2021/9/%E5%B1%8F%E5%B9%95%E6%88%AA%E5%9B%BE2021-09-25203756_2.jpg&quot;&gt;&lt;img width=&quot;171&quot; height=&quot;412&quot; title=&quot;屏幕截图 2021-09-25 203756&quot; style=&quot;display: inline; background-image: none;&quot; alt=&quot;屏幕截图 2021-09-25 203756&quot; src=&quot;http://www.codegize.com/zb_users/upload/2021/9/%E5%B1%8F%E5%B9%95%E6%88%AA%E5%9B%BE2021-09-25203756_thumb.jpg&quot; border=&quot;0&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;OK。那大部分就完成了。最后就是保存了。我们在MazeLayerGraphEditor中的OnGUI可以写一个buttom，然后把相关数据写到自定义的数据就可以了。&lt;/p&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;&lt;/font&gt;&lt;/a&gt;&lt;/font&gt;</description><pubDate>Sat, 25 Sep 2021 20:41:26 +0800</pubDate></item><item><title>关于AAB的知识点整理</title><link>http://www.codegize.com/?id=73</link><description>&lt;p&gt;2018年，google推出了aab技术。在此之后google发布通知：从 2021 年 8 月起，新应用需要使用 Android App Bundle 才能在 Google Play 中发布。&lt;/p&gt;&lt;p&gt;这意味着以GP为主要平台的海外版本，都需要使用aab。那么什么是aab，和apk有什么不同呢？&lt;/p&gt;&lt;p&gt;aab官方介绍：&lt;a href=&quot;https://developer.android.com/guide/app-bundle&quot;&gt;https://developer.android.com/guide/app-bundle&lt;/a&gt;&lt;/p&gt;&lt;p&gt;简单地说aab就是一个带有很多分包数据的压缩包。它将一个apk拆分了多个小包，比如按CPU架构拆分，按语言拆分等等，最终移动设备安装时只需要下载需要的分包即可。&lt;/p&gt;&lt;p&gt;apk可以直接安装到用户的设备上，但是aab只是一种发布格式，所以不能直接安装。但是可以使用bundletool命令行连接设备进行模拟安装。&lt;/p&gt;&lt;h3&gt;技术细节&lt;/h3&gt;&lt;h4&gt;aab的数据格式&lt;/h4&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;上面提到，aab其实是一个压缩包，它包含了一系列的文件。下图显示了一个aab文件内部的组成：&lt;/p&gt;&lt;table border=&quot;0&quot; cellpadding=&quot;0&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;p&gt;aab&lt;br/&gt;│ BundleConfig.pb&lt;br/&gt;├─base&lt;br/&gt;│ │ assets.pb&lt;br/&gt;│ │ native.pb&lt;br/&gt;│ │ resources.pb&lt;br/&gt;│ ├─assets&lt;br/&gt;│ ├─dex&lt;br/&gt;│ │ classes.dex&lt;br/&gt;│ ├─lib&lt;br/&gt;│ │ └─armeabi-v7a&lt;br/&gt;│ │ libmain.so&lt;br/&gt;│ │ libmonobdwgc-2.0.so&lt;br/&gt;│ │ libMonoPosixHelper.so&lt;br/&gt;│ │ libunity.so&lt;br/&gt;│ ├─manifest&lt;br/&gt;│ │ AndroidManifest.xml&lt;br/&gt;│ └─res&lt;br/&gt;├─BUNDLE-METADATA&lt;br/&gt;│ └─com.android.tools.build.libraries&lt;br/&gt;│ dependencies.pb&lt;br/&gt;└─META-INF&lt;br/&gt;ANDROIDD.RSA&lt;br/&gt;ANDROIDD.SF&lt;br/&gt;MANIFEST.MF&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;aab存在的目的是为了拆分出一系列的apk文件。为了能够拆分出来，首先就需要收集数据文件，并对数据文件进行整理，标记每个文件的作用。另外还需要配置拆分的规则。&lt;/p&gt;&lt;p&gt;其中所有的pb文件，其数据结构都可以在以下地址找到：&lt;/p&gt;&lt;p&gt;https://github.com/google/bundletool/blob/master/src/main/proto&lt;/p&gt;&lt;h4&gt;base目录&lt;/h4&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;在base目录下，我们会发现很多文件和apk大部分是相同的，但是用途又有点不同。&lt;/p&gt;&lt;p&gt;数据文件&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;manifest.xml：它和apk中的一样，都是一些配置项。但不同的是，apk中这个文件是二进制的格式，而aab中用的是pb格式。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;res目录/assets目录/libs目录/dex目录：和apk是相同的组织形式，唯一的区别是res目录下的配置文件，全部也是用的pb格式&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;标记数据&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;assets.pb&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;native.pb&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;resources.pb&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;assets.pb，native.pb,resources.pb是base中核心的内容，它列举了整个base下所有文件的组成信息，比如某个文件用于某个ScreenDensity（HDPI,XHDPI,XXHDPI之类），或者某个so文件用于某个CPU架构等等。有了这些数据，在拆分apk的时候，就可以将不同的文件拆分到不同的apk中。&lt;/p&gt;&lt;h4&gt;BundleConfig.pb&lt;/h4&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;buildconfig用于配置拆分的规则，见&lt;a href=&quot;https://github.com/google/bundletool/blob/master/src/main/proto/config.proto&quot;&gt;https://github.com/google/bundletool/blob/master/src/main/proto/config.proto&lt;/a&gt;h&lt;/p&gt;&lt;p&gt;其中也包含了很多的优化项，部分采用gradle进行打包aab的时候会影响到buildconfig的数据，比如UncompressNativeLibraries&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://developer.android.com/studio/releases/gradle-plugin#4-0-0-issues&quot;&gt;https://developer.android.com/studio/releases/gradle-plugin#4-0-0-issues&lt;/a&gt;&lt;/p&gt;&lt;table border=&quot;0&quot; cellpadding=&quot;0&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;p&gt;构建 Android App Bundle 时，由以 Android 6.0（API 级别 23）或更高版本为目标平台的 App Bundle 生成的 APK 现在默认包含原生库的未压缩版本。这项优化无需设备创建库的副本，因此减少了应用占用的存储空间。如果您想要停用此优化，请在 gradle.properties 文件中添加以下代码：&lt;/p&gt;&lt;p&gt;android.bundle.enableUncompressedNativeLibs = false&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;另一个在gradle工程里面影响拆分配置是的build.gradle文件下的bundle模块，如(unity2018默认生成)&lt;/p&gt;&lt;table border=&quot;0&quot; cellpadding=&quot;0&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;p&gt;bundle {&lt;/p&gt;&lt;p&gt;language {&lt;/p&gt;&lt;p&gt;enableSplit = false&lt;/p&gt;&lt;p&gt;}&lt;/p&gt;&lt;p&gt;density {&lt;/p&gt;&lt;p&gt;enableSplit = false&lt;/p&gt;&lt;p&gt;}&lt;/p&gt;&lt;p&gt;abi {&lt;/p&gt;&lt;p&gt;enableSplit = true&lt;/p&gt;&lt;p&gt;}&lt;/p&gt;&lt;p&gt;}&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;这会影响最终的拆包，不会做语言的拆分和density的拆分。如果在unity中含有多国语言或者多个ScreenDensity，那么可以在PlayerSetting的Publishing Setting中勾选Custom Gradle Template，修改这个值&lt;/p&gt;&lt;p&gt;注意：如果使用的是bundltool打包aab，因为没有gradle相关的文件，所以需要修改buildconfig.json，新增UncompressNativeLibraries=false的配置。见用bundletool打包aab&lt;/p&gt;&lt;h3&gt;2、拆分apk：aab到apks&lt;/h3&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;在android lolopop以上，会有SplitApks的功能。它允许一个应用程序可以分散在多个apk中，但是运行起来仍然是一个程序。因此，aab利用这一机制，将aab文件拆分为多个apk，最终根据用户设备，按需安装必要的apk即可。&lt;/p&gt;&lt;p&gt;aab一般来说会根据ScreenDensity，CPU架构和本地化语言进行拆分。这样的会，用户将不会下载用不到的资源，从而大大减少下载的内容大小。提高下载效率。&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.codegize.com/zb_users/upload/2021/6/clip_image002_2.png&quot;&gt;&lt;img width=&quot;244&quot; height=&quot;136&quot; title=&quot;clip_image002&quot; style=&quot;margin: 0px; display: inline; background-image: none;&quot; alt=&quot;clip_image002&quot; src=&quot;http://www.codegize.com/zb_users/upload/2021/6/clip_image002_thumb.png&quot; border=&quot;0&quot;/&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;在gp平台进行下载安装，或者使用bundletool安装apks的时候，过程如下。&lt;/p&gt;&lt;p&gt;平台或者bundletool首先会判断系统是否支持SplitApk功能，即设备的android版本高于或等于Android Lolipop&lt;/p&gt;&lt;p&gt;如果含有该功能，则根据设备的ScreenDensiny,CPU架构和本地化语言下载对应的分包&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.codegize.com/zb_users/upload/2021/6/clip_image004_2.png&quot;&gt;&lt;img width=&quot;244&quot; height=&quot;151&quot; title=&quot;clip_image004&quot; style=&quot;display: inline; background-image: none;&quot; alt=&quot;clip_image004&quot; src=&quot;http://www.codegize.com/zb_users/upload/2021/6/clip_image004_thumb.png&quot; border=&quot;0&quot;/&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;通过bundletool，可以将aab转为一个叫做apks的文件，它也是一个压缩包&lt;/p&gt;&lt;p&gt;在这个包里面文件结构如下（为了方便删除了一些本地化语言的apk），可以在splits下发现有很多的分包apk。&lt;/p&gt;&lt;p&gt;而对于Android lolipop之前，则会使用standlones里面的apk&lt;/p&gt;&lt;table border=&quot;0&quot; cellpadding=&quot;0&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;pre&gt;apks&lt;/pre&gt;&lt;pre&gt;│&amp;nbsp;&amp;nbsp;toc.pb&lt;/pre&gt;&lt;pre&gt;├─splits&lt;/pre&gt;&lt;pre&gt;│&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;base-af.apk&lt;/pre&gt;&lt;pre&gt;│&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;base-am.apk&lt;/pre&gt;&lt;pre&gt;│&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;base-ar.apk&lt;/pre&gt;&lt;pre&gt;│&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;base-arm64_v8a.apk&lt;/pre&gt;&lt;pre&gt;│&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;base-armeabi_v7a.apk&lt;/pre&gt;&lt;pre&gt;│&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;base-as.apk&lt;/pre&gt;&lt;pre&gt;│&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;base-az.apk&lt;/pre&gt;&lt;pre&gt;│&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;base-hdpi.apk&lt;/pre&gt;&lt;pre&gt;│&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;base-ldpi.apk&lt;/pre&gt;&lt;pre&gt;│&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;base-lo.apk&lt;/pre&gt;&lt;pre&gt;│&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;base-lt.apk&lt;/pre&gt;&lt;pre&gt;│&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;base-lv.apk&lt;/pre&gt;&lt;pre&gt;│&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;base-master.apk&lt;/pre&gt;&lt;pre&gt;│&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;base-mdpi.apk&lt;/pre&gt;&lt;pre&gt;│&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;base-mk.apk&lt;/pre&gt;&lt;pre&gt;│&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;base-tr.apk&lt;/pre&gt;&lt;pre&gt;│&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;base-tvdpi.apk&lt;/pre&gt;&lt;pre&gt;│&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;base-uk.apk&lt;/pre&gt;&lt;pre&gt;│&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;base-ur.apk&lt;/pre&gt;&lt;pre&gt;│&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;base-uz.apk&lt;/pre&gt;&lt;pre&gt;│&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;base-vi.apk&lt;/pre&gt;&lt;pre&gt;│&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;base-xhdpi.apk&lt;/pre&gt;&lt;pre&gt;│&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;base-xxhdpi.apk&lt;/pre&gt;&lt;pre&gt;│&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;base-xxxhdpi.apk&lt;/pre&gt;&lt;pre&gt;│&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;base-zh.apk&lt;/pre&gt;&lt;pre&gt;│&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;base-zu.apk|&lt;/pre&gt;&lt;pre&gt;└─standalones&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;standalone-arm64_v8a_hdpi.apk&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;standalone-arm64_v8a_ldpi.apk&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;standalone-arm64_v8a_mdpi.apk&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;standalone-arm64_v8a_tvdpi.apk&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;standalone-arm64_v8a_xhdpi.apk&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;standalone-arm64_v8a_xxhdpi.apk&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;standalone-arm64_v8a_xxxhdpi.apk&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;standalone-armeabi_v7a_hdpi.apk&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;standalone-armeabi_v7a_ldpi.apk&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;standalone-armeabi_v7a_mdpi.apk&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;standalone-armeabi_v7a_tvdpi.apk&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;standalone-armeabi_v7a_xhdpi.apk&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;standalone-armeabi_v7a_xxhdpi.apk&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;standalone-armeabi_v7a_xxxhdpi.apk&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;h3&gt;3、bundltool&lt;/h3&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;上面我们说了很多的bundltool，这里提一下这个工具，Github地址：&lt;a href=&quot;https://github.com/google/bundletool&quot;&gt;https://github.com/google/bundletool&lt;/a&gt;&lt;/p&gt;&lt;p&gt;可以从releases下载最新的版本&lt;/p&gt;&lt;p&gt;它的作用主要是（其他功能请自行参考github）：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;打包aab&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;通过aab转apks&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;安装apks到设备&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;在这个文章中介绍了bundletool进行打包的内容：&lt;a href=&quot;https://developer.android.com/studio/build/building-cmdline#bundletool-build&quot;&gt;https://developer.android.com/studio/build/building-cmdline#bundletool-build&lt;/a&gt;&lt;/p&gt;&lt;p&gt;在这个文章中介绍了后2个内容：&lt;a href=&quot;https://developer.android.com/studio/command-line/bundletool&quot;&gt;https://developer.android.com/studio/command-line/bundletool&lt;/a&gt;&lt;/p&gt;&lt;p&gt;要注意的是，aab转apks的时候需要进行签名，否则将无法安装&lt;/p&gt;&lt;h3&gt;链接整理&lt;/h3&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;官方介绍：&lt;a href=&quot;https://developer.android.com/guide/app-bundle&quot;&gt;https://developer.android.com/guide/app-bundle&lt;/a&gt;&lt;/p&gt;&lt;p&gt;官方博文：&lt;a href=&quot;https://medium.com/google-developer-experts/exploring-the-android-app-bundle-ca16846fa3d7&quot;&gt;https://medium.com/google-developer-experts/exploring-the-android-app-bundle-ca16846fa3d7&lt;/a&gt;&lt;/p&gt;&lt;p&gt;BundleTool：&lt;a href=&quot;https://github.com/google/bundletool&quot;&gt;https://github.com/google/bundletool&lt;/a&gt;&lt;/p&gt;&lt;p&gt;BundleTool的prop数据格式：&lt;a href=&quot;https://github.com/google/bundletool/blob/master/src/main/proto&quot;&gt;https://github.com/google/bundletool/blob/master/src/main/proto&lt;/a&gt;&lt;/p&gt;&lt;p&gt;BundleTool打包aab：&lt;a href=&quot;https://developer.android.com/studio/build/building-cmdline#bundletool-build&quot;&gt;https://developer.android.com/studio/build/building-cmdline#bundletool-build&lt;/a&gt;&lt;/p&gt;&lt;p&gt;BundleTool安装测试：&lt;a href=&quot;https://developer.android.com/studio/command-line/bundletool&quot;&gt;https://developer.android.com/studio/command-line/bundletool&lt;/a&gt;&lt;/p&gt;&lt;p&gt;UncompressNativeLibraries问题：&lt;a href=&quot;https://developer.android.com/studio/releases/gradle-plugin#4-0-0-issues&quot;&gt;https://developer.android.com/studio/releases/gradle-plugin#4-0-0-issues&lt;/a&gt;&lt;/p&gt;</description><pubDate>Sat, 05 Jun 2021 14:30:02 +0800</pubDate></item><item><title>焦虑症</title><link>http://www.codegize.com/?id=72</link><description>&lt;p&gt;不知道和5月份的血月有没有什么关系，最近好多人的精神和情绪都受到了一定的影响。不过我感觉如果是的话，这个也可能只是一种诱因，更主要的问题还在于自己不好的生活习惯，以及引起的长时间的低质量的睡眠。&lt;/p&gt;&lt;h2&gt;突发性的头晕&lt;/h2&gt;&lt;p&gt;5月2号早上的时候，刚刚起床在玩手机麻将，突然间就咚的一下，脑袋突然一阵空白。因为就1秒不到就恢复了，当时没在意。&lt;/p&gt;&lt;p&gt;但是在5月7号早上的时候，好好地在听歌写代码，突然间，一阵晕眩感袭来。我飞快地拿下耳机，然后和同事说，我貌似要晕了。同事也吓了一跳，急忙的问我什么情况，然后递给我一瓶可乐，以为是低血糖。休息片刻之后，差不多5秒不到的时间，又恢复了。不过这次让我感觉到慌张，想到了之前网上各种程序员猝死的报导，更是害怕极了。&lt;/p&gt;&lt;h2&gt;看病1&lt;/h2&gt;&lt;p&gt;5月8号到5月13号，担心身体问题，不敢告诉家里人，自己去浙二医院做了各种检查，血常规，甲状腺，心电图，核磁共振，颈椎彩超，心超，动态心电图，脑电图。但是所有的指标都是正常的，在检查期间，医生也没法开药治疗，只能听天由命，这让我更加害怕和紧张。生怕自己有个万一，甚至我都在脑中打好了遗嘱的草稿。直到13号，医生暂时诊断为焦虑障碍，才开了一些抗焦虑和助睡眠的药物。请了一个星期的假在家里休息。但是依然失眠，或者说睡眠质量极差。依然会突然性地晕，尤其是在医院等待过程中，远比在家的次数更多。&lt;/p&gt;&lt;h2&gt;关注症状和诱因&lt;/h2&gt;&lt;p&gt;有一次我在家直接怒了，然后发现反而头脑清醒了一些。于是就开始注意各种症状：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;症状1：紧张时，头晕，一片空白，看东西会突然糊一下，持续大概5秒内&lt;/li&gt;&lt;li&gt;症状2：专注时，头会如同针刺或者电击一般地疼痛，然后可能开始头晕，和上面一样&lt;/li&gt;&lt;li&gt;症状3：受到刺激的时候，有时间即使是开个门，或者风吹到皮肤上，会心慌，然后头晕&lt;/li&gt;&lt;li&gt;症状4：看视频，如果开声音，或者放音乐，几分钟后就晕头晕&lt;/li&gt;&lt;li&gt;症状5：人多的时候，尤其是嘈杂环境，极容易头晕&lt;/li&gt;&lt;li&gt;症状6：走路的时候，可能突发性头晕&lt;/li&gt;&lt;li&gt;症状7：吃饭时，很容易头晕&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;于是我开始特意避开这些，专注在家静养。同时我和家里人说了头晕的事情，结果老爸的担心，让我即烦恼，又担心他高血压，又懊恼不应该和他说。不过堂弟堂妹说周末会过来看我，让我至少不用担心晕过去没人知道了，至少安心了一些。&lt;/p&gt;&lt;h2&gt;尝试性上班&lt;/h2&gt;&lt;p&gt;20号，本是病假的最后一天，我打算去尝试性上班，虽然走路有风险，但是还是下定决心。在家静养的过程中我也发现了，只要休息几秒，深呼吸一下就会好，所以小心翼翼地走到了公司。而且是赶个大早去食堂吃了早餐。还买了行军床，毯子，眼罩，换了把人体工学椅子。&lt;/p&gt;&lt;p&gt;而且由于降噪耳机的帮助，晕眩次数少了一些。但是只要有人和我说话，就会头晕。所以在20号下午就回去休息了。21号又上班，感觉差不多，但是能坚持下来了。&lt;/p&gt;&lt;p&gt;周末在家休息了2天。周日堂弟堂妹来看望，整个下午没有怎么发作，甚至可以到外面去吃饭。&lt;/p&gt;&lt;h2&gt;看病2&lt;/h2&gt;&lt;p&gt;24号周一，可能是由于失眠继续加重的原因。头晕加重，早上发作次数增加。不敢去上班，怕晕倒在路上或者在大家面前丢脸。于是请了2天假，预约了25号的邵逸夫医院，去看神经内科和精神卫生科。&lt;/p&gt;&lt;p&gt;25号去了邵逸夫，做了肌电图和心理评测，肌电图显示交感神经兴奋度高，心理评测为轻度焦虑。2位医生也确认为焦虑，开了药。在拿了报告，去医生那边的时候，却被一个女的说插队，而我在医院晕得厉害，一个人连排队都没办法做到。叫了边上的导诊员护士，她也不帮忙，让我心寒到底。还好有个小哥也来看医生，非常热情，看我不舒服，让我先看病，又帮忙指点拿药位置，让我非常感动。果然世界上还是有好心人的。顿时心情也好了很多。回到家，整个人都放松了下来，这天后面就没有晕过。&lt;/p&gt;&lt;h2&gt;继续上班&lt;/h2&gt;&lt;p&gt;26号到29号，一边上班，一边去查相关的资料。知乎的一篇文章仿佛拯救了我，让我认识了这个所谓的焦虑症。&lt;/p&gt;&lt;p&gt;&lt;a title=&quot;https://zhuanlan.zhihu.com/p/25586638&quot; href=&quot;https://zhuanlan.zhihu.com/p/25586638&quot;&gt;https://zhuanlan.zhihu.com/p/25586638&lt;/a&gt;&lt;/p&gt;&lt;p&gt;其中有一段，我直接感动了。它是这么写的：&lt;/p&gt;&lt;p&gt;------------------------------------------------------------------------&lt;/p&gt;&lt;p&gt;亲爱的：&lt;br&gt;
我能体会到，此刻的你，有多焦急；同时我也深知，你的每一天过的有多痛苦。我知道你会缺乏耐心去做任何事情，也未必有耐心看完我的经历。但我还是想建议你：安静的坐在沙发上，忍着无尽的恐惧，慢慢的逐字进行阅读。&lt;br&gt;
这本指南，我耗时一个月，滴着血流着泪，最终将它熬成一本干货。&lt;br&gt;
毋庸担心，当你不舒服的时候，我就在你的面前，陪着你。&lt;br&gt;
因为曾经的我，就是此刻的你！&lt;/p&gt;&lt;p&gt;-----------------------------------------------------------------------&lt;/p&gt;&lt;h2&gt;相信会好的&lt;/h2&gt;&lt;p&gt;既然知道了一些原因，我相信我能调整回来&lt;/p&gt;&lt;p&gt;今天30号，我写下了这个文章。虽然写的过程还是会阵阵头晕，但是我感觉还不错。&lt;/p&gt;&lt;p&gt;相信一切都会好的！&lt;/p&gt;</description><pubDate>Sun, 30 May 2021 11:01:21 +0800</pubDate></item></channel></rss>