﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-战魂小筑-随笔分类-游戏开发技术</title><link>http://www.cppblog.com/sunicdavy/category/11295.html</link><description>讨论群:309800774 知乎关注:http://zhihu.com/people/sunicdavy 开源项目:https://github.com/davyxu</description><language>zh-cn</language><lastBuildDate>Wed, 29 Aug 2018 03:26:16 GMT</lastBuildDate><pubDate>Wed, 29 Aug 2018 03:26:16 GMT</pubDate><ttl>60</ttl><item><title>游戏与Web的服务器对比</title><link>http://www.cppblog.com/sunicdavy/archive/2018/08/29/215887.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Wed, 29 Aug 2018 03:16:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2018/08/29/215887.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/215887.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2018/08/29/215887.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/215887.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/215887.html</trackback:ping><description><![CDATA[<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">为了编写基于</span><a href="https://github.com/davyxu/cellnet"><span style="font-size: 16px; color: #003884;">cellnet</span></a><span style="font-size: 16px; color: #333333;">的新一代游戏服务器框架，最近深入研究微服务，ServiceMesh等概念。研究过程中对Web和游戏两种服务器架构设计有一些心得，编写并记录下来。(下文中，Game表示游戏服务器，Web表示Web服务器) `` </span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333; font-weight: bold;">状态缓存</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">所谓状态缓存，就是在内存而非专业数据缓存服务器（如redis）中保存和处理逻辑数据，手动编写此过程较为繁琐但是效率较高，但随着状态逻辑复杂性和并发、扩容问题提出，状态同步会变得越来越复杂。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">Game:</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">强交互性的服务器类型需要在服务器做缓存，逻辑编写也较为容易，无需处理事务并发问题。例如：组队，匹配，战斗逻辑。服务器不能随意重启。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">弱交互性的服务器类型可配合redis做成无状态服务器，例如：养成，技能升级，领取物品等。服务器随时支持重启。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">游戏服务器为了提高性能，早期所有服务器都是使用状态缓存写法编写，特别是MMORPG这类强交互的游戏服务器尤为严重。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">Web:</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">均为无状态服务器，弱交互。使用事务方式处理并发逻辑，例如：交易，下单等。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;"> </span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333; font-weight: bold;">推送，单独发送</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">这里提到的所谓推送，单独发送是与RPC区别的通讯方法。RPC要求请求必须有回应。而推送单独发送则更像是通知和广播，无需目的方返回任何消息。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">Game:</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">找到服务器的Session，直接Send</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">通过中转服务器，或称为中心服务器进行注册/广播</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">客户端的model数据需要更新时，服务器会主动推送消息。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">游戏服务器没有严格的RPC设计需求，推送和单独发送较Web服务器更多。而且游戏服务器多使用长连接，所以主动推送也比Web服务器来的方便一些。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">Web:</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">将推送做成专有的服务，并做排队和并发处理。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;"> </span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333; font-weight: bold;">可用性</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">听说过游戏停服更新，支付宝服务器在刷二维码时停服了可一定被骂惨吧。Web对服务器高可用性要求很高，游戏虽然也注重服务器稳定性和可用性，但是由于版本迭代更新频繁，停服更新反而能获得玩家接受。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">Game:</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">游戏对可用性要求不高。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">游戏大版本更新时需要停服更新。支持热更新技术的服务器（例如Erlang，Skynet）仅使用热更新修复bug，很少直接更新新版本。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">不是所有的游戏服务器支持动态添加服务器。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">Web:</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">极高的可用性，服务不允许停服更新，使用蓝绿及灰度方式更新服务器。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">随时可以横向扩展服务器，提高服务器容量和承载。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;"> </span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333; font-weight: bold;">连接及传输</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">均使用TCP传输协议，游戏服务器注重性能，自有协议及二进制协议使用较多。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">Web注重兼容和接口友好，使用JSON格式较多。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">Game:</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">使用长连接，需要从逻辑层维护连接状态及处理服务器不在线情况</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">使用自有封包格式，大部分使用protobuf或二进制流格式。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">Web:</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">微服务大部分使用短连接，grpc支持http2长连接</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">使用json编码方便调试和版本兼容。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;"> </span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333; font-weight: bold;">流量限制</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">人数多了，任何服务器都扛不住，流量限制和登入限制能有效保护服务器稳定。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">Game:</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">单服有人数限制，可以通过GM后台设置挡墙，超过无法进入</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">Web:</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">限流器中间件，可以精确到服务控制流量</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;"> </span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333; font-weight: bold;">断流，防止雪崩</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">Game:</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">游戏没有，也不需要这种概念，游戏请求不会突然升高，即便有，也通过GM后台人为控制</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">Web:</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">断流器中间件 </span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333; font-weight: bold;">服务发现</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">如何找到服务器地址。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">服务有变化时，通过Watch系统通知订阅者更新本地缓存</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">服务器没有变化时，使用本地缓存找到服务地址</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">Game:</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">游戏服务器互相依赖复用只在很小的范围内，因此无需在不同语言不同进程服务间获得地址，大部分在配置文件中填写各服务的IP及地址即可互相访问。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">早期游戏自己编写服务器状态及地址发现服务。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">有用redis做服务发现</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">Web:</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">使用服务发现系统，分布式部署。无需依赖配置文件</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;"> </span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333; font-weight: bold;">网关需求</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">Game:</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">网关处理客户端上下线通知，心跳，维持连接，转发，广播上下行封包</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">Web:</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">根据请求地址路由，无上下线概念，无心跳。广播通过消息推送系统完成</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;"> </span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">由于笔者从事游戏行业，对Web服务器概念在逐渐熟悉中，若有错误和不足请各位大佬指出。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">本人新书《Go语言从入门到进阶实战》，生动的语言，例子带有各种彩蛋，轻松了解Go语言特性，更有</span><a href="https://github.com/davyxu/cellnet"><span style="font-size: 16px; color: #003884;">cellnet</span></a><span style="font-size: 16px; color: #333333;">框架剖析解密</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><a href="https://search.jd.com/Search?keyword=go%E8%AF%AD%E8%A8%80%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E8%BF%9B%E9%98%B6%E5%AE%9E%E6%88%98&amp;enc=utf-8&amp;suggest=1.def.0.V02&amp;wq=Go%E8%AF%AD%E8%A8%80%E4%BB%8E&amp;pvid=145d55a92cab4b07b71326f8beb1700b"><span style="font-size: 16px; color: #003884;">https://search.jd.com/Search?keyword=go%E8%AF%AD%E8%A8%80%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E8%BF%9B%E9%98%B6%E5%AE%9E%E6%88%98&amp;enc=utf-8&amp;suggest=1.def.0.V02&amp;wq=Go%E8%AF%AD%E8%A8%80%E4%BB%8E&amp;pvid=145d55a92cab4b07b71326f8beb1700b</span></a></div>
<img src ="http://www.cppblog.com/sunicdavy/aggbug/215887.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2018-08-29 11:16 <a href="http://www.cppblog.com/sunicdavy/archive/2018/08/29/215887.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在Windows下运行Linux Shell</title><link>http://www.cppblog.com/sunicdavy/archive/2017/11/27/215373.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Mon, 27 Nov 2017 07:15:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2017/11/27/215373.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/215373.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2017/11/27/215373.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/215373.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/215373.html</trackback:ping><description><![CDATA[<p data-source-line="2" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, 微软雅黑, &quot;PingFang SC&quot;, Helvetica, Tahoma, Arial, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, SimSun, 宋体, Heiti, 黑体, sans-serif; background-color: #ffffff;"></p><h1></h1><p data-source-line="2" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, 微软雅黑, &quot;PingFang SC&quot;, Helvetica, Tahoma, Arial, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, SimSun, 宋体, Heiti, 黑体, sans-serif; background-color: #ffffff;">越来越多的人选择用Mac或者Linux环境进行跨平台项目开发。但是仍然有大部分人习惯于在Windows环境下进行开发，毕竟Windows在各方面使用还是较为方便，特别像文件版本管理（Git，SVN等）</p><p data-source-line="4" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, 微软雅黑, &quot;PingFang SC&quot;, Helvetica, Tahoma, Arial, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, SimSun, 宋体, Heiti, 黑体, sans-serif; background-color: #ffffff;">在跨平台下开发游戏或软件，就需要有一套方便的自动化工具。Windows下需要使用批处理，虽然有PowerShell加持，但这东西学了也不靠谱，只有一个平台能用。大家还是习惯Linux Shell。连Mac平台都可以用Shell，Windows上要做自动化脚本就显得非常尴尬。</p><p data-source-line="6" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, 微软雅黑, &quot;PingFang SC&quot;, Helvetica, Tahoma, Arial, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, SimSun, 宋体, Heiti, 黑体, sans-serif; background-color: #ffffff;">我曾经在项目中使用go编写了一套将配置转为批处理和Linux Shell的工具。使用过程较为复杂，但是能跨平台进行表格导出和协议编译等工作。</p><p data-source-line="8" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, 微软雅黑, &quot;PingFang SC&quot;, Helvetica, Tahoma, Arial, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, SimSun, 宋体, Heiti, 黑体, sans-serif; background-color: #ffffff;">但是，这个工具还是需要对不同的平台编写多套模板进行代码生成，非常繁琐。如果有一套跨平台的Shell，编写一次就可以跨平台运行那该多好。</p><p data-source-line="10" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, 微软雅黑, &quot;PingFang SC&quot;, Helvetica, Tahoma, Arial, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, SimSun, 宋体, Heiti, 黑体, sans-serif; background-color: #ffffff;">查阅资料后，一共有几个方案：</p><ol data-source-line="11" style="box-sizing: border-box; padding-left: 2em; margin-top: 0px; margin-bottom: 16px; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, 微软雅黑, &quot;PingFang SC&quot;, Helvetica, Tahoma, Arial, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, SimSun, 宋体, Heiti, 黑体, sans-serif; background-color: #ffffff;"><li style="box-sizing: border-box;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">使用Python作为自动化工具 这个方案其实就是使用python把批处理和Shell干的事情用代码来解决。但前提是要重新学习Python，也需要一部分熟悉简单的Python语法，人为学习成本较高，也比较费事。</p></li><li style="box-sizing: border-box; margin-top: 0.25em;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">自己编写一套独立的自动化工具 这个方案需要长时间的适配过程，差什么指令补什么指令，对项目进度有一定干扰。</p></li><li style="box-sizing: border-box; margin-top: 0.25em;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">自己编写Linux Shell的解释器 这个就更难了，要做到100%兼容，基本不可能。</p></li></ol><ol start="4" data-source-line="21" style="box-sizing: border-box; padding-left: 2em; margin-top: 0px; margin-bottom: 16px; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, 微软雅黑, &quot;PingFang SC&quot;, Helvetica, Tahoma, Arial, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, SimSun, 宋体, Heiti, 黑体, sans-serif; background-color: #ffffff;"><li style="box-sizing: border-box;">使用Cygwin和Mingw 需要一个微型运行时进行Linux Shell的解释，msys大概是18M左右，可行性较高。</li></ol><p data-source-line="24" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, 微软雅黑, &quot;PingFang SC&quot;, Helvetica, Tahoma, Arial, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, SimSun, 宋体, Heiti, 黑体, sans-serif; background-color: #ffffff;">在研究Cygwin和Mingw如何整合的过程中，我误操作点击了一个sh后缀的Linux Shell，这是我希望让Mingw运行的Shell。结果呢，sh后缀的文件居然能在Windows下运行。我马上编写了一系列的例子，发现几乎完全兼容常用的Shell指令。 经过研究，我发现Windows下能运行sh文件是由Git自带的msys2提供的。MSYS2 （Minimal SYStem 2，&nbsp;<a href="http://www.msys2.org/%EF%BC%89" style="box-sizing: border-box; background-color: transparent; color: #0366d6; text-decoration-line: none;">http://www.msys2.org/）</a>&nbsp;是一个MSYS的独立改写版本，主要用于 shell 命令行开发环境。同时它也是一个在Cygwin （POSIX 兼容性层） 和 MinGW-w64（从"MinGW-生成"）基础上产生的，追求更好的互操作性的 Windows 软件。</p><p data-source-line="27" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, 微软雅黑, &quot;PingFang SC&quot;, Helvetica, Tahoma, Arial, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, SimSun, 宋体, Heiti, 黑体, sans-serif; background-color: #ffffff;">那就是说，<span style="box-sizing: border-box; font-weight: 600;">只要安装了Git（<a href="https://git-scm.com/%EF%BC%89%EF%BC%8C%E9%82%A3%E4%B9%88%E5%B0%B1%E5%8F%AF%E4%BB%A5%E5%9C%A8Windows%E4%B8%8B%E7%9B%B4%E6%8E%A5%E8%BF%90%E8%A1%8CLinux" style="box-sizing: border-box; background-color: transparent; color: #0366d6; text-decoration-line: none;">https://git-scm.com/），</a></span><strong><span style="font-family: verdana, &quot;courier new&quot;;">那么就可以在Windows下直接运行Linux Shell</span><span style="box-sizing: border-box;">，只需要将文件后缀命名为sh即可</span></strong>。</p><p data-source-line="29" style="box-sizing: border-box; margin-top: 0px; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, 微软雅黑, &quot;PingFang SC&quot;, Helvetica, Tahoma, Arial, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, SimSun, 宋体, Heiti, 黑体, sans-serif; background-color: #ffffff; margin-bottom: 0px !important;">问过周边友人是否知道这一功能，都说知道，只是没有广播而已，害我研究很久&#8230;&#8230;</p><p data-source-line="29" style="box-sizing: border-box; margin-top: 0px; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, 微软雅黑, &quot;PingFang SC&quot;, Helvetica, Tahoma, Arial, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, SimSun, 宋体, Heiti, 黑体, sans-serif; background-color: #ffffff; margin-bottom: 0px !important;"></p><p data-source-line="29" style="box-sizing: border-box; margin-top: 0px; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, 微软雅黑, &quot;PingFang SC&quot;, Helvetica, Tahoma, Arial, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, SimSun, 宋体, Heiti, 黑体, sans-serif; background-color: #ffffff; margin-bottom: 0px !important;"></p><img src ="http://www.cppblog.com/sunicdavy/aggbug/215373.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2017-11-27 15:15 <a href="http://www.cppblog.com/sunicdavy/archive/2017/11/27/215373.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Golang 热更新研究笔记</title><link>http://www.cppblog.com/sunicdavy/archive/2017/07/06/215057.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Thu, 06 Jul 2017 04:47:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2017/07/06/215057.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/215057.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2017/07/06/215057.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/215057.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/215057.html</trackback:ping><description><![CDATA[<p data-source-line="1" style="box-sizing: border-box; margin-bottom: 16px; color: #333333; font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, Helvetica, Arial, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 21px; widows: 1; background-color: #ffffff; margin-top: 0px !important;">本文主要研究游戏服务器带状态的热更新需求 http的无状态热更新需求已经有成熟方案, 故不在本文描述范围</p><h1><a href="file:///C:/Users/Davy/AppData/Local/Youdao/YNote/markdown/index.html#基本概念" style="box-sizing: border-box; color: #4078c0; text-decoration-line: none;"></a>基本概念</h1><ul data-source-line="6" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; padding-left: 2em; color: #333333; font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, Helvetica, Arial, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 21px; widows: 1; background-color: #ffffff;"><li style="box-sizing: border-box;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">Golang的热更新采用什么机制?</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">使用go1.8提供的plugin包机制实现</p></li><li style="box-sizing: border-box; margin-top: 0.25em;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">plugin包本身设计的目的是热更新么?</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">plugin包其实只是支持将代码分别编译为多个动态库,动态加载后运行 并不能完全支持类似C/C++的动态库方式处理代码</p></li><li style="box-sizing: border-box; margin-top: 0.25em;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">带状态的进程热更新的基本概念及范围是什么?</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">数据部分(model)不更新, 只更新逻辑部分(函数)</p></li><li style="box-sizing: border-box; margin-top: 0.25em;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">表格和配置更新算热更新么?</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">算, 但不是本文描述范围</p></li><li style="box-sizing: border-box; margin-top: 0.25em;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">热更新能在windows上使用么?</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">不支持</p></li></ul><h1><a href="file:///C:/Users/Davy/AppData/Local/Youdao/YNote/markdown/index.html#代码及结构" style="box-sizing: border-box; color: #4078c0; text-decoration-line: none;"></a>代码及结构</h1><ul data-source-line="29" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; padding-left: 2em; color: #333333; font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, Helvetica, Arial, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 21px; widows: 1; background-color: #ffffff;"><li style="box-sizing: border-box;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">我能将原来一个exe的代码编译为so提供给plugin使用么?</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">可以, 但是必须仍然保留main包作为插件入口, 并在main包内添加提供给plugin调用入口.</p></li><li style="box-sizing: border-box; margin-top: 0.25em;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">如果动态库中没有main包, 编译出的so能用么?</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">不能, 包必须包含main, 否则输出的是.a的文件, plugin包加载会报错</p></li><li style="box-sizing: border-box; margin-top: 0.25em;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">动态库中, 非main包的的代码修改能做热更新么?</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;"><span style="box-sizing: border-box; font-weight: 600;">不能</span>!(崩溃了吧, 我提了一个issue:&nbsp;<a href="https://github.com/golang/go/issues/20554" style="box-sizing: border-box; color: #4078c0; text-decoration-line: none; background-color: transparent;">https://github.com/golang/go/issues/20554</a>)</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">如果确实做了修改, 底层会报错: plugin was built with a different version of package</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">解决方法: 修改plugin包底层实现并重新编译 打开runtime/plugin.go, 注释以下代码 for _, pkghash := range md.pkghashes { if pkghash.linktimehash != *pkghash.runtimehash { return "", nil, pkghash.modulename } } 执行/usr/local/go/run.bash 重编译+测试</p></li><li style="box-sizing: border-box; margin-top: 0.25em;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">代码中哪些可以被更新? 方法可以被更新么? 闭包呢?</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">只能更新拥有静态地址的结构.例如: 包级别函数(类似于静态函数)</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">例如: svc_0.so里有一个Foo函数, svc_1.so修改了Foo函数实现, 热更新可实现</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;"><span style="box-sizing: border-box; font-weight: 600;">闭包=函数+捕获变量</span>, 实际上是一个动态结构, 没有静态地址, 无法被更新</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">各种包级别变量, 结构体变量, 结构体方法, 局部变量均不能被热更新, 但是变量值不会被影响</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">新增结构可以被运行</p></li><li style="box-sizing: border-box; margin-top: 0.25em;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">使用结构体方法调用了包级别函数, 包级别函数能被更新么?</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">可以, 虽然方法不能被更新, 但方法被调用的包级别函数的地址是固定的, 所以可以被热更新</p></li><li style="box-sizing: border-box; margin-top: 0.25em;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">init包初始化函数能用么? 能被热更新么?</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">官方这样描述:</p><pre data-source-line="71" style="box-sizing: border-box; font-stretch: normal; font-size: 11.9px; line-height: 1.45; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; word-wrap: normal; margin-top: 0px; margin-bottom: 16px; padding: 16px; overflow: auto; border-radius: 3px; background-color: #f7f7f7;"><code style="box-sizing: border-box; display: inline; overflow: visible; padding: 0px; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; margin: 0px; font-size: 11.9px; border-radius: 3px; word-break: normal; border: 0px; line-height: inherit; word-wrap: normal; background: 0px 0px transparent;"><span style="box-sizing: border-box; font-weight: 700;">When</span> a plugin <span style="box-sizing: border-box; font-weight: 700;">is</span> first opened, the init functions <span style="box-sizing: border-box; font-weight: 700;">of</span> <span style="box-sizing: border-box; font-weight: 700;">all</span> packages <span style="box-sizing: border-box; font-weight: 700;">not</span> already part <span style="box-sizing: border-box; font-weight: 700;">of</span> the program are called. The main <span style="box-sizing: border-box; font-weight: 700;">function</span> <span style="box-sizing: border-box; font-weight: 700;">is</span> <span style="box-sizing: border-box; font-weight: 700;">not</span> run. A plugin <span style="box-sizing: border-box; font-weight: 700;">is</span> only initialized once, <span style="box-sizing: border-box; font-weight: 700;">and</span> cannot be closed</code></pre><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">插件第一次被打开时, 其关联的, 没有成为程序的一部分的所有的包的init函数将被调用. 插件的main函数不会被调用. 插件只会被初始化一次, 不能被关闭</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">因此, 需要手动将init函数改成自己的函数, 统一在so的main包里调用</p></li></ul><h1><a href="file:///C:/Users/Davy/AppData/Local/Youdao/YNote/markdown/index.html#编译" style="box-sizing: border-box; color: #4078c0; text-decoration-line: none;"></a>编译</h1><ul data-source-line="80" style="box-sizing: border-box; margin-top: 0px; padding-left: 2em; color: #333333; font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, Helvetica, Arial, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 21px; widows: 1; background-color: #ffffff; margin-bottom: 0px !important;"><li style="box-sizing: border-box;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">如何编译获得plugin包支持的动态库</p><pre data-source-line="82" style="box-sizing: border-box; font-stretch: normal; font-size: 11.9px; line-height: 1.45; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; word-wrap: normal; margin-top: 0px; margin-bottom: 16px; padding: 16px; overflow: auto; border-radius: 3px; background-color: #f7f7f7;"><code style="box-sizing: border-box; display: inline; overflow: visible; padding: 0px; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; margin: 0px; font-size: 11.9px; border-radius: 3px; word-break: normal; border: 0px; line-height: inherit; word-wrap: normal; background: 0px 0px transparent;">SVCNAME=<span style="box-sizing: border-box; color: teal;">$1</span> SVCVER=<span style="box-sizing: border-box; color: teal;">$2</span> TIMESTAMP=`date <span style="box-sizing: border-box; color: #dd1144;">'+%Y%m%d_%H%M%S'</span>` go build -v -buildmode=plugin --ldflags=<span style="box-sizing: border-box; color: #dd1144;">"-pluginpath=${SVCNAME}_${TIMESTAMP}"</span> -o ${SVCNAME}<span style="box-sizing: border-box; color: teal;">_</span>${SVCVER}.so ${SVCNAME}</code></pre><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">-buildmode=plugin是重要参数</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">--ldflags里的-pluginpath的作用是: 每次编译的内部识别路径都是不同的, 避免重复加载的警告</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">参考:&nbsp;<a href="https://github.com/golang/go/issues/19004" style="box-sizing: border-box; color: #4078c0; text-decoration-line: none; background-color: transparent;">https://github.com/golang/go/issues/19004</a></p></li></ul><img src ="http://www.cppblog.com/sunicdavy/aggbug/215057.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2017-07-06 12:47 <a href="http://www.cppblog.com/sunicdavy/archive/2017/07/06/215057.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MMO相位技术研究</title><link>http://www.cppblog.com/sunicdavy/archive/2017/04/08/214817.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Sat, 08 Apr 2017 06:41:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2017/04/08/214817.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/214817.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2017/04/08/214817.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/214817.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/214817.html</trackback:ping><description><![CDATA[<h1>相位技术</h1><p data-source-line="3" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;">相位技术大规模出现在魔兽世界WLK版本, 现在应用已经广泛应用在各种MMORPG游戏中. 下面对相位技术的做法进行简单归纳汇总</p><h2><a href="file:///C:/Users/Davy/AppData/Local/Youdao/YNote/markdown/index.html#表现分类" style="box-sizing: border-box; color: #4078c0; text-decoration-line: none;"></a>表现分类</h2><h3><a href="file:///C:/Users/Davy/AppData/Local/Youdao/YNote/markdown/index.html#副本相位" style="box-sizing: border-box; color: #4078c0; text-decoration-line: none;"></a>副本相位</h3><p data-source-line="10" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;">早期副本的出现, 避免抢怪问题. 所以, 副本其实本身就是一种相位技术. 只不过实现时, 我们一般会将小队和怪物直接预分配在独立的一个副本实例中(所以副本原文也是实例的意思)</p><h3><a href="file:///C:/Users/Davy/AppData/Local/Youdao/YNote/markdown/index.html#分线相位" style="box-sizing: border-box; color: #4078c0; text-decoration-line: none;"></a>分线相位</h3><p data-source-line="15" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;">相位技术还没有正式命名时, 同一个场景, 玩家进到不同的分线看到的玩家不一样, 也是属于相位的一种. 当然, 如果是组队玩家, 服务器默认会分配所有队伍玩家在同一个线(位面)</p><h3><a href="file:///C:/Users/Davy/AppData/Local/Youdao/YNote/markdown/index.html#真相位" style="box-sizing: border-box; color: #4078c0; text-decoration-line: none;"></a>真相位</h3><p data-source-line="20" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;">副本相位和分线相位其实都是静态相位, 一旦进入, 中途不会有切换或者混合查看的过程. 真相位可以在一个场景中,动态切换相位, 相位内和相位外所以不同</p><p data-source-line="22" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;">我们常见的真相位表现为:&nbsp;<span style="box-sizing: border-box; font-weight: bolder;">相位中的角色+玩家+队伍成员</span></p><p data-source-line="24" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;">在护送任务时, 还会在上面所见角色中叠加世界中的所有角色, 也就是说, 你和队伍成员可以看到的角色, 其他人看不到, 其他人也看不到你和你的队伍成员</p><hr style="box-sizing: content-box; overflow: hidden; height: 4px; padding: 0px; margin: 16px 0px; border-width: 0px; border-style: initial; border-bottom-color: #eeeeee; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background: #e7e7e7;" /><p data-source-line="28" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;">为了清晰的简单的描述, 我为相位创建如下概念与名词</p><h2><a href="file:///C:/Users/Davy/AppData/Local/Youdao/YNote/markdown/index.html#相位客体" style="box-sizing: border-box; color: #4078c0; text-decoration-line: none;"></a>相位客体</h2><p data-source-line="33" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;">表现为除玩家外的角色(怪物,交互物体与相位可见场景)</p><h3><a href="file:///C:/Users/Davy/AppData/Local/Youdao/YNote/markdown/index.html#私有客体" style="box-sizing: border-box; color: #4078c0; text-decoration-line: none;"></a>私有客体</h3><p data-source-line="37" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;">这是最常见的一种相位内角色</p><ul data-source-line="39" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; padding-left: 2em; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;"><li style="box-sizing: border-box;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">持有变量</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">取PhasingID时,为PhasingTargetID</p></li><li style="box-sizing: border-box;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">生成规则</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">当玩家开启相位后, 在玩家相位内<span style="box-sizing: border-box; font-weight: bolder;">生成的角色</span>为私有客体.</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">此时, 将 PhasingTargetID设置为相位生成者的实例ID</p></li><li style="box-sizing: border-box;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">删除规则</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">如果玩家退出相位, 私有客体会存在一段时间或按照需求删除</p></li></ul><h3><a href="file:///C:/Users/Davy/AppData/Local/Youdao/YNote/markdown/index.html#公共客体" style="box-sizing: border-box; color: #4078c0; text-decoration-line: none;"></a>公共客体</h3><p data-source-line="55" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;">一般指提前放置在场景中, 世界内不可见, 但是能被同相位玩家可见,且同相位玩家都可以互相可见 比如: 只要接了同一个任务的玩家, 都可以看到的NPC</p><ul data-source-line="58" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; padding-left: 2em; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;"><li style="box-sizing: border-box;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">持有变量</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">取PhasingID时,为PublicPhasingID</p></li><li style="box-sizing: border-box;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">生成规则</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">通过场景编辑器, 放置角色时, 设置其可被观察到的任务ID</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">角色被加载后, 将任务ID设置到StaticPhasingID</p></li><li style="box-sizing: border-box;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">删除规则</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">场景删除, 角色删除</p></li></ul><h2><a href="file:///C:/Users/Davy/AppData/Local/Youdao/YNote/markdown/index.html#相位主体" style="box-sizing: border-box; color: #4078c0; text-decoration-line: none;"></a>相位主体</h2><p data-source-line="75" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;">包含玩家与同队伍玩家</p><ul data-source-line="78" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; padding-left: 2em; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;"><li style="box-sizing: border-box;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">开启相位后, 可见私有客体+公有客体</p></li><li style="box-sizing: border-box;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">队长视为相位主体, 单人时, 自己为队长</p></li><li style="box-sizing: border-box;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">队伍其他成员共享队长的私有相位客体</p></li><li style="box-sizing: border-box;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">队伍其他成员根据自己的PublicPhasingID匹配目标对象的PublicPhasingID时可互相可见</p></li><li style="box-sizing: border-box;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">持有变量</p></li></ul><p data-source-line="88" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;">相位开启时, 取PhasingID时, 为角色实例ID</p><p data-source-line="90" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;">相位关闭时, 取PhasingID时, 为0</p><p data-source-line="92" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;">PublicPhasingID</p><h2><a href="file:///C:/Users/Davy/AppData/Local/Youdao/YNote/markdown/index.html#可见规则" style="box-sizing: border-box; color: #4078c0; text-decoration-line: none;"></a>可见规则</h2><p data-source-line="98" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;">当两个角色的PhasingID相等时, 主体与私有客体互相可见</p><p data-source-line="100" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;">当两个角色的PublicPhasingID相等时, 主体与公有客体互相可见</p><p data-source-line="102" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;">可以通过开关设置, 是否在可见的相位客体基础上, 叠加世界角色(护送任务)</p><h2><a href="file:///C:/Users/Davy/AppData/Local/Youdao/YNote/markdown/index.html#约束" style="box-sizing: border-box; color: #4078c0; text-decoration-line: none;"></a>约束</h2><ul data-source-line="106" style="box-sizing: border-box; margin-top: 0px; padding-left: 2em; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff; margin-bottom: 0px !important;"><li style="box-sizing: border-box;">玩家同时只能看见1个相位</li></ul><img src ="http://www.cppblog.com/sunicdavy/aggbug/214817.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2017-04-08 14:41 <a href="http://www.cppblog.com/sunicdavy/archive/2017/04/08/214817.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Unity3D粒子系统屏幕外不更新不渲染问题</title><link>http://www.cppblog.com/sunicdavy/archive/2016/08/01/214082.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Mon, 01 Aug 2016 07:23:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2016/08/01/214082.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/214082.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2016/08/01/214082.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/214082.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/214082.html</trackback:ping><description><![CDATA[<p>这是一个Unity3D元老级bug, 表现就是:&nbsp; 角色在屏幕边缘放特效,&nbsp; 离开屏幕持续一段时间后再回到屏幕后, 发现特效重新播放. 显然这是错误的效果</p> <p>解决方法:</p> <p>在ParticleSystem组件上勾选SubEmitter, 不要问为什么, 做就好</p> <p>相关官方链接</p> <p><a title="http://answers.unity3d.com/questions/218369/shuriken-particle-system-not-rendering-particles-w.html" href="http://answers.unity3d.com/questions/218369/shuriken-particle-system-not-rendering-particles-w.html">http://answers.unity3d.com/questions/218369/shuriken-particle-system-not-rendering-particles-w.html</a></p> <p>&nbsp;</p> <p>天煞的, 4.X程序无法访问粒子系统的参数, 所以只能辛苦美术兄弟们了</p><img src ="http://www.cppblog.com/sunicdavy/aggbug/214082.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2016-08-01 15:23 <a href="http://www.cppblog.com/sunicdavy/archive/2016/08/01/214082.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>苹果ios应用的网络ipv6适配攻略</title><link>http://www.cppblog.com/sunicdavy/archive/2016/06/16/213731.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Thu, 16 Jun 2016 06:18:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2016/06/16/213731.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/213731.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2016/06/16/213731.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/213731.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/213731.html</trackback:ping><description><![CDATA[<p>苹果要求在2016年6月1日后新的app必须支持ipv6网络, 技术发展靠苹果果然没错, 但开发者还是要开始忙起来了<br>这里介绍下Unity3D的适配的一些经验 <h3>基本注意点</h3> <ul> <li>ios ipv6适配无需修改服务器, 也就是说, 如果你的服务器依然是ipv4的也是可以使用的</li> <li>苹果的适配方案是将ipv4的地址转换为ipv6, 到了路由层再转回去继续利用ipv4网络传输</li></ul> <h3>测试网络环境搭建</h3> <p><font color="#ffffff">转载请注明:</font><a title="http://www.cppblog.com/sunicdavy" href="http://www.cppblog.com/sunicdavy"><font color="#ffffff">http://www.cppblog.com/sunicdavy</font></a><font color="#ffffff">战魂小筑</font> <p>网上有很多翻译了苹果官方的搭建ipv6测试网络环境的文章, 例如:<br><a href="http://www.cocoachina.com/ios/20160525/16431.html">http://www.cocoachina.com/ios/20160525/16431.html</a><br>注意以下几点 <ul> <li> <p>无需路由器支持ipv6, 但猫(modem)必须要支持ipv6. 因为现在大多数都是光猫<br>以下截图是光猫管理端<br><a href="http://www.cppblog.com/images/cppblog_com/sunicdavy/Windows-Live-Writer/d3db4a514dd7_AD6A/3440e3f9-12de-435b-85ab-a7a3be8b384b%5B6%5D_1.jpg"><img title="3440e3f9-12de-435b-85ab-a7a3be8b384b[6]" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="3440e3f9-12de-435b-85ab-a7a3be8b384b[6]" src="http://www.cppblog.com/images/cppblog_com/sunicdavy/Windows-Live-Writer/d3db4a514dd7_AD6A/3440e3f9-12de-435b-85ab-a7a3be8b384b%5B6%5D_thumb_1.jpg" width="354" height="408"></a><br>光猫里的ipv6支持默认是关闭的, 所以需要手动打开, 按默认值配置即可</p> <li> <p>请确认mac os系统必须是osx 10.11以后的版本才可以打开NAT64</p> <li> <p>正确连接mac的ios设备应是如下截图示意<br><a href="http://www.cppblog.com/images/cppblog_com/sunicdavy/Windows-Live-Writer/d3db4a514dd7_AD6A/91f54476-4b5d-4585-a364-0da2139774c1%5B6%5D_1.jpg"><img title="91f54476-4b5d-4585-a364-0da2139774c1[6]" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="91f54476-4b5d-4585-a364-0da2139774c1[6]" src="http://www.cppblog.com/images/cppblog_com/sunicdavy/Windows-Live-Writer/d3db4a514dd7_AD6A/91f54476-4b5d-4585-a364-0da2139774c1%5B6%5D_thumb_1.jpg" width="296" height="508"></a></p> <li>默认连接上wifi时看连接信息时, 一般只会有红色DNS地址或者根本不显示  <li>只有在第一次访问网络, 例如打开浏览器进入任意网站时, 才会显示上面的几条信息  <li>如果只有DNS没有IP地址和子网掩码, 一般是光猫没有打开ipv6的DHCP, 没有分配IP  <li>还有一种测试ipv6 DHCP是否正常工作的方法: 关闭NAT64时可以上网, 但打开NAT64无法上网</li></ul> <p><font color="#ffffff">转载请注明:</font><a title="http://www.cppblog.com/sunicdavy" href="http://www.cppblog.com/sunicdavy"><font color="#ffffff">http://www.cppblog.com/sunicdavy</font></a><font color="#ffffff">战魂小筑</font></p> <h3>Unity3D的Socket适配</h3> <p>WWW类本身已经支持了IPV6, 无需处理, 这里讲解使用C#原生Socket的处理 <ul> <li>测试用的设备的iOS版本必须是9.3以上的  <li>Socket构造时, AddressFamily 设置为InterNetworkV6时只支持ipv6网络, 传入InterNetwork时只支持ipv4网络  <li> <p>4.7.2和5.4.3的当前版本在mono层并未支持ipv6代码适配的核心函数getaddrinfo, 因此需要通过oc层做转换, 以下是代码<br>这段代码将getaddrinfo的地址转换成一个完整字符串, 格式是:<br>ipv4|ipv4地址|ipv6|ipv6地址|</p></li></ul> <p>P.S. copyStr这种用法参考了<a href="http://www.codeinsect.net/blog/2016/05/26/unity-ipv6-socket-%E6%94%AF%E6%8C%81%EF%BC%8C%E5%B7%B2%E6%B5%8B%E8%AF%95%E9%80%9A%E8%BF%87/">http://www.codeinsect.net/blog/2016/05/26/unity-ipv6-socket-%E6%94%AF%E6%8C%81%EF%BC%8C%E5%B7%B2%E6%B5%8B%E8%AF%95%E9%80%9A%E8%BF%87/</a><br>会造成内存泄露, 如果有更好的方法欢迎反馈 <p><font color="#ffffff">转载请注明:</font><a title="http://www.cppblog.com/sunicdavy" href="http://www.cppblog.com/sunicdavy"><font color="#ffffff">http://www.cppblog.com/sunicdavy</font></a><font color="#ffffff">战魂小筑</font> <p>iosaddrinfo.mm<pre><p><div class="csharpcode"><pre class="alt"><span class="lnum">   1:  </span>#include &lt;sys/socket.h&gt;</pre><pre><span class="lnum">   2:  </span>#include &lt;netdb.h&gt;</pre><pre class="alt"><span class="lnum">   3:  </span>#include &lt;arpa/inet.h&gt;</pre><pre><span class="lnum">   4:  </span>#include &lt;err.h&gt;</pre><pre class="alt"><span class="lnum">   5:  </span><span class="preproc">#define</span> OUTSTR_SIZE 4096</pre><pre><span class="lnum">   6:  </span><span class="kwrd">extern</span> <span class="str">"C"</span></pre><pre class="alt"><span class="lnum">   7:  </span>{</pre><pre><span class="lnum">   8:  </span>    <span class="kwrd">const</span> <span class="kwrd">char</span>* copyStr( <span class="kwrd">const</span> <span class="kwrd">char</span>* str )</pre><pre class="alt"><span class="lnum">   9:  </span>    {</pre><pre><span class="lnum">  10:  </span>        <span class="kwrd">char</span>* s = (<span class="kwrd">char</span>*)malloc(strlen(str) + 1);</pre><pre class="alt"><span class="lnum">  11:  </span>        strcpy(s, str);</pre><pre><span class="lnum">  12:  </span>        <span class="kwrd">return</span> s;</pre><pre class="alt"><span class="lnum">  13:  </span>    }</pre><pre><span class="lnum">  14:  </span>    <span class="kwrd">const</span> <span class="kwrd">char</span>* IOSGetAddressInfo(<span class="kwrd">const</span> <span class="kwrd">char</span> *host )</pre><pre class="alt"><span class="lnum">  15:  </span>    {</pre><pre><span class="lnum">  16:  </span>        <span class="kwrd">if</span>( NULL == host )</pre><pre class="alt"><span class="lnum">  17:  </span>            <span class="kwrd">return</span> copyStr(<span class="str">"ERROR_HOSTNULL"</span>);</pre><pre><span class="lnum">  18:  </span>        <span class="kwrd">char</span> outstr[OUTSTR_SIZE];</pre><pre class="alt"><span class="lnum">  19:  </span>        <span class="kwrd">struct</span> addrinfo hints, *res, *res0;</pre><pre><span class="lnum">  20:  </span>        memset(&amp;hints, 0, <span class="kwrd">sizeof</span>(hints));</pre><pre class="alt"><span class="lnum">  21:  </span>        hints.ai_family = PF_UNSPEC;</pre><pre><span class="lnum">  22:  </span>        hints.ai_socktype = SOCK_STREAM;</pre><pre class="alt"><span class="lnum">  23:  </span>        hints.ai_flags = AI_DEFAULT;</pre><pre><span class="lnum">  24:  </span>        printf(<span class="str">"getaddrinfo: %s\n"</span>, host);</pre><pre class="alt"><span class="lnum">  25:  </span>        <span class="kwrd">int</span> error = getaddrinfo(host, <span class="str">"http"</span>, &amp;hints, &amp;res0);</pre><pre><span class="lnum">  26:  </span>        <span class="kwrd">if</span> (error != 0 )</pre><pre class="alt"><span class="lnum">  27:  </span>        {</pre><pre><span class="lnum">  28:  </span>            printf(<span class="str">"getaddrinfo: %s\n"</span>, gai_strerror(error));</pre><pre class="alt"><span class="lnum">  29:  </span>            <span class="kwrd">return</span> copyStr(<span class="str">"ERROR_GETADDR"</span>);</pre><pre><span class="lnum">  30:  </span>        }</pre><pre class="alt"><span class="lnum">  31:  </span>        memset( outstr, 0, <span class="kwrd">sizeof</span>(<span class="kwrd">char</span>)*OUTSTR_SIZE );</pre><pre><span class="lnum">  32:  </span>        <span class="kwrd">struct</span> sockaddr_in6* addr6;</pre><pre class="alt"><span class="lnum">  33:  </span>        <span class="kwrd">struct</span> sockaddr_in* addr;</pre><pre><span class="lnum">  34:  </span>        <span class="kwrd">const</span> <span class="kwrd">char</span>* solvedaddr;</pre><pre class="alt"><span class="lnum">  35:  </span>        <span class="kwrd">char</span> ipbuf[32];</pre><pre><span class="lnum">  36:  </span>        <span class="kwrd">for</span> (res = res0; res; res = res-&gt;ai_next)</pre><pre class="alt"><span class="lnum">  37:  </span>        {</pre><pre><span class="lnum">  38:  </span>            <span class="kwrd">if</span> (res-&gt;ai_family == AF_INET6)</pre><pre class="alt"><span class="lnum">  39:  </span>            {</pre><pre><span class="lnum">  40:  </span>                addr6 =( <span class="kwrd">struct</span> sockaddr_in6*)res-&gt;ai_addr;</pre><pre class="alt"><span class="lnum">  41:  </span>                solvedaddr = inet_ntop(AF_INET6, &amp;addr6-&gt;sin6_addr, ipbuf, <span class="kwrd">sizeof</span>(ipbuf));</pre><pre><span class="lnum">  42:  </span>                strcat ( outstr, <span class="str">"ipv6|"</span>);</pre><pre class="alt"><span class="lnum">  43:  </span>                strcat ( outstr, solvedaddr);</pre><pre><span class="lnum">  44:  </span>            }</pre><pre class="alt"><span class="lnum">  45:  </span>            <span class="kwrd">else</span></pre><pre><span class="lnum">  46:  </span>            {</pre><pre class="alt"><span class="lnum">  47:  </span>                addr =( <span class="kwrd">struct</span> sockaddr_in*)res-&gt;ai_addr;</pre><pre><span class="lnum">  48:  </span>                solvedaddr = inet_ntop(AF_INET, &amp;addr-&gt;sin_addr, ipbuf, <span class="kwrd">sizeof</span>(ipbuf));</pre><pre class="alt"><span class="lnum">  49:  </span>                strcat ( outstr, <span class="str">"ipv4|"</span>);</pre><pre><span class="lnum">  50:  </span>                strcat ( outstr, solvedaddr);</pre><pre class="alt"><span class="lnum">  51:  </span>            }</pre><pre><span class="lnum">  52:  </span>            strcat ( outstr, <span class="str">"|"</span>);</pre><pre class="alt"><span class="lnum">  53:  </span>        }</pre><pre><span class="lnum">  54:  </span>        <span class="kwrd">return</span> copyStr(outstr);</pre><pre class="alt"><span class="lnum">  55:  </span>    }</pre><pre><span class="lnum">  56:  </span>}</pre><pre><font color="#ffffff">转载请注明:</font><a title="http://www.cppblog.com/sunicdavy" href="http://www.cppblog.com/sunicdavy"><font color="#ffffff">http://www.cppblog.com/sunicdavy</font></a><font color="#ffffff">战魂小筑</font></pre></div><style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style></pre>
<p>iosaddrinfo.h<pre><p><div class="csharpcode"><pre class="alt"><span class="lnum">   1:  </span><span class="preproc">#pragma</span> once</pre><pre><span class="lnum">   2:  </span><span class="kwrd">extern</span> <span class="str">"C"</span>{</pre><pre class="alt"><span class="lnum">   3:  </span>    <span class="kwrd">const</span> <span class="kwrd">char</span>* IOSGetAddressInfo(<span class="kwrd">const</span> <span class="kwrd">char</span> *host );</pre><pre><span class="lnum">   4:  </span>}</pre></div><style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style></pre>
<ul>
<li>C#层的处理假设多个地址中都是统一的地址类型,要么全是v4要么全是v6<br>返回给定的host内多个IP地址, 可以供处理复杂的北网通,南电信问题</li></ul><pre><p><div class="csharpcode"><pre class="alt"><span class="lnum">   1:  </span><span class="kwrd">using</span> System;</pre><pre><span class="lnum">   2:  </span><span class="kwrd">using</span> System.Net;</pre><pre class="alt"><span class="lnum">   3:  </span><span class="kwrd">using</span> System.Net.Sockets;</pre><pre><span class="lnum">   4:  </span><span class="kwrd">using</span> System.Runtime.InteropServices;</pre><pre class="alt"><span class="lnum">   5:  </span><span class="kwrd">using</span> UnityEngine;</pre><pre><span class="lnum">   6:  </span><span class="kwrd">using</span> System.Collections;</pre><pre class="alt"><span class="lnum">   7:  </span><span class="kwrd">using</span> System.Collections.Generic;</pre><pre><span class="lnum">   8:  </span><span class="kwrd">public</span> <span class="kwrd">class</span> IOSIPV6</pre><pre class="alt"><span class="lnum">   9:  </span>{</pre><pre><span class="lnum">  10:  </span>    [DllImport(<span class="str">"__Internal"</span>)]</pre><pre class="alt"><span class="lnum">  11:  </span>    <span class="kwrd">private</span> <span class="kwrd">static</span> <span class="kwrd">extern</span> <span class="kwrd">string</span> IOSGetAddressInfo(<span class="kwrd">string</span> host );  </pre><pre><span class="lnum">  12:  </span>    <span class="kwrd">public</span> <span class="kwrd">static</span> IPAddress[] ResolveIOSAddress(<span class="kwrd">string</span> host, <span class="kwrd">out</span> AddressFamily af)</pre><pre class="alt"><span class="lnum">  13:  </span>    {</pre><pre><span class="lnum">  14:  </span>        af = AddressFamily.InterNetwork;</pre><pre class="alt"><span class="lnum">  15:  </span>        var outstr = IOSGetAddressInfo(host);</pre><pre><span class="lnum">  16:  </span>        Debug.Log(<span class="str">"IOSGetAddressInfo: "</span> + outstr);</pre><pre class="alt"><span class="lnum">  17:  </span>        <span class="kwrd">if</span> (outstr.StartsWith (<span class="str">"ERROR"</span>)) </pre><pre><span class="lnum">  18:  </span>        {</pre><pre class="alt"><span class="lnum">  19:  </span>            <span class="kwrd">return</span> <span class="kwrd">null</span>;</pre><pre><span class="lnum">  20:  </span>        }</pre><pre class="alt"><span class="lnum">  21:  </span>        var addressliststr = outstr.Split(<span class="str">'|'</span>);</pre><pre><span class="lnum">  22:  </span>        var addrlist = <span class="kwrd">new</span> List&lt;IPAddress&gt;();</pre><pre class="alt"><span class="lnum">  23:  </span>        <span class="kwrd">foreach</span> (<span class="kwrd">string</span> s <span class="kwrd">in</span> addressliststr)</pre><pre><span class="lnum">  24:  </span>        {</pre><pre class="alt"><span class="lnum">  25:  </span>            <span class="kwrd">if</span> (String.IsNullOrEmpty(s.Trim()))</pre><pre><span class="lnum">  26:  </span>                <span class="kwrd">continue</span>;</pre><pre class="alt"><span class="lnum">  27:  </span>            <span class="kwrd">switch</span>( s )</pre><pre><span class="lnum">  28:  </span>            {</pre><pre class="alt"><span class="lnum">  29:  </span>                <span class="kwrd">case</span> <span class="str">"ipv6"</span>:</pre><pre><span class="lnum">  30:  </span>                    {                        </pre><pre class="alt"><span class="lnum">  31:  </span>                        af = AddressFamily.InterNetworkV6;</pre><pre><span class="lnum">  32:  </span>                    }</pre><pre class="alt"><span class="lnum">  33:  </span>                    <span class="kwrd">break</span>;</pre><pre><span class="lnum">  34:  </span>                <span class="kwrd">case</span> <span class="str">"ipv4"</span>:</pre><pre class="alt"><span class="lnum">  35:  </span>                    {</pre><pre><span class="lnum">  36:  </span>                        af = AddressFamily.InterNetwork;</pre><pre class="alt"><span class="lnum">  37:  </span>                    }</pre><pre><span class="lnum">  38:  </span>                    <span class="kwrd">break</span>;</pre><pre class="alt"><span class="lnum">  39:  </span>                <span class="kwrd">default</span>:</pre><pre><span class="lnum">  40:  </span>                    {</pre><pre class="alt"><span class="lnum">  41:  </span>                        addrlist.Add(IPAddress.Parse(s));</pre><pre><span class="lnum">  42:  </span>                    }</pre><pre class="alt"><span class="lnum">  43:  </span>                    <span class="kwrd">break</span>;</pre><pre><span class="lnum">  44:  </span>            }</pre><pre class="alt"><span class="lnum">  45:  </span>        }</pre><pre><span class="lnum">  46:  </span>        <span class="kwrd">return</span> addrlist.ToArray();</pre><pre class="alt"><span class="lnum">  47:  </span>    }</pre><pre><span class="lnum">  48:  </span>}</pre><pre><font color="#ffffff">转载请注明:</font><a title="http://www.cppblog.com/sunicdavy" href="http://www.cppblog.com/sunicdavy"><font color="#ffffff">http://www.cppblog.com/sunicdavy</font></a><font color="#ffffff">战魂小筑</font></pre></div><style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style></pre>
<h3>参考链接</h3>
<p>官方文档<br><a href="https://developer.apple.com/library/ios/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/UnderstandingandPreparingfortheIPv6Transition/UnderstandingandPreparingfortheIPv6Transition.html#//apple_ref/doc/uid/TP40010220-CH213-SW1">https://developer.apple.com/library/ios/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/UnderstandingandPreparingfortheIPv6Transition/UnderstandingandPreparingfortheIPv6Transition.html#//apple_ref/doc/uid/TP40010220-CH213-SW1</a>
<p>某人的解决方案<br><a href="http://www.codeinsect.net/blog/2016/05/26/unity-ipv6-socket-%E6%94%AF%E6%8C%81%EF%BC%8C%E5%B7%B2%E6%B5%8B%E8%AF%95%E9%80%9A%E8%BF%87/">http://www.codeinsect.net/blog/2016/05/26/unity-ipv6-socket-%E6%94%AF%E6%8C%81%EF%BC%8C%E5%B7%B2%E6%B5%8B%E8%AF%95%E9%80%9A%E8%BF%87/</a><br>注意, 此方案中的方法可用, 但是地址并不能解决南北互通的问题



<img src ="http://www.cppblog.com/sunicdavy/aggbug/213731.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2016-06-16 14:18 <a href="http://www.cppblog.com/sunicdavy/archive/2016/06/16/213731.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>资源管理模式之Unity3D的Prefab与电子表格</title><link>http://www.cppblog.com/sunicdavy/archive/2016/03/24/213107.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Thu, 24 Mar 2016 08:33:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2016/03/24/213107.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/213107.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2016/03/24/213107.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/213107.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/213107.html</trackback:ping><description><![CDATA[<p>最近在项目中进行资源优化. 我们的项目一直以来都是以传统的电子表格配置为中心的资源驱动加载方法, 拿角色携带的特效要播放出来这个case来具体点说就是:</p> <p>1. 技能部分的特效可以遍历动作表播放的所有特效id, 提前预载</p> <p>2. buff类特效是动态确定的,无法分析. 需要通过角色表添加资源id在加载角色时加载特效</p> <p>这种做法的缺点:</p> <p>当角色特效效果调整时, 美术和策划需要调整特效id表. 多出来不用的特效也加载是感觉不出来的, 分析也是很困难的</p> <p>所以这种以传统的电子表格配置为中心的方式在Unity3D里, 内存, 包优化会是个大问题.</p> <p>&nbsp;</p> <p>那么, 什么是Unity3D的开发核心思想? </p> <p>除了组件思想外, 就是Prefab, 贯彻整个编辑器及引擎自始至终</p> <p>&nbsp;</p> <p>处理角色携带特效加载后播放的这个case, 用Prefab为中心的资源管理来做的话, 大概就是这样:</p> <p>1. 程序编写一个角色特效列表脚本, 把List暴露出来可以在编辑器里使用</p> <p>2. 美术在做技能时, 把要用到的特效拖拽到List中</p> <p>3. 特效无需再编制全局ID编码</p> <p>4. 策划根据这个角色挂接的特效索引, 在配置表里添加播放指令</p> <p>这样做的优点:</p> <p>角色引用到的资源才会被打到最终游戏包内, 不使用的资源是不会被加载的</p> <p>&nbsp;</p> <p>类似的, 在UI特效里, 也应该是将要播放的特效挂接到对象中, 而不是动态通过代码去加载</p> <p>在Unity3D中, Prefab将图片,Shader, 特效, 脚本等一切平等看待, 只要有引用, 一次性加载. </p> <p>同时, 也可以通过静态工具分析Prefab. </p> <p>如果是通过代码加载的效果, 则只能让程序员做优化, 这种过程无法让Unity3D官方后期提供的工具进行优化</p> <p>&nbsp;</p> <p>所以, 推荐使用Prefab为中心的资源管理模式</p><img src ="http://www.cppblog.com/sunicdavy/aggbug/213107.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2016-03-24 16:33 <a href="http://www.cppblog.com/sunicdavy/archive/2016/03/24/213107.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Google Protobuf 3版本介绍</title><link>http://www.cppblog.com/sunicdavy/archive/2016/01/25/212739.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Mon, 25 Jan 2016 06:23:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2016/01/25/212739.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/212739.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2016/01/25/212739.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/212739.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/212739.html</trackback:ping><description><![CDATA[<p>本文编写时, Google 官方的 <a href="https://github.com/google/protobuf">protobuf</a> 版本是3.0.0beta</p> <p>下面介绍下proto3的一些细节变化</p> <h1>Proto3的语法变化</h1> <h2>语法标记</h2> <p>这个版本的protoc的protobuf编译器已经可以支持proto2语法和proto3的语法</p> <p>如果你的proto文件没有添加syntax说明的话, 用这个版本的编译器会报错, 提示你默认proto2支持, 请添加语法标记</p> <p>syntax = "proto2";</p> <p>&nbsp;</p> <h2>optional不需要了</h2> <p>只保留repeated标记数组类型, optional和required都被去掉了</p> <p>实际使用证明, required的设计确实是蛋疼, C++的调试版会弹出assert,release版和optional也没啥区别</p> <h2>map支持</h2> <p>map编写格式为</p><pre>map&lt;key_type, value_type&gt; map_field = N;</pre><pre>例如:</pre><pre>map&lt;string, Project&gt; projects = 3;</pre><pre>代码生成确认支持map, 这对于很多语言来说又可以偷懒了</pre>
<h2>字段default标记不能使用了</h2>
<p>位于proto2语法的字段number后的[default=XX]</p>
<p>这个东西不能用了, 理由是:</p>
<p>对于同一段序列化后的数据, 如果序列化端的default和反序列化端的default描述不一样会导致最终结果完全不一致</p>
<p>即: 同一个数据两个结果, 这是不可预测的结果, 因此干掉这个特性</p>
<p>不过本人觉得, 对于游戏来说, 这个功能本身可以压缩很多数据,虽然会有隐患</p>
<p>&nbsp;</p>
<h2>枚举默认值一定是0</h2>
<p>proto2里的默认值是枚举的第一个value对应的值, 不一定为0</p>
<p>proto3在你定义value时, 强制要求第一个值必须为0</p>
<p>这个修改为避免隐患还是有帮助的</p>
<h2>泛型描述支持</h2>
<p>any类型, 可以代表任何类型, 可以先读进来, 再进行解析, 没具体用, 步子跨大了怕扯到蛋</p>
<h2>支持json序列化</h2>
<p>这个极好, json再次被同化了</p>
<h2>增加了多种语言支持</h2>
<p>js, objc, ruby, C#等等</p>
<p>然而, C#版本的基础runtime库是用C# 6.0的语法写的,这对于Unity mono祖传2.0来说, 确实扯到蛋了,没法用</p>
<h2>Protobuf现在使用CMAKE做配置系统</h2>
<p>编译起来稍微麻烦, 还要下个被墙掉的cmake…</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h1>第三方库里对于proto3的变化</h1>
<p>Golang的官方protobuf支持: <a title="https://github.com/golang/protobuf" href="https://github.com/golang/protobuf">https://github.com/golang/protobuf</a></p>
<h2>生成代码中的结构体字段类型变化</h2>
<p>对于proto2的文件, 生成的go代码中的结构体依然使用类型指针作为默认存储, 兼容老的系统</p>
<p>对于proto3的文件, 生成的go代码中的结构体直接使用字段作为默认存储, 不再使用GetXXX来作为字段值访问, 赋值时也无需使用proto.类型() 函数进行指针类型字段值创建.</p>
<p>这个调整很是方便, 但丢失了optional判断功能, 对应C++里就是hasXXX的功能, 不过好歹这个逻辑现在用的不多了</p>
<p>这个修改大概也是配合json序列化来做的, go默认的json序列化时, 无法使用proto2生成的结构体的, 因为都是指针,无法赋值..</p>
<p>&nbsp;</p>
<h2>新版protoc-gen-go的插件会生成descriptor的压缩数据</h2>
<p>新插件会给每次生成的文件添加这样一段代码</p><pre><div class="csharpcode"><pre class="alt">var fileDescriptor0 = []<span class="kwrd">byte</span>{</pre><pre>    <span class="rem">// 220 bytes of a gzipped FileDescriptorProto</span></pre><pre class="alt">    0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x64, 0x8f, 0xcd, 0x4e, 0xc5, 0x20,</pre><pre>    0x10, 0x85, 0x53, 0xbd, 0x35, 0x32, 0xb7, 0xdd, 0x4c, 0x5c, 0xb0, 0x70, 0x71, 0xd3, 0xb8, 0x70,</pre><pre class="alt">    0x75, 0x17, 0xfa, 0x04, 0xc6, 0xd8, 0xb8, 0x50, 0x63, 0xa8, 0x2f, 0x80, 0xed, 0x44, 0x89, 0x28,</pre><pre>    0x04, 0xc6, 0xbf, 0x47, 0xf1, 0x6d, 0x95, 0x49, 0x8d, 0x4d, 0x5c, 0x01, 0xdf, 0x39, 0x7c, 0x30,</pre><pre class="alt">    0x00, 0x1c, 0x82, 0xdf, 0xc6, 0x14, 0x38, 0xe0, 0xaa, 0xec, 0xbb, 0x37, 0x68, 0x2e, 0x3e, 0x62,</pre><pre>    0x48, 0x7c, 0x49, 0x76, 0xa2, 0x84, 0x47, 0xd0, 0xde, 0x96, 0xf8, 0xee, 0x33, 0xd2, 0x8d, 0x7d,</pre><pre class="alt">    0x26, 0x5d, 0x6d, 0xaa, 0x63, 0x65, 0xda, 0xb8, 0x84, 0xd8, 0x41, 0x63, 0xc2, 0x7b, 0xef, 0xc8,</pre><pre>    0x4f, 0x52, 0xda, 0x91, 0x52, 0x93, 0x16, 0x0c, 0x0f, 0x41, 0x89, 0xa9, 0x77, 0x9e, 0xf4, 0xae,</pre><pre class="alt">    0x14, 0x54, 0xfc, 0x05, 0xdd, 0x57, 0x05, 0x4a, 0xba, 0xd7, 0xc4, 0x16, 0xb7, 0x80, 0x03, 0x27,</pre><pre>    0xf7, 0xf2, 0x70, 0x72, 0xe5, 0x32, 0x0f, 0xd1, 0x3b, 0xa6, 0x34, 0x5b, 0x31, 0xff, 0x4b, 0x70,</pre><pre class="alt">    0x03, 0x6b, 0x43, 0x91, 0x2c, 0x9f, 0x3f, 0xd2, 0xf8, 0x24, 0xf6, 0x7d, 0xb3, 0x4e, 0x7f, 0x08,</pre><pre>    0x0f, 0xa0, 0x3e, 0xf3, 0xce, 0x66, 0xbd, 0x12, 0x49, 0x6d, 0xcb, 0xa1, 0x4c, 0x37, 0xbf, 0xf3,</pre><pre class="alt">    0xb3, 0xbc, 0x8e, 0xac, 0x6b, 0xb9, 0xd9, 0xe6, 0x25, 0xbc, 0xdf, 0x93, 0x6f, 0x9e, 0x7e, 0x07,</pre><pre>    0x00, 0x00, 0xff, 0xff, 0x0c, 0x9f, 0x10, 0xa8, 0x2e, 0x01, 0x00, 0x00,</pre><pre class="alt">}</pre></div><style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style><br></pre>
<p>对于meta信息的提取还是很方便的</p>
<p>然而</p>
<p>对于多个文件的生成, 这样做非常的麻烦, 因为这个字段会重复导致编译错误</p>
<p>很多人在论坛里吐槽, 官方给出的解决方法是, 使用protoc一次性传入一个package下的所有的proto直接生成一个go</p>
<p>而不是现在的一个proto一个go</p>
<h2>生成代码会自动注册到全局, 并可以方便的查询</h2>
<p>以前这个代码需要自己来做, 现在官方提供了支持, 很是方便</p>
<p>然而, 为什么不支持遍历… 残念啊, 又要自己动手了</p><img src ="http://www.cppblog.com/sunicdavy/aggbug/212739.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2016-01-25 14:23 <a href="http://www.cppblog.com/sunicdavy/archive/2016/01/25/212739.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>pp助手服务器端支付的RSA的奇葩公钥解密设计</title><link>http://www.cppblog.com/sunicdavy/archive/2015/10/12/211993.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Mon, 12 Oct 2015 06:27:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2015/10/12/211993.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/211993.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2015/10/12/211993.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/211993.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/211993.html</trackback:ping><description><![CDATA[<p>最近接入pp助手的服务器端支付, 按照PP官方提供的文档来看, 需要服务器做RSA的验证. </p> <p>首先我们来看下</p> <h1>RSA的几个标准用法</h1> <h2>非对称加密解密</h2> <p>假设A要把内容传输给B</p> <p>1. B生成RSA的公钥和密钥, 这是成对出现的, 密钥由B保存, 把公钥告诉A</p> <p>2. A用B的公钥加密内容, 并把密文内容传输给B</p> <p>3. B用密钥解密</p> <h2>验证</h2> <p>证明某个内容是你发的, 而不是被别人冒名顶替, 例如git的push中就带有这个功能</p> <p>假设A有内容,&nbsp; B要验证内容确实由A发出</p> <p>1. A生成公钥和密钥</p> <p>2. A将内容做一个hash, 把hash码用自己的密钥加密并把这段密文发给B</p> <p>3. B用A的公钥对密文进行验证, 即可确认密文是否由A发出</p> <p>&nbsp;</p> <p>可以看出, 两种用法都是典型的非对称用法</p> <p>但PP助手却干了件神奇的事情:</p> <h1>非对称当对称算法加解密</h1> <p>在PP SDK官方文档里, 我们找到了PHP语言的验证方法, 方法里使用了这样一个API</p> <p><a href="http://php.net/manual/zh/function.openssl-public-decrypt.php">openssl_public_decrypt</a></p> <p>从官方文档看得出这个使用openssl的算法库</p> <p>&nbsp;</p> <p>类似的, 还有Java, C++, Python语言的处理方法</p> <p>其中, C++也是用的openssl, Python则是需要预编译C库，在Ubuntu下需要手工patch M2Crypto的_ssl.c文件.</p> <p>&nbsp;</p> <p>先不说这些非正规的编译,patch方法会造成多大的问题, 单就这个用公钥解密就很蛋疼</p> <p>从之前的RSA算法中了解, 只有对公钥进行验证的方法, 也就是只能得到是还是不是的结果. 但PP的SDK则要求必须用公钥解密…</p> <p>解出的数据为一段json, 以对比是否有订单篡改.</p> <p>&nbsp;</p> <p>那么这种做法就等效于, 用最简单的异或+一个公钥进行订单加密, 然后同样用这个公钥进行解密</p> <p>只不过用RSA感觉很高级…</p> <p>这种做法一旦公钥在PP助手服务器或者玩家的开发服务器, 甚至源代码泄露, 那么马上就有很大的伪造订单的危险</p> <p>&nbsp;</p> <p>我把这个做法发给朋友看, 他们说, 其实PP助手的开发者只管用了RSA, 跟传输不是明文就好了, 至于什么信息安全, 都是屁!</p><img src ="http://www.cppblog.com/sunicdavy/aggbug/211993.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2015-10-12 14:27 <a href="http://www.cppblog.com/sunicdavy/archive/2015/10/12/211993.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一个诡异的Unity3D的网络问题</title><link>http://www.cppblog.com/sunicdavy/archive/2015/07/06/211162.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Mon, 06 Jul 2015 08:11:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2015/07/06/211162.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/211162.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2015/07/06/211162.html#Feedback</comments><slash:comments>8</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/211162.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/211162.html</trackback:ping><description><![CDATA[<p>项目中, 我们使用Unity3D做客户端开发. 自己撸了一套C#网络库, 随着项目的推进, 问题来了:</p> <h1>问题</h1> <p><strong>每次Unity3D编辑器打开时, 连接服务器都会有一定几率失败, 需要反复关闭再打开编辑器3~4次后, 才能正常接收到封包</strong></p> <p><font color="#ffffff">转载请注明: 战魂小筑</font><a href="http://www.cppblog.com/sunicdavy"><font color="#ffffff">http://www.cppblog.com/sunicdavy</font></a></p> <h1><strong>探索</strong></h1> <p>我们的网络库基于C#的Begin/End系的异步Socket, 这种socket更接近C++的asio模型, 撸起来特爽.</p> <p>1. 根据经验, 这个诡异问题多半跟多线程有关系. 复查代码, 无效. </p> <p>2. 找友人更换网络库, 换阻塞Socket实现和SocketAsyncEventArgs这种实现都试过, 仍然无法解决问题.</p> <p>3. 接下来还是对Begin/End系的网络库进行日志追踪. 发现, 发送会总是成功, 连接成功和接收封包有一定几率会断掉</p> <p>我们并没有单独开线程来处理, 而是利用底层异步通知, 然后有线程安全队列切换到主线程进行投递. 因此底层的线程正常性是整个问题的焦点</p> <p>由于一直无法找到原因, 这个问题搁置了</p> <p><font color="#ffffff">转载请注明: 战魂小筑</font><a href="http://www.cppblog.com/sunicdavy"><font color="#ffffff">http://www.cppblog.com/sunicdavy</font></a></p> <h1>解决方案</h1> <p>直到有一个偶然的机会, 取过同事代码后. 突然发现第一次打开Unity3D编辑器可以直接登录. 但之后又不行. 同事提醒, 会不会是优先度问题. </p> <p>马上打开Edit-&gt;Project Settings-&gt;Script Execution Orders. <strong>提高了网络组建优先度</strong></p> <p><a href="http://www.cppblog.com/images/cppblog_com/sunicdavy/Windows-Live-Writer/Unity3D_DF1C/image_2.png"><img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/sunicdavy/Windows-Live-Writer/Unity3D_DF1C/image_thumb.png" width="394" height="267"></a></p> <p>测试, 通过, 问题解决</p> <p><font color="#ffffff">转载请注明: 战魂小筑</font><a href="http://www.cppblog.com/sunicdavy"><font color="#ffffff">http://www.cppblog.com/sunicdavy</font></a></p> <h1>总结</h1> <p><font color="#ffffff">转载请注明: 战魂小筑</font><a href="http://www.cppblog.com/sunicdavy"><font color="#ffffff">http://www.cppblog.com/sunicdavy</font></a></p> <p>一直怀疑这个问题跟Mono版本过老有关系, 但由于5.2版本到年底才更新, 之前只能自己啃bug. </p> <p>在这个问题发生后解决前, 我们还有一个相关见闻: 我们将网络部分比较稳定的代码拆分放到dll中, 通过Unity3D的机制进行加载</p> <p>结果, 网络无法初始化. 估计也是跟这个问题有关系</p> <p>总之, 有类似问题时, 可以试用脚本执行顺序大法进行尝试</p><img src ="http://www.cppblog.com/sunicdavy/aggbug/211162.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2015-07-06 16:11 <a href="http://www.cppblog.com/sunicdavy/archive/2015/07/06/211162.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>游戏数据库选型mysql,mongo, redis, memcached</title><link>http://www.cppblog.com/sunicdavy/archive/2015/06/19/210992.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Fri, 19 Jun 2015 08:23:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2015/06/19/210992.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/210992.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2015/06/19/210992.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/210992.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/210992.html</trackback:ping><description><![CDATA[<h1>数据库选择历程</h1> <p>我们的项目一直使用MySQL作为数据库. 无论是从C++的服务器, 还是到Golang服务器. 当年搞服务器时, 看大部分人都是用SQL(MySQL/SQLServer), 而Mongo感觉像邪教一样, 再加上服务器还是Linux比较正统, 所以果断选了MySQL.</p> <p>刚开始感觉,游戏服务器的数据存储其实应该是蛮神圣的过程. 那么多的数据, 需要按照MySQL一样分表, 分字段存储, 为了查询, 还要乖乖的学一下SQL的语法</p> <p>就这么折腾了几年. 在云DB的蒙蔽下, 一直认为MySQL就是做游戏服务器存储的专业技术. 分布式和存储压力一定交给云DB来做. 直到真正试了下NoSQL在游戏服务器开发里的思路.</p> <p>用了Golang, 才发现同步写逻辑是多么的优雅. </p> <p>用了NoSQL系列的数据库, 才意识到: 游戏服务器的数据存储和游戏服务器的存盘两个概念差异其实蛮大的.</p> <p>MySQL中, 背包其实跟角色完全没有关系, 只是通过1个角色id映射过去, 人为的割裂了数据的关联性. 还硬生生的整出个概念叫结构化查询让你学</p> <p>NoSQL中, 只是把数据库当成是存储点, 每个角色的数据是完整的一块. 里面怎么存随你便. 每个角色通过id来查询, 其他都没有了</p> <p>于是乎, 游戏开发变得异常简单. MySQL角色进门查询4~5次才能搞定要的数据.而NoSQL一口气全查出来, 存盘也无需增量, 直接存盘就可以了</p> <p>所以现在觉得, NoSQL的思路对于游戏服务器存储来说简直是完美的!</p> <p><font color="#ffffff">转载请注明: 战魂小筑</font><a href="http://www.cppblog.com/sunicdavy"><font color="#ffffff">http://www.cppblog.com/sunicdavy</font></a></p> <p>&nbsp;</p> <h1>NoSQL数据库方案对比</h1> <p>NoSQL下实现方案很多, 游戏常用的就这么3家: mongo, redis, memcached</p> <p>下面说下优缺点</p> <h2>mongo</h2> <p>磁盘映射内存数据库</p> <p>value为document类型, 基于BSON的value序列化</p> <p>应用场景:</p> <p>适合多写少读, 例如日志和备份</p> <p><font color="#ffffff">转载请注明: 战魂小筑</font><a href="http://www.cppblog.com/sunicdavy"><font color="#ffffff">http://www.cppblog.com/sunicdavy</font></a></p> <p>&nbsp;</p> <h2>redis</h2> <p>内存数据库</p> <p>单核</p> <p>value限制512M</p> <p>多种value类型, 游戏用途使用私有的序列化协议(例如protobuf)</p> <p>支持落地(bgsave)</p> <p>用户: 新浪, 淘宝, Flickr, Github</p> <p>应用场景: 适合读写都很高, 数据处理复杂等</p> <p><font color="#ffffff">转载请注明: 战魂小筑</font><a href="http://www.cppblog.com/sunicdavy"><font color="#ffffff">http://www.cppblog.com/sunicdavy</font></a></p> <p>&nbsp;</p> <h2>memcached</h2> <p>内存数据库</p> <p>多核</p> <p>value限制1M</p> <p>不支持落地(持久化)</p> <p>用户: LiveJournal、hatena、Facebook、Vox</p> <p>应用场景: 动态系统中的缓冲, 适合多读少写</p> <p><font color="#ffffff">转载请注明: 战魂小筑</font><a href="http://www.cppblog.com/sunicdavy"><font color="#ffffff">http://www.cppblog.com/sunicdavy</font></a></p> <h1>个人评价</h1> <p>memcached 适合网页缓冲, 游戏里很少有使用. 目前只有腾讯云支持云memcached</p> <p>redis非常适合游戏的内存数据库, 但是落地策略会比较复杂, 需要具体分析, 可以参考后面的链接看下云风怎么处理这个问题</p> <p>mongo数据库在早期还是非常不错的NoSQL的数据库. 工具比较方便, 可视化. 但是随着近年来游戏的并发度越来越高, 所以为了一次到位, 很多人还是选择了redis</p> <p>下图参考自知乎问题. 链接在后面有提示, 若侵权请联系删除</p> <p><font color="#ffffff">转载请注明: 战魂小筑</font><a href="http://www.cppblog.com/sunicdavy"><font color="#ffffff">http://www.cppblog.com/sunicdavy</font></a></p> <p><a href="http://www.cppblog.com/images/cppblog_com/sunicdavy/Windows-Live-Writer/857198a996df_9ADD/image_5.png"><img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; margin: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/sunicdavy/Windows-Live-Writer/857198a996df_9ADD/image_thumb_1.png" width="591" height="168"></a></p> <h1><strong>参考链接:</strong></h1> <h5><font style="font-weight: normal">&nbsp;&nbsp;&nbsp; 谈谈陌陌争霸在数据库方面踩过的坑( Redis 篇)</font></h5> <p><a title="http://blog.codingnow.com/2014/03/mmzb_redis.html" href="http://blog.codingnow.com/2014/03/mmzb_redis.html">http://blog.codingnow.com/2014/03/mmzb_redis.html</a></p> <p><font color="#ffffff">转载请注明: 战魂小筑</font><a href="http://www.cppblog.com/sunicdavy"><font color="#ffffff">http://www.cppblog.com/sunicdavy</font></a></p> <p>Memcache,Redis,MongoDB（数据缓存系统）方案对比与分析</p> <p><a title="http://blog.csdn.net/suifeng3051/article/details/23739295" href="http://blog.csdn.net/suifeng3051/article/details/23739295">http://blog.csdn.net/suifeng3051/article/details/23739295</a></p> <p>&nbsp;</p> <p><a title="http://www.zhihu.com/question/31417262" href="http://www.zhihu.com/question/31417262">http://www.zhihu.com/question/31417262</a></p><img src ="http://www.cppblog.com/sunicdavy/aggbug/210992.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2015-06-19 16:23 <a href="http://www.cppblog.com/sunicdavy/archive/2015/06/19/210992.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C/C++服务器架构机制设计总结</title><link>http://www.cppblog.com/sunicdavy/archive/2014/12/18/209225.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Thu, 18 Dec 2014 08:39:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2014/12/18/209225.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/209225.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2014/12/18/209225.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/209225.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/209225.html</trackback:ping><description><![CDATA[<p>近期在写基于go的游戏服务器框架, 在全面脱离C/C++前, 需要对老架构进行一个总结  <p>基于C/C++游戏服务器框架总体设计的还是不错的, 兄弟们总体使用效果都是好评. 因为在技术上喜欢"偷懒", 所以在很多设计上, 都是力求简单, 高效(开发效率).  <p><strong>基于任务的异步DB查询系统, 带多重异步的同步</strong> <p>代码示例:  <div class="csharpcode"><pre class="alt"><span class="lnum">   1:  </span>&nbsp;</pre><pre><span class="lnum">   2:  </span><span class="kwrd">void</span> BatchQueryPlayerInfo( uint32 ClientID, <span class="kwrd">const</span> std::<span class="kwrd">string</span>&amp; AccountName, int64 CharID )</pre><pre class="alt"><span class="lnum">   3:  </span>{</pre><pre><span class="lnum">   4:  </span>    GDBExecutor-&gt;Commit</pre><pre class="alt"><span class="lnum">   5:  </span>        (    </pre><pre><span class="lnum">   6:  </span>        dynamic_cast&lt;DBDataTask*&gt;( (<span class="kwrd">new</span> DBQueryCharInfo(  ClientID, CharID ) ) </pre><pre class="alt"><span class="lnum">   7:  </span>        -&gt;LinkAtomTask( <span class="kwrd">new</span> DBQueryQuest( ClientID, CharID ) )</pre><pre><span class="lnum">   8:  </span>        -&gt;LinkAtomTask( <span class="kwrd">new</span> DBQuerySkill( ClientID, CharID ) )</pre><pre class="alt"><span class="lnum">   9:  </span>        -&gt;LinkAtomTask( <span class="kwrd">new</span> DBQueryHero( ClientID, CharID ) )</pre><pre><span class="lnum">  10:  </span>        -&gt;LinkAtomTask( <span class="kwrd">new</span> DBQueryAccountInfo( ClientID, AccountName ) )</pre><pre class="alt"><span class="lnum">  11:  </span>        -&gt;LinkAtomTask( <span class="kwrd">new</span> DBQueryEquip( ClientID, CharID ) )</pre><pre><span class="lnum">  12:  </span>        -&gt;LinkAtomTask( <span class="kwrd">new</span> DBQueryObject( ClientID ,CharID ) )</pre><pre class="alt"><span class="lnum">  13:  </span>        -&gt;LinkAtomTask( <span class="kwrd">new</span> DBQueryLevel(ClientID, CharID))</pre><pre><span class="lnum">  14:  </span>        -&gt;LinkAtomTask( <span class="kwrd">new</span> DBQueryChapter(ClientID, CharID))</pre><pre class="alt"><span class="lnum">  15:  </span>        -&gt;LinkAtomTask( <span class="kwrd">new</span> DBQueryActivity( ClientID, CharID ))</pre><pre><span class="lnum">  16:  </span>        )</pre><pre class="alt"><span class="lnum">  17:  </span>        );</pre><pre><span class="lnum">  18:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  19:  </span>}</pre></div>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>


<p>这段主要处理玩家在登陆时, 需要从DB查询大量的不同分类的数据. 为了保证效率, 我让每个Task并行执行, 然后通过一个机制, 让所有任务完成后, 回调第一个任务的一个函数. 这样就无需手动实现很多粘合代码, 避免了反复调试和错误</p>
<p><strong>基于protobuf反射机制的语句自动合成</strong></p>
<div class="csharpcode"><pre class="alt"><span class="lnum">   1:  </span>DBUpdateCharInfo::DBUpdateCharInfo( int64 CharID, <span class="kwrd">const</span> std::<span class="kwrd">string</span>&amp; Buffer )</pre><pre><span class="lnum">   2:  </span>{</pre><pre class="alt"><span class="lnum">   3:  </span>    <span class="kwrd">char</span> buffer[256];</pre><pre><span class="lnum">   4:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">   5:  </span>    sprintf( buffer, <span class="str">"update tb_char set $FIELD$ where charid = %lld;"</span>, CharID );</pre><pre><span class="lnum">   6:  </span>        </pre><pre class="alt"><span class="lnum">   7:  </span>    ExecuteCommand( buffer, Buffer, dbopr::FET_Equation );</pre><pre><span class="lnum">   8:  </span>}</pre></div>
<p>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>
这段就是一个典型的DB任务, 构造函数提供了CharID和一个由结构体序列化好的buffer, $FIELD$字段, 是通过反射根据Buffer内容, 自动填充字段</p>
<p>这段例子中, $FIELD$可以填充为 hp=100, mp=100之类的. 自动填充避免了因为添加字段的到处添加代码, 还需要调试, 容易搞错</p>
<p>&nbsp;</p>
<p><strong>配置系统概念</strong></p>
<p>基于同一个配置系统, 分层实现不同的需求. 更简单的说, 解决的1个实际问题是: </p>
<p>自己改了配置文件中的ip, 上传svn后, 覆盖了别人的配置, 很多人的解决方法都是, 本地配置不提交. 但同时问题又来了:</p>
<p>当配置中有别人新加的系统配置, 怎么保证每个人都能更新到?</p>
<p>上线后, 服务器交付运维, 他们会对配置有一定程度的修改, 这个时候怎么合并程序配置和运维配置?</p>
<p>其实对于冲突的需求, 只要对系统进行分层就可以解决问题,我的处理方式:</p>
<p>配置分为:</p>
<p>全局配置: 所有服务的总体配置</p>
<p>单服务配置: 本服务的配置, 涉及网络及逻辑</p>
<p>本地配置: 这个配置每个人一份, 不上传SVN</p>
<p>命令行配置: 格式和前面的一致, 这块就可以通过运维进行配置</p>
<p>总体结构其实就是OO的派生概念, 下层可以覆盖, 修改上层的配置</p>
<p>&nbsp;</p>
<p><strong>服务器互联及识别框架</strong></p>
<p>基本功能: 基于一些简单的配置就可以将多台服务器, 同种类的不同服务器互相连接起来, 断线自动重连.</p>
<p>服务器连接后, 所有服务器可知晓并可自动按需连接</p>
<p>逻辑端也很方便的进行广播或者单独发送等</p>
<p>也就是说, 每个服务器的连接和接受端都是带识别名称或id的.</p>
<p>后面觉得这套东西实在是做的复杂, 多整出一台中心服务器来做. 但好歹框架稳定下来了, 也就好了.</p>
<p>&nbsp;</p>
<p><strong>基于lua的服务器web后台框架</strong></p>
<p>思想是很不错的,&nbsp; C++ 配合lua本身绝对是个失败</p>
<p>问题出在web处理,本身都是一个同步阻塞过程, 而这个后台框架是异步方式来做, 所以特别别扭</p>
<p>不过比起以前的本地GM系统, 这块的设计是伟大的进步</p>
<p>&nbsp;</p>
<p>现在正在设计基于golang的服务器框架, 基本框架已经完工, 等待编写逻辑后的实战测试</p>
<p>以上的很多思想在golang的服务器框架都有改进, 特别是golang本身做web也是优秀的, 外加martini这种牛X框架, 更是水到渠成</p>
<p>如果你对服务器框架设计有特别的认识, 或者想碰撞思想, 可以加博客群 309800774或者我的qq: 20998333讨论</p><img src ="http://www.cppblog.com/sunicdavy/aggbug/209225.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2014-12-18 16:39 <a href="http://www.cppblog.com/sunicdavy/archive/2014/12/18/209225.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>自定义TexturePacker插件导出自己的plist文件</title><link>http://www.cppblog.com/sunicdavy/archive/2014/02/06/205645.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Thu, 06 Feb 2014 07:23:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2014/02/06/205645.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/205645.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2014/02/06/205645.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/205645.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/205645.html</trackback:ping><description><![CDATA[<p>cocos2dx引擎使用plist文件, 一种特殊的xml格式作为其atlas纹理的描述文件. plist遵循苹果的xml中key-value的设计风格.对于OC来说是合适的, 但xml本身性能低下, 垃圾内容过多, 也让plist对于高性能游戏引擎不再适合. 因此, 研究TexturePacker的导出插件技术</p> <p>TexturePacker的自定义插件目录位于其安装目录的bin\exporters\下, 但有一些插件属于内建支持, 例如cocos2dx的plist格式, 因此无法找到对应插件</p> <p>本人参考shiva3d插件, 对应导出界面的DataFormat中的Shiva3D, 快速学会了如何导出</p> <p>官方文档位于<a title="http://www.codeandweb.com/texturepacker/documentation/#customization" href="http://www.codeandweb.com/texturepacker/documentation/#customization">http://www.codeandweb.com/texturepacker/documentation/#customization</a></p> <p>插件的基本格式及原理是:</p> <p>bin\exporters\下的某一目录下存在的一个名为exporter.xml文件作为插件的描述,例如:</p> <div class="csharpcode"><pre class="alt"><span class="kwrd">&lt;</span><span class="html">exporter</span> <span class="attr">version</span><span class="kwrd">="1.0"</span><span class="kwrd">&gt;</span></pre><pre>    <span class="rem">&lt;!-- identifier of the exporter --&gt;</span></pre><pre class="alt">    <span class="kwrd">&lt;</span><span class="html">name</span><span class="kwrd">&gt;</span>shiva3d<span class="kwrd">&lt;/</span><span class="html">name</span><span class="kwrd">&gt;</span></pre><pre>&nbsp;</pre><pre class="alt">    <span class="rem">&lt;!-- display name of the exporter for the combo box --&gt;</span></pre><pre>    <span class="kwrd">&lt;</span><span class="html">displayName</span><span class="kwrd">&gt;</span>Shiva3D<span class="kwrd">&lt;/</span><span class="html">displayName</span><span class="kwrd">&gt;</span></pre><pre class="alt">    </pre><pre>    <span class="rem">&lt;!-- description of the exporter --&gt;</span></pre><pre class="alt">    <span class="kwrd">&lt;</span><span class="html">description</span><span class="kwrd">&gt;</span>Exporter for Shiva3D.<span class="kwrd">&lt;/</span><span class="html">description</span><span class="kwrd">&gt;</span></pre><pre>&nbsp;</pre><pre class="alt">    <span class="rem">&lt;!-- exporter version --&gt;</span></pre><pre>    <span class="kwrd">&lt;</span><span class="html">version</span><span class="kwrd">&gt;</span>1.0<span class="kwrd">&lt;/</span><span class="html">version</span><span class="kwrd">&gt;</span></pre><pre class="alt">    </pre><pre>    <span class="rem">&lt;!-- currently only one file allowed - more to come with update --&gt;</span></pre><pre class="alt">    <span class="kwrd">&lt;</span><span class="html">files</span><span class="kwrd">&gt;</span></pre><pre>        <span class="kwrd">&lt;</span><span class="html">file</span><span class="kwrd">&gt;</span></pre><pre class="alt">            <span class="rem">&lt;!-- name of this file variable --&gt;</span></pre><pre>            <span class="kwrd">&lt;</span><span class="html">name</span><span class="kwrd">&gt;</span>xml<span class="kwrd">&lt;/</span><span class="html">name</span><span class="kwrd">&gt;</span></pre><pre class="alt">&nbsp;</pre><pre>            <span class="rem">&lt;!-- human readable name (for GUI) --&gt;</span></pre><pre class="alt">            <span class="kwrd">&lt;</span><span class="html">displayName</span><span class="kwrd">&gt;</span>XML<span class="kwrd">&lt;/</span><span class="html">displayName</span><span class="kwrd">&gt;</span></pre><pre>&nbsp;</pre><pre class="alt">            <span class="rem">&lt;!-- file extension for the file --&gt;</span></pre><pre>            <span class="kwrd">&lt;</span><span class="html">fileExtension</span><span class="kwrd">&gt;</span>xml<span class="kwrd">&lt;/</span><span class="html">fileExtension</span><span class="kwrd">&gt;</span></pre><pre class="alt">&nbsp;</pre><pre>            <span class="rem">&lt;!-- name of the template file --&gt;</span></pre><pre class="alt">            <span class="kwrd">&lt;</span><span class="html">template</span><span class="kwrd">&gt;</span>shiva.xml<span class="kwrd">&lt;/</span><span class="html">template</span><span class="kwrd">&gt;</span></pre><pre>        <span class="kwrd">&lt;/</span><span class="html">file</span><span class="kwrd">&gt;</span></pre><pre class="alt">    <span class="kwrd">&lt;/</span><span class="html">files</span><span class="kwrd">&gt;</span></pre><pre>&nbsp;</pre><pre class="alt">    <span class="rem">&lt;!-- target framework supports trimming --&gt;</span></pre><pre>    <span class="kwrd">&lt;</span><span class="html">supportsTrimming</span><span class="kwrd">&gt;</span>false<span class="kwrd">&lt;/</span><span class="html">supportsTrimming</span><span class="kwrd">&gt;</span></pre><pre class="alt">&nbsp;</pre><pre>    <span class="rem">&lt;!-- target framework supports rotated sprites --&gt;</span></pre><pre class="alt">    <span class="kwrd">&lt;</span><span class="html">supportsRotation</span><span class="kwrd">&gt;</span>true<span class="kwrd">&lt;/</span><span class="html">supportsRotation</span><span class="kwrd">&gt;</span></pre><pre>&nbsp;</pre><pre class="alt">    <span class="rem">&lt;!-- rotated sprites direction (cw/ccw) --&gt;</span></pre><pre>    <span class="kwrd">&lt;</span><span class="html">rotationDirection</span><span class="kwrd">&gt;</span>cw<span class="kwrd">&lt;/</span><span class="html">rotationDirection</span><span class="kwrd">&gt;</span></pre><pre class="alt">&nbsp;</pre><pre>    <span class="rem">&lt;!-- supports npot sizes --&gt;</span></pre><pre class="alt">    <span class="kwrd">&lt;</span><span class="html">supportsNPOT</span><span class="kwrd">&gt;</span>true<span class="kwrd">&lt;/</span><span class="html">supportsNPOT</span><span class="kwrd">&gt;</span></pre><pre>&nbsp;</pre><pre class="alt">    <span class="rem">&lt;!-- supports file name stripping (remove .png etc) --&gt;</span></pre><pre>    <span class="kwrd">&lt;</span><span class="html">supportsTrimSpriteNames</span><span class="kwrd">&gt;</span>yes<span class="kwrd">&lt;/</span><span class="html">supportsTrimSpriteNames</span><span class="kwrd">&gt;</span></pre><pre class="alt">&nbsp;</pre><pre>    <span class="rem">&lt;!-- supports texure subpath --&gt;</span></pre><pre class="alt">    <span class="kwrd">&lt;</span><span class="html">supportsTextureSubPath</span><span class="kwrd">&gt;</span>yes<span class="kwrd">&lt;/</span><span class="html">supportsTextureSubPath</span><span class="kwrd">&gt;</span></pre><pre>&nbsp;</pre><pre class="alt"><span class="kwrd">&lt;/</span><span class="html">exporter</span><span class="kwrd">&gt;</span></pre><pre>&nbsp;</pre><pre class="alt">&nbsp;</pre></div>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p>&nbsp;</p>
<p>在Template字段中, 描述同目录的导出文件格式模板. TexturePacker使用一种叫<a href="http://www.codeandweb.com/outbound/www-grantlee-org-apidox-for_themers-html/">Grantlee</a>的模板引擎,类似于Python使用的Django模板引擎, 文档参见:<a href="http://www.codeandweb.com/outbound/www-grantlee-org-apidox-for_themers-html/">Grantlee Documentation</a>. 简单的文本格式可以参考shiva.xml快速学会</p>
<p>这里我们使用protobuf的文本格式(极为类似json)导出plist, 下面是导出模板</p>
<p>&nbsp;</p>
<div class="csharpcode"><pre class="alt">{% for sprite in allSprites %}</pre><pre>Sprite {</pre><pre class="alt">    Name: "{{sprite.trimmedName}}"</pre><pre>    FrameX: {{sprite.frameRect.x}}</pre><pre class="alt">    FrameY: {{sprite.frameRect.y}}</pre><pre>    FrameWidth: {{sprite.frameRectWithoutRotation.width}}</pre><pre class="alt">    FrameHeight: {{sprite.frameRectWithoutRotation.height}}</pre><pre>    OffsetX: {{sprite.cornerOffset.x}}</pre><pre class="alt">    OffsetY: {{sprite.cornerOffset.y}}</pre><pre>    OriginalWidth: {{sprite.untrimmedSize.width}}</pre><pre class="alt">    OriginalHeight: {{sprite.untrimmedSize.height}}</pre><pre>    {% if sprite.rotated %}Rotated: true {% endif %}</pre><pre class="alt">}</pre><pre>{% endfor %}</pre></div>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p>导出的结果类似于:</p>
<div class="csharpcode"><pre class="alt">&nbsp;</pre><pre>Sprite {</pre><pre class="alt">    Name: <span class="str">"car01"</span></pre><pre>    FrameX: 100</pre><pre class="alt">    FrameY: 129</pre><pre>    FrameWidth: 76</pre><pre class="alt">    FrameHeight: 47</pre><pre>    OffsetX: 0</pre><pre class="alt">    OffsetY: 0</pre><pre>    OriginalWidth: 76</pre><pre class="alt">    OriginalHeight: 47</pre><pre>    Rotated: <span class="kwrd">true</span> </pre><pre class="alt">}</pre><pre>&nbsp;</pre><pre class="alt">Sprite {</pre><pre>    Name: <span class="str">"car02"</span></pre><pre class="alt">    FrameX: 100</pre><pre>    FrameY: 51</pre><pre class="alt">    FrameWidth: 76</pre><pre>    FrameHeight: 47</pre><pre class="alt">    OffsetX: 0</pre><pre>    OffsetY: 0</pre><pre class="alt">    OriginalWidth: 76</pre><pre>    OriginalHeight: 47</pre><pre class="alt">    Rotated: <span class="kwrd">true</span> </pre><pre>}</pre></div>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>


<p>...</p>
<p>导出插件还支持js扩展, 具体内容请继续参考官方文档, 但对于简单的文本格式, 这种方式已经足够了</p>
<p>对比plist后, 发现plist中的垃圾信息极为多, 而且作为spriteframe的name居然带有扩展名...&nbsp; 因此脱离plist,编写自己的导出插件才是王道!</p><img src ="http://www.cppblog.com/sunicdavy/aggbug/205645.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2014-02-06 15:23 <a href="http://www.cppblog.com/sunicdavy/archive/2014/02/06/205645.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用HG(Mercurial)做分布式代码管理的一些经验</title><link>http://www.cppblog.com/sunicdavy/archive/2013/10/25/203915.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Fri, 25 Oct 2013 14:51:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2013/10/25/203915.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/203915.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2013/10/25/203915.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/203915.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/203915.html</trackback:ping><description><![CDATA[<p>距离第一次使用HG已经由2,3年了。 从第一次将HG用于自己的项目， 用U盘同步代码. 到现在将HG应用于linux, 版本差异发布, 项目内部多人的分布式开发，已经感觉非常熟练。</p> <p>我们的项目的客户端和服务器均由C++开发，由于HG设计的理念是1个工程对应1个库， 因此我们的客户端和服务器是分开的两个HG代码库。这种思想和SVN管理的代码有很大不同。SVN时代的游戏工程大多是这样安排目录的：</p> <p>common &lt;-客户端和服务器共享的库</p> <p>client&lt;-客户端的代码</p> <p>server&lt;-服务器的代码</p> <p>通过SVN强大的权限控制给不同的前后端赋予权限，前后端程序将获得不同的目录组合。SVN下的这种工程组织方法能很好的解决单一语言跨工程的代码，协议共享问题。虽然现在各种Erlang，Java的服务器语言与as3,lua的不同客户端脚本语言混杂的时代已经无所谓这种老式设计思想。但是对于我们纯C++的手游来说，还是必须面对分布式代码管理工具下的代码跨库共享问题。</p> <p>我就这个问题与多年前被我推荐过HG的朋友讨论起来，他们也存在我们这个问题，但是他们的解决方法就是每个工程一个库。然后被我问到：“同步一次代码，一次次的打开不同的库（他们客户端+服务器一共6到7个HG代码库），进行同步， 完成后， 还要反向pull，不累啊？”， 朋友回答：“习惯就好”</p> <p>随后，我也翻查了git对多项目的支持。得到的答案也是跟HG一样的， 这类分布式代码管理工具本身的设计理念只有账号，而无权限， 本身就是基于开源代码精神设计的工具， 如果分了权限，岂不是违背开源精神（这是我想的<img class="wlEmoticon wlEmoticon-smile" style="border-top-style: none; border-left-style: none; border-bottom-style: none; border-right-style: none" alt="微笑" src="http://www.cppblog.com/images/cppblog_com/sunicdavy/Windows-Live-Writer/09a081eb5d4c_13A7F/wlEmoticon-smile_2.png">）。因此如果想管理多个项目代码， 要么多库，要么合库。</p><img src ="http://www.cppblog.com/sunicdavy/aggbug/203915.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2013-10-25 22:51 <a href="http://www.cppblog.com/sunicdavy/archive/2013/10/25/203915.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Google Protocolbuf 文本格式的解析</title><link>http://www.cppblog.com/sunicdavy/archive/2013/07/09/201643.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Tue, 09 Jul 2013 10:29:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2013/07/09/201643.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/201643.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2013/07/09/201643.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/201643.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/201643.html</trackback:ping><description><![CDATA[<p>protobuf就是为懒人而造的工具, 啥协议, 啥配置文件, 统统定义proto, 解析就ok, 非常方便</p> <p>&nbsp;</p> <p>文本格式的解析错误不能使用捕获错误来获取, 因此,我们需要使用自定义的错误收集器进行收集, 看代码:</p> <div class="csharpcode"><pre class="alt">#include &lt;google/protobuf/text_format.h&gt;</pre><pre>#include &lt;google/protobuf/io/zero_copy_stream_impl_lite.h&gt;</pre><pre class="alt">#include &lt;google/protobuf/io/tokenizer.h&gt;</pre><pre>&nbsp;</pre><pre class="alt"><span class="kwrd">class</span> PBTextErrorCollector : <span class="kwrd">public</span> google::protobuf::io::ErrorCollector</pre><pre>{</pre><pre class="alt"><span class="kwrd">public</span>:</pre><pre>    PBTextErrorCollector( <span class="kwrd">const</span> std::<span class="kwrd">string</span>&amp; FileName )</pre><pre class="alt">        : mFileName( FileName )</pre><pre>    {</pre><pre class="alt">&nbsp;</pre><pre>    }</pre><pre class="alt">&nbsp;</pre><pre>    <span class="kwrd">virtual</span> <span class="kwrd">void</span> AddError(<span class="kwrd">int</span> line, <span class="kwrd">int</span> column, <span class="kwrd">const</span> <span class="kwrd">string</span>&amp; message)</pre><pre class="alt">    {</pre><pre>        CCLog(<span class="str">"%s(%d:%d) %s "</span>, mFileName.c_str(), line, column, message.c_str() );</pre><pre class="alt">    }</pre><pre>&nbsp;</pre><pre class="alt">    <span class="kwrd">virtual</span> <span class="kwrd">void</span> AddWarning(<span class="kwrd">int</span> line, <span class="kwrd">int</span> column, <span class="kwrd">const</span> <span class="kwrd">string</span>&amp; message) </pre><pre>    {</pre><pre class="alt">        CCLog(<span class="str">"%s(%d:%d) %s "</span>, mFileName.c_str(), line, column, message.c_str() );</pre><pre>    }</pre><pre class="alt">&nbsp;</pre><pre><span class="kwrd">private</span>:</pre><pre class="alt">    std::<span class="kwrd">string</span> mFileName;</pre><pre>};</pre><pre class="alt">&nbsp;</pre></div>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p>解析代码</p>
<div class="csharpcode"><pre class="alt">google::protobuf::TextFormat::Parser P;        </pre><pre>    P.RecordErrorsTo( &amp;PEC );</pre><pre class="alt">    P.Parse( &amp;AIS, &amp;AF );</pre></div>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p>&nbsp;</p>
<p>另外: 文本格式的注释使用unix shell风格: 以#开头</p>
<p>下面是我的文本格式的配置文件</p>
<p>&nbsp;</p><pre class="csharpcode">AnchorPointX: 0.5
AnchorPointY: 0

SpriteScale: 2

ComponentName: <span class="str">"ActorActionManager"</span>
ComponentName: <span class="str">"ActorFrameEventDispatcher"</span>
<span class="rem">#ComponentName: "SoundFXController"</span>
ComponentName: <span class="str">"RoleDeltaMoveController"</span>
ComponentName: <span class="str">"RoleBehaviorDirector"</span>

InitAction: AA_Idle

Animations 
{
  AnimationName: <span class="str">"mai_idle"</span>
  AnimationInterval: 0.067
}
</pre>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style><img src ="http://www.cppblog.com/sunicdavy/aggbug/201643.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2013-07-09 18:29 <a href="http://www.cppblog.com/sunicdavy/archive/2013/07/09/201643.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转载]高效程序员的四十五个习惯</title><link>http://www.cppblog.com/sunicdavy/archive/2012/04/03/169958.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Tue, 03 Apr 2012 13:40:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2012/04/03/169958.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/169958.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2012/04/03/169958.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/169958.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/169958.html</trackback:ping><description><![CDATA[<p>用作团队编码标准很不错</p> <p><strong></strong>&nbsp;</p> <p><strong>态度篇<br></strong>1. 做实事<br>不要抱怨，发牢骚，指责他人，找出问题所在，想办法解决。对问题和错误，要勇于承担。<br>2. 欲速则不达<br>用小聪明、权宜之计解决问题，求快而不顾代码质量，会给项目留下要命的死角。<br>3. 对事不对人<br>就事论事，明智、真诚、虚心地讨论问题，提出创新方案。<br>4. 排除万难，奋勇前进<br>勇气往往是克服困难的唯一方法。<br><strong>学习篇<br></strong>5. 跟踪变化<br>新技术层出不穷并不可怕。坚持学习新技术，读书，读技术杂志，参加技术活动，与人交流。要多理解新词背后的所以然，把握技术大趋势，将新技术用于产品开发要谨慎。<br>6. 对团队投资<br>打造学习型团队，不断提高兄弟们的平均水平。<br>7. 懂得丢弃<br>老的套路和技术，该丢，就得丢。不要固步自封。<br>8. 打破砂锅问到底<br>不断追问，真正搞懂问题的本质。为什么？应该成为你的口头禅。<br>9. 把握开发节奏<br>控制好时间，养成好习惯，不要加班。</p> <p><strong>开发流程篇<br></strong>10. 让客户做决定<br>让用户在现场，倾听他们的声音，对业务最重要的决策应该让他们说了算。<br>11. 让设计指导而不是操纵开发<br>设计是前进的地图，它指引的是方向，而不是目的本身。设计的详略程度应该适当。<br>12. 合理地使用技术<br>根据需要而不是其他因素选择技术。对各种技术方案进行严格地追问，真诚面对各种问题。<br>13. 让应用随时都可以发布<br>通过善用持续集成和版本管理，你应该随时都能够编译、运行甚至部署应用。<br>14. 提早集成，频繁集成<br>集成有风险，要尽早尽量多地集成。<br>15. 提早实现自动化部署<br>16. 使用演示获得频繁反馈<br>17. 使用短迭代，增量发布<br>18. 固定价格就意味着背叛承诺<br>估算应该基于实际的工作不断变化。<br><strong>用户篇<br></strong>19. 守护天使<br>自动化单元测试是你的守护天使。<br>20. 先用它再实现它<br>测试驱动开发其实是一种设计工具。<br>21. 不同环境，就有不同问题<br>要重视多平台问题。<br>22. 自动验收测试<br>23. 度量真实的进度<br>在工作量估算上，不要自欺欺人。<br>24. 倾听用户的声音<br>每一声抱怨都隐藏着宝贵的真理。 <p><strong>编程篇<br></strong>25. 代码要清晰地表达意图 <p>代码是给人读的，不要耍小聪明。<br>26. 用代码沟通<br>注释的艺术。<br>27. 动态地进行取舍 <p>记住，没有最佳解决方案。各种目标不可能面面俱到，关注对用户重要的需求。<br>28. 增量式编程<br>写一点代码就构建、测试、重构、休息。让代码干净利落。<br>29. 尽量简单<br>宁简勿繁。如果没有充足的理由，就不要使用什么模式、原则和特别的技术。<br>30. 编写内聚的代码<br>类和组件应该足够小，任务单一。<br>31. 告知，不要询问<br>多用消息传递，少用函数调用。<br>32. 根据契约进行替换<br>委托往往优于继承。 <p><strong> 调试篇<br></strong>33. 记录问题解决日志<br>不要在同一地方摔倒两次。错误是最宝贵的财富。<br>34. 警告就是错误<br>忽视编译器的警告可能铸成大错。<br>35. 对问题各个击破<br>分而治之是计算机科学中最重要的思想之一。但是，要从设计和原型阶段就考虑各部分应该能够很好地分离。<br>36. 报告所有的异常<br>37. 提供有用的错误信息<br>稍微多花一点心思，出错的时候，将给你带来极大便利。 <p><strong>团队协作篇<br></strong>38. 定期安排会面时间<br>常开会，开短会。<br>39. 架构师必须写代码 <p>不写代码的架构师不是好架构师。好的设计都来自实际编程。编程可以带来深入的理解。<br>40. 实行代码集体所有制<br>让开发人员在系统不同区域中不同的模块和任务之间轮岗。<br>41. 成为指导者<br>教学相长。分享能提高团队的总体能力。<br>42. 让大家自己想办法 <p>指引方向，而不是直接提供解决方案。让每个人都有机会在干中学习。<br>43. 准备好后再共享代码<br>不要提交无法编译或者没有通过单元测试的代码！<br>44. 做代码复查<br>复查对提高代码质量、减少错误极为重要。<br>45. 及时通报进展与问题 <p>主动通报，不要让别人来问你。</p><img src ="http://www.cppblog.com/sunicdavy/aggbug/169958.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2012-04-03 21:40 <a href="http://www.cppblog.com/sunicdavy/archive/2012/04/03/169958.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转载]GameEngineArchitecture读书笔记(一)</title><link>http://www.cppblog.com/sunicdavy/archive/2011/04/10/143890.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Sun, 10 Apr 2011 13:41:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2011/04/10/143890.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/143890.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2011/04/10/143890.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/143890.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/143890.html</trackback:ping><description><![CDATA[<ul> <li>Game Team  <ul> <li>国外AI和Audio程序员所占的角色还是很重要的, 而国内AI都是服务器在做, Audio基本上没有人下多少工夫  <li>美术的话TA越来越重要, 3D游戏开发不缺少  <li>另外, 项目管理也很重要, 程序员没有那么多精力去关注这些事情</li></ul> <li>Game Engine  <ul> <li>引擎的三个特性: 数据驱动, 可复用, 可扩展  <li>流派  <ul> <li>第一人称  <ul> <li>写实效果, 对于技术要求最高. 真实渲染, 高帧率, 物理模拟, 动画和高智能AI, 多人游戏支持</li></ul> <li>第三人称  <ul> <li>卡通效果, 丰富的动作, 可交互场景</li></ul> <li>格斗游戏  <ul> <li>大量的动作, 打击判定, 角色渲染, 皮肤/布料/毛发渲染</li></ul> <li>竞速游戏  <li>即时战略  <ul> <li>地形支持. 复杂AI</li></ul> <li>多人在线  <ul> <li>服务器, 图形效果要求低</li></ul> <li>其他</li></ul> <li>中间件  <ul> <li>游戏开发越来越多的使用到中间件, 没有哪一个引擎能把所有的部分做到极致  <li>现在的引擎更像是一个容器, 各种第三方插件整合到一起  <li>就国内现状来说, 用商业引擎的一般会再买几个中间件, 不然功能不全; 用自研引擎的要么找开源的, 要么自己做  <li>典型的几个中间件:  <ul> <li>Lighting: Beast/Enlighten  <li>Physics: Havok/PhysX/Bullet  <li>Animation: Granny/Havok/Edge  <li>AI: Kynapse/Xaiment  <li>UI: Scaleform/Iggy  <li>Video: Bink  <li>Audio: fmod/XACT/Miles  <li>Network: RakNet</li></ul></li></ul> <li>Gameplay  <ul> <li>很多引擎是缺少这一层的, 可能OGRE的流行让大部分人觉得渲染引擎就是游戏引擎吧?  <li>除了渲染, 像对象系统, 事件系统, 脚本系统, AI等也是一个游戏引擎不可缺少的部分</li></ul> <li>Pipeline  <ul> <li>这才是一个引擎具有竞争力的地方, 因为它直接关系到一个游戏的开发效率  <li>对于一个引擎来说, 画面效果虽然重要, 但是pipeline比画面和效率更为重要  <li>游戏开发是个不断迭代的过程, 所以提高迭代的速度也意味着降低成本  <li>一个引擎, 不管什么都是围绕着"资源"来进行的</li></ul> <li>Tools  <ul> <li>版本管理  <ul> <li>最开始接触的是SVN. 当然, 不可否认这是开源免费的最佳代表, 用来管理代码还是不错的. 但是用它管理美术资源无疑是个效率很低的选择  <li>Git/Hg, 相比SVN我觉得更好用一些, TortoiseGit是我现在的首选. TortoiseHg用了一段时间, 跟TortoiseSVN的操作习惯差别太大, 而且界面还是python的, 不太习惯  <li>Perforce, 商业解决方案. 效率的确高(特别是美术二进制资源), 插件(VS/Max/Maya/PS)也不错. 从SVN转过来后老是对它某些细节有点不爽, 因为它不会主动对比文件差异, 这也是它为什么速度快的原因-_-</li></ul> <li>Profiling  <ul> <li>VTune/CodyAnalyst是两上程序用的工具. 最近发现VS2010自代的也相当好用, 不做汇编级的分析的话完全够用了  <li>PerfHUD/PIX/GPA: NV现在感觉对PerfHUD支持的少了. PIX如果程序写法不标准会分析不了. GPA现在是越来越好用了, 要是把PIX的一些功能也吸收过去就更好了</li></ul></li></ul></li></ul></li></ul> <p>转载自: 逍遥自在的CSDN博客 <a href="http://blog.csdn.net/xoyojank/archive/2011/04/10/6313422.aspx">http://blog.csdn.net/xoyojank/archive/2011/04/10/6313422.aspx</a></p><img src ="http://www.cppblog.com/sunicdavy/aggbug/143890.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2011-04-10 21:41 <a href="http://www.cppblog.com/sunicdavy/archive/2011/04/10/143890.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC的RTTI系统性能测试</title><link>http://www.cppblog.com/sunicdavy/archive/2010/10/22/130893.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Fri, 22 Oct 2010 08:00:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2010/10/22/130893.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/130893.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2010/10/22/130893.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/130893.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/130893.html</trackback:ping><description><![CDATA[<p>测试环境：Visual Studio 2008 SP1</p> <p>测试对象：RTTI的dynamic_cast和自己实现的RTTI系统，代码如下</p> <div class="csharpcode"><pre class="alt">        template&lt;typename TClass&gt;</pre><pre>        TClass* Cast( )</pre><pre class="alt">        {</pre><pre>            <span class="kwrd">return</span> IsKindOf( TClass::StaticGetClassInfo() ) ? (TClass*)<span class="kwrd">this</span>:<span class="kwrd">null</span>;</pre><pre class="alt">        }</pre></div>
<p>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>
</p>
<p>&nbsp;</p>
<div class="csharpcode"><pre class="alt">    <span class="kwrd">bool</span> RTTIObject::IsKindOf( RTTIClass* ClassInfo )</pre><pre>    {</pre><pre class="alt">        RTTIClass* ThisClass = GetRTTIClass();</pre><pre>&nbsp;</pre><pre class="alt">        <span class="kwrd">if</span> ( ThisClass == <span class="kwrd">null</span> )</pre><pre>            <span class="kwrd">return</span> <span class="kwrd">false</span>;</pre><pre class="alt">        </pre><pre>        <span class="kwrd">return</span> ThisClass-&gt;IsKindOf( ClassInfo );</pre><pre class="alt">    }</pre></div>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p>&nbsp;</p>
<div class="csharpcode"><pre class="alt">    <span class="kwrd">bool</span> RTTIClass::IsKindOf( RTTIClass* ClassInfo )</pre><pre>    {</pre><pre class="alt">        RTTIClass* ThisClass = <span class="kwrd">this</span>;</pre><pre>        <span class="kwrd">while</span> ( ThisClass != <span class="kwrd">null</span> )</pre><pre class="alt">        {</pre><pre>            <span class="kwrd">if</span> ( ClassInfo == ThisClass )</pre><pre class="alt">                <span class="kwrd">return</span> <span class="kwrd">true</span>;</pre><pre>&nbsp;</pre><pre class="alt">            ThisClass = ThisClass-&gt;mParentClass;</pre><pre>        }</pre><pre class="alt">&nbsp;</pre><pre>        <span class="kwrd">return</span> <span class="kwrd">false</span>;</pre><pre class="alt">    }</pre></div>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p>&nbsp;</p>
<p>测试代码：</p>
<div class="csharpcode"><pre class="alt"><span class="kwrd">class</span> ClassA : <span class="kwrd">public</span> RTTIObject</pre><pre>{</pre><pre class="alt"><span class="kwrd">public</span>:</pre><pre>DECLARE_RTTI_CLASS( ClassA )</pre><pre class="alt"><span class="kwrd">int</span> a;</pre><pre><span class="kwrd">private</span>:</pre><pre class="alt">};</pre><pre>IMPLEMENT_RTTIROOT( ClassA )</pre><pre class="alt">&nbsp;</pre><pre><span class="kwrd">class</span> ClassB: <span class="kwrd">public</span> ClassA</pre><pre class="alt">{</pre><pre>    DECLARE_RTTI_CLASS( ClassB )</pre><pre class="alt"><span class="kwrd">public</span>:</pre><pre><span class="kwrd">int</span> b;</pre><pre class="alt"><span class="kwrd">private</span>:</pre><pre>};</pre><pre class="alt">IMPLEMENT_RTTI_CLASS( ClassB, ClassA )</pre><pre>&nbsp;</pre><pre class="alt"><span class="kwrd">class</span> ClassC : <span class="kwrd">public</span> ClassB</pre><pre>{</pre><pre class="alt">    DECLARE_RTTI_CLASS( ClassC )</pre><pre><span class="kwrd">public</span>:</pre><pre class="alt"><span class="kwrd">int</span> c;</pre><pre><span class="kwrd">private</span>:</pre><pre class="alt">};</pre><pre>IMPLEMENT_RTTI_CLASS( ClassC, ClassB )</pre><pre class="alt">&nbsp;</pre><pre><span class="kwrd">class</span> ClassD: <span class="kwrd">public</span> ClassA</pre><pre class="alt">{</pre><pre>    DECLARE_RTTI_CLASS( ClassD )</pre><pre class="alt"><span class="kwrd">public</span>:</pre><pre><span class="kwrd">int</span> d;</pre><pre class="alt"><span class="kwrd">private</span>:</pre><pre>};</pre></div>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p></p>
<div class="csharpcode"><pre class="alt">    ClassC c;</pre><pre>    ClassD d;</pre><pre class="alt">    </pre><pre>    ClassA* fakeC = &amp;c;</pre><pre class="alt">    ClassA* fakeD = &amp;d;</pre><pre>&nbsp;</pre><pre class="alt">    <span class="kwrd">const</span> <span class="kwrd">int</span> TestTimes = 10000;</pre><pre>&nbsp;</pre><pre class="alt">    <span class="kwrd">float</span> t1 = TimeSource::GetAppTime();</pre><pre>&nbsp;</pre><pre class="alt">    <span class="kwrd">for</span> ( <span class="kwrd">int</span> i = 0;i&lt;TestTimes;i++)</pre><pre>    {</pre><pre class="alt">        ClassC* realC = dynamic_cast&lt;ClassC*&gt;(fakeC);</pre><pre>        ClassD* realD = dynamic_cast&lt;ClassD*&gt;(fakeD);</pre><pre class="alt">    }</pre><pre>&nbsp;</pre><pre class="alt">    <span class="kwrd">float</span> t2 = TimeSource::GetAppTime() - t1;</pre><pre>&nbsp;</pre><pre class="alt">    <span class="kwrd">for</span> ( <span class="kwrd">int</span> i = 0;i&lt;TestTimes;i++)</pre><pre>    {</pre><pre class="alt">        ClassC* realC = fakeC-&gt;Cast&lt;ClassC&gt;( );</pre><pre>        ClassD* realD = fakeD-&gt;Cast&lt;ClassD&gt;( );</pre><pre class="alt">    }</pre><pre>&nbsp;</pre><pre class="alt">    <span class="kwrd">float</span> t3 = TimeSource::GetAppTime() - t2;</pre><pre>&nbsp;</pre><pre class="alt">    SimpleLog log;</pre><pre>    log.Debug(L<span class="str">"%f  %f"</span>, t2, t3);</pre></div>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p>&nbsp;</p>
<table border="1" cellspacing="0" cellpadding="2" width="400">
<tbody>
<tr>
<td valign="top" width="133"> 10000次，单位:毫秒</td>
<td valign="top" width="133">&nbsp; dynamic_cast</td>
<td valign="top" width="133">&nbsp;&nbsp;&nbsp; Cast</td></tr>
<tr>
<td valign="top" width="133">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Debug</td>
<td valign="top" width="133">1.468590</td>
<td valign="top" width="133">5.173067</td></tr>
<tr>
<td valign="top" width="133">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Release</td>
<td valign="top" width="133">1.025950</td>
<td valign="top" width="133">0.702404</td></tr></tbody></table>
<p>&nbsp;</p>
<p>可以看得出来，没有优化过的Cast代码性能极差，但是优化过的Cast性能超越了系统的dynamic_cast,跟踪汇编发现系统有做个一些异常及bad_cast的处理</p>
<p>建议：可以做一个宏，在不支持RTTI的编译器及平台下使用自己的Cast</p><img src ="http://www.cppblog.com/sunicdavy/aggbug/130893.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2010-10-22 16:00 <a href="http://www.cppblog.com/sunicdavy/archive/2010/10/22/130893.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在VC调试器中显示CEGUI 字符串</title><link>http://www.cppblog.com/sunicdavy/archive/2010/05/14/115356.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Fri, 14 May 2010 04:01:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2010/05/14/115356.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/115356.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2010/05/14/115356.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/115356.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/115356.html</trackback:ping><description><![CDATA[<p>CEGUI的字符串类设计的初衷是以32个字符为分界点, 低于32个字符使用固定buffer, 高于才使用栈分配内存存储字符串. 不过因为CEGUI使用utf32,兼容性虽然很好,但是在VC调试器里无法显示是个很大的问题.</p> <p>这里参考了mybios博客中的<a href="http://www.cppblog.com/mybios/archive/2009/11/10/28914.html">文章</a>,给CEGUI字符串做一个patch</p> <p>然后需要找到vs2008的autoexp.dat文件</p> <p>XP下位于:C:\Program Files\Microsoft Visual Studio 9.0\Common7\Packages\Debugger\autoexp.dat</p> <p>用记事本等工具打开, 在AutoExpand段中像这样添加:</p> <p>[AutoExpand]<br>; CEGUI String<br>CEGUI::String = str =&lt;d_quickbuff,su&gt; length =&lt;d_cplength&gt; <p>即可在VC调试器中看到CEGUI字符串内容, 不过中文还是暂时无法支持</p><img src ="http://www.cppblog.com/sunicdavy/aggbug/115356.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2010-05-14 12:01 <a href="http://www.cppblog.com/sunicdavy/archive/2010/05/14/115356.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>增强骨骼动画系统的几个要点</title><link>http://www.cppblog.com/sunicdavy/archive/2010/05/11/115080.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Tue, 11 May 2010 02:21:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2010/05/11/115080.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/115080.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2010/05/11/115080.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/115080.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/115080.html</trackback:ping><description><![CDATA[<p>要在游戏中用到强大而有扩展性的骨骼动画,有很多注意点.</p> <p>首先,我们得弃用CPU蒙皮, 虽然兼容性好,但是面对现今多核但并不提高单核速率的情况下,GPU还是王道.而且GPU蒙皮代码可能更简单,不过也有一点小缺点, 对于小引擎来说,Shader必须给静态模型和骨骼动画模型写两套.</p> <p>其次我们需要加强一个SubSkin的骨骼支持数量. 骨骼动画上的每个SubSkin都是一次Draw, 但是按照传统骨骼动画系统,每个骨头对应一个矩阵传入,那么SM2.0保守计算只能支持50根骨头. 不过在我前段时间的<a href="http://www.cppblog.com/sunicdavy/archive/2010/04/26/113578.html">文章</a>中有提到这个技术.并且已经在我的骨骼动画系统及OGRE中实现,效果很好.</p> <p>美术也许很反感一个人物做1个SubSkin, 他们更新好多个SubSkin,也就是说身体每个部分都是一个SubSkin, 这样方便修改, 同时系统支持的骨骼数量还可以有一定量的上升.不过我们还需要做一个索引工作. 传统的GPU骨骼动画中总是在渲染SubSkin前传入所有这些SubSkin需要用到的骨骼矩阵. 但是每个SubSkin并不一定能用到所有的这些矩阵,这明显是一种浪费. 因此在OGRE中做过一次索引预处理,也就是将每个SubSkin用到的骨骼统计出来, 在渲染这次SubSkin时才重新传到GPU. 很明显,这是用速度还空间和兼容性. 如果在DX10以上,有ConstantBuffer还好. DX9实在太慢了</p> <p>使用Marker点的换装系统很难处理例如贴身衣物这类物件换装. OGRE中有一种共享骨骼的技术, 可以支持, 不过从代码分析看来,这种技术对CPU端骨骼计算量实在是大的惊人. 因此我们决定将整个SubSkin(也就是SubEntity)换掉,这样由美术根据不同换装类型来将衣服在MAX中直接绑定好后直接替换原始模型中的SubSkin即可达到换装效果.可以说这是从动态计算到静态预处理的转变,效率提升很多.</p><img src ="http://www.cppblog.com/sunicdavy/aggbug/115080.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2010-05-11 10:21 <a href="http://www.cppblog.com/sunicdavy/archive/2010/05/11/115080.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转载|推荐] 非常棒的ARPG引擎LingEngine</title><link>http://www.cppblog.com/sunicdavy/archive/2010/05/07/114724.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Fri, 07 May 2010 02:12:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2010/05/07/114724.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/114724.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2010/05/07/114724.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/114724.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/114724.html</trackback:ping><description><![CDATA[<p>在逛<a href="http://www.opengpu.org/index.php">http://www.opengpu.org/index.php</a> 时发现一个优秀的ARPG客户端引擎<a href="http://blog.csdn.net/Nightmare/archive/2010/04/04/5449634.aspx">LingEngine</a></p> <p>各位可以<a href="http://cid-2be543ad601c493f.skydrive.live.com/self.aspx/.Public/LingEngine0.69.7z">下载</a>看下</p> <p>&nbsp;</p> <p><a href="http://www.cppblog.com/images/cppblog_com/sunicdavy/WindowsLiveWriter/ARPGLingEngine_8F5B/image_2.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/sunicdavy/WindowsLiveWriter/ARPGLingEngine_8F5B/image_thumb.png" width="966" height="632"></a> </p> <p>从直观个人分析该引擎技术包括:</p> <p>1. 基于<a href="http://code.google.com/p/slimdx/">SlimDX</a>的.NET引擎</p> <p>2. JavaScript脚本</p> <p>3. 场景剔除效率还不错</p> <p>4. 手感非常棒, 不亚于WOW</p> <p>&nbsp;</p> <p>他<a href="http://blog.csdn.net/Nightmare/archive/2010/04/04/5449634.aspx">博客</a>里还有几篇关于保留模式引擎的讨论. 个人觉得这大概是以后的趋势. 微软的WPF首先当了炮灰, 庆幸.</p><img src ="http://www.cppblog.com/sunicdavy/aggbug/114724.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2010-05-07 10:12 <a href="http://www.cppblog.com/sunicdavy/archive/2010/05/07/114724.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[原创]提高Shader Model 2.0 蒙皮骨骼动画的骨骼限制</title><link>http://www.cppblog.com/sunicdavy/archive/2010/04/26/113578.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Mon, 26 Apr 2010 05:31:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2010/04/26/113578.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/113578.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2010/04/26/113578.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/113578.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/113578.html</trackback:ping><description><![CDATA[<p>传统的蒙皮骨骼动画混合方法易于理解,但是在SM 2.0的256常量限制下,骨骼数保守计算最多50根骨头,因此对美术的工作流程以及模型渲染方法造成了很大的障碍</p> <div class="csharpcode"><pre class="alt">float4x4 matBoneArray[40]; <span class="rem">//  这是传输的瓶颈</span></pre><pre>&nbsp;</pre><pre class="alt">VS_OUTPUT vs_main( SkinnedVS_INPUT In )</pre><pre>{</pre><pre class="alt">&nbsp;</pre><pre>    VS_OUTPUT Out = (VS_OUTPUT)0;</pre><pre class="alt">&nbsp;</pre><pre>    float4x4 skinTransform = 0;</pre><pre class="alt">&nbsp;</pre><pre>    skinTransform += matBoneArray[In.BoneIndices.x] * In.BoneWeights.x;</pre><pre class="alt">    skinTransform += matBoneArray[In.BoneIndices.y] * In.BoneWeights.y;</pre><pre>    skinTransform += matBoneArray[In.BoneIndices.z] * In.BoneWeights.z;</pre><pre class="alt">    skinTransform += matBoneArray[In.BoneIndices.w] * In.BoneWeights.w;</pre><pre>    float4 localpos = mul(In.Position, skinTransform);</pre><pre class="alt">    </pre><pre>    Out.Position = mul( localpos, matViewProj ); </pre><pre class="alt">    Out.TexCoord = In.TexCoord;</pre><pre>  </pre><pre class="alt">    <span class="kwrd">return</span> Out;</pre><pre>}</pre></div>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p>matBoneArray这个数组是骨骼的LocalRot和LocalTranslation 通过以下函数build出来</p>
<div class="csharpcode"><pre class="alt">    Matrix4&amp; Matrix4::FromTranslationRotation( <span class="kwrd">const</span> Vector3&amp; translation, <span class="kwrd">const</span> Quaternion&amp; rotation )</pre><pre>    {</pre><pre class="alt">        <span class="kwrd">float</span> xx = rotation.x * rotation.x * 2.0f, yy = rotation.y * rotation.y * 2.0f, zz = rotation.z * rotation.z * 2.0f;</pre><pre>        <span class="kwrd">float</span> xy = rotation.x * rotation.y * 2.0f, zw = rotation.z * rotation.w * 2.0f, xz = rotation.x * rotation.z * 2.0f;</pre><pre class="alt">        <span class="kwrd">float</span> yw = rotation.y * rotation.w * 2.0f, yz = rotation.y * rotation.z * 2.0f, xw = rotation.x * rotation.w * 2.0f;</pre><pre>&nbsp;</pre><pre class="alt">        m[0][0] = 1.0f - yy - zz; m[0][1] =        xy + zw; m[0][2] =        xz - yw; m[0][3] = 0.0f;</pre><pre>        m[1][0] =        xy - zw; m[1][1] = 1.0f - xx - zz; m[1][2] =        yz + xw; m[1][3] = 0.0f;</pre><pre class="alt">        m[2][0] =        xz + yw; m[2][1] =        yz - xw; m[2][2] = 1.0f - xx - yy; m[2][3] = 0.0f;</pre><pre>        m[3][0] =  translation.x; m[3][1] =  translation.y; m[3][2] =  translation.z; m[3][3] = 1.0f;</pre><pre class="alt">&nbsp;</pre><pre>        <span class="kwrd">return</span> *<span class="kwrd">this</span>;</pre><pre class="alt">    }</pre></div>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p></p>
<p>从这里你可以发现, 本来每根骨头只需要2个float4 传递变换信息的,现在却需要4个float4,也就是一个矩阵来传递,矩阵中还有很多不使用的变量也被传输到GPU中,这里就是优化的点.</p>
<p>重新调整后的Shader代码:</p>
<div class="csharpcode"><pre class="alt">float4x4 BuildFromTransRot( float4 translation, float4 rot )</pre><pre>{</pre><pre class="alt">    float4 rotation = rot;</pre><pre>    </pre><pre class="alt">    <span class="kwrd">float</span> xx = rotation.x * rotation.x * 2.0f, yy = rotation.y * rotation.y * 2.0f, zz = rotation.z * rotation.z * 2.0f;</pre><pre>    <span class="kwrd">float</span> xy = rotation.x * rotation.y * 2.0f, zw = rotation.z * rotation.w * 2.0f, xz = rotation.x * rotation.z * 2.0f;</pre><pre class="alt">    <span class="kwrd">float</span> yw = rotation.y * rotation.w * 2.0f, yz = rotation.y * rotation.z * 2.0f, xw = rotation.x * rotation.w * 2.0f;</pre><pre>    float4x4 m = { </pre><pre class="alt">    {1.0f - yy - zz,             xy + zw,             xz - yw,         0},</pre><pre>    {xy - zw,              1.0f - xx - zz,             yz + xw,         0},</pre><pre class="alt">    {xz + yw,                      yz - xw,     1.0f - xx - yy,         0},</pre><pre>    {translation.x,       translation.y,       translation.z,         1}</pre><pre class="alt">    </pre><pre>    };</pre><pre class="alt">    </pre><pre>    <span class="kwrd">return</span> m;</pre><pre class="alt">}</pre><pre>&nbsp;</pre><pre class="alt">float4x4 GetBoneElement( <span class="kwrd">float</span> index )</pre><pre>{</pre><pre class="alt">    <span class="kwrd">return</span> BuildFromTransRot( vecBoneLocalTrans[index], vecBoneLocalRot[index] );</pre><pre>}</pre></div>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p></p>
<div class="csharpcode"><pre class="alt">VS_OUTPUT vs_main( SkinnedVS_INPUT In )</pre><pre>{</pre><pre class="alt">&nbsp;</pre><pre>    VS_OUTPUT Out = (VS_OUTPUT)0;</pre><pre class="alt">&nbsp;</pre><pre>    float4x4 skinTransform = 0;</pre><pre class="alt">&nbsp;</pre><pre>    skinTransform += GetBoneElement(In.BoneIndices.x) * In.BoneWeights.x;</pre><pre class="alt">    skinTransform += GetBoneElement(In.BoneIndices.y) * In.BoneWeights.y;</pre><pre>    skinTransform += GetBoneElement(In.BoneIndices.z) * In.BoneWeights.z;</pre><pre class="alt">    skinTransform += GetBoneElement(In.BoneIndices.w) * In.BoneWeights.w;</pre><pre>    float4 localpos = mul(In.Position, skinTransform);</pre><pre class="alt">    </pre><pre>    Out.Position = mul( localpos, matViewProj ); </pre><pre class="alt">    Out.TexCoord = In.TexCoord;</pre><pre>  </pre><pre class="alt">    <span class="kwrd">return</span> Out;</pre><pre>}</pre></div>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p>我们将骨头的local旋转及偏移传递至GPU,然后在GPU内重组,虽然对GPU性能计算有部分损耗,但是骨骼数量就能保守提高到100个.</p><img src ="http://www.cppblog.com/sunicdavy/aggbug/113578.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2010-04-26 13:31 <a href="http://www.cppblog.com/sunicdavy/archive/2010/04/26/113578.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>游戏工程里的使用C++静态库与动态库</title><link>http://www.cppblog.com/sunicdavy/archive/2010/04/07/111859.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Wed, 07 Apr 2010 08:08:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2010/04/07/111859.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/111859.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2010/04/07/111859.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/111859.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/111859.html</trackback:ping><description><![CDATA[<p>假设我们有3个工程及其工程类型：</p> <p>CORE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DLL</p> <p>ENGINE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DLL</p> <p>GAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EXE</p> <p>D3DRENDER&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DLL</p> <p>其中D3DRENDER是GAME动态载入的，其需要链接CORE,ENGINE</p> <p>这是一个很常见的模式，但是不好的是，因为CORE和ENGINE均是DLL，代码中的Symbol都被导出才可使用。任何人使用DEPENDENCE工具就可以将DLL中引用的东西查看的清楚，虽然这不至于造成技术泄漏，但从速度和DLL大小来说都是不划算的。</p> <p>现在很多游戏主exe一般都是10M+甚至20M+的大exe，这都是使用静态链接而成。但是对代码结构也必须做出一定的调整。所有工程必须都是静态库，这样才能保证像CORE这样的静态库中的全局/静态变量不至于被链接2份而造成内存段逻辑错误。</p> <p>当然，使用全静态库还需要注意一点：所有的lib都是在最后的game工程里来做链接。</p><img src ="http://www.cppblog.com/sunicdavy/aggbug/111859.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2010-04-07 16:08 <a href="http://www.cppblog.com/sunicdavy/archive/2010/04/07/111859.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]虚幻引擎UDK开发官方视频教程</title><link>http://www.cppblog.com/sunicdavy/archive/2010/04/07/111833.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Wed, 07 Apr 2010 02:36:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2010/04/07/111833.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/111833.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2010/04/07/111833.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/111833.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/111833.html</trackback:ping><description><![CDATA[<p>转载自 <a href="http://forum.indiegame.cn/viewthread.php?tid=69&amp;from=recommend_f">独立游戏中文论坛</a> <p>UDK是unrealengine develpoment kit 的缩写，简单来说就是大名鼎鼎的虚幻３引擎的免费商业版本．不过虚幻３毕竟还是４年前的dx9的入门级引擎，在商业上取得<br>巨大成功，技术上也显得落后．目前Epic想榨干虚幻３的最后一点潜力，于是干脆发布了这个免费版本．任何人都可以用ＵＤＫ开发游戏，但是如果游戏牟利的话每年还是要向<br>Epic交纳一定数量的技术授权费用的．先不管这个，还是来看看它的官方视频教程吧．<br>　　[attach]44[/attach]<br>链接如下：　　<br><a href="http://udn.epicgames.com/Three/VideoTutorials.html">http://udn.epicgames.com/Three/VideoTutorials.html</a><br>一共５个教程　从引擎配置介绍开始，到关卡和人物编辑器，以及最后一个完整的小游戏的制作，对于入门来说完全足够了．<br>视频说的还比较详细，听力不好的同学可以对照下开发文档　<a href="http://www.udk.com/documentation">http://www.udk.com/documentation</a>　里面基本说的很详细．<br>最后附上ＵＤＫ的下载地址：　<a href="http://www.udk.com/udkdownload">March 2010 UDK Beta</a> (548 MB .exe)　<br>好了，ＵＤＫ对于初学者来说还是比较适合的．对于游戏的开发人员来说引擎的整体架构还是很值得学习的．希望你学的愉快．</p><img src ="http://www.cppblog.com/sunicdavy/aggbug/111833.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2010-04-07 10:36 <a href="http://www.cppblog.com/sunicdavy/archive/2010/04/07/111833.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>模拟OGRE的Compositor</title><link>http://www.cppblog.com/sunicdavy/archive/2010/04/01/111312.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Thu, 01 Apr 2010 10:56:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2010/04/01/111312.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/111312.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2010/04/01/111312.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/111312.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/111312.html</trackback:ping><description><![CDATA[<p>RenderTarget完成后，开始模拟OGRE的Compositor。</p> <p>OGRE的Compositor其实就是用于解决绘制PostEffect的，简单的说，就是一种RenderTarget的流程控制脚本</p> <p>这是OGRE compositor文件的片段</p> <div class="csharpcode"><pre class="alt">compositor Bloom</pre><pre>{</pre><pre class="alt">    technique</pre><pre>    {</pre><pre class="alt">        <span class="rem">// Temporary textures</span></pre><pre>        texture rt_output target_width target_height PF_R8G8B8</pre><pre class="alt">        texture rt0 target_width_scaled 0.25 target_height_scaled 0.25 PF_R8G8B8</pre><pre>        texture rt1 target_width_scaled 0.25 target_height_scaled 0.25 PF_R8G8B8</pre><pre class="alt">&nbsp;</pre><pre>        target rt_output</pre><pre class="alt">        {</pre><pre>            <span class="rem">// Render output from previous compositor (or original scene)</span></pre><pre class="alt">            input previous</pre><pre>        }</pre><pre class="alt">&nbsp;</pre><pre>        target rt0</pre><pre class="alt">        {</pre><pre>            <span class="rem">// Start with clear texture</span></pre><pre class="alt">            input none</pre><pre>            <span class="rem">// Horizontal blur pass</span></pre><pre class="alt">            pass render_quad</pre><pre>            {</pre><pre class="alt">                <span class="rem">// Renders a fullscreen quad with a material</span></pre><pre>                material Ogre/Compositor/BrightPass2</pre><pre class="alt">                input 0 rt_output</pre><pre>            }</pre><pre class="alt">        }</pre><pre>&nbsp;</pre><pre class="alt">        target rt1</pre><pre>        {</pre><pre class="alt">            <span class="rem">// Start with clear texture</span></pre><pre>            input none</pre><pre class="alt">            <span class="rem">// Horizontal blur pass</span></pre><pre>            pass render_quad</pre><pre class="alt">            {</pre><pre>                <span class="rem">// Renders a fullscreen quad with a material</span></pre><pre class="alt">                material Ogre/Compositor/BlurV</pre><pre>                input 0 rt0</pre><pre class="alt">            }</pre><pre>        }</pre><pre class="alt">&nbsp;</pre><pre>        target rt0</pre><pre class="alt">        {</pre><pre>            <span class="rem">// Start with clear texture</span></pre><pre class="alt">            input none</pre><pre>            <span class="rem">// Horizontal blur pass</span></pre><pre class="alt">            pass render_quad</pre><pre>            {</pre><pre class="alt">                <span class="rem">// Renders a fullscreen quad with a material</span></pre><pre>                material Ogre/Compositor/BlurH</pre><pre class="alt">                input 0 rt1</pre><pre>            }</pre><pre class="alt">        }</pre><pre>&nbsp;</pre><pre class="alt">        target_output</pre><pre>        {</pre><pre class="alt">            <span class="rem">// Start with clear output</span></pre><pre>            input none</pre><pre class="alt">            <span class="rem">// Draw a fullscreen quad</span></pre><pre>            pass render_quad</pre><pre class="alt">            {</pre><pre>                <span class="rem">// Renders a fullscreen quad with a material</span></pre><pre class="alt">                material Ogre/Compositor/BloomBlend2</pre><pre>                input 0 rt_output</pre><pre class="alt">                input 1 rt0</pre><pre>            }</pre><pre class="alt">        }</pre><pre>    }</pre><pre class="alt">}</pre></div>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p>&nbsp;</p>
<p>大概我们知道，一个Compositor分为资源定义与绘制步骤（target xxx）</p>
<p>而一个绘制步骤又分别定义：</p>
<p>1. （输入）绘制的是什么东西？</p>
<p>2. （效果）绘制成什么样子？</p>
<p>3. （输出）往哪里绘制？</p>
<p>输出方式在这个例子有2种：纹理（RT）和屏幕</p>
<p>输入方式有2中：纹理及场景</p>
<p>我们可以使用一个回调来对一个绘制步骤提供绘制输入</p>
<p>绘制效果就是一大堆的Shader，这些shader都是基于一个quad来做的，也就是一个矩形，使用变换后的顶点和一个纹理坐标作为顶点定义</p>
<p>不过这里是不需要做vertexshader的，仅仅ps足矣。</p>
<p>绘制的最后，是将前面绘制的RT（纹理）混合起来</p>
<p>当然，如果步骤比较多和复杂时，RT之间跟寄存器一样，可以反复使用</p>
<p><a href="http://www.cppblog.com/images/cppblog_com/sunicdavy/WindowsLiveWriter/OGRECompositor_10A35/YR7HEX8VAB%5B67GPOWLNPIBA_2.jpg"><img title="YR7HEX8VAB[67GPOWLNPIBA" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="170" alt="YR7HEX8VAB[67GPOWLNPIBA" src="http://www.cppblog.com/images/cppblog_com/sunicdavy/WindowsLiveWriter/OGRECompositor_10A35/YR7HEX8VAB%5B67GPOWLNPIBA_thumb.jpg" width="244" border="0"></a></p>
<p>显示茶壶法线的场景加上 Blur 的PostEffect</p>
<div class="csharpcode"><pre class="alt"><span class="kwrd">&lt;?</span><span class="html">xml</span> <span class="attr">version</span><span class="kwrd">="1.0"</span> <span class="attr">encoding</span><span class="kwrd">="gb2312"</span> ?<span class="kwrd">&gt;</span></pre><pre><span class="kwrd">&lt;</span><span class="html">Compositor</span> <span class="attr">name</span> = <span class="kwrd">"bloom"</span> <span class="kwrd">&gt;</span></pre><pre class="alt">  <span class="kwrd">&lt;</span><span class="html">Resource</span><span class="kwrd">&gt;</span></pre><pre>    <span class="kwrd">&lt;</span><span class="html">RenderTarget</span> <span class="attr">name</span> <span class="kwrd">="rt_source"</span> <span class="attr">size</span><span class="kwrd">="screenquad"</span> <span class="kwrd">/&gt;</span></pre><pre class="alt">    <span class="kwrd">&lt;</span><span class="html">RenderTarget</span> <span class="attr">name</span> <span class="kwrd">="rt0"</span> <span class="attr">size</span><span class="kwrd">="screenquad"</span> <span class="kwrd">/&gt;</span></pre><pre>    <span class="kwrd">&lt;</span><span class="html">RenderTarget</span> <span class="attr">name</span> <span class="kwrd">="rt1"</span> <span class="attr">size</span><span class="kwrd">="screenquad"</span> <span class="kwrd">/&gt;</span></pre><pre class="alt">  <span class="kwrd">&lt;/</span><span class="html">Resource</span><span class="kwrd">&gt;</span></pre><pre>  <span class="kwrd">&lt;</span><span class="html">Step</span> <span class="attr">target</span><span class="kwrd">="rt_source"</span><span class="kwrd">&gt;</span></pre><pre class="alt">    <span class="kwrd">&lt;</span><span class="html">Geometry</span> <span class="attr">type</span> <span class="kwrd">="callback"</span> <span class="attr">callback</span> = <span class="kwrd">"rt_input"</span><span class="kwrd">/&gt;</span></pre><pre>  <span class="kwrd">&lt;/</span><span class="html">Step</span><span class="kwrd">&gt;</span></pre><pre class="alt">  <span class="kwrd">&lt;</span><span class="html">Step</span> <span class="attr">target</span><span class="kwrd">="rt0"</span><span class="kwrd">&gt;</span></pre><pre>    <span class="kwrd">&lt;</span><span class="html">Geometry</span> <span class="attr">type</span> = <span class="kwrd">"screenquad"</span><span class="kwrd">/&gt;</span></pre><pre class="alt">    <span class="kwrd">&lt;</span><span class="html">Effect</span> <span class="attr">name</span> <span class="kwrd">="material\blurH.xml"</span><span class="kwrd">&gt;</span></pre><pre>      <span class="kwrd">&lt;</span><span class="html">Texture</span> <span class="attr">name</span> <span class="kwrd">="mTexture"</span> <span class="attr">value</span> <span class="kwrd">="rt_source"</span> <span class="kwrd">/&gt;</span></pre><pre class="alt">    <span class="kwrd">&lt;/</span><span class="html">Effect</span><span class="kwrd">&gt;</span></pre><pre>  <span class="kwrd">&lt;/</span><span class="html">Step</span><span class="kwrd">&gt;</span></pre><pre class="alt">  <span class="kwrd">&lt;</span><span class="html">Step</span> <span class="attr">target</span><span class="kwrd">="rt1"</span><span class="kwrd">&gt;</span></pre><pre>    <span class="kwrd">&lt;</span><span class="html">Geometry</span> <span class="attr">type</span> = <span class="kwrd">"screenquad"</span><span class="kwrd">/&gt;</span></pre><pre class="alt">    <span class="kwrd">&lt;</span><span class="html">Effect</span> <span class="attr">name</span> <span class="kwrd">="material\blurV.xml"</span><span class="kwrd">&gt;</span></pre><pre>      <span class="kwrd">&lt;</span><span class="html">Texture</span> <span class="attr">name</span> <span class="kwrd">="mTexture"</span> <span class="attr">value</span> <span class="kwrd">="rt_source"</span> <span class="kwrd">/&gt;</span></pre><pre class="alt">    <span class="kwrd">&lt;/</span><span class="html">Effect</span><span class="kwrd">&gt;</span></pre><pre>  <span class="kwrd">&lt;/</span><span class="html">Step</span><span class="kwrd">&gt;</span></pre><pre class="alt">  <span class="kwrd">&lt;</span><span class="html">Step</span><span class="kwrd">&gt;</span></pre><pre>    <span class="kwrd">&lt;</span><span class="html">Geometry</span> <span class="attr">type</span> = <span class="kwrd">"screenquad"</span><span class="kwrd">/&gt;</span></pre><pre class="alt">    <span class="kwrd">&lt;</span><span class="html">Effect</span> <span class="attr">name</span> <span class="kwrd">="material\combine.xml"</span><span class="kwrd">&gt;</span></pre><pre>      <span class="kwrd">&lt;</span><span class="html">Texture</span> <span class="attr">name</span> <span class="kwrd">="mTexture1"</span> <span class="attr">value</span> <span class="kwrd">="rt0"</span> <span class="kwrd">/&gt;</span></pre><pre class="alt">      <span class="kwrd">&lt;</span><span class="html">Texture</span> <span class="attr">name</span> <span class="kwrd">="mTexture2"</span> <span class="attr">value</span> <span class="kwrd">="rt1"</span> <span class="kwrd">/&gt;</span></pre><pre>    <span class="kwrd">&lt;/</span><span class="html">Effect</span><span class="kwrd">&gt;</span></pre><pre class="alt">  <span class="kwrd">&lt;/</span><span class="html">Step</span><span class="kwrd">&gt;</span></pre><pre><span class="kwrd">&lt;/</span><span class="html">Compositor</span><span class="kwrd">&gt;</span></pre></div>这是我的引擎里的Compositor脚本，还在慢慢加强功能，希望能有一天达到OGRE的Compositor功能
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style><img src ="http://www.cppblog.com/sunicdavy/aggbug/111312.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2010-04-01 18:56 <a href="http://www.cppblog.com/sunicdavy/archive/2010/04/01/111312.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一套可扩充的游戏模型系统</title><link>http://www.cppblog.com/sunicdavy/archive/2010/03/12/109538.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Fri, 12 Mar 2010 08:13:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2010/03/12/109538.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/109538.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2010/03/12/109538.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/109538.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/109538.html</trackback:ping><description><![CDATA[<p>本人的设计图可以方便在文本编辑器里查看(&gt;为派生 +为包含)  <p>MAX插件导出的模型资源分：Mesh/Skin, Skeleton, Animation <p>不同动作按照不同的动画文件保存 <p>&nbsp; <p>ResourceHandle 包含基本id<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt;NamedResourceHandle 带有名称资源，包含hashA, hashB， 使用暴雪hash函数生成<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt;ModelHandle&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt;MeshHandle&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt;SkeletonHandle&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt;AnimationHandle  <p>获取资源，如果资源不存在时，自动加载<br>ModelMaster.ManualCache( &amp;ModelHandle )  <p>直接资源访问：<br>RawSkeleton = ModelMaster.ManualCache( &amp;SkeletonHandle("a.skl") )<br>RawSkeleton-&gt;GetMarker(...)  <p>异步资源加载，异步id保存于ModelHandle中，在callback中根据id确认<br>ModelMaster.AsyncCache( &amp;ModelHandle )  <p>获取资源指针，未加载时，返回空<br>ModelResource = ModelMaster.Fetch( &amp;ModelHandle )  <p>模型资源加载器<br>&nbsp;&nbsp;&nbsp; 在模型句柄中绑定对应加载器<br>&nbsp;&nbsp;&nbsp; 可以自行编写带换装的ModelLoader，通过读取自己的配置文件，自行加载资源后生成RawModel<br>ModelLoader<br>&nbsp;&nbsp;&nbsp; ModelHandle&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ---mapping---&gt;&nbsp;&nbsp;&nbsp; ModelLoader&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ---generate--&gt; RawModel<br>&nbsp;&nbsp;&nbsp; MeshHandle&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ---mapping---&gt;&nbsp;&nbsp;&nbsp; MeshLoader&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ---generate--&gt; RawMesh<br>&nbsp;&nbsp;&nbsp; SkeletonHandle&nbsp;&nbsp;&nbsp;&nbsp; ---mapping---&gt;&nbsp;&nbsp;&nbsp; SkeletonLoader&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ---generate--&gt; RawSkeleton<br>&nbsp;&nbsp;&nbsp; AnimationHandle&nbsp;&nbsp;&nbsp; ---mapping---&gt;&nbsp;&nbsp;&nbsp; AnimationLoader&nbsp;&nbsp; ---generate--&gt; RawAnimation  <p>引用计数类&nbsp;&nbsp;&nbsp; <br>ModelResource<br>&nbsp;&nbsp;&nbsp; &gt;RawModel<br>&nbsp;&nbsp;&nbsp; &gt;RawMesh<br>&nbsp;&nbsp;&nbsp; &gt;RawSkeleton<br>&nbsp;&nbsp;&nbsp; &gt;RawAnimation  <p>RawModel中不保留Handle，只保留指针<br>RawModel<br>&nbsp;&nbsp;&nbsp; +MeshVB&nbsp;&nbsp;&nbsp; 从模型文件中直接读取顶点格式，包含 静态,GPU,CPU类型顶点<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; +RawMesh<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; +MeshIB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一次性填充IB<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt;GPUMeshVB&nbsp;&nbsp;&nbsp; 一次性填充VB<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &gt;CPUMeshVB&nbsp;&nbsp;&nbsp; 每帧计算<br>&nbsp;&nbsp;&nbsp; +Animation&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 运行期数据（时间/帧）<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; +RawAnimation&nbsp;&nbsp;&nbsp; 原始动画内容<br>&nbsp;&nbsp;&nbsp; +Skeleton<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; +RawSkeleton</p><img src ="http://www.cppblog.com/sunicdavy/aggbug/109538.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2010-03-12 16:13 <a href="http://www.cppblog.com/sunicdavy/archive/2010/03/12/109538.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>枚举反射对象和结构体反射填充</title><link>http://www.cppblog.com/sunicdavy/archive/2010/02/26/108509.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Fri, 26 Feb 2010 09:58:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2010/02/26/108509.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/108509.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2010/02/26/108509.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/108509.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/108509.html</trackback:ping><description><![CDATA[<pre class="csharpcode">&nbsp;</pre>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p>最近在写D3D9模拟D3D10接口的渲染系统中碰到大量的渲染状态对象，不仅成员多，枚举也多的要命。</p>
<p>&nbsp;</p><pre class="csharpcode">    <span class="kwrd">struct</span> CORE_API RasterizerState : ResourceHandle            
    {
        eFillMode            mFillMode;        
        eCullMode            mCullMode;
        <span class="kwrd">bool</span>                mFrontFaceCCW;
        <span class="kwrd">float</span>                mDepthBias;
        <span class="kwrd">float</span>                mSlopeScaledDepthBias;
        <span class="kwrd">bool</span>                mDepthClipEnable;
        <span class="kwrd">bool</span>                mScissorEnable;
        <span class="kwrd">bool</span>                mMultisampleEnable;

        RasterizerState();
    };
</pre>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p>而要从配置文件中读取数据并填充到这个结构体，对于C++来说完全就是吃力不讨好的，写出来的代码也是极为过程，修改和扩展极为麻烦的。</p>
<p>因此决定使用反射的方法来填充数据，先总结一下我的C++反射系统</p>
<blockquote><pre class="csharpcode"><span class="kwrd">class</span> RTTIObject <span class="rem">// 动态类型识别对象基类，对象通过一些宏后可以很方便的通过字符串创建出类实例，并且可以查询注册时的类型和其他绑定信息</span>
<span class="kwrd">class</span> NameRef  <span class="rem">// 名字表，类似于虚幻中的FName，可以定义Const和普通Name，比较和拷贝只是一个dword耗费的时间</span>
value_parse，value_tostring，value_typename // 一系列类型模板函数，提供对类型的ToString，Parse及类型名查询</pre></blockquote>
<p>&nbsp;</p>
<p>首先需要处理的是枚举查询，这里将枚举通过宏做成一个个枚举对象，并可以通过名字创建实例</p>
<blockquote><pre class="csharpcode"><span class="preproc">#define</span> DECLARE_ENUMOBJECT( TEnum ) \
    <span class="kwrd">struct</span> EnumObject_##TEnum : EnumObject\
    {\
    DECLARE_RTTIOBJECT( EnumObject_##TEnum );\
    EnumObject_##TEnum( );\
    };


<span class="preproc">#define</span> IMPLEMENT_ENUMOBJECT_BEGIN( TEnum, TEnum_prefixoffset, TMember_prefixoffset ) \
    IMPLEMENT_RTTIOBJECT_STRING( EnumObject_##TEnum, #TEnum + TEnum_prefixoffset, #TEnum + TEnum_prefixoffset, <span class="str">"EnumObject"</span> )\
    EnumObject_##TEnum::EnumObject_##TEnum(){ <span class="kwrd">const</span> <span class="kwrd">int</span> member_prefixoffset = TMember_prefixoffset;

<span class="preproc">#define</span> ENUMOBJECT_ADD( enumkey ) AddMember( #enumkey + member_prefixoffset, (dword)enumkey );

<span class="preproc">#define</span> IMPLEMENT_ENUMOBJECT_END }

<span class="preproc">#define</span> ENUMOBJECT_STATICINIT( TEnum ) EnumObject_##TEnum::StaticInit();
</pre></blockquote>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p>EnumObject 中通过宏将枚举的名称和值保存在这个对象中</p>
<blockquote><pre class="csharpcode">IMPLEMENT_ENUMOBJECT_BEGIN( eFillMode, 1, 3 )  <span class="rem">// 这里的1，3是将eFillMode及FM_Point转成字符串后去掉前缀</span>
    ENUMOBJECT_ADD( FM_Point )
    ENUMOBJECT_ADD( FM_Line )
    ENUMOBJECT_ADD( FM_Fill )
IMPLEMENT_ENUMOBJECT_END

<span class="rem">// 注册到RTTIObject系统</span>

ENUMOBJECT_STATICINIT( eFillMode )
</pre>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p>&nbsp;</p><pre class="csharpcode"><span class="rem">// 通过枚举对象可以查找到字符串对应的值</span>
dword v;
EnumObject::GetEnumValue( <span class="str">"FillMode"</span>, <span class="str">"Point"</span>, v )</pre></blockquote><pre class="csharpcode"></pre>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p>下一步是将结构体成员信息记录</p><pre class="csharpcode">    <span class="kwrd">void</span> SettingObject::BindMember( <span class="kwrd">const</span> NameRef&amp; objname, <span class="kwrd">void</span>* instancePtr, <span class="kwrd">void</span>* dataPtr, SettingProxy* proxy )
    {
        proxy-&gt;mOffset = dword(dataPtr) - dword(instancePtr);

        MemberList&amp; memberlist = mSettingMap[ objname ];
        memberlist[ proxy-&gt;mName ] = proxy;
    }<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style></pre>
<p>这里记录的是结构体成员的内存偏移</p>
<p>使用大量的宏，可以让结构体绑定变得漂亮</p>
<blockquote><pre class="csharpcode"><span class="preproc">#define</span> BIND_SETTINGOBJECT_BEGIN( TClass ) \
    { <span class="kwrd">const</span> NameRef&amp; soname = TClass::StaticGetClassInfo()-&gt;mClassName;TClass soobj;

<span class="preproc">#define</span> BIND_SO_MEMBER( TMemberType, TMember ) \
    so.BindMember( soname, &amp;soobj, &amp;soobj.TMember, <span class="kwrd">new</span> TSettingElement&lt;TMemberType&gt;(#TMember + 1 ) );

<span class="preproc">#define</span> BIND_SO_MEMBER_NAME( TMemberType, TMember, TName ) \
    so.BindMember( soname, &amp;soobj, &amp;soobj.TMember, <span class="kwrd">new</span> TSettingElement&lt;TMemberType&gt;(TName) );

<span class="preproc">#define</span> BIND_SO_ENUM( TEnumType, TMember ) \
    so.BindMember( soname, &amp;soobj, &amp;soobj.TMember, <span class="kwrd">new</span> TSettingEnum(#TMember + 1, #TEnumType + 1) );

<span class="preproc">#define</span> BIND_SO_ENUM_NAME( TEnumType, TMember, TName ) \
    so.BindMember( soname, &amp;soobj, &amp;soobj.TMember, <span class="kwrd">new</span> TSettingEnum(TName, #TEnumType + 1) );

<span class="preproc">#define</span> BIND_SETTINGOBJECT_END }</pre></blockquote>
<p>绑定代码如下</p><pre class="csharpcode">        BIND_SETTINGOBJECT_BEGIN( RasterizerState )
            BIND_SO_ENUM    ( eFillMode    , mFillMode )
            BIND_SO_ENUM    ( eCullMode    , mCullMode )
            BIND_SO_MEMBER    ( <span class="kwrd">bool</span>        , mFrontFaceCCW )
            BIND_SO_MEMBER    ( <span class="kwrd">float</span>        , mDepthBias )
            BIND_SO_MEMBER    ( <span class="kwrd">float</span>        , mSlopeScaledDepthBias)
            BIND_SO_MEMBER    ( <span class="kwrd">bool</span>        , mDepthClipEnable)
            BIND_SO_MEMBER    ( <span class="kwrd">bool</span>        , mScissorEnable)
            BIND_SO_MEMBER    ( <span class="kwrd">bool</span>        , mMultisampleEnable)
        BIND_SETTINGOBJECT_END</pre>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p>&nbsp;</p>
<p>所有结构体的信息被记录在SettingObject中，读取配置文件填充结构体的任务就变得异常的简单了</p>
<blockquote><pre class="csharpcode">    SettingObject settings;
<span class="rem">// 将所有的结构体信息记录</span>
    InitRenderStateObjectSetting( settings );

    <span class="kwrd">const</span> NameRef&amp; rzname = DepthStencilState::StaticGetClassInfo()-&gt;mClassName;

    DepthStencilState a;
 <span class="rem">// 这里就是将配置文件的信息填充到结构体</span>
    settings.SetMember( rzname, &amp;a, <span class="str">"BackFace.StencilFunc"</span>, <span class="str">"Equal"</span> );</pre>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>
</blockquote><pre class="csharpcode">&nbsp;</pre><img src ="http://www.cppblog.com/sunicdavy/aggbug/108509.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2010-02-26 17:58 <a href="http://www.cppblog.com/sunicdavy/archive/2010/02/26/108509.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LemonComposer  2D游戏动画开发工具</title><link>http://www.cppblog.com/sunicdavy/archive/2010/02/05/107257.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Fri, 05 Feb 2010 06:58:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2010/02/05/107257.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/107257.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2010/02/05/107257.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/107257.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/107257.html</trackback:ping><description><![CDATA[<p>Lemon是本人开发的一套适用于2D游戏动画和高级游戏框架及配套编辑器（LemonComposer）</p> <blockquote> <p>Lemon系统特性：</p> <p>1. 支持 Canvas,Sprite,ImageSet（图片帧存储于一张图片，等大小）</p> <p>2. ImageSetEx（自由摆放的图片帧于一张图片）*</p> <p>3. 支持对象无关键帧时使用静态属性进行设置，类似于HGE里的精灵</p> <p>4. 每个对象均可成为Container，并拥有Child Node</p> <p>5. 动画关键帧类型支持：缩放，旋转，位移，颜色，动画帧，锚点，音效*</p> <p>6. 支持拾取</p> <p>7. 基于XML存储的文件格式</p> <p>8. 基于<a href="http://squirrel-lang.org/">Squirrel</a>松鼠脚本的高速面向对象脚本*</p> <p>9. 图形系统Graphics抽象，适用于任何渲染设备</p> <p>10. 控件系统*</p> <p>11. 视频回放*</p> <p>所有对象均由RTTI创建，枚举均有NamePool+Hash，并由于PropertySet的反射系统</p> <p>&nbsp;</p></blockquote> <blockquote> <p>LemonComposer编辑器特性</p> <p>界面基于我去年开发的<a href="http://www.cppblog.com/sunicdavy/archive/2009/07/24/91059.html">MotionUI</a>，lua</p> <p>8+1控制点点对象调节属性</p> <p>类Adobe Flash的帧编辑。</p> <p>类3DS Max的分轨道关键帧编辑，有助于优化art assert</p> <p>自由调节对象层级及父子关系</p> <p>全功能无限制自由Redo,Undo</p> <p>&nbsp;</p></blockquote> <p>*将在未来版本支持</p> <p><a href="http://www.cppblog.com/images/cppblog_com/sunicdavy/WindowsLiveWriter/LemonComposer2D_D2B9/image_2.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/sunicdavy/WindowsLiveWriter/LemonComposer2D_D2B9/image_thumb.png" width="483" height="300"></a> </p> <p>&nbsp;</p> <p>&nbsp;</p> <blockquote> <p>2D游戏是独立游戏的主流，也是创意，投入比最小的一个维度。但是基于2D的大多是一些类似于HGE，IndieLib等开源免费2D引擎。但是面对游戏中大量的动画而言，开发者大多是使用图片帧来制作，虽然效果很好，但是设备资源好用和制作难度也是很难控制的。</p></blockquote> <blockquote> <p>流行于去年的植物对僵尸和2004年发行的<a href="http://www.verycd.com/topics/51268/">RO Offline</a>经过资源分析，就是使用类似于Lemon系统，或者说Flash的系统制作而成，因此效果和扩展性非常好。</p> <p>这就是Lemon存在的理由。</p> <p>Flash面向的是GDI+Web，那么Lemon就是针对游戏专有的，基于硬件加速的游戏框架</p> <p>Flash Action Script 对应的就是Lemon的<a href="http://squirrel-lang.org/">Squirrel</a>脚本</p> <p>FlashIDE 对应的就是Lemon Composer</p> <p>Lemon的目标就是让2D游戏开发更简单，让游戏中充满更多的动画, 让游戏开发难度降低</p> <p><a href="http://www.cppblog.com/images/cppblog_com/sunicdavy/WindowsLiveWriter/LemonComposer2D_D2B9/farming-gold-in-pvz%5B1%5D_2.jpg"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="farming-gold-in-pvz[1]" border="0" alt="farming-gold-in-pvz[1]" src="http://www.cppblog.com/images/cppblog_com/sunicdavy/WindowsLiveWriter/LemonComposer2D_D2B9/farming-gold-in-pvz%5B1%5D_thumb.jpg" width="244" height="196"></a></p></blockquote><img src ="http://www.cppblog.com/sunicdavy/aggbug/107257.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2010-02-05 14:58 <a href="http://www.cppblog.com/sunicdavy/archive/2010/02/05/107257.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>解决Render Target中的Alpha通道绘制问题</title><link>http://www.cppblog.com/sunicdavy/archive/2010/01/20/106072.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Wed, 20 Jan 2010 08:56:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2010/01/20/106072.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/106072.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2010/01/20/106072.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/106072.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/106072.html</trackback:ping><description><![CDATA[<p>前段时间曾经碰到过RT纹理绘制出来时需要透明的问题。当时也Google了一下，但是很少有人提起过这个问题。昨天看<a href="http://www.cppblog.com/jianguhan/">剑孤寒的空间</a>的Galaxy2D引擎中使用RT的透明绘制，文章在<a href="http://www.cppblog.com/jianguhan/archive/2010/01/17/105866.html">这里</a>。发现这个特性居然需要显卡支持，马上查过DX9SDK文档，发现这样一篇<a href="http://msdn.microsoft.com/en-us/library/ee422179(VS.85).aspx">文章</a>，已经告诉我们怎么做了：</p> <h3>Render Target Alpha (Direct3D 9)</h3> <p>The frame buffer blender can now blend alpha channels independent from color-channel blending on render targets. This control is enabled with a new render state, D3DRS_SEPARATEALPHABLENDENABLE. <p>When D3DRS_SEPARATEALPHABLENDENABLE is set to FALSE (which is the default condition), the render-target blending factors and operations applied to alpha are the same as those defined for blending color channels. A driver needs to set the D3DPMISCCAPS_SEPARATEALPHABLEND cap to indicate that it can support render-target alpha blending. Be sure to enable D3DRS_ALPHABLEND to tell the pipeline that alpha blending is needed. <p>To control the factors in the alpha channel of the render-target blenders, two new render states are defined as follows:<pre>D3DRS_SRCBLENDALPHA 
D3DRS_DESTBLENDALPHA 
</pre>
<p>Like the D3DRS_SRCBLEND and D3DRS_DESTBLEND, these can be set to one of the values in the <a href="http://msdn.microsoft.com/en-us/library/ee416368(VS.85).aspx">D3DBLEND</a> enumeration. The source and destination blend settings can be combined in several ways, depending on the settings in the SrcBlendCaps and DestBlendCaps members of <a href="http://msdn.microsoft.com/en-us/library/ee416379(VS.85).aspx">D3DCAPS9</a>.
<p>The alpha blending is done as follows:<pre>renderTargetAlpha = (alphain* srcBlendOp) BlendOp (alphart* destBlendOp) 
</pre>
<p>Where:
<ul>
<li>alphain is the input alpha value. 
<li>srcBlendOp is one of the blend factors in <strong>D3DBLEND</strong>. 
<li>BlendOp is one of the blend factors in <a href="http://msdn.microsoft.com/en-us/library/ee416370(VS.85).aspx">D3DBLENDOP</a>. 
<li>alphart is the render-target alpha value. 
<li>destBlendOp is one of the blend factors in <strong>D3DBLEND</strong>. 
<li>renderTargetAlpha is the final blended alpha value.</li></ul>
<p>&nbsp;</p>
<p>翻译如下：</p>
<p>&nbsp;&nbsp; 使用 D3DRS_SEPARATEALPHABLENDENABLE渲染状态可以让Frame Buffer 混合器将RT中的Alpha通道与颜色通道分开混合。</p>
<p>当D3DRS_SEPARATEALPHABLENDENABLE 设置为 FALSE（默认），RT渲染参数和操作会跟颜色通道一样被应用到Alpha通道。 这项特性需要显卡支持D3DPMISCCAPS_SEPARATEALPHABLEND 特性。记住，在之前设置D3DRS_ALPHABLEND以便打开Alpha混合。</p>
<p>&nbsp;&nbsp; RT混合器的Alpha通道混合因子渲染状态如下：</p>
<p>D3DRS_SRCBLENDALPHA </p>
<p>D3DRS_DESTBLENDALPHA </p>
<p>其被定义在<a href="http://msdn.microsoft.com/en-us/library/ee416368(VS.85).aspx">D3DBLEND</a>枚举中，D3DRS_SRCBLEND 和D3DRS_DESTBLEND也是这样定义的。来源色与目标颜色将会有很多组合方式，主要依赖于<a href="http://msdn.microsoft.com/en-us/library/ee416379(VS.85).aspx">D3DCAPS9</a>中的SrcBlendCaps 和DestBlendCaps</p>
<p>Alpha混合公式如下：</p>
<p>renderTargetAlpha = (alphain* srcBlendOp) BlendOp (alphart* destBlendOp) </p>
<p>其中：</p>
<p>&nbsp;&nbsp;&nbsp; alphain为输入alpha值</p>
<p>&nbsp;&nbsp;&nbsp; srcBlendOp是D3DBLEND中的一个混合因子</p>
<p>&nbsp;&nbsp;&nbsp; BlendOp是 <a href="http://msdn.microsoft.com/en-us/library/ee416370(VS.85).aspx">D3DBLENDOP</a>中的一个混合因子</p>
<p>&nbsp;&nbsp;&nbsp; alphart是RT的alpha值</p>
<p>&nbsp;&nbsp;&nbsp; destBlendOp是D3DBLEND中的一个混合因子</p>
<p>&nbsp;&nbsp;&nbsp; renderTargetAlpha是最后混合后的alpha值</p><img src ="http://www.cppblog.com/sunicdavy/aggbug/106072.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2010-01-20 16:56 <a href="http://www.cppblog.com/sunicdavy/archive/2010/01/20/106072.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>判断点在凸四边形中</title><link>http://www.cppblog.com/sunicdavy/archive/2010/01/08/105136.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Fri, 08 Jan 2010 02:29:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2010/01/08/105136.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/105136.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2010/01/08/105136.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/105136.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/105136.html</trackback:ping><description><![CDATA[<p>前几天需要做一个鼠标点击判定，具体是判断一个点是否在某个凸四边形中。</p> <p>最简单的方法莫过于判断鼠标点是否在2个三角形中。但是很多判定方法都是有问题的，比如说</p> <p>&nbsp;</p> <p>copy自IndieLib</p><pre class="csharpcode"><span class="kwrd">bool</span> Triangle2D::Inside2( <span class="kwrd">const</span> Vector2&amp; p )
{
    Vector2 v0 = mP3 - mP1;
    Vector2 v1 = mP2 - mP1;
    Vector2 v2 = p - mP1; 

    <span class="rem">// Compute dot products</span>
    <span class="kwrd">float</span> dot00 =  Vector2::DotProduct( v0, v0 );
    <span class="kwrd">float</span> dot01 =  Vector2::DotProduct( v0, v1 );
    <span class="kwrd">float</span> dot02 =  Vector2::DotProduct( v0, v2 );
    <span class="kwrd">float</span> dot11 =  Vector2::DotProduct( v1, v1 );
    <span class="kwrd">float</span> dot12 =  Vector2::DotProduct( v1, v2 ); 

    <span class="rem">// Compute barycentric coordinates</span>
    <span class="kwrd">float</span> invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
    <span class="kwrd">float</span> u = (dot11 * dot02 - dot01 * dot12) * invDenom;
    <span class="kwrd">float</span> v = (dot00 * dot12 - dot01 * dot02) * invDenom; 

    <span class="rem">// Check if point is in triangle</span>
    <span class="kwrd">return</span> (u &gt; 0) &amp;&amp; (v &gt; 0) &amp;&amp; (u + v &lt; 1);
} 

  
</pre>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p>Google出的某人代码 <pre class="csharpcode"><span class="kwrd">float</span> Triangle2D::CrossProduct3(<span class="kwrd">const</span> Vector2&amp; p1,<span class="kwrd">const</span> Vector2&amp; p2, <span class="kwrd">const</span> Vector2&amp; p0 )
{
    <span class="kwrd">return</span> (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
} 

<span class="kwrd">bool</span> Triangle2D::Inside( <span class="kwrd">const</span> Vector2&amp; p )
{
    <span class="kwrd">return</span> (CrossProduct3(mP1,p,mP2)*CrossProduct3(mP3,p,mP2)&lt;0) &amp;&amp;
           (CrossProduct3(mP2,p,mP1)*CrossProduct3(mP3,p,mP1)&lt;0) &amp;&amp;
           (CrossProduct3(mP1,p,mP3)*CrossProduct3(mP2,p,mP3)&lt;0);
} 
</pre>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p>&nbsp; <p>这2个方法都有缺陷，当点在三角形边上时，就无法得出。当用在一个正方形判断时，正方形中心点就判定为没有在其内部，显然是一个错误。 
<p>&nbsp; <p>之后，又Google出某几个大侠的算法和思想，考虑了下，判定点与四边形重心点的线段是否与四边形4条边相交，相交时，其在四边形外部，反之亦然。 <pre class="csharpcode"><span class="kwrd">bool</span> Quadrangle::Inside2( <span class="kwrd">const</span> Vector2&amp; p )
{
    Vector2 c = Segement2D::GetCrossPoint( mP1, mP3, mP2, mP4 ); 

    <span class="kwrd">return</span> !(Segement2D::Intersect( mP1, mP2, c, p) || 
           Segement2D::Intersect( mP2, mP3, c, p) ||
           Segement2D::Intersect( mP3, mP4, c, p) ||
           Segement2D::Intersect( mP4, mP1, c, p) );
} 

<span class="kwrd">bool</span> Segement2D::Intersect( <span class="kwrd">const</span> Vector2&amp; p1, <span class="kwrd">const</span> Vector2&amp; p2,<span class="kwrd">const</span> Vector2&amp; p3, <span class="kwrd">const</span> Vector2&amp; p4 )
{
    <span class="kwrd">float</span> gradab, gradcd, ycptab, ycptcd, interceptX, intercepty; 

    <span class="rem">// In order to avoid divisions by zero</span>
    <span class="rem">//if (mP1.y == mP2.y)</span>
    <span class="rem">//    mP2.y += 0.0001f; </span>

    <span class="rem">//if (mP1.x == mP2.x)</span>
    <span class="rem">//    mP2.x += 0.0001f; </span>

    <span class="rem">//if (seg.mP1.y == seg.mP2.y)</span>
    <span class="rem">//    seg.mP2.y += 0.0001f; </span>

    <span class="rem">//if (seg.mP1.x == seg.mP2.x)</span>
    <span class="rem">//    seg.mP2.x += 0.0001f; </span>

    <span class="rem">// Calculates the intersection between the two lines</span>
    gradab = (p1.y - p2.y) / (p1.x - p2.x);
    gradcd = (p3.y - p4.y) / (p3.x - p4.x); 

    ycptab = p1.y - p1.x * gradab;
    ycptcd = p3.y - p3.x * gradcd;
    interceptX = (ycptab - ycptcd) / (gradcd - gradab);
    intercepty = (ycptab - (gradab * ycptcd) / gradcd) / (1 - gradab / gradcd); 

    <span class="rem">// Checking in the intersection is inside the segment</span>
    <span class="kwrd">if</span> (!((interceptX &gt;= p1.x &amp;&amp; interceptX &lt;= p2.x) || (interceptX &gt;= p2.x &amp;&amp; interceptX &lt;= p1.x)))
        <span class="kwrd">return</span> 0; 

    <span class="kwrd">if</span> (!((intercepty &gt;= p1.y &amp;&amp; intercepty &lt;= p2.y) || (intercepty &gt;= p2.y &amp;&amp; intercepty &lt;= p1.y)))
        <span class="kwrd">return</span> 0; 

    <span class="kwrd">if</span> (!((interceptX &gt;= p3.x &amp;&amp; interceptX &lt;= p4.x) || (interceptX &gt;= p4.x &amp;&amp; interceptX &lt;= p3.x)))
        <span class="kwrd">return</span> 0; 

    <span class="kwrd">if</span> (!((intercepty &gt;= p3.y &amp;&amp; intercepty &lt;= p4.y) || (intercepty &gt;= p4.y &amp;&amp; intercepty &lt;= p3.y)))
        <span class="kwrd">return</span> 0; 

    <span class="kwrd">return</span> 1;
} 

Vector2 Segement2D::GetCrossPoint(<span class="kwrd">const</span> Vector2&amp; p1, <span class="kwrd">const</span> Vector2&amp; p2, <span class="kwrd">const</span> Vector2&amp; q1, <span class="kwrd">const</span> Vector2&amp; q2)
{
    <span class="rem">//必须相交求出的才是线段的交点，但是下面的程序段是通用的 </span>

    <span class="rem">/*根据两点式化为标准式，进而求线性方程组*/</span>
    Vector2 crossPoint;
    <span class="rem">//求x坐标</span>
    <span class="kwrd">float</span> tempLeft = (q2.x - q1.x) * (p1.y - p2.y) - (p2.x - p1.x) * (q1.y - q2.y);
    <span class="kwrd">float</span> tempRight = (p1.y - q1.y) * (p2.x - p1.x) * (q2.x - q1.x) + q1.x * (q2.y - q1.y) * (p2.x - p1.x) - p1.x * (p2.y - p1.y) * (q2.x - q1.x);
    crossPoint.x = tempRight / tempLeft;
    <span class="rem">//求y坐标</span>
    tempLeft = (p1.x - p2.x) * (q2.y - q1.y) - (p2.y - p1.y) * (q1.x - q2.x);
    tempRight = p2.y * (p1.x - p2.x) * (q2.y - q1.y) + (q2.x- p2.x) * (q2.y - q1.y) * (p1.y - p2.y) - q2.y * (q1.x - q2.x) * (p2.y - p1.y);
    crossPoint.y = tempRight / tempLeft; 

    <span class="kwrd">return</span> crossPoint;
}
</pre>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p>这个算法效率并不是很高，但对于设计器来说无所谓了，如果有好的准确算法，可以讨论</p><img src ="http://www.cppblog.com/sunicdavy/aggbug/105136.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2010-01-08 10:29 <a href="http://www.cppblog.com/sunicdavy/archive/2010/01/08/105136.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>