题
你会怎么模型把一个游戏服务器作为一个宁静的API?例如,一个国际象棋服务器,在哪里你可以玩一个游戏的棋对另一个客户相同。你会需要某种方式的请求和谈判一个游戏与其他客户,以及一些方式播放的人移动的游戏。
这是一个很好的候选人的其余部分(安宁)API?或应该是仿照一种不同的方式?
解决方案
您尝试建模的资源有哪些?我似乎有四个:你,你的对手,特定的游戏(会话,实例)和游戏板状态。所以它会从像
这样的东西开始/game
/game/gameID/gamer/gamerID
/game/gameID/board
我们在 InfoQ 上有一个很好的介绍/概述。
其他提示
我在想:
/game/<gameID>/move/<moveID>
就基本资源而言。我不确定如何处理“让其他玩家移动了吗?”但是,这个想法。我已经考虑过简单地进行GET请求阻止,直到进行移动 - 即。我的客户会将我移动的坐标设为
/game/13/move/1
然后GET
/game/13/move/2
服务器不会立即响应,但保持连接打开,直到其他玩家移动(即PUT到该位置)。这是nakajima所指的“彗星式”吗?
查理,我不太确定你所说的“令牌”是什么意思。为了轮到它 - 这是否解决了相同的问题,而无需轮询或阻塞连接?对于玩家ID,将这些作为部分URL的资源进行建模是否有意义?我打算简单地使用HTTP用户身份验证(用户/传递作为每个请求的一部分发送)。您仍然可以在没有身份验证的情况下获取大多数资源,但是如果您尝试了,那么,
PUT /game/13/move/2
如果你没有该游戏的正确凭据,它会给你一个权限被拒绝的错误。 好的,基本思想的其余的是你们转移的状态;你想到很少或没有"会议的国家"在服务器上。所以你不会想使用的话状态和保持活动,这是什么彗星。但是,认为有关的例的播放,通过邮件游戏:你们两个都有一个副本,董事会,和你交流动。邮局不知道的游戏。
现在,我承认这是生长在我的脑海里,因为我想想吧--事实上,我可以写一篇文章,基于这个问题--但这里的想法,因为一些故事:
- 你想玩一个游戏的棋上 行,让你去到一个已知的URI 得到一个。你回来一页 显示是谁,如果任何人,是等待 开始游戏。
- 你挑一个人在等着 播放和点击相应的 链接。你会得到一个新的显示器(阿贾克斯 魔法在这里如果你想要的)的 董事会设置的。你是白色, 白先走。
- 不管是谁都有权进入移动 一种移动,并承诺(如服 你的手离开这块在一个游戏。) 董事会更新和正确的 移动到其他播放机。
你什么都不需要多方面的服务器国家---尽管你可能想要扩大这种通过跟踪移动等,说为排名--的问题是谁有权的举动可以被计算的完全自委员会网页:如果你有权利的,你有一个形式为进入移动;当你发送的形式返回,响应返回某一页你有没有老虎为进入移动。
通过"令牌"我只是一些任意的表示,一位国家"我的动"/"你的移动"。
看来,如果你需要的资源是
- 一个"找到一个游戏"的主页
- 用户网页,如果你跟踪的统计数据 而这样的
- 一个独特的URI每一个活跃的游戏。
谢谢,查理。我还不清楚你如何得知对手在你的计划中的举动。当然,谁有权移动的问题可以简单地计算 - 从董事会资源,或通过使用明确说明轮到它移动的单独资源。但客户如何知道此资源已发生变化?是否必须继续轮询,记住以前的状态,直到它注意到某些事情发生了变化?在邮局模式中,邮局“推”了发送给客户端(您的邮箱)的消息,这在HTTP中是不可能的。
我认为这是一个更普遍的问题的一部分:如果有一个REST资源我想要监视更改或修改,那么最好的方法是什么?服务器可以做些什么来使客户更容易?
我认为我实际上会将此作为一个单独的问题发布,因为我认为它本身很有趣。
我不认为REST是这种应用程序的不错选择。您需要进行的转换和操作(移动,查看移动历史,撤消,获取建议,转向通知)不能巧妙地映射到REST的资源概念。 (如果考虑一个RESTful API如何用于更复杂的回合制游戏,如Scrabble或Monopoly,可能会更加明显。)
我认为任何合理的REST API都可能最终成为非RESTful内容的包装器,例如发送便携式游戏记谱法来回。
我认为你可以模拟它。 实施将会更加困难,因为您需要彗星) - 解决方案或者您必须通过AJAX以相对较短的间隔轮询服务器。
就你如何展示RESTful界面而言,我要说你需要一个带坐标的棋盘,可以占据这些坐标的棋子,以及改变这些坐标的动作。
当玩家进行移动时,将创建一个新动作。验证确认允许后,您将更新游戏状态,然后呈现更新UI所需的任何响应。
所以这基本上就是我的模型。实施方面是我认为这里面临的更大困难。
我不认为这一切都得到了证实,Nakajima。你可以传递数据,例如JSON,用于棋盘位置,移动,以及用于下一步移动的令牌。这就像通过邮件播放一样。
你首先去游戏并寻找合作伙伴,所以
/game/
为您提供等待的人员列表。当你进来时,如果没有人在等你就得到一个游戏ID;否则你会选择等待他人的游戏ID。
/game/gameID
显示了你的董事会。你需要一些东西来决定谁扮演白人的决定,我会把它作为一种练习。 GET操作为您提供了电路板,因此POST发送移动;如果你没有移动,你会收到错误。你可以在下一个GET找到结果。
天啊,在这个模型中,我甚至没有使用游戏玩家ID,虽然它可能是好的,所以没有人可以像kibitzer一样潜入游戏。
所以你的想法是,不是将动作作为第一类对象,而是将每一步都视为游戏本身的更新?这当然是一种不同的方式,但我认为我更倾向于将动作对象拆分为自己的第一类实体,原因有两个。最大的原因是我相信它更可测试。移动是否有效可以存在于操作对象中,而不需要担心电路板始终处于有效状态。当然,我不知道这两种方法会带来什么,但这对我来说感觉更好。
您可以通过YAGNI完全驳斥的另一个原因是,第一类动作对象将提供移动历史记录。或许有趣,但除非有要求,否则是一个没有实际意义的点。
planet.jabber 中的一位开发人员参与 Chesspark ,一个在线国际象棋社区。他们广泛使用Jabber / XMPP;如果我没弄错的话,请这些是他关于这个主题的帖子。
XMPP是一种即时消息传递协议,大致基于小型XML消息交换。有大多数语言的库,包括 Javascript。不过,我不确定它是否适合你的问题。
对于一个简单的游戏喜欢国际象棋,这是真的只是有关定义的mediatype.
这里是一个例子是可能是过度的简化mediatype模型国际象棋游戏。
我要跳过管理的多个游戏,可以在同一服务器上运行,模型只是一个已经在运行的游戏。
第一步通常是定义的一个指数的应用程序。
index
该入境点的游戏。获取这个发现的有关游戏的信息。
有效载荷可能看起来是这样的:
{
"links": {
"self": "http://my-chess-game.host/games/123",
"player": "http://my-chess-game.host/players/1",
"player": "http://my-chess-game.host/players/2",
"me": "http://my-chess-game.host/players/1",
...
}
"board": [
{
"x": 0,
"y": 1,
"piece": null,
"rel": "space",
"href": "http://my-chess-game/.../boards/123/0/1/something-random-to-discourage-uri-construction"
},
{
"x": 1,
"y": 2,
"rel": "space",
"href": "...",
"piece": {
"player": "http://my-chess-game/.../players/1",
"type": "http://my-chess-game/pieces/Bishop",
"rel": "piece",
"href": "http://my-chess-game/games/123/pieces/player1/Bishop/1",
"links": [
{ "rel": "move": "href": "http://my-chess-game/.../boards/123/..." },
...
]
}
},
...
]
}
move
后一JSON有效载荷的链接标有一个 rel
的 move
移动一块。以下领域必须包括:
- 位置:URI的空间移动到
成功的对策有一个地位代码200并将包含一个实体,该实体一样的 index
有效载荷的最新状态。
400如果不允许用户的移动他的一块还有,或者如果这不是他的转。
player
得到一个描述中的一员。
以下领域必须在响应:
- 用户名:用户名的球员
- href:URI识别玩这种游戏。
piece
碎片嵌入 index
有效载荷,但可能存在的自己。每 piece
必须具备以下领域:
- 类型:URI识别类型的一块。E.G.主教,车,国王。歌厅这URI可提供的信息关于如何这件作品内的国际象棋游戏.
- href:URI识别实际上这个委员会。得到请求这URI可以提供的信息有关这种特定的一块。
每一块都必须有一个 move
链接。
一个替代设计的决定,我可以在这里做的是提供一个链接对每个有效的移动。可能有很好的理由这样做,但我想表明它不是必需的。可能有极少数的其他资源的你想要包括处理的东西喜欢帮助客户确定其打开它是诸如此类的东西。
为更复杂的游戏,就像文明,RTSs,平价店,或社区和什么不可以,这可能不是这样实际海事组织。