我有一个基于Meteor框架构建的游戏。一个游戏文档是这样的:
{
...
participants : [
{
"name":"a",
"character":"fighter",
"weapon" : "sword"
},
{
"name":"b",
"character":"wizard",
"weapon" : "book"
},
...
],
...
}
我希望战斗机角色看不到"b"用户的字符。(和 b 字符看不到 a(大约有10个字段,如角色和武器,它们的值可以在游戏中发生变化,因此受到限制。
现在我正在使用会话变量来不显示该信息。但是,这不是一个非常安全的想法。如何根据基于字符的值订阅/发布文档?
想到了 2 种可能的解决方案:1.发布不同字段值的所有组合,并根据用户的当前状态进行订阅。但是,我正在使用Iron Router的waitOn功能在渲染页面之前加载订阅。所以我不太有信心我可以在游戏期间更改订阅。另外因为它是一款对时间敏感的游戏,我想更改订阅会在游戏过程中花费一些时间并破坏游戏乐趣。
我现在的问题是用户输入
Collection.find({}(
到控制台并查看其他用户的字段。如果我将我的集合名称更改为难以找到的名称,有人可以发现集合名称吗?我找不到在客户端查找集合的命令。
Meteor 中通常解决这个问题的方式是使用两个出版物。如果您的游戏状态由单个文档表示,则可能无法轻松实现它,因此为了举例说明,我将暂时假设您有一个存储相应数据的Participants
集合。
因此,无论如何,您应该有一个订阅,其中包含所有玩家可用的数据,例如
Meteor.publish('players', function (gameId) {
return Participants.find({ gameId: gameId }, { fields: {
// exclude the "character" field from the result
character: 0
}});
});
以及私人玩家数据的另一个订阅:
Meteor.publish('myPrivateData', function (gameId) {
// NOTE: not excluding anything, because we are only
// publishing a single document here, whose owner
// is the current user ...
return Participants.find({
userId: this.userId,
gameId: gameId,
});
});
现在,在客户端,您唯一需要做的就是订阅这两个数据集,因此:
Meteor.subscribe('players', myGameId);
Meteor.subscribe('myPrivateData', myGameId);
Meteor 将足够聪明地将传入的数据合并到一个Participants
集合中,其中其他玩家的文档将不包含character
字段。
编辑
如果您的字段可见性将动态变化,我建议采用以下方法:
- 将所有受限制的属性放在一个单独的集合中,该集合可以准确跟踪谁可以查看哪个字段
- 在客户端使用
observe
将该集合集成到本地玩家表示中,以便更轻松地访问数据
数据模型
例如,集合可能如下所示:
PlayerProperties = new Mongo.Collection('playerProperties');
/* schema:
userId : String
gameId : String
key : String
value : *
whoCanSee : [String]
*/
发布数据
首先,您需要向每个玩家公开自己的属性
Meteor.publish('myProperties', function (gameId) {
return PlayerProperties.find({
userId: this.userId,
gameId: gameId
});
});
然后其他玩家属性:
Meteor.publish('otherPlayersProperties', function (gameId) {
if (!this.userId) return [];
return PlayerProperties.find({
gameId: gameId,
whoCanSee: this.userId,
});
});
现在,您在游戏过程中唯一需要做的就是确保在用户能够看到该属性后立即将相应的userId
添加到whoCanSee
数组中。
改进
为了使您的数据井井有条,我建议仅收集客户端,例如 IntegratedPlayerData
,您可以使用它将播放器属性排列成某种可管理的结构:
var IntegratedPlayerData = new Mongo.Collection(null);
var cache = {};
PlayerProperties.find().observe({
added: function (doc) {
IntegratedPlayerData.upsert({ _id : doc.userId }, {
$set: _.object([ doc.key ], [ doc.value ])
});
},
changed: function (doc) {
IntegratedPlayerData.update({ _id : doc.userId }, {
$set: _.object([ doc.key ], [ doc.value ])
});
},
removed: function (doc) {
IntegratedPlayerData.update({ _id : doc.userId }, {
$unset: _.object([ doc.key ], [ true ])
});
}
});
这种数据"集成"只是一个草案,可以通过许多不同的方式进行优化。它可能会在服务器端使用自定义发布方法完成。