9a69ad5
Branches > facts > 9a69ad5 > files / src / net / bowmap / transport
Add fact storage
Commit: 9a69ad5651676ae5ebd437867cad194ac3318e59
Parent: 239bccb
5 changed files:
src/net/bowmap/protocol/handle.clj 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 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 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 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 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))