My thoughts:
I have had in mind that ComponentSystems would be able to "subscribe" to time based events beyond the every-tick update method (I say tick rather than frame because a headless server would not have frames). It should be clarified these at least some of these events are based on ingame time, not clock time, so they might be called on, say, dawn, midday, dusk and midnight, or every "hour", or so forth. This can be done in a similar way to the current UpdateSubscriberSystem interface - perhaps an interface with onDawn(), etc methods.
For system methods subscribing to various granualities of time passing (i.e. for methods that are called every minute, 10 minutes, 1 hour of time) I would suggest an annotation approach to hook these methods into a centralised time manager. This would still be based on the passage of ingame time though, not real time (if the game is paused time should not tick forwards and these methods should not be called). But these are real-time quantities, not based on an ingame day (confusing).
The progress towards these events should survive world saving/loading - if you are 9 minutes into a world, save it and then restart and load it, the 10 minute events should occur after 1 more minute.
The third type of time event is for individual entities to subscribe for temporal events - an example would be the current Lifespan component, which allows entities to be destroyed after a time period. Ideally systems should be able to create an event to send against an entity, but have its propagation delayed until a period of time has passed. This means that these events would need to be saved and loaded with the world as well - the work I have been doing around event serialization for multiplayer will help here.
I'm not overly familiar with quartz, but unless it is able to schedule around a virtual clock it won't be useful for this.
For world simulators... these will only run on the server, so multiplayer shouldn't matter to them (plant growth would be an example of this). In this case I consider a simulator to be anything changing with time, as opposed to lighting which is derived purely from block data (and thus can be done client-side). I guess I disagree with
dei on this point - I feel requiring all simulators to be purely deterministic to be too limiting, and probably unmanagable due to edge cases (specifically the edge of loaded chunk-space, which can differ between client and server).
As long as they go through the WorldProvider system, then changes to the world should be thread safe, so they can be run on background threads - changes to entities are not thread safe at the moment and should only be done on the main thread.
Control of which chunks are available is completely under control of the ChunkProvider, based on the concept of certain entities having regions around them that are relevant. Simulators should work with this, and simply run on loaded chunks (and specifically complete chunks surrounded by complete chunks, so that any light propagation they trigger will work correctly). When a chunk is unloaded, the world time should be stored with the chunk, and then when a chunk is created/loaded simulators should be informed and this world time can be used for simulators to do rapid updates. This is currently missing functionality - along with having a chunk waiting on simulators to finish updating it on load. (Basically, what
dei said).
dei said:
Because plant-growth based on grammars or simpler rules is highly deterministic and local anyway you can calculate each plant's state out of the surrounding 4 blocks and the time it already exists.
The reason I believe this won't be deterministic is because of chunk boundaries. Assuming we have a 5x5 square of chunks loaded. Obviously the outer layer of blocks cannot be simulated as some of their surrounding blocks are missing. So the outer layer of chunks probably should not be simulated. The next layer of chunks can be simulated, but the outer layer of blocks are frozen in the past and not being updated. So the simulation of the next layer will be different to what would have happened if the outer layer was being simulated. If the inner blocks are all exposed dirt, and the outer blocks are grass with a 1-block think layer of dirt around the inside, then until the outer chunks are simulated none of that vegetation can propagate into the middle.