﻿<?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/tuantuan/category/7442.html</link><description>WEB开发,高性能服务器开发,网络编程,游戏开发 跌跌撞撞中寻找未来</description><language>zh-cn</language><lastBuildDate>Mon, 23 Jun 2008 17:21:46 GMT</lastBuildDate><pubDate>Mon, 23 Jun 2008 17:21:46 GMT</pubDate><ttl>60</ttl><item><title>游戏官网的运营</title><link>http://www.cppblog.com/tuantuan/archive/2008/06/23/54415.html</link><dc:creator>谢岱唛</dc:creator><author>谢岱唛</author><pubDate>Mon, 23 Jun 2008 15:19:00 GMT</pubDate><guid>http://www.cppblog.com/tuantuan/archive/2008/06/23/54415.html</guid><wfw:comment>http://www.cppblog.com/tuantuan/comments/54415.html</wfw:comment><comments>http://www.cppblog.com/tuantuan/archive/2008/06/23/54415.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tuantuan/comments/commentRss/54415.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tuantuan/services/trackbacks/54415.html</trackback:ping><description><![CDATA[<p>游戏官网是游戏推广的一个重要途径。<br></p>
<p><br>待完善&nbsp;</p>
<img src ="http://www.cppblog.com/tuantuan/aggbug/54415.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tuantuan/" target="_blank">谢岱唛</a> 2008-06-23 23:19 <a href="http://www.cppblog.com/tuantuan/archive/2008/06/23/54415.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>游戏Entity设计不完全整理</title><link>http://www.cppblog.com/tuantuan/archive/2008/06/23/54413.html</link><dc:creator>谢岱唛</dc:creator><author>谢岱唛</author><pubDate>Mon, 23 Jun 2008 15:09:00 GMT</pubDate><guid>http://www.cppblog.com/tuantuan/archive/2008/06/23/54413.html</guid><wfw:comment>http://www.cppblog.com/tuantuan/comments/54413.html</wfw:comment><comments>http://www.cppblog.com/tuantuan/archive/2008/06/23/54413.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tuantuan/comments/commentRss/54413.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tuantuan/services/trackbacks/54413.html</trackback:ping><description><![CDATA[<div>
<p><span><span><span>在游戏引擎中，</span><span>Entity</span><span>通常被翻译成实体，也常用诸如</span><span>GameObject</span><span>、</span><span>Actor</span><span>、</span><span>SimulationObject</span><span>、</span><span>Unit</span><span>、</span><span>Character</span><span>等名字。相比于对图像声音引擎的热情，</span><span>Entity</span><span>层多年来一直备受冷遇，但最近几年随着大型游戏的发展，</span><span>Entity</span><span>层设计的重要性已经达到和图像声音的同等水平，而且已经出现了多种通用型</span><span>Entity</span><span>架构。当然，这里伴随着争议和分歧。</span></p>
<h3><span>直接模式（</span><span>The C Approach</span><span>）</span></h3>
<p><span>这是最早、最简单、也是任何人都能直接想到的模式。这种方式下一个</span><span>Entity</span><span>就是一个简单的</span><span>struct:</span></p>
<p><span>struct Mob<br>{<br>int level, hp, mp, attack, &#8230;;<br>};</span></p>
<p><span>这种情况下往往需要对不同类型的</span><span>Entity</span><span>定义不同的</span><span>struct</span><span>，比如</span><span>Player</span><span>、</span><span>Mob</span><span>、</span><span>Item</span><span>、</span><span>Doodad</span><span>等。</span><span>Entity</span><span>的数据库可以直接使用现成的数据库系统或者从数据文件读取，比如</span><span>csv</span><span>文件。一般会选择</span><span>Excel</span><span>编辑数据库，然后导出</span><span>csv</span><span>。</span><span>Excel</span><span>的强大表格和统计计算功能是调节游戏数据平衡的得力工具。以致这种最古老而简单的</span><span>Entity</span><span>模式以强大的生命力一直活到现在。</span></p>
<p><span>那么为什么</span><span>Developers</span><span>会要去探索其他方式呢？最大的问题是这种方式下各种</span><span>Entity</span><span>完全不同质。比如</span><span>Player</span><span>、</span><span>Mob</span><span>、</span><span>Doodad</span><span>都有位置，都要做碰撞检测，但他们却是不同的类型，不能使用同一份代码；</span><span>Player</span><span>和</span><span>Mob</span><span>都有</span><span>hp</span><span>和</span><span>mp</span><span>，也有基本相同的处理逻辑&#8230;&#8230;当然，这个可以用</span><span>hack</span><span>的方法解决：只要各个</span><span>struct</span><span>前若干个成员类型和顺序完全相同，就可以将指针</span><span>cast</span><span>成统一的一个</span><span>Entity</span><span>类型来处理。不过，任何人都能想到更好的办法，用类！</span></p>
<h3><span>继承模式（</span><span>Inheritage</span><span>）</span></h3>
<p><span>这也是</span><span>Entity</span><span>、</span><span>GameObject</span><span>等这些名字的由来，他们就是基类。于是我们可以得到一颗继承关系树，例如：</span></p>
<p><span>Entity</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Character</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Player</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Mob</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Missile</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Laser</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>GuidedMissile</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Item</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&#8230;</span></p>
<p><span>Entity</span><span>对象的逻辑大多也是直接包含在类里的。但也有人采用了数据对象和逻辑对象的分离，其好处是对相同的数据可以替换不同的逻辑。不过，个人比较怀疑这种分离是否值得，因为类的派生本身就是可以拥有不同的逻辑。</span></p>
<p><span>另外，</span><span>Entity</span><span>间的交互除了用标准的直接访问方式外，经常使用消息模式。消息模式和</span><span>Windows</span><span>的消息模式类似，</span><span>Entity</span><span>间通过消息交互。虽说窗口编程画了多年时间才摆脱了当年肥大的</span><span>switch</span><span>的消息处理模式，在</span><span>Entity</span><span>层使用消息模式还是有意义的，因为消息很容易广播且可以直接在网络上发送。执着于</span><span>OO</span><span>的人会将消息写成</span><span>Command</span><span>对象，但原理仍然是一样的。</span></p>
<p><span>同时，联网游戏出现，指针不能在不同的机器上标识对象，我们必须用稳定的</span><span>ID</span><span>来标识对象，于是我们有了</span><span>EntityManager</span><span>来分配</span><span>ID</span><span>和管理对象集合，或者叫</span><span>GameObjectManager</span><span>、</span><span>ObjectManager</span><span>等。这在一段时期内几乎成了完美的方案。</span></p>
<p><span>随着游戏内容的丰富性的迅速膨胀，传统的由程序员来实现游戏逻辑功能的模式也越来越力不从心。脚本语言的集成将大部分创意性工作从程序员的担子上拿了下来，交还给游戏设计人员。为了给脚本提供足够的控制权，</span><span>Entity</span><span>结构上必须有充分的灵活性。</span></p>
<h3><span>数据驱动（</span><span>Data-Driven</span><span>）</span></h3>
<p><span>现在有句很流行的话，&#8220;唯一不变的是变化。（</span><span>The only constant is change.</span><span>）&#8221;数据驱动使得变化对引擎的影响最小化。数据驱动不能算是一种独立的</span><span>Entity</span><span>模式，不如说它是一种设计思想，其目的就是将内容制作和游戏引擎的制作分离开来。与上面所说的填充</span><span>Entity</span><span>属性数据库的不同之处在于，它还要能通过数据来设计游戏逻辑。</span></p>
<p><span>游戏设计人员需要的一项最基本功能就是自定义人物属性，所以与其在类里写死属性成员，不如使用属性表（</span><span>Attributes/Properties</span><span>）。通常使用一个哈希表（</span><span>Hashtable</span><span>），或者</span><span>std::map</span><span>，或者</span><span>Dictionary</span><span>，或者就是个数组，随个人喜好，其实就是要一个</span><span>key-value</span><span>的映射表。然后为脚本和编辑器提供对属性表的操作。</span></p>
<p><span>动态的逻辑主要就靠脚本了，必须为脚本提供足够的事件和方法。个人推荐用</span><span>Lua</span><span>脚本，因为它是在游戏领域内用得最多的通用脚本语言，其引擎很小、速度很快、易于集成，尽管语法过于松散。不要迷信宣传去用庞大、极慢、难于集成的</span><span>Python</span><span>。为脚本提供事件，其实也就是调用脚本里的函数，这里如果使用了前面所述的消息模式，那么就只要调用一个脚本方法，传递不同的消息参数就行了。当然也有人觉得这样很丑陋而更愿意为不同的事件注册不同的函数。</span></p>
<p><span>当有了数据驱动后，</span><span>Entity</span><span>的继承树就基本失去意义了，因为一个</span><span>Entity</span><span>是什么已经不是程序里决定的了，而是通过数据和脚本设计出来的。但数据和脚本又不是全部，一个</span><span>Entity</span><span>的核心内容和需要高效处理的部分，如碰撞检测，还是要程序来完成。于是我们需要重新设计</span><span>Entity</span><span>类，困难的局面也就由此开始。</span></p>
<p><span>一个直观的想法是一个统一且唯一的</span><span>Entity</span><span>类，它包含了所有的基本功能，如显示、碰撞检测、运动、背包等，然后由数据决定哪些组件被启用。比如一个玩家角色可能会启用绝大部分组件，而一颗树只启用显示和碰撞检测组件。但也伴随着缺点：一、这个类太大了；二、对于树木等一些简单的</span><span>Entity</span><span>也要浪费其他组件的私有数据所占的内存。那么一个简单的折中是部分使用继承、部分使用数据定制。例如</span><span>Entity</span><span>只提供最基本的组件，再派生出</span><span>CharactorEntity</span><span>提供足够人物角色使用的组件。</span></p>
<h3><span>组件模式（</span><span>Component-Based Entity</span><span>）</span></h3>
<p><span>提到组件，那么很自然的就过渡到组件模式，就是把显示、运动、攻击、背包、队伍、声音等基本功能都做成独立的组件，由数据来决定向</span><span>Entity</span><span>里添加哪些组件。由此可以得到另外一个扩展，就是既然可以有引擎内置的组件，那就也可以有脚本制作的组件，实现脚本模块的复用。这种模式在</span><span>GDC2002</span><span>正式提出，到现在主流的引擎都有这种设计。</span></p>
<p><span>这种模式在理论上很完美，但实践上还是有不少疑问。最常见的问题就是组件间的依赖关系。理想情况下，各个组件是完全独立的，但实践中必然有所依赖。比如运动速度、攻击强度等和角色的基本属性有关，运动组件需要角色的包围盒来测试是否碰撞，</span><span>AI</span><span>组件需要分析角色当前状态和发出运动、攻击命令，角色动作状态变化时改变显示组件属性，攻击组件需要访问队伍信息组件以禁止攻击队友等等。处理这种依赖关系主要要解决两个问题：</span></p>
<p>&lt;!--[if !supportLists]--&gt;<span><span>一、<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span>&lt;!--[endif]--&gt;<span>谁依赖谁。比如是敏捷属性改变而去修改移动速度，还是运动组件读取敏捷属性来计算移动速度。如果要游戏设计人员自由定义基本属性的话，就要选择前者，因为基本属性组件会是脚本组件。</span></p>
<p>&lt;!--[if !supportLists]--&gt;<span><span>二、<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span>&lt;!--[endif]--&gt;<span>如何取得另一组件的指针</span><span>/</span><span>引用。常见的方法是给每个组件类型一个唯一</span><span>ID</span><span>，然后用该</span><span>ID</span><span>在</span><span>Entity</span><span>上查询注册了的组件，如果找到返回其指针</span><span>/</span><span>引用，否则返回</span><span>null</span><span>。当然，每次访问都做这个查询会很浪费</span><span>CPU</span><span>，如果</span><span>Entity</span><span>的组件不会在运行时动态添加删除的话（除非在编辑器里，否则很少有人会这么做），可以在</span><span>Entity</span><span>初始化后让每个组件缓存它所要用的其他组件指针。那么当所依赖的组件不存在怎么办，一般情况下都是无声地忽略。</span></p>
<p><span>当</span><span>Entity</span><span>由很多组件组成后，交互的消息需要发给每一个组件。这里又一次体现出消息机制的优势，你不需要在</span><span>Entity</span><span>里为每一个事件函数写一个</span><span>loop</span><span>来调用组件的相应事件函数。但这里也出现了一个问题，消息到达各个组件的顺序。很多时候这个顺序不会有什么影响，但个别时候不同的顺序会导致完全不同的逻辑发展方向。</span></p>
<p><span>此外，</span><span>Entity</span><span>的序列化存储也变得比较复杂，经典的</span><span>Excel</span><span>导出</span><span>csv</span><span>的模式难以奏效，因为这里需要结构化的存储，所以需要结构化的数据文件如</span><span>XML</span><span>来存储，或者完全用脚本来包含所有数据和构造</span><span>Entity</span><span>。</span></p>
<p><span>据个人经验，使用数据驱动的继承模式时很是向往组件模式，感觉上它一个非常自然的扩展方向，但顾忌其引入的额外的复杂性，尤其是需要游戏设计人员具有一定的编程能力，所以一直不敢全盘接过使用。但退一步，在引擎里仍然使用组件思想，但</span><span>Entity</span><span>的组件构成在编译时固定，可以达到某种妥协，这和采用继承与数据驱动的折中类似。</span></p>
<h3><span>混入模式（</span><span>Mix-in</span><span>）</span></h3>
<p><span>这是又一种常见的折中模式，即使用</span><span>C++</span><span>的多重继承，将各个组件类混入一个</span><span>Entity</span><span>类。如：</span></p>
<p><span>class Mob: public GameObject, public Renderable, public Movable, public Attackable<br>{<br>&#8230;<br>}</span></p>
<p><span>这种方法因其简单而且非常符合多重继承设计思想而被很多引擎采用。当然缺点也是只能在支持多重继承的语言里使用，而且当组件很丰富时，</span><span>dynamic_cast</span><span>就变成一个代价高昂的操作。</span><span> <br></span></p>
<h3><span>功能性与复杂性（</span><span>Functionality vs Complexity</span><span>）</span></h3>
<p><span>编程领域最古老的原则之一就是要&#8220;简单快速&#8221;。但随着问题的复杂化，程序也随之变得越来越复杂。好的方法应该能有效的降低或隐藏复杂性。但是，没有不带副作用的药（</span><span>No silver bullet.</span><span>），在取得更强大的功能的同时总会带来额外的复杂性。我们需要做出权衡，在必要时牺牲一些功能，也就是要估算性价比。</span><br></p>
<p><span>一般游戏内容制作人员不会或不太会编程，编程人员也不善于游戏的内容创造和数值平衡，过于复杂的系统会导致需要两面兼顾的人才，会大大增加做出一款游戏的难度。</span></p>
</span></span></div>
<img src ="http://www.cppblog.com/tuantuan/aggbug/54413.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tuantuan/" target="_blank">谢岱唛</a> 2008-06-23 23:09 <a href="http://www.cppblog.com/tuantuan/archive/2008/06/23/54413.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>游戏引擎列表 </title><link>http://www.cppblog.com/tuantuan/archive/2008/06/23/54412.html</link><dc:creator>谢岱唛</dc:creator><author>谢岱唛</author><pubDate>Mon, 23 Jun 2008 15:04:00 GMT</pubDate><guid>http://www.cppblog.com/tuantuan/archive/2008/06/23/54412.html</guid><wfw:comment>http://www.cppblog.com/tuantuan/comments/54412.html</wfw:comment><comments>http://www.cppblog.com/tuantuan/archive/2008/06/23/54412.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tuantuan/comments/commentRss/54412.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tuantuan/services/trackbacks/54412.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 免费引擎    Agar - 一个高级图形应用程序框架，用于2D和3D游戏。    Allegro library - 基于 C/C++ 的游戏引擎，支持图形，声音，输入，游戏时钟，浮点，压缩文件以及GUI。    Axiom 引擎 - OGRE的衍生引擎。    Baja 引擎 - 专业品质的图像引擎，用于The Lost Mansion。    Boom - Doom代...&nbsp;&nbsp;<a href='http://www.cppblog.com/tuantuan/archive/2008/06/23/54412.html'>阅读全文</a><img src ="http://www.cppblog.com/tuantuan/aggbug/54412.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tuantuan/" target="_blank">谢岱唛</a> 2008-06-23 23:04 <a href="http://www.cppblog.com/tuantuan/archive/2008/06/23/54412.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一种经典的网络游戏服务器架构</title><link>http://www.cppblog.com/tuantuan/archive/2008/06/23/54411.html</link><dc:creator>谢岱唛</dc:creator><author>谢岱唛</author><pubDate>Mon, 23 Jun 2008 14:53:00 GMT</pubDate><guid>http://www.cppblog.com/tuantuan/archive/2008/06/23/54411.html</guid><wfw:comment>http://www.cppblog.com/tuantuan/comments/54411.html</wfw:comment><comments>http://www.cppblog.com/tuantuan/archive/2008/06/23/54411.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tuantuan/comments/commentRss/54411.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tuantuan/services/trackbacks/54411.html</trackback:ping><description><![CDATA[首先，二话不说，上图（用Windows画图画的。。。）<br><br><img height=768 alt="" src="http://www.cppblog.com/images/cppblog_com/johndragon/servergraph.jpg" width=988 border=0><br>这个图是一个区的架构图，所有区的架构是一样的。上面虚线框的ServerGroup和旁边方框内的架构一样。图上的所有x N的服务器，都是多台一起的。红线，绿线，和蓝线图上也有图示，这里就不多介绍了。关于Agent Server大家也能看出来，其实就是Gate。<br>这里主要介绍下图上的标记了号码的位置的数据连接的内容和意义。<br><br>1-&nbsp;&nbsp;&nbsp;这是一条WebService的管道，在用户激活该区帐号，或者修改帐号密码的时候，通过这条通道来插入和更新用户的帐号信息。<br>2-&nbsp;&nbsp;&nbsp;这也是一条WebService管道，用来获取和控制用户该该组内的角色信息，以及进行付费商城代币之类的更新操作。<br>3-&nbsp;&nbsp;&nbsp;这是一条本地的TCP/IP连接，这条连接主要用来进行服务器组在登陆服务器的注册，以及登陆服务器验证帐户后，向用户服务器注册帐户登陆信息，以及进行对已经登陆的帐户角色信息进行操作（比如踢掉当前登陆的角色），还有服务器组的信息更新（当前在线玩家数量等）。<br>4-&nbsp;&nbsp;&nbsp;这也是一条本地TCP/IP连接，这条连接用来对连接到GameServer的客户端进行验证，以及获取角色数据信息，还有传回GameServer上角色的数据信息改变。<br>5-&nbsp;&nbsp;&nbsp;这条连接也是一条本地的TCP/IP连接，它用来进行公共信息服务器和数个游戏服务器间的交互，用来交换一些游戏世界级的信息（比如公会信息，跨服组队信息，跨服聊天频道等）。<br>6-&nbsp;&nbsp;&nbsp;这里的两条连接，想表达的意思是，UserServer和GameServer的Agent是可以互换使用的，也就是玩家进入组内之后，就不需要再切换Agent。如果不怕乱套，也可以把登陆服务器的Agent也算上，这样用户整个过程里就不需要再更换Agent，减少重复连接的次数，也提高了稳定性。（毕竟连接次数少了，也降低了连不上服务器的出现几率）<br><br>在这个架构里面，GameServer实际上是一个游戏逻辑的综合体，里面可以再去扩展成几个不同的逻辑服务器，通过PublicServer进行公共数据交换。<br>UserServer实际上扮演了一个ServerGroup的领头羊的角色，它负责向LoginServer注册和更新服务器组的信息（名字，当前人数），并且对Agent进行调度，对选择了该组的玩家提供一个用户量最少的Agent。同时，它也兼了一个角色管理服务器的功能，发送给客户端当前的角色列表，角色的创建，删除，选择等管理操作，都是在这里进行的。而且，它还是一个用户信息的验证服务器，GameServer需要通过它来进行客户端的合法性验证，以及获取玩家选择的角色数据信息。<br><br><br>采用这种架构的游戏，通常有以下表现。<br>1- 用户必须激活一个大区，才能在大区内登陆自己的帐号。<br>2- 用户启动客户端的时候，弹出一个登陆器，选择大区。<br>3- 用户启动真正的客户端的时候，一开始就是输入帐号密码。<br>4- 帐号验证完成之后，进行区内的服务器选择。<br>5- 服务器选择完成之后，进入角色管理。同时，角色在不同的服务器里不能共享。<br><br>市面上符合上面几个表现特征的游戏相当的多，而且也不乏旷世巨作。这个架构不是一个新的架构，但是它足够经典和完善，并且逻辑简单而清晰，用来做MMORPG，或者其它网络游戏的服务器架构，是一种不错的选择。<br>
<img src ="http://www.cppblog.com/tuantuan/aggbug/54411.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tuantuan/" target="_blank">谢岱唛</a> 2008-06-23 22:53 <a href="http://www.cppblog.com/tuantuan/archive/2008/06/23/54411.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>