1

競争力のあるターンベースのゲームを開発しています。匿名の訪問者がページにアクセスすると、ゲームの完全ではないインスタンスに自動的にサブスクライブし、アクションを観察するか参加することができます。各ゲーム インスタンスのスポット数は限られています。ゲームに参加する (スポットを取得する) と、古いサブスクリプションは停止され、選択したスポットに基づく個人情報も含む新しいサブスクリプションが作成されます。ここまでは順調ですね。

ここで、プレーヤーが妥当な時間内に自分のターンを完了しないときはいつでも、サーバーがスポットを解放できるようにしたいと考えています。

問題は、自分の場所から追い出されたプレーヤーが、自分の場所を占有している他の誰かに送られることを意図した更新を受信しないようにするにはどうすればよいかということです。クライアントは信頼できないため、明らかにこれはサーバー側で発生する必要があります。追い出されたユーザーがシームレスにオブザーバーに戻ることが理想的です。

publish()内で呼び出すことができるメソッドstop()があることは知っていますが、 Meteor.setTimeout()によって設定されたコールバックがサーバーで呼び出されたときに、特定のクライアントの公開されたサブスクリプションを停止するためにそれを使用する方法は?

私がやろうとしていることの大幅に変更されたコード (動作することを意図したものではなく、アイデアを提供するためだけに)

  if Meteor.isClient
      publicGameHandle = Meteor.subscribe 'GameInstances'

      join = (gameInstanceId, spot) ->
          Meteor.call "join", gameInstanceId, spot, (err, guestId) ->
              Session.set("guestId", guestId)
              privateGameHandle = Meteor.subscribe 'GameInstances',
              gameInstanceId, spot, guestId, ->
                  publicGameHandle.stop()

   if Meteor.isServer
       privateSubscriptions = {}

       Meteor.publish 'GameInstances', (gameInstanceId, spot, guestId) ->
           if gameInstanceId
               GameInstances.find {_id: gameInstanceId}
               privateSubscriptions[guestId] = @
           else
               secretFields = {spots.guestId:false, spots.privateGameInfo:false}
               GameInstances.find {openSpots: {$gt: 0}}, {fields: secretFields}

       Meteor.methods({
           join: (gameInstanceId, spot) ->
               guestId = Random.id()
                   gameInstances[gameInstanceId].addPlayer(spot, guestId)
               guestId

           completePlayerTurn: (gameInstanceId, spot, guestId) ->
               gameInstance = gameInstances[gameInstanceId]
               Meteor.clearTimeout(gameInstance.timer)
               nextPlayer = gameInstance.getNextPlayer()

               kick = () ->
                   privateSubcriptions[nextPlayer.guestId].stop()
                   gameInstance.removePlayer(nextPlayer.guestId)
               gameinstance.timer = Meteor.setTimeout(kick, 60000)
4

1 に答える 1

1

どちらもゲーム データを返す 2 つの個別のサブスクリプションを作成します。一方のサブスクリプションはパブリック ゲーム データを返し、もう一方は currentUser が表示できるゲーム データを返す必要があります。それらは、クライアント側で 1 つのコレクションにマージされます。ユーザーが参加したゲームには非公開情報と公開情報が含まれ、参加していないゲームには公開情報のみが含まれます。次に、クライアント側ではGame.findOne(thisGame.id)、プレイヤーがゲームに参加したときに liveQuery のようなものが自動的に個人情報を受け取り、テンプレートを再レンダリングさせます。

説明のための疑似コード:

if Meteor.isClient
  Meteor.subscribe 'GameInstances'
  Meteor.subscribe 'MyGameInstances', guestId

  join = (gameInstanceId, spot) ->
      Meteor.call "join", gameInstanceId, spot, (err, guestId) ->
          Session.set("guestId", guestId)

if Meteor.isServer

   Meteor.publish 'GameInstances', () ->
       secretFields = {spots.guestId:false, spots.privateGameInfo:false}
       GameInstances.find {openSpots: {$gt: 0}}, {fields: secretFields}

   Meteor.publish 'MyGameInstances', (guestId) ->
       GameInstances.find {'spots.guestId': guestId}, {fields: secretFields}

   Meteor.methods({
       join: (gameInstanceId, spot) ->
           guestId = Random.id()
           gameInstances[gameInstanceId].addPlayer(spot, guestId)
           guestId

       completePlayerTurn: (gameInstanceId, spot, guestId) ->
           gameInstance = gameInstances[gameInstanceId]
           Meteor.clearTimeout(gameInstance.timer)
           nextPlayer = gameInstance.getNextPlayer()

           kick = () ->
               gameInstance.removePlayer(nextPlayer.guestId)
           gameinstance.timer = Meteor.setTimeout(kick, 60000)

1 つのゲーム インスタンスに多くのプレイヤーの個人情報を含めているようです。そのため、許可されているフィールドをフィルタリングするのが難しくなります (そして、他のプレイヤーのプライベート情報を公開せずに、現在のゲストのプライベート情報のみを公開します)。

その場合、次のいずれかを検討できます。

  • 個人情報を別のコレクションにリファクタリングし、別のサブスクリプションとして公開する
  • カスタム公開機能。次に例を示します。

https://gist.github.com/colllin/8321227

このコードでは、1 つのコレクションを監視し、Meteor.usersコレクションにマージされるデータを公開しています。サブスクリプションが のようなデータを発行していることがわかります{_id: userId, wins: 25}。これによりwins、クライアント側のユーザー モデルでフィールドが使用可能になります。おそらくobserve()、Games コレクションが必要ですが、現在のユーザーに基づいてプライベート データを手動でフィルター処理し、そのプライベート データを Games コレクションに公開して、パブリック データとマージする必要があります。guestId上記のように、発行関数に渡すことができます。

于 2014-01-08T18:07:48.250 に答える