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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141 | ;; ported-from: src/games/host/valley-blocks-host.ts @ v1.3.0
;; (itself: game2/client/src/game/party.ts hi/lv/bs routing, the
;; live-beats-idle "playing" split-brain rule, round flow @ 25e6d79) — the
;; referee lives in valley-blocks-sim.cljs; roster/timers/auto-start in the
;; driver base.
;; divergences: same as the other hosts (no roster-grace, no election
;; backstop); game2's wire shapes differ from the base — "ro" carries
;; [id, name, wins] 3-tuples plus mode/target/playing (overridden below) and
;; browsers announce with "hi".name, normalized to the base's nick. The
;; HostSeat score field holds round wins (game2 has no per-match score at the
;; roster level). The round seed is drawn here, not in the sim.
(ns ardegazu.peer.games.host.valley-blocks-host
(:require [ardegazu.peer.games.host.driver :as driver]
[ardegazu.peer.games.host.valley-blocks-sim :as vb]
[shadow.cljs.modern :refer (defclass)]))
(declare vb-roster)
(defclass ValleyBlocksHost
(extends driver/HostDriver)
(constructor [this room opts]
(super room (if ^boolean (js* "~{} == null" opts) (js-obj) opts))
(let [o (if ^boolean (js* "~{} == null" opts) (js-obj) opts)
rng (unchecked-get o "rng")]
(unchecked-set this "_rng" (if ^boolean (js* "~{} == null" rng) js/Math.random rng))
;; playing/roundover — true from "st" until the post-round "lo"
(unchecked-set this "_live" false)
(unchecked-set
this "sim"
(vb/ValleyBlocksSim.
(js-obj "roster" (fn [] (vb-roster this))
"addWin" (fn [id]
(let [p (.get ^js (unchecked-get this "roster") id)]
(when ^boolean (js* "!!(~{})" p)
(unchecked-set p "score" (inc (unchecked-get p "score")))))
js/undefined)
"mode" (unchecked-get o "mode")
"target" (unchecked-get o "target")))))))
(defn- vb-roster
"The game2 wire roster — [id, name, wins] (wins ride the score field)."
[self]
(let [out #js []]
(.forEach ^js (unchecked-get self "roster")
(fn [p id] (.push out #js [id (unchecked-get p "nick") (unchecked-get p "score")])))
out))
(let [proto (.-prototype ValleyBlocksHost)]
(unchecked-set proto "vbRoster" (fn [] (this-as self (vb-roster self))))
;; game2's "ro" shape: 3-tuple ps + mode/target and the playing flag.
(unchecked-set
proto "broadcastRoster"
(fn []
(this-as self
(driver/emit-frame
self
(js-obj "f" (js-obj "t" "ro"
"host" (unchecked-get (unchecked-get self "room") "myId")
"ps" (vb-roster self)
"mode" (unchecked-get (unchecked-get self "sim") "_mode")
"target" (unchecked-get (unchecked-get self "sim") "_target")
"playing" (if (unchecked-get self "_live") 1 0))))
js/undefined)))
;; live round beats idle claim, ties to lowest id (both sides of the split).
(unchecked-set
proto "concedeRule"
(fn [from m]
(this-as self
(let [my-live (unchecked-get self "_live")
their-live (identical? 1 (unchecked-get m "playing"))
i-win (if-not (identical? my-live their-live)
my-live
(< (unchecked-get (unchecked-get self "room") "myId") from))]
(not i-win)))))
(unchecked-set
proto "startMatch"
(fn [ids]
(this-as self
(if (< (.-length ^js ids) 2)
(driver/on-lobby self)
(let [seed (js/Math.floor (* ((unchecked-get self "_rng")) 0x7fffffff))]
(unchecked-set self "_live" true)
(driver/run-emit self (vb/start-round (unchecked-get self "sim") ids seed))
;; refresh the playing flag for bystanders
(driver/broadcast-roster self)))
js/undefined)))
(unchecked-set
proto "onGameFrame"
(fn [from m]
(this-as self
(let [t (unchecked-get m "t")]
(cond
(identical? t "hi")
;; browsers announce `name`; the base seats by `nick`
(let [m2 (js/Object.assign (js-obj) m)
nm (unchecked-get m "name")]
(unchecked-set m2 "nick" (if (string? nm) nm (unchecked-get m "nick")))
(driver/on-hi self from m2))
(identical? t "lv")
(do (when (.delete ^js (unchecked-get self "roster") from)
(driver/broadcast-roster self))
(driver/run-emit self (vb/player-left (unchecked-get self "sim") from)))
(identical? t "bs")
(driver/run-emit self (vb/on-board-state (unchecked-get self "sim") from
(bit-or (unchecked-get m "round") 0)
(bit-or (unchecked-get m "seat") 0)
(unchecked-get m "s")))
:else nil))
js/undefined)))
(unchecked-set
proto "execStep"
(fn [step]
(this-as self
(when (identical? step "lobby")
(unchecked-set self "_live" false)
(driver/emit-frame self (js-obj "f" (js-obj "t" "lo")))
(driver/broadcast-roster self))
js/undefined)))
(unchecked-set proto "simPeerGone"
(fn [id] (this-as self
(driver/run-emit self (vb/player-left (unchecked-get self "sim") id))
js/undefined)))
(unchecked-set proto "sendSnap"
(fn [to] (this-as self
(driver/run-emit self (vb/snapshot (unchecked-get self "sim") to))
js/undefined)))
(unchecked-set proto "roundLive" (fn [] (this-as self (unchecked-get self "_live"))))
(unchecked-set proto "simRunning"
(fn [] (this-as self (unchecked-get (unchecked-get self "sim") "_running"))))
(unchecked-set proto "abortSim"
(fn [] (this-as self
(unchecked-set self "_live" false)
(vb/abort (unchecked-get self "sim"))))))
|