Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions docs/EngineStartUp/Engine-Start-Up.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
## Engine Start-Up

```mermaid
graph TD;
PreInitialise[Pre-Initialise]
subgraph InitialiseManagers[Initialise Managers]
ModuleManager --> ModuleTypeRegistry --> ReflectFactory --> CopyStrategyLibrary --> TypeHandlerLibrary
TypeHandlerLibrary --> ModuleAwareAssetTypeHandler --> AssetManager
end
subgraph Initialise
ConfigurationSubsystem --> TimeSubsystem --> OtherSubsystems[Other Subsystems...] --> MonitoringSubsystem
MonitoringSubsystem --> PhysicsSubsystem --> CommandSubsystem --> NetworkSubsystem
NetworkSubsystem --> WorldGenerationSubsystem --> GameSubsystem --> I18nSubsystem --> TelemetrySubsystem
end
InitialiseAssets[Initialise Assets]
PostInitialise[Post-Initialise]

PreInitialise --> ModuleManager
AssetManager --> ConfigurationSubsystem
TelemetrySubsystem --> InitialiseAssets --> PostInitialise
```

### Why three phases?
_These are just my guesses based on the provided documentation._
#### Pre-initialise
This phase allows for doing most of the initialisation for a subsystem that does not rely on other subsystems.
Any subsystem state that needs to be accessed from other subsystems should be initialised here.

#### Initialise
This is the first point at which subsystems have access to the module context. Most subsystems will properly initialise
themselves here. It also allows subsystems to interact in a limited fashion, although this shouldn't be often needed.

#### Post-initialise
This is the last point at which a subsystem should initialise itself. After this stage, the subsystem should be
considered fully initialised. If a subsystem must depend immediately on other initialised subsystems, interact
with them here. This occurs after engine assets have been loaded.

#### Why is this not ideal?
- Most subsystems actually have an implicit undocumented dependency on `TimeSubsystem` and `ConfigurationSubsystem`.
These subsystems are hard-coded to always run first during engine start-up and as-such break the principle of
subsystem independence (subsystems should be allowed to initialise in any order within the same stage).
- These implicit dependencies prevent us from initialising subsystems in parallel, which is limiting potential
start-up performance.
- Currently, all subsystems are actually initialised in the sequence you see above for each stage.
This has the potential to harbour further implicit dependencies that we are yet unaware of.
- (It's also a blocker for migrating to use Gestalt-DI, which requires dependencies to declared up-front.)

#### Potential Improvements
- Change `TimeSubsystem` and `ConfigurationSubsystem` to be classified as managers. This would allow them to initialise
in sequence after `ModuleManager` but before subsystems' `initialise()`.

## Revised Start-Up Sequence (provisional)
```mermaid
graph TD;
PreInitialise[Pre-Initialise]
subgraph InitialiseManagers[Initialise Managers]
ModuleManager --> ModuleTypeRegistry --> ReflectFactory --> CopyStrategyLibrary --> TypeHandlerLibrary
TypeHandlerLibrary --> ModuleAwareAssetTypeHandler --> AssetManager
end
subgraph Initialise
ConfigurationSubsystem
TimeSubsystem
OtherSubsystems[Other Subsystems...]
MonitoringSubsystem
PhysicsSubsystem
CommandSubsystem
NetworkSubsystem
WorldGenerationSubsystem
GameSubsystem
I18nSubsystem
TelemetrySubsystem
end
InitialiseAssets[Initialise Assets]
PostInitialise[Post-Initialise]

PreInitialise --> ModuleManager
AssetManager --> Initialise
Initialise --> InitialiseAssets --> PostInitialise
```
79 changes: 79 additions & 0 deletions docs/EngineStartUp/Engine-States.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
### Engine States

```mermaid
graph TD;
subgraph MainMenu
subgraph MainMenuHandleInput[HandleInput]
MainMenuInputSystemHandleInput[InputSystem]
end

subgraph MainMenuUpdate[Update]
MainMenuNUIManagerUpdate[NUIManager] --> MainMenuEventSystemUpdate[EventSystem]
MainMenuEventSystemUpdate --> MainMenuStorageServiceWorkerUpdate[StorageServiceWorker]
end

subgraph MainMenuRender[Render]
MainMenuNUIManagerRender[NUIManager]
end
end

subgraph Loading
subgraph LoadingUpdate[Update]
LoadingLoadingScreenUpdate[LoadingScreen::updateStatus] --> LoadingNUIManagerUpdate[NUIManager]
LoadingNUIManagerUpdate--> LoadingStepUpdate[Step Update]
subgraph LoadingStepUpdate
direction TB
RegisterMods --> InitRenderingHeadlessCheck{!headless}
InitRenderingHeadlessCheck -->|true| InitialiseRendering --> InitialiseEntitySystem
InitRenderingHeadlessCheck -->|false| InitialiseEntitySystem
InitialiseEntitySystem --> RegisterBlocks --> InitGraphicsHeadlessCheck{!headless}
InitGraphicsHeadlessCheck -->|true| InitialiseGraphics --> LoadPrefabs
InitGraphicsHeadlessCheck -->|false| LoadPrefabs
LoadPrefabs --> ProcessBlockPrefabs
ProcessBlockPrefabs --> InitialiseComponentSystemManager --> InitInputHeadlessCheck{!headless}
InitInputHeadlessCheck -->|true| RegisterInputSystem --> RegisterSystems
InitInputHeadlessCheck -->|false| RegisterSystems
RegisterSystems --> InitialiseCommandSystem --> LoadExtraBlockData --> InitialiseWorld
InitialiseWorld --> RegisterBlockFamilies --> EnsureSaveGameConsistency
EnsureSaveGameConsistency --> InitialisePhysics --> InitialiseSystems --> PreBeginSystems
PreBeginSystems --> LoadEntities --> InitialiseBlockTypeEntities --> CreateWorldEntity
CreateWorldEntity --> InitialiseWorldGenerator --> InitialiseRecordAndReplay
InitialiseRecordAndReplay --> NetModeIsServerCheck{netMode.isServer}
NetModeIsServerCheck -->|true| StartServer --> PostBeginSystems
NetModeIsServerCheck -->|false| PostBeginSystems
PostBeginSystems --> NetModeHasLocalClientCheck{netMode.hasLocalClient}
NetModeHasLocalClientCheck -->|true| SetupLocalPlayer --> AwaitCharacterSpawn --> PrepareWorld
NetModeHasLocalClientCheck -->|false| PrepareWorld
PrepareWorld
end
end

subgraph LoadingRender[Render]
LoadingNUIManagerRender[NUIManager]
end
end

subgraph InGame
subgraph InGameHandleInput[HandleInput]
InGameHandleInputInputSystem[InputSystem]
end

subgraph InGameUpdate[Update]
InGameEventSystemUpdate[EventSystem] --> InGameComponentSystemsUpdate[UpdateSubscriberSystems]
InGameComponentSystemsUpdate --> InGameWorldRendererUpdate[WorldRenderer]
InGameWorldRendererUpdate --> InGameStorageManagerUpdate[StorageManager]
InGameStorageManagerUpdate --> InGameNUIManagerUpdate[NUIManager]
InGameNUIManagerUpdate --> InStorageServiceWorkerUpdate[StorageServiceWorker]
end

subgraph InGameRender[Render]
InGameDisplayDevicePrepareToRender[DisplayDevice::prepareToRender] --> InGameNUIManagerRender[NUIManager]
InGameNUIManagerRender--> InGameWorldRendererrRender[WorldRenderer]
end
end

MainMenu -->|Start Game| Loading
Loading -->|Failed| MainMenu
Loading -->|Succeeded| InGame
InGame -->|Exit To Main Menu| MainMenu
```
83 changes: 53 additions & 30 deletions engine-tests/src/main/java/org/terasology/engine/Environment.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@
import com.google.common.collect.Sets;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.terasology.context.Lifetime;
import org.terasology.engine.context.Context;
import org.terasology.engine.context.internal.ContextImpl;
import org.terasology.engine.core.PathManager;
import org.terasology.engine.core.module.ModuleManager;
import org.terasology.engine.recording.RecordAndReplayCurrentStatus;
import org.terasology.engine.registry.CoreRegistry;
import org.terasology.gestalt.assets.management.AssetManager;
import org.terasology.gestalt.di.ServiceRegistry;
import org.terasology.gestalt.naming.Name;

import java.io.IOException;
Expand Down Expand Up @@ -46,41 +49,48 @@ class Environment {

protected void reset(Set<Name> moduleNames) throws IOException {
this.context = new ContextImpl();
ServiceRegistry serviceRegistry = new ServiceRegistry();
RecordAndReplayCurrentStatus recordAndReplayCurrentStatus = new RecordAndReplayCurrentStatus();
context.put(RecordAndReplayCurrentStatus.class, recordAndReplayCurrentStatus);
serviceRegistry.with(RecordAndReplayCurrentStatus.class).lifetime(Lifetime.Singleton).use(() -> recordAndReplayCurrentStatus);
CoreRegistry.setContext(context);

setupPathManager();

Bullet.init(true, false);

setupConfig();
setupConfig(serviceRegistry);

setupModuleManager(moduleNames);
ModuleManager moduleManager = setupModuleManager(serviceRegistry, moduleNames);

setupDisplay();
setupDisplay(serviceRegistry);

setupAudio();
setupAudio(serviceRegistry);

AssetManager assetManager = setupAssetManager();
AssetManager assetManager = setupAssetManager(moduleManager, serviceRegistry);

setupBlockManager(assetManager);
setupBlockManager(serviceRegistry, assetManager);

setupExtraDataManager(context);
setupExtraDataManager(serviceRegistry, context);

setupCollisionManager();
setupCollisionManager(serviceRegistry);

setupNetwork();
setupNetwork(serviceRegistry);

setupEntitySystem();
setupEntitySystem(serviceRegistry);

setupStorageManager();
setupStorageManager(serviceRegistry);

setupComponentManager();
setupComponentManager(serviceRegistry);

setupWorldProvider();
setupWorldProvider(serviceRegistry);

setupCelestialSystem();
setupCelestialSystem(serviceRegistry);

this.context = new ContextImpl(serviceRegistry);

registerBlockTypeHandlers(this.context);
registerCollisionTypeHandlers(this.context);
initComponentManager(this.context);

loadPrefabs();
}
Expand All @@ -89,69 +99,82 @@ protected void loadPrefabs() {
// empty
}

protected void setupComponentManager() {
protected void setupComponentManager(ServiceRegistry serviceRegistry) {
// empty
}

protected void initComponentManager(Context context) {
// empty
}

protected void setupPathManager() throws IOException {
PathManager.getInstance();
}

protected void setupModuleManager(Set<Name> moduleNames) {
protected ModuleManager setupModuleManager(ServiceRegistry serviceRegistry, Set<Name> moduleNames) {
// empty
return null;
}

protected void setupDisplay() {
protected void setupDisplay(ServiceRegistry serviceRegistry) {
// empty
}

protected void setupConfig() {
protected void setupConfig(ServiceRegistry serviceRegistry) {
// empty
}

protected void setupAudio() {
protected void setupAudio(ServiceRegistry serviceRegistry) {
// empty
}

protected AssetManager setupAssetManager() {
protected AssetManager setupAssetManager(ModuleManager moduleManager, ServiceRegistry serviceRegistry) {
// empty
return null;
}

protected AssetManager setupEmptyAssetManager() {
protected AssetManager setupEmptyAssetManager(ModuleManager moduleManager, ServiceRegistry serviceRegistry) {
// empty
return null;
}

protected void setupBlockManager(AssetManager assetManager) {
protected void setupBlockManager(ServiceRegistry serviceRegistry, AssetManager assetManager) {
// empty
}

protected void registerBlockTypeHandlers(Context context) {
// empty
}

protected void setupExtraDataManager(ServiceRegistry serviceRegistry, Context context) {
// empty
}

protected void setupExtraDataManager(Context context) {
protected void setupCollisionManager(ServiceRegistry serviceRegistry) {
// empty
}

protected void setupCollisionManager() {
protected void registerCollisionTypeHandlers(Context context) {
// empty
}

protected void setupEntitySystem() {
protected void setupEntitySystem(ServiceRegistry serviceRegistry) {
// empty
}

protected void setupNetwork() {
protected void setupNetwork(ServiceRegistry serviceRegistry) {
// empty
}

protected void setupStorageManager() throws IOException {
protected void setupStorageManager(ServiceRegistry serviceRegistry) throws IOException {
// empty
}

protected void setupWorldProvider() {
protected void setupWorldProvider(ServiceRegistry serviceRegistry) {
// empty
}

protected void setupCelestialSystem() {
protected void setupCelestialSystem(ServiceRegistry serviceRegistry) {
// empty
}

Expand Down
Loading
Loading