滕王阁及个别网页显示不正常服务器无法登录游戏/其余服务器正常游戏…

posts - 940,&
comments - 126,&
trackbacks - 0
作者博客:http://blog.csdn.net/yahle大纲:项目的历史背景的设计思路服务器的技术服务器的设计服务器的改进图形引擎myhoho及UI库的设计客户端与服务器的集成网络游戏一般采用C\S模式,网络游戏的设计重点,我认为在于Server端,也就是我们说的服务器。在服务器端的设计,我把服务器按照功能分为2个部分,一个负责游戏世界的处理,一个服务器服务器与客户端的通讯。在负责游戏世界的处理的服务器,我又按照功能分为地图服务器和逻辑服务器。这样划分的依据是他们处理的内容不同进行。当初的设计还考虑到系统的集群功能,可以把游戏的地图移动处理和游戏的逻辑处理都分别分摊到其它服务器里面去。但是做到最后,发现这样的设计也不是太好,主要是因为在处理一些游戏事件的时候需要两个服务器之间进行协同,这样势必要创建一定的网络游戏消息,在开始制作游戏的时候,因为需要系统的东西不是很多,所以没有太注意,到项目的后期,想增加一个功能的时候,就发现在处理船只沉没的时候,服务器需要传递很多同步数据,而且服务器各自在设置玩家数据的时候,也有很多重复的地方。如果今后还要再加点什么其它功能,那要同步的地方就实在是太多了,所以按照功能把服务器分为2个部分的设计还是存在缺陷的,如果让我重新再来,我会选择单服务器的设计,当然这个服务器还是要和连接服务器进行分离,因为游戏的逻辑处理和与玩家的通讯还是很好分开的,而且分开的话,也有利于逻辑服务器的设计。登陆(连接)服务器的设计:& &在网络游戏里,其中一个很大的难点就是玩家与服务器的通讯,在Windos的服务器架构下,网络游戏服务器端采用的I/O模型,通常是完成端口。在项目开始时研究完成端口,感觉很难,根本看不懂,因为它在很多地方与以前写网络通讯软件时用的方法不同。但是当我分析过3个完成端口的程序后,基本了解的它的使用方法。而且在懂以后,回过头来看,其它完成端口的概念也不是很复杂,只要能清楚的了解几个函数的使用方法以及基本的处理框架流程,你就会发现它其实非常的简单。& &完成端口的一些需要理解的地方:1。消息队列2。工作线程3。网络消息返回结构体& &一般我们在设计服务器端的时候,最关键的地方是如何分辩刚刚收到的网络数据是由那个玩家发送过来的,如果是采用消息事件驱动的话,是可以得到一个socket的值,然后再用这个值与系统里存在的socket进行比对,这样就可以得到是那位玩家发送过来的游戏消息。我在还没有使用完成端口的时候,就是使用这个方法。这样的设计有一个缺点就是每次收到数据的时候回浪费很多时间在于确定消息发送者身份上。但是在完成端口的设计里,我们可以采用一个取巧的方法进行设计。所以,这个问题很轻易的就结局了,而且系统开销也不是很大,关于完成端口,可以参考一下的文章:《关于Winsock异步I/O模型中的事件模型》http://search.csdn.net/Expert/topic/166/166227.xml?temp=.4639093《手把手教你玩转SOCKET模型之重叠I/O篇》http://blog.csdn.net/piggyxp/archive//114883.aspx《学习日记]的学习--初步理解》/bbs/showthread.asp?threadid=25898《用完成端口开发大响应规模的Winsock应用程序》http://www.xiaozhou.net/ReadNews.asp?NewsID=901《理解I/O Completion Port》/Program/Control/IOCP.htm几个关键函数的说明:/library/en-us/fileio/fs/postqueuedcompletionstatus.asp?frame=true/library/en-us/fileio/fs/createiocompletionport.asp?frame=true/library/en-us/fileio/fs/getqueuedcompletionstatus.asp?frame=true/library/en-us/winsock/winsock/wsarecv_2.asp?frame=true如果你能认真的搞清楚上面的东西,我估计你离理解完成端口就只有一步了。剩下的这一步就是自己编码实现一个下了。有些时候,看得懂了不一定会实际应用,不实实在在的写一点程序,验证一下你的想法,是不会真正搞清楚原理的。不过除非你想深入的研究网络技术,否则只要知道怎么用就可以了,剩下的就是寻找一个合适的别人封装好的类来使用。这样可以节省你很多的事件,当然拿来的东西最好有源代码,这样如果发生什么问题,你也好确定是在那个地方出错,要改或者扩充功能都会方便很多。当然,还要注意人家的版权,最好在引用别人代码的地方加一些小小的注解,这样用不了多少时间,而且对你,对原作者都有好处^_^。不过在完成端口上我还是没有成为拿来主义者,还是自己封装了完成端口的操作,原因找到的源代码代码封装的接口函数我怎么看怎么觉得别扭,所以最后还是自己封装了一个完成端口,有兴趣的可以去看我的源代码,里面有很详细的注解。而且就我看来,要拿我封装的完成端口类使用起来还是很简单的。使用的时候,只要继承我的CIOCP,然后,根据需要覆盖3个虚函数(OnAccept,OnRead,OnClose)就可以了,最多是在连接函数里,需要用一个函数去设置一下完成端口信息。当然,我封装的类稍微简单了一些,如果要拿来响应大规模连接,还是存在很多的问题,但是如果只是针对少量连接,还是可以应付的。对于客户端的I/O模型,我就没有那么用心的去寻找什么好的解决方案,采用了一个最简单的,最原始的阻塞线程的方法做。原理很简单:创建一个sockt,把socket设置为阻塞,连接服务器成功后,启动一个线程,在线程里面用recv()等待服务器发过来的消息。在我的代码里,也是把阻塞线程的方法封装成一个类,在使用的时候,先继承TClientSocket,然后覆盖(重载)里面的OnRead()函数,并在里面写入一些处理收到数据后的操作代码。在用的时候,只要connect成功,系统就会自动启动一个接收线程,一旦有数据就触发刚才覆盖的OnRead函数。这个类我也不是完全直接写的,在里面使用了别人的一些代码,主要是让每个类都能把线程封装起来,这样在创建不同的类的实体的时候,每个类的实体自己都会有一个单独的数据接收线程。当然除了阻塞线程的方法,比较常用的还有就是用消息事件的方法收取数据了。我刚开始的时候,也是采用这个方法(以前用过^_^),但是后来发现不太好封装,最后采用阻塞线程的方法,这样做还有一个好处可以让我的代码看起来更加舒服一些。不过就我分析《航海世纪》客户端采用的是消息事件的I/O模型。其它的网络游戏就不太清楚了,我想也应该是采用消息事件方式的吧。。& &我记得在gameres上看到过某人写的一篇关于完成端口的笔记,他在篇末结束的时候,提出一个思考题:我们在学习完成端口的时候,都知道它是用于server端的操作,而且很多文章也是这样写的,但是不知道有没有考虑过,用完成端口做客户端来使用?& &其实这个问题很好回答,***是OK。拿IOCP做客户端也是可行的,就以封装的IOCP为例,只要在继承原来的CIOCP类的基础上,再写一个Connect(char * ip, int port)的函数,就可以实现客户端的要求了。
bool&CIOCPClient::Connect(char&*ip,&int&port) &&{ &&&&&&&&&&&&&&&&&&if&(!bInit) &&&&&&&&&&&&if&(!Init()) &&&&&&&&&&&&&&&&return&false; &&&&&&&&&&&&&&SOCKET&m_socket&=&socket(AF_INET,&SOCK_STREAM,&IPPROTO_TCP); &&&&&&&&if&(m_socket&==&SOCKET_ERROR) &&&&&&&&&&return&false; &&&&&&&&&&&&&&&&sockaddr_in&ClientA &&&&&&&&ClientAddr.sin_family&=&AF_INET; &&&&&&&&ClientAddr.sin_port&=&htons(port);&&&& &&&&&&&&ClientAddr.sin_addr.s_addr&=&inet_addr(ip); &&&&&&&&&&&&bind(m_socket,&(SOCKADDR&*)&ClientAddr,&sizeof(ClientAddr)); &&&&&&&&if&(connect(m_socket,&(SOCKADDR&*)&ClientAddr,&sizeof(ClientAddr))&==&SOCKET_ERROR) &&&&&&&&&&&&return&false; &&&&&&this-&m_workThread&=&true; &&&&&&&&&&&&g_hwThread&=&CreateThread(NULL,&0,&WorkThread,&(LPVOID)this,&0,&&m_wthreadID);&&&&&&&&this-&SetIoCompletionPort(m_socket,&NULL);&&&&&&&&return&true; &&&&} && bool CIOCPClient::Connect(char *ip, int port)
& & & &// &连接服务器
& &if (!bInit)
& & & &if (!Init())
& & & & & &
& &// &初始化连接socket
& &SOCKET m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
& &if (m_socket == SOCKET_ERROR)
& &// 填写服务器地址信息
& &sockaddr_in ClientA
& &ClientAddr.sin_family = AF_INET;
& &ClientAddr.sin_port = htons(port); & &
& &ClientAddr.sin_addr.s_addr = inet_addr(ip);
& &// 绑定***端口
& &bind(m_socket, (SOCKADDR *)&ClientAddr, sizeof(ClientAddr));
& &if (connect(m_socket, (SOCKADDR *)&ClientAddr, sizeof(ClientAddr)) == SOCKET_ERROR)
& &this-&m_workThread =
& &g_hwThread = CreateThread(NULL, 0, WorkThread, (LPVOID)this, 0, &m_wthreadID); &// &创建工作线程,用来处理完成端口消息的
& &this-&SetIoCompletionPort(m_socket, NULL); &// &设置完成端口***的socket
前面一段是用来连接服务器,所有的客户端程序都是要这样做的,当连接成功后,m_socket就是我们想要的用于与服务器端通讯的socket,然后,我们启动工作线程,并使用SetIoCompletionPort来设置完成端口***的socket。只要在原来的基础上增加一个函数,就可以把用于服务器的ICOP变成用于客户端的IOCP。& &在收到网络数据以后,下一步就是根据需要,把收到的网络数据包转变为游戏消息数据包。在转换之前,首先是要从收到的网络数据里面提取出有效的消息。这里为什么说是要提取有效部分?其主要原因是,我们创建的游戏消息数据,在进行网络传输的时候,不是以消息的长度来传的,而是根据系统在接收到发送数据请求的时候,根据实际情况来发送的。例如我这里有一条很长的游戏消息,有3k,但是系统一次只能发送1k的数据,所以,我们的游戏消息,只能把我们的游戏消息分为3个包,分3次发送,这样在我们接收消息的时候,就会触发3次OnRead,而这3次OnRead收到的数据都不是一次完整的游戏消息。所以,我们在收到网络数据后,要先和上一次收到的网络数据进行合并,然后再在里面提取出有效的游戏消息,并在提取后,把已经提取的部分删除。我在这里把这一步操作封装到一个类里CBuftoMsg。这里顺便说明一下:一条游戏消息的网络数据包是以0x00EEEE(16进制)为结束标记(《航海世纪》的做法)。
struct&TMessage &&&&{ &&&&&&&&char&*&p;&&&&&&&&&&&&&&&&&&&long&&&&&&&&&&&&&&&&}; &&&&&&&&&&& &&&&&&class&CBuftoMsg &&&&&&&&{ &&&&&&&&protected: &&&&&&&&&&&&char&msgbuf[BUF_LEN];&&& &&&&&&&&&&&&char&*&buf_ &&&&&&&&&&&&char&*&buf_ &&&&&&&&&&&&int&buf_ &&&&&&&&public: &&&&&&&&&&&&CBuftoMsg(void); &&&&&&&&&&&&TMessage&getMessage(void); &&&&&&&&&&&&void&cleanup_buf(void); &&&&&&&&&&&&bool&AddMsgBuf(const&char&*,&int); &&&&&&&&&&&&int& &&&&&&&&}; &&&&&&&&&&& &&&&&&CBuftoMsg::CBuftoMsg(void) &&&&&&&&{ &&&&&&&&&&&&buf_begin&=& &&&&&&&&&&&&buf_end&=& &&&&&&&&&&&&buf_len&=&0; &&&&&&&&} &&&&&&&&&&& &&&&&&TMessage&CBuftoMsg::getMessage() &&&&&&&&{ &&&&&&&&&&&&char&*&p&&&&=&buf_ &&&&&&&&&&&&TMessage& &&&&&&&&&&&&result.len&&=&0; &&&&&&&&&&&&result.p&&&&=&NULL; &&&&&&&&&&&&while(p&&=&buf_begin&+&buf_len&-&2) &&&&&&&&&&&&{ &&&&&&&&&&&&&&&&if&(&*p&==&0x00) &&&&&&&&&&&&&&&&{ &&&&&&&&&&&&&&&&&&&&const&static&char&ce&=&0xEE; &&&&&&&&&&&&&&&&&&&&if&(*(p&+&1)&==&ce) &&&&&&&&&&&&&&&&&&&&&&&&if(*(p&+&2)&==&ce) &&&&&&&&&&&&&&&&&&&&&&&&{ &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&result.p&&&&=&buf_ &&&&&&&&&&&&&&&&&&&&&&&&&&&&result.len&&=&p&-&buf_begin&+&3; &&&&&&&&&&&&&&&&&&&&&&&&&&&&buf_begin&&&=&&p&+&3; &&&&&&&&&&&&&&&&&&&&&&&&&&&&buf_end&&&&&=&buf_begin&+&buf_ &&&&&&&&&&&&&&&&&&&&&&&&&&&&buf_len&-=&result. &&&&&&&&&&&&&&&&&&&&&&&&&&&&break; &&&&&&&&&&&&&&&&&&&&&&&&} &&&&&&&&&&&&&&&&} &&&&&&&&&&&&&&&&p++; &&&&&&&&&&&&} &&&&&&&&&&&&return& &&&&&&&&} &&&&&&&&&&& &&&&&&void&CBuftoMsg::cleanup_buf() &&&&&&&&{ &&&&&&&&&&&&if&(buf_len&&&BUF_LEN) &&&&&&&&&&&&{ &&&&&&&&&&&&&&&&if&(buf_len&==&0) &&&&&&&&&&&&&&&&{ &&&&&&&&&&&&&&&&&&&&buf_begin&&&=& &&&&&&&&&&&&&&&&&&&&buf_end&&&&&=& &&&&&&&&&&&&&&&&} &&&&&&&&&&&&&&&&else&&&&&&&&&&&&&&&&{ &&&&&&&&&&&&&&&&&&&&memmove(msgbuf,&buf_end&-&buf_len,&buf_len); &&&&&&&&&&&&&&&&&&&&buf_begin&=& &&&&&&&&&&&&&&&&&&&&buf_end&=&buf_end&-&buf_ &&&&&&&&&&&&} &&&&&&&&&&} &&&&&&&&else&&&&&&&&{ &&&&&&&&&&&&&&&&&&&&&&&&buf_begin&&&=& &&&&&&&&&&&&buf_end&&&&&=& &&&&&&&&&&&&buf_len&&&&&=&0; &&&&&&&&} &&&&} &&&&bool&CBuftoMsg::AddMsgBuf(const&char&*&buf,&int&len) &&{ &&&&&&&&if&(len&&&1) &&&&&&&&&&&&return&false; &&&&&&&&bool&result&=&true; &&&&&&&&buf_len&+=& &&&&&&&&if&(buf_len&&=&BUF_LEN)&&&&&&&&&&&{ &&&&&&&&&&this-&cleanup_buf();&&&& &&&&&&&&&&result&=&false; &&&&&&&&} &&&&&&&&memcpy(buf_begin,&buf,&len); &&&&&&&&return& &&&&} &&&& struct TMessage
& &char * & & & // &消息头所在的位置
& & & & & // &整个消息的长度
class CBuftoMsg
protected:
& &char msgbuf[BUF_LEN]; &
& &char * buf_
& &char * buf_
& &int buf_
& &CBuftoMsg(void);
& &TMessage getMessage(void);
& &void cleanup_buf(void);
& &bool AddMsgBuf(const char *, int);
CBuftoMsg::CBuftoMsg(void)
& &buf_begin =
& &buf_end =
& &buf_len = 0;
TMessage CBuftoMsg::getMessage()
& &char * p & &= buf_
& &result.len &= 0;
& &result.p & &= NULL;
& &while(p &= buf_begin + buf_len - 2)
& & & &if ( *p == 0x00)
& & & & & &const static char ce = 0xEE;
& & & & & &if (*(p + 1) == ce)
& & & & & & & &if(*(p + 2) == ce)
& & & & & & & &{
& & & & & & & & & &// &每条消息都是以 00 EE EE 为结束标志
& & & & & & & & & &result.p & &= buf_
& & & & & & & & & &result.len &= p - buf_begin + 3;
& & & & & & & & & &buf_begin & = &p + 3;
& & & & & & & & & &buf_end & & = buf_begin + buf_
& & & & & & & & & &buf_len -= result.
& & & & & & & & & &
& & & & & & & &}
& & & &p++;
void CBuftoMsg::cleanup_buf()
& &if (buf_len & BUF_LEN)
& & & &if (buf_len == 0)
& & & & & &buf_begin & =
& & & & & &buf_end & & =
& & & &else
& & & & & &memmove(msgbuf, buf_end - buf_len, buf_len);
& & & & & &buf_begin =
& & & & & &buf_end = buf_end - buf_
& & & &// &加入缓冲区的数据过多,要抛弃原来的内容
& & & &buf_begin & =
& & & &buf_end & & =
& & & &buf_len & & = 0;
bool CBuftoMsg::AddMsgBuf(const char * buf, int len)
& &if (len & 1)
& &bool result =
& &buf_len +=
& &if (buf_len &= BUF_LEN) & & // &如果缓冲区装满了则直接把原来的缓冲区清空再重新复制数据
& & & &this-&cleanup_buf(); & &
& & & &result =
& &memcpy(buf_begin, buf, len);
我在这里把 CBuftoMsg 的代码贴出来,主要是因为,我在写本文的时候,发现一个惊天动地的bug,有兴趣的读者可以自己去找一下。不过一开始写代码的时候,还不是这样的,当初的代码bug比这个还要多,问题还要严重,严重到经常让服务器程序莫名其妙的崩溃,而且这个问题,一直到5月份,系统在进行集成测试的时候才发现并解决(还没有彻底解决,至少目前我还发现了bug,),以前一直都没有怎么注意到这个问题,而且我们还把因为这个bug造成的问题,归结到线程的互斥上去^_^!我的登陆服务器,除了基本的处理网络数据包以外,还负责玩家系统的登陆验证,这部分东西不是很复杂,在我的程序里,只是简单的从ini文件里读取玩家的信息而已,有兴趣的自己去看我的代码(不过这部分远还没有真正的完善,存在很多问题)。除了登陆验证以外,在登陆程序还负责进行消息转发,就是把客户端的消息分别发送到不同的服务器。如果当初设计的是一个逻辑服务器,这个功能就可以简单很多,只要发送到一个服务器里就可以了。现在的要发到2个服务器,所以还需要对收到的游戏消息进行分类。为了方便,我对原来定义消息的ID进行了分类,所以,在GameMessageID.***件里定义的游戏消息对应的ID编号不是顺序编排的。不过也因为这样,在现在看来,这样的设计,有一些不太好。在整个系统里,存在有4个主体,他们之间互相发送,就用了12组的数据,为了方便计算,我把一个变量的范围分为16个不同的区域,这样每个区域只有16个值可以用(我这里是用char类型256/16=16)。在加上用另外一个变量表示逻辑上上的分类(目前按照功能分了12组,有登陆、贸易、银行、船厂等)这样对于贸易这个类型的游戏消息,从客户端发送到逻辑服务器上,只能有16中可能性,如果要发送更多消息,可能要增加另外一个逻辑分类:贸易2^_^!当初这样的设计只是想简化一下系统的处理过程,不过却造成了系统的扩充困难,要解决也不是没有办法,把类型分类的变量由char类型,改为int类型,这样对一个变量分区,在范围上会款很多,而且不会造成逻辑分类上的困扰,但是,这样存在一个弊端就是就是每条网络消息数据包的长度增加了一点点。不要小看这一个字节的变量,现在设计的一条游戏消息头的长度是10个字节,如果把char改为int,无形中就增加了3个字节,在和原来的比较,这样每条消息在消息头部分,就多出23%,也就是我们100M的网络现在只能利用77%而已。& &^_^呵呵看出什么问题没有?& &没有,那我告诉你,有一个概念被偷换了,消息头的数据不等于整条游戏的消息数据,所以,消息头部分虽然多出了23%,但是整条游戏消息并不会增加这么多,最多增加17%,最少应该不会操作5%。平均起来,应该在10%左右(游戏消息里,很多消息的实际部分可能就一个int变量而已)。不过,就算是10%,也占用了带宽。& &^_^呵呵还看出什么问题没有?& &^_^先去读一下我的代码,再回头看看,上面的论述还有什么问题。& &实际上,每条游戏消息由:消息头、消息实体、结束标记组成,其中固定的是消息头和结束标记,所以,实际上一条实际上游戏消息的数据包,最多比原来的多15%,平均起来,应该是8%~10%的增量而异。& &好了,不在这个计算细节上扣太多精力了。要解决这个问题,要么是增加网络数据的发送量,要么,就是调整游戏结构,例如,把两个功能服务器合并为一个服务器,这样服务器的对象实体就由原来的4个分为3个,两两间的通讯,就由原来的12路缩减为6路,只要分8个区域就ok了。这样每个逻辑分类就有32条游戏消息可以使用。当然,如果进一步合并服务器,把服务器端都合并到一个程序,那就不用分类了^_^!& &在登陆服务器目录下,还有一组mynet.h/mynet.cpp的文件,是我当初为服务器端设计的函数,封装的是消息事件网络响应模型。只不过封装得不是怎么好,被抛弃不用了,有兴趣的可以去看看,反正我是不推荐看的。只不过是在这里说明一下整个工程目录的结构而已。
阅读(...) 评论()您现在的位置: >>
>> 电信网络割接 部分服务器受到影响
电信网络割接 部分服务器受到影响
致《西游》玩家:
电信将于日进行网络割接,受此影响,届时《》部分服务器将可能会出现无法登陆现象,预计维护时间为9月27日(周三)06:00——06:30,如果在预定时间内未完成升级内容,维护时间也将继续顺延。请各位玩家相互转告,并提前留意游戏时间。由此给玩家带来的不便,敬请谅解,网易游戏感谢所有玩家的支持和配合。
可能受到影响的服务器包括:
安徽区:莲花峰、慈光阁、九华山、天门山、点将台、采石矶、琅琊山、 紫蓬山、寿州窑
福建1区:东山岛、朱紫坊、仙人渡、胡里山、石鼓山
福建2区:白鹭洲、湄洲岛、九日山、日光岩、齐云楼、天后宫、鼓浪屿 百花村、清源山、武夷山
广东1区:石景山、九洲岛、梅溪坊、清晖园、湖光岩
广东2区:锦绣园、镇海楼、万绿湖、南澳岛、天堂顶、三元塔、桑浦山 七星岩、如意岛、越秀山、鼎湖山、进贤门、南昆山
广东3区:罗浮山、广济桥、丹霞山、隐贤山庄、南华寺、海陵岛、
广东4区:流溪河、宝墨园、流花湖、三百洞、光孝寺、状元坊、黄花岗 白云山、佛山梁园、三元里
广西1区:青秀山、明秀园、通灵峡、真武阁、扬美古镇
广西2区:桃花江、还珠洞、黄姚古镇、龙城郡、雀儿山、八角寨、
海外专区: 侠客岛
河北3区:赵州桥
河南2区:少室山
湖北1区:长坂坡、武当山、东湖园、昭君台
湖北2区:望江亭、晴川阁、大别山、荆州古城、赤壁古城、天堂寨、
行吟阁、黄鹤楼、神农架、盘龙城、古琴台、长春观
湖南区:洞庭湖、南岳衡山、凤凰古镇、岳阳楼、张家界、白鹤泉、
柳叶湖、观竹楼、韶山冲
华北区:摘星台
华南区:千寻塔、清幽谷、动感地带、天上人间、日月湾、忘忧谷、
江苏1区:红梅阁、大鹿岛
江苏2区:十里秦淮、紫金山、姑苏城、玄武湖、夫子庙、虎丘山、
北固山、寄畅园、东林书院、沧浪亭、朝
江苏3区:花果山、水帘洞、狮子山、锦屏山、云龙山、烟雨楼、云龙湖
江西区: 井冈山、三清山、百花洲、庐山胜境、滕王阁、鄱阳湖
山东5区:灵岩山
山西区:云岗石窟、平遥古城
陕西区:钟鼓楼、定军山、拜将坛、小雁塔
上海1区:天马山、长兴岛、玉玲珑、晚芳亭、宝光塔、天福楼、城隍庙上海老街、飘香榭、珍宝阁
上海2区:崇明岛、朱家角、东方明珠、上海滩、黄浦江、汇龙潭
深圳1区:红树林、香蜜湖、观澜湖、石岩湖、大观园、金沙湾、莲花山 园博园
深圳2区:青青世界、小梅沙、梧桐山、欢乐谷、世界之窗、大梅沙、
民俗村、锦绣中华
四川2区:西岭雪山、青羊宫、文殊院、万胜府、老君阁、峨眉山、
都江堰、光明顶、青城山、天经阁、合江门
西北区:火焰山、通天河、可可西里
西南区:夜郎之都、彩云之南、昆明湖
月光宝盒:花样年华、黄金时代、群英荟萃、小憩园、缤纷岁月
浙江1区:烟雨南湖
浙江2区:六和塔、天台山、西子湖、苏堤春晓、飞来峰、虎跑泉、
曲院风荷、映月湖、雷峰塔、灵隐寺
浙江4区:三味书屋、会稽山、楠溪江、玉苍山、百草园、绍兴鉴湖、
物华天宝、雁荡山、越王台、绍兴兰亭、温州泽雅
重庆区:枇杷山、宝顶山、解放碑、朝天门、歌乐山
追忆:再续前缘、梦回望月、梦回奔日、青山绿水、地久天长、梦回唐朝长青树
官方链接:《梦幻西游》官方网站:
《梦幻西游》官方论坛:
客户端下载链接:
《梦幻西游》是以神话题材《西游记》为背景,采用最流行的Q版风格打造出来的浪漫型网游,整个游戏都渗透着青春活力的气息。崭新的画风、风趣的对白、精密的门派平衡、引人入胜的任务、优良的系统设计,全都贯穿于整个游戏之中,网易出色的研发力量,更加懂得把握玩家心理的设计理念,使得《梦幻西游》成为目前国内同时在线人数最多的超人气MMORPG网络游戏,目前注册人数超过9900万 ,最高同时在线人数突破131万,一共开设收费服务器达452组。
防盗提示:《梦幻西游》的官方网站是,除此之外的任何涉及《梦幻西游》游戏的网站我们都不保证其安全性。 《梦幻西游》,浪漫相聚每一天!
网易互动娱乐有限公司
梦幻西游开发组

参考资料

 

随机推荐