The Krestianstvo fiddle includes several demos, that can help you to look inside Croquet VM, while it is running. So, if you start any of "Clicker", "Counter" or "Painter" demo worlds at http://e.krestianstvo.org, you can click on "Info" button that will show the VM internals.
The central part of the Croquet VM is a time sharing and temporal recursion concept. It is implemented with the Croquet's specific view on objects and computations in general. Any object is tied to some concrete Island (isolate), which by itself is surrounded and floating in the sea of messages. The messages are holding the TeaTime (or Virtual Time), which essentially determines what object is with it's history (the state in other words). In Squeak Smalltalk implementation, Island is an Island object, in Croquet OS, Island is Croquet.Session object, and in Krestianstvo it is a Selo.
All objects are actually live inside isolated Selos and requires compliance with the principle of deterministic computation. Objects communicate within each other by sending and receiving Future messages, that never go through the network. Thus, applications are local-first by default and all object's data is located on the e/client. Messages which are distributed through a Sea are named as External messages (relatively to the Selos). These messages are explicitly stamped by the e/server's local time. The streams of Future and External messages are mixed up, sorted and dispatched locally by every e/client itself. The main purpose of External messages is not only to inject data from any external sources (like sensors, input controllers ect.) into the Selo, but to notify and setting up an upper bound of the Virtual Time. Just exactly up to that bound all Future messages, that accumulated during computations will be executed, and the new upper bound will be set up.
So, there three easy steps to create any Krestianstvo application:
- Create a Selo with a seloID and world template.
- Create and register Object within that Selo.
- Connect to that Selo with clientID, got from e/http-request "sec-websocket-key" or UUID, when there are more than one client in one Selo in one Electric app.
Virtual Time is moving exactly forward only when some External message is coming into the Selo. For example, in the "Counter" world demo, the number is counting forward, while sending Future message to itself using temporal recursion. If there are will be no any External message from a metronome or e.g. mouse move event, the object will not change. Master user is selected for snapshotting the current Selo state, that is needed for connecting the new peers at initial connection. If the master accidentally leaves, it will be dynamically intercepted by another client.
Krestianstvo Electric introduces the Lazy Reflector for Croquet VM architecture. This becomes possible due to implementing it in Clojure Electric programming architecture involving continuous-time signals with lazy sampling and streaming DAGs.
All known Croquet implementations (including the Smalltalk, VWF, Croquet OS and recent Multisync protocol) also OSS Krestianstvo on Solid JS are involving discrete timestamp generator (aka Reflector server). The Reflector should produces periodic ticks (~25-50 ms) and also timestamps all external messages coming from the views, then replicates these messages back to all connected peers of some concrete session (Island). If Reflector will not produce any messages, the Croquet VM will be suspended, waiting for any. In simple words, Reflector periodic ticks are needed for any animated in time simulation go forward in Croquet. But, the high frequency Reflector becomes redundant for simulations with slow rates for example or in the applications with no time-animated simulations at all.
The Lazy Reflector is ticking and time-stamping only on demand, staying the most time idle and laziness - not producing any work at all! However it guarantees, that all connected peers will get just the same ticks and time stamped messages, without missing a single one! As it is based on backpressured Electric continuous lazy server clock.
(new (actQueue (reset! !reflectorTime (e/server e/system-time-ms))))
That perfectly fits Croquet architecture, as in general the most application work is done locally by the clients themselves. That includes involving Future messages with temporal recursion that producing no network traffic at all (future messages never going to the Reflector).
Also Lazy Reflector ticks are now not added to the Croquet VM priority queue. They are only moving local virtual time forward, pulling lazy server clock on demand by the future messages.
To try it in action, there are several example applications in Krestianstvo Electric. Want to mention, that in the Counter example, the button "Loop" is not triggering Reflector to start ticking periodically. The button send only one external message launching temporal recursion on all connected peers. Then future messages pull the lazy server clock with the sample rate defined in the future step amount (after every virtual 0.5 sec in future do :step).
step (fn [m]
(swap! !objData update-in [seloID objID :x] inc)
(sendFutureMsg {:name :step, :when 0.5, :objid objID}))