I am working on a web application (ASP.NET) game that would consist of a single page, and on that page, there would be a game board akin to Monopoly. I am trying to determine what the best architectural approach would be. The main requirements I have identified thus far are:
我正在开发一个由单个页面组成的Web应用程序(ASP.NET)游戏,在该页面上,将有一个类似于Monopoly的游戏板。我想确定最好的架构方法是什么。到目前为止我确定的主要要求是:
- Up to six users share a single game state object.
- The users need to keep (relatively) up to date on the current state of the game, i.e. whose turn it is, what did the active user just roll, how much money does each other user have, etc.
最多六个用户共享一个游戏状态对象。
用户需要保持(相对)最新的游戏当前状态,即轮到它,活跃用户刚刚滚动什么,每个其他用户有多少钱等等。
I have thought about keeping the game state in a database, but it seems like overkill to keep updating the database when a game state object (say, in a cache) could be kept up to date. For example, the flow might go like this:
我曾考虑将游戏状态保存在数据库中,但是当游戏状态对象(例如,在缓存中)可以保持最新时,继续更新数据库似乎有些过分。例如,流程可能如下所示:
- Receive request for data from a user.
- Look up data in database. Create object from that data.
- Verify user has permissions to perform request based on the game's state (i.e. make sure it's really their turn or have enough money to buy that property).
- Update the game object.
- Write the game object back to the database.
- Repeat for every single request.
接收来自用户的数据请求。
在数据库中查找数据。从该数据创建对象。
验证用户是否有权根据游戏的状态执行请求(即确保轮到他们或者有足够的钱购买该属性)。
更新游戏对象。
将游戏对象写回数据库。
对每个请求重复一次。
Consider that a single server would be serving several concurrent games.
考虑单个服务器将服务几个并发游戏。
- I have thought about using AJAX to make requests to an an ASP.NET page.
- I have thought about using AJAX requests to a web service using silverlight.
- I have thought about using WCF duplex channels in silverlight.
我曾考虑过使用AJAX向ASP.NET页面发出请求。
我曾考虑过使用Silverlight将AJAX请求用于Web服务。
我曾想过在silverlight中使用WCF双工通道。
I can't figure out what the best approach is. All seem to have their drawbacks. Does anyone out there have experience with this sort of thing and care to share those experiences? Feel free to ask your own questions if I am being too ambiguous! Thanks.
我无法弄清楚最好的方法是什么。所有人似乎都有自己的缺点。有没有人有这方面的经验并且愿意分享这些经历?如果我太模糊,请随意问自己的问题!谢谢。
Update: Does anyone have any suggestions for how to implement this connection to the server based on the three options I mention above?
更新:根据我上面提到的三个选项,有没有人对如何实现与服务器的连接有任何建议?
3 个解决方案
#1
3
While updating a database seems like overkill, it has advantages when it comes time to scale up, as you can have multiple webheads talking to one backend.
虽然更新数据库看起来有点过分,但在扩展时它具有优势,因为您可以让多个网络头与一个后端进行通信。
A larger concern is how you communicate the game state to the clients. While a full update of the game state from time to time ensures that any changes are caught and all clients remain in synchronization even if they miss a message, gamestate is often quite large.
更大的问题是如何将游戏状态传达给客户。虽然游戏状态的不断更新可确保捕获任何更改并且所有客户端即使错过消息也保持同步,但游戏状态通常非常大。
Consider as well that usually you want gamestate messages to trigger animations or other display updates to portray the action (for example, of a piece moves, it shouldn't just appear at the destination in most cases... it should move across the board).
考虑一下,通常你希望游戏状态消息触发动画或其他显示更新来描绘动作(例如,一个棋子移动,它不应该只在大多数情况下出现在目的地......它应该在棋盘上移动)。
Because of that, one solution that combines the best of both worlds is to keep a database that collects all of the actions performed in a table, with sequential IDs. When a client requests an update, it can give all the actions after the last one it knew about, and the client can "act out" the moves. This means even if an request fails, it can simply retry the request and none of the actions will be lost.
因此,结合两者中最好的一个解决方案是保留一个数据库,该数据库收集表中执行的所有操作,具有顺序ID。当客户端请求更新时,它可以在它知道的最后一个操作之后给出所有操作,并且客户端可以“操作”移动。这意味着即使请求失败,它也可以简单地重试请求,并且不会丢失任何操作。
The server can then maintain an internal view of the gamestate as well, from the same data. It can also reject illegal actions and prevent them from entering the game action table (and thus prevent other clients from being incorrectly updated).
然后,服务器也可以从相同的数据维护游戏状态的内部视图。它还可以拒绝非法操作并阻止它们进入游戏操作表(从而防止其他客户端被错误更新)。
Finally, because the server does have the "one true" gamestate, the clients can periodically check against that (which will allow you to find errors in your client or server code). Because the server database should be considered the primary, you can retransmit the entire gamestate to any client that gets incorrect state, so minor client errors won't (potentially) ruin the experience (except perhaps a pause while the state is downloaded).
最后,因为服务器确实具有“一个真正的”游戏状态,所以客户端可以定期检查(这将允许您在客户端或服务器代码中查找错误)。因为服务器数据库应该被视为主服务器,所以您可以将整个游戏状态重新传输到任何状态不正确的客户端,因此轻微的客户端错误不会(可能)破坏体验(除非在下载状态时暂停)。
#2
4
You could use the ASP.Net Cache or the Application state to store the game object since these are shared between users. The cache would probably be the best place since objects can be removed from it to save memory.
您可以使用ASP.Net Cache或Application状态来存储游戏对象,因为这些是在用户之间共享的。缓存可能是最好的位置,因为可以从中删除对象以节省内存。
If you store the game object in cache using a unique key you can then store the key in each visitors Session and use this to retrieve the shared game object. If the cache has been cleared you will recreate the object from the database.
如果使用唯一键将游戏对象存储在缓存中,则可以将密钥存储在每个访问者会话中,并使用它来检索共享游戏对象。如果已清除缓存,则将从数据库重新创建对象。
#3
1
Why don't you just create an application level object to store your details. See Application State and Global Variables in ASP.NET for details. You can use the sessionID to act as a key for the data for each player.
为什么不创建应用程序级别对象来存储您的详细信息。有关详细信息,请参阅ASP.NET中的应用程序状态和全局变量。您可以使用sessionID作为每个播放器数据的键。
You could also use the Cache to do the same thing using a long time out. This does have the advantage that older data could be flushed from the Cache after a period of time ie 6 hours or whatever.
您也可以使用Cache来使用很长时间来执行相同的操作。这确实具有以下优点:在一段时间(即6小时或更长时间)之后可以从高速缓存中刷新旧数据。
#1
3
While updating a database seems like overkill, it has advantages when it comes time to scale up, as you can have multiple webheads talking to one backend.
虽然更新数据库看起来有点过分,但在扩展时它具有优势,因为您可以让多个网络头与一个后端进行通信。
A larger concern is how you communicate the game state to the clients. While a full update of the game state from time to time ensures that any changes are caught and all clients remain in synchronization even if they miss a message, gamestate is often quite large.
更大的问题是如何将游戏状态传达给客户。虽然游戏状态的不断更新可确保捕获任何更改并且所有客户端即使错过消息也保持同步,但游戏状态通常非常大。
Consider as well that usually you want gamestate messages to trigger animations or other display updates to portray the action (for example, of a piece moves, it shouldn't just appear at the destination in most cases... it should move across the board).
考虑一下,通常你希望游戏状态消息触发动画或其他显示更新来描绘动作(例如,一个棋子移动,它不应该只在大多数情况下出现在目的地......它应该在棋盘上移动)。
Because of that, one solution that combines the best of both worlds is to keep a database that collects all of the actions performed in a table, with sequential IDs. When a client requests an update, it can give all the actions after the last one it knew about, and the client can "act out" the moves. This means even if an request fails, it can simply retry the request and none of the actions will be lost.
因此,结合两者中最好的一个解决方案是保留一个数据库,该数据库收集表中执行的所有操作,具有顺序ID。当客户端请求更新时,它可以在它知道的最后一个操作之后给出所有操作,并且客户端可以“操作”移动。这意味着即使请求失败,它也可以简单地重试请求,并且不会丢失任何操作。
The server can then maintain an internal view of the gamestate as well, from the same data. It can also reject illegal actions and prevent them from entering the game action table (and thus prevent other clients from being incorrectly updated).
然后,服务器也可以从相同的数据维护游戏状态的内部视图。它还可以拒绝非法操作并阻止它们进入游戏操作表(从而防止其他客户端被错误更新)。
Finally, because the server does have the "one true" gamestate, the clients can periodically check against that (which will allow you to find errors in your client or server code). Because the server database should be considered the primary, you can retransmit the entire gamestate to any client that gets incorrect state, so minor client errors won't (potentially) ruin the experience (except perhaps a pause while the state is downloaded).
最后,因为服务器确实具有“一个真正的”游戏状态,所以客户端可以定期检查(这将允许您在客户端或服务器代码中查找错误)。因为服务器数据库应该被视为主服务器,所以您可以将整个游戏状态重新传输到任何状态不正确的客户端,因此轻微的客户端错误不会(可能)破坏体验(除非在下载状态时暂停)。
#2
4
You could use the ASP.Net Cache or the Application state to store the game object since these are shared between users. The cache would probably be the best place since objects can be removed from it to save memory.
您可以使用ASP.Net Cache或Application状态来存储游戏对象,因为这些是在用户之间共享的。缓存可能是最好的位置,因为可以从中删除对象以节省内存。
If you store the game object in cache using a unique key you can then store the key in each visitors Session and use this to retrieve the shared game object. If the cache has been cleared you will recreate the object from the database.
如果使用唯一键将游戏对象存储在缓存中,则可以将密钥存储在每个访问者会话中,并使用它来检索共享游戏对象。如果已清除缓存,则将从数据库重新创建对象。
#3
1
Why don't you just create an application level object to store your details. See Application State and Global Variables in ASP.NET for details. You can use the sessionID to act as a key for the data for each player.
为什么不创建应用程序级别对象来存储您的详细信息。有关详细信息,请参阅ASP.NET中的应用程序状态和全局变量。您可以使用sessionID作为每个播放器数据的键。
You could also use the Cache to do the same thing using a long time out. This does have the advantage that older data could be flushed from the Cache after a period of time ie 6 hours or whatever.
您也可以使用Cache来使用很长时间来执行相同的操作。这确实具有以下优点:在一段时间(即6小时或更长时间)之后可以从高速缓存中刷新旧数据。