9a69ad5

Branches > facts > 9a69ad5 > files / src / net / bowmap / transport

Add fact storage

Grahp, 2026-08-23

Commit: 9a69ad5651676ae5ebd437867cad194ac3318e59
Parent: 239bccb

5 changed files:

src/net/bowmap/protocol/handle.clj modified (view file)

@@ -29,7 +29,7 @@                     :protocol-id protocol)}))  (defmethod handle-packet ::serverbound/status-request [_ _]-  {:facts [{::fact/id ::fact/server-list-requested}]})+  {:facts [{::fact/attribute ::fact/server-list-requested}]})  (defmethod handle-packet ::serverbound/ping-request [_ pk]   {:packets [{::pk/id ::clientbound/pong-response@@ -95,8 +95,9 @@         player {::entity/id entity-id                 ::player/uuid uuid}]     {:client client-     :facts [{::fact/id ::fact/player-joined-              ::player/player player}]+     :facts [{::fact/attribute ::fact/player-joined+              ::fact/entity uuid+              ::fact/value player}]      :packets (-> [{::pk/id ::clientbound/login                     :entity-id entity-id                     :hardcore? false@@ -139,9 +140,9 @@                                             {:keys [& ::position/x ::position/y ::position/z ::position/yaw ::position/pitch]                                              :as packet                                              :select movement}]-  {:facts [(merge {::fact/id ::fact/updated-player-movement-                   ::player/uuid uuid-                   ::position/position movement})]})+  {:facts [(merge {::fact/attribute ::fact/updated-player-movement+                   ::fact/entity uuid+                   ::fact/value movement})]})  (defmethod handle-packet ::serverbound/set-player-rotation [client pk]   (handle-player-update-movement-packet client pk))

src/net/bowmap/server/logic.clj modified (view file)

@@ -10,7 +10,9 @@ (defmulti handle-fact   "Returns a sequence of effects from a fact."   (fn [fact]-    (::fact/id fact)))+    (::fact/attribute fact)))++(defmethod handle-fact :default [_])  (defmethod handle-fact ::fact/server-list-requested [_]   (dosync@@ -20,51 +22,44 @@                              ; Gets the number of players playing, which is what you want                              ; And there are no side-effects!                              #_(count (fact ::fact/playing))-                             :players {:online (count @server/players)+                             :players {:online (count (fact/fact ::fact/playing))                                        :max server/max-player-count}                              :description {:text "Bowmap!"}                              :enforcesSecureChat false}}])) -; Want this to be pure, which means you need a way to encode that state change as data?-(defmethod handle-fact ::fact/player-joined [{::player/keys! [player]}]+(defmethod handle-fact ::fact/player-joined [{::fact/keys! [value]}]   (dosync-    (let [{::player/keys! [uuid]} player]-      (if (@server/players uuid)+    (let [{::player/keys! [uuid]} value]+      (if (contains? (fact/fact ::fact/playing) uuid)         (throw (Exception. "Player tried to join with an existing UUID"))-        (commute server/players assoc uuid (ref player)))-      [])))+        [{::fact/attribute ::fact/playing+          ::fact/entity uuid}])))) -(defmethod handle-fact ::fact/player-left [{:keys! [::player/uuid]}]-  (dosync-    {::fact/id ::fact/playing-     ::fact/mode ::fact/retract-     ::player/uuid uuid}-    (commute server/players dissoc uuid)-    []))+; TODO this is never actually used :p+; So the player list and re-joining are broken+(defmethod handle-fact ::fact/player-left [{::fact/keys! [entity]}]+  [{::fact/attribute ::fact/playing+    ::fact/mode ::fact/retract+    ::fact/entity entity}]) -(defmethod handle-fact ::fact/updated-player-movement [{:keys! [::player/uuid ::position/position]}]-  (dosync-    (alter (@server/players uuid) update ::position/position merge position)-    []))+#_(defmethod handle-fact ::fact/updated-player-movement [{:keys! [::player/uuid ::position/position]}]+    (dosync+      (alter (@server/players uuid) update ::position/position merge position)+      [])) +; TODO move this comment to the fact definition itself somewhere ; Called when the player actually moves, not just when a position is sent (defmethod handle-fact ::fact/player-moved [_ _]) -(defn fact? [x]-  (::fact/id x))- (defn apply-rules-  "Applies rules recursively, returns a map containing :facts and :effects, the seqs of all facts that were asserted/retracted, and the seq of all effects that are implied from that fact."+  "Applies rules recursively, returns a map containing :facts and :effects.+   :facts being the seqs of all facts that were asserted/retracted,+   :effects being the seq of all effects that are implied from that fact."   ([fact] (apply-rules {:facts [fact] :effects []} fact))   ([acc fact]    (let [results (handle-fact fact)]      (reduce (fn [acc result]-               (if (fact? result)+               (if (::fact/attribute result)                  (apply-rules (update acc :facts conj result) result)                  (update acc :effects conj result)))              acc results))))--(comment-  (apply-rules {:net.bowmap.stormbow.fact/id :net.bowmap.stormbow.fact/server-list-requested})-  (apply-rules-    {::fact/id ::fact/server-list-requested}))

src/net/bowmap/server/server.clj modified (view file)

@@ -1,11 +1,3 @@ (ns net.bowmap.server.server) -; Map of player uuids to their refs-(defonce players (ref {})) (def max-player-count 1000)--(defn player-  "Returns the current map of known information about a player given their uuid.-   Returns nil when nothing is known."-  [uuid]-  @(@players uuid))

src/net/bowmap/stormbow/effect_execution.clj modified (view file)

@@ -4,7 +4,8 @@    [net.bowmap.protocol.client :as client]    [net.bowmap.protocol.packet :as pk]    [net.bowmap.protocol.packet.clientbound :as clientbound]-   [net.bowmap.stormbow.effect :as effect]))+   [net.bowmap.stormbow.effect :as effect]+   [net.bowmap.stormbow.fact :as fact]))  (defmulti execute-effect!   (fn [effect]@@ -17,7 +18,10 @@                 :response server-list-response}]     (put! clientbound-packets packet))) -; TODO this now also has :facts [...]-; So you can update state based on that :)-(defn execute-effects! [effects]-  (run! execute-effect! (:effects effects)))+(defn execute-effects! [{:keys! [facts effects]}]+  (doseq [{::fact/keys [mode attribute entity value]} facts]+    (when (fact/fact attribute)+      (if (= mode ::fact/retract)+        (fact/retract-fact attribute entity)+        (fact/assert-fact attribute entity value))))+  (run! execute-effect! effects))

src/net/bowmap/stormbow/fact.clj modified (view file)

@@ -2,5 +2,30 @@   (:require    [clojure.spec.alpha :as s])) -(s/def ::fact (s/keys :opt [::id]))-(s/def ::id qualified-keyword?) ; Could use a set of all facts+(s/def ::fact (s/keys :opt [::attribute ::entity ::value]))++(defonce attributes->entity-value-pairs (ref {}))++; These are all ephemeral right now ofc :p+(defn register-attribute! [attribute cardinality]+  (case cardinality+    ::one+    (dosync+      (commute attributes->entity-value-pairs assoc attribute (ref {}))))+  attribute)++(register-attribute! ::playing ::one)++(defn assert-fact [attribute entity value]+  (dosync+    ; Can only have one value+    (alter (@attributes->entity-value-pairs attribute) assoc entity value)))++(defn retract-fact [attribute entity]+  (dosync+    (alter (req! @attributes->entity-value-pairs attribute) dissoc entity)))++(defn fact+  "Returns the current transactional value of the fact given its attribute"+  [attribute]+  (some-> (@attributes->entity-value-pairs attribute) deref))