manager.clj 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. (ns bombnet.manager
  2. (:require [bombnet.game :refer :all]
  3. [clojure.set :refer [difference]]
  4. [clojure.core.async :refer [>! >!! <! <!! alts! alts!! chan go go-loop timeout]]))
  5. (defrecord Room [clients players state msg-ch ready-ch])
  6. (defrecord Manager [rooms])
  7. (defn new-manager []
  8. (->Manager (atom {})))
  9. (defn client-join [room {:keys [id] :as client}]
  10. (assoc-in room [:clients id] client))
  11. (defn client-leave [room id]
  12. (let [new-room (-> room
  13. (update :clients dissoc id)
  14. (update :players difference #{id}))]
  15. (if (not-empty (:clients new-room)) new-room)))
  16. (defn player-join [room id]
  17. (let [player-ch (get-in room [:clients id :channel])
  18. player-count (count (:players room))]
  19. (if (>= player-count 4)
  20. (do
  21. (>!! player-ch {:message "Could not join game. Lobby is full."})
  22. room)
  23. (do
  24. (>!! player-ch {:message "Joined game."})
  25. (update room :players conj id)))))
  26. (defn player-leave [room id]
  27. (update room :players difference #{id}))
  28. (defn player-action [room id action]
  29. (if (some? (:state room))
  30. (let [new-room (update room :state queue-action id action)
  31. ready-ch (:ready-ch new-room)
  32. ready (every? :action (get-in new-room [:state :players]))]
  33. (if ready
  34. (>!! ready-ch "ready"))
  35. new-room)))
  36. (defn schedule-tick [room]
  37. (let [{:keys [msg-ch ready-ch]} room]
  38. (go
  39. (alts! [ready-ch (timeout 5000)])
  40. (>! msg-ch [:game-tick "tick"]))))
  41. (defn publish-state [{:keys [clients state]}]
  42. (doseq [ch (map :channel (vals clients))]
  43. (>!! ch {:game state})))
  44. (defn game-start [room]
  45. (let [clients (map #(dissoc % :channel) (vals (:clients room)))
  46. players (filter #((:players room) (:id %)) clients)
  47. new-state (new-game players)
  48. new-room (assoc room :state new-state)]
  49. (schedule-tick new-room)
  50. (publish-state new-room)
  51. new-room))
  52. (defn game-tick [room]
  53. (let [new-state (update-state (:state room))
  54. new-room (assoc room :state new-state)]
  55. (if (not (finished? new-state))
  56. (schedule-tick new-room))
  57. (publish-state new-room)
  58. new-room))
  59. (defn message [room {:keys [id message]}]
  60. (let [type (:type message)]
  61. (condp = type
  62. "start" (game-start room)
  63. "join" (player-join room id)
  64. "leave" (player-leave room id)
  65. "action" (player-action room id (:action message))
  66. (do
  67. (println "Unknown message")
  68. room))))
  69. (defn start-room [in-ch close-ch]
  70. (go-loop
  71. [room (->Room {} #{} nil in-ch (chan))]
  72. (let [[message-type payload] (<! in-ch)
  73. new-room (condp = message-type
  74. :client-join (client-join room payload)
  75. :client-leave (client-leave room payload)
  76. :game-start (game-start room)
  77. :game-tick (game-tick room)
  78. :message (message room payload))]
  79. (if (some? new-room)
  80. (recur new-room)
  81. (>! close-ch :kill-me-now)))))
  82. (defn get-room [{:keys [rooms]} room]
  83. (if-let [room-chan (get @rooms room)]
  84. room-chan
  85. (let [room-chan (chan)
  86. close-chan (chan)]
  87. (start-room room-chan close-chan)
  88. (go
  89. (<! close-chan)
  90. (swap! rooms dissoc room))
  91. (swap! rooms assoc room room-chan)
  92. room-chan)))