server::run()一些注释
1、network::accept_connect是非阻塞等待。
2、string_ip:本机连接时是127.0.0.1。
3、reason:空。指示accept_connect过程没有发生错误。
4、sock:为此个客户端服务的sock。
处理登陆
登陆分两个步骤,分别对应两个包:(process_login处理这两个包)
1、[version]version="0.1.4"[/version]
2、[login]selective_ping="1"username="ancientcc2"[/login]
处理游戏大厅
游戏大厅触发的动作:(process_data_lobby处理这些个动作)
创建:[create_game]name="ancientcc2xxxxx"[/create_game]
第二个消息
"#textdomain wesnoth-multiplayer
description=_ "These caves were once the lair of Chak'kso Ney'yks, a legendary Elder Basilisk. The petrified forms of his victims remain as monuments to his savage power."
experience_modifier="70"
id="multiplayer_Basilisk"
map_data="border_size=1
usage=map
_off^_usr , _off^_usr , _off^_usr , _off^_usr , _off^_usr , _off^_usr , _off^_usr , char *
加入:[join]id="1"observe="no"[/join]
<要加入的是ancientcc>
第二个消息:
[scenario_diff]
[change_child]
index="1"
[side]
[insert]
current_player="ancientcc"
name="ancientcc"
player_id="ancientcc2"
save_id="ancientcc2"
user_description="ancientcc"
[/insert]
[delete]
id="x"
[/delete]
[/side]
[/change_child]
[/scenario_diff]
第三个消息
[change_faction]
faction="0"
gender="null"
leader="random"
name="ancientcc"
[/change_faction]
观察:[join]id="3"observe="yes"[/join]
<要加入的是ancientcc1>
一、网络数据的压缩和解压缩
玩家发来命令,服务器转发向玩家命令,服务器产生事件,都是以压缩过形式在网络上流通。document封装一条命令/事件,内部操作支持了解缩和解压缩。注:这个一条是相对的,它可能是数条命令合成的一条命令,像send_history后形成的document。
要知道压缩和解压缩大概是怎么个过程首先就要了解document对象几个成员,它大概存储了什么内容。
@compressed_buf:已压缩过数据。这往往是直接从网络上收到的数据。这个构造函数作就是根据网络上收到数据恢复出命令。 document::document(string_span compressed_buf) : compressed_buf_(compressed_buf), output_(NULL), buffers_(), root_(NULL), prev_(NULL), next_(NULL) { string_span uncompressed_buf; // uncompress_buffer执行解压缩,解压缩后的数据放在从堆中分配出的一块内存 buffers_.push_back(uncompress_buffer(compressed_buf, &uncompressed_buf)); output_ = uncompressed_buf.begin(); const char* cbuf = output_; try { root_ = new node(*this, NULL, &cbuf); } catch(...) { delete [] buffers_.front(); buffers_.clear(); throw; } attach_list(); } 至此大概可以总结下各个成员意义 compressed_buf_:压缩过数据。 buffers_:数据存储缓冲。它是一个vector,它的[0]存储的是未压缩过数据,[1]存储的是压缩过数据。注意下这两个数据都被从堆中分配,析构时要delete。 output_:未压缩过数据。 root_:<尚未理解>
程序往往要遍历历史命令,这个遍历是通过把命令组织在一个链表,attach_list()作用就这是把这个命令放入链表。下图是使用的链表结构

send_history会遍历所有历史命令(但它不是通过链表),并在遍历时把所有命令合成一条命令,形成一个新的document
功能:把历史记录发向sock指定玩家。 注:在发送过程中,它会把原有记录合成一条记录,再写回历史容器 void game::send_history(const network::connection sock) const { if(history_.empty()) { return; } //we make a new document based on converting to plain text and //concatenating the buffers. //TODO: Work out how to concentate buffers without decompressing. std::string buf; for(std::vector<simple_wml::document*>::iterator i = history_.begin(); i != history_.end(); ++i) { // (*i)->output()返回是未压缩过数据 buf += (*i)->output(); delete *i; } try { simple_wml::document* doc = new simple_wml::document(buf.c_str(), simple_wml::INIT_STATIC); const simple_wml::string_span& data = doc->output_compressed(); // 压缩 doc->compress(); network::send_raw_data(data.begin(), data.size(), sock,"game_history"); history_.clear(); history_.push_back(doc); } catch (simple_wml::error& e) { WRN_CONFIG << __func__ << ": simple_wml error: " << e.message << std::endl; } }
二、FAQ
A:如何让0.1.6的客户端登陆进1.9.x的服务器?
Q:修改multiplayer.cpp中的open_connection(...),
if(data.child("version")) { config cfg; config res; cfg["version"] = game_config::version; res.add_child("version", cfg); network::send_data(res, 0, true); } cfg["version"] = game_config::version改为cfg["version"] = "0.1.5";
A:登陆后,如何让0.1.6的客户端使用1.9.x的服务器?
Q:使用后要做到:
1、kingdom客户端不能“加入”、“观察”wesnoth创建游戏。
2、wesnoth客户端不能“加入”、“观察”kingdom创建游戏。
实现方法:
创建游戏时会发送[create_game]块,[create_game]中除了name字段可以有password。让kingdom创建游戏时使用一个固定密码(会使用checksum),客户端要加入需要这个密码。kingdom客户端会自动给出这个密码,wesnoth客户端则要求这个密码,但不知道这个密码无法“加入”、“观察”这个游戏。
改了era,让wesnoth客户端都认为是“未知时代”,以灰掉“加入”、“观察”按钮。
A:创建的游戏中含有较验码,避免客户端配置文件不一致的玩同一个剧本?
Q:
三、对韦诺之战服务器代码做的修改
服务器尽量会做到和韦诺之战服务器通用。能不改的尽量不改。
server::read_config()
当中要读服务器配置,这个配置往往被放在My Documents目录下,而在Windows下这个目录往往带中文,这时需要能解析中文目录名的读文件函数。
scoped_istream stream = preprocess_file(config_file_); 改为 scoped_istream stream = istream_file(config_file_, true);
对于“建立联网游戏”,它是启动游戏时自动启动服务器,这时要读取的配置文件往往是放在My Documents目录下。