dev / templates / app-cljs-live / client / src / __NAME__ / game / app.cljs
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
;; Demo app logic: a roster of open peers + broadcast text notes.
;;
;; This is the namespace you gut. It shows the working pattern — own your
;; state, consume the small net surface main hands you, validate every frame
;; (in main, via frames/is-app-frame), let ui touch the DOM — and nothing
;; else. Shared mutable state rides plain JS objects with string keys (never
;; renamed by :advanced), accessed through the s/s! helpers — the game1 shape.
(ns __NAME__.game.app
  (:require [__NAME__.config :as config]
            [__NAME__.game.frames :as frames]
            [__NAME__.game.ui :as ui]))

(def S
  (js-obj "joined" false
          "nick" ""
          "nicks" (js/Map.) ; peerId → announced nick (learned from "hi" frames)
          "notes" #js []))

(defn s [k] (unchecked-get S k))
(defn s! [k v] (unchecked-set S k v))

;; the slice of Net the app consumes (see net/index for the full surface)
(def ^:private net* (volatile! nil))

(defn init-app [n] (vreset! net* n))

(defn- net ^js [] @net*)

(defn- my-id [] (unchecked-get (net) "myId"))

(defn nick-of [id]
  (if (identical? id (my-id))
    (s "nick")
    (let [v (.get ^js (s "nicks") id)]
      (if (some? v) v (str "peer-" (.slice ^string id -4))))))

(defn rerender
  "Re-render everything the app owns (also called on language change)."
  []
  (when (s "joined")
    (let [rows #js [(js-obj "id" (my-id) "nick" (s "nick") "me" true)]]
      (doseq [id (array-seq ((unchecked-get (net) "openPeers")))]
        (.push rows (js-obj "id" id "nick" (nick-of id) "me" false)))
      (ui/render-roster rows)
      (ui/render-notes (s "notes") (my-id)))))

(defn- hi [] (frames/mk-hi (s "nick")))

(defn join [nick]
  (s! "joined" true)
  (s! "nick" nick)
  (doseq [id (array-seq ((unchecked-get (net) "openPeers")))]
    ((unchecked-get (net) "send") id (hi)))
  (ui/show-room)
  (rerender))

;; ---------------- net callbacks (wired in main) ----------------

(defn on-room-roster [_peers]
  (rerender))

(defn on-peer-open [id]
  (when (s "joined")
    ((unchecked-get (net) "send") id (hi))) ; introduce myself to the newcomer
  (rerender))

(defn on-peer-gone [id]
  (.delete ^js (s "nicks") id)
  (rerender))

(defn- add-note [^js n]
  (let [^js notes (s "notes")]
    (.push notes n)
    (when (> (.-length notes) 200) (.shift notes))
    (ui/render-notes notes (my-id))))

(defn handle-msg [from ^js frame]
  (let [t (unchecked-get frame "t")]
    (cond
      (identical? t "hi")
      (do (.set ^js (s "nicks") from (.slice ^string (unchecked-get frame "nick") 0 24))
          (rerender))

      (identical? t "note")
      (add-note (js-obj "from" from
                        "nick" (nick-of from)
                        "text" (.slice ^string (unchecked-get frame "text") 0 config/NOTE-MAX)
                        "ts" (unchecked-get frame "ts"))))))

;; ---------------- actions ----------------

(defn send-note [text]
  (let [clean (.slice (.trim ^string text) 0 config/NOTE-MAX)]
    (when (and (seq clean) (s "joined"))
      (let [f (frames/mk-note clean (js/Date.now))]
        ((unchecked-get (net) "broadcast") f)
        (add-note (js-obj "from" (my-id)
                          "nick" (s "nick")
                          "text" clean
                          "ts" (unchecked-get f "ts")))))))

static mirror of HEAD · about · clone: git clone https://git.ardegazu.ro/dev.git