logic.clj

Branches > main > bffdd52 > files / src / net / bowmap / server / logic.clj

(ns net.bowmap.server.logic
  (:require
   [net.bowmap.server.player :as player]
   [net.bowmap.server.position :as position]
   [net.bowmap.server.server :as server]
   [net.bowmap.stormbow.effect :as effect]
   [net.bowmap.stormbow.event :as event]))

(defmulti handle-event
  "Returns a sequence of effects and events yielded from an event."
  (fn [event]
    (::event/id event)))

(defmethod handle-event ::event/player-joining [{:keys! [::player/uuid ::player/username] :as p}]
  (dosync
    (if (@server/players uuid)
      (throw (Exception. "Player tried to join with an existing UUID"))
      (commute server/players update uuid merge p))
    []))

; TODO this is asymmetric
(defmethod handle-event ::event/player-joining [{:keys! [::player/uuid ::player/username] :as p}]
  (dosync
    (if (@server/players uuid)
      (throw (Exception. "Player tried to join with an existing UUID"))
      (commute server/players update uuid merge p))
    []))

(defmethod handle-event ::event/player-joined [{:keys! [::player/uuid ::player/player]}]
  (dosync
    (commute server/players update uuid merge player)
    [{::event/id ::event/broadcast
      :message {:text (str (or (::player/username (server/player uuid)) "Unknown Player") " Joined!")}}]))

(defmethod handle-event ::event/player-left [{:keys! [::player/uuid]}]
  (dosync
    (let [username (::player/username (server/player uuid))]
      (commute server/players dissoc uuid)
      [{::event/id ::event/broadcast
        :message {:text (str (or username "Unknown Player") " Left.")}}])))

(defmethod handle-event ::event/broadcast [{:keys! [message]}]
  (dosync
    (for [[recipient] @server/players]
      {::effect/id ::effect/send-chat-message
       ::player/uuid recipient
       :message message})))

(defmethod handle-event ::event/updated-player-movement [{:keys! [::player/uuid ::position/position] :as e}]
  (dosync
    (when (not= position (::position/position (@server/players uuid)))
      [(assoc e ::event/id ::event/player-moved)])))

; Called when the player actually moves, not just when a position is sent
(defmethod handle-event ::event/player-moved [{:keys! [::player/uuid ::position/position]}]
  (dosync
    (commute server/players update-in [uuid ::position/position] merge position)
    []))

(defmethod handle-event ::event/player-sent-chat-message [{:keys! [message ::player/uuid]}]
  (for [[recipient] @server/players]
    {::effect/id ::effect/send-chat-message
     ::player/uuid recipient
     :message {:text (str (::player/username (server/player uuid)) ": " message)}}))

(defn handle-events
  "Handles the supplied event, and all events returned recursively from this one.
   Returns a seq of all effects that are yielded from handling all events recursively."
  [event]
  (reduce (fn [effects result]
            (if (::event/id result)
              (into effects (handle-events result))
              (conj effects result)))
          [] (handle-event event)))